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

Commit 0ad4e2fd authored by Michal Karpinski's avatar Michal Karpinski
Browse files

Allow background activity starts if realCallingUid is in

the foreground

Most notably adds support for:
- shortcuts (not PendingIntent-based, but realCallingUid is launcher,
which is foreground at the time of clicking)
- notifications, slices, actions and widgets (but only those that
are based on PendingIntent.getActivity() - trampolines are not yet
supported)

Note: this currently also allows PendingIntent-based starts for many
use cases where it's a persistent system process calling send(), but
we won't be allowing them anymore in forthcoming CLs (most notably
the AlarmManager use cases).

Bug: 110956953
Test: atest WmTests:ActivityStarterTests
Test: manual
Change-Id: I3c9de8cbe76bef5cc99d721536e19bb39b03405f
parent 8dac427f
Loading
Loading
Loading
Loading
+13 −6
Original line number Diff line number Diff line
@@ -738,7 +738,8 @@ class ActivityStarter {
        // not sure if we need to create START_ABORTED_BACKGROUND so for now piggybacking
        // on START_ABORTED
        if (!abort) {
            abort |= shouldAbortBackgroundActivityStart(callingUid, callingPackage, callerApp);
            abort |= shouldAbortBackgroundActivityStart(callingUid, callingPackage, realCallingUid,
                    callerApp);
        }

        // Merge the two options bundles, while realCallerOptions takes precedence.
@@ -886,7 +887,7 @@ class ActivityStarter {
    }

    private boolean shouldAbortBackgroundActivityStart(int callingUid, final String callingPackage,
            WindowProcessController callerApp) {
            int realCallingUid, WindowProcessController callerApp) {
        if (mService.isBackgroundActivityStartsEnabled()) {
            return false;
        }
@@ -898,12 +899,12 @@ class ActivityStarter {
        if (callerApp != null && callerApp.hasForegroundActivities()) {
            return false;
        }
        // don't abort if the callingUid's process is important enough
        if (mService.getUidStateLocked(callingUid) <= ActivityManager.PROCESS_STATE_TOP) {
        // don't abort if the callingUid is in the foreground
        if (isUidForeground(callingUid)) {
            return false;
        }
        // don't abort if the callingUid has any visible window
        if (mService.mWindowManager.isAnyWindowVisibleForUid(callingUid)) {
        // don't abort if the realCallingUid is in the foreground and callingUid isn't
        if ((realCallingUid != callingUid) && isUidForeground(realCallingUid)) {
            return false;
        }
        // don't abort if the caller has the same uid as the recents component
@@ -920,6 +921,12 @@ class ActivityStarter {
        return true;
    }

    /** Returns true if uid has a visible window or its process is in top or persistent state. */
    private boolean isUidForeground(int uid) {
        return (mService.getUidStateLocked(uid) <= ActivityManager.PROCESS_STATE_TOP)
            || mService.mWindowManager.isAnyWindowVisibleForUid(uid);
    }

    private void maybeLogActivityStart(int callingUid, String callingPackage, int realCallingUid,
            Intent intent, WindowProcessController callerApp, ActivityRecord r,
            PendingIntentRecord originatingPendingIntent, boolean abortedStart) {
+64 −25
Original line number Diff line number Diff line
@@ -113,6 +113,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
    private static final int FAKE_REAL_CALLING_UID = 667;
    private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude";
    private static final int UNIMPORTANT_UID = 12345;
    private static final int UNIMPORTANT_UID2 = 12346;

    @Before
    public void setUp() throws Exception {
@@ -561,8 +562,10 @@ public class ActivityStarterTests extends ActivityTestsBase {
    public void testBackgroundActivityStartsAllowed_noStartsAborted() {
        doReturn(true).when(mService).isBackgroundActivityStartsEnabled();

        runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted",
                false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, false, false);
        runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false,
                UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
                false, false);
    }

    /**
@@ -573,8 +576,11 @@ public class ActivityStarterTests extends ActivityTestsBase {
    public void testBackgroundActivityStartsDisallowed_unsupportedStartsAborted() {
        doReturn(false).when(mService).isBackgroundActivityStartsEnabled();

        runAndVerifyBackgroundActivityStartsSubtest("disallowed_unsupportedUsecase_aborted",
                true, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, false, false);
        runAndVerifyBackgroundActivityStartsSubtest(
                "disallowed_unsupportedUsecase_aborted", true,
                UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
                false, false);
    }

    /**
@@ -586,44 +592,77 @@ public class ActivityStarterTests extends ActivityTestsBase {
    public void testBackgroundActivityStartsDisallowed_supportedStartsNotAborted() {
        doReturn(false).when(mService).isBackgroundActivityStartsEnabled();

        runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted",
                false, Process.ROOT_UID, false, PROCESS_STATE_TOP + 1, false, false);
        runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted",
                false, Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1, false, false);
        runAndVerifyBackgroundActivityStartsSubtest("disallowed_hasVisibleWindow_notAborted",
                false, UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1, false, false);
        runAndVerifyBackgroundActivityStartsSubtest("disallowed_processStateTop_notAborted",
                false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP, false, false);
        runAndVerifyBackgroundActivityStartsSubtest("disallowed_hasForegroundActivities_notAborted",
                false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, true, false);
        runAndVerifyBackgroundActivityStartsSubtest("disallowed_callerIsRecents_notAborted",
                false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, false, true);
        runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false,
                Process.ROOT_UID, false, PROCESS_STATE_TOP + 1,
                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
                false, false);
        runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false,
                Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1,
                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
                false, false);
        runAndVerifyBackgroundActivityStartsSubtest(
                "disallowed_callingUidHasVisibleWindow_notAborted", false,
                UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1,
                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
                false, false);
        runAndVerifyBackgroundActivityStartsSubtest(
                "disallowed_callingUidProcessStateTop_notAborted", false,
                UNIMPORTANT_UID, false, PROCESS_STATE_TOP,
                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
                false, false);
        runAndVerifyBackgroundActivityStartsSubtest(
                "disallowed_realCallingUidHasVisibleWindow_notAborted", false,
                UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
                UNIMPORTANT_UID2, true, PROCESS_STATE_TOP + 1,
                false, false);
        runAndVerifyBackgroundActivityStartsSubtest(
                "disallowed_realCallingUidProcessStateTop_notAborted", false,
                UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP,
                false, false);
        runAndVerifyBackgroundActivityStartsSubtest(
                "disallowed_hasForegroundActivities_notAborted", false,
                UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
                true, false);
        runAndVerifyBackgroundActivityStartsSubtest(
                "disallowed_callerIsRecents_notAborted", false,
                UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
                false, true);
    }

    private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
            int testCallingUid, boolean hasVisibleWindow, int procState,
            int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
            int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,
            boolean hasForegroundActivities, boolean callerIsRecents) {
        // window visibility
        doReturn(hasVisibleWindow).when(mService.mWindowManager).isAnyWindowVisibleForUid(
                testCallingUid);
        doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager).isAnyWindowVisibleForUid(
                callingUid);
        doReturn(realCallingUidHasVisibleWindow).when(mService.mWindowManager)
                .isAnyWindowVisibleForUid(realCallingUid);
        // process importance
        doReturn(procState).when(mService).getUidStateLocked(testCallingUid);
        doReturn(callingUidProcState).when(mService).getUidStateLocked(callingUid);
        doReturn(realCallingUidProcState).when(mService).getUidStateLocked(realCallingUid);
        // foreground activities
        final IApplicationThread caller = mock(IApplicationThread.class);
        final ApplicationInfo ai = new ApplicationInfo();
        ai.uid = testCallingUid;
        ai.uid = callingUid;
        final WindowProcessController callerApp =
                new WindowProcessController(mService, ai, null, testCallingUid, -1, null, null);
                new WindowProcessController(mService, ai, null, callingUid, -1, null, null);
        callerApp.setHasForegroundActivities(hasForegroundActivities);
        doReturn(callerApp).when(mService).getProcessController(caller);
        // caller is recents
        RecentTasks recentTasks = mock(RecentTasks.class);
        mService.mStackSupervisor.setRecentTasks(recentTasks);
        doReturn(callerIsRecents).when(recentTasks).isCallerRecents(testCallingUid);
        doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid);

        final ActivityOptions options = spy(ActivityOptions.makeBasic());
        ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK).setCaller(caller)
                .setCallingUid(testCallingUid).setActivityOptions(new SafeActivityOptions(options));
        ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
                .setCaller(caller)
                .setCallingUid(callingUid)
                .setRealCallingUid(realCallingUid)
                .setActivityOptions(new SafeActivityOptions(options));

        final int result = starter.setReason("testBackgroundActivityStarts_" + name).execute();