diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index e390ae28a0924..6529b11043323 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -479,6 +479,35 @@ public abstract class PackageManagerInternal implements PackageSettingsSnapshotP
@AppIdInt int recipientAppId, int visibleUid,
boolean direct);
+ /**
+ * Grants implicit access based on an interaction between two apps. This grants access to the
+ * from one application to the other's package metadata.
+ *
+ * When an application explicitly tries to interact with another application [via an
+ * activity, service or provider that is either declared in the caller's
+ * manifest via the {@code } tag or has been exposed via the target apps manifest using
+ * the {@code visibleToInstantApp} attribute], the target application must be able to see
+ * metadata about the calling app. If the calling application uses an implicit intent [ie
+ * action VIEW, category BROWSABLE], it remains hidden from the launched app.
+ *
+ * If an interaction is not explicit, the {@code direct} argument should be set to false as
+ * visibility should not be granted in some cases. This method handles that logic.
+ *
+ * @param userId the user
+ * @param intent the intent that triggered the grant
+ * @param recipientAppId The app ID of the application that is being given access to {@code
+ * visibleUid}
+ * @param visibleUid The uid of the application that is becoming accessible to {@code
+ * recipientAppId}
+ * @param direct true if the access is being made due to direct interaction between visibleUid
+ * and recipientAppId.
+ * @param retainOnUpdate true if the implicit access is retained across package update.
+ */
+ public abstract void grantImplicitAccess(
+ @UserIdInt int userId, Intent intent,
+ @AppIdInt int recipientAppId, int visibleUid,
+ boolean direct, boolean retainOnUpdate);
+
public abstract boolean isInstantAppInstallerComponent(ComponentName component);
/**
* Prunes instant apps and state associated with uninstalled
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 56b77b5944434..15e671cd7d035 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -96,6 +96,13 @@ public class AppsFilter implements Watchable, Snappable {
*/
private final SparseSetArray mImplicitlyQueryable = new SparseSetArray<>();
+ /**
+ * This contains a list of app UIDs that are implicitly queryable because another app explicitly
+ * interacted with it, but could keep across package updates. For example, if application A
+ * grants persistable uri permission to application B; regardless of any manifest entries.
+ */
+ private final SparseSetArray mRetainedImplicitlyQueryable = new SparseSetArray<>();
+
/**
* A mapping from the set of App IDs that query other App IDs via package name to the
* list of packages that they can see.
@@ -256,6 +263,7 @@ public class AppsFilter implements Watchable, Snappable {
*/
private AppsFilter(AppsFilter orig) {
Snapshots.copy(mImplicitlyQueryable, orig.mImplicitlyQueryable);
+ Snapshots.copy(mRetainedImplicitlyQueryable, orig.mRetainedImplicitlyQueryable);
Snapshots.copy(mQueriesViaPackage, orig.mQueriesViaPackage);
Snapshots.copy(mQueriesViaComponent, orig.mQueriesViaComponent);
Snapshots.copy(mQueryableViaUsesLibrary, orig.mQueryableViaUsesLibrary);
@@ -633,15 +641,19 @@ public class AppsFilter implements Watchable, Snappable {
*
* @param recipientUid the uid gaining visibility of the {@code visibleUid}.
* @param visibleUid the uid becoming visible to the {@recipientUid}
+ * @param retainOnUpdate if the implicit access retained across package updates.
* @return {@code true} if implicit access was not already granted.
*/
- public boolean grantImplicitAccess(int recipientUid, int visibleUid) {
+ public boolean grantImplicitAccess(int recipientUid, int visibleUid, boolean retainOnUpdate) {
if (recipientUid == visibleUid) {
return false;
}
- final boolean changed = mImplicitlyQueryable.add(recipientUid, visibleUid);
+ final boolean changed = retainOnUpdate
+ ? mRetainedImplicitlyQueryable.add(recipientUid, visibleUid)
+ : mImplicitlyQueryable.add(recipientUid, visibleUid);
if (changed && DEBUG_LOGGING) {
- Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid);
+ Slog.i(TAG, (retainOnUpdate ? "retained " : "") + "implicit access granted: "
+ + recipientUid + " -> " + visibleUid);
}
synchronized (mCacheLock) {
if (mShouldFilterCache != null) {
@@ -677,7 +689,7 @@ public class AppsFilter implements Watchable, Snappable {
try {
if (isReplace) {
// let's first remove any prior rules for this package
- removePackage(newPkgSetting);
+ removePackage(newPkgSetting, true /*isReplace*/);
}
mStateProvider.runWithState((settings, users) -> {
ArraySet additionalChangedPackages =
@@ -1078,8 +1090,9 @@ public class AppsFilter implements Watchable, Snappable {
* Removes a package for consideration when filtering visibility between apps.
*
* @param setting the setting of the package being removed.
+ * @param isReplace if the package is being replaced.
*/
- public void removePackage(PackageSetting setting) {
+ public void removePackage(PackageSetting setting, boolean isReplace) {
mStateProvider.runWithState((settings, users) -> {
final int userCount = users.length;
for (int u = 0; u < userCount; u++) {
@@ -1089,6 +1102,16 @@ public class AppsFilter implements Watchable, Snappable {
for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) {
mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i), removingUid);
}
+
+ if (isReplace) {
+ continue;
+ }
+
+ mRetainedImplicitlyQueryable.remove(removingUid);
+ for (int i = mRetainedImplicitlyQueryable.size() - 1; i >= 0; i--) {
+ mRetainedImplicitlyQueryable.remove(
+ mRetainedImplicitlyQueryable.keyAt(i), removingUid);
+ }
}
if (!mQueriesViaComponentRequireRecompute) {
@@ -1412,6 +1435,24 @@ public class AppsFilter implements Watchable, Snappable {
}
}
+ try {
+ if (DEBUG_TRACING) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mRetainedImplicitlyQueryable");
+ }
+ final int targetUid = UserHandle.getUid(targetUserId, targetAppId);
+ if (mRetainedImplicitlyQueryable.contains(callingUid, targetUid)) {
+ if (DEBUG_LOGGING) {
+ log(callingSetting, targetPkgSetting,
+ "retained implicitly queryable for user");
+ }
+ return false;
+ }
+ } finally {
+ if (DEBUG_TRACING) {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
try {
if (DEBUG_TRACING) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mOverlayReferenceMapper");
@@ -1550,6 +1591,9 @@ public class AppsFilter implements Watchable, Snappable {
dumpQueriesMap(pw,
filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId),
mImplicitlyQueryable, " ", expandPackages);
+ dumpQueriesMap(pw,
+ filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId),
+ mRetainedImplicitlyQueryable, " ", expandPackages);
}
pw.println(" queryable via uses-library:");
dumpQueriesMap(pw, filteringAppId, mQueryableViaUsesLibrary, " ", expandPackages);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 114dec61274ba..3cd41d30aa86c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18051,7 +18051,8 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
mDomainVerificationManager.clearPackage(deletedPs.name);
mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName);
- mAppsFilter.removePackage(getPackageSetting(packageName));
+ mAppsFilter.removePackage(getPackageSetting(packageName),
+ false /* isReplace */);
removedAppId = mSettings.removePackageLPw(packageName);
if (outInfo != null) {
outInfo.mRemovedAppId = removedAppId;
@@ -23787,6 +23788,13 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void grantImplicitAccess(int userId, Intent intent,
int recipientAppId, int visibleUid, boolean direct) {
+ grantImplicitAccess(userId, intent, recipientAppId, visibleUid, direct,
+ false /* retainOnUpdate */);
+ }
+
+ @Override
+ public void grantImplicitAccess(int userId, Intent intent,
+ int recipientAppId, int visibleUid, boolean direct, boolean retainOnUpdate) {
synchronized (mLock) {
final AndroidPackage visiblePackage = getPackage(visibleUid);
final int recipientUid = UserHandle.getUid(userId, recipientAppId);
@@ -23807,7 +23815,8 @@ public class PackageManagerService extends IPackageManager.Stub
accessGranted = mInstantAppRegistry.grantInstantAccessLPw(userId, intent,
recipientAppId, UserHandle.getAppId(visibleUid) /*instantAppId*/);
} else {
- accessGranted = mAppsFilter.grantImplicitAccess(recipientUid, visibleUid);
+ accessGranted = mAppsFilter.grantImplicitAccess(recipientUid, visibleUid,
+ retainOnUpdate);
}
if (accessGranted) {
ApplicationPackageManager.invalidateGetPackagesForUidCache();
@@ -24747,7 +24756,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
int visibleUid = providerInfo.applicationInfo.uid;
mPmInternal.grantImplicitAccess(userId, null /*Intent*/, UserHandle.getAppId(recipientUid),
- visibleUid, false);
+ visibleUid, false /*direct*/);
}
boolean canHaveOatDir(String packageName) {
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index fd1995ddec584..b17257a9db805 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -706,10 +706,10 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
sourcePkg, targetPkg, targetUid, grantUri);
perm.initPersistedModes(modeFlags, createdTime);
mPmInternal.grantImplicitAccess(
- targetUserId, null,
+ targetUserId, null /* intent */,
UserHandle.getAppId(targetUid),
pi.applicationInfo.uid,
- false /* direct */);
+ false /* direct */, true /* retainOnUpdate */);
}
} else {
Slog.w(TAG, "Persisted grant for " + uri + " had source " + sourcePkg
@@ -773,8 +773,9 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
perm = findOrCreateUriPermissionLocked(pi.packageName, targetPkg, targetUid, grantUri);
}
perm.grantModes(modeFlags, owner);
- mPmInternal.grantImplicitAccess(UserHandle.getUserId(targetUid), null,
- UserHandle.getAppId(targetUid), pi.applicationInfo.uid, false /*direct*/);
+ mPmInternal.grantImplicitAccess(UserHandle.getUserId(targetUid), null /*intent*/,
+ UserHandle.getAppId(targetUid), pi.applicationInfo.uid, false /*direct*/,
+ (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0);
}
/** Like grantUriPermissionUnchecked, but takes an Intent. */
@@ -1187,7 +1188,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
// provider supports granting permissions
mPmInternal.grantImplicitAccess(
UserHandle.getUserId(targetUid), null,
- UserHandle.getAppId(targetUid), pi.applicationInfo.uid, false);
+ UserHandle.getAppId(targetUid), pi.applicationInfo.uid, false /*direct*/);
return -1;
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index be942d6738af6..9bc20a7ba4e61 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -829,7 +829,7 @@ public class AppsFilterTest {
assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_APPID, overlaySetting,
actorSetting, SYSTEM_USER));
- appsFilter.removePackage(targetSetting);
+ appsFilter.removePackage(targetSetting, false /* isReplace */);
// Actor loses visibility to the overlay via removal of the target
assertTrue(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSetting,
@@ -1074,7 +1074,8 @@ public class AppsFilterTest {
watcher.verifyNoChangeReported("getVisibility");
// provider read
- appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId);
+ appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId,
+ false /* retainOnUpdate */);
watcher.verifyChangeReported("grantImplicitAccess");
// ensure implicit access is included in the filter
@@ -1143,7 +1144,8 @@ public class AppsFilterTest {
watcher.verifyNoChangeReported("get");
// provider read
- appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId);
+ appsFilter.grantImplicitAccess(
+ hasProviderAppId, queriesProviderAppId, false /* retainOnUpdate */);
watcher.verifyChangeReported("grantImplicitAccess");
// ensure implicit access is included in the filter
@@ -1154,7 +1156,7 @@ public class AppsFilterTest {
watcher.verifyNoChangeReported("get");
// remove a package
- appsFilter.removePackage(seesNothing);
+ appsFilter.removePackage(seesNothing, false /* isReplace */);
watcher.verifyChangeReported("removePackage");
}
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
index 25b51dad460a8..e418d2f8d3280 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
@@ -73,8 +73,8 @@ public class UriGrantsManagerServiceTest {
// we expect the following only during grant if a grant is expected
private void verifyNoVisibilityGrant() {
- verify(mContext.mPmInternal, never())
- .grantImplicitAccess(anyInt(), any(), anyInt(), anyInt(), anyBoolean());
+ verify(mContext.mPmInternal, never()).grantImplicitAccess(
+ anyInt(), any(), anyInt(), anyInt(), anyBoolean(), anyBoolean());
}
@Before