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.Slog;
24 import com.android.server.am.ActivityManagerService.GrantUri;
25 import com.google.android.collect.Sets;
27 import java.io.PrintWriter;
28 import java.util.Comparator;
31 * Description of a permission granted to an app to access a particular URI.
33 * CTS tests for this functionality can be run with "runtest cts-appsecurity".
35 * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/
36 * src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
38 final class UriPermission {
39 private static final String TAG = "UriPermission";
41 public static final int STRENGTH_NONE = 0;
42 public static final int STRENGTH_OWNED = 1;
43 public static final int STRENGTH_GLOBAL = 2;
44 public static final int STRENGTH_PERSISTABLE = 3;
46 final int targetUserId;
47 final String sourcePkg;
48 final String targetPkg;
50 /** Cached UID of {@link #targetPkg}; should not be persisted */
56 * Allowed modes. All permission enforcement should use this field. Must
57 * always be a combination of {@link #ownedModeFlags},
58 * {@link #globalModeFlags}, {@link #persistableModeFlags}, and
59 * {@link #persistedModeFlags}. Mutations <em>must</em> only be performed by
64 /** Allowed modes with active owner. */
65 int ownedModeFlags = 0;
66 /** Allowed modes without explicit owner. */
67 int globalModeFlags = 0;
68 /** Allowed modes that have been offered for possible persisting. */
69 int persistableModeFlags = 0;
71 /** Allowed modes that should be persisted across device boots. */
72 int persistedModeFlags = 0;
75 * Timestamp when {@link #persistedModeFlags} was first defined in
76 * {@link System#currentTimeMillis()} time base.
78 long persistedCreateTime = INVALID_TIME;
80 private static final long INVALID_TIME = Long.MIN_VALUE;
82 private ArraySet<UriPermissionOwner> mReadOwners;
83 private ArraySet<UriPermissionOwner> mWriteOwners;
85 private String stringName;
87 UriPermission(String sourcePkg, String targetPkg, int targetUid, GrantUri uri) {
88 this.targetUserId = UserHandle.getUserId(targetUid);
89 this.sourcePkg = sourcePkg;
90 this.targetPkg = targetPkg;
91 this.targetUid = targetUid;
95 private void updateModeFlags() {
96 modeFlags = ownedModeFlags | globalModeFlags | persistableModeFlags | persistedModeFlags;
100 * Initialize persisted modes as read from file. This doesn't issue any
101 * global or owner grants.
103 void initPersistedModes(int modeFlags, long createdTime) {
104 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
105 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
107 persistableModeFlags = modeFlags;
108 persistedModeFlags = modeFlags;
109 persistedCreateTime = createdTime;
114 void grantModes(int modeFlags, UriPermissionOwner owner) {
115 final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
116 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
117 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
120 persistableModeFlags |= modeFlags;
124 globalModeFlags |= modeFlags;
126 if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
129 if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
130 addWriteOwner(owner);
138 * @return if mode changes should trigger persisting.
140 boolean takePersistableModes(int modeFlags) {
141 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
142 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
144 if ((modeFlags & persistableModeFlags) != modeFlags) {
145 Slog.w(TAG, "Requested flags 0x"
146 + Integer.toHexString(modeFlags) + ", but only 0x"
147 + Integer.toHexString(persistableModeFlags) + " are allowed");
151 final int before = persistedModeFlags;
152 persistedModeFlags |= (persistableModeFlags & modeFlags);
154 if (persistedModeFlags != 0) {
155 persistedCreateTime = System.currentTimeMillis();
159 return persistedModeFlags != before;
162 boolean releasePersistableModes(int modeFlags) {
163 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
164 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
166 final int before = persistedModeFlags;
168 persistableModeFlags &= ~modeFlags;
169 persistedModeFlags &= ~modeFlags;
171 if (persistedModeFlags == 0) {
172 persistedCreateTime = INVALID_TIME;
176 return persistedModeFlags != before;
180 * @return if mode changes should trigger persisting.
182 boolean revokeModes(int modeFlags, boolean includingOwners) {
183 final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
184 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
185 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
187 final int before = persistedModeFlags;
189 if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
191 persistableModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
192 persistedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
194 globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
195 if (mReadOwners != null && includingOwners) {
196 ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
197 for (UriPermissionOwner r : mReadOwners) {
198 r.removeReadPermission(this);
203 if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
205 persistableModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
206 persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
208 globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
209 if (mWriteOwners != null && includingOwners) {
210 ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
211 for (UriPermissionOwner r : mWriteOwners) {
212 r.removeWritePermission(this);
218 if (persistedModeFlags == 0) {
219 persistedCreateTime = INVALID_TIME;
223 return persistedModeFlags != before;
227 * Return strength of this permission grant for the given flags.
229 public int getStrength(int modeFlags) {
230 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
231 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
232 if ((persistableModeFlags & modeFlags) == modeFlags) {
233 return STRENGTH_PERSISTABLE;
234 } else if ((globalModeFlags & modeFlags) == modeFlags) {
235 return STRENGTH_GLOBAL;
236 } else if ((ownedModeFlags & modeFlags) == modeFlags) {
237 return STRENGTH_OWNED;
239 return STRENGTH_NONE;
243 private void addReadOwner(UriPermissionOwner owner) {
244 if (mReadOwners == null) {
245 mReadOwners = Sets.newArraySet();
246 ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
249 if (mReadOwners.add(owner)) {
250 owner.addReadPermission(this);
255 * Remove given read owner, updating {@Link #modeFlags} as needed.
257 void removeReadOwner(UriPermissionOwner owner) {
258 if (!mReadOwners.remove(owner)) {
259 Slog.wtf(TAG, "Unknown read owner " + owner + " in " + this);
261 if (mReadOwners.size() == 0) {
263 ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
268 private void addWriteOwner(UriPermissionOwner owner) {
269 if (mWriteOwners == null) {
270 mWriteOwners = Sets.newArraySet();
271 ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
274 if (mWriteOwners.add(owner)) {
275 owner.addWritePermission(this);
280 * Remove given write owner, updating {@Link #modeFlags} as needed.
282 void removeWriteOwner(UriPermissionOwner owner) {
283 if (!mWriteOwners.remove(owner)) {
284 Slog.wtf(TAG, "Unknown write owner " + owner + " in " + this);
286 if (mWriteOwners.size() == 0) {
288 ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
294 public String toString() {
295 if (stringName != null) {
298 StringBuilder sb = new StringBuilder(128);
299 sb.append("UriPermission{");
300 sb.append(Integer.toHexString(System.identityHashCode(this)));
304 return stringName = sb.toString();
307 void dump(PrintWriter pw, String prefix) {
309 pw.print("targetUserId=" + targetUserId);
310 pw.print(" sourcePkg=" + sourcePkg);
311 pw.println(" targetPkg=" + targetPkg);
314 pw.print("mode=0x" + Integer.toHexString(modeFlags));
315 pw.print(" owned=0x" + Integer.toHexString(ownedModeFlags));
316 pw.print(" global=0x" + Integer.toHexString(globalModeFlags));
317 pw.print(" persistable=0x" + Integer.toHexString(persistableModeFlags));
318 pw.print(" persisted=0x" + Integer.toHexString(persistedModeFlags));
319 if (persistedCreateTime != INVALID_TIME) {
320 pw.print(" persistedCreate=" + persistedCreateTime);
324 if (mReadOwners != null) {
326 pw.println("readOwners:");
327 for (UriPermissionOwner owner : mReadOwners) {
329 pw.println(" * " + owner);
332 if (mWriteOwners != null) {
334 pw.println("writeOwners:");
335 for (UriPermissionOwner owner : mReadOwners) {
337 pw.println(" * " + owner);
342 public static class PersistedTimeComparator implements Comparator<UriPermission> {
344 public int compare(UriPermission lhs, UriPermission rhs) {
345 return Long.compare(lhs.persistedCreateTime, rhs.persistedCreateTime);
350 * Snapshot of {@link UriPermission} with frozen
351 * {@link UriPermission#persistedModeFlags} state.
353 public static class Snapshot {
354 final int targetUserId;
355 final String sourcePkg;
356 final String targetPkg;
358 final int persistedModeFlags;
359 final long persistedCreateTime;
361 private Snapshot(UriPermission perm) {
362 this.targetUserId = perm.targetUserId;
363 this.sourcePkg = perm.sourcePkg;
364 this.targetPkg = perm.targetPkg;
366 this.persistedModeFlags = perm.persistedModeFlags;
367 this.persistedCreateTime = perm.persistedCreateTime;
371 public Snapshot snapshot() {
372 return new Snapshot(this);
375 public android.content.UriPermission buildPersistedPublicApiObject() {
376 return new android.content.UriPermission(uri.uri, persistedModeFlags, persistedCreateTime);