summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Nate Myren <ntmyren@google.com> 2022-04-28 21:49:15 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2022-04-28 21:49:15 +0000
commit7585a9580d2748da253f8c6ff81b468eb627e108 (patch)
tree0a37a8321e013a9c0d6ef965fc38b90e05bcfcce
parent19a82701608e7ac93b7aa34f0007dbc931e90f7a (diff)
parentb17596b05127cae7a15d6d127c42bb4501b2c731 (diff)
Merge "Show Notification Permission dialog on (some) task trampolines" into tm-dev
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyInternal.java5
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java67
-rw-r--r--services/core/java/com/android/server/wm/AppTaskImpl.java16
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java2
4 files changed, 70 insertions, 20 deletions
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyInternal.java b/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
index 92b9944b74cf..77885c7ab8ba 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
@@ -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
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 14abc9aabc29..7ba1cadc5c8b 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -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) {
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 6e46fa6b67d0..e80c2607a0ad 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -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();
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index ca4c450a4592..c0dff14e5de5 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -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;
}