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

Commit 7585a958 authored by Nate Myren's avatar Nate Myren Committed by Android (Google) Code Review
Browse files

Merge "Show Notification Permission dialog on (some) task trampolines" into tm-dev

parents 19a82701 b17596b0
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -74,10 +74,13 @@ public abstract class PermissionPolicyInternal {
     *
     * @param taskInfo The task to be checked
     * @param currPkg The package of the current top visible activity
     * @param callingPkg The package that started the top visible activity
     * @param intent The intent of the current top visible activity
     * @param activityName The name of the current top visible activity
     */
    public abstract boolean shouldShowNotificationDialogForTask(@Nullable TaskInfo taskInfo,
            @Nullable String currPkg, @Nullable Intent intent);
            @Nullable String currPkg, @Nullable String callingPkg, @Nullable Intent intent,
            @NonNull String activityName);

    /**
     * @return true if an intent will resolve to a permission request dialog activity
+56 −11
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.AppOpsManager;
@@ -1166,7 +1167,8 @@ public final class PermissionPolicyService extends SystemService {
                            ActivityInterceptorInfo info) {
                        super.onActivityLaunched(taskInfo, activityInfo, info);
                        if (!shouldShowNotificationDialogOrClearFlags(taskInfo,
                                activityInfo.packageName, info.intent, info.checkedOptions, true)
                                activityInfo.packageName, info.callingPackage, info.intent,
                                info.checkedOptions, activityInfo.name, true)
                                || isNoDisplayActivity(activityInfo)) {
                            return;
                        }
@@ -1237,9 +1239,9 @@ public final class PermissionPolicyService extends SystemService {

        @Override
        public boolean shouldShowNotificationDialogForTask(TaskInfo taskInfo, String currPkg,
                Intent intent) {
            return shouldShowNotificationDialogOrClearFlags(
                    taskInfo, currPkg, intent, null, false);
                String callingPkg, Intent intent, String activityName) {
            return shouldShowNotificationDialogOrClearFlags(taskInfo, currPkg, callingPkg, intent,
                    null, activityName, false);
        }

        private boolean isNoDisplayActivity(@NonNull ActivityInfo aInfo) {
@@ -1265,23 +1267,61 @@ public final class PermissionPolicyService extends SystemService {
         * 1. The isEligibleForLegacyPermissionPrompt ActivityOption is set, or
         * 2. The intent is a launcher intent (action is ACTION_MAIN, category is LAUNCHER), or
         * 3. The activity belongs to the same package as the one which launched the task
         * originally, and the task was started with a launcher intent
         * originally, and the task was started with a launcher intent, or
         * 4. The activity is the first activity in a new task, and was started by the app the
         * activity belongs to, and that app has another task that is currently focused, which was
         * started with a launcher intent. This case seeks to identify cases where an app launches,
         * then immediately trampolines to a new activity and task.
         * @param taskInfo The task to be checked
         * @param currPkg The package of the current top visible activity
         * @param callingPkg The package that initiated this dialog action
         * @param intent The intent of the current top visible activity
         * @param options The ActivityOptions of the newly started activity, if this is called due
         *                to an activity start
         * @param startedActivity The ActivityInfo of the newly started activity, if this is called
         *                        due to an activity start
         */
        private boolean shouldShowNotificationDialogOrClearFlags(TaskInfo taskInfo, String currPkg,
                Intent intent, ActivityOptions options, boolean activityStart) {
            if (intent == null || currPkg == null || taskInfo == null
                String callingPkg, Intent intent, ActivityOptions options,
                String topActivityName, boolean startedActivity) {
            if (intent == null || currPkg == null || taskInfo == null || topActivityName == null
                    || (!(taskInfo.isFocused && taskInfo.isVisible && taskInfo.isRunning)
                    && !activityStart)) {
                    && !startedActivity)) {
                return false;
            }

            return isLauncherIntent(intent)
                    || (options != null && options.isEligibleForLegacyPermissionPrompt())
                    || (currPkg.equals(taskInfo.baseActivity.getPackageName())
                    && isLauncherIntent(taskInfo.baseIntent));
                    || isTaskStartedFromLauncher(currPkg, taskInfo)
                    || (isTaskPotentialTrampoline(topActivityName, currPkg, callingPkg, taskInfo,
                    intent)
                    && (!startedActivity || pkgHasRunningLauncherTask(currPkg, taskInfo)));
        }

        private boolean isTaskPotentialTrampoline(String activityName, String currPkg,
                String callingPkg, TaskInfo taskInfo, Intent intent) {
            return currPkg.equals(callingPkg) && taskInfo.baseIntent.filterEquals(intent)
                    && taskInfo.numActivities == 1
                    && activityName.equals(taskInfo.topActivityInfo.name);
        }

        private boolean pkgHasRunningLauncherTask(String currPkg, TaskInfo taskInfo) {
            ActivityTaskManagerInternal m =
                    LocalServices.getService(ActivityTaskManagerInternal.class);
            try {
                // TODO(b/230616478) Investigate alternatives like ActivityMetricsLaunchObserver
                List<ActivityManager.AppTask> tasks =
                        m.getAppTasks(currPkg, mPackageManager.getPackageUid(currPkg, 0));
                for (int i = 0; i < tasks.size(); i++) {
                    TaskInfo other = tasks.get(i).getTaskInfo();
                    if (other.taskId != taskInfo.taskId && other.isFocused && other.isRunning
                            && isTaskStartedFromLauncher(currPkg, other)) {
                        return true;
                    }
                }
            } catch (PackageManager.NameNotFoundException e) {
                // Fall through
            }
            return false;
        }

        private boolean isLauncherIntent(Intent intent) {
@@ -1292,6 +1332,11 @@ public final class PermissionPolicyService extends SystemService {
                    || intent.getCategories().contains(Intent.CATEGORY_CAR_LAUNCHER));
        }

        private boolean isTaskStartedFromLauncher(String currPkg, TaskInfo taskInfo) {
            return currPkg.equals(taskInfo.baseActivity.getPackageName())
                    && isLauncherIntent(taskInfo.baseIntent);
        }

        private void clearNotificationReviewFlagsIfNeeded(String packageName, UserHandle user) {
            if ((mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, packageName, user)
                    & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
+9 −7
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;

@@ -48,8 +49,9 @@ class AppTaskImpl extends IAppTask.Stub {
        mCallingUid = callingUid;
    }

    private void checkCaller() {
        if (mCallingUid != Binder.getCallingUid()) {
    private void checkCallerOrSystemOrRoot() {
        if (mCallingUid != Binder.getCallingUid() && Process.SYSTEM_UID != Binder.getCallingUid()
                && Process.ROOT_UID != Binder.getCallingUid()) {
            throw new SecurityException("Caller " + mCallingUid
                    + " does not match caller of getAppTasks(): " + Binder.getCallingUid());
        }
@@ -67,7 +69,7 @@ class AppTaskImpl extends IAppTask.Stub {

    @Override
    public void finishAndRemoveTask() {
        checkCaller();
        checkCallerOrSystemOrRoot();

        synchronized (mService.mGlobalLock) {
            final long origId = Binder.clearCallingIdentity();
@@ -85,7 +87,7 @@ class AppTaskImpl extends IAppTask.Stub {

    @Override
    public ActivityManager.RecentTaskInfo getTaskInfo() {
        checkCaller();
        checkCallerOrSystemOrRoot();

        synchronized (mService.mGlobalLock) {
            final long origId = Binder.clearCallingIdentity();
@@ -105,7 +107,7 @@ class AppTaskImpl extends IAppTask.Stub {

    @Override
    public void moveToFront(IApplicationThread appThread, String callingPackage) {
        checkCaller();
        checkCallerOrSystemOrRoot();
        // Will bring task to front if it already has a root activity.
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
@@ -136,7 +138,7 @@ class AppTaskImpl extends IAppTask.Stub {
    @Override
    public int startActivity(IBinder whoThread, String callingPackage, String callingFeatureId,
            Intent intent, String resolvedType, Bundle bOptions) {
        checkCaller();
        checkCallerOrSystemOrRoot();
        mService.assertPackageMatchesCallingUid(callingPackage);

        int callingUser = UserHandle.getCallingUserId();
@@ -167,7 +169,7 @@ class AppTaskImpl extends IAppTask.Stub {

    @Override
    public void setExcludeFromRecents(boolean exclude) {
        checkCaller();
        checkCallerOrSystemOrRoot();

        synchronized (mService.mGlobalLock) {
            final long origId = Binder.clearCallingIdentity();
+1 −1
Original line number Diff line number Diff line
@@ -3382,7 +3382,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
            if (record != null && record.isUid(uid)
                    && Objects.equals(pkgName, record.packageName)
                    && pPi.shouldShowNotificationDialogForTask(record.getTask().getTaskInfo(),
                    pkgName, record.intent)) {
                    pkgName, record.launchedFromPackage, record.intent, record.getName())) {
                validTaskId[0] = record.getTask().mTaskId;
                return true;
            }