blob: 2a59a1d254434c61f0cf8b47f9cb696166d73a77 [file] [log] [blame]
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001/*
2 * Copyright (C) 2012 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 android.app;
18
Dianne Hackbornf265ea92013-01-31 15:00:51 -080019import android.Manifest;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080020import com.android.internal.app.IAppOpsService;
21
Dianne Hackborn35654b62013-01-14 17:38:02 -080022import java.util.ArrayList;
23import java.util.List;
24
Dianne Hackborna06de0f2012-12-11 16:34:47 -080025import android.content.Context;
Dianne Hackborn35654b62013-01-14 17:38:02 -080026import android.os.Parcel;
27import android.os.Parcelable;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080028import android.os.Process;
29import android.os.RemoteException;
30
31/** @hide */
32public class AppOpsManager {
33 final Context mContext;
34 final IAppOpsService mService;
35
36 public static final int MODE_ALLOWED = 0;
37 public static final int MODE_IGNORED = 1;
38 public static final int MODE_ERRORED = 2;
39
Dianne Hackbornf51f6122013-02-04 18:23:34 -080040 public static final int OP_NONE = -1;
Dianne Hackborn35654b62013-01-14 17:38:02 -080041 public static final int OP_COARSE_LOCATION = 0;
42 public static final int OP_FINE_LOCATION = 1;
43 public static final int OP_GPS = 2;
44 public static final int OP_VIBRATE = 3;
45 public static final int OP_READ_CONTACTS = 4;
46 public static final int OP_WRITE_CONTACTS = 5;
47 public static final int OP_READ_CALL_LOG = 6;
48 public static final int OP_WRITE_CALL_LOG = 7;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -080049 public static final int OP_READ_CALENDAR = 8;
50 public static final int OP_WRITE_CALENDAR = 9;
51 public static final int OP_WIFI_SCAN = 10;
Daniel Sandler4a900ac2013-01-30 14:04:10 -050052 public static final int OP_POST_NOTIFICATION = 11;
Dianne Hackbornf265ea92013-01-31 15:00:51 -080053 public static final int OP_NEIGHBORING_CELLS = 12;
54 public static final int OP_CALL_PHONE = 13;
Dianne Hackbornf51f6122013-02-04 18:23:34 -080055 public static final int OP_READ_SMS = 14;
56 public static final int OP_WRITE_SMS = 15;
57 public static final int OP_RECEIVE_SMS = 16;
58 public static final int OP_RECEIVE_EMERGECY_SMS = 17;
59 public static final int OP_RECEIVE_MMS = 18;
60 public static final int OP_RECEIVE_WAP_PUSH = 19;
61 public static final int OP_SEND_SMS = 20;
62 public static final int OP_READ_ICC_SMS = 21;
63 public static final int OP_WRITE_ICC_SMS = 22;
Dianne Hackbornf265ea92013-01-31 15:00:51 -080064 /** @hide */
Dianne Hackbornf51f6122013-02-04 18:23:34 -080065 public static final int _NUM_OP = 23;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080066
Dianne Hackbornf265ea92013-01-31 15:00:51 -080067 /**
68 * This maps each operation to the operation that serves as the
69 * switch to determine whether it is allowed. Generally this is
70 * a 1:1 mapping, but for some things (like location) that have
71 * multiple low-level operations being tracked that should be
72 * presented to hte user as one switch then this can be used to
73 * make them all controlled by the same single operation.
74 */
75 private static int[] sOpToSwitch = new int[] {
76 OP_COARSE_LOCATION,
77 OP_COARSE_LOCATION,
78 OP_COARSE_LOCATION,
79 OP_VIBRATE,
80 OP_READ_CONTACTS,
81 OP_WRITE_CONTACTS,
82 OP_READ_CALL_LOG,
83 OP_WRITE_CALL_LOG,
84 OP_READ_CALENDAR,
85 OP_WRITE_CALENDAR,
86 OP_COARSE_LOCATION,
87 OP_POST_NOTIFICATION,
88 OP_COARSE_LOCATION,
89 OP_CALL_PHONE,
Dianne Hackbornf51f6122013-02-04 18:23:34 -080090 OP_READ_SMS,
91 OP_WRITE_SMS,
92 OP_READ_SMS,
93 OP_READ_SMS,
94 OP_READ_SMS,
95 OP_READ_SMS,
96 OP_WRITE_SMS,
97 OP_READ_SMS,
98 OP_WRITE_SMS,
Dianne Hackbornf265ea92013-01-31 15:00:51 -080099 };
100
101 /**
102 * This provides a simple name for each operation to be used
103 * in debug output.
104 */
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800105 private static String[] sOpNames = new String[] {
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800106 "COARSE_LOCATION",
107 "FINE_LOCATION",
108 "GPS",
109 "VIBRATE",
110 "READ_CONTACTS",
111 "WRITE_CONTACTS",
112 "READ_CALL_LOG",
113 "WRITE_CALL_LOG",
114 "READ_CALENDAR",
115 "WRITE_CALENDAR",
116 "WIFI_SCAN",
117 "POST_NOTIFICATION",
118 "NEIGHBORING_CELLS",
119 "CALL_PHONE",
Dianne Hackbornf51f6122013-02-04 18:23:34 -0800120 "READ_SMS",
121 "WRITE_SMS",
122 "RECEIVE_SMS",
123 "RECEIVE_EMERGECY_SMS",
124 "RECEIVE_MMS",
125 "RECEIVE_WAP_PUSH",
126 "SEND_SMS",
127 "READ_ICC_SMS",
128 "WRITE_ICC_SMS",
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800129 };
130
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800131 /**
132 * This optionally maps a permission to an operation. If there
133 * is no permission associated with an operation, it is null.
134 */
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800135 private static String[] sOpPerms = new String[] {
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800136 android.Manifest.permission.ACCESS_COARSE_LOCATION,
137 android.Manifest.permission.ACCESS_FINE_LOCATION,
138 null,
139 android.Manifest.permission.VIBRATE,
140 android.Manifest.permission.READ_CONTACTS,
141 android.Manifest.permission.WRITE_CONTACTS,
142 android.Manifest.permission.READ_CALL_LOG,
143 android.Manifest.permission.WRITE_CALL_LOG,
144 android.Manifest.permission.READ_CALENDAR,
145 android.Manifest.permission.WRITE_CALENDAR,
146 null, // no permission required for notifications
147 android.Manifest.permission.ACCESS_WIFI_STATE,
148 null, // neighboring cells shares the coarse location perm
149 android.Manifest.permission.CALL_PHONE,
Dianne Hackbornf51f6122013-02-04 18:23:34 -0800150 android.Manifest.permission.READ_SMS,
151 android.Manifest.permission.WRITE_SMS,
152 android.Manifest.permission.RECEIVE_SMS,
153 android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST,
154 android.Manifest.permission.RECEIVE_MMS,
155 android.Manifest.permission.RECEIVE_WAP_PUSH,
156 android.Manifest.permission.SEND_SMS,
157 android.Manifest.permission.READ_SMS,
158 android.Manifest.permission.WRITE_SMS,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800159 };
160
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800161 public static int opToSwitch(int op) {
162 return sOpToSwitch[op];
163 }
164
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800165 public static String opToName(int op) {
166 return op < sOpNames.length ? sOpNames[op] : ("Unknown(" + op + ")");
167 }
168
169 public static String opToPermission(int op) {
170 return sOpPerms[op];
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800171 }
172
Dianne Hackborn35654b62013-01-14 17:38:02 -0800173 public static class PackageOps implements Parcelable {
174 private final String mPackageName;
175 private final int mUid;
176 private final List<OpEntry> mEntries;
177
178 public PackageOps(String packageName, int uid, List<OpEntry> entries) {
179 mPackageName = packageName;
180 mUid = uid;
181 mEntries = entries;
182 }
183
184 public String getPackageName() {
185 return mPackageName;
186 }
187
188 public int getUid() {
189 return mUid;
190 }
191
192 public List<OpEntry> getOps() {
193 return mEntries;
194 }
195
196 @Override
197 public int describeContents() {
198 return 0;
199 }
200
201 @Override
202 public void writeToParcel(Parcel dest, int flags) {
203 dest.writeString(mPackageName);
204 dest.writeInt(mUid);
205 dest.writeInt(mEntries.size());
206 for (int i=0; i<mEntries.size(); i++) {
207 mEntries.get(i).writeToParcel(dest, flags);
208 }
209 }
210
211 PackageOps(Parcel source) {
212 mPackageName = source.readString();
213 mUid = source.readInt();
214 mEntries = new ArrayList<OpEntry>();
215 final int N = source.readInt();
216 for (int i=0; i<N; i++) {
217 mEntries.add(OpEntry.CREATOR.createFromParcel(source));
218 }
219 }
220
221 public static final Creator<PackageOps> CREATOR = new Creator<PackageOps>() {
222 @Override public PackageOps createFromParcel(Parcel source) {
223 return new PackageOps(source);
224 }
225
226 @Override public PackageOps[] newArray(int size) {
227 return new PackageOps[size];
228 }
229 };
230 }
231
232 public static class OpEntry implements Parcelable {
233 private final int mOp;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800234 private final int mMode;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800235 private final long mTime;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800236 private final long mRejectTime;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800237 private final int mDuration;
238
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800239 public OpEntry(int op, int mode, long time, long rejectTime, int duration) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800240 mOp = op;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800241 mMode = mode;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800242 mTime = time;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800243 mRejectTime = rejectTime;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800244 mDuration = duration;
245 }
246
247 public int getOp() {
248 return mOp;
249 }
250
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800251 public int getMode() {
252 return mMode;
253 }
254
Dianne Hackborn35654b62013-01-14 17:38:02 -0800255 public long getTime() {
256 return mTime;
257 }
258
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800259 public long getRejectTime() {
260 return mRejectTime;
261 }
262
Dianne Hackborn35654b62013-01-14 17:38:02 -0800263 public boolean isRunning() {
264 return mDuration == -1;
265 }
266
267 public int getDuration() {
268 return mDuration == -1 ? (int)(System.currentTimeMillis()-mTime) : mDuration;
269 }
270
271 @Override
272 public int describeContents() {
273 return 0;
274 }
275
276 @Override
277 public void writeToParcel(Parcel dest, int flags) {
278 dest.writeInt(mOp);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800279 dest.writeInt(mMode);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800280 dest.writeLong(mTime);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800281 dest.writeLong(mRejectTime);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800282 dest.writeInt(mDuration);
283 }
284
285 OpEntry(Parcel source) {
286 mOp = source.readInt();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800287 mMode = source.readInt();
Dianne Hackborn35654b62013-01-14 17:38:02 -0800288 mTime = source.readLong();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800289 mRejectTime = source.readLong();
Dianne Hackborn35654b62013-01-14 17:38:02 -0800290 mDuration = source.readInt();
291 }
292
293 public static final Creator<OpEntry> CREATOR = new Creator<OpEntry>() {
294 @Override public OpEntry createFromParcel(Parcel source) {
295 return new OpEntry(source);
296 }
297
298 @Override public OpEntry[] newArray(int size) {
299 return new OpEntry[size];
300 }
301 };
302 }
303
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800304 public AppOpsManager(Context context, IAppOpsService service) {
305 mContext = context;
306 mService = service;
307 }
308
Dianne Hackborn35654b62013-01-14 17:38:02 -0800309 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
310 try {
311 return mService.getPackagesForOps(ops);
312 } catch (RemoteException e) {
313 }
314 return null;
315 }
316
Dianne Hackborn72e39832013-01-18 18:36:09 -0800317 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
318 try {
319 return mService.getOpsForPackage(uid, packageName, ops);
320 } catch (RemoteException e) {
321 }
322 return null;
323 }
324
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800325 public void setMode(int code, int uid, String packageName, int mode) {
326 try {
327 mService.setMode(code, uid, packageName, mode);
328 } catch (RemoteException e) {
329 }
330 }
331
Dianne Hackborn35654b62013-01-14 17:38:02 -0800332 public int checkOp(int op, int uid, String packageName) {
333 try {
334 int mode = mService.checkOperation(op, uid, packageName);
335 if (mode == MODE_ERRORED) {
336 throw new SecurityException("Operation not allowed");
337 }
338 return mode;
339 } catch (RemoteException e) {
340 }
341 return MODE_IGNORED;
342 }
343
344 public int checkOpNoThrow(int op, int uid, String packageName) {
345 try {
346 return mService.checkOperation(op, uid, packageName);
347 } catch (RemoteException e) {
348 }
349 return MODE_IGNORED;
350 }
351
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800352 public int noteOp(int op, int uid, String packageName) {
353 try {
354 int mode = mService.noteOperation(op, uid, packageName);
355 if (mode == MODE_ERRORED) {
356 throw new SecurityException("Operation not allowed");
357 }
358 return mode;
359 } catch (RemoteException e) {
360 }
361 return MODE_IGNORED;
362 }
363
364 public int noteOpNoThrow(int op, int uid, String packageName) {
365 try {
366 return mService.noteOperation(op, uid, packageName);
367 } catch (RemoteException e) {
368 }
369 return MODE_IGNORED;
370 }
371
372 public int noteOp(int op) {
Dianne Hackbornd8e1dbb2013-01-17 17:47:37 -0800373 return noteOp(op, Process.myUid(), mContext.getBasePackageName());
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800374 }
375
376 public int startOp(int op, int uid, String packageName) {
377 try {
378 int mode = mService.startOperation(op, uid, packageName);
379 if (mode == MODE_ERRORED) {
380 throw new SecurityException("Operation not allowed");
381 }
382 return mode;
383 } catch (RemoteException e) {
384 }
385 return MODE_IGNORED;
386 }
387
388 public int startOpNoThrow(int op, int uid, String packageName) {
389 try {
390 return mService.startOperation(op, uid, packageName);
391 } catch (RemoteException e) {
392 }
393 return MODE_IGNORED;
394 }
395
396 public int startOp(int op) {
Dianne Hackbornd8e1dbb2013-01-17 17:47:37 -0800397 return startOp(op, Process.myUid(), mContext.getBasePackageName());
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800398 }
399
400 public void finishOp(int op, int uid, String packageName) {
401 try {
402 mService.finishOperation(op, uid, packageName);
403 } catch (RemoteException e) {
404 }
405 }
406
407 public void finishOp(int op) {
Dianne Hackbornd8e1dbb2013-01-17 17:47:37 -0800408 finishOp(op, Process.myUid(), mContext.getBasePackageName());
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800409 }
410}