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

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

Merge "ASM Rule and Debug Updates." into main

parents ed5a6f51 07a30c91
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ class ActivitySecurityModelFeatureFlags {
    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 = 8;
    static final int ASM_VERSION = 9;

    private static final String NAMESPACE = NAMESPACE_WINDOW_MANAGER;
    private static final String KEY_ASM_PREFIX = "ActivitySecurity__";
+2 −2
Original line number Diff line number Diff line
@@ -2053,8 +2053,8 @@ class ActivityStarter {
        }

        if (!mSupervisor.getBackgroundActivityLaunchController().checkActivityAllowedToStart(
                mSourceRecord, r, newTask, targetTask, mLaunchFlags, mBalCode, mCallingUid,
                mRealCallingUid)) {
                mSourceRecord, r, newTask, avoidMoveToFront(), targetTask, mLaunchFlags, mBalCode,
                mCallingUid, mRealCallingUid)) {
            return START_ABORTED;
        }

+93 −24
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.ArraySet;
@@ -1042,8 +1043,9 @@ public class BackgroundActivityStartController {
     * create a new task or bring an existing one into the foreground
     */
    boolean checkActivityAllowedToStart(@Nullable ActivityRecord sourceRecord,
            @NonNull ActivityRecord targetRecord, boolean newTask, @NonNull Task targetTask,
            int launchFlags, int balCode, int callingUid, int realCallingUid) {
            @NonNull ActivityRecord targetRecord, boolean newTask, boolean avoidMoveTaskToFront,
            @Nullable Task targetTask, int launchFlags, int balCode, int callingUid,
            int realCallingUid) {
        // BAL Exception allowed in all cases
        if (balCode == BAL_ALLOW_ALLOWLISTED_UID) {
            return true;
@@ -1067,16 +1069,38 @@ public class BackgroundActivityStartController {
        }

        if (balCode == BAL_ALLOW_GRACE_PERIOD) {
            // Allow if launching into new task, and caller matches most recently finished activity
            if (taskToFront && mTopFinishedActivity != null
                    && mTopFinishedActivity.mUid == callingUid) {
                return true;
            } else if (!taskToFront) {
            }

            // Launching into existing task - allow if matches most recently finished activity
            // within the task.
            // We can reach here multiple ways:
            // 1. activity in fg fires intent (taskToFront = false, sourceRecord is available)
            // 2. activity in bg fires intent (taskToFront = false, sourceRecord is available)
            // 3. activity in bg fires intent with NEW_FLAG (taskToFront = true,
            //         avoidMoveTaskToFront = true, sourceRecord is available)
            // 4. activity in bg fires PI (taskToFront = true, avoidMoveTaskToFront = true,
            //         sourceRecord is not available, targetTask may be available)
            if (!taskToFront || avoidMoveTaskToFront) {
                if (targetTask != null) {
                    FinishedActivityEntry finishedEntry =
                            mTaskIdToFinishedActivity.get(targetTask.mTaskId);
                    if (finishedEntry != null && finishedEntry.mUid == callingUid) {
                        return true;
                    }
                }

                if (sourceRecord != null) {
                    FinishedActivityEntry finishedEntry =
                            mTaskIdToFinishedActivity.get(sourceRecord.getTask().mTaskId);
                    if (finishedEntry != null && finishedEntry.mUid == callingUid) {
                        return true;
                    }
                }
            }
        }

        BlockActivityStart bas = null;
@@ -1098,7 +1122,7 @@ public class BackgroundActivityStartController {
                bas = isTopActivityMatchingUidAbsentForAsm(taskToCheck, sourceRecord.getUid(),
                        sourceRecord);
            }
        } else if (!taskToFront) {
        } else if (targetTask != null && (!taskToFront || avoidMoveTaskToFront)) {
            // We don't have a sourceRecord, and we're launching into an existing task.
            // Allow if callingUid is top of stack.
            bas = isTopActivityMatchingUidAbsentForAsm(targetTask, callingUid,
@@ -1111,12 +1135,14 @@ public class BackgroundActivityStartController {

        // ASM rules have failed. Log why
        return logAsmFailureAndCheckFeatureEnabled(sourceRecord, callingUid, realCallingUid,
                newTask, targetTask, targetRecord, balCode, launchFlags, bas, taskToFront);
                newTask, avoidMoveTaskToFront, targetTask, targetRecord, balCode, launchFlags,
                bas, taskToFront);
    }

    private boolean logAsmFailureAndCheckFeatureEnabled(ActivityRecord sourceRecord, int callingUid,
            int realCallingUid, boolean newTask, Task targetTask, ActivityRecord targetRecord,
            @BalCode int balCode, int launchFlags, BlockActivityStart bas, boolean taskToFront) {
            int realCallingUid, boolean newTask, boolean avoidMoveTaskToFront, Task targetTask,
            ActivityRecord targetRecord, @BalCode int balCode, int launchFlags,
            BlockActivityStart bas, boolean taskToFront) {

        ActivityRecord targetTopActivity = targetTask == null ? null
                : targetTask.getActivity(ar -> !ar.finishing && !ar.isAlwaysOnTop());
@@ -1133,7 +1159,7 @@ public class BackgroundActivityStartController {

        String asmDebugInfo = getDebugInfoForActivitySecurity("Launch", sourceRecord,
                targetRecord, targetTask, targetTopActivity, realCallingUid, balCode,
                blockActivityStartAndFeatureEnabled, taskToFront);
                blockActivityStartAndFeatureEnabled, taskToFront, avoidMoveTaskToFront);

        FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED,
                /* caller_uid */
@@ -1265,7 +1291,7 @@ public class BackgroundActivityStartController {

            Slog.i(TAG, getDebugInfoForActivitySecurity("Clear Top", sourceRecord, targetRecord,
                    targetTask, targetTaskTop, realCallingUid, balCode, shouldBlockActivityStart,
                    /* taskToFront */ true));
                    /* taskToFront */ true, /* avoidMoveTaskToFront */ false));
        }
    }

@@ -1379,7 +1405,7 @@ public class BackgroundActivityStartController {
    private BlockActivityStart isTopActivityMatchingUidAbsentForAsm(@NonNull Task task,
            int uid, @Nullable ActivityRecord sourceRecord) {
        // If the source is visible, consider it 'top'.
        if (sourceRecord != null && sourceRecord.isVisible()) {
        if (sourceRecord != null && sourceRecord.isVisibleRequested()) {
            return new BlockActivityStart(false, false);
        }

@@ -1389,6 +1415,12 @@ public class BackgroundActivityStartController {
            return new BlockActivityStart(false, false);
        }

        // If UID is visible in target task, allow launch
        if (task.forAllActivities((Predicate<ActivityRecord>)
                ar -> ar.isUid(uid) && ar.isVisibleRequested())) {
            return new BlockActivityStart(false, false);
        }

        // Consider the source activity, whether or not it is finishing. Do not consider any other
        // finishing activity.
        Predicate<ActivityRecord> topOfStackPredicate = (ar) -> ar.equals(sourceRecord)
@@ -1480,27 +1512,26 @@ public class BackgroundActivityStartController {
            @Nullable ActivityRecord sourceRecord, @NonNull ActivityRecord targetRecord,
            @Nullable Task targetTask, @Nullable ActivityRecord targetTopActivity,
            int realCallingUid, @BalCode int balCode,
            boolean blockActivityStartAndFeatureEnabled, boolean taskToFront) {
            boolean blockActivityStartAndFeatureEnabled, boolean taskToFront,
            boolean avoidMoveTaskToFront) {
        final String prefix = "[ASM] ";
        Function<ActivityRecord, String> recordToString = (ar) -> {
            if (ar == null) {
                return null;
            }

            return (ar == sourceRecord ?        " [source]=> "
                    : ar == targetTopActivity ? " [ top  ]=> "
                    : ar == targetRecord ?      " [target]=> "
                    :                           "         => ")
                    + ar
                    + " :: visible=" + ar.isVisible()
                    + ", finishing=" + ar.isFinishing()
                    + ", alwaysOnTop=" + ar.isAlwaysOnTop()
                    + ", taskFragment=" + ar.getTaskFragment();
                    + getDebugStringForActivityRecord(ar);
        };

        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);
        joiner.add(prefix + "System Time: " + SystemClock.uptimeMillis());

        boolean targetTaskMatchesSourceTask = targetTask != null
                && sourceRecord != null && sourceRecord.getTask() == targetTask;
@@ -1512,6 +1543,8 @@ public class BackgroundActivityStartController {
            joiner.add(prefix + "Real Calling Uid Package: " + realCallingPackage);
        } else {
            joiner.add(prefix + "Source Record: " + recordToString.apply(sourceRecord));
            joiner.add(prefix + "Source Launch Package: " + sourceRecord.launchedFromPackage);
            joiner.add(prefix + "Source Launch Intent: " + sourceRecord.intent);
            if (targetTaskMatchesSourceTask) {
                joiner.add(prefix + "Source/Target Task: " + sourceRecord.getTask());
                joiner.add(prefix + "Source/Target Task Stack: ");
@@ -1536,7 +1569,30 @@ public class BackgroundActivityStartController {
        joiner.add(prefix + "Target Record: " + recordToString.apply(targetRecord));
        joiner.add(prefix + "Intent: " + targetRecord.intent);
        joiner.add(prefix + "TaskToFront: " + taskToFront);
        joiner.add(prefix + "AvoidMoveToFront: " + avoidMoveTaskToFront);
        joiner.add(prefix + "BalCode: " + balCodeToString(balCode));
        joiner.add(prefix + "LastResumedActivity: "
                       + recordToString.apply(mService.mLastResumedActivity));

        if (mTopFinishedActivity != null) {
            joiner.add(prefix + "TopFinishedActivity: " + mTopFinishedActivity.mDebugInfo);
        }

        if (!mTaskIdToFinishedActivity.isEmpty()) {
            joiner.add(prefix + "TaskIdToFinishedActivity: ");
            mTaskIdToFinishedActivity.values().forEach(
                    (fae) -> joiner.add(prefix + "  " + fae.mDebugInfo));
        }

        if (balCode == BAL_ALLOW_VISIBLE_WINDOW || balCode == BAL_ALLOW_NON_APP_VISIBLE_WINDOW
                || balCode == BAL_ALLOW_FOREGROUND) {
            Task task = sourceRecord != null ? sourceRecord.getTask() : targetTask;
            if (task != null && task.getDisplayArea() != null) {
                joiner.add(prefix + "Tasks: ");
                task.getDisplayArea().forAllTasks((Consumer<Task>)
                        t -> joiner.add(prefix + "   T: " + t.toFullString()));
            }
        }

        joiner.add(prefix + "------ Activity Security " + action + " Debug Logging End ------");
        return joiner.toString();
@@ -1620,7 +1676,7 @@ public class BackgroundActivityStartController {
            return;
        }

        if (!finishActivity.mVisibleRequested
        if (!finishActivity.isVisibleRequested()
                && finishActivity != finishActivity.getTask().getTopMostActivity()) {
            return;
        }
@@ -1666,10 +1722,22 @@ public class BackgroundActivityStartController {
        }
    }

    private static String getDebugStringForActivityRecord(ActivityRecord ar) {
        return ar
                + " :: visible=" + ar.isVisible()
                + ", visibleRequested=" + ar.isVisibleRequested()
                + ", finishing=" + ar.isFinishing()
                + ", alwaysOnTop=" + ar.isAlwaysOnTop()
                + ", lastLaunchTime=" + ar.lastLaunchTime
                + ", lastVisibleTime=" + ar.lastVisibleTime
                + ", taskFragment=" + ar.getTaskFragment();
    }

    private class FinishedActivityEntry {
        int mUid;
        int mTaskId;
        int mLaunchCount;
        String mDebugInfo;

        FinishedActivityEntry(ActivityRecord ar) {
            FinishedActivityEntry entry = mTaskIdToFinishedActivity.get(ar.getTask().mTaskId);
@@ -1677,6 +1745,7 @@ public class BackgroundActivityStartController {
            this.mUid = ar.getUid();
            this.mTaskId = taskId;
            this.mLaunchCount = entry == null || !ar.isUid(entry.mUid) ? 1 : entry.mLaunchCount + 1;
            this.mDebugInfo = getDebugStringForActivityRecord(ar);

            mService.mH.postDelayed(() -> {
                synchronized (mService.mGlobalLock) {