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

This commit is contained in:
Nate Myren
2022-04-28 21:49:15 +00:00
committed by Android (Google) Code Review
4 changed files with 70 additions and 20 deletions

View File

@@ -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

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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;
}