diff options
Diffstat (limited to 'services/java/com/android/server/am/UriPermission.java')
-rw-r--r-- | services/java/com/android/server/am/UriPermission.java | 230 |
1 files changed, 198 insertions, 32 deletions
diff --git a/services/java/com/android/server/am/UriPermission.java b/services/java/com/android/server/am/UriPermission.java index c5b1c7b..e79faf9 100644 --- a/services/java/com/android/server/am/UriPermission.java +++ b/services/java/com/android/server/am/UriPermission.java @@ -18,6 +18,11 @@ package com.android.server.am; import android.content.Intent; import android.net.Uri; +import android.os.UserHandle; +import android.util.Log; + +import com.android.internal.util.IndentingPrintWriter; +import com.google.android.collect.Sets; import java.io.PrintWriter; import java.util.HashSet; @@ -31,43 +36,171 @@ import java.util.HashSet; * src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java */ class UriPermission { - final int uid; + private static final String TAG = "UriPermission"; + + final int userHandle; + final String sourcePkg; + final String targetPkg; + + /** Cached UID of {@link #targetPkg}; should not be persisted */ + final int targetUid; + final Uri uri; + + /** + * 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. + */ 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. + */ int globalModeFlags = 0; - final HashSet<UriPermissionOwner> readOwners = new HashSet<UriPermissionOwner>(); - final HashSet<UriPermissionOwner> writeOwners = new HashSet<UriPermissionOwner>(); - - String stringName; - - UriPermission(int _uid, Uri _uri) { - uid = _uid; - uri = _uri; + + /** + * Allowed modes that should be persisted across device boots. These modes + * have no explicit owners. Mutations should only be performed by the owning + * class. + */ + int persistedModeFlags = 0; + + private HashSet<UriPermissionOwner> mReadOwners; + private HashSet<UriPermissionOwner> mWriteOwners; + + private String stringName; + + UriPermission(String sourcePkg, String targetPkg, int targetUid, Uri uri) { + this.userHandle = UserHandle.getUserId(targetUid); + this.sourcePkg = sourcePkg; + this.targetPkg = targetPkg; + this.targetUid = targetUid; + this.uri = uri; + } + + /** + * @return If mode changes should trigger persisting. + */ + boolean grantModes(int modeFlagsToGrant, boolean persist, UriPermissionOwner owner) { + boolean persistChanged = false; + + modeFlags |= modeFlagsToGrant; + + if (persist) { + final int before = persistedModeFlags; + persistedModeFlags |= modeFlagsToGrant; + persistChanged = persistedModeFlags != before; + + // Treat persisted grants as global (ownerless) + owner = null; + } + + if (owner == null) { + globalModeFlags |= modeFlags; + } 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; } - void clearModes(int modeFlagsToClear) { - if ((modeFlagsToClear&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) { + /** + * @return If mode changes should trigger persisting. + */ + boolean clearModes(int modeFlagsToClear, boolean persist) { + final int before = persistedModeFlags; + + if ((modeFlagsToClear & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) { + if (persist) { + persistedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; + } globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; - if (readOwners.size() > 0) { - for (UriPermissionOwner r : readOwners) { + if (mReadOwners != null) { + for (UriPermissionOwner r : mReadOwners) { r.removeReadPermission(this); } - readOwners.clear(); + mReadOwners = null; } } - if ((modeFlagsToClear&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { + if ((modeFlagsToClear & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { + if (persist) { + persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; + } globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; - if (writeOwners.size() > 0) { - for (UriPermissionOwner r : writeOwners) { + if (mWriteOwners != null) { + for (UriPermissionOwner r : mWriteOwners) { r.removeWritePermission(this); } - writeOwners.clear(); + mWriteOwners = null; + } + } + + // Mode flags always bubble up + globalModeFlags |= persistedModeFlags; + modeFlags |= globalModeFlags; + + return persistedModeFlags != before; + } + + private void addReadOwner(UriPermissionOwner owner) { + if (mReadOwners == null) { + mReadOwners = Sets.newHashSet(); + } + mReadOwners.add(owner); + } + + /** + * Remove given read owner, updating {@Link #modeFlags} as needed. + */ + void removeReadOwner(UriPermissionOwner owner) { + if (!mReadOwners.remove(owner)) { + Log.wtf(TAG, "Unknown read owner " + owner + " in " + this); + } + if (mReadOwners.size() == 0) { + mReadOwners = null; + if ((globalModeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) { + modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; } } } - + + private void addWriteOwner(UriPermissionOwner owner) { + if (mWriteOwners == null) { + mWriteOwners = Sets.newHashSet(); + } + mWriteOwners.add(owner); + } + + /** + * Remove given write owner, updating {@Link #modeFlags} as needed. + */ + void removeWriteOwner(UriPermissionOwner owner) { + if (!mWriteOwners.remove(owner)) { + Log.wtf(TAG, "Unknown write owner " + owner + " in " + this); + } + if (mWriteOwners.size() == 0) { + mWriteOwners = null; + if ((globalModeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) { + modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; + } + } + } + + @Override public String toString() { if (stringName != null) { return stringName; @@ -82,22 +215,55 @@ class UriPermission { } void dump(PrintWriter pw, String prefix) { - pw.print(prefix); pw.print("modeFlags=0x"); - pw.print(Integer.toHexString(modeFlags)); - pw.print(" uid="); pw.print(uid); - pw.print(" globalModeFlags=0x"); - pw.println(Integer.toHexString(globalModeFlags)); - if (readOwners.size() != 0) { - pw.print(prefix); pw.println("readOwners:"); - for (UriPermissionOwner owner : readOwners) { - pw.print(prefix); pw.print(" * "); pw.println(owner); + pw.print(prefix); + pw.print("userHandle=" + userHandle); + pw.print("sourcePkg=" + sourcePkg); + 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)); + + if (mReadOwners != null) { + pw.print(prefix); + pw.println("readOwners:"); + for (UriPermissionOwner owner : mReadOwners) { + pw.print(prefix); + pw.println(" * " + owner); } } - if (writeOwners.size() != 0) { - pw.print(prefix); pw.println("writeOwners:"); - for (UriPermissionOwner owner : writeOwners) { - pw.print(prefix); pw.print(" * "); pw.println(owner); + if (mWriteOwners != null) { + pw.print(prefix); + pw.println("writeOwners:"); + for (UriPermissionOwner owner : mReadOwners) { + pw.print(prefix); + pw.println(" * " + owner); } } } + + /** + * Snapshot of {@link UriPermission} with frozen + * {@link UriPermission#persistedModeFlags} state. + */ + public static class Snapshot { + final int userHandle; + final String sourcePkg; + final String targetPkg; + final Uri uri; + final int persistedModeFlags; + + private Snapshot(UriPermission perm) { + this.userHandle = perm.userHandle; + this.sourcePkg = perm.sourcePkg; + this.targetPkg = perm.targetPkg; + this.uri = perm.uri; + this.persistedModeFlags = perm.persistedModeFlags; + } + } + + public Snapshot snapshot() { + return new Snapshot(this); + } } |