blob: 7057c248258d7bbdf88dc53eb1c0887c8b89c555 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17package com.android.server.am;
18
19import android.content.Intent;
20import android.net.Uri;
Jeff Sharkey328ebf22013-03-21 18:09:39 -070021import android.os.UserHandle;
22import android.util.Log;
Jeff Sharkeye66c1772013-09-20 14:30:59 -070023import android.util.Slog;
Jeff Sharkey328ebf22013-03-21 18:09:39 -070024
Jeff Sharkey328ebf22013-03-21 18:09:39 -070025import com.google.android.collect.Sets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026
27import java.io.PrintWriter;
Jeff Sharkeye66c1772013-09-20 14:30:59 -070028import java.util.Comparator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import java.util.HashSet;
30
Dianne Hackborn7e269642010-08-25 19:50:20 -070031/**
32 * Description of a permission granted to an app to access a particular URI.
33 *
34 * CTS tests for this functionality can be run with "runtest cts-appsecurity".
35 *
Dianne Hackborncca1f0e2010-09-26 18:34:53 -070036 * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/
37 * src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
Dianne Hackborn7e269642010-08-25 19:50:20 -070038 */
Dianne Hackbornbe4e6aa2013-06-07 13:25:29 -070039final class UriPermission {
Jeff Sharkey328ebf22013-03-21 18:09:39 -070040 private static final String TAG = "UriPermission";
41
Jeff Sharkeye66c1772013-09-20 14:30:59 -070042 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;
46
Jeff Sharkey328ebf22013-03-21 18:09:39 -070047 final int userHandle;
48 final String sourcePkg;
49 final String targetPkg;
50
51 /** Cached UID of {@link #targetPkg}; should not be persisted */
52 final int targetUid;
53
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054 final Uri uri;
Jeff Sharkey328ebf22013-03-21 18:09:39 -070055
56 /**
57 * Allowed modes. All permission enforcement should use this field. Must
Jeff Sharkeye66c1772013-09-20 14:30:59 -070058 * always be a combination of {@link #ownedModeFlags},
59 * {@link #globalModeFlags}, {@link #persistableModeFlags}, and
60 * {@link #persistedModeFlags}. Mutations <em>must</em> only be performed by
61 * the owning class.
Jeff Sharkey328ebf22013-03-21 18:09:39 -070062 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 int modeFlags = 0;
Jeff Sharkey328ebf22013-03-21 18:09:39 -070064
Jeff Sharkeye66c1772013-09-20 14:30:59 -070065 /** Allowed modes with explicit owner. */
66 int ownedModeFlags = 0;
67 /** Allowed modes without explicit owner. */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068 int globalModeFlags = 0;
Jeff Sharkeye66c1772013-09-20 14:30:59 -070069 /** Allowed modes that have been offered for possible persisting. */
70 int persistableModeFlags = 0;
71 /** Allowed modes that should be persisted across device boots. */
72 int persistedModeFlags = 0;
Jeff Sharkey328ebf22013-03-21 18:09:39 -070073
74 /**
Jeff Sharkeye66c1772013-09-20 14:30:59 -070075 * Timestamp when {@link #persistedModeFlags} was first defined in
76 * {@link System#currentTimeMillis()} time base.
Jeff Sharkey328ebf22013-03-21 18:09:39 -070077 */
Jeff Sharkeye66c1772013-09-20 14:30:59 -070078 long persistedCreateTime = INVALID_TIME;
79
80 private static final long INVALID_TIME = Long.MIN_VALUE;
Jeff Sharkey328ebf22013-03-21 18:09:39 -070081
82 private HashSet<UriPermissionOwner> mReadOwners;
83 private HashSet<UriPermissionOwner> mWriteOwners;
84
85 private String stringName;
86
87 UriPermission(String sourcePkg, String targetPkg, int targetUid, Uri uri) {
88 this.userHandle = UserHandle.getUserId(targetUid);
89 this.sourcePkg = sourcePkg;
90 this.targetPkg = targetPkg;
91 this.targetUid = targetUid;
92 this.uri = uri;
93 }
94
Jeff Sharkeye66c1772013-09-20 14:30:59 -070095 private void updateModeFlags() {
96 modeFlags = ownedModeFlags | globalModeFlags | persistableModeFlags | persistedModeFlags;
97 }
98
Jeff Sharkey328ebf22013-03-21 18:09:39 -070099 /**
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700100 * Initialize persisted modes as read from file. This doesn't issue any
101 * global or owner grants.
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700102 */
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700103 void initPersistedModes(int modeFlags, long createdTime) {
104 persistableModeFlags = modeFlags;
105 persistedModeFlags = modeFlags;
106 persistedCreateTime = createdTime;
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700107
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700108 updateModeFlags();
109 }
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700110
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700111 void grantModes(int modeFlags, boolean persistable, UriPermissionOwner owner) {
112 if (persistable) {
113 persistableModeFlags |= modeFlags;
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700114 }
115
116 if (owner == null) {
117 globalModeFlags |= modeFlags;
118 } else {
119 if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
120 addReadOwner(owner);
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700121 }
122 if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
123 addWriteOwner(owner);
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700124 }
125 }
126
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700127 updateModeFlags();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 }
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700129
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700130 /**
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700131 * @return if mode changes should trigger persisting.
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700132 */
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700133 boolean takePersistableModes(int modeFlags) {
134 if ((~persistableModeFlags & modeFlags) != 0) {
135 Slog.w(TAG, "Trying to take 0x" + Integer.toHexString(modeFlags) + " but only 0x"
136 + Integer.toHexString(persistableModeFlags) + " are available");
137 }
138
139 final int before = persistedModeFlags;
140 persistedModeFlags |= (persistableModeFlags & modeFlags);
141
142 if (persistedModeFlags != 0) {
143 persistedCreateTime = System.currentTimeMillis();
144 }
145
146 updateModeFlags();
147 return persistedModeFlags != before;
148 }
149
150 boolean releasePersistableModes(int modeFlags) {
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700151 final int before = persistedModeFlags;
152
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700153 persistableModeFlags &= ~modeFlags;
154 persistedModeFlags &= ~modeFlags;
155
156 if (persistedModeFlags == 0) {
157 persistedCreateTime = INVALID_TIME;
158 }
159
160 updateModeFlags();
161 return persistedModeFlags != before;
162 }
163
164 /**
165 * @return if mode changes should trigger persisting.
166 */
167 boolean clearModes(int modeFlags, boolean persistable) {
168 final int before = persistedModeFlags;
169
170 if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
171 if (persistable) {
172 persistableModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700173 persistedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
174 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700176 if (mReadOwners != null) {
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700177 ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700178 for (UriPermissionOwner r : mReadOwners) {
Dianne Hackborn39792d22010-08-19 18:01:52 -0700179 r.removeReadPermission(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 }
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700181 mReadOwners = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 }
183 }
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700184 if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
185 if (persistable) {
186 persistableModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700187 persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
188 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700190 if (mWriteOwners != null) {
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700191 ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700192 for (UriPermissionOwner r : mWriteOwners) {
Dianne Hackborn39792d22010-08-19 18:01:52 -0700193 r.removeWritePermission(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 }
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700195 mWriteOwners = null;
196 }
197 }
198
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700199 if (persistedModeFlags == 0) {
200 persistedCreateTime = INVALID_TIME;
201 }
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700202
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700203 updateModeFlags();
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700204 return persistedModeFlags != before;
205 }
206
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700207 /**
208 * Return strength of this permission grant for the given flags.
209 */
210 public int getStrength(int modeFlags) {
211 if ((persistableModeFlags & modeFlags) == modeFlags) {
212 return STRENGTH_PERSISTABLE;
213 } else if ((globalModeFlags & modeFlags) == modeFlags) {
214 return STRENGTH_GLOBAL;
215 } else if ((ownedModeFlags & modeFlags) == modeFlags) {
216 return STRENGTH_OWNED;
217 } else {
218 return STRENGTH_NONE;
219 }
220 }
221
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700222 private void addReadOwner(UriPermissionOwner owner) {
223 if (mReadOwners == null) {
224 mReadOwners = Sets.newHashSet();
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700225 ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
226 updateModeFlags();
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700227 }
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700228 if (mReadOwners.add(owner)) {
229 owner.addReadPermission(this);
230 }
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700231 }
232
233 /**
234 * Remove given read owner, updating {@Link #modeFlags} as needed.
235 */
236 void removeReadOwner(UriPermissionOwner owner) {
237 if (!mReadOwners.remove(owner)) {
238 Log.wtf(TAG, "Unknown read owner " + owner + " in " + this);
239 }
240 if (mReadOwners.size() == 0) {
241 mReadOwners = null;
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700242 ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
243 updateModeFlags();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 }
245 }
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700246
247 private void addWriteOwner(UriPermissionOwner owner) {
248 if (mWriteOwners == null) {
249 mWriteOwners = Sets.newHashSet();
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700250 ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
251 updateModeFlags();
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700252 }
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700253 if (mWriteOwners.add(owner)) {
254 owner.addWritePermission(this);
255 }
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700256 }
257
258 /**
259 * Remove given write owner, updating {@Link #modeFlags} as needed.
260 */
261 void removeWriteOwner(UriPermissionOwner owner) {
262 if (!mWriteOwners.remove(owner)) {
263 Log.wtf(TAG, "Unknown write owner " + owner + " in " + this);
264 }
265 if (mWriteOwners.size() == 0) {
266 mWriteOwners = null;
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700267 ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
268 updateModeFlags();
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700269 }
270 }
271
272 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700274 if (stringName != null) {
275 return stringName;
276 }
277 StringBuilder sb = new StringBuilder(128);
278 sb.append("UriPermission{");
279 sb.append(Integer.toHexString(System.identityHashCode(this)));
280 sb.append(' ');
281 sb.append(uri);
282 sb.append('}');
283 return stringName = sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 }
285
286 void dump(PrintWriter pw, String prefix) {
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700287 pw.print(prefix);
288 pw.print("userHandle=" + userHandle);
Jeff Sharkey9e0036e2013-04-26 16:54:55 -0700289 pw.print(" sourcePkg=" + sourcePkg);
290 pw.println(" targetPkg=" + targetPkg);
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700291
292 pw.print(prefix);
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700293 pw.print("mode=0x" + Integer.toHexString(modeFlags));
294 pw.print(" owned=0x" + Integer.toHexString(ownedModeFlags));
295 pw.print(" global=0x" + Integer.toHexString(globalModeFlags));
296 pw.print(" persistable=0x" + Integer.toHexString(persistableModeFlags));
297 pw.print(" persisted=0x" + Integer.toHexString(persistedModeFlags));
298 if (persistedCreateTime != INVALID_TIME) {
299 pw.print(" persistedCreate=" + persistedCreateTime);
300 }
301 pw.println();
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700302
303 if (mReadOwners != null) {
304 pw.print(prefix);
305 pw.println("readOwners:");
306 for (UriPermissionOwner owner : mReadOwners) {
307 pw.print(prefix);
308 pw.println(" * " + owner);
Dianne Hackborn39792d22010-08-19 18:01:52 -0700309 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700310 }
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700311 if (mWriteOwners != null) {
312 pw.print(prefix);
313 pw.println("writeOwners:");
314 for (UriPermissionOwner owner : mReadOwners) {
315 pw.print(prefix);
316 pw.println(" * " + owner);
Dianne Hackborn39792d22010-08-19 18:01:52 -0700317 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700318 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 }
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700320
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700321 public static class PersistedTimeComparator implements Comparator<UriPermission> {
322 @Override
323 public int compare(UriPermission lhs, UriPermission rhs) {
324 return Long.compare(lhs.persistedCreateTime, rhs.persistedCreateTime);
325 }
326 }
327
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700328 /**
329 * Snapshot of {@link UriPermission} with frozen
330 * {@link UriPermission#persistedModeFlags} state.
331 */
332 public static class Snapshot {
333 final int userHandle;
334 final String sourcePkg;
335 final String targetPkg;
336 final Uri uri;
337 final int persistedModeFlags;
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700338 final long persistedCreateTime;
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700339
340 private Snapshot(UriPermission perm) {
341 this.userHandle = perm.userHandle;
342 this.sourcePkg = perm.sourcePkg;
343 this.targetPkg = perm.targetPkg;
344 this.uri = perm.uri;
345 this.persistedModeFlags = perm.persistedModeFlags;
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700346 this.persistedCreateTime = perm.persistedCreateTime;
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700347 }
348 }
349
350 public Snapshot snapshot() {
351 return new Snapshot(this);
352 }
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700353
354 public android.content.UriPermission buildPersistedPublicApiObject() {
355 return new android.content.UriPermission(uri, persistedModeFlags, persistedCreateTime);
356 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357}