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

Commit c003dda6 authored by Hani Kazmi's avatar Hani Kazmi
Browse files

Clear out top activities not matching launched uid in task

This change is a continuation of ag/20482146. If we have task1 with
activities A1,B1, a task2 in the foreground could launch A2 with the
NEWTASK flag, and affinity for A1 - causing an activity sandwich we
wish to prevent. Hence, we clear out all activities not matching A's
UID when A2 is launched with NEW_TASK.

Test: atest ActivitySecurityModelTest
Test: manually tested on device
Bug: 248045984
Change-Id: Ia90b197aa7d41f91a7f8cc51b572cd344619c6ad
parent da1d1ff3
Loading
Loading
Loading
Loading
+50 −0
Original line number Diff line number Diff line
@@ -2080,6 +2080,7 @@ class ActivityStarter {
                reusedTask != null ? reusedTask.getTopNonFinishingActivity() : null, intentGrants);

        if (mAddingToTask) {
            clearTopIfNeeded(targetTask, mCallingUid, mStartActivity.getUid(), mLaunchFlags);
            return START_SUCCESS;
        }

@@ -2111,6 +2112,55 @@ class ActivityStarter {
        return mMovedToFront ? START_TASK_TO_FRONT : START_DELIVERED_TO_TOP;
    }

    /**
     * If the top activity uid does not match the launched activity, and the launch was not
     * requested from the top uid, we want to clear out all non matching activities to prevent the
     * top activity being sandwiched.
     */
    private void clearTopIfNeeded(@NonNull Task targetTask, int callingUid, int startingUid,
            int launchFlags) {
        if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != FLAG_ACTIVITY_NEW_TASK) {
            // Launch is from the same task, so must be a top or privileged UID
            return;
        }

        ActivityRecord targetTaskTop = targetTask.getTopNonFinishingActivity();
        if (targetTaskTop != null && targetTaskTop.getUid() != startingUid) {
            boolean shouldBlockActivityStart = ActivitySecurityModelFeatureFlags
                    .shouldBlockActivityStart(callingUid);
            int[] finishCount = new int[0];
            if (shouldBlockActivityStart) {
                ActivityRecord activity = targetTask.getActivity(
                        ar -> !ar.finishing && ar.isUid(startingUid));

                if (activity == null) {
                    // mStartActivity is not in task, so clear everything
                    activity = mStartActivity;
                }

                finishCount = new int[1];
                if (activity != null) {
                    targetTask.performClearTop(activity, launchFlags, finishCount);
                }

                if (finishCount[0] > 0) {
                    Slog.w(TAG, "Clearing top n: " + finishCount[0] + " activities from task t: "
                            + targetTask + " not matching top uid: " + callingUid);
                }
            }

            if (ActivitySecurityModelFeatureFlags.shouldShowToast(callingUid)
                    && (!shouldBlockActivityStart || finishCount[0] > 0)) {
                UiThread.getHandler().post(() -> Toast.makeText(mService.mContext,
                        (shouldBlockActivityStart
                                ? "Top activities cleared by "
                                : "Top activities would be cleared by ")
                                + ActivitySecurityModelFeatureFlags.DOC_LINK,
                        Toast.LENGTH_SHORT).show());
            }
        }
    }

    /**
     * Check if the activity being launched is the same as the one currently at the top and it
     * should only be launched once.