Restricciones de Android 10+ para iniciar la actividad desde el fondo

Restringir la actividad de inicio en segundo plano

Si no se cumplen las condiciones pertinentes, no se permite que la actividad se inicie en segundo plano y se imprimirán los siguientes registros relacionados:

// anything that has fallen through would currently be aborted
Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage
       + "; callingUid: " + callingUid
       + "; appSwitchState: " + appSwitchState
       + "; isCallingUidForeground: " + isCallingUidForeground
       + "; callingUidHasAnyVisibleWindow: " + callingUidHasAnyVisibleWindow
       + "; callingUidProcState: " + DebugUtils.valueToString(ActivityManager.class,
                                                              "PROCESS_STATE_", callingUidProcState)
       + "; isCallingUidPersistentSystemProcess: " + isCallingUidPersistentSystemProcess
       + "; realCallingUid: " + realCallingUid
       + "; isRealCallingUidForeground: " + isRealCallingUidForeground
       + "; realCallingUidHasAnyVisibleWindow: " + realCallingUidHasAnyVisibleWindow
       + "; realCallingUidProcState: " + DebugUtils.valueToString(ActivityManager.class,
                                                                  "PROCESS_STATE_", realCallingUidProcState)
       + "; isRealCallingUidPersistentSystemProcess: "
       + isRealCallingUidPersistentSystemProcess
       + "; originatingPendingIntent: " + originatingPendingIntent
       + "; allowBackgroundActivityStart: " + allowBackgroundActivityStart
       + "; intent: " + intent
       + "; callerApp: " + callerApp
       + "; inVisibleTask: " + (callerApp != null && callerApp.hasActivityInVisibleTask())
       + "]");

Excepciones a las restricciones

Las aplicaciones que se ejecutan en Android 10 o superior solo pueden iniciar una actividad si se cumplen una o más de las siguientes condiciones:

ROOT_UID/SYSTEM_UID/NFC_UID等重要uid

final boolean useCallingUidState =
        originatingPendingIntent == null || checkedOptions == null
                || !checkedOptions.getIgnorePendingIntentCreatorForegroundState();
.......
if (useCallingUidState) {
    
    
    if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID
            || callingAppId == Process.NFC_UID) {
    
    
        if (DEBUG_ACTIVITY_STARTS) {
    
    
            Slog.d(TAG,
                    "Activity start allowed for important callingUid (" + callingUid + ")");
        }
        return false;
    }
    ......

proceso en casa

        if (useCallingUidState) {
    
    
          ......
            if (isHomeApp(callingUid, callingPackage)) {
    
    
                if (DEBUG_ACTIVITY_STARTS) {
    
    
                    Slog.d(TAG,
                            "Activity start allowed for home app callingUid (" + callingUid + ")");
                }
                return false;
            }

El proceso bajo el uid donde se encuentra la ventana Ime

        if (useCallingUidState) {
    
    
         ......
            // IME should always be allowed to start activity, like IME settings.
            final WindowState imeWindow = mRootWindowContainer.getCurrentInputMethodWindow();
            if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) {
    
    
                if (DEBUG_ACTIVITY_STARTS) {
    
    
                    Slog.d(TAG, "Activity start allowed for active ime (" + callingUid + ")");
                }
                return false;
            }

La aplicación tiene una ventana visible, como una Actividad en primer plano

La aplicación es un proceso de sistema persistente y está realizando operaciones de interfaz de usuario

// 是persistent系统进程,并正在执行UI操作
final boolean isCallingUidPersistentSystemProcess =
        callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
// 如果允许应用程序切换,则允许具有可见应用程序窗口的普通应用程序启动活动,
// 或者将允许具有非应用程序可见窗口的动态壁纸等应用程序。
final boolean appSwitchAllowedOrFg =
        appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY;
final boolean allowCallingUidStartActivity =
        ((appSwitchAllowedOrFg || mService.mActiveUids.hasNonAppVisibleWindow(callingUid))
        && callingUidHasAnyVisibleWindow)
        || isCallingUidPersistentSystemProcess;
if (useCallingUidState && allowCallingUidStartActivity) {
    
    
    if (DEBUG_ACTIVITY_STARTS) {
    
    
        Slog.d(TAG, "Activity start allowed: callingUidHasAnyVisibleWindow = " + callingUid
                + ", isCallingUidPersistentSystemProcess = "
                + isCallingUidPersistentSystemProcess);
    }
    return false;
}

La aplicación declara el permiso START_ACTIVITIES_FROM_BACKGROUND

Solo las aplicaciones del directorio system/priv-app/ privilegiado pueden solicitar la exención

<!-- @SystemApi @hide Allows an application to start activities from background -->
<permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"
			android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier|role" />
        if (useCallingUidState) {
    
    
            // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
            if (mService.checkPermission(
                    START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
                    == PERMISSION_GRANTED) {
    
    
                if (DEBUG_ACTIVITY_STARTS) {
    
    
                    Slog.d(TAG,
                            "Background activity start allowed: START_ACTIVITIES_FROM_BACKGROUND "
                                    + "permission granted for uid "
                                    + callingUid);
                }
                return false;
            }

La aplicación es el proceso bajo el uid del componente Reciente (aquí está generalmente el proceso de inicio)

        if (useCallingUidState) {
    
    
        	.......
            // don't abort if the caller has the same uid as the recents component
            if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
    
    
                if (DEBUG_ACTIVITY_STARTS) {
    
    
                    Slog.d(TAG, "Background activity start allowed: callingUid (" + callingUid
                            + ") is recents");
                }
                return false;
            }

La aplicación es el propietario del dispositivo.

Las aplicaciones son controladores de políticas de dispositivos que se ejecutan en modo propietario del dispositivo . Ejemplos de casos de uso incluyen dispositivos empresariales totalmente administrados , así como dispositivos especializados como señalización digital y quioscos .

        if (useCallingUidState) {
    
    
          ......
            // don't abort if the callingUid is the device owner
            if (mService.isDeviceOwner(callingUid)) {
    
    
                if (DEBUG_ACTIVITY_STARTS) {
    
    
                    Slog.d(TAG, "Background activity start allowed: callingUid (" + callingUid
                            + ") is device owner");
                }
                return false;
            }

Las aplicaciones se asocian con dispositivos de hardware complementarios a través de la API CompanionDeviceManager .

Esta API es compatible con la API de inicio de aplicaciones en respuesta a las acciones del usuario en el dispositivo emparejado.

        if (useCallingUidState) {
    
    
           ......
            // don't abort if the callingUid has companion device
            final int callingUserId = UserHandle.getUserId(callingUid);
            if (mService.isAssociatedCompanionApp(callingUserId,
                    callingUid)) {
    
    
                if (DEBUG_ACTIVITY_STARTS) {
    
    
                    Slog.d(TAG, "Background activity start allowed: callingUid (" + callingUid
                            + ") is companion app");
                }
                return false;
            }

El usuario ha concedido el permiso SYSTEM_ALERT_WINDOW a la aplicación

**Nota:** Las aplicaciones que se ejecutan en Android 10 (versión Go) no pueden obtener el permiso SYSTEM_ALERT_WINDOW .
Nota: Si la aplicación apunta al nivel de API 23 o superior, el usuario de la aplicación debe otorgar explícitamente este permiso a la aplicación a través de la pantalla de administración de permisos.

<permission android:name="android.permission.SYSTEM_ALERT_WINDOW"
        	android:label="@string/permlab_systemAlertWindow"
        	android:description="@string/permdesc_systemAlertWindow"
	        android:protectionLevel="signature|setup|appop|installer|pre23|development" />
        if (useCallingUidState) {
    
    
           ......
            // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission
            if (mService.hasSystemAlertWindowPermission(callingUid,
                    callingPid, callingPackage)) {
    
    
                Slog.w(TAG, "Background activity start for " + callingPackage
                        + " allowed because SYSTEM_ALERT_WINDOW permission is granted.");
                return false;
            }
        }

Acerca de la serie areBackgroundActivityStartsAllowed

Si no tenemos una aplicación de llamada en este punto, no se proporciona ninguna llamada a startActivity(). Este es el caso de los lanzamientos basados ​​en PendingIntent, ya que es posible que el proceso del creador no se inicie y esté activo. Si este es el caso, recuperamos WindowProcessController para la persona que llama de send() si la persona que llama lo permite para que podamos tomar una decisión en función de su estado.

// 遗留行为允许使用调用者前台状态绕过 BAL 限制。
final boolean balAllowedByPiSender =
        PendingIntentRecord.isPendingIntentBalAllowedByCaller(checkedOptions);
int callerAppUid = callingUid;
if (callerApp == null && balAllowedByPiSender) {
    
    
    callerApp = mService.getProcessController(realCallingPid, realCallingUid);
    callerAppUid = realCallingUid;
}
if (callerApp != null && useCallingUidState) {
    
    
    // first check the original calling process
    if (callerApp.areBackgroundActivityStartsAllowed(appSwitchState)) {
    
    
        if (DEBUG_ACTIVITY_STARTS) {
    
    
            Slog.d(TAG, "Background activity start allowed: callerApp process (pid = "
                    + callerApp.getPid() + ", uid = " + callerAppUid + ") is allowed");
        }
        return false;
    }
    // only if that one wasn't allowed, check the other ones
    final ArraySet<WindowProcessController> uidProcesses =
            mService.mProcessMap.getProcesses(callerAppUid);
    if (uidProcesses != null) {
    
    
        for (int i = uidProcesses.size() - 1; i >= 0; i--) {
    
    
            final WindowProcessController proc = uidProcesses.valueAt(i);
            if (proc != callerApp
                    && proc.areBackgroundActivityStartsAllowed(appSwitchState)) {
    
    
                if (DEBUG_ACTIVITY_STARTS) {
    
    
                    Slog.d(TAG,
                            "Background activity start allowed: process " + proc.getPid()
                                    + " from uid " + callerAppUid + " is allowed");
                }
                return false;
            }
        }
    }
}

Una actividad de la aplicación se inició/finalizó hace un tiempo

Si no se permite el cambio de aplicación, ignoramos todas las excepciones del período de gracia de la actividad de lanzamiento, por lo que la aplicación no puede iniciarse sola en onPause() después de presionar el botón de inicio.

La actividad se puede iniciar en segundo plano dentro de los 10 segundos posteriores al inicio o finalización de la actividad después del momento de detener el cambio de aplicación

    boolean areBackgroundActivityStartsAllowed(int pid, int uid, String packageName,
            int appSwitchState, boolean isCheckingForFgsStart,
            boolean hasActivityInVisibleTask, boolean hasBackgroundActivityStartPrivileges,
            long lastStopAppSwitchesTime, long lastActivityLaunchTime,
            long lastActivityFinishTime) {
    
    
        if (appSwitchState == APP_SWITCH_ALLOW) {
    
    
            // 如果调用者中的任何activity最近启动或finish,则允许,
            final long now = SystemClock.uptimeMillis();
            // 启动或finish有10s宽限
            if (now - lastActivityLaunchTime < ACTIVITY_BG_START_GRACE_PERIOD_MS
                    || now - lastActivityFinishTime < ACTIVITY_BG_START_GRACE_PERIOD_MS) {
    
    
                // 得在停止应用程序切换的时间之后启动或finish才行
                if (lastActivityLaunchTime > lastStopAppSwitchesTime
                        || lastActivityFinishTime > lastStopAppSwitchesTime) {
    
    
                    if (DEBUG_ACTIVITY_STARTS) {
    
    
                        Slog.d(TAG, "[Process(" + pid
                                + ")] Activity start allowed: within "
                                + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period");
                    }
                    return true;
                }
                if (DEBUG_ACTIVITY_STARTS) {
    
    
                    Slog.d(TAG, "[Process(" + pid + ")] Activity start within "
                            + ACTIVITY_BG_START_GRACE_PERIOD_MS
                            + "ms grace period but also within stop app switch window");
                }

            }
        }

El proceso de Instrumentación Activa con el privilegio de iniciar actividad en segundo plano

        // Allow if the proc is instrumenting with background activity starts privs.
        if (hasBackgroundActivityStartPrivileges) {
    
    
            if (DEBUG_ACTIVITY_STARTS) {
    
    
                Slog.d(TAG, "[Process(" + pid
                        + ")] Activity start allowed: process instrumenting with background "
                        + "activity starts privileges");
            }
            return true;
        }

La aplicación es propietaria de la Actividad en la pila posterior de la tarea en primer plano

android U puede ser cancelado

    boolean hasActivityInVisibleTask() {
    
    
        return (mActivityStateFlags & ACTIVITY_STATE_FLAG_HAS_ACTIVITY_IN_VISIBLE_TASK) != 0;
    }
        // Allow if the caller has an activity in any foreground task.
        if (hasActivityInVisibleTask
                && (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) {
    
    
            if (DEBUG_ACTIVITY_STARTS) {
    
    
                Slog.d(TAG, "[Process(" + pid
                        + ")] Activity start allowed: process has activity in foreground task");
            }
            return true;
        }

Un servicio en la aplicación está vinculado por otra aplicación visible

Tenga en cuenta que la aplicación vinculada al servicio debe permanecer visible para que la aplicación en segundo plano inicie correctamente la actividad.

        // Allow if the caller is bound by a UID that's currently foreground.
        if (isBoundByForegroundUid()) {
    
    
            if (DEBUG_ACTIVITY_STARTS) {
    
    
                Slog.d(TAG, "[Process(" + pid
                        + ")] Activity start allowed: process bound by foreground uid");
            }
            return true;
        }

    private boolean isBoundByForegroundUid() {
    
    
        synchronized (this) {
    
    
            if (mBoundClientUids != null) {
    
    
                for (int i = mBoundClientUids.size() - 1; i >= 0; i--) {
    
    
                    if (mUidHasActiveVisibleWindowPredicate.test(mBoundClientUids.get(i))) {
    
    
                        return true;
                    }
                }
            }
        }
        return false;
    }
    /** A uid is considered to be foreground if it has a visible non-toast window. */
    @HotPath(caller = HotPath.START_SERVICE)
    boolean hasActiveVisibleWindow(int uid) {
    
    
        if (mVisibleActivityProcessTracker.hasVisibleActivity(uid)) {
    
    
            return true;
        }
        return mActiveUids.hasNonAppVisibleWindow(uid);
    }

La aplicación recibe la notificación PendingIntent del sistema

Para las intenciones pendientes de los servicios y los receptores de transmisión, las aplicaciones pueden iniciar una actividad unos segundos después de que se envíe la intención pendiente.

La aplicación recibe un PendingIntent de otra aplicación visible

El Servicio de la aplicación tiene una conexión con BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS

Necesita declarar el permiso START_ACTIVITIES_FROM_BACKGROUND

Android 10 (nivel de API 29) y versiones posteriores imponen límites sobre cuánto tiempo una aplicación en segundo plano puede iniciar una actividad . Estos límites ayudan a minimizar las interrupciones para los usuarios y les brindan más control sobre lo que aparece en sus pantallas.
**NOTA:** Con el fin de iniciar una actividad, el sistema aún considera que una aplicación que ejecuta un servicio en primer plano es una aplicación "en segundo plano".

Vea la introducción de BackgroundLaunchProcessController para más detalles

        // Allow if the flag was explicitly set.
        if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) {
    
    
            if (DEBUG_ACTIVITY_STARTS) {
    
    
                Slog.d(TAG, "[Process(" + pid
                        + ")] Activity start allowed: process allowed by token");
            }
            return true;
        }

La aplicación inicia la actividad en una tarea existente con el mismo uid

        // Do not allow background activity start in new task or in a task that uid is not present.
        // Also do not allow pinned window to start single instance activity in background,
        // as it will recreate the window and makes it to foreground.
        boolean blockBalInTask = (newTask
                || !targetTask.isUidPresent(mCallingUid)
                || (LAUNCH_SINGLE_INSTANCE == mLaunchMode && targetTask.inPinnedWindowingMode()));

        if (mRestrictedBgActivity && blockBalInTask && handleBackgroundActivityAbort(r)) {
    
    
            Slog.e(TAG, "Abort background activity starts from " + mCallingUid);
            return START_ABORTED;
        }

Cómo solicitar una exención

Permiso relacionado

Solicitar permiso START_ACTIVITIES_FROM_BACKGROUND

Solo las aplicaciones del directorio system/priv-app/ privilegiado pueden solicitar la exención

<uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
<permissions>
    <privapp-permissions package="com.android.xxx">
        <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
     </privapp-permissions>
</permissions>

Solicitar el permiso SYSTEM_ALERT_WINDOW

**Nota:** Las aplicaciones que se ejecutan en Android 10 (versión Go) no pueden obtener el permiso SYSTEM_ALERT_WINDOW .
Nota: Si la aplicación apunta al nivel de API 23 o superior, el usuario de la aplicación debe otorgar explícitamente este permiso a la aplicación a través de la pantalla de administración de permisos.

 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

El servicio tiene un enlace de cliente especial

Un servicio en la aplicación está vinculado por otra aplicación visible

Un servicio en la aplicación está vinculado por otra aplicación con el indicador BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS

Otra aplicación necesita declarar el permiso START_ACTIVITIES_FROM_BACKGROUND

Supongo que te gusta

Origin blog.csdn.net/xiaoyantan/article/details/128401740
Recomendado
Clasificación