summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2014-04-04 12:12:41 -0700
committerJeff Sharkey <jsharkey@android.com>2014-04-22 21:06:49 -0700
commit846318a3250fa95f47a9decfbffb05a31dbd0006 (patch)
treec5d28f5d77e1fd625117e65bc9d24acfdfb6b94e /services
parentfb5d9f338153f569775bbc76177cab05441999c1 (diff)
downloadframeworks_base-846318a3250fa95f47a9decfbffb05a31dbd0006.zip
frameworks_base-846318a3250fa95f47a9decfbffb05a31dbd0006.tar.gz
frameworks_base-846318a3250fa95f47a9decfbffb05a31dbd0006.tar.bz2
Allow prefix-based Uri permission grants.
Define new FLAG_GRANT_PREFIX_URI_PERMISSION which indicates that a Uri permission grant should also apply to any other Uris that have matching scheme, authority, and path segments. For example, a prefix grant for /foo/ would allow /foo/bar/ but not /foo2/. Allow persistable and prefix grants to be issued directly through grantUriPermission(). Relaxing persistable is fine, since it still requires the receiver to actively take the permission. Since exact- and prefix-match grants for the same Uri can coexist, we track them separately using a new UriGrant key. (Consider the case where an app separately extends READ|PREFIX and WRITE for the same Uri: we can't let that become READ|WRITE|PREFIX.) Fix revoke to always take away persisted permissions. Move prefix matching logic to Uri and add tests. Add new flags to "am" tool, and various internal uses around Intent and Context. Switch some lagging users to ArraySet. Bug: 10607375 Change-Id: Ia8ce2b88421ff9f2fe5a979a27a026fc445d46f1
Diffstat (limited to 'services')
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java311
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityRecord.java9
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java9
-rw-r--r--services/core/java/com/android/server/am/UriPermission.java50
-rw-r--r--services/core/java/com/android/server/am/UriPermissionOwner.java89
5 files changed, 266 insertions, 202 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ecbb0d9..1bbdf3b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17,8 +17,10 @@
package com.android.server.am;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readLongAttribute;
+import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
@@ -724,6 +726,7 @@ public final class ActivityManagerService extends ActivityManagerNative
private static final String ATTR_URI = "uri";
private static final String ATTR_MODE_FLAGS = "modeFlags";
private static final String ATTR_CREATED_TIME = "createdTime";
+ private static final String ATTR_PREFIX = "prefix";
/**
* Global set of specific {@link Uri} permissions that have been granted.
@@ -731,8 +734,41 @@ public final class ActivityManagerService extends ActivityManagerNative
* to {@link UriPermission#uri} to {@link UriPermission}.
*/
@GuardedBy("this")
- private final SparseArray<ArrayMap<Uri, UriPermission>>
- mGrantedUriPermissions = new SparseArray<ArrayMap<Uri, UriPermission>>();
+ private final SparseArray<ArrayMap<GrantUri, UriPermission>>
+ mGrantedUriPermissions = new SparseArray<ArrayMap<GrantUri, UriPermission>>();
+
+ public static class GrantUri {
+ public final Uri uri;
+ public final boolean prefix;
+
+ public GrantUri(Uri uri, boolean prefix) {
+ this.uri = uri;
+ this.prefix = prefix;
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof GrantUri) {
+ GrantUri other = (GrantUri) o;
+ return uri.equals(other.uri) && prefix == other.prefix;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ if (prefix) {
+ return uri.toString() + " [prefix]";
+ } else {
+ return uri.toString();
+ }
+ }
+ }
CoreSettingsObserver mCoreSettingsObserver;
@@ -5822,7 +5858,7 @@ public final class ActivityManagerService extends ActivityManagerNative
* in {@link ContentProvider}.
*/
private final boolean checkHoldingPermissionsLocked(
- IPackageManager pm, ProviderInfo pi, Uri uri, int uid, int modeFlags) {
+ IPackageManager pm, ProviderInfo pi, Uri uri, int uid, final int modeFlags) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"checkHoldingPermissionsLocked: uri=" + uri + " uid=" + uid);
@@ -5918,18 +5954,17 @@ public final class ActivityManagerService extends ActivityManagerNative
return pi;
}
- private UriPermission findUriPermissionLocked(int targetUid, Uri uri) {
- ArrayMap<Uri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
+ private UriPermission findUriPermissionLocked(int targetUid, GrantUri uri) {
+ final ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
if (targetUris != null) {
return targetUris.get(uri);
- } else {
- return null;
}
+ return null;
}
- private UriPermission findOrCreateUriPermissionLocked(
- String sourcePkg, String targetPkg, int targetUid, Uri uri) {
- ArrayMap<Uri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
+ private UriPermission findOrCreateUriPermissionLocked(String sourcePkg,
+ String targetPkg, int targetUid, GrantUri uri) {
+ ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
if (targetUris == null) {
targetUris = Maps.newArrayMap();
mGrantedUriPermissions.put(targetUid, targetUris);
@@ -5945,20 +5980,36 @@ public final class ActivityManagerService extends ActivityManagerNative
}
private final boolean checkUriPermissionLocked(
- Uri uri, int uid, int modeFlags, int minStrength) {
+ Uri uri, int uid, final int modeFlags, int minStrength) {
// Root gets to do everything.
if (uid == 0) {
return true;
}
- ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
+
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(uid);
if (perms == null) return false;
- UriPermission perm = perms.get(uri);
- if (perm == null) return false;
- return perm.getStrength(modeFlags) >= minStrength;
+
+ // First look for exact match
+ final UriPermission exactPerm = perms.get(new GrantUri(uri, false));
+ if (exactPerm != null && exactPerm.getStrength(modeFlags) >= minStrength) {
+ return true;
+ }
+
+ // No exact match, look for prefixes
+ final int N = perms.size();
+ for (int i = 0; i < N; i++) {
+ final UriPermission perm = perms.valueAt(i);
+ if (perm.uri.prefix && uri.isPathPrefixMatch(perm.uri.uri)
+ && perm.getStrength(modeFlags) >= minStrength) {
+ return true;
+ }
+ }
+
+ return false;
}
@Override
- public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
+ public int checkUriPermission(Uri uri, int pid, int uid, final int modeFlags) {
enforceNotIsolatedCaller("checkUriPermission");
// Another redirected-binder-call permissions check as in
@@ -5990,11 +6041,8 @@ public final class ActivityManagerService extends ActivityManagerNative
* lastTargetUid else set that to -1.
*/
int checkGrantUriPermissionLocked(int callingUid, String targetPkg,
- Uri uri, int modeFlags, int lastTargetUid) {
- final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
- modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- if (modeFlags == 0) {
+ Uri uri, final int modeFlags, int lastTargetUid) {
+ if (!Intent.isAccessUriMode(modeFlags)) {
return -1;
}
@@ -6089,6 +6137,8 @@ public final class ActivityManagerService extends ActivityManagerNative
if (callingUid != Process.myUid()) {
if (!checkHoldingPermissionsLocked(pm, pi, uri, callingUid, modeFlags)) {
// Require they hold a strong enough Uri permission
+ final boolean persistable =
+ (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
final int minStrength = persistable ? UriPermission.STRENGTH_PERSISTABLE
: UriPermission.STRENGTH_OWNED;
if (!checkUriPermissionLocked(uri, callingUid, modeFlags, minStrength)) {
@@ -6103,19 +6153,16 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public int checkGrantUriPermission(int callingUid, String targetPkg,
- Uri uri, int modeFlags) {
+ Uri uri, final int modeFlags) {
enforceNotIsolatedCaller("checkGrantUriPermission");
synchronized(this) {
return checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags, -1);
}
}
- void grantUriPermissionUncheckedLocked(
- int targetUid, String targetPkg, Uri uri, int modeFlags, UriPermissionOwner owner) {
- final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
- modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- if (modeFlags == 0) {
+ void grantUriPermissionUncheckedLocked(int targetUid, String targetPkg, Uri uri,
+ final int modeFlags, UriPermissionOwner owner) {
+ if (!Intent.isAccessUriMode(modeFlags)) {
return;
}
@@ -6133,13 +6180,14 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
+ final boolean prefix = (modeFlags & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) != 0;
final UriPermission perm = findOrCreateUriPermissionLocked(
- pi.packageName, targetPkg, targetUid, uri);
- perm.grantModes(modeFlags, persistable, owner);
+ pi.packageName, targetPkg, targetUid, new GrantUri(uri, prefix));
+ perm.grantModes(modeFlags, owner);
}
void grantUriPermissionLocked(int callingUid, String targetPkg, Uri uri,
- int modeFlags, UriPermissionOwner owner) {
+ final int modeFlags, UriPermissionOwner owner) {
if (targetPkg == null) {
throw new NullPointerException("targetPkg");
}
@@ -6253,7 +6301,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public void grantUriPermission(IApplicationThread caller, String targetPkg,
- Uri uri, int modeFlags) {
+ Uri uri, final int modeFlags) {
enforceNotIsolatedCaller("grantUriPermission");
synchronized(this) {
final ProcessRecord r = getRecordForAppLocked(caller);
@@ -6269,32 +6317,32 @@ public final class ActivityManagerService extends ActivityManagerNative
throw new IllegalArgumentException("null uri");
}
- // Persistable only supported through Intents
- Preconditions.checkFlagsArgument(modeFlags,
- Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ Preconditions.checkFlagsArgument(modeFlags, Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+ | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
- grantUriPermissionLocked(r.uid, targetPkg, uri, modeFlags,
- null);
+ grantUriPermissionLocked(r.uid, targetPkg, uri, modeFlags, null);
}
}
void removeUriPermissionIfNeededLocked(UriPermission perm) {
- if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
- |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
- ArrayMap<Uri, UriPermission> perms
- = mGrantedUriPermissions.get(perm.targetUid);
+ if (perm.modeFlags == 0) {
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
+ perm.targetUid);
if (perms != null) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Removing " + perm.targetUid + " permission to " + perm.uri);
+
perms.remove(perm.uri);
- if (perms.size() == 0) {
+ if (perms.isEmpty()) {
mGrantedUriPermissions.remove(perm.targetUid);
}
}
}
}
- private void revokeUriPermissionLocked(int callingUid, Uri uri, int modeFlags) {
+ private void revokeUriPermissionLocked(int callingUid, Uri uri, final int modeFlags) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Revoking all granted permissions to " + uri);
final IPackageManager pm = AppGlobals.getPackageManager();
@@ -6318,46 +6366,29 @@ public final class ActivityManagerService extends ActivityManagerNative
boolean persistChanged = false;
// Go through all of the permissions and remove any that match.
- final List<String> SEGMENTS = uri.getPathSegments();
- if (SEGMENTS != null) {
- final int NS = SEGMENTS.size();
- int N = mGrantedUriPermissions.size();
- for (int i=0; i<N; i++) {
- ArrayMap<Uri, UriPermission> perms
- = mGrantedUriPermissions.valueAt(i);
- Iterator<UriPermission> it = perms.values().iterator();
- toploop:
- while (it.hasNext()) {
- UriPermission perm = it.next();
- Uri targetUri = perm.uri;
- if (!authority.equals(targetUri.getAuthority())) {
- continue;
- }
- List<String> targetSegments = targetUri.getPathSegments();
- if (targetSegments == null) {
- continue;
- }
- if (targetSegments.size() < NS) {
- continue;
- }
- for (int j=0; j<NS; j++) {
- if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
- continue toploop;
- }
- }
- if (DEBUG_URI_PERMISSION) Slog.v(TAG,
- "Revoking " + perm.targetUid + " permission to " + perm.uri);
- persistChanged |= perm.clearModes(modeFlags, true);
+ int N = mGrantedUriPermissions.size();
+ for (int i = 0; i < N; i++) {
+ final int targetUid = mGrantedUriPermissions.keyAt(i);
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
+
+ for (Iterator<UriPermission> it = perms.values().iterator(); it.hasNext();) {
+ final UriPermission perm = it.next();
+ if (perm.uri.uri.isPathPrefixMatch(uri)) {
+ if (DEBUG_URI_PERMISSION)
+ Slog.v(TAG,
+ "Revoking " + perm.targetUid + " permission to " + perm.uri);
+ persistChanged |= perm.revokeModes(
+ modeFlags | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
if (perm.modeFlags == 0) {
it.remove();
}
}
- if (perms.size() == 0) {
- mGrantedUriPermissions.remove(
- mGrantedUriPermissions.keyAt(i));
- N--;
- i--;
- }
+ }
+
+ if (perms.isEmpty()) {
+ mGrantedUriPermissions.remove(targetUid);
+ N--;
+ i--;
}
}
@@ -6368,7 +6399,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public void revokeUriPermission(IApplicationThread caller, Uri uri,
- int modeFlags) {
+ final int modeFlags) {
enforceNotIsolatedCaller("revokeUriPermission");
synchronized(this) {
final ProcessRecord r = getRecordForAppLocked(caller);
@@ -6382,9 +6413,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
- modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- if (modeFlags == 0) {
+ if (!Intent.isAccessUriMode(modeFlags)) {
return;
}
@@ -6419,20 +6448,22 @@ public final class ActivityManagerService extends ActivityManagerNative
boolean persistChanged = false;
- final int size = mGrantedUriPermissions.size();
- for (int i = 0; i < size; i++) {
+ int N = mGrantedUriPermissions.size();
+ for (int i = 0; i < N; i++) {
+ final int targetUid = mGrantedUriPermissions.keyAt(i);
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
+
// Only inspect grants matching user
if (userHandle == UserHandle.USER_ALL
- || userHandle == UserHandle.getUserId(mGrantedUriPermissions.keyAt(i))) {
- final Iterator<UriPermission> it = mGrantedUriPermissions.valueAt(i)
- .values().iterator();
- while (it.hasNext()) {
+ || userHandle == UserHandle.getUserId(targetUid)) {
+ for (Iterator<UriPermission> it = perms.values().iterator(); it.hasNext();) {
final UriPermission perm = it.next();
// Only inspect grants matching package
if (packageName == null || perm.sourcePkg.equals(packageName)
|| perm.targetPkg.equals(packageName)) {
- persistChanged |= perm.clearModes(~0, persistable);
+ persistChanged |= perm.revokeModes(
+ persistable ? ~0 : ~Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
// Only remove when no modes remain; any persisted grants
// will keep this alive.
@@ -6441,6 +6472,12 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
}
+
+ if (perms.isEmpty()) {
+ mGrantedUriPermissions.remove(targetUid);
+ N--;
+ i--;
+ }
}
}
@@ -6460,7 +6497,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg,
- Uri uri, int modeFlags) {
+ Uri uri, final int modeFlags) {
synchronized(this) {
UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
if (owner == null) {
@@ -6514,8 +6551,9 @@ public final class ActivityManagerService extends ActivityManagerNative
ArrayList<UriPermission.Snapshot> persist = Lists.newArrayList();
synchronized (this) {
final int size = mGrantedUriPermissions.size();
- for (int i = 0 ; i < size; i++) {
- for (UriPermission perm : mGrantedUriPermissions.valueAt(i).values()) {
+ for (int i = 0; i < size; i++) {
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
+ for (UriPermission perm : perms.values()) {
if (perm.persistedModeFlags != 0) {
persist.add(perm.snapshot());
}
@@ -6536,7 +6574,8 @@ public final class ActivityManagerService extends ActivityManagerNative
writeIntAttribute(out, ATTR_USER_HANDLE, perm.userHandle);
out.attribute(null, ATTR_SOURCE_PKG, perm.sourcePkg);
out.attribute(null, ATTR_TARGET_PKG, perm.targetPkg);
- out.attribute(null, ATTR_URI, String.valueOf(perm.uri));
+ out.attribute(null, ATTR_URI, String.valueOf(perm.uri.uri));
+ writeBooleanAttribute(out, ATTR_PREFIX, perm.uri.prefix);
writeIntAttribute(out, ATTR_MODE_FLAGS, perm.persistedModeFlags);
writeLongAttribute(out, ATTR_CREATED_TIME, perm.persistedCreateTime);
out.endTag(null, TAG_URI_GRANT);
@@ -6572,6 +6611,7 @@ public final class ActivityManagerService extends ActivityManagerNative
final String sourcePkg = in.getAttributeValue(null, ATTR_SOURCE_PKG);
final String targetPkg = in.getAttributeValue(null, ATTR_TARGET_PKG);
final Uri uri = Uri.parse(in.getAttributeValue(null, ATTR_URI));
+ final boolean prefix = readBooleanAttribute(in, ATTR_PREFIX);
final int modeFlags = readIntAttribute(in, ATTR_MODE_FLAGS);
final long createdTime = readLongAttribute(in, ATTR_CREATED_TIME, now);
@@ -6587,7 +6627,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (targetUid != -1) {
final UriPermission perm = findOrCreateUriPermissionLocked(
- sourcePkg, targetPkg, targetUid, uri);
+ sourcePkg, targetPkg, targetUid, new GrantUri(uri, prefix));
perm.initPersistedModes(modeFlags, createdTime);
}
} else {
@@ -6609,7 +6649,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
- public void takePersistableUriPermission(Uri uri, int modeFlags) {
+ public void takePersistableUriPermission(Uri uri, final int modeFlags) {
enforceNotIsolatedCaller("takePersistableUriPermission");
Preconditions.checkFlagsArgument(modeFlags,
@@ -6617,13 +6657,28 @@ public final class ActivityManagerService extends ActivityManagerNative
synchronized (this) {
final int callingUid = Binder.getCallingUid();
- final UriPermission perm = findUriPermissionLocked(callingUid, uri);
- if (perm == null) {
- throw new SecurityException("No permission grant found for UID " + callingUid
- + " and Uri " + uri.toSafeString());
+ boolean persistChanged = false;
+
+ UriPermission exactPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, false));
+ UriPermission prefixPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, true));
+
+ final boolean exactValid = (exactPerm != null)
+ && ((modeFlags & exactPerm.persistableModeFlags) == modeFlags);
+ final boolean prefixValid = (prefixPerm != null)
+ && ((modeFlags & prefixPerm.persistableModeFlags) == modeFlags);
+
+ if (!(exactValid || prefixValid)) {
+ throw new SecurityException("No persistable permission grants found for UID "
+ + callingUid + " and Uri " + uri.toSafeString());
+ }
+
+ if (exactValid) {
+ persistChanged |= exactPerm.takePersistableModes(modeFlags);
+ }
+ if (prefixValid) {
+ persistChanged |= prefixPerm.takePersistableModes(modeFlags);
}
- boolean persistChanged = perm.takePersistableModes(modeFlags);
persistChanged |= maybePrunePersistedUriGrantsLocked(callingUid);
if (persistChanged) {
@@ -6633,7 +6688,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
- public void releasePersistableUriPermission(Uri uri, int modeFlags) {
+ public void releasePersistableUriPermission(Uri uri, final int modeFlags) {
enforceNotIsolatedCaller("releasePersistableUriPermission");
Preconditions.checkFlagsArgument(modeFlags,
@@ -6641,16 +6696,24 @@ public final class ActivityManagerService extends ActivityManagerNative
synchronized (this) {
final int callingUid = Binder.getCallingUid();
+ boolean persistChanged = false;
- final UriPermission perm = findUriPermissionLocked(callingUid, uri);
- if (perm == null) {
- Slog.w(TAG, "No permission grant found for UID " + callingUid + " and Uri "
- + uri.toSafeString());
- return;
+ UriPermission exactPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, false));
+ UriPermission prefixPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, true));
+ if (exactPerm == null && prefixPerm == null) {
+ throw new SecurityException("No permission grants found for UID " + callingUid
+ + " and Uri " + uri.toSafeString());
+ }
+
+ if (exactPerm != null) {
+ persistChanged |= exactPerm.releasePersistableModes(modeFlags);
+ removeUriPermissionIfNeededLocked(exactPerm);
+ }
+ if (prefixPerm != null) {
+ persistChanged |= prefixPerm.releasePersistableModes(modeFlags);
+ removeUriPermissionIfNeededLocked(prefixPerm);
}
- final boolean persistChanged = perm.releasePersistableModes(modeFlags);
- removeUriPermissionIfNeededLocked(perm);
if (persistChanged) {
schedulePersistUriGrants();
}
@@ -6664,7 +6727,7 @@ public final class ActivityManagerService extends ActivityManagerNative
* @return if any mutations occured that require persisting.
*/
private boolean maybePrunePersistedUriGrantsLocked(int uid) {
- final ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(uid);
if (perms == null) return false;
if (perms.size() < MAX_PERSISTED_URI_GRANTS) return false;
@@ -6714,13 +6777,12 @@ public final class ActivityManagerService extends ActivityManagerNative
final ArrayList<android.content.UriPermission> result = Lists.newArrayList();
synchronized (this) {
if (incoming) {
- final ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
+ callingUid);
if (perms == null) {
Slog.w(TAG, "No permission grants found for " + packageName);
} else {
- final int size = perms.size();
- for (int i = 0; i < size; i++) {
- final UriPermission perm = perms.valueAt(i);
+ for (UriPermission perm : perms.values()) {
if (packageName.equals(perm.targetPkg) && perm.persistedModeFlags != 0) {
result.add(perm.buildPersistedPublicApiObject());
}
@@ -6729,10 +6791,9 @@ public final class ActivityManagerService extends ActivityManagerNative
} else {
final int size = mGrantedUriPermissions.size();
for (int i = 0; i < size; i++) {
- final ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
- final int permsSize = perms.size();
- for (int j = 0; j < permsSize; j++) {
- final UriPermission perm = perms.valueAt(j);
+ final ArrayMap<GrantUri, UriPermission> perms =
+ mGrantedUriPermissions.valueAt(i);
+ for (UriPermission perm : perms.values()) {
if (packageName.equals(perm.sourcePkg) && perm.persistedModeFlags != 0) {
result.add(perm.buildPersistedPublicApiObject());
}
@@ -7602,11 +7663,11 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
}
-
- ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
+
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
if (perms != null) {
- for (Map.Entry<Uri, UriPermission> uri : perms.entrySet()) {
- if (uri.getKey().getAuthority().equals(cpi.authority)) {
+ for (GrantUri uri : perms.keySet()) {
+ if (uri.uri.getAuthority().equals(cpi.authority)) {
return null;
}
}
@@ -11573,8 +11634,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (dumpUid >= -1 && UserHandle.getAppId(uid) != dumpUid) {
continue;
}
- ArrayMap<Uri, UriPermission> perms
- = mGrantedUriPermissions.valueAt(i);
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
if (!printed) {
if (needSep) pw.println();
needSep = true;
@@ -11582,8 +11642,7 @@ public final class ActivityManagerService extends ActivityManagerNative
printed = true;
printedAnything = true;
}
- pw.print(" * UID "); pw.print(uid);
- pw.println(" holds:");
+ pw.print(" * UID "); pw.print(uid); pw.println(" holds:");
for (UriPermission perm : perms.values()) {
pw.print(" "); pw.println(perm);
if (dumpAll) {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 60adfb0..3e59def 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -215,14 +215,7 @@ final class ActivityRecord {
pw.print(prefix); pw.print("pendingOptions="); pw.println(pendingOptions);
}
if (uriPermissions != null) {
- if (uriPermissions.readUriPermissions != null) {
- pw.print(prefix); pw.print("readUriPermissions=");
- pw.println(uriPermissions.readUriPermissions);
- }
- if (uriPermissions.writeUriPermissions != null) {
- pw.print(prefix); pw.print("writeUriPermissions=");
- pw.println(uriPermissions.writeUriPermissions);
- }
+ uriPermissions.dump(pw, prefix);
}
pw.print(prefix); pw.print("launchFailed="); pw.print(launchFailed);
pw.print(" launchCount="); pw.print(launchCount);
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 363a9b7..e54c95e 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -193,14 +193,7 @@ final class ServiceRecord extends Binder {
pw.println(si.neededGrants);
}
if (si.uriPermissions != null) {
- if (si.uriPermissions.readUriPermissions != null) {
- pw.print(prefix); pw.print(" readUriPermissions=");
- pw.println(si.uriPermissions.readUriPermissions);
- }
- if (si.uriPermissions.writeUriPermissions != null) {
- pw.print(prefix); pw.print(" writeUriPermissions=");
- pw.println(si.uriPermissions.writeUriPermissions);
- }
+ si.uriPermissions.dump(pw, prefix);
}
}
}
diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
index 1f12b74..4970b8d 100644
--- a/services/core/java/com/android/server/am/UriPermission.java
+++ b/services/core/java/com/android/server/am/UriPermission.java
@@ -17,15 +17,16 @@
package com.android.server.am;
import android.content.Intent;
-import android.net.Uri;
import android.os.UserHandle;
+import android.util.ArraySet;
import android.util.Log;
+import android.util.Slog;
+import com.android.server.am.ActivityManagerService.GrantUri;
import com.google.android.collect.Sets;
import java.io.PrintWriter;
import java.util.Comparator;
-import java.util.HashSet;
/**
* Description of a permission granted to an app to access a particular URI.
@@ -50,7 +51,7 @@ final class UriPermission {
/** Cached UID of {@link #targetPkg}; should not be persisted */
final int targetUid;
- final Uri uri;
+ final GrantUri uri;
/**
* Allowed modes. All permission enforcement should use this field. Must
@@ -61,12 +62,13 @@ final class UriPermission {
*/
int modeFlags = 0;
- /** Allowed modes with explicit owner. */
+ /** Allowed modes with active owner. */
int ownedModeFlags = 0;
/** Allowed modes without explicit owner. */
int globalModeFlags = 0;
/** Allowed modes that have been offered for possible persisting. */
int persistableModeFlags = 0;
+
/** Allowed modes that should be persisted across device boots. */
int persistedModeFlags = 0;
@@ -78,12 +80,12 @@ final class UriPermission {
private static final long INVALID_TIME = Long.MIN_VALUE;
- private HashSet<UriPermissionOwner> mReadOwners;
- private HashSet<UriPermissionOwner> mWriteOwners;
+ private ArraySet<UriPermissionOwner> mReadOwners;
+ private ArraySet<UriPermissionOwner> mWriteOwners;
private String stringName;
- UriPermission(String sourcePkg, String targetPkg, int targetUid, Uri uri) {
+ UriPermission(String sourcePkg, String targetPkg, int targetUid, GrantUri uri) {
this.userHandle = UserHandle.getUserId(targetUid);
this.sourcePkg = sourcePkg;
this.targetPkg = targetPkg;
@@ -100,6 +102,9 @@ final class UriPermission {
* global or owner grants.
*/
void initPersistedModes(int modeFlags, long createdTime) {
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
persistableModeFlags = modeFlags;
persistedModeFlags = modeFlags;
persistedCreateTime = createdTime;
@@ -107,7 +112,11 @@ final class UriPermission {
updateModeFlags();
}
- void grantModes(int modeFlags, boolean persistable, UriPermissionOwner owner) {
+ void grantModes(int modeFlags, UriPermissionOwner owner) {
+ final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
if (persistable) {
persistableModeFlags |= modeFlags;
}
@@ -130,10 +139,14 @@ final class UriPermission {
* @return if mode changes should trigger persisting.
*/
boolean takePersistableModes(int modeFlags) {
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
if ((modeFlags & persistableModeFlags) != modeFlags) {
- throw new SecurityException("Requested flags 0x"
+ Slog.w(TAG, "Requested flags 0x"
+ Integer.toHexString(modeFlags) + ", but only 0x"
+ Integer.toHexString(persistableModeFlags) + " are allowed");
+ return false;
}
final int before = persistedModeFlags;
@@ -148,6 +161,9 @@ final class UriPermission {
}
boolean releasePersistableModes(int modeFlags) {
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
final int before = persistedModeFlags;
persistableModeFlags &= ~modeFlags;
@@ -164,7 +180,11 @@ final class UriPermission {
/**
* @return if mode changes should trigger persisting.
*/
- boolean clearModes(int modeFlags, boolean persistable) {
+ boolean revokeModes(int modeFlags) {
+ final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
final int before = persistedModeFlags;
if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
@@ -208,6 +228,8 @@ final class UriPermission {
* Return strength of this permission grant for the given flags.
*/
public int getStrength(int modeFlags) {
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if ((persistableModeFlags & modeFlags) == modeFlags) {
return STRENGTH_PERSISTABLE;
} else if ((globalModeFlags & modeFlags) == modeFlags) {
@@ -221,7 +243,7 @@ final class UriPermission {
private void addReadOwner(UriPermissionOwner owner) {
if (mReadOwners == null) {
- mReadOwners = Sets.newHashSet();
+ mReadOwners = Sets.newArraySet();
ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
updateModeFlags();
}
@@ -246,7 +268,7 @@ final class UriPermission {
private void addWriteOwner(UriPermissionOwner owner) {
if (mWriteOwners == null) {
- mWriteOwners = Sets.newHashSet();
+ mWriteOwners = Sets.newArraySet();
ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
updateModeFlags();
}
@@ -333,7 +355,7 @@ final class UriPermission {
final int userHandle;
final String sourcePkg;
final String targetPkg;
- final Uri uri;
+ final GrantUri uri;
final int persistedModeFlags;
final long persistedCreateTime;
@@ -352,6 +374,6 @@ final class UriPermission {
}
public android.content.UriPermission buildPersistedPublicApiObject() {
- return new android.content.UriPermission(uri, persistedModeFlags, persistedCreateTime);
+ return new android.content.UriPermission(uri.uri, persistedModeFlags, persistedCreateTime);
}
}
diff --git a/services/core/java/com/android/server/am/UriPermissionOwner.java b/services/core/java/com/android/server/am/UriPermissionOwner.java
index 7bbd3bc..65d7047 100644
--- a/services/core/java/com/android/server/am/UriPermissionOwner.java
+++ b/services/core/java/com/android/server/am/UriPermissionOwner.java
@@ -20,8 +20,11 @@ import android.content.Intent;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
+import android.util.ArraySet;
-import java.util.HashSet;
+import com.google.android.collect.Sets;
+
+import java.io.PrintWriter;
import java.util.Iterator;
final class UriPermissionOwner {
@@ -30,8 +33,8 @@ final class UriPermissionOwner {
Binder externalToken;
- HashSet<UriPermission> readUriPermissions; // special access to reading uris.
- HashSet<UriPermission> writeUriPermissions; // special access to writing uris.
+ private ArraySet<UriPermission> mReadPerms;
+ private ArraySet<UriPermission> mWritePerms;
class ExternalToken extends Binder {
UriPermissionOwner getOwner() {
@@ -39,9 +42,9 @@ final class UriPermissionOwner {
}
}
- UriPermissionOwner(ActivityManagerService _service, Object _owner) {
- service = _service;
- owner = _owner;
+ UriPermissionOwner(ActivityManagerService service, Object owner) {
+ this.service = service;
+ this.owner = owner;
}
Binder getExternalTokenLocked() {
@@ -64,82 +67,76 @@ final class UriPermissionOwner {
}
void removeUriPermissionsLocked(int mode) {
- if ((mode&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0
- && readUriPermissions != null) {
- for (UriPermission perm : readUriPermissions) {
- perm.removeReadOwner(this);
- service.removeUriPermissionIfNeededLocked(perm);
- }
- readUriPermissions = null;
- }
- if ((mode&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0
- && writeUriPermissions != null) {
- for (UriPermission perm : writeUriPermissions) {
- perm.removeWriteOwner(this);
- service.removeUriPermissionIfNeededLocked(perm);
- }
- writeUriPermissions = null;
- }
+ removeUriPermissionLocked(null, mode);
}
void removeUriPermissionLocked(Uri uri, int mode) {
- if ((mode&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0
- && readUriPermissions != null) {
- Iterator<UriPermission> it = readUriPermissions.iterator();
+ if ((mode & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0
+ && mReadPerms != null) {
+ Iterator<UriPermission> it = mReadPerms.iterator();
while (it.hasNext()) {
UriPermission perm = it.next();
- if (uri.equals(perm.uri)) {
+ if (uri == null || uri.equals(perm.uri)) {
perm.removeReadOwner(this);
service.removeUriPermissionIfNeededLocked(perm);
it.remove();
}
}
- if (readUriPermissions.size() == 0) {
- readUriPermissions = null;
+ if (mReadPerms.isEmpty()) {
+ mReadPerms = null;
}
}
- if ((mode&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0
- && writeUriPermissions != null) {
- Iterator<UriPermission> it = writeUriPermissions.iterator();
+ if ((mode & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0
+ && mWritePerms != null) {
+ Iterator<UriPermission> it = mWritePerms.iterator();
while (it.hasNext()) {
UriPermission perm = it.next();
- if (uri.equals(perm.uri)) {
+ if (uri == null || uri.equals(perm.uri)) {
perm.removeWriteOwner(this);
service.removeUriPermissionIfNeededLocked(perm);
it.remove();
}
}
- if (writeUriPermissions.size() == 0) {
- writeUriPermissions = null;
+ if (mWritePerms.isEmpty()) {
+ mWritePerms = null;
}
}
}
public void addReadPermission(UriPermission perm) {
- if (readUriPermissions == null) {
- readUriPermissions = new HashSet<UriPermission>();
+ if (mReadPerms == null) {
+ mReadPerms = Sets.newArraySet();
}
- readUriPermissions.add(perm);
+ mReadPerms.add(perm);
}
public void addWritePermission(UriPermission perm) {
- if (writeUriPermissions == null) {
- writeUriPermissions = new HashSet<UriPermission>();
+ if (mWritePerms == null) {
+ mWritePerms = Sets.newArraySet();
}
- writeUriPermissions.add(perm);
+ mWritePerms.add(perm);
}
public void removeReadPermission(UriPermission perm) {
- readUriPermissions.remove(perm);
- if (readUriPermissions.size() == 0) {
- readUriPermissions = null;
+ mReadPerms.remove(perm);
+ if (mReadPerms.isEmpty()) {
+ mReadPerms = null;
}
}
public void removeWritePermission(UriPermission perm) {
- writeUriPermissions.remove(perm);
- if (writeUriPermissions.size() == 0) {
- writeUriPermissions = null;
+ mWritePerms.remove(perm);
+ if (mWritePerms.isEmpty()) {
+ mWritePerms = null;
+ }
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ if (mReadPerms != null) {
+ pw.print(prefix); pw.print("readUriPermissions="); pw.println(mReadPerms);
+ }
+ if (mWritePerms != null) {
+ pw.print(prefix); pw.print("writeUriPermissions="); pw.println(mWritePerms);
}
}