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 Original line 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
        // not sure if we need to create START_ABORTED_BACKGROUND so for now piggybacking
        // on START_ABORTED
        // on START_ABORTED
        if (!abort) {
        if (!abort) {
            abort |= shouldAbortBackgroundActivityStart(callingUid, callingPackage, callerApp);
            abort |= shouldAbortBackgroundActivityStart(callingUid, callingPackage, realCallingUid,
                    callerApp);
        }
        }


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


    private boolean shouldAbortBackgroundActivityStart(int callingUid, final String callingPackage,
    private boolean shouldAbortBackgroundActivityStart(int callingUid, final String callingPackage,
            WindowProcessController callerApp) {
            int realCallingUid, WindowProcessController callerApp) {
        if (mService.isBackgroundActivityStartsEnabled()) {
        if (mService.isBackgroundActivityStartsEnabled()) {
            return false;
            return false;
        }
        }
@@ -898,12 +899,12 @@ class ActivityStarter {
        if (callerApp != null && callerApp.hasForegroundActivities()) {
        if (callerApp != null && callerApp.hasForegroundActivities()) {
            return false;
            return false;
        }
        }
        // don't abort if the callingUid's process is important enough
        // don't abort if the callingUid is in the foreground
        if (mService.getUidStateLocked(callingUid) <= ActivityManager.PROCESS_STATE_TOP) {
        if (isUidForeground(callingUid)) {
            return false;
            return false;
        }
        }
        // don't abort if the callingUid has any visible window
        // don't abort if the realCallingUid is in the foreground and callingUid isn't
        if (mService.mWindowManager.isAnyWindowVisibleForUid(callingUid)) {
        if ((realCallingUid != callingUid) && isUidForeground(realCallingUid)) {
            return false;
            return false;
        }
        }
        // don't abort if the caller has the same uid as the recents component
        // don't abort if the caller has the same uid as the recents component
@@ -920,6 +921,12 @@ class ActivityStarter {
        return true;
        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,
    private void maybeLogActivityStart(int callingUid, String callingPackage, int realCallingUid,
            Intent intent, WindowProcessController callerApp, ActivityRecord r,
            Intent intent, WindowProcessController callerApp, ActivityRecord r,
            PendingIntentRecord originatingPendingIntent, boolean abortedStart) {
            PendingIntentRecord originatingPendingIntent, boolean abortedStart) {
+64 −25
Original line number Original line 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 int FAKE_REAL_CALLING_UID = 667;
    private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude";
    private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude";
    private static final int UNIMPORTANT_UID = 12345;
    private static final int UNIMPORTANT_UID = 12345;
    private static final int UNIMPORTANT_UID2 = 12346;


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


        runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted",
        runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false,
                false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, false, 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() {
    public void testBackgroundActivityStartsDisallowed_unsupportedStartsAborted() {
        doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
        doReturn(false).when(mService).isBackgroundActivityStartsEnabled();


        runAndVerifyBackgroundActivityStartsSubtest("disallowed_unsupportedUsecase_aborted",
        runAndVerifyBackgroundActivityStartsSubtest(
                true, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, false, false);
                "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() {
    public void testBackgroundActivityStartsDisallowed_supportedStartsNotAborted() {
        doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
        doReturn(false).when(mService).isBackgroundActivityStartsEnabled();


        runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted",
        runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false,
                false, Process.ROOT_UID, false, PROCESS_STATE_TOP + 1, false, false);
                Process.ROOT_UID, false, PROCESS_STATE_TOP + 1,
        runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted",
                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
                false, Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1, false, false);
                false, false);
        runAndVerifyBackgroundActivityStartsSubtest("disallowed_hasVisibleWindow_notAborted",
        runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false,
                false, UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1, false, false);
                Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1,
        runAndVerifyBackgroundActivityStartsSubtest("disallowed_processStateTop_notAborted",
                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
                false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP, false, false);
                false, false);
        runAndVerifyBackgroundActivityStartsSubtest("disallowed_hasForegroundActivities_notAborted",
        runAndVerifyBackgroundActivityStartsSubtest(
                false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, true, false);
                "disallowed_callingUidHasVisibleWindow_notAborted", false,
        runAndVerifyBackgroundActivityStartsSubtest("disallowed_callerIsRecents_notAborted",
                UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1,
                false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, false, true);
                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,
    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) {
            boolean hasForegroundActivities, boolean callerIsRecents) {
        // window visibility
        // window visibility
        doReturn(hasVisibleWindow).when(mService.mWindowManager).isAnyWindowVisibleForUid(
        doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager).isAnyWindowVisibleForUid(
                testCallingUid);
                callingUid);
        doReturn(realCallingUidHasVisibleWindow).when(mService.mWindowManager)
                .isAnyWindowVisibleForUid(realCallingUid);
        // process importance
        // process importance
        doReturn(procState).when(mService).getUidStateLocked(testCallingUid);
        doReturn(callingUidProcState).when(mService).getUidStateLocked(callingUid);
        doReturn(realCallingUidProcState).when(mService).getUidStateLocked(realCallingUid);
        // foreground activities
        // foreground activities
        final IApplicationThread caller = mock(IApplicationThread.class);
        final IApplicationThread caller = mock(IApplicationThread.class);
        final ApplicationInfo ai = new ApplicationInfo();
        final ApplicationInfo ai = new ApplicationInfo();
        ai.uid = testCallingUid;
        ai.uid = callingUid;
        final WindowProcessController callerApp =
        final WindowProcessController callerApp =
                new WindowProcessController(mService, ai, null, testCallingUid, -1, null, null);
                new WindowProcessController(mService, ai, null, callingUid, -1, null, null);
        callerApp.setHasForegroundActivities(hasForegroundActivities);
        callerApp.setHasForegroundActivities(hasForegroundActivities);
        doReturn(callerApp).when(mService).getProcessController(caller);
        doReturn(callerApp).when(mService).getProcessController(caller);
        // caller is recents
        // caller is recents
        RecentTasks recentTasks = mock(RecentTasks.class);
        RecentTasks recentTasks = mock(RecentTasks.class);
        mService.mStackSupervisor.setRecentTasks(recentTasks);
        mService.mStackSupervisor.setRecentTasks(recentTasks);
        doReturn(callerIsRecents).when(recentTasks).isCallerRecents(testCallingUid);
        doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid);


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


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