2 * Copyright (C) 2006 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.server.am;
19 import android.content.Intent;
20 import android.os.UserHandle;
21 import android.util.ArraySet;
22 import android.util.Log;
23 import android.util.Slog;
25 import com.android.server.am.ActivityManagerService.GrantUri;
26 import com.google.android.collect.Sets;
28 import java.io.PrintWriter;
29 import java.util.Comparator;
32 * Description of a permission granted to an app to access a particular URI.
34 * CTS tests for this functionality can be run with "runtest cts-appsecurity".
36 * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/
37 * src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
39 final class UriPermission {
40 private static final String TAG = "UriPermission";
42 public static final int STRENGTH_NONE = 0;
43 public static final int STRENGTH_OWNED = 1;
44 public static final int STRENGTH_GLOBAL = 2;
45 public static final int STRENGTH_PERSISTABLE = 3;
47 final int targetUserId;
48 final String sourcePkg;
49 final String targetPkg;
51 /** Cached UID of {@link #targetPkg}; should not be persisted */
57 * Allowed modes. All permission enforcement should use this field. Must
58 * always be a combination of {@link #ownedModeFlags},
59 * {@link #globalModeFlags}, {@link #persistableModeFlags}, and
60 * {@link #persistedModeFlags}. Mutations <em>must</em> only be performed by
65 /** Allowed modes with active owner. */
66 int ownedModeFlags = 0;
67 /** Allowed modes without explicit owner. */
68 int globalModeFlags = 0;
69 /** Allowed modes that have been offered for possible persisting. */
70 int persistableModeFlags = 0;
72 /** Allowed modes that should be persisted across device boots. */
73 int persistedModeFlags = 0;
76 * Timestamp when {@link #persistedModeFlags} was first defined in
77 * {@link System#currentTimeMillis()} time base.
79 long persistedCreateTime = INVALID_TIME;
81 private static final long INVALID_TIME = Long.MIN_VALUE;
83 private ArraySet<UriPermissionOwner> mReadOwners;
84 private ArraySet<UriPermissionOwner> mWriteOwners;
86 private String stringName;
88 UriPermission(String sourcePkg, String targetPkg, int targetUid, GrantUri uri) {
89 this.targetUserId = UserHandle.getUserId(targetUid);
90 this.sourcePkg = sourcePkg;
91 this.targetPkg = targetPkg;
92 this.targetUid = targetUid;
96 private void updateModeFlags() {
97 final int oldModeFlags = modeFlags;
98 modeFlags = ownedModeFlags | globalModeFlags | persistableModeFlags | persistedModeFlags;
100 if (Log.isLoggable(TAG, Log.VERBOSE) && (modeFlags != oldModeFlags)) {
102 "Permission for " + targetPkg + " to " + uri + " is changing from 0x"
103 + Integer.toHexString(oldModeFlags) + " to 0x"
104 + Integer.toHexString(modeFlags),
110 * Initialize persisted modes as read from file. This doesn't issue any
111 * global or owner grants.
113 void initPersistedModes(int modeFlags, long createdTime) {
114 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
115 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
117 persistableModeFlags = modeFlags;
118 persistedModeFlags = modeFlags;
119 persistedCreateTime = createdTime;
124 void grantModes(int modeFlags, UriPermissionOwner owner) {
125 final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
126 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
127 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
130 persistableModeFlags |= modeFlags;
134 globalModeFlags |= modeFlags;
136 if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
139 if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
140 addWriteOwner(owner);
148 * @return if mode changes should trigger persisting.
150 boolean takePersistableModes(int modeFlags) {
151 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
152 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
154 if ((modeFlags & persistableModeFlags) != modeFlags) {
155 Slog.w(TAG, "Requested flags 0x"
156 + Integer.toHexString(modeFlags) + ", but only 0x"
157 + Integer.toHexString(persistableModeFlags) + " are allowed");
161 final int before = persistedModeFlags;
162 persistedModeFlags |= (persistableModeFlags & modeFlags);
164 if (persistedModeFlags != 0) {
165 persistedCreateTime = System.currentTimeMillis();
169 return persistedModeFlags != before;
172 boolean releasePersistableModes(int modeFlags) {
173 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
174 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
176 final int before = persistedModeFlags;
178 persistableModeFlags &= ~modeFlags;
179 persistedModeFlags &= ~modeFlags;
181 if (persistedModeFlags == 0) {
182 persistedCreateTime = INVALID_TIME;
186 return persistedModeFlags != before;
190 * @return if mode changes should trigger persisting.
192 boolean revokeModes(int modeFlags, boolean includingOwners) {
193 final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
194 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
195 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
197 final int before = persistedModeFlags;
199 if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
201 persistableModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
202 persistedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
204 globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
205 if (mReadOwners != null && includingOwners) {
206 ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
207 for (UriPermissionOwner r : mReadOwners) {
208 r.removeReadPermission(this);
213 if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
215 persistableModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
216 persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
218 globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
219 if (mWriteOwners != null && includingOwners) {
220 ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
221 for (UriPermissionOwner r : mWriteOwners) {
222 r.removeWritePermission(this);
228 if (persistedModeFlags == 0) {
229 persistedCreateTime = INVALID_TIME;
233 return persistedModeFlags != before;
237 * Return strength of this permission grant for the given flags.
239 public int getStrength(int modeFlags) {
240 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
241 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
242 if ((persistableModeFlags & modeFlags) == modeFlags) {
243 return STRENGTH_PERSISTABLE;
244 } else if ((globalModeFlags & modeFlags) == modeFlags) {
245 return STRENGTH_GLOBAL;
246 } else if ((ownedModeFlags & modeFlags) == modeFlags) {
247 return STRENGTH_OWNED;
249 return STRENGTH_NONE;
253 private void addReadOwner(UriPermissionOwner owner) {
254 if (mReadOwners == null) {
255 mReadOwners = Sets.newArraySet();
256 ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
259 if (mReadOwners.add(owner)) {
260 owner.addReadPermission(this);
265 * Remove given read owner, updating {@Link #modeFlags} as needed.
267 void removeReadOwner(UriPermissionOwner owner) {
268 if (!mReadOwners.remove(owner)) {
269 Slog.wtf(TAG, "Unknown read owner " + owner + " in " + this);
271 if (mReadOwners.size() == 0) {
273 ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
278 private void addWriteOwner(UriPermissionOwner owner) {
279 if (mWriteOwners == null) {
280 mWriteOwners = Sets.newArraySet();
281 ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
284 if (mWriteOwners.add(owner)) {
285 owner.addWritePermission(this);
290 * Remove given write owner, updating {@Link #modeFlags} as needed.
292 void removeWriteOwner(UriPermissionOwner owner) {
293 if (!mWriteOwners.remove(owner)) {
294 Slog.wtf(TAG, "Unknown write owner " + owner + " in " + this);
296 if (mWriteOwners.size() == 0) {
298 ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
304 public String toString() {
305 if (stringName != null) {
308 StringBuilder sb = new StringBuilder(128);
309 sb.append("UriPermission{");
310 sb.append(Integer.toHexString(System.identityHashCode(this)));
314 return stringName = sb.toString();
317 void dump(PrintWriter pw, String prefix) {
319 pw.print("targetUserId=" + targetUserId);
320 pw.print(" sourcePkg=" + sourcePkg);
321 pw.println(" targetPkg=" + targetPkg);
324 pw.print("mode=0x" + Integer.toHexString(modeFlags));
325 pw.print(" owned=0x" + Integer.toHexString(ownedModeFlags));
326 pw.print(" global=0x" + Integer.toHexString(globalModeFlags));
327 pw.print(" persistable=0x" + Integer.toHexString(persistableModeFlags));
328 pw.print(" persisted=0x" + Integer.toHexString(persistedModeFlags));
329 if (persistedCreateTime != INVALID_TIME) {
330 pw.print(" persistedCreate=" + persistedCreateTime);
334 if (mReadOwners != null) {
336 pw.println("readOwners:");
337 for (UriPermissionOwner owner : mReadOwners) {
339 pw.println(" * " + owner);
342 if (mWriteOwners != null) {
344 pw.println("writeOwners:");
345 for (UriPermissionOwner owner : mReadOwners) {
347 pw.println(" * " + owner);
352 public static class PersistedTimeComparator implements Comparator<UriPermission> {
354 public int compare(UriPermission lhs, UriPermission rhs) {
355 return Long.compare(lhs.persistedCreateTime, rhs.persistedCreateTime);
360 * Snapshot of {@link UriPermission} with frozen
361 * {@link UriPermission#persistedModeFlags} state.
363 public static class Snapshot {
364 final int targetUserId;
365 final String sourcePkg;
366 final String targetPkg;
368 final int persistedModeFlags;
369 final long persistedCreateTime;
371 private Snapshot(UriPermission perm) {
372 this.targetUserId = perm.targetUserId;
373 this.sourcePkg = perm.sourcePkg;
374 this.targetPkg = perm.targetPkg;
376 this.persistedModeFlags = perm.persistedModeFlags;
377 this.persistedCreateTime = perm.persistedCreateTime;
381 public Snapshot snapshot() {
382 return new Snapshot(this);
385 public android.content.UriPermission buildPersistedPublicApiObject() {
386 return new android.content.UriPermission(uri.uri, persistedModeFlags, persistedCreateTime);