summaryrefslogtreecommitdiffstats
path: root/services/java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java')
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java225
-rw-r--r--services/java/com/android/server/am/UriPermission.java190
2 files changed, 302 insertions, 113 deletions
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 4f73588..387641d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -18,7 +18,9 @@ package com.android.server.am;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.android.internal.util.XmlUtils.readIntAttribute;
+import static com.android.internal.util.XmlUtils.readLongAttribute;
import static com.android.internal.util.XmlUtils.writeIntAttribute;
+import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -36,7 +38,6 @@ import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.TransferPipe;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.MemInfoReader;
@@ -113,6 +114,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PathPermission;
@@ -153,6 +155,7 @@ import android.os.SystemProperties;
import android.os.UpdateLock;
import android.os.UserHandle;
import android.provider.Settings;
+import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.AtomicFile;
import android.util.EventLog;
@@ -310,6 +313,9 @@ public final class ActivityManagerService extends ActivityManagerNative
// to respond with the result.
static final int PENDING_ASSIST_EXTRAS_TIMEOUT = 500;
+ // Maximum number of persisted Uri grants a package is allowed
+ static final int MAX_PERSISTED_URI_GRANTS = 128;
+
static final int MY_PID = Process.myPid();
static final String[] EMPTY_STRING_ARRAY = new String[0];
@@ -685,6 +691,7 @@ public final class ActivityManagerService extends ActivityManagerNative
private static final String ATTR_TARGET_PKG = "targetPkg";
private static final String ATTR_URI = "uri";
private static final String ATTR_MODE_FLAGS = "modeFlags";
+ private static final String ATTR_CREATED_TIME = "createdTime";
/**
* Global set of specific {@link Uri} permissions that have been granted.
@@ -5669,6 +5676,15 @@ public final class ActivityManagerService extends ActivityManagerNative
return pi;
}
+ private UriPermission findUriPermissionLocked(int targetUid, Uri uri) {
+ ArrayMap<Uri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
+ if (targetUris != null) {
+ return targetUris.get(uri);
+ } else {
+ return null;
+ }
+ }
+
private UriPermission findOrCreateUriPermissionLocked(
String sourcePkg, String targetPkg, int targetUid, Uri uri) {
ArrayMap<Uri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
@@ -5686,8 +5702,8 @@ public final class ActivityManagerService extends ActivityManagerNative
return perm;
}
- private final boolean checkUriPermissionLocked(Uri uri, int uid,
- int modeFlags) {
+ private final boolean checkUriPermissionLocked(
+ Uri uri, int uid, int modeFlags, int minStrength) {
// Root gets to do everything.
if (uid == 0) {
return true;
@@ -5696,7 +5712,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (perms == null) return false;
UriPermission perm = perms.get(uri);
if (perm == null) return false;
- return (modeFlags&perm.modeFlags) == modeFlags;
+ return perm.getStrength(modeFlags) >= minStrength;
}
@Override
@@ -5716,7 +5732,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return PackageManager.PERMISSION_GRANTED;
}
synchronized(this) {
- return checkUriPermissionLocked(uri, uid, modeFlags)
+ return checkUriPermissionLocked(uri, uid, modeFlags, UriPermission.STRENGTH_OWNED)
? PackageManager.PERMISSION_GRANTED
: PackageManager.PERMISSION_DENIED;
}
@@ -5733,7 +5749,7 @@ public final class ActivityManagerService extends ActivityManagerNative
*/
int checkGrantUriPermissionLocked(int callingUid, String targetPkg,
Uri uri, int modeFlags, int lastTargetUid) {
- final boolean persist = (modeFlags & Intent.FLAG_PERSIST_GRANT_URI_PERMISSION) != 0;
+ 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) {
@@ -5777,7 +5793,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (targetUid >= 0) {
// First... does the target actually need this permission?
- if (checkHoldingPermissionsLocked(pm, pi, uri, targetUid, modeFlags) && !persist) {
+ if (checkHoldingPermissionsLocked(pm, pi, uri, targetUid, modeFlags)) {
// No need to grant the target this permission.
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Target " + targetPkg + " already has full permission to " + uri);
@@ -5796,7 +5812,7 @@ public final class ActivityManagerService extends ActivityManagerNative
allowed = false;
}
}
- if (allowed && !persist) {
+ if (allowed) {
return -1;
}
}
@@ -5830,7 +5846,10 @@ public final class ActivityManagerService extends ActivityManagerNative
// this uri?
if (callingUid != Process.myUid()) {
if (!checkHoldingPermissionsLocked(pm, pi, uri, callingUid, modeFlags)) {
- if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
+ // Require they hold a strong enough Uri permission
+ final int minStrength = persistable ? UriPermission.STRENGTH_PERSISTABLE
+ : UriPermission.STRENGTH_OWNED;
+ if (!checkUriPermissionLocked(uri, callingUid, modeFlags, minStrength)) {
throw new SecurityException("Uid " + callingUid
+ " does not have permission to uri " + uri);
}
@@ -5851,7 +5870,7 @@ public final class ActivityManagerService extends ActivityManagerNative
void grantUriPermissionUncheckedLocked(
int targetUid, String targetPkg, Uri uri, int modeFlags, UriPermissionOwner owner) {
- final boolean persist = (modeFlags & Intent.FLAG_PERSIST_GRANT_URI_PERMISSION) != 0;
+ 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) {
@@ -5874,11 +5893,7 @@ public final class ActivityManagerService extends ActivityManagerNative
final UriPermission perm = findOrCreateUriPermissionLocked(
pi.packageName, targetPkg, targetUid, uri);
- final boolean persistChanged = perm.grantModes(modeFlags, persist, owner);
- if (persistChanged) {
- mHandler.removeMessages(PERSIST_URI_GRANTS_MSG);
- mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG).sendToTarget();
- }
+ perm.grantModes(modeFlags, persistable, owner);
}
void grantUriPermissionLocked(int callingUid, String targetPkg, Uri uri,
@@ -5930,6 +5945,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (data == null && clip == null) {
return null;
}
+
if (data != null) {
int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, data,
mode, needed != null ? needed.targetUid : -1);
@@ -6011,6 +6027,14 @@ public final class ActivityManagerService extends ActivityManagerNative
throw new IllegalArgumentException("null uri");
}
+ // Persistable only supported through Intents
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ if (modeFlags == 0) {
+ throw new IllegalArgumentException("Mode flags must be "
+ + "FLAG_GRANT_READ_URI_PERMISSION and/or FLAG_GRANT_WRITE_URI_PERMISSION");
+ }
+
grantUriPermissionLocked(r.uid, targetPkg, uri, modeFlags,
null);
}
@@ -6032,8 +6056,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- private void revokeUriPermissionLocked(
- int callingUid, Uri uri, int modeFlags, boolean persist) {
+ private void revokeUriPermissionLocked(int callingUid, Uri uri, int modeFlags) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Revoking all granted permissions to " + uri);
final IPackageManager pm = AppGlobals.getPackageManager();
@@ -6086,7 +6109,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Revoking " + perm.targetUid + " permission to " + perm.uri);
- persistChanged |= perm.clearModes(modeFlags, persist);
+ persistChanged |= perm.clearModes(modeFlags, true);
if (perm.modeFlags == 0) {
it.remove();
}
@@ -6101,8 +6124,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (persistChanged) {
- mHandler.removeMessages(PERSIST_URI_GRANTS_MSG);
- mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG).sendToTarget();
+ schedulePersistUriGrants();
}
}
@@ -6122,7 +6144,6 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
- final boolean persist = (modeFlags & Intent.FLAG_PERSIST_GRANT_URI_PERMISSION) != 0;
modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (modeFlags == 0) {
@@ -6138,7 +6159,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
- revokeUriPermissionLocked(r.uid, uri, modeFlags, persist);
+ revokeUriPermissionLocked(r.uid, uri, modeFlags);
}
}
@@ -6150,10 +6171,10 @@ public final class ActivityManagerService extends ActivityManagerNative
* packages.
* @param userHandle User to match, or {@link UserHandle#USER_ALL} to apply
* to all users.
- * @param persist If persistent grants should be removed.
+ * @param persistable If persistable grants should be removed.
*/
private void removeUriPermissionsForPackageLocked(
- String packageName, int userHandle, boolean persist) {
+ String packageName, int userHandle, boolean persistable) {
if (userHandle == UserHandle.USER_ALL && packageName == null) {
throw new IllegalArgumentException("Must narrow by either package or user");
}
@@ -6173,7 +6194,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Only inspect grants matching package
if (packageName == null || perm.sourcePkg.equals(packageName)
|| perm.targetPkg.equals(packageName)) {
- persistChanged |= perm.clearModes(~0, persist);
+ persistChanged |= perm.clearModes(~0, persistable);
// Only remove when no modes remain; any persisted grants
// will keep this alive.
@@ -6186,8 +6207,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (persistChanged) {
- mHandler.removeMessages(PERSIST_URI_GRANTS_MSG);
- mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG).sendToTarget();
+ schedulePersistUriGrants();
}
}
@@ -6242,6 +6262,13 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ private void schedulePersistUriGrants() {
+ if (!mHandler.hasMessages(PERSIST_URI_GRANTS_MSG)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG),
+ 10 * DateUtils.SECOND_IN_MILLIS);
+ }
+ }
+
private void writeGrantedUriPermissions() {
if (DEBUG_URI_PERMISSION) Slog.v(TAG, "writeGrantedUriPermissions()");
@@ -6273,6 +6300,7 @@ public final class ActivityManagerService extends ActivityManagerNative
out.attribute(null, ATTR_TARGET_PKG, perm.targetPkg);
out.attribute(null, ATTR_URI, String.valueOf(perm.uri));
writeIntAttribute(out, ATTR_MODE_FLAGS, perm.persistedModeFlags);
+ writeLongAttribute(out, ATTR_CREATED_TIME, perm.persistedCreateTime);
out.endTag(null, TAG_URI_GRANT);
}
out.endTag(null, TAG_URI_GRANTS);
@@ -6289,6 +6317,8 @@ public final class ActivityManagerService extends ActivityManagerNative
private void readGrantedUriPermissionsLocked() {
if (DEBUG_URI_PERMISSION) Slog.v(TAG, "readGrantedUriPermissions()");
+ final long now = System.currentTimeMillis();
+
FileInputStream fis = null;
try {
fis = mGrantFile.openRead();
@@ -6305,6 +6335,7 @@ public final class ActivityManagerService extends ActivityManagerNative
final String targetPkg = in.getAttributeValue(null, ATTR_TARGET_PKG);
final Uri uri = Uri.parse(in.getAttributeValue(null, ATTR_URI));
final int modeFlags = readIntAttribute(in, ATTR_MODE_FLAGS);
+ final long createdTime = readLongAttribute(in, ATTR_CREATED_TIME, now);
// Sanity check that provider still belongs to source package
final ProviderInfo pi = getProviderInfoLocked(
@@ -6319,7 +6350,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (targetUid != -1) {
final UriPermission perm = findOrCreateUriPermissionLocked(
sourcePkg, targetPkg, targetUid, uri);
- perm.grantModes(modeFlags, true, null);
+ perm.initPersistedModes(modeFlags, createdTime);
}
} else {
Slog.w(TAG, "Persisted grant for " + uri + " had source " + sourcePkg
@@ -6340,47 +6371,117 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
- public Uri[] getGrantedUriPermissions(
- String sourcePackage, String targetPackage, int modeFlags, int modeMask) {
- enforceNotIsolatedCaller("getGrantedUriPermissions");
+ public void takePersistableUriPermission(Uri uri, int modeFlags) {
+ enforceNotIsolatedCaller("takePersistableUriPermission");
+
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ if (modeFlags == 0) {
+ return;
+ }
+
synchronized (this) {
- // Verify that caller owns at least one of the requested packages
- final int uid = Binder.getCallingUid();
- final IPackageManager pm = AppGlobals.getPackageManager();
- final String[] callerPackages;
- try {
- callerPackages = pm.getPackagesForUid(uid);
- } catch (RemoteException e) {
- throw new SecurityException("Failed to find packages for UID " + uid);
+ final int callingUid = Binder.getCallingUid();
+ final UriPermission perm = findUriPermissionLocked(callingUid, uri);
+ if (perm == null) {
+ Slog.w(TAG, "No permission grant found for UID " + callingUid + " and Uri "
+ + uri.toSafeString());
+ return;
}
- final boolean callerOwnsSource = sourcePackage != null
- && ArrayUtils.contains(callerPackages, sourcePackage);
- final boolean callerOwnsTarget = targetPackage != null
- && ArrayUtils.contains(callerPackages, targetPackage);
- if (!(callerOwnsSource || callerOwnsTarget)) {
- throw new SecurityException("Caller " + Arrays.toString(callerPackages)
- + " doesn't own " + sourcePackage + " or " + targetPackage);
+
+ boolean persistChanged = perm.takePersistableModes(modeFlags);
+ persistChanged |= maybePrunePersistedUriGrantsLocked(callingUid);
+
+ if (persistChanged) {
+ schedulePersistUriGrants();
}
+ }
+ }
- final ArrayList<Uri> result = Lists.newArrayList();
- final int size = mGrantedUriPermissions.size();
- for (int i = 0; i < size; i++) {
- final ArrayMap<Uri, UriPermission> map = mGrantedUriPermissions.valueAt(i);
- final int mapSize = map.size();
- for (int j = 0; j < mapSize; j++) {
- final UriPermission perm = map.valueAt(j);
- final boolean sourceMatch = sourcePackage == null
- || sourcePackage.equals(perm.sourcePkg);
- final boolean targetMatch = targetPackage == null
- || targetPackage.equals(perm.targetPkg);
- final boolean modeMatch = (perm.modeFlags & modeMask) == modeFlags;
- if (sourceMatch && targetMatch && modeMatch) {
- result.add(perm.uri);
+ @Override
+ public void releasePersistableUriPermission(Uri uri, int modeFlags) {
+ enforceNotIsolatedCaller("releasePersistableUriPermission");
+
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ if (modeFlags == 0) {
+ return;
+ }
+
+ synchronized (this) {
+ final int callingUid = Binder.getCallingUid();
+
+ final UriPermission perm = findUriPermissionLocked(callingUid, uri);
+ if (perm == null) {
+ Slog.w(TAG, "No permission grant found for UID " + callingUid + " and Uri "
+ + uri.toSafeString());
+ return;
+ }
+
+ final boolean persistChanged = perm.releasePersistableModes(modeFlags);
+ removeUriPermissionIfNeededLocked(perm);
+ if (persistChanged) {
+ schedulePersistUriGrants();
+ }
+ }
+ }
+
+ /**
+ * Prune any older {@link UriPermission} for the given UID until outstanding
+ * persisted grants are below {@link #MAX_PERSISTED_URI_GRANTS}.
+ *
+ * @return if any mutations occured that require persisting.
+ */
+ private boolean maybePrunePersistedUriGrantsLocked(int uid) {
+ final ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
+ if (perms == null) return false;
+ if (perms.size() < MAX_PERSISTED_URI_GRANTS) return false;
+
+ final ArrayList<UriPermission> persisted = Lists.newArrayList();
+ for (UriPermission perm : perms.values()) {
+ if (perm.persistedModeFlags != 0) {
+ persisted.add(perm);
+ }
+ }
+
+ final int trimCount = persisted.size() - MAX_PERSISTED_URI_GRANTS;
+ if (trimCount <= 0) return false;
+
+ Collections.sort(persisted, new UriPermission.PersistedTimeComparator());
+ for (int i = 0; i < trimCount; i++) {
+ final UriPermission perm = persisted.get(i);
+
+ if (DEBUG_URI_PERMISSION) {
+ Slog.v(TAG, "Trimming grant created at " + perm.persistedCreateTime);
+ }
+
+ perm.releasePersistableModes(~0);
+ removeUriPermissionIfNeededLocked(perm);
+ }
+
+ return true;
+ }
+
+ @Override
+ public ParceledListSlice<android.content.UriPermission> getPersistedUriPermissions() {
+ enforceNotIsolatedCaller("getPersistedUriPermissions");
+
+ synchronized (this) {
+ final int callingUid = Binder.getCallingUid();
+ final ArrayList<android.content.UriPermission> result = Lists.newArrayList();
+ final ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
+ if (perms == null) {
+ Slog.w(TAG, "No permission grants found for UID " + callingUid);
+ } else {
+ final int size = perms.size();
+ for (int i = 0; i < size; i++) {
+ final UriPermission perm = perms.valueAt(i);
+ if (perm.persistedModeFlags != 0) {
+ result.add(perm.buildPersistedPublicApiObject());
}
}
}
-
- return result.toArray(new Uri[result.size()]);
+ return new ParceledListSlice<android.content.UriPermission>(result);
}
}
diff --git a/services/java/com/android/server/am/UriPermission.java b/services/java/com/android/server/am/UriPermission.java
index 5e2ad00..7057c24 100644
--- a/services/java/com/android/server/am/UriPermission.java
+++ b/services/java/com/android/server/am/UriPermission.java
@@ -20,11 +20,12 @@ import android.content.Intent;
import android.net.Uri;
import android.os.UserHandle;
import android.util.Log;
+import android.util.Slog;
-import com.android.internal.util.IndentingPrintWriter;
import com.google.android.collect.Sets;
import java.io.PrintWriter;
+import java.util.Comparator;
import java.util.HashSet;
/**
@@ -38,6 +39,11 @@ import java.util.HashSet;
final class UriPermission {
private static final String TAG = "UriPermission";
+ public static final int STRENGTH_NONE = 0;
+ public static final int STRENGTH_OWNED = 1;
+ public static final int STRENGTH_GLOBAL = 2;
+ public static final int STRENGTH_PERSISTABLE = 3;
+
final int userHandle;
final String sourcePkg;
final String targetPkg;
@@ -49,26 +55,29 @@ final class UriPermission {
/**
* Allowed modes. All permission enforcement should use this field. Must
- * always be a superset of {@link #globalModeFlags},
- * {@link #persistedModeFlags}, {@link #mReadOwners}, and
- * {@link #mWriteOwners}. Mutations should only be performed by the owning
- * class.
+ * always be a combination of {@link #ownedModeFlags},
+ * {@link #globalModeFlags}, {@link #persistableModeFlags}, and
+ * {@link #persistedModeFlags}. Mutations <em>must</em> only be performed by
+ * the owning class.
*/
int modeFlags = 0;
- /**
- * Allowed modes without explicit owner. Must always be a superset of
- * {@link #persistedModeFlags}. Mutations should only be performed by the
- * owning class.
- */
+ /** Allowed modes with explicit 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;
/**
- * Allowed modes that should be persisted across device boots. These modes
- * have no explicit owners. Mutations should only be performed by the owning
- * class.
+ * Timestamp when {@link #persistedModeFlags} was first defined in
+ * {@link System#currentTimeMillis()} time base.
*/
- int persistedModeFlags = 0;
+ long persistedCreateTime = INVALID_TIME;
+
+ private static final long INVALID_TIME = Long.MIN_VALUE;
private HashSet<UriPermissionOwner> mReadOwners;
private HashSet<UriPermissionOwner> mWriteOwners;
@@ -83,21 +92,25 @@ final class UriPermission {
this.uri = uri;
}
+ private void updateModeFlags() {
+ modeFlags = ownedModeFlags | globalModeFlags | persistableModeFlags | persistedModeFlags;
+ }
+
/**
- * @return If mode changes should trigger persisting.
+ * Initialize persisted modes as read from file. This doesn't issue any
+ * global or owner grants.
*/
- boolean grantModes(int modeFlagsToGrant, boolean persist, UriPermissionOwner owner) {
- boolean persistChanged = false;
-
- modeFlags |= modeFlagsToGrant;
+ void initPersistedModes(int modeFlags, long createdTime) {
+ persistableModeFlags = modeFlags;
+ persistedModeFlags = modeFlags;
+ persistedCreateTime = createdTime;
- if (persist) {
- final int before = persistedModeFlags;
- persistedModeFlags |= modeFlagsToGrant;
- persistChanged = persistedModeFlags != before;
+ updateModeFlags();
+ }
- // Treat persisted grants as global (ownerless)
- owner = null;
+ void grantModes(int modeFlags, boolean persistable, UriPermissionOwner owner) {
+ if (persistable) {
+ persistableModeFlags |= modeFlags;
}
if (owner == null) {
@@ -105,43 +118,77 @@ final class UriPermission {
} else {
if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
addReadOwner(owner);
- owner.addReadPermission(this);
}
if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
addWriteOwner(owner);
- owner.addWritePermission(this);
}
}
- return persistChanged;
+ updateModeFlags();
}
-
+
/**
- * @return If mode changes should trigger persisting.
+ * @return if mode changes should trigger persisting.
*/
- boolean clearModes(int modeFlagsToClear, boolean persist) {
+ boolean takePersistableModes(int modeFlags) {
+ if ((~persistableModeFlags & modeFlags) != 0) {
+ Slog.w(TAG, "Trying to take 0x" + Integer.toHexString(modeFlags) + " but only 0x"
+ + Integer.toHexString(persistableModeFlags) + " are available");
+ }
+
+ final int before = persistedModeFlags;
+ persistedModeFlags |= (persistableModeFlags & modeFlags);
+
+ if (persistedModeFlags != 0) {
+ persistedCreateTime = System.currentTimeMillis();
+ }
+
+ updateModeFlags();
+ return persistedModeFlags != before;
+ }
+
+ boolean releasePersistableModes(int modeFlags) {
final int before = persistedModeFlags;
- if ((modeFlagsToClear & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
- if (persist) {
+ persistableModeFlags &= ~modeFlags;
+ persistedModeFlags &= ~modeFlags;
+
+ if (persistedModeFlags == 0) {
+ persistedCreateTime = INVALID_TIME;
+ }
+
+ updateModeFlags();
+ return persistedModeFlags != before;
+ }
+
+ /**
+ * @return if mode changes should trigger persisting.
+ */
+ boolean clearModes(int modeFlags, boolean persistable) {
+ final int before = persistedModeFlags;
+
+ if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+ if (persistable) {
+ persistableModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
persistedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
}
globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
- modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
if (mReadOwners != null) {
+ ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
for (UriPermissionOwner r : mReadOwners) {
r.removeReadPermission(this);
}
mReadOwners = null;
}
}
- if ((modeFlagsToClear & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
- if (persist) {
+ if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+ if (persistable) {
+ persistableModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
}
globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
- modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
if (mWriteOwners != null) {
+ ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
for (UriPermissionOwner r : mWriteOwners) {
r.removeWritePermission(this);
}
@@ -149,18 +196,38 @@ final class UriPermission {
}
}
- // Mode flags always bubble up
- globalModeFlags |= persistedModeFlags;
- modeFlags |= globalModeFlags;
+ if (persistedModeFlags == 0) {
+ persistedCreateTime = INVALID_TIME;
+ }
+ updateModeFlags();
return persistedModeFlags != before;
}
+ /**
+ * Return strength of this permission grant for the given flags.
+ */
+ public int getStrength(int modeFlags) {
+ if ((persistableModeFlags & modeFlags) == modeFlags) {
+ return STRENGTH_PERSISTABLE;
+ } else if ((globalModeFlags & modeFlags) == modeFlags) {
+ return STRENGTH_GLOBAL;
+ } else if ((ownedModeFlags & modeFlags) == modeFlags) {
+ return STRENGTH_OWNED;
+ } else {
+ return STRENGTH_NONE;
+ }
+ }
+
private void addReadOwner(UriPermissionOwner owner) {
if (mReadOwners == null) {
mReadOwners = Sets.newHashSet();
+ ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
+ updateModeFlags();
+ }
+ if (mReadOwners.add(owner)) {
+ owner.addReadPermission(this);
}
- mReadOwners.add(owner);
}
/**
@@ -172,17 +239,20 @@ final class UriPermission {
}
if (mReadOwners.size() == 0) {
mReadOwners = null;
- if ((globalModeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
- modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
- }
+ ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
+ updateModeFlags();
}
}
private void addWriteOwner(UriPermissionOwner owner) {
if (mWriteOwners == null) {
mWriteOwners = Sets.newHashSet();
+ ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+ updateModeFlags();
+ }
+ if (mWriteOwners.add(owner)) {
+ owner.addWritePermission(this);
}
- mWriteOwners.add(owner);
}
/**
@@ -194,9 +264,8 @@ final class UriPermission {
}
if (mWriteOwners.size() == 0) {
mWriteOwners = null;
- if ((globalModeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
- modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
- }
+ ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+ updateModeFlags();
}
}
@@ -221,9 +290,15 @@ final class UriPermission {
pw.println(" targetPkg=" + targetPkg);
pw.print(prefix);
- pw.print("modeFlags=0x" + Integer.toHexString(modeFlags));
- pw.print(" globalModeFlags=0x" + Integer.toHexString(globalModeFlags));
- pw.println(" persistedModeFlags=0x" + Integer.toHexString(persistedModeFlags));
+ pw.print("mode=0x" + Integer.toHexString(modeFlags));
+ pw.print(" owned=0x" + Integer.toHexString(ownedModeFlags));
+ pw.print(" global=0x" + Integer.toHexString(globalModeFlags));
+ pw.print(" persistable=0x" + Integer.toHexString(persistableModeFlags));
+ pw.print(" persisted=0x" + Integer.toHexString(persistedModeFlags));
+ if (persistedCreateTime != INVALID_TIME) {
+ pw.print(" persistedCreate=" + persistedCreateTime);
+ }
+ pw.println();
if (mReadOwners != null) {
pw.print(prefix);
@@ -243,6 +318,13 @@ final class UriPermission {
}
}
+ public static class PersistedTimeComparator implements Comparator<UriPermission> {
+ @Override
+ public int compare(UriPermission lhs, UriPermission rhs) {
+ return Long.compare(lhs.persistedCreateTime, rhs.persistedCreateTime);
+ }
+ }
+
/**
* Snapshot of {@link UriPermission} with frozen
* {@link UriPermission#persistedModeFlags} state.
@@ -253,6 +335,7 @@ final class UriPermission {
final String targetPkg;
final Uri uri;
final int persistedModeFlags;
+ final long persistedCreateTime;
private Snapshot(UriPermission perm) {
this.userHandle = perm.userHandle;
@@ -260,10 +343,15 @@ final class UriPermission {
this.targetPkg = perm.targetPkg;
this.uri = perm.uri;
this.persistedModeFlags = perm.persistedModeFlags;
+ this.persistedCreateTime = perm.persistedCreateTime;
}
}
public Snapshot snapshot() {
return new Snapshot(this);
}
+
+ public android.content.UriPermission buildPersistedPublicApiObject() {
+ return new android.content.UriPermission(uri, persistedModeFlags, persistedCreateTime);
+ }
}