Loading services/core/java/com/android/server/wm/ActivityStarter.java +112 −53 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; import static com.android.server.wm.ActivityRecord.State.FINISHING; import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; Loading @@ -74,7 +75,12 @@ import static com.android.server.wm.ActivityTaskManagerService.ANIMATE; import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME; import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_ALLOWLISTED_COMPONENT; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_ALLOWLISTED_UID; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_BAL_PERMISSION; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_DEFAULT; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_PENDING_INTENT; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW; import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY; Loading Loading @@ -152,6 +158,7 @@ class ActivityStarter { private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS; private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION; private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING; private static final int INVALID_LAUNCH_MODE = -1; /** Loading Loading @@ -1851,42 +1858,96 @@ class ActivityStarter { } } // Log activity starts which violate one of the following rules of the // activity security model (ASM): // 1. Only the top activity on a task can start activities on that task // 2. Only the top activity on the top task can create new (top) tasks // We don't currently block, but these checks may later become blocks // TODO(b/236234252): Shift to BackgroundActivityStartController once // class is ready if (!checkActivitySecurityModel(r, newTask, targetTask)) { return START_SUCCESS; } return START_SUCCESS; } /** * TODO(b/263368846): Shift to BackgroundActivityStartController once class is ready * Log activity starts which violate one of the following rules of the * activity security model (ASM): * See go/activity-security for rationale behind the rules. * We don't currently block, but these checks may later become blocks * 1. Within a task, only an activity matching a top UID of the task can start activities * 2. Only activities within a foreground task, which match a top UID of the task, can * create a new task or bring an existing one into the foreground */ private boolean checkActivitySecurityModel(ActivityRecord r, boolean newTask, Task targetTask) { // Intents with FLAG_ACTIVITY_NEW_TASK will always be considered as creating a new task // even if the intent is delivered to an existing task. boolean taskToFront = newTask || (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == FLAG_ACTIVITY_NEW_TASK; if (mSourceRecord != null) { int callerUid = mSourceRecord.getUid(); ActivityRecord targetTopActivity = targetTask != null ? targetTask.getTopNonFinishingActivity() : null; boolean passesAsmChecks = newTask ? mService.mVisibleActivityProcessTracker.hasResumedActivity(callerUid) : targetTopActivity != null && targetTopActivity.getUid() == callerUid; if (!passesAsmChecks) { boolean passesAsmChecks = true; Task sourceTask = mSourceRecord.getTask(); // Don't allow launches into a new task if the current task is not foreground. if (taskToFront) { passesAsmChecks = sourceTask != null && sourceTask.isVisible(); } Task taskToCheck = taskToFront ? sourceTask : targetTask; passesAsmChecks = passesAsmChecks && ActivityTaskSupervisor .doesTopActivityMatchingUidExistForAsm(taskToCheck, mSourceRecord.getUid(), mSourceRecord); if (passesAsmChecks) { return true; } } // BAL exception only allowed for new tasks if (taskToFront) { if (mBalCode == BAL_ALLOW_ALLOWLISTED_COMPONENT || mBalCode == BAL_ALLOW_BAL_PERMISSION || mBalCode == BAL_ALLOW_PENDING_INTENT) { return true; } } // BAL Exception allowed in all cases if (mBalCode == BAL_ALLOW_ALLOWLISTED_UID) { return true; } // TODO(b/230590090): Revisit this - ideally we would not rely on visibility, but rather // have an explicit api for activities to opt-out of ASM protection if they need to. if (mBalCode == BAL_ALLOW_VISIBLE_WINDOW) { return true; } // ASM rules have failed. Log why ActivityRecord targetTopActivity = targetTask == null ? null : targetTask.getActivity(ar -> !ar.isState(FINISHING) && !ar.isAlwaysOnTop()); Slog.i(TAG, "Launching r: " + r + " from background: " + mSourceRecord + ". New task: " + newTask); boolean newOrEmptyTask = newTask || (targetTopActivity == null); int action = newTask + ". New task: " + newTask + ". Top activity: " + targetTopActivity); int action = newTask || mSourceRecord == null ? FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__ACTIVITY_START_NEW_TASK : (mSourceRecord.getTask().equals(targetTask) ? FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__ACTIVITY_START_SAME_TASK : FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__ACTIVITY_START_DIFFERENT_TASK); FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED, /* caller_uid */ callerUid, mSourceRecord != null ? mSourceRecord.getUid() : -1, /* caller_activity_class_name */ mSourceRecord.info.name, mSourceRecord != null ? mSourceRecord.info.name : null, /* target_task_top_activity_uid */ newOrEmptyTask ? -1 : targetTopActivity.getUid(), targetTopActivity != null ? targetTopActivity.getUid() : -1, /* target_task_top_activity_class_name */ newOrEmptyTask ? null : targetTopActivity.info.name, targetTopActivity != null ? targetTopActivity.info.name : null, /* target_task_is_different */ newTask || !mSourceRecord.getTask().equals(targetTask), newTask || mSourceRecord == null || targetTask == null || !targetTask.equals(mSourceRecord.getTask()), /* target_activity_uid */ r.getUid(), /* target_activity_class_name */ Loading @@ -1894,19 +1955,17 @@ class ActivityStarter { /* target_intent_action */ r.intent.getAction(), /* target_intent_flags */ r.intent.getFlags(), mLaunchFlags, /* action */ action, /* version */ 1, /* multi_window */ targetTask != null && !targetTask.equals(mSourceRecord.getTask()) && targetTask.isVisible() /* multi_window - we have our source not in the target task, but both are visible */ targetTask != null && mSourceRecord != null && !targetTask.equals(mSourceRecord.getTask()) && targetTask.isVisible() ); } } return START_SUCCESS; return false; } /** Loading services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +57 −3 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; import static com.android.server.wm.ActivityRecord.State.FINISHING; import static com.android.server.wm.ActivityRecord.State.PAUSED; import static com.android.server.wm.ActivityRecord.State.PAUSING; import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS; Loading Loading @@ -157,6 +158,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; // TODO: This class has become a dumping ground. Let's // - Move things relating to the hierarchy to RootWindowContainer Loading Loading @@ -1629,10 +1631,11 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // cleared the calling identify. If so, we infer we do not need further restrictions here. // TODO(b/263368846) Move to live with the rest of the ASM logic. if (callingUid != SYSTEM_UID) { ActivityRecord topActivity = task.getTopNonFinishingActivity(); boolean passesAsmChecks = topActivity != null && topActivity.getUid() == callingUid; boolean passesAsmChecks = doesTopActivityMatchingUidExistForAsm(task, callingUid, null); if (!passesAsmChecks) { ActivityRecord topActivity = task.getActivity(ar -> !ar.isState(FINISHING) && !ar.isAlwaysOnTop()); Slog.i(TAG, "Finishing task from background. t: " + task); FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED, /* caller_uid */ Loading Loading @@ -1677,6 +1680,57 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { } } /** * For the purpose of ASM, ‘Top UID” for a task is defined as an activity UID * 1. Which is top of the stack in z-order * a. Excluding any activities with the flag ‘isAlwaysOnTop’ and * b. Excluding any activities which are `finishing` * 2. Or top of an adjacent task fragment to (1) * * The 'sourceRecord' can be considered top even if it is 'finishing' * * TODO(b/263368846) Shift to BackgroundActivityStartController once class is ready */ @Nullable static boolean doesTopActivityMatchingUidExistForAsm(@Nullable Task task, int uid, @Nullable ActivityRecord sourceRecord) { // If the source is visible, consider it 'top'. if (sourceRecord != null && sourceRecord.isVisible()) { return true; } // Consider the source activity, whether or not it is finishing. Do not consider any other // finishing activity. Predicate<ActivityRecord> topOfStackPredicate = (ar) -> ar.equals(sourceRecord) || (!ar.isState(FINISHING) && !ar.isAlwaysOnTop()); // Check top of stack (or the first task fragment for embedding). ActivityRecord topActivity = task.getActivity(topOfStackPredicate); if (topActivity == null) { return false; } if (topActivity.getUid() == uid) { return true; } // Even if the top activity is not a match, we may be in an embedded activity scenario with // an adjacent task fragment. Get the second fragment. TaskFragment taskFragment = topActivity.getTaskFragment(); if (taskFragment == null) { return false; } TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment(); if (adjacentTaskFragment == null) { return false; } // Check the second fragment. topActivity = adjacentTaskFragment.getActivity(topOfStackPredicate); return topActivity != null && topActivity.getUid() == uid; } void cleanUpRemovedTaskLocked(Task task, boolean killProcess, boolean removeFromRecents) { if (removeFromRecents) { mRecentTasks.remove(task); Loading Loading
services/core/java/com/android/server/wm/ActivityStarter.java +112 −53 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; import static com.android.server.wm.ActivityRecord.State.FINISHING; import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; Loading @@ -74,7 +75,12 @@ import static com.android.server.wm.ActivityTaskManagerService.ANIMATE; import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME; import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_ALLOWLISTED_COMPONENT; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_ALLOWLISTED_UID; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_BAL_PERMISSION; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_DEFAULT; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_PENDING_INTENT; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW; import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY; Loading Loading @@ -152,6 +158,7 @@ class ActivityStarter { private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS; private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION; private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING; private static final int INVALID_LAUNCH_MODE = -1; /** Loading Loading @@ -1851,42 +1858,96 @@ class ActivityStarter { } } // Log activity starts which violate one of the following rules of the // activity security model (ASM): // 1. Only the top activity on a task can start activities on that task // 2. Only the top activity on the top task can create new (top) tasks // We don't currently block, but these checks may later become blocks // TODO(b/236234252): Shift to BackgroundActivityStartController once // class is ready if (!checkActivitySecurityModel(r, newTask, targetTask)) { return START_SUCCESS; } return START_SUCCESS; } /** * TODO(b/263368846): Shift to BackgroundActivityStartController once class is ready * Log activity starts which violate one of the following rules of the * activity security model (ASM): * See go/activity-security for rationale behind the rules. * We don't currently block, but these checks may later become blocks * 1. Within a task, only an activity matching a top UID of the task can start activities * 2. Only activities within a foreground task, which match a top UID of the task, can * create a new task or bring an existing one into the foreground */ private boolean checkActivitySecurityModel(ActivityRecord r, boolean newTask, Task targetTask) { // Intents with FLAG_ACTIVITY_NEW_TASK will always be considered as creating a new task // even if the intent is delivered to an existing task. boolean taskToFront = newTask || (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == FLAG_ACTIVITY_NEW_TASK; if (mSourceRecord != null) { int callerUid = mSourceRecord.getUid(); ActivityRecord targetTopActivity = targetTask != null ? targetTask.getTopNonFinishingActivity() : null; boolean passesAsmChecks = newTask ? mService.mVisibleActivityProcessTracker.hasResumedActivity(callerUid) : targetTopActivity != null && targetTopActivity.getUid() == callerUid; if (!passesAsmChecks) { boolean passesAsmChecks = true; Task sourceTask = mSourceRecord.getTask(); // Don't allow launches into a new task if the current task is not foreground. if (taskToFront) { passesAsmChecks = sourceTask != null && sourceTask.isVisible(); } Task taskToCheck = taskToFront ? sourceTask : targetTask; passesAsmChecks = passesAsmChecks && ActivityTaskSupervisor .doesTopActivityMatchingUidExistForAsm(taskToCheck, mSourceRecord.getUid(), mSourceRecord); if (passesAsmChecks) { return true; } } // BAL exception only allowed for new tasks if (taskToFront) { if (mBalCode == BAL_ALLOW_ALLOWLISTED_COMPONENT || mBalCode == BAL_ALLOW_BAL_PERMISSION || mBalCode == BAL_ALLOW_PENDING_INTENT) { return true; } } // BAL Exception allowed in all cases if (mBalCode == BAL_ALLOW_ALLOWLISTED_UID) { return true; } // TODO(b/230590090): Revisit this - ideally we would not rely on visibility, but rather // have an explicit api for activities to opt-out of ASM protection if they need to. if (mBalCode == BAL_ALLOW_VISIBLE_WINDOW) { return true; } // ASM rules have failed. Log why ActivityRecord targetTopActivity = targetTask == null ? null : targetTask.getActivity(ar -> !ar.isState(FINISHING) && !ar.isAlwaysOnTop()); Slog.i(TAG, "Launching r: " + r + " from background: " + mSourceRecord + ". New task: " + newTask); boolean newOrEmptyTask = newTask || (targetTopActivity == null); int action = newTask + ". New task: " + newTask + ". Top activity: " + targetTopActivity); int action = newTask || mSourceRecord == null ? FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__ACTIVITY_START_NEW_TASK : (mSourceRecord.getTask().equals(targetTask) ? FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__ACTIVITY_START_SAME_TASK : FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__ACTIVITY_START_DIFFERENT_TASK); FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED, /* caller_uid */ callerUid, mSourceRecord != null ? mSourceRecord.getUid() : -1, /* caller_activity_class_name */ mSourceRecord.info.name, mSourceRecord != null ? mSourceRecord.info.name : null, /* target_task_top_activity_uid */ newOrEmptyTask ? -1 : targetTopActivity.getUid(), targetTopActivity != null ? targetTopActivity.getUid() : -1, /* target_task_top_activity_class_name */ newOrEmptyTask ? null : targetTopActivity.info.name, targetTopActivity != null ? targetTopActivity.info.name : null, /* target_task_is_different */ newTask || !mSourceRecord.getTask().equals(targetTask), newTask || mSourceRecord == null || targetTask == null || !targetTask.equals(mSourceRecord.getTask()), /* target_activity_uid */ r.getUid(), /* target_activity_class_name */ Loading @@ -1894,19 +1955,17 @@ class ActivityStarter { /* target_intent_action */ r.intent.getAction(), /* target_intent_flags */ r.intent.getFlags(), mLaunchFlags, /* action */ action, /* version */ 1, /* multi_window */ targetTask != null && !targetTask.equals(mSourceRecord.getTask()) && targetTask.isVisible() /* multi_window - we have our source not in the target task, but both are visible */ targetTask != null && mSourceRecord != null && !targetTask.equals(mSourceRecord.getTask()) && targetTask.isVisible() ); } } return START_SUCCESS; return false; } /** Loading
services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +57 −3 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; import static com.android.server.wm.ActivityRecord.State.FINISHING; import static com.android.server.wm.ActivityRecord.State.PAUSED; import static com.android.server.wm.ActivityRecord.State.PAUSING; import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS; Loading Loading @@ -157,6 +158,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; // TODO: This class has become a dumping ground. Let's // - Move things relating to the hierarchy to RootWindowContainer Loading Loading @@ -1629,10 +1631,11 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // cleared the calling identify. If so, we infer we do not need further restrictions here. // TODO(b/263368846) Move to live with the rest of the ASM logic. if (callingUid != SYSTEM_UID) { ActivityRecord topActivity = task.getTopNonFinishingActivity(); boolean passesAsmChecks = topActivity != null && topActivity.getUid() == callingUid; boolean passesAsmChecks = doesTopActivityMatchingUidExistForAsm(task, callingUid, null); if (!passesAsmChecks) { ActivityRecord topActivity = task.getActivity(ar -> !ar.isState(FINISHING) && !ar.isAlwaysOnTop()); Slog.i(TAG, "Finishing task from background. t: " + task); FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED, /* caller_uid */ Loading Loading @@ -1677,6 +1680,57 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { } } /** * For the purpose of ASM, ‘Top UID” for a task is defined as an activity UID * 1. Which is top of the stack in z-order * a. Excluding any activities with the flag ‘isAlwaysOnTop’ and * b. Excluding any activities which are `finishing` * 2. Or top of an adjacent task fragment to (1) * * The 'sourceRecord' can be considered top even if it is 'finishing' * * TODO(b/263368846) Shift to BackgroundActivityStartController once class is ready */ @Nullable static boolean doesTopActivityMatchingUidExistForAsm(@Nullable Task task, int uid, @Nullable ActivityRecord sourceRecord) { // If the source is visible, consider it 'top'. if (sourceRecord != null && sourceRecord.isVisible()) { return true; } // Consider the source activity, whether or not it is finishing. Do not consider any other // finishing activity. Predicate<ActivityRecord> topOfStackPredicate = (ar) -> ar.equals(sourceRecord) || (!ar.isState(FINISHING) && !ar.isAlwaysOnTop()); // Check top of stack (or the first task fragment for embedding). ActivityRecord topActivity = task.getActivity(topOfStackPredicate); if (topActivity == null) { return false; } if (topActivity.getUid() == uid) { return true; } // Even if the top activity is not a match, we may be in an embedded activity scenario with // an adjacent task fragment. Get the second fragment. TaskFragment taskFragment = topActivity.getTaskFragment(); if (taskFragment == null) { return false; } TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment(); if (adjacentTaskFragment == null) { return false; } // Check the second fragment. topActivity = adjacentTaskFragment.getActivity(topOfStackPredicate); return topActivity != null && topActivity.getUid() == uid; } void cleanUpRemovedTaskLocked(Task task, boolean killProcess, boolean removeFromRecents) { if (removeFromRecents) { mRecentTasks.remove(task); Loading