Merge "Check all tasks for good intent launch when creating channels" into tm-dev
This commit is contained in:
@@ -3746,6 +3746,10 @@ public class NotificationManagerService extends SystemService {
|
||||
if (!hadChannel && hasChannel && !hasRequestedNotificationPermission
|
||||
&& startingTaskId != ActivityTaskManager.INVALID_TASK_ID) {
|
||||
hasRequestedNotificationPermission = true;
|
||||
if (mPermissionPolicyInternal == null) {
|
||||
mPermissionPolicyInternal =
|
||||
LocalServices.getService(PermissionPolicyInternal.class);
|
||||
}
|
||||
mHandler.post(new ShowNotificationPermissionPromptRunnable(pkg,
|
||||
UserHandle.getUserId(uid), startingTaskId,
|
||||
mPermissionPolicyInternal));
|
||||
@@ -3764,19 +3768,7 @@ public class NotificationManagerService extends SystemService {
|
||||
try {
|
||||
int uid = mPackageManager.getPackageUid(pkg, 0,
|
||||
UserHandle.getUserId(Binder.getCallingUid()));
|
||||
List<ActivityManager.AppTask> tasks = mAtm.getAppTasks(pkg, uid);
|
||||
for (int i = 0; i < tasks.size(); i++) {
|
||||
ActivityManager.RecentTaskInfo task = tasks.get(i).getTaskInfo();
|
||||
if (mPermissionPolicyInternal == null) {
|
||||
mPermissionPolicyInternal =
|
||||
LocalServices.getService(PermissionPolicyInternal.class);
|
||||
}
|
||||
if (mPermissionPolicyInternal != null
|
||||
&& mPermissionPolicyInternal.canShowPermissionPromptForTask(task)) {
|
||||
taskId = task.taskId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
taskId = mAtm.getTaskToShowPermissionDialogOn(pkg, uid);
|
||||
} catch (RemoteException e) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ public abstract class PermissionPolicyInternal {
|
||||
* prompt should be shown if the app targets S-, is currently running in a visible, focused
|
||||
* task, has the REVIEW_REQUIRED flag set on its implicit notification permission, and has
|
||||
* created at least one notification channel (even if it has since been deleted).
|
||||
*
|
||||
* @param packageName The package whose permission is being checked
|
||||
* @param userId The user for whom the package is being started
|
||||
* @param taskId The task the notification prompt should be attached to
|
||||
@@ -66,10 +67,22 @@ public abstract class PermissionPolicyInternal {
|
||||
|
||||
/**
|
||||
* Determine if a particular task is in the proper state to show a system-triggered permission
|
||||
* prompt. A prompt can be shown if the task is focused, visible, and running.
|
||||
* prompt. A prompt can be shown if the task is focused, visible, and running and
|
||||
* 1. The intent is a launcher intent (action is ACTION_MAIN, category is LAUNCHER), or
|
||||
* 2. The activity belongs to the same package as the one which launched the task originally,
|
||||
* and the task was started with a launcher intent
|
||||
*
|
||||
* @param taskInfo The task to be checked
|
||||
* @param currPkg The package of the current top visible activity
|
||||
* @param intent The intent of the current top visible activity
|
||||
*/
|
||||
public abstract boolean canShowPermissionPromptForTask(@Nullable TaskInfo taskInfo);
|
||||
public abstract boolean shouldShowNotificationDialogForTask(@Nullable TaskInfo taskInfo,
|
||||
@Nullable String currPkg, @Nullable Intent intent);
|
||||
|
||||
/**
|
||||
* @return true if an intent will resolve to a permission request dialog activity
|
||||
*/
|
||||
public abstract boolean isIntentToPermissionDialog(@NonNull Intent intent);
|
||||
|
||||
/**
|
||||
* @return Whether the policy is initialized for a user.
|
||||
|
||||
@@ -21,6 +21,8 @@ import static android.app.AppOpsManager.MODE_ALLOWED;
|
||||
import static android.app.AppOpsManager.MODE_FOREGROUND;
|
||||
import static android.app.AppOpsManager.MODE_IGNORED;
|
||||
import static android.app.AppOpsManager.OP_NONE;
|
||||
import static android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS;
|
||||
import static android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER;
|
||||
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
|
||||
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
|
||||
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
|
||||
@@ -1016,7 +1018,7 @@ public final class PermissionPolicyService extends SystemService {
|
||||
ActivityInterceptorInfo info) {
|
||||
String action = info.intent.getAction();
|
||||
ActivityInterceptResult result = null;
|
||||
if (!PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(action)
|
||||
if (!ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(action)
|
||||
&& !PackageManager.ACTION_REQUEST_PERMISSIONS.equals(action)) {
|
||||
return null;
|
||||
}
|
||||
@@ -1033,7 +1035,7 @@ public final class PermissionPolicyService extends SystemService {
|
||||
&& !mContinueNotifGrantMessageUids.contains(info.realCallingUid)) {
|
||||
return result;
|
||||
}
|
||||
if (PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(action)) {
|
||||
if (ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(action)) {
|
||||
String otherPkg = info.intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
|
||||
if (otherPkg == null || (mPackageManager.getPermissionFlags(
|
||||
POST_NOTIFICATIONS, otherPkg, UserHandle.of(info.userId))
|
||||
@@ -1052,8 +1054,8 @@ public final class PermissionPolicyService extends SystemService {
|
||||
public void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo,
|
||||
ActivityInterceptorInfo info) {
|
||||
super.onActivityLaunched(taskInfo, activityInfo, info);
|
||||
if (!shouldShowNotificationDialogOrClearFlags(info.intent,
|
||||
info.checkedOptions)) {
|
||||
if (!shouldShowNotificationDialogOrClearFlags(taskInfo,
|
||||
activityInfo.packageName, info.intent, info.checkedOptions, true)) {
|
||||
return;
|
||||
}
|
||||
UserHandle user = UserHandle.of(taskInfo.userId);
|
||||
@@ -1085,7 +1087,7 @@ public final class PermissionPolicyService extends SystemService {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(intent.getAction())
|
||||
if (ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(intent.getAction())
|
||||
&& (callingUid != Process.SYSTEM_UID || !SYSTEM_PKG.equals(callingPackage))) {
|
||||
return false;
|
||||
}
|
||||
@@ -1104,18 +1106,48 @@ public final class PermissionPolicyService extends SystemService {
|
||||
launchNotificationPermissionRequestDialog(packageName, user, taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIntentToPermissionDialog(@NonNull Intent intent) {
|
||||
return Objects.equals(intent.getPackage(),
|
||||
mPackageManager.getPermissionControllerPackageName())
|
||||
&& (Objects.equals(intent.getAction(), ACTION_REQUEST_PERMISSIONS_FOR_OTHER)
|
||||
|| Objects.equals(intent.getAction(), ACTION_REQUEST_PERMISSIONS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldShowNotificationDialogForTask(TaskInfo taskInfo, String currPkg,
|
||||
Intent intent) {
|
||||
return shouldShowNotificationDialogOrClearFlags(
|
||||
taskInfo, currPkg, intent, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we should show a notification dialog, or clear the REVIEW_REQUIRED flag,
|
||||
* from a particular package for a particular intent. Returns true if:
|
||||
* Determine if a particular task is in the proper state to show a system-triggered
|
||||
* permission prompt. A prompt can be shown if the task is just starting, or the task is
|
||||
* currently focused, visible, and running, and,
|
||||
* 1. The isEligibleForLegacyPermissionPrompt ActivityOption is set, or
|
||||
* 2. The intent is a launcher intent (action is ACTION_MAIN, category is LAUNCHER)
|
||||
* 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
|
||||
* @param taskInfo The task to be checked
|
||||
* @param currPkg The package of the current top visible activity
|
||||
* @param intent The intent of the current top visible activity
|
||||
*/
|
||||
private boolean shouldShowNotificationDialogOrClearFlags(Intent intent,
|
||||
ActivityOptions options) {
|
||||
if ((options != null && options.isEligibleForLegacyPermissionPrompt())) {
|
||||
return true;
|
||||
private boolean shouldShowNotificationDialogOrClearFlags(TaskInfo taskInfo, String currPkg,
|
||||
Intent intent, ActivityOptions options, boolean activityStart) {
|
||||
if (intent == null || currPkg == null || taskInfo == null
|
||||
|| (!(taskInfo.isFocused && taskInfo.isVisible && taskInfo.isRunning)
|
||||
&& !activityStart)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isLauncherIntent(intent)
|
||||
|| (options != null && options.isEligibleForLegacyPermissionPrompt())
|
||||
|| (currPkg.equals(taskInfo.baseActivity.getPackageName())
|
||||
&& isLauncherIntent(taskInfo.baseIntent));
|
||||
}
|
||||
|
||||
private boolean isLauncherIntent(Intent intent) {
|
||||
return Intent.ACTION_MAIN.equals(intent.getAction())
|
||||
&& intent.getCategories() != null
|
||||
&& (intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)
|
||||
@@ -1144,7 +1176,7 @@ public final class PermissionPolicyService extends SystemService {
|
||||
Intent grantPermission = mPackageManager
|
||||
.buildRequestPermissionsIntent(new String[] { POST_NOTIFICATIONS });
|
||||
grantPermission.setAction(
|
||||
PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER);
|
||||
ACTION_REQUEST_PERMISSIONS_FOR_OTHER);
|
||||
grantPermission.putExtra(Intent.EXTRA_PACKAGE_NAME, pkgName);
|
||||
|
||||
ActivityOptions options = new ActivityOptions(new Bundle());
|
||||
@@ -1170,12 +1202,6 @@ public final class PermissionPolicyService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canShowPermissionPromptForTask(@Nullable TaskInfo taskInfo) {
|
||||
return taskInfo != null && taskInfo.isFocused && taskInfo.isVisible
|
||||
&& taskInfo.isRunning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the intent action is removed for the calling package (often based on target SDK
|
||||
* version). If the action is removed, we'll silently cancel the activity launch.
|
||||
|
||||
@@ -680,4 +680,15 @@ public abstract class ActivityTaskManagerInternal {
|
||||
|
||||
/** Get the app tasks for a package */
|
||||
public abstract List<ActivityManager.AppTask> getAppTasks(String pkgName, int uid);
|
||||
|
||||
/**
|
||||
* Determine if there exists a task which meets the criteria set by the PermissionPolicyService
|
||||
* to show a system-owned permission dialog over, for a given package
|
||||
* @see PermissionPolicyInternal.shouldShowNotificationDialogForTask
|
||||
*
|
||||
* @param pkgName The package whose activity must be top
|
||||
* @param uid The uid that must have a top activity
|
||||
* @return a task ID if a valid task ID is found. Otherwise, return INVALID_TASK_ID
|
||||
*/
|
||||
public abstract int getTaskToShowPermissionDialogOn(String pkgName, int uid);
|
||||
}
|
||||
|
||||
@@ -6754,5 +6754,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
}
|
||||
return tasks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTaskToShowPermissionDialogOn(String pkgName, int uid) {
|
||||
synchronized (ActivityTaskManagerService.this.mGlobalLock) {
|
||||
return ActivityTaskManagerService.this.mRootWindowContainer
|
||||
.getTaskToShowPermissionDialogOn(pkgName, uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +149,7 @@ import com.android.server.LocalServices;
|
||||
import com.android.server.am.ActivityManagerService;
|
||||
import com.android.server.am.AppTimeTracker;
|
||||
import com.android.server.am.UserState;
|
||||
import com.android.server.policy.PermissionPolicyInternal;
|
||||
import com.android.server.policy.WindowManagerPolicy;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
@@ -3331,6 +3332,36 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
|
||||
mService.startLaunchPowerMode(reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over all task fragments, to see if there exists one that meets the
|
||||
* PermissionPolicyService's criteria to show a permission dialog.
|
||||
*/
|
||||
public int getTaskToShowPermissionDialogOn(String pkgName, int uid) {
|
||||
PermissionPolicyInternal pPi = mService.getPermissionPolicyInternal();
|
||||
if (pPi == null) {
|
||||
return INVALID_TASK_ID;
|
||||
}
|
||||
|
||||
final int[] validTaskId = {INVALID_TASK_ID};
|
||||
forAllLeafTaskFragments(fragment -> {
|
||||
ActivityRecord record = fragment.getActivity((r) -> {
|
||||
// skip hidden (or about to hide) apps, or the permission dialog
|
||||
return r.canBeTopRunning() && r.isVisibleRequested()
|
||||
&& !pPi.isIntentToPermissionDialog(r.intent);
|
||||
});
|
||||
if (record != null && record.isUid(uid)
|
||||
&& Objects.equals(pkgName, record.packageName)
|
||||
&& pPi.shouldShowNotificationDialogForTask(record.getTask().getTaskInfo(),
|
||||
pkgName, record.intent)) {
|
||||
validTaskId[0] = record.getTask().mTaskId;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
return validTaskId[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the activities matching the given {@param name} in the either the focused root task
|
||||
* or all visible root tasks if {@param dumpVisibleRootTasksOnly} is true.
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.server.notification;
|
||||
|
||||
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
|
||||
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
|
||||
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
|
||||
import static android.app.AppOpsManager.MODE_ALLOWED;
|
||||
import static android.app.AppOpsManager.MODE_IGNORED;
|
||||
import static android.app.Notification.FLAG_AUTO_CANCEL;
|
||||
@@ -432,8 +433,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
|
||||
when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{PKG});
|
||||
when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{PKG});
|
||||
when(mPermissionPolicyInternal.canShowPermissionPromptForTask(
|
||||
any(ActivityManager.RecentTaskInfo.class))).thenReturn(false);
|
||||
when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt()))
|
||||
.thenReturn(INVALID_TASK_ID);
|
||||
mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
|
||||
when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0});
|
||||
|
||||
@@ -971,8 +972,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
@Test
|
||||
public void testCreateNotificationChannels_FirstChannelWithFgndTaskStartsPermDialog()
|
||||
throws Exception {
|
||||
when(mPermissionPolicyInternal.canShowPermissionPromptForTask(any(
|
||||
ActivityManager.RecentTaskInfo.class))).thenReturn(true);
|
||||
when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID);
|
||||
final NotificationChannel channel =
|
||||
new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
|
||||
mBinderService.createNotificationChannels(PKG_NO_CHANNELS,
|
||||
@@ -985,8 +985,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
@Test
|
||||
public void testCreateNotificationChannels_SecondChannelWithFgndTaskDoesntStartPermDialog()
|
||||
throws Exception {
|
||||
when(mPermissionPolicyInternal.canShowPermissionPromptForTask(any(
|
||||
ActivityManager.RecentTaskInfo.class))).thenReturn(true);
|
||||
when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID);
|
||||
assertTrue(mBinderService.getNumNotificationChannelsForPackage(PKG, mUid, true) > 0);
|
||||
|
||||
final NotificationChannel channel =
|
||||
@@ -1001,8 +1000,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
public void testCreateNotificationChannels_FirstChannelWithBgndTaskDoesntStartPermDialog()
|
||||
throws Exception {
|
||||
reset(mPermissionPolicyInternal);
|
||||
when(mPermissionPolicyInternal.canShowPermissionPromptForTask(any(
|
||||
ActivityManager.RecentTaskInfo.class))).thenReturn(false);
|
||||
when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID);
|
||||
|
||||
final NotificationChannel channel =
|
||||
new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
|
||||
|
||||
Reference in New Issue
Block a user