Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 83f5395c authored by Hani Kazmi's avatar Hani Kazmi Committed by Android (Google) Code Review
Browse files

Merge changes from topic "cherrypicker-L76800000958796731:N60400001340845132" into udc-dev

* changes:
  Update ASM clear task to only conisder present DisplayArea
  ASM - Use finishing instead of isState() and more logging
parents b7bdaebc 2903f3d5
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -42,6 +42,9 @@ class ActivitySecurityModelFeatureFlags {
    // TODO(b/230590090): Replace with public documentation once ready
    static final String DOC_LINK = "go/android-asm";

    /** Used to determine which version of the ASM logic was used in logs while we iterate */
    static final int ASM_VERSION = 5;

    private static final String NAMESPACE = NAMESPACE_WINDOW_MANAGER;
    private static final String KEY_ASM_PREFIX = "ActivitySecurity__";
    private static final String KEY_ASM_RESTRICTIONS_ENABLED = KEY_ASM_PREFIX
+90 −15
Original line number Diff line number Diff line
@@ -60,7 +60,6 @@ import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TAS

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;
@@ -75,6 +74,7 @@ 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.ActivityTaskSupervisor.getApplicationLabel;
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_DEFAULT;
@@ -83,6 +83,7 @@ import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_SAW_PERMISSION;
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.BackgroundActivityStartController.balCodeToString;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
@@ -150,6 +151,9 @@ import com.android.server.wm.TaskFragment.EmbeddingCheckResult;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.util.Date;
import java.util.StringJoiner;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;

/**
@@ -1967,8 +1971,7 @@ class ActivityStarter {

        // ASM rules have failed. Log why
        ActivityRecord targetTopActivity = targetTask == null ? null
                : targetTask.getActivity(ar ->
                        !ar.isState(FINISHING) && !ar.isAlwaysOnTop());
                : targetTask.getActivity(ar -> !ar.finishing && !ar.isAlwaysOnTop());

        int action = newTask || mSourceRecord == null
                ? FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__ACTIVITY_START_NEW_TASK
@@ -1999,7 +2002,7 @@ class ActivityStarter {
                /* action */
                action,
                /* version */
                4,
                ActivitySecurityModelFeatureFlags.ASM_VERSION,
                /* 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(),
@@ -2011,22 +2014,26 @@ class ActivityStarter {
                    .shouldRestrictActivitySwitch(mCallingUid)
                && shouldBlockActivityStart;

        String launchedFromPackageName = r.launchedFromPackage;
        if (ActivitySecurityModelFeatureFlags.shouldShowToast(mCallingUid)) {
            String toastText = ActivitySecurityModelFeatureFlags.DOC_LINK
                    + (blockActivityStartAndFeatureEnabled ? " blocked " : " would block ")
                    + getApplicationLabel(mService.mContext.getPackageManager(),
                        launchedFromPackageName);
            UiThread.getHandler().post(() -> Toast.makeText(mService.mContext,
                    "Activity start from " + r.launchedFromPackage
                            + (blockActivityStartAndFeatureEnabled ? " " : " would be ")
                            + "blocked by " + ActivitySecurityModelFeatureFlags.DOC_LINK,
                    Toast.LENGTH_SHORT).show());
        }
                    toastText, Toast.LENGTH_LONG).show());

            logDebugInfoForActivitySecurity("Launch", r, targetTask, targetTopActivity,
                    blockActivityStartAndFeatureEnabled, /* taskToFront */ taskToFront);
        }

        if (blockActivityStartAndFeatureEnabled) {
            Slog.e(TAG, "Abort Launching r: " + r
            Slog.e(TAG, "[ASM] Abort Launching r: " + r
                    + " as source: "
                    + (mSourceRecord != null ? mSourceRecord : r.launchedFromPackage)
                    + (mSourceRecord != null ? mSourceRecord : launchedFromPackageName)
                    + " is in background. New task: " + newTask
                    + ". Top activity: " + targetTopActivity
                    + ". BAL Code: " + mBalCode);
                    + ". BAL Code: " + balCodeToString(mBalCode));

            return false;
        }
@@ -2034,6 +2041,71 @@ class ActivityStarter {
        return true;
    }

    /** Only called when an activity launch may be blocked, which should happen very rarely */
    private void logDebugInfoForActivitySecurity(String action, ActivityRecord r, Task targetTask,
            ActivityRecord targetTopActivity, boolean blockActivityStartAndFeatureEnabled,
            boolean taskToFront) {
        final String prefix = "[ASM] ";
        Function<ActivityRecord, String> recordToString = (ar) -> {
            if (ar == null) {
                return null;
            }
            return (ar == mSourceRecord ? " [source]=> "
                    : ar == targetTopActivity ? " [ top  ]=> "
                            : ar == r ? " [target]=> "
                                    : "         => ")
                    + ar
                    + " :: visible=" + ar.isVisible()
                    + ", finishing=" + ar.isFinishing()
                    + ", alwaysOnTop=" + ar.isAlwaysOnTop()
                    + ", taskFragment=" + ar.getTaskFragment();
        };

        StringJoiner joiner = new StringJoiner("\n");
        joiner.add(prefix + "------ Activity Security " + action + " Debug Logging Start ------");
        joiner.add(prefix + "Block Enabled: " + blockActivityStartAndFeatureEnabled);
        joiner.add(prefix + "ASM Version: " + ActivitySecurityModelFeatureFlags.ASM_VERSION);

        boolean targetTaskMatchesSourceTask = targetTask != null
                && mSourceRecord != null && mSourceRecord.getTask() == targetTask;

        if (mSourceRecord == null) {
            joiner.add(prefix + "Source Package: " + r.launchedFromPackage);
            String realCallingPackage = mService.mContext.getPackageManager().getNameForUid(
                    mRealCallingUid);
            joiner.add(prefix + "Real Calling Uid Package: " + realCallingPackage);
        } else {
            joiner.add(prefix + "Source Record: " + recordToString.apply(mSourceRecord));
            if (targetTaskMatchesSourceTask) {
                joiner.add(prefix + "Source/Target Task: " + mSourceRecord.getTask());
                joiner.add(prefix + "Source/Target Task Stack: ");
            } else {
                joiner.add(prefix + "Source Task: " + mSourceRecord.getTask());
                joiner.add(prefix + "Source Task Stack: ");
            }
            mSourceRecord.getTask().forAllActivities((Consumer<ActivityRecord>)
                    ar -> joiner.add(prefix + recordToString.apply(ar)));
        }

        joiner.add(prefix + "Target Task Top: " + recordToString.apply(targetTopActivity));
        if (!targetTaskMatchesSourceTask) {
            joiner.add(prefix + "Target Task: " + targetTask);
            if (targetTask != null) {
                joiner.add(prefix + "Target Task Stack: ");
                targetTask.forAllActivities((Consumer<ActivityRecord>)
                        ar -> joiner.add(prefix + recordToString.apply(ar)));
            }
        }

        joiner.add(prefix + "Target Record: " + recordToString.apply(r));
        joiner.add(prefix + "Intent: " + mIntent);
        joiner.add(prefix + "TaskToFront: " + taskToFront);
        joiner.add(prefix + "BalCode: " + balCodeToString(mBalCode));

        joiner.add(prefix + "------ Activity Security " + action + " Debug Logging End ------");
        Slog.i(TAG, joiner.toString());
    }

    /**
     * Returns whether embedding of {@code starting} is allowed.
     *
@@ -2165,8 +2237,8 @@ class ActivityStarter {
            return;
        }

        Predicate<ActivityRecord> isLaunchingOrLaunched = ar -> !ar.finishing && (ar.isUid(
                startingUid) || ar.isUid(callingUid) || ar.isUid(realCallingUid));
        Predicate<ActivityRecord> isLaunchingOrLaunched = ar -> !ar.finishing
                && (ar.isUid(startingUid) || ar.isUid(callingUid) || ar.isUid(realCallingUid));

        // Return early if we know for sure we won't need to clear any activities by just checking
        // the top activity.
@@ -2202,7 +2274,10 @@ class ActivityStarter {
                            ? "Top activities cleared by "
                            : "Top activities would be cleared by ")
                            + ActivitySecurityModelFeatureFlags.DOC_LINK,
                    Toast.LENGTH_SHORT).show());
                    Toast.LENGTH_LONG).show());

            logDebugInfoForActivitySecurity("Clear Top", mStartActivity, targetTask, targetTaskTop,
                    shouldBlockActivityStart, /* taskToFront */ true);
        }
    }

+107 −68
Original line number Diff line number Diff line
@@ -51,7 +51,6 @@ 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;
@@ -1636,20 +1635,50 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
            // Prevent recursion.
            return;
        }
        boolean shouldBlockActivitySwitchIfFeatureEnabled = false;
        boolean wouldBlockActivitySwitchIgnoringFlags = false;
        task.mTransitionController.requestCloseTransitionIfNeeded(task);
        task.mInRemoveTask = true;
        try {
            task.removeActivities(reason, false /* excludingTaskOverlay */);
            cleanUpRemovedTaskLocked(task, killProcess, removeFromRecents);
            mService.getLockTaskController().clearLockedTask(task);
            mService.getTaskChangeNotificationController().notifyTaskStackChanged();
            if (task.isPersistable) {
                mService.notifyTaskPersisterLocked(null, true);
            }
            checkActivitySecurityForTaskClear(callingUid, task, callerActivityClassName);
        } finally {
            task.mInRemoveTask = false;
        }
    }

    // TODO(b/263368846) Move to live with the rest of the ASM logic.
    /**
     * Returns home if the passed in callingUid is not top of the stack, rather than returning to
     * previous task.
     */
    private void checkActivitySecurityForTaskClear(int callingUid, Task task,
            String callerActivityClassName) {
        // We may have already checked that the callingUid has additional clearTask privileges, and
        // 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) {
            Pair<Boolean, Boolean> pair = doesTopActivityMatchingUidExistForAsm(task,
                    callingUid,
                    null);
            shouldBlockActivitySwitchIfFeatureEnabled = !pair.first;
            wouldBlockActivitySwitchIgnoringFlags = !pair.second;
            if (wouldBlockActivitySwitchIgnoringFlags) {
                ActivityRecord topActivity =  task.getActivity(ar ->
                        !ar.isState(FINISHING) && !ar.isAlwaysOnTop());
        if (callingUid == SYSTEM_UID) {
            return;
        }

        TaskDisplayArea displayArea = task.getTaskDisplayArea();
        if (displayArea == null) {
            // If there is no associated display area, we can not return home.
            return;
        }

        Pair<Boolean, Boolean> pair = doesTopActivityMatchingUidExistForAsm(task, callingUid, null);
        boolean shouldBlockActivitySwitchIfFeatureEnabled = !pair.first;
        boolean wouldBlockActivitySwitchIgnoringFlags = !pair.second;

        if (!wouldBlockActivitySwitchIgnoringFlags) {
            return;
        }

        ActivityRecord topActivity = task.getActivity(ar -> !ar.finishing && !ar.isAlwaysOnTop());
        FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED,
                /* caller_uid */
                callingUid,
@@ -1672,48 +1701,48 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
                /* action */
                FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__FINISH_TASK,
                /* version */
                        3,
                ActivitySecurityModelFeatureFlags.ASM_VERSION,
                /* multi_window */
                false,
                /* bal_code */
                -1
        );
            }
        }
        task.mTransitionController.requestCloseTransitionIfNeeded(task);
        task.mInRemoveTask = true;
        try {
            task.removeActivities(reason, false /* excludingTaskOverlay */);
            cleanUpRemovedTaskLocked(task, killProcess, removeFromRecents);
            mService.getLockTaskController().clearLockedTask(task);
            mService.getTaskChangeNotificationController().notifyTaskStackChanged();
            if (task.isPersistable) {
                mService.notifyTaskPersisterLocked(null, true);
            }
            if (wouldBlockActivitySwitchIgnoringFlags) {

        boolean restrictActivitySwitch = ActivitySecurityModelFeatureFlags
                .shouldRestrictActivitySwitch(callingUid)
                && shouldBlockActivitySwitchIfFeatureEnabled;

        PackageManager pm = mService.mContext.getPackageManager();
        String callingPackage = pm.getNameForUid(callingUid);
        final CharSequence callingLabel;
        if (callingPackage == null) {
            callingPackage = String.valueOf(callingUid);
            callingLabel = callingPackage;
        } else {
            callingLabel = getApplicationLabel(pm, callingPackage);
        }

        if (ActivitySecurityModelFeatureFlags.shouldShowToast(callingUid)) {
                    UiThread.getHandler().post(() -> Toast.makeText(mService.mContext,
                            (restrictActivitySwitch
                                    ? "Returning home due to "
                                    : "Would return home due to ")
                                    + ActivitySecurityModelFeatureFlags.DOC_LINK,
                            Toast.LENGTH_SHORT).show());
            Toast toast = Toast.makeText(mService.mContext,
                    (ActivitySecurityModelFeatureFlags.DOC_LINK
                            + (restrictActivitySwitch
                            ? "returned home due to "
                            : "would return home due to ")
                            + callingLabel),
                    Toast.LENGTH_LONG);
            UiThread.getHandler().post(toast::show);
        }

        // If the activity switch should be restricted, return home rather than the
        // previously top task, to prevent users from being confused which app they're
        // viewing
        if (restrictActivitySwitch) {
                    Slog.w(TAG, "Return to home as source uid: " + callingUid
            Slog.w(TAG, "[ASM] Return to home as source: " + callingPackage
                    + " is not on top of task t: " + task);
            displayArea.moveHomeActivityToTop("taskRemoved");
        } else {
            Slog.i(TAG, "[ASM] Would return to home as source: " + callingPackage
                    + " is not on top of task t: " + task);
                    task.getTaskDisplayArea().moveHomeActivityToTop("taskRemoved");
                }
            }
        } finally {
            task.mInRemoveTask = false;
        }
    }

@@ -1743,7 +1772,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
        // 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());
                || (!ar.finishing && !ar.isAlwaysOnTop());

        // Check top of stack (or the first task fragment for embedding).
        ActivityRecord topActivity = task.getActivity(topOfStackPredicate);
@@ -1777,6 +1806,16 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
        return topActivity.allowCrossUidActivitySwitchFromBelow(uid);
    }

    static CharSequence getApplicationLabel(PackageManager pm, String packageName) {
        try {
            ApplicationInfo launchedFromPackageInfo = pm.getApplicationInfo(
                    packageName, PackageManager.ApplicationInfoFlags.of(0));
            return pm.getApplicationLabel(launchedFromPackageInfo);
        } catch (PackageManager.NameNotFoundException e) {
            return packageName;
        }
    }

    void cleanUpRemovedTaskLocked(Task task, boolean killProcess, boolean removeFromRecents) {
        if (removeFromRecents) {
            mRecentTasks.remove(task);
+29 −0
Original line number Diff line number Diff line
@@ -114,6 +114,35 @@ public class BackgroundActivityStartController {
    /** Process belongs to a SDK sandbox */
    static final int BAL_ALLOW_SDK_SANDBOX = 10;

    static String balCodeToString(@BalCode int balCode) {
        switch (balCode) {
            case BAL_ALLOW_ALLOWLISTED_COMPONENT:
                return "BAL_ALLOW_ALLOWLISTED_COMPONENT";
            case BAL_ALLOW_ALLOWLISTED_UID:
                return "BAL_ALLOW_ALLOWLISTED_UID";
            case BAL_ALLOW_DEFAULT:
                return "BAL_ALLOW_DEFAULT";
            case BAL_ALLOW_FOREGROUND:
                return "BAL_ALLOW_FOREGROUND";
            case BAL_ALLOW_GRACE_PERIOD:
                return "BAL_ALLOW_GRACE_PERIOD";
            case BAL_ALLOW_PENDING_INTENT:
                return "BAL_ALLOW_PENDING_INTENT";
            case BAL_ALLOW_PERMISSION:
                return "BAL_ALLOW_PERMISSION";
            case BAL_ALLOW_SAW_PERMISSION:
                return "BAL_ALLOW_SAW_PERMISSION";
            case BAL_ALLOW_SDK_SANDBOX:
                return "BAL_ALLOW_SDK_SANDBOX";
            case BAL_ALLOW_VISIBLE_WINDOW:
                return "BAL_ALLOW_VISIBLE_WINDOW";
            case BAL_BLOCK:
                return "BAL_BLOCK";
            default:
                throw new IllegalArgumentException("Unexpected value: " + balCode);
        }
    }

    BackgroundActivityStartController(
            final ActivityTaskManagerService service, final ActivityTaskSupervisor supervisor) {
        mService = service;