Merge "Show Notification Permission dialog on (some) task trampolines" into tm-dev am: 7585a9580d
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17776866 Change-Id: Ib1240c900e7a44b19f7354c98c8470e161c9b889 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -74,10 +74,13 @@ public abstract class PermissionPolicyInternal {
|
|||||||
*
|
*
|
||||||
* @param taskInfo The task to be checked
|
* @param taskInfo The task to be checked
|
||||||
* @param currPkg The package of the current top visible activity
|
* @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 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,
|
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
|
* @return true if an intent will resolve to a permission request dialog activity
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import android.Manifest;
|
|||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.annotation.UserIdInt;
|
import android.annotation.UserIdInt;
|
||||||
|
import android.app.ActivityManager;
|
||||||
import android.app.ActivityOptions;
|
import android.app.ActivityOptions;
|
||||||
import android.app.ActivityTaskManager;
|
import android.app.ActivityTaskManager;
|
||||||
import android.app.AppOpsManager;
|
import android.app.AppOpsManager;
|
||||||
@@ -1166,7 +1167,8 @@ public final class PermissionPolicyService extends SystemService {
|
|||||||
ActivityInterceptorInfo info) {
|
ActivityInterceptorInfo info) {
|
||||||
super.onActivityLaunched(taskInfo, activityInfo, info);
|
super.onActivityLaunched(taskInfo, activityInfo, info);
|
||||||
if (!shouldShowNotificationDialogOrClearFlags(taskInfo,
|
if (!shouldShowNotificationDialogOrClearFlags(taskInfo,
|
||||||
activityInfo.packageName, info.intent, info.checkedOptions, true)
|
activityInfo.packageName, info.callingPackage, info.intent,
|
||||||
|
info.checkedOptions, activityInfo.name, true)
|
||||||
|| isNoDisplayActivity(activityInfo)) {
|
|| isNoDisplayActivity(activityInfo)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1237,9 +1239,9 @@ public final class PermissionPolicyService extends SystemService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldShowNotificationDialogForTask(TaskInfo taskInfo, String currPkg,
|
public boolean shouldShowNotificationDialogForTask(TaskInfo taskInfo, String currPkg,
|
||||||
Intent intent) {
|
String callingPkg, Intent intent, String activityName) {
|
||||||
return shouldShowNotificationDialogOrClearFlags(
|
return shouldShowNotificationDialogOrClearFlags(taskInfo, currPkg, callingPkg, intent,
|
||||||
taskInfo, currPkg, intent, null, false);
|
null, activityName, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isNoDisplayActivity(@NonNull ActivityInfo aInfo) {
|
private boolean isNoDisplayActivity(@NonNull ActivityInfo aInfo) {
|
||||||
@@ -1265,23 +1267,61 @@ public final class PermissionPolicyService extends SystemService {
|
|||||||
* 1. The isEligibleForLegacyPermissionPrompt ActivityOption is set, or
|
* 1. The isEligibleForLegacyPermissionPrompt ActivityOption is set, or
|
||||||
* 2. The intent is a launcher intent (action is ACTION_MAIN, category is LAUNCHER), 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
|
* 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 taskInfo The task to be checked
|
||||||
* @param currPkg The package of the current top visible activity
|
* @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 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,
|
private boolean shouldShowNotificationDialogOrClearFlags(TaskInfo taskInfo, String currPkg,
|
||||||
Intent intent, ActivityOptions options, boolean activityStart) {
|
String callingPkg, Intent intent, ActivityOptions options,
|
||||||
if (intent == null || currPkg == null || taskInfo == null
|
String topActivityName, boolean startedActivity) {
|
||||||
|
if (intent == null || currPkg == null || taskInfo == null || topActivityName == null
|
||||||
|| (!(taskInfo.isFocused && taskInfo.isVisible && taskInfo.isRunning)
|
|| (!(taskInfo.isFocused && taskInfo.isVisible && taskInfo.isRunning)
|
||||||
&& !activityStart)) {
|
&& !startedActivity)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return isLauncherIntent(intent)
|
return isLauncherIntent(intent)
|
||||||
|| (options != null && options.isEligibleForLegacyPermissionPrompt())
|
|| (options != null && options.isEligibleForLegacyPermissionPrompt())
|
||||||
|| (currPkg.equals(taskInfo.baseActivity.getPackageName())
|
|| isTaskStartedFromLauncher(currPkg, taskInfo)
|
||||||
&& isLauncherIntent(taskInfo.baseIntent));
|
|| (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) {
|
private boolean isLauncherIntent(Intent intent) {
|
||||||
@@ -1292,6 +1332,11 @@ public final class PermissionPolicyService extends SystemService {
|
|||||||
|| intent.getCategories().contains(Intent.CATEGORY_CAR_LAUNCHER));
|
|| 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) {
|
private void clearNotificationReviewFlagsIfNeeded(String packageName, UserHandle user) {
|
||||||
if ((mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, packageName, user)
|
if ((mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, packageName, user)
|
||||||
& FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
|
& FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import android.os.Binder;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
import android.os.Process;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
|
||||||
@@ -48,8 +49,9 @@ class AppTaskImpl extends IAppTask.Stub {
|
|||||||
mCallingUid = callingUid;
|
mCallingUid = callingUid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkCaller() {
|
private void checkCallerOrSystemOrRoot() {
|
||||||
if (mCallingUid != Binder.getCallingUid()) {
|
if (mCallingUid != Binder.getCallingUid() && Process.SYSTEM_UID != Binder.getCallingUid()
|
||||||
|
&& Process.ROOT_UID != Binder.getCallingUid()) {
|
||||||
throw new SecurityException("Caller " + mCallingUid
|
throw new SecurityException("Caller " + mCallingUid
|
||||||
+ " does not match caller of getAppTasks(): " + Binder.getCallingUid());
|
+ " does not match caller of getAppTasks(): " + Binder.getCallingUid());
|
||||||
}
|
}
|
||||||
@@ -67,7 +69,7 @@ class AppTaskImpl extends IAppTask.Stub {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finishAndRemoveTask() {
|
public void finishAndRemoveTask() {
|
||||||
checkCaller();
|
checkCallerOrSystemOrRoot();
|
||||||
|
|
||||||
synchronized (mService.mGlobalLock) {
|
synchronized (mService.mGlobalLock) {
|
||||||
final long origId = Binder.clearCallingIdentity();
|
final long origId = Binder.clearCallingIdentity();
|
||||||
@@ -85,7 +87,7 @@ class AppTaskImpl extends IAppTask.Stub {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActivityManager.RecentTaskInfo getTaskInfo() {
|
public ActivityManager.RecentTaskInfo getTaskInfo() {
|
||||||
checkCaller();
|
checkCallerOrSystemOrRoot();
|
||||||
|
|
||||||
synchronized (mService.mGlobalLock) {
|
synchronized (mService.mGlobalLock) {
|
||||||
final long origId = Binder.clearCallingIdentity();
|
final long origId = Binder.clearCallingIdentity();
|
||||||
@@ -105,7 +107,7 @@ class AppTaskImpl extends IAppTask.Stub {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void moveToFront(IApplicationThread appThread, String callingPackage) {
|
public void moveToFront(IApplicationThread appThread, String callingPackage) {
|
||||||
checkCaller();
|
checkCallerOrSystemOrRoot();
|
||||||
// Will bring task to front if it already has a root activity.
|
// Will bring task to front if it already has a root activity.
|
||||||
final int callingPid = Binder.getCallingPid();
|
final int callingPid = Binder.getCallingPid();
|
||||||
final int callingUid = Binder.getCallingUid();
|
final int callingUid = Binder.getCallingUid();
|
||||||
@@ -136,7 +138,7 @@ class AppTaskImpl extends IAppTask.Stub {
|
|||||||
@Override
|
@Override
|
||||||
public int startActivity(IBinder whoThread, String callingPackage, String callingFeatureId,
|
public int startActivity(IBinder whoThread, String callingPackage, String callingFeatureId,
|
||||||
Intent intent, String resolvedType, Bundle bOptions) {
|
Intent intent, String resolvedType, Bundle bOptions) {
|
||||||
checkCaller();
|
checkCallerOrSystemOrRoot();
|
||||||
mService.assertPackageMatchesCallingUid(callingPackage);
|
mService.assertPackageMatchesCallingUid(callingPackage);
|
||||||
|
|
||||||
int callingUser = UserHandle.getCallingUserId();
|
int callingUser = UserHandle.getCallingUserId();
|
||||||
@@ -167,7 +169,7 @@ class AppTaskImpl extends IAppTask.Stub {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setExcludeFromRecents(boolean exclude) {
|
public void setExcludeFromRecents(boolean exclude) {
|
||||||
checkCaller();
|
checkCallerOrSystemOrRoot();
|
||||||
|
|
||||||
synchronized (mService.mGlobalLock) {
|
synchronized (mService.mGlobalLock) {
|
||||||
final long origId = Binder.clearCallingIdentity();
|
final long origId = Binder.clearCallingIdentity();
|
||||||
|
|||||||
@@ -3382,7 +3382,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
|
|||||||
if (record != null && record.isUid(uid)
|
if (record != null && record.isUid(uid)
|
||||||
&& Objects.equals(pkgName, record.packageName)
|
&& Objects.equals(pkgName, record.packageName)
|
||||||
&& pPi.shouldShowNotificationDialogForTask(record.getTask().getTaskInfo(),
|
&& pPi.shouldShowNotificationDialogForTask(record.getTask().getTaskInfo(),
|
||||||
pkgName, record.intent)) {
|
pkgName, record.launchedFromPackage, record.intent, record.getName())) {
|
||||||
validTaskId[0] = record.getTask().mTaskId;
|
validTaskId[0] = record.getTask().mTaskId;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user