diff options
Diffstat (limited to 'services/java')
-rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 225 | ||||
-rw-r--r-- | services/java/com/android/server/am/UriPermission.java | 190 |
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); + } } |