Merge tag 'android-security-13.0.0_r29' into int/13/fp3
Android Security 13.0.0 Release 29 (13218412)
* tag 'android-security-13.0.0_r29':
RESTRICT AUTOMERGE Merge multiple requests by an app in the same task upwards (t)
Change-Id: Ie781594b23dfb121dbdb28dee406435b669b053c
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java
index 4a8793c..91e02d3 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java
@@ -51,6 +51,7 @@
import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.core.util.Consumer;
import com.android.modules.utils.build.SdkLevel;
@@ -104,6 +105,10 @@
public static final int DIALOG_WITH_FINE_LOCATION_ONLY = 4;
public static final int DIALOG_WITH_COARSE_LOCATION_ONLY = 5;
+ // The maximum number of dialogs we will allow the same package, on the same task, to launch
+ // simultaneously
+ public static final int MAX_DIALOGS_PER_PKG_TASK = 10;
+
public static final Map<String, Integer> PERMISSION_TO_BIT_SHIFT =
new HashMap<String, Integer>() {{
put(ACCESS_COARSE_LOCATION, 0);
@@ -145,6 +150,8 @@
private List<GrantPermissionsActivity> mFollowerActivities = new ArrayList<>();
/** Whether this activity has asked another GrantPermissionsActivity to show on its behalf */
private boolean mDelegated;
+ /** Whether this activity has been triggered by the system */
+ private boolean mIsSystemTriggered = false;
/** The set result code, or MAX_VALUE if it hasn't been set yet */
private int mResultCode = Integer.MAX_VALUE;
/** Package that shall have permissions granted */
@@ -175,6 +182,7 @@
.getStringArrayExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES);
if (PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(getIntent().getAction())) {
+ mIsSystemTriggered = true;
mTargetPackage = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
if (mTargetPackage == null) {
Log.e(LOG_TAG, "null EXTRA_PACKAGE_NAME. Must be set for "
@@ -205,21 +213,40 @@
}
mOriginalRequestedPermissions = mRequestedPermissions;
+ GrantPermissionsViewModelFactory factory =
+ new GrantPermissionsViewModelFactory(
+ getApplication(),
+ mTargetPackage,
+ mRequestedPermissions,
+ mSessionId,
+ icicle);
+ mViewModel = factory.create(GrantPermissionsViewModel.class);
+
synchronized (sCurrentGrantRequests) {
mKey = new Pair<>(mTargetPackage, getTaskId());
- if (!sCurrentGrantRequests.containsKey(mKey)) {
+ GrantPermissionsActivity current = sCurrentGrantRequests.get(mKey);
+ if (current == null) {
sCurrentGrantRequests.put(mKey, this);
finishSystemStartedDialogsOnOtherTasksLocked();
- } else if (getCallingPackage() == null) {
- // The trampoline doesn't require results. Delegate, and finish.
- sCurrentGrantRequests.get(mKey).onNewFollowerActivity(null,
- mRequestedPermissions);
+ } else if (mIsSystemTriggered) {
+ // The system triggered dialog doesn't require results. Delegate, and finish.
+ current.onNewFollowerActivity(null, Arrays.asList(mRequestedPermissions), false);
finishAfterTransition();
return;
- } else {
+ } else if (current.mIsSystemTriggered) {
+ // merge into the system triggered dialog, which has task overlay set
mDelegated = true;
- sCurrentGrantRequests.get(mKey).onNewFollowerActivity(this,
- mRequestedPermissions);
+ current.onNewFollowerActivity(this, Arrays.asList(mRequestedPermissions), false);
+ } else {
+ // this + current + current.mFollowerActivities
+ if ((current.mFollowerActivities.size() + 2) > MAX_DIALOGS_PER_PKG_TASK) {
+ // If there are too many dialogs for the same package, in the same task, cancel
+ finishAfterTransition();
+ return;
+ }
+ // Merge the old dialogs into the new
+ onNewFollowerActivity(current, Arrays.asList(current.mRequestedPermissions), true);
+ sCurrentGrantRequests.put(mKey, this);
}
}
@@ -242,10 +269,9 @@
Process.myUserHandle()).setResultListener(this);
}
- GrantPermissionsViewModelFactory factory = new GrantPermissionsViewModelFactory(
- getApplication(), mTargetPackage, mRequestedPermissions, mSessionId, icicle);
- mViewModel = factory.create(GrantPermissionsViewModel.class);
- mViewModel.getRequestInfosLiveData().observe(this, this::onRequestInfoLoad);
+ if (!mDelegated) {
+ mViewModel.getRequestInfosLiveData().observe(this, this::onRequestInfoLoad);
+ }
mRootView = mViewHandler.createView();
mRootView.setVisibility(View.GONE);
@@ -278,7 +304,7 @@
// as the UI behaves differently for updates and initial creations.
if (icicle != null) {
mViewHandler.loadInstanceState(icicle);
- } else {
+ } else if (mRootView == null || mRootView.getVisibility() != View.VISIBLE) {
// Do not show screen dim until data is loaded
window.setDimAmount(0f);
}
@@ -291,14 +317,24 @@
* activity finishing
* @param newPermissions The new permissions requested in the activity
*/
- private void onNewFollowerActivity(GrantPermissionsActivity follower, String[] newPermissions) {
+ private void onNewFollowerActivity(@Nullable GrantPermissionsActivity follower,
+ @NonNull List<String> newPermissions, boolean followerIsOlder) {
if (follower != null) {
// Ensure the list of follower activities is a stack
mFollowerActivities.add(0, follower);
+ follower.mViewModel = mViewModel;
+ if (followerIsOlder) {
+ follower.mDelegated = true;
+ }
}
- boolean isShowingGroup = mRootView != null && mRootView.getVisibility() == View.VISIBLE;
- List<RequestInfo> currentGroups = mViewModel.getRequestInfosLiveData().getValue();
+ // If the follower is older, examine it to find the pre-merge group
+ GrantPermissionsActivity olderActivity = follower != null && followerIsOlder
+ ? follower : this;
+ boolean isShowingGroup = olderActivity.mRootView != null
+ && olderActivity.mRootView.getVisibility() == View.VISIBLE;
+ List<RequestInfo> currentGroups =
+ olderActivity.mViewModel.getRequestInfosLiveData().getValue();
if (mPreMergeShownGroupName == null && isShowingGroup
&& currentGroups != null && !currentGroups.isEmpty()) {
mPreMergeShownGroupName = currentGroups.get(0).getGroupName();
@@ -313,6 +349,19 @@
}
}
+ if (isShowingGroup && mPreMergeShownGroupName != null
+ && followerIsOlder && currentGroups != null) {
+ // Load a request from the old activity
+ mRequestInfos = currentGroups;
+ showNextRequest();
+ olderActivity.mRootView.setVisibility(View.GONE);
+ }
+ if (follower != null && followerIsOlder) {
+ follower.mFollowerActivities.forEach((oldFollower) ->
+ onNewFollowerActivity(oldFollower, new ArrayList<>(), true));
+ follower.mFollowerActivities.clear();
+ }
+
if (!newPermission) {
return;
}
@@ -363,7 +412,7 @@
}
private void showNextRequest() {
- if (mRequestInfos == null || mRequestInfos.isEmpty()) {
+ if (mRequestInfos == null || mRequestInfos.isEmpty() || mDelegated) {
return;
}
@@ -654,13 +703,16 @@
private boolean setResultIfNeeded(int resultCode) {
if (!isResultSet()) {
String[] oldRequestedPermissions = mRequestedPermissions;
+ mResultCode = resultCode;
removeActivityFromMap();
// If a new merge request came in before we managed to remove this activity from the
// map, then cancel the result set for now.
if (!Arrays.equals(oldRequestedPermissions, mRequestedPermissions)) {
+ // Reset the result code back to its starting value of MAX_VALUE;
+ mResultCode = Integer.MAX_VALUE;
return false;
}
- mResultCode = resultCode;
+
if (mViewModel != null) {
mViewModel.logRequestedPermissionGroups();
}