blob: 5e2ad00955ed567f689b5906bb98f08eebf00e70 [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;
23
24import com.android.internal.util.IndentingPrintWriter;
25import com.google.android.collect.Sets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026
27import java.io.PrintWriter;
28import java.util.HashSet;
29
Dianne Hackborn7e269642010-08-25 19:50:20 -070030/**
31 * Description of a permission granted to an app to access a particular URI.
32 *
33 * CTS tests for this functionality can be run with "runtest cts-appsecurity".
34 *
Dianne Hackborncca1f0e2010-09-26 18:34:53 -070035 * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/
36 * src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
Dianne Hackborn7e269642010-08-25 19:50:20 -070037 */
Dianne Hackbornbe4e6aa2013-06-07 13:25:29 -070038final class UriPermission {
Jeff Sharkey328ebf22013-03-21 18:09:39 -070039 private static final String TAG = "UriPermission";
40
41 final int userHandle;
42 final String sourcePkg;
43 final String targetPkg;
44
45 /** Cached UID of {@link #targetPkg}; should not be persisted */
46 final int targetUid;
47
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048 final Uri uri;
Jeff Sharkey328ebf22013-03-21 18:09:39 -070049
50 /**
51 * Allowed modes. All permission enforcement should use this field. Must
52 * always be a superset of {@link #globalModeFlags},
53 * {@link #persistedModeFlags}, {@link #mReadOwners}, and
54 * {@link #mWriteOwners}. Mutations should only be performed by the owning
55 * class.
56 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057 int modeFlags = 0;
Jeff Sharkey328ebf22013-03-21 18:09:39 -070058
59 /**
60 * Allowed modes without explicit owner. Must always be a superset of
61 * {@link #persistedModeFlags}. Mutations should only be performed by the
62 * owning class.
63 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064 int globalModeFlags = 0;
Jeff Sharkey328ebf22013-03-21 18:09:39 -070065
66 /**
67 * Allowed modes that should be persisted across device boots. These modes
68 * have no explicit owners. Mutations should only be performed by the owning
69 * class.
70 */
71 int persistedModeFlags = 0;
72
73 private HashSet<UriPermissionOwner> mReadOwners;
74 private HashSet<UriPermissionOwner> mWriteOwners;
75
76 private String stringName;
77
78 UriPermission(String sourcePkg, String targetPkg, int targetUid, Uri uri) {
79 this.userHandle = UserHandle.getUserId(targetUid);
80 this.sourcePkg = sourcePkg;
81 this.targetPkg = targetPkg;
82 this.targetUid = targetUid;
83 this.uri = uri;
84 }
85
86 /**
87 * @return If mode changes should trigger persisting.
88 */
89 boolean grantModes(int modeFlagsToGrant, boolean persist, UriPermissionOwner owner) {
90 boolean persistChanged = false;
91
92 modeFlags |= modeFlagsToGrant;
93
94 if (persist) {
95 final int before = persistedModeFlags;
96 persistedModeFlags |= modeFlagsToGrant;
97 persistChanged = persistedModeFlags != before;
98
99 // Treat persisted grants as global (ownerless)
100 owner = null;
101 }
102
103 if (owner == null) {
104 globalModeFlags |= modeFlags;
105 } else {
106 if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
107 addReadOwner(owner);
108 owner.addReadPermission(this);
109 }
110 if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
111 addWriteOwner(owner);
112 owner.addWritePermission(this);
113 }
114 }
115
116 return persistChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 }
118
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700119 /**
120 * @return If mode changes should trigger persisting.
121 */
122 boolean clearModes(int modeFlagsToClear, boolean persist) {
123 final int before = persistedModeFlags;
124
125 if ((modeFlagsToClear & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
126 if (persist) {
127 persistedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
128 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
130 modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700131 if (mReadOwners != null) {
132 for (UriPermissionOwner r : mReadOwners) {
Dianne Hackborn39792d22010-08-19 18:01:52 -0700133 r.removeReadPermission(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 }
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700135 mReadOwners = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 }
137 }
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700138 if ((modeFlagsToClear & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
139 if (persist) {
140 persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
141 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
143 modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700144 if (mWriteOwners != null) {
145 for (UriPermissionOwner r : mWriteOwners) {
Dianne Hackborn39792d22010-08-19 18:01:52 -0700146 r.removeWritePermission(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 }
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700148 mWriteOwners = null;
149 }
150 }
151
152 // Mode flags always bubble up
153 globalModeFlags |= persistedModeFlags;
154 modeFlags |= globalModeFlags;
155
156 return persistedModeFlags != before;
157 }
158
159 private void addReadOwner(UriPermissionOwner owner) {
160 if (mReadOwners == null) {
161 mReadOwners = Sets.newHashSet();
162 }
163 mReadOwners.add(owner);
164 }
165
166 /**
167 * Remove given read owner, updating {@Link #modeFlags} as needed.
168 */
169 void removeReadOwner(UriPermissionOwner owner) {
170 if (!mReadOwners.remove(owner)) {
171 Log.wtf(TAG, "Unknown read owner " + owner + " in " + this);
172 }
173 if (mReadOwners.size() == 0) {
174 mReadOwners = null;
175 if ((globalModeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
176 modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 }
178 }
179 }
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700180
181 private void addWriteOwner(UriPermissionOwner owner) {
182 if (mWriteOwners == null) {
183 mWriteOwners = Sets.newHashSet();
184 }
185 mWriteOwners.add(owner);
186 }
187
188 /**
189 * Remove given write owner, updating {@Link #modeFlags} as needed.
190 */
191 void removeWriteOwner(UriPermissionOwner owner) {
192 if (!mWriteOwners.remove(owner)) {
193 Log.wtf(TAG, "Unknown write owner " + owner + " in " + this);
194 }
195 if (mWriteOwners.size() == 0) {
196 mWriteOwners = null;
197 if ((globalModeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
198 modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
199 }
200 }
201 }
202
203 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700205 if (stringName != null) {
206 return stringName;
207 }
208 StringBuilder sb = new StringBuilder(128);
209 sb.append("UriPermission{");
210 sb.append(Integer.toHexString(System.identityHashCode(this)));
211 sb.append(' ');
212 sb.append(uri);
213 sb.append('}');
214 return stringName = sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 }
216
217 void dump(PrintWriter pw, String prefix) {
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700218 pw.print(prefix);
219 pw.print("userHandle=" + userHandle);
Jeff Sharkey9e0036e2013-04-26 16:54:55 -0700220 pw.print(" sourcePkg=" + sourcePkg);
221 pw.println(" targetPkg=" + targetPkg);
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700222
223 pw.print(prefix);
224 pw.print("modeFlags=0x" + Integer.toHexString(modeFlags));
Jeff Sharkey9e0036e2013-04-26 16:54:55 -0700225 pw.print(" globalModeFlags=0x" + Integer.toHexString(globalModeFlags));
226 pw.println(" persistedModeFlags=0x" + Integer.toHexString(persistedModeFlags));
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700227
228 if (mReadOwners != null) {
229 pw.print(prefix);
230 pw.println("readOwners:");
231 for (UriPermissionOwner owner : mReadOwners) {
232 pw.print(prefix);
233 pw.println(" * " + owner);
Dianne Hackborn39792d22010-08-19 18:01:52 -0700234 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700235 }
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700236 if (mWriteOwners != null) {
237 pw.print(prefix);
238 pw.println("writeOwners:");
239 for (UriPermissionOwner owner : mReadOwners) {
240 pw.print(prefix);
241 pw.println(" * " + owner);
Dianne Hackborn39792d22010-08-19 18:01:52 -0700242 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700243 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 }
Jeff Sharkey328ebf22013-03-21 18:09:39 -0700245
246 /**
247 * Snapshot of {@link UriPermission} with frozen
248 * {@link UriPermission#persistedModeFlags} state.
249 */
250 public static class Snapshot {
251 final int userHandle;
252 final String sourcePkg;
253 final String targetPkg;
254 final Uri uri;
255 final int persistedModeFlags;
256
257 private Snapshot(UriPermission perm) {
258 this.userHandle = perm.userHandle;
259 this.sourcePkg = perm.sourcePkg;
260 this.targetPkg = perm.targetPkg;
261 this.uri = perm.uri;
262 this.persistedModeFlags = perm.persistedModeFlags;
263 }
264 }
265
266 public Snapshot snapshot() {
267 return new Snapshot(this);
268 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269}