blob: e7db2a87c86581b5ae067c88ecd60dcb0de6603e [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 com.android.server;
18
19import java.io.File;
20import java.io.FileDescriptor;
Dianne Hackborn35654b62013-01-14 17:38:02 -080021import java.io.FileInputStream;
22import java.io.FileNotFoundException;
23import java.io.FileOutputStream;
24import java.io.IOException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080025import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +010026import java.nio.charset.StandardCharsets;
Dianne Hackborn35654b62013-01-14 17:38:02 -080027import java.util.ArrayList;
Ruben Brunk29931bc2016-03-11 00:24:26 -080028import java.util.Arrays;
Svetoslav215b44a2015-08-04 19:03:40 -070029import java.util.Collections;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080030import java.util.HashMap;
Dianne Hackbornc2293022013-02-06 23:14:49 -080031import java.util.Iterator;
Dianne Hackborn35654b62013-01-14 17:38:02 -080032import java.util.List;
Dianne Hackborn607b4142013-08-02 18:10:10 -070033import java.util.Map;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080034
Svet Ganov9cea80cd2016-02-16 11:47:00 -080035import android.Manifest;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -080036import android.app.ActivityManager;
Jason Monk1c7c3192014-06-26 12:52:18 -040037import android.app.ActivityThread;
Svet Ganov2af57082015-07-30 08:44:20 -070038import android.app.AppGlobals;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080039import android.app.AppOpsManager;
40import android.content.Context;
Jason Monk1c7c3192014-06-26 12:52:18 -040041import android.content.pm.ApplicationInfo;
42import android.content.pm.IPackageManager;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080043import android.content.pm.PackageManager;
John Spurlock7b414672014-07-18 13:02:39 -040044import android.media.AudioAttributes;
Dianne Hackborn35654b62013-01-14 17:38:02 -080045import android.os.AsyncTask;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080046import android.os.Binder;
Jason Monk62062992014-05-06 09:55:28 -040047import android.os.Bundle;
Dianne Hackborn35654b62013-01-14 17:38:02 -080048import android.os.Handler;
Dianne Hackbornc2293022013-02-06 23:14:49 -080049import android.os.IBinder;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080050import android.os.Process;
Dianne Hackbornc2293022013-02-06 23:14:49 -080051import android.os.RemoteException;
Dianne Hackborn268e4e32015-11-18 16:29:56 -080052import android.os.ResultReceiver;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080053import android.os.ServiceManager;
Dianne Hackborn268e4e32015-11-18 16:29:56 -080054import android.os.ShellCommand;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080055import android.os.UserHandle;
Svet Ganov6ee871e2015-07-10 14:29:33 -070056import android.os.storage.MountServiceInternal;
Dianne Hackborne98f5db2013-07-17 17:23:25 -070057import android.util.ArrayMap;
John Spurlock1af30c72014-03-10 08:33:35 -040058import android.util.ArraySet;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080059import android.util.AtomicFile;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -080060import android.util.Log;
Ruben Brunk29931bc2016-03-11 00:24:26 -080061import android.util.Pair;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080062import android.util.Slog;
63import android.util.SparseArray;
Svet Ganov2af57082015-07-30 08:44:20 -070064import android.util.SparseIntArray;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080065import android.util.TimeUtils;
Dianne Hackborn35654b62013-01-14 17:38:02 -080066import android.util.Xml;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080067
68import com.android.internal.app.IAppOpsService;
Dianne Hackbornc2293022013-02-06 23:14:49 -080069import com.android.internal.app.IAppOpsCallback;
Svet Ganov6ee871e2015-07-10 14:29:33 -070070import com.android.internal.os.Zygote;
Svet Ganov2af57082015-07-30 08:44:20 -070071import com.android.internal.util.ArrayUtils;
Dianne Hackborn35654b62013-01-14 17:38:02 -080072import com.android.internal.util.FastXmlSerializer;
Svet Ganov9cea80cd2016-02-16 11:47:00 -080073import com.android.internal.util.Preconditions;
Dianne Hackborn35654b62013-01-14 17:38:02 -080074import com.android.internal.util.XmlUtils;
75
Svet Ganov2af57082015-07-30 08:44:20 -070076import libcore.util.EmptyArray;
Dianne Hackborn35654b62013-01-14 17:38:02 -080077import org.xmlpull.v1.XmlPullParser;
78import org.xmlpull.v1.XmlPullParserException;
79import org.xmlpull.v1.XmlSerializer;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080080
81public class AppOpsService extends IAppOpsService.Stub {
82 static final String TAG = "AppOps";
Dianne Hackborn35654b62013-01-14 17:38:02 -080083 static final boolean DEBUG = false;
84
85 // Write at most every 30 minutes.
86 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080087
88 Context mContext;
89 final AtomicFile mFile;
Dianne Hackborn35654b62013-01-14 17:38:02 -080090 final Handler mHandler;
91
92 boolean mWriteScheduled;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -080093 boolean mFastWriteScheduled;
Dianne Hackborn35654b62013-01-14 17:38:02 -080094 final Runnable mWriteRunner = new Runnable() {
95 public void run() {
96 synchronized (AppOpsService.this) {
97 mWriteScheduled = false;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -080098 mFastWriteScheduled = false;
Dianne Hackborn35654b62013-01-14 17:38:02 -080099 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
100 @Override protected Void doInBackground(Void... params) {
101 writeState();
102 return null;
103 }
104 };
105 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
106 }
107 }
108 };
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800109
Svet Ganov9cea80cd2016-02-16 11:47:00 -0800110 private final SparseArray<UidState> mUidStates = new SparseArray<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800111
Ruben Brunk29931bc2016-03-11 00:24:26 -0800112 /*
113 * These are app op restrictions imposed per user from various parties.
114 *
115 * This is organized as follows:
116 *
117 * ArrayMap w/ mapping:
118 * IBinder (for client imposing restriction) --> SparseArray w/ mapping:
119 * User handle --> Pair containing:
120 * - Array w/ index = AppOp code, value = restricted status boolean
121 * - SparseArray w/ mapping:
122 * AppOp code --> Set of packages that are not restricted for this code
123 *
Ruben Brunk32f0fa42016-03-11 19:07:07 -0800124 * For efficiency, a core assumption here is that the number of per-package exemptions stored
125 * here will be relatively small. If this changes, this data structure should be revisited.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800126 */
127 private final ArrayMap<IBinder, SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>>>
128 mOpUserRestrictions = new ArrayMap<>();
Jason Monk62062992014-05-06 09:55:28 -0400129
Svet Ganov2af57082015-07-30 08:44:20 -0700130 private static final class UidState {
131 public final int uid;
132 public ArrayMap<String, Ops> pkgOps;
133 public SparseIntArray opModes;
134
135 public UidState(int uid) {
136 this.uid = uid;
137 }
138
139 public void clear() {
140 pkgOps = null;
141 opModes = null;
142 }
143
144 public boolean isDefault() {
145 return (pkgOps == null || pkgOps.isEmpty())
146 && (opModes == null || opModes.size() <= 0);
147 }
148 }
149
Dianne Hackbornc2293022013-02-06 23:14:49 -0800150 public final static class Ops extends SparseArray<Op> {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800151 public final String packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700152 public final UidState uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400153 public final boolean isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800154
Svet Ganov2af57082015-07-30 08:44:20 -0700155 public Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800156 packageName = _packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700157 uidState = _uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400158 isPrivileged = _isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800159 }
160 }
161
Dianne Hackbornc2293022013-02-06 23:14:49 -0800162 public final static class Op {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700163 public final int uid;
164 public final String packageName;
Svet Ganov99b60432015-06-27 13:15:22 -0700165 public int proxyUid = -1;
166 public String proxyPackageName;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800167 public final int op;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800168 public int mode;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800169 public int duration;
170 public long time;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800171 public long rejectTime;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800172 public int nesting;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800173
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700174 public Op(int _uid, String _packageName, int _op) {
175 uid = _uid;
176 packageName = _packageName;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800177 op = _op;
David Braunf5d83192013-09-16 13:43:51 -0700178 mode = AppOpsManager.opToDefaultMode(op);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800179 }
180 }
181
Dianne Hackbornc2293022013-02-06 23:14:49 -0800182 final SparseArray<ArrayList<Callback>> mOpModeWatchers
183 = new SparseArray<ArrayList<Callback>>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700184 final ArrayMap<String, ArrayList<Callback>> mPackageModeWatchers
185 = new ArrayMap<String, ArrayList<Callback>>();
186 final ArrayMap<IBinder, Callback> mModeWatchers
187 = new ArrayMap<IBinder, Callback>();
John Spurlock1af30c72014-03-10 08:33:35 -0400188 final SparseArray<SparseArray<Restriction>> mAudioRestrictions
189 = new SparseArray<SparseArray<Restriction>>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800190
191 public final class Callback implements DeathRecipient {
192 final IAppOpsCallback mCallback;
193
194 public Callback(IAppOpsCallback callback) {
195 mCallback = callback;
196 try {
197 mCallback.asBinder().linkToDeath(this, 0);
198 } catch (RemoteException e) {
199 }
200 }
201
202 public void unlinkToDeath() {
203 mCallback.asBinder().unlinkToDeath(this, 0);
204 }
205
206 @Override
207 public void binderDied() {
208 stopWatchingMode(mCallback);
209 }
210 }
211
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700212 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<IBinder, ClientState>();
213
214 public final class ClientState extends Binder implements DeathRecipient {
215 final IBinder mAppToken;
216 final int mPid;
217 final ArrayList<Op> mStartedOps;
218
219 public ClientState(IBinder appToken) {
220 mAppToken = appToken;
221 mPid = Binder.getCallingPid();
222 if (appToken instanceof Binder) {
223 // For local clients, there is no reason to track them.
224 mStartedOps = null;
225 } else {
226 mStartedOps = new ArrayList<Op>();
227 try {
228 mAppToken.linkToDeath(this, 0);
229 } catch (RemoteException e) {
230 }
231 }
232 }
233
234 @Override
235 public String toString() {
236 return "ClientState{" +
237 "mAppToken=" + mAppToken +
238 ", " + (mStartedOps != null ? ("pid=" + mPid) : "local") +
239 '}';
240 }
241
242 @Override
243 public void binderDied() {
244 synchronized (AppOpsService.this) {
245 for (int i=mStartedOps.size()-1; i>=0; i--) {
246 finishOperationLocked(mStartedOps.get(i));
247 }
248 mClients.remove(mAppToken);
249 }
250 }
251 }
252
Jeff Brown6f357d32014-01-15 20:40:55 -0800253 public AppOpsService(File storagePath, Handler handler) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800254 mFile = new AtomicFile(storagePath);
Jeff Brown6f357d32014-01-15 20:40:55 -0800255 mHandler = handler;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800256 readState();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800257 }
David Braunf5d83192013-09-16 13:43:51 -0700258
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800259 public void publish(Context context) {
260 mContext = context;
261 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
262 }
263
Dianne Hackborn514074f2013-02-11 10:52:46 -0800264 public void systemReady() {
265 synchronized (this) {
266 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700267 for (int i = mUidStates.size() - 1; i >= 0; i--) {
268 UidState uidState = mUidStates.valueAt(i);
269
270 String[] packageNames = getPackagesForUid(uidState.uid);
271 if (ArrayUtils.isEmpty(packageNames)) {
272 uidState.clear();
273 mUidStates.removeAt(i);
274 changed = true;
275 continue;
276 }
277
278 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
279 if (pkgs == null) {
280 continue;
281 }
282
Dianne Hackborn514074f2013-02-11 10:52:46 -0800283 Iterator<Ops> it = pkgs.values().iterator();
284 while (it.hasNext()) {
285 Ops ops = it.next();
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700286 int curUid = -1;
Dianne Hackborn514074f2013-02-11 10:52:46 -0800287 try {
Jeff Sharkeycd654482016-01-08 17:42:11 -0700288 curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
289 PackageManager.MATCH_UNINSTALLED_PACKAGES,
Svet Ganov2af57082015-07-30 08:44:20 -0700290 UserHandle.getUserId(ops.uidState.uid));
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700291 } catch (RemoteException ignored) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800292 }
Svet Ganov2af57082015-07-30 08:44:20 -0700293 if (curUid != ops.uidState.uid) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800294 Slog.i(TAG, "Pruning old package " + ops.packageName
Svet Ganov2af57082015-07-30 08:44:20 -0700295 + "/" + ops.uidState + ": new uid=" + curUid);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800296 it.remove();
297 changed = true;
298 }
299 }
Svet Ganov2af57082015-07-30 08:44:20 -0700300
301 if (uidState.isDefault()) {
302 mUidStates.removeAt(i);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800303 }
304 }
305 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800306 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800307 }
308 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700309
310 MountServiceInternal mountServiceInternal = LocalServices.getService(
311 MountServiceInternal.class);
312 mountServiceInternal.addExternalStoragePolicy(
313 new MountServiceInternal.ExternalStorageMountPolicy() {
314 @Override
315 public int getMountMode(int uid, String packageName) {
316 if (Process.isIsolated(uid)) {
317 return Zygote.MOUNT_EXTERNAL_NONE;
318 }
319 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
320 packageName) != AppOpsManager.MODE_ALLOWED) {
321 return Zygote.MOUNT_EXTERNAL_NONE;
322 }
323 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
324 packageName) != AppOpsManager.MODE_ALLOWED) {
325 return Zygote.MOUNT_EXTERNAL_READ;
326 }
327 return Zygote.MOUNT_EXTERNAL_WRITE;
328 }
329
330 @Override
331 public boolean hasExternalStorage(int uid, String packageName) {
332 final int mountMode = getMountMode(uid, packageName);
333 return mountMode == Zygote.MOUNT_EXTERNAL_READ
334 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
335 }
336 });
Dianne Hackborn514074f2013-02-11 10:52:46 -0800337 }
338
339 public void packageRemoved(int uid, String packageName) {
340 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700341 UidState uidState = mUidStates.get(uid);
342 if (uidState == null) {
343 return;
344 }
345
346 boolean changed = false;
347
348 // Remove any package state if such.
349 if (uidState.pkgOps != null && uidState.pkgOps.remove(packageName) != null) {
350 changed = true;
351 }
352
353 // If we just nuked the last package state check if the UID is valid.
354 if (changed && uidState.pkgOps.isEmpty()
355 && getPackagesForUid(uid).length <= 0) {
356 mUidStates.remove(uid);
357 }
358
359 if (changed) {
360 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800361 }
362 }
363 }
364
365 public void uidRemoved(int uid) {
366 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700367 if (mUidStates.indexOfKey(uid) >= 0) {
368 mUidStates.remove(uid);
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800369 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800370 }
371 }
372 }
373
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800374 public void shutdown() {
375 Slog.w(TAG, "Writing app ops before shutdown...");
Dianne Hackborn35654b62013-01-14 17:38:02 -0800376 boolean doWrite = false;
377 synchronized (this) {
378 if (mWriteScheduled) {
379 mWriteScheduled = false;
380 doWrite = true;
381 }
382 }
383 if (doWrite) {
384 writeState();
385 }
386 }
387
Dianne Hackborn72e39832013-01-18 18:36:09 -0800388 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
389 ArrayList<AppOpsManager.OpEntry> resOps = null;
390 if (ops == null) {
391 resOps = new ArrayList<AppOpsManager.OpEntry>();
392 for (int j=0; j<pkgOps.size(); j++) {
393 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800394 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Svet Ganov99b60432015-06-27 13:15:22 -0700395 curOp.rejectTime, curOp.duration, curOp.proxyUid,
396 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800397 }
398 } else {
399 for (int j=0; j<ops.length; j++) {
400 Op curOp = pkgOps.get(ops[j]);
401 if (curOp != null) {
402 if (resOps == null) {
403 resOps = new ArrayList<AppOpsManager.OpEntry>();
404 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800405 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Svet Ganov99b60432015-06-27 13:15:22 -0700406 curOp.rejectTime, curOp.duration, curOp.proxyUid,
407 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800408 }
409 }
410 }
411 return resOps;
412 }
413
Dianne Hackborn35654b62013-01-14 17:38:02 -0800414 @Override
415 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
416 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
417 Binder.getCallingPid(), Binder.getCallingUid(), null);
418 ArrayList<AppOpsManager.PackageOps> res = null;
419 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700420 final int uidStateCount = mUidStates.size();
421 for (int i = 0; i < uidStateCount; i++) {
422 UidState uidState = mUidStates.valueAt(i);
423 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
424 continue;
425 }
426 ArrayMap<String, Ops> packages = uidState.pkgOps;
427 final int packageCount = packages.size();
428 for (int j = 0; j < packageCount; j++) {
429 Ops pkgOps = packages.valueAt(j);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800430 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800431 if (resOps != null) {
432 if (res == null) {
433 res = new ArrayList<AppOpsManager.PackageOps>();
434 }
435 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700436 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800437 res.add(resPackage);
438 }
439 }
440 }
441 }
442 return res;
443 }
444
445 @Override
Dianne Hackborn72e39832013-01-18 18:36:09 -0800446 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
447 int[] ops) {
448 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
449 Binder.getCallingPid(), Binder.getCallingUid(), null);
450 synchronized (this) {
451 Ops pkgOps = getOpsLocked(uid, packageName, false);
452 if (pkgOps == null) {
453 return null;
454 }
455 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
456 if (resOps == null) {
457 return null;
458 }
459 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
460 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700461 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800462 res.add(resPackage);
463 return res;
464 }
465 }
466
Dianne Hackborn607b4142013-08-02 18:10:10 -0700467 private void pruneOp(Op op, int uid, String packageName) {
468 if (op.time == 0 && op.rejectTime == 0) {
469 Ops ops = getOpsLocked(uid, packageName, false);
470 if (ops != null) {
471 ops.remove(op.op);
472 if (ops.size() <= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -0700473 UidState uidState = ops.uidState;
474 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700475 if (pkgOps != null) {
476 pkgOps.remove(ops.packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700477 if (pkgOps.isEmpty()) {
478 uidState.pkgOps = null;
479 }
480 if (uidState.isDefault()) {
481 mUidStates.remove(uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700482 }
483 }
484 }
485 }
486 }
487 }
488
Dianne Hackborn72e39832013-01-18 18:36:09 -0800489 @Override
Svet Ganov2af57082015-07-30 08:44:20 -0700490 public void setUidMode(int code, int uid, int mode) {
491 if (Binder.getCallingPid() != Process.myPid()) {
492 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
493 Binder.getCallingPid(), Binder.getCallingUid(), null);
494 }
495 verifyIncomingOp(code);
496 code = AppOpsManager.opToSwitch(code);
497
498 synchronized (this) {
499 final int defaultMode = AppOpsManager.opToDefaultMode(code);
500
501 UidState uidState = getUidStateLocked(uid, false);
502 if (uidState == null) {
503 if (mode == defaultMode) {
504 return;
505 }
506 uidState = new UidState(uid);
507 uidState.opModes = new SparseIntArray();
508 uidState.opModes.put(code, mode);
509 mUidStates.put(uid, uidState);
510 scheduleWriteLocked();
511 } else if (uidState.opModes == null) {
512 if (mode != defaultMode) {
513 uidState.opModes = new SparseIntArray();
514 uidState.opModes.put(code, mode);
515 scheduleWriteLocked();
516 }
517 } else {
518 if (uidState.opModes.get(code) == mode) {
519 return;
520 }
521 if (mode == defaultMode) {
522 uidState.opModes.delete(code);
523 if (uidState.opModes.size() <= 0) {
524 uidState.opModes = null;
525 }
526 } else {
527 uidState.opModes.put(code, mode);
528 }
529 scheduleWriteLocked();
530 }
531 }
532
Svetoslav215b44a2015-08-04 19:03:40 -0700533 String[] uidPackageNames = getPackagesForUid(uid);
Svet Ganov2af57082015-07-30 08:44:20 -0700534 ArrayMap<Callback, ArraySet<String>> callbackSpecs = null;
535
riddle_hsu40b300f2015-11-23 13:22:03 +0800536 synchronized (this) {
537 ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -0700538 if (callbacks != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700539 final int callbackCount = callbacks.size();
540 for (int i = 0; i < callbackCount; i++) {
541 Callback callback = callbacks.get(i);
riddle_hsu40b300f2015-11-23 13:22:03 +0800542 ArraySet<String> changedPackages = new ArraySet<>();
543 Collections.addAll(changedPackages, uidPackageNames);
544 callbackSpecs = new ArrayMap<>();
545 callbackSpecs.put(callback, changedPackages);
546 }
547 }
548
549 for (String uidPackageName : uidPackageNames) {
550 callbacks = mPackageModeWatchers.get(uidPackageName);
551 if (callbacks != null) {
552 if (callbackSpecs == null) {
553 callbackSpecs = new ArrayMap<>();
Svet Ganov2af57082015-07-30 08:44:20 -0700554 }
riddle_hsu40b300f2015-11-23 13:22:03 +0800555 final int callbackCount = callbacks.size();
556 for (int i = 0; i < callbackCount; i++) {
557 Callback callback = callbacks.get(i);
558 ArraySet<String> changedPackages = callbackSpecs.get(callback);
559 if (changedPackages == null) {
560 changedPackages = new ArraySet<>();
561 callbackSpecs.put(callback, changedPackages);
562 }
563 changedPackages.add(uidPackageName);
564 }
Svet Ganov2af57082015-07-30 08:44:20 -0700565 }
566 }
567 }
568
569 if (callbackSpecs == null) {
570 return;
571 }
572
573 // There are components watching for mode changes such as window manager
574 // and location manager which are in our process. The callbacks in these
575 // components may require permissions our remote caller does not have.
576 final long identity = Binder.clearCallingIdentity();
577 try {
578 for (int i = 0; i < callbackSpecs.size(); i++) {
579 Callback callback = callbackSpecs.keyAt(i);
580 ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
581 try {
582 if (reportedPackageNames == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700583 callback.mCallback.opChanged(code, uid, null);
Svet Ganov2af57082015-07-30 08:44:20 -0700584 } else {
585 final int reportedPackageCount = reportedPackageNames.size();
586 for (int j = 0; j < reportedPackageCount; j++) {
587 String reportedPackageName = reportedPackageNames.valueAt(j);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700588 callback.mCallback.opChanged(code, uid, reportedPackageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700589 }
590 }
591 } catch (RemoteException e) {
592 Log.w(TAG, "Error dispatching op op change", e);
593 }
594 }
595 } finally {
596 Binder.restoreCallingIdentity(identity);
597 }
598 }
599
600 @Override
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800601 public void setMode(int code, int uid, String packageName, int mode) {
Dianne Hackbornb64afe12014-07-22 16:29:04 -0700602 if (Binder.getCallingPid() != Process.myPid()) {
603 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
604 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborn133b9df2014-07-01 13:06:10 -0700605 }
Dianne Hackborn961321f2013-02-05 17:22:41 -0800606 verifyIncomingOp(code);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800607 ArrayList<Callback> repCbs = null;
608 code = AppOpsManager.opToSwitch(code);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800609 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700610 UidState uidState = getUidStateLocked(uid, false);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800611 Op op = getOpLocked(code, uid, packageName, true);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800612 if (op != null) {
613 if (op.mode != mode) {
614 op.mode = mode;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800615 ArrayList<Callback> cbs = mOpModeWatchers.get(code);
616 if (cbs != null) {
617 if (repCbs == null) {
618 repCbs = new ArrayList<Callback>();
619 }
620 repCbs.addAll(cbs);
621 }
622 cbs = mPackageModeWatchers.get(packageName);
623 if (cbs != null) {
624 if (repCbs == null) {
625 repCbs = new ArrayList<Callback>();
626 }
627 repCbs.addAll(cbs);
628 }
David Braunf5d83192013-09-16 13:43:51 -0700629 if (mode == AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800630 // If going into the default mode, prune this op
631 // if there is nothing else interesting in it.
Dianne Hackborn607b4142013-08-02 18:10:10 -0700632 pruneOp(op, uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800633 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800634 scheduleFastWriteLocked();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800635 }
636 }
637 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800638 if (repCbs != null) {
Svet Ganov38536112015-05-19 12:45:52 -0700639 // There are components watching for mode changes such as window manager
640 // and location manager which are in our process. The callbacks in these
641 // components may require permissions our remote caller does not have.
642 final long identity = Binder.clearCallingIdentity();
643 try {
644 for (int i = 0; i < repCbs.size(); i++) {
645 try {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700646 repCbs.get(i).mCallback.opChanged(code, uid, packageName);
Svet Ganov38536112015-05-19 12:45:52 -0700647 } catch (RemoteException e) {
648 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800649 }
Svet Ganov38536112015-05-19 12:45:52 -0700650 } finally {
651 Binder.restoreCallingIdentity(identity);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800652 }
653 }
654 }
655
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700656 private static HashMap<Callback, ArrayList<ChangeRec>> addCallbacks(
657 HashMap<Callback, ArrayList<ChangeRec>> callbacks,
658 int op, int uid, String packageName, ArrayList<Callback> cbs) {
Dianne Hackborn607b4142013-08-02 18:10:10 -0700659 if (cbs == null) {
660 return callbacks;
661 }
662 if (callbacks == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700663 callbacks = new HashMap<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700664 }
Svet Ganov2af57082015-07-30 08:44:20 -0700665 boolean duplicate = false;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700666 for (int i=0; i<cbs.size(); i++) {
667 Callback cb = cbs.get(i);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700668 ArrayList<ChangeRec> reports = callbacks.get(cb);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700669 if (reports == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700670 reports = new ArrayList<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700671 callbacks.put(cb, reports);
Svet Ganov2af57082015-07-30 08:44:20 -0700672 } else {
673 final int reportCount = reports.size();
674 for (int j = 0; j < reportCount; j++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700675 ChangeRec report = reports.get(j);
676 if (report.op == op && report.pkg.equals(packageName)) {
Svet Ganov2af57082015-07-30 08:44:20 -0700677 duplicate = true;
678 break;
679 }
680 }
Dianne Hackborn607b4142013-08-02 18:10:10 -0700681 }
Svet Ganov2af57082015-07-30 08:44:20 -0700682 if (!duplicate) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700683 reports.add(new ChangeRec(op, uid, packageName));
Svet Ganov2af57082015-07-30 08:44:20 -0700684 }
Dianne Hackborn607b4142013-08-02 18:10:10 -0700685 }
686 return callbacks;
687 }
688
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700689 static final class ChangeRec {
690 final int op;
691 final int uid;
692 final String pkg;
693
694 ChangeRec(int _op, int _uid, String _pkg) {
695 op = _op;
696 uid = _uid;
697 pkg = _pkg;
698 }
699 }
700
Dianne Hackborn607b4142013-08-02 18:10:10 -0700701 @Override
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800702 public void resetAllModes(int reqUserId, String reqPackageName) {
703 final int callingPid = Binder.getCallingPid();
704 final int callingUid = Binder.getCallingUid();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700705 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800706 callingPid, callingUid, null);
707 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
708 true, true, "resetAllModes", null);
Svet Ganov2af57082015-07-30 08:44:20 -0700709
710 int reqUid = -1;
711 if (reqPackageName != null) {
712 try {
713 reqUid = AppGlobals.getPackageManager().getPackageUid(
Jeff Sharkeycd654482016-01-08 17:42:11 -0700714 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
Svet Ganov2af57082015-07-30 08:44:20 -0700715 } catch (RemoteException e) {
716 /* ignore - local call */
717 }
718 }
719
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700720 HashMap<Callback, ArrayList<ChangeRec>> callbacks = null;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700721 synchronized (this) {
722 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700723 for (int i = mUidStates.size() - 1; i >= 0; i--) {
724 UidState uidState = mUidStates.valueAt(i);
725
726 SparseIntArray opModes = uidState.opModes;
727 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
728 final int uidOpCount = opModes.size();
729 for (int j = uidOpCount - 1; j >= 0; j--) {
730 final int code = opModes.keyAt(j);
731 if (AppOpsManager.opAllowsReset(code)) {
732 opModes.removeAt(j);
733 if (opModes.size() <= 0) {
734 uidState.opModes = null;
735 }
736 for (String packageName : getPackagesForUid(uidState.uid)) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700737 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -0700738 mOpModeWatchers.get(code));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700739 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -0700740 mPackageModeWatchers.get(packageName));
741 }
742 }
743 }
744 }
745
746 if (uidState.pkgOps == null) {
747 continue;
748 }
749
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800750 if (reqUserId != UserHandle.USER_ALL
Svet Ganov2af57082015-07-30 08:44:20 -0700751 && reqUserId != UserHandle.getUserId(uidState.uid)) {
Alexandra Gherghinad6a98972014-08-04 17:05:34 +0100752 // Skip any ops for a different user
753 continue;
754 }
Svet Ganov2af57082015-07-30 08:44:20 -0700755
756 Map<String, Ops> packages = uidState.pkgOps;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -0700757 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
758 while (it.hasNext()) {
759 Map.Entry<String, Ops> ent = it.next();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700760 String packageName = ent.getKey();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800761 if (reqPackageName != null && !reqPackageName.equals(packageName)) {
762 // Skip any ops for a different package
763 continue;
764 }
Dianne Hackborn607b4142013-08-02 18:10:10 -0700765 Ops pkgOps = ent.getValue();
Dianne Hackborn7f09ec32013-08-07 15:36:08 -0700766 for (int j=pkgOps.size()-1; j>=0; j--) {
Dianne Hackborn607b4142013-08-02 18:10:10 -0700767 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn8828d3a2013-09-25 16:47:10 -0700768 if (AppOpsManager.opAllowsReset(curOp.op)
769 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
David Braunf5d83192013-09-16 13:43:51 -0700770 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700771 changed = true;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700772 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -0700773 mOpModeWatchers.get(curOp.op));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700774 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -0700775 mPackageModeWatchers.get(packageName));
Dianne Hackborn7f09ec32013-08-07 15:36:08 -0700776 if (curOp.time == 0 && curOp.rejectTime == 0) {
777 pkgOps.removeAt(j);
778 }
Dianne Hackborn607b4142013-08-02 18:10:10 -0700779 }
780 }
Dianne Hackborn7f09ec32013-08-07 15:36:08 -0700781 if (pkgOps.size() == 0) {
782 it.remove();
783 }
784 }
Svet Ganov2af57082015-07-30 08:44:20 -0700785 if (uidState.isDefault()) {
786 mUidStates.remove(uidState.uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700787 }
788 }
Svet Ganov2af57082015-07-30 08:44:20 -0700789
Dianne Hackborn607b4142013-08-02 18:10:10 -0700790 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800791 scheduleFastWriteLocked();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700792 }
793 }
794 if (callbacks != null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700795 for (Map.Entry<Callback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
Dianne Hackborn607b4142013-08-02 18:10:10 -0700796 Callback cb = ent.getKey();
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700797 ArrayList<ChangeRec> reports = ent.getValue();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700798 for (int i=0; i<reports.size(); i++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700799 ChangeRec rep = reports.get(i);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700800 try {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700801 cb.mCallback.opChanged(rep.op, rep.uid, rep.pkg);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700802 } catch (RemoteException e) {
803 }
804 }
805 }
806 }
807 }
808
Dianne Hackbornc2293022013-02-06 23:14:49 -0800809 @Override
810 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -0800811 if (callback == null) {
812 return;
813 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800814 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700815 op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800816 Callback cb = mModeWatchers.get(callback.asBinder());
817 if (cb == null) {
818 cb = new Callback(callback);
819 mModeWatchers.put(callback.asBinder(), cb);
820 }
821 if (op != AppOpsManager.OP_NONE) {
822 ArrayList<Callback> cbs = mOpModeWatchers.get(op);
823 if (cbs == null) {
824 cbs = new ArrayList<Callback>();
825 mOpModeWatchers.put(op, cbs);
826 }
827 cbs.add(cb);
828 }
829 if (packageName != null) {
830 ArrayList<Callback> cbs = mPackageModeWatchers.get(packageName);
831 if (cbs == null) {
832 cbs = new ArrayList<Callback>();
833 mPackageModeWatchers.put(packageName, cbs);
834 }
835 cbs.add(cb);
836 }
837 }
838 }
839
840 @Override
841 public void stopWatchingMode(IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -0800842 if (callback == null) {
843 return;
844 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800845 synchronized (this) {
846 Callback cb = mModeWatchers.remove(callback.asBinder());
847 if (cb != null) {
848 cb.unlinkToDeath();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700849 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800850 ArrayList<Callback> cbs = mOpModeWatchers.valueAt(i);
851 cbs.remove(cb);
852 if (cbs.size() <= 0) {
853 mOpModeWatchers.removeAt(i);
854 }
855 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700856 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
857 ArrayList<Callback> cbs = mPackageModeWatchers.valueAt(i);
858 cbs.remove(cb);
859 if (cbs.size() <= 0) {
860 mPackageModeWatchers.removeAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800861 }
862 }
863 }
864 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800865 }
866
867 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700868 public IBinder getToken(IBinder clientToken) {
869 synchronized (this) {
870 ClientState cs = mClients.get(clientToken);
871 if (cs == null) {
872 cs = new ClientState(clientToken);
873 mClients.put(clientToken, cs);
874 }
875 return cs;
876 }
877 }
878
879 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -0800880 public int checkOperation(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800881 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -0800882 verifyIncomingOp(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800883 synchronized (this) {
Jason Monk1c7c3192014-06-26 12:52:18 -0400884 if (isOpRestricted(uid, code, packageName)) {
Jason Monk62062992014-05-06 09:55:28 -0400885 return AppOpsManager.MODE_IGNORED;
886 }
Svet Ganov2af57082015-07-30 08:44:20 -0700887 code = AppOpsManager.opToSwitch(code);
888 UidState uidState = getUidStateLocked(uid, false);
889 if (uidState != null && uidState.opModes != null) {
890 final int uidMode = uidState.opModes.get(code);
891 if (uidMode != AppOpsManager.MODE_ALLOWED) {
892 return uidMode;
893 }
894 }
895 Op op = getOpLocked(code, uid, packageName, false);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800896 if (op == null) {
David Braunf5d83192013-09-16 13:43:51 -0700897 return AppOpsManager.opToDefaultMode(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800898 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800899 return op.mode;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800900 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800901 }
902
903 @Override
John Spurlock7b414672014-07-18 13:02:39 -0400904 public int checkAudioOperation(int code, int usage, int uid, String packageName) {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +0000905 if (isPackageSuspendedForUser(packageName, uid)) {
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +0000906 Log.i(TAG, "Audio disabled for suspended package=" + packageName + " for uid=" + uid);
907 return AppOpsManager.MODE_IGNORED;
908 }
909
John Spurlock1af30c72014-03-10 08:33:35 -0400910 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -0400911 final int mode = checkRestrictionLocked(code, usage, uid, packageName);
John Spurlock1af30c72014-03-10 08:33:35 -0400912 if (mode != AppOpsManager.MODE_ALLOWED) {
913 return mode;
914 }
915 }
916 return checkOperation(code, uid, packageName);
917 }
918
Andrei Stingaceanu355b2322016-02-12 16:43:51 +0000919 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +0000920 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +0000921 return AppGlobals.getPackageManager().isPackageSuspendedForUser(
922 pkg, UserHandle.getUserId(uid));
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +0000923 } catch (RemoteException re) {
924 throw new SecurityException("Could not talk to package manager service");
925 }
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +0000926 }
927
John Spurlock7b414672014-07-18 13:02:39 -0400928 private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
929 final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
930 if (usageRestrictions != null) {
931 final Restriction r = usageRestrictions.get(usage);
John Spurlock1af30c72014-03-10 08:33:35 -0400932 if (r != null && !r.exceptionPackages.contains(packageName)) {
933 return r.mode;
934 }
935 }
936 return AppOpsManager.MODE_ALLOWED;
937 }
938
939 @Override
John Spurlock7b414672014-07-18 13:02:39 -0400940 public void setAudioRestriction(int code, int usage, int uid, int mode,
John Spurlock1af30c72014-03-10 08:33:35 -0400941 String[] exceptionPackages) {
942 verifyIncomingUid(uid);
943 verifyIncomingOp(code);
944 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -0400945 SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
946 if (usageRestrictions == null) {
947 usageRestrictions = new SparseArray<Restriction>();
948 mAudioRestrictions.put(code, usageRestrictions);
John Spurlock1af30c72014-03-10 08:33:35 -0400949 }
John Spurlock7b414672014-07-18 13:02:39 -0400950 usageRestrictions.remove(usage);
John Spurlock1af30c72014-03-10 08:33:35 -0400951 if (mode != AppOpsManager.MODE_ALLOWED) {
952 final Restriction r = new Restriction();
953 r.mode = mode;
954 if (exceptionPackages != null) {
955 final int N = exceptionPackages.length;
956 r.exceptionPackages = new ArraySet<String>(N);
957 for (int i = 0; i < N; i++) {
958 final String pkg = exceptionPackages[i];
959 if (pkg != null) {
960 r.exceptionPackages.add(pkg.trim());
961 }
962 }
963 }
John Spurlock7b414672014-07-18 13:02:39 -0400964 usageRestrictions.put(usage, r);
John Spurlock1af30c72014-03-10 08:33:35 -0400965 }
966 }
967 }
968
969 @Override
Jeff Sharkey911d7f42013-09-05 18:11:45 -0700970 public int checkPackage(int uid, String packageName) {
971 synchronized (this) {
Dianne Hackborn0fcef842014-09-12 15:38:33 -0700972 if (getOpsRawLocked(uid, packageName, true) != null) {
Jeff Sharkey911d7f42013-09-05 18:11:45 -0700973 return AppOpsManager.MODE_ALLOWED;
974 } else {
975 return AppOpsManager.MODE_ERRORED;
976 }
977 }
978 }
979
980 @Override
Svet Ganov99b60432015-06-27 13:15:22 -0700981 public int noteProxyOperation(int code, String proxyPackageName,
982 int proxiedUid, String proxiedPackageName) {
983 verifyIncomingOp(code);
984 final int proxyMode = noteOperationUnchecked(code, Binder.getCallingUid(),
985 proxyPackageName, -1, null);
986 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
987 return proxyMode;
988 }
989 return noteOperationUnchecked(code, proxiedUid, proxiedPackageName,
990 Binder.getCallingUid(), proxyPackageName);
Svet Ganov99b60432015-06-27 13:15:22 -0700991 }
992
993 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800994 public int noteOperation(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800995 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -0800996 verifyIncomingOp(code);
Svet Ganov99b60432015-06-27 13:15:22 -0700997 return noteOperationUnchecked(code, uid, packageName, 0, null);
998 }
999
1000 private int noteOperationUnchecked(int code, int uid, String packageName,
1001 int proxyUid, String proxyPackageName) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001002 synchronized (this) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001003 Ops ops = getOpsLocked(uid, packageName, true);
1004 if (ops == null) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001005 if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
1006 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001007 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001008 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001009 Op op = getOpLocked(ops, code, true);
Jason Monk1c7c3192014-06-26 12:52:18 -04001010 if (isOpRestricted(uid, code, packageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001011 return AppOpsManager.MODE_IGNORED;
1012 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001013 if (op.duration == -1) {
1014 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
1015 + " code " + code + " time=" + op.time + " duration=" + op.duration);
1016 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001017 op.duration = 0;
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001018 final int switchCode = AppOpsManager.opToSwitch(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001019 UidState uidState = ops.uidState;
1020 if (uidState.opModes != null) {
1021 final int uidMode = uidState.opModes.get(switchCode);
1022 if (uidMode != AppOpsManager.MODE_ALLOWED) {
1023 if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
1024 + switchCode + " (" + code + ") uid " + uid + " package "
1025 + packageName);
1026 op.rejectTime = System.currentTimeMillis();
1027 return uidMode;
1028 }
1029 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001030 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
1031 if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
1032 if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
1033 + switchCode + " (" + code + ") uid " + uid + " package " + packageName);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001034 op.rejectTime = System.currentTimeMillis();
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001035 return switchOp.mode;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001036 }
1037 if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
1038 + " package " + packageName);
1039 op.time = System.currentTimeMillis();
Dianne Hackborn514074f2013-02-11 10:52:46 -08001040 op.rejectTime = 0;
Svet Ganov99b60432015-06-27 13:15:22 -07001041 op.proxyUid = proxyUid;
1042 op.proxyPackageName = proxyPackageName;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001043 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001044 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001045 }
1046
1047 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001048 public int startOperation(IBinder token, int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001049 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001050 verifyIncomingOp(code);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001051 ClientState client = (ClientState)token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001052 synchronized (this) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001053 Ops ops = getOpsLocked(uid, packageName, true);
1054 if (ops == null) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001055 if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
1056 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001057 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001058 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001059 Op op = getOpLocked(ops, code, true);
Jason Monk1c7c3192014-06-26 12:52:18 -04001060 if (isOpRestricted(uid, code, packageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001061 return AppOpsManager.MODE_IGNORED;
1062 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001063 final int switchCode = AppOpsManager.opToSwitch(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001064 UidState uidState = ops.uidState;
1065 if (uidState.opModes != null) {
1066 final int uidMode = uidState.opModes.get(switchCode);
1067 if (uidMode != AppOpsManager.MODE_ALLOWED) {
1068 if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
1069 + switchCode + " (" + code + ") uid " + uid + " package "
1070 + packageName);
1071 op.rejectTime = System.currentTimeMillis();
1072 return uidMode;
1073 }
1074 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001075 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
1076 if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
1077 if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code "
1078 + switchCode + " (" + code + ") uid " + uid + " package " + packageName);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001079 op.rejectTime = System.currentTimeMillis();
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001080 return switchOp.mode;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001081 }
1082 if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid
1083 + " package " + packageName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001084 if (op.nesting == 0) {
1085 op.time = System.currentTimeMillis();
Dianne Hackborn514074f2013-02-11 10:52:46 -08001086 op.rejectTime = 0;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001087 op.duration = -1;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001088 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001089 op.nesting++;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001090 if (client.mStartedOps != null) {
1091 client.mStartedOps.add(op);
1092 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001093 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001094 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001095 }
1096
1097 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001098 public void finishOperation(IBinder token, int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001099 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001100 verifyIncomingOp(code);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001101 ClientState client = (ClientState)token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001102 synchronized (this) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001103 Op op = getOpLocked(code, uid, packageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001104 if (op == null) {
1105 return;
1106 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001107 if (client.mStartedOps != null) {
1108 if (!client.mStartedOps.remove(op)) {
1109 throw new IllegalStateException("Operation not started: uid" + op.uid
1110 + " pkg=" + op.packageName + " op=" + op.op);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001111 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001112 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001113 finishOperationLocked(op);
1114 }
1115 }
1116
Svet Ganovb9d71a62015-04-30 10:38:13 -07001117 @Override
1118 public int permissionToOpCode(String permission) {
1119 return AppOpsManager.permissionToOpCode(permission);
1120 }
1121
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001122 void finishOperationLocked(Op op) {
1123 if (op.nesting <= 1) {
1124 if (op.nesting == 1) {
1125 op.duration = (int)(System.currentTimeMillis() - op.time);
1126 op.time += op.duration;
1127 } else {
1128 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
1129 + op.packageName + " code " + op.op + " time=" + op.time
1130 + " duration=" + op.duration + " nesting=" + op.nesting);
1131 }
1132 op.nesting = 0;
1133 } else {
1134 op.nesting--;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001135 }
1136 }
1137
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001138 private void verifyIncomingUid(int uid) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001139 if (uid == Binder.getCallingUid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001140 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001141 }
1142 if (Binder.getCallingPid() == Process.myPid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001143 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001144 }
1145 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
1146 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001147 }
1148
Dianne Hackborn961321f2013-02-05 17:22:41 -08001149 private void verifyIncomingOp(int op) {
1150 if (op >= 0 && op < AppOpsManager._NUM_OP) {
1151 return;
1152 }
1153 throw new IllegalArgumentException("Bad operation #" + op);
1154 }
1155
Svet Ganov2af57082015-07-30 08:44:20 -07001156 private UidState getUidStateLocked(int uid, boolean edit) {
1157 UidState uidState = mUidStates.get(uid);
1158 if (uidState == null) {
1159 if (!edit) {
1160 return null;
1161 }
1162 uidState = new UidState(uid);
1163 mUidStates.put(uid, uidState);
1164 }
1165 return uidState;
1166 }
1167
Dianne Hackborn72e39832013-01-18 18:36:09 -08001168 private Ops getOpsLocked(int uid, String packageName, boolean edit) {
Dianne Hackborn0fcef842014-09-12 15:38:33 -07001169 if (uid == 0) {
1170 packageName = "root";
1171 } else if (uid == Process.SHELL_UID) {
1172 packageName = "com.android.shell";
1173 }
1174 return getOpsRawLocked(uid, packageName, edit);
1175 }
1176
1177 private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
Svet Ganov2af57082015-07-30 08:44:20 -07001178 UidState uidState = getUidStateLocked(uid, edit);
1179 if (uidState == null) {
1180 return null;
1181 }
1182
1183 if (uidState.pkgOps == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001184 if (!edit) {
1185 return null;
1186 }
Svet Ganov2af57082015-07-30 08:44:20 -07001187 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001188 }
Svet Ganov2af57082015-07-30 08:44:20 -07001189
1190 Ops ops = uidState.pkgOps.get(packageName);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001191 if (ops == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001192 if (!edit) {
1193 return null;
1194 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001195 boolean isPrivileged = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001196 // This is the first time we have seen this package name under this uid,
1197 // so let's make sure it is valid.
Dianne Hackborn514074f2013-02-11 10:52:46 -08001198 if (uid != 0) {
1199 final long ident = Binder.clearCallingIdentity();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001200 try {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001201 int pkgUid = -1;
1202 try {
Jason Monk1c7c3192014-06-26 12:52:18 -04001203 ApplicationInfo appInfo = ActivityThread.getPackageManager()
Jeff Sharkeycd654482016-01-08 17:42:11 -07001204 .getApplicationInfo(packageName,
1205 PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
1206 UserHandle.getUserId(uid));
Jason Monk1c7c3192014-06-26 12:52:18 -04001207 if (appInfo != null) {
1208 pkgUid = appInfo.uid;
Alex Klyubinb9f8a522015-02-03 11:12:59 -08001209 isPrivileged = (appInfo.privateFlags
1210 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04001211 } else {
1212 if ("media".equals(packageName)) {
1213 pkgUid = Process.MEDIA_UID;
1214 isPrivileged = false;
Andy Hunged0ea402015-10-30 14:11:46 -07001215 } else if ("audioserver".equals(packageName)) {
1216 pkgUid = Process.AUDIOSERVER_UID;
1217 isPrivileged = false;
Chien-Yu Chen75cade02016-01-11 10:56:21 -08001218 } else if ("cameraserver".equals(packageName)) {
1219 pkgUid = Process.CAMERASERVER_UID;
1220 isPrivileged = false;
Jason Monk1c7c3192014-06-26 12:52:18 -04001221 }
Dianne Hackborn713df152013-05-17 11:27:57 -07001222 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001223 } catch (RemoteException e) {
1224 Slog.w(TAG, "Could not contact PackageManager", e);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001225 }
1226 if (pkgUid != uid) {
1227 // Oops! The package name is not valid for the uid they are calling
1228 // under. Abort.
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001229 RuntimeException ex = new RuntimeException("here");
1230 ex.fillInStackTrace();
Dianne Hackborn514074f2013-02-11 10:52:46 -08001231 Slog.w(TAG, "Bad call: specified package " + packageName
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001232 + " under uid " + uid + " but it is really " + pkgUid, ex);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001233 return null;
1234 }
1235 } finally {
1236 Binder.restoreCallingIdentity(ident);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001237 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001238 }
Svet Ganov2af57082015-07-30 08:44:20 -07001239 ops = new Ops(packageName, uidState, isPrivileged);
1240 uidState.pkgOps.put(packageName, ops);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001241 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08001242 return ops;
1243 }
1244
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001245 private void scheduleWriteLocked() {
1246 if (!mWriteScheduled) {
1247 mWriteScheduled = true;
1248 mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
1249 }
1250 }
1251
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001252 private void scheduleFastWriteLocked() {
1253 if (!mFastWriteScheduled) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001254 mWriteScheduled = true;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001255 mFastWriteScheduled = true;
1256 mHandler.removeCallbacks(mWriteRunner);
1257 mHandler.postDelayed(mWriteRunner, 10*1000);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001258 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001259 }
1260
Dianne Hackborn72e39832013-01-18 18:36:09 -08001261 private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
1262 Ops ops = getOpsLocked(uid, packageName, edit);
1263 if (ops == null) {
1264 return null;
1265 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001266 return getOpLocked(ops, code, edit);
1267 }
1268
1269 private Op getOpLocked(Ops ops, int code, boolean edit) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001270 Op op = ops.get(code);
1271 if (op == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001272 if (!edit) {
1273 return null;
1274 }
Svet Ganov2af57082015-07-30 08:44:20 -07001275 op = new Op(ops.uidState.uid, ops.packageName, code);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001276 ops.put(code, op);
1277 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001278 if (edit) {
1279 scheduleWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001280 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001281 return op;
1282 }
1283
Jason Monk1c7c3192014-06-26 12:52:18 -04001284 private boolean isOpRestricted(int uid, int code, String packageName) {
Jason Monk62062992014-05-06 09:55:28 -04001285 int userHandle = UserHandle.getUserId(uid);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001286 final int restrictionSetCount = mOpUserRestrictions.size();
Ruben Brunk29931bc2016-03-11 00:24:26 -08001287
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001288 for (int i = 0; i < restrictionSetCount; i++) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08001289 // For each client, check that the given op is not restricted, or that the given
1290 // package is exempt from the restriction.
1291
1292 SparseArray<Pair<boolean[],SparseArray<ArraySet<String>>>> perUserRestrictions =
1293 mOpUserRestrictions.valueAt(i);
1294
1295 Pair<boolean[],SparseArray<ArraySet<String>>> restrictions =
1296 perUserRestrictions.get(userHandle);
1297 if (restrictions == null) {
1298 continue; // No restrictions set by this client
1299 }
1300
1301 boolean[] opRestrictions = restrictions.first;
1302 SparseArray<ArraySet<String>> opExceptions = restrictions.second;
1303
1304 if (opRestrictions == null) {
1305 continue; // No restrictions set by this client
1306 }
1307
1308 if (opRestrictions[code]) {
Ruben Brunk32f0fa42016-03-11 19:07:07 -08001309
1310 if (opExceptions != null) {
1311 ArraySet<String> ex = opExceptions.get(code);
1312 if (ex != null && ex.contains(packageName)) {
1313 continue; // AppOps code is restricted, but this package is exempt
1314 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08001315 }
1316
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001317 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08001318 // If we are the system, bypass user restrictions for certain codes
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001319 synchronized (this) {
1320 Ops ops = getOpsLocked(uid, packageName, true);
1321 if ((ops != null) && ops.isPrivileged) {
1322 return false;
1323 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001324 }
1325 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08001326
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001327 return true;
Jason Monk1c7c3192014-06-26 12:52:18 -04001328 }
Jason Monk62062992014-05-06 09:55:28 -04001329 }
1330 return false;
1331 }
1332
Dianne Hackborn35654b62013-01-14 17:38:02 -08001333 void readState() {
1334 synchronized (mFile) {
1335 synchronized (this) {
1336 FileInputStream stream;
1337 try {
1338 stream = mFile.openRead();
1339 } catch (FileNotFoundException e) {
1340 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
1341 return;
1342 }
1343 boolean success = false;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07001344 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001345 try {
1346 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001347 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08001348 int type;
1349 while ((type = parser.next()) != XmlPullParser.START_TAG
1350 && type != XmlPullParser.END_DOCUMENT) {
1351 ;
1352 }
1353
1354 if (type != XmlPullParser.START_TAG) {
1355 throw new IllegalStateException("no start tag found");
1356 }
1357
1358 int outerDepth = parser.getDepth();
1359 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1360 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1361 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1362 continue;
1363 }
1364
1365 String tagName = parser.getName();
1366 if (tagName.equals("pkg")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00001367 readPackage(parser);
Svetoslav215b44a2015-08-04 19:03:40 -07001368 } else if (tagName.equals("uid")) {
Svet Ganov2af57082015-07-30 08:44:20 -07001369 readUidOps(parser);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001370 } else {
1371 Slog.w(TAG, "Unknown element under <app-ops>: "
1372 + parser.getName());
1373 XmlUtils.skipCurrentTag(parser);
1374 }
1375 }
1376 success = true;
1377 } catch (IllegalStateException e) {
1378 Slog.w(TAG, "Failed parsing " + e);
1379 } catch (NullPointerException e) {
1380 Slog.w(TAG, "Failed parsing " + e);
1381 } catch (NumberFormatException e) {
1382 Slog.w(TAG, "Failed parsing " + e);
1383 } catch (XmlPullParserException e) {
1384 Slog.w(TAG, "Failed parsing " + e);
1385 } catch (IOException e) {
1386 Slog.w(TAG, "Failed parsing " + e);
1387 } catch (IndexOutOfBoundsException e) {
1388 Slog.w(TAG, "Failed parsing " + e);
1389 } finally {
1390 if (!success) {
Svet Ganov2af57082015-07-30 08:44:20 -07001391 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001392 }
1393 try {
1394 stream.close();
1395 } catch (IOException e) {
1396 }
1397 }
1398 }
1399 }
1400 }
1401
Svet Ganov2af57082015-07-30 08:44:20 -07001402 void readUidOps(XmlPullParser parser) throws NumberFormatException,
1403 XmlPullParserException, IOException {
1404 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
1405 int outerDepth = parser.getDepth();
1406 int type;
1407 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1408 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1409 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1410 continue;
1411 }
1412
1413 String tagName = parser.getName();
1414 if (tagName.equals("op")) {
1415 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
1416 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
1417 UidState uidState = getUidStateLocked(uid, true);
1418 if (uidState.opModes == null) {
1419 uidState.opModes = new SparseIntArray();
1420 }
1421 uidState.opModes.put(code, mode);
1422 } else {
1423 Slog.w(TAG, "Unknown element under <uid-ops>: "
1424 + parser.getName());
1425 XmlUtils.skipCurrentTag(parser);
1426 }
1427 }
1428 }
1429
Dave Burke0997c5bd2013-08-02 20:25:02 +00001430 void readPackage(XmlPullParser parser) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08001431 XmlPullParserException, IOException {
1432 String pkgName = parser.getAttributeValue(null, "n");
1433 int outerDepth = parser.getDepth();
1434 int type;
1435 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1436 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1437 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1438 continue;
1439 }
1440
1441 String tagName = parser.getName();
1442 if (tagName.equals("uid")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00001443 readUid(parser, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001444 } else {
1445 Slog.w(TAG, "Unknown element under <pkg>: "
1446 + parser.getName());
1447 XmlUtils.skipCurrentTag(parser);
1448 }
1449 }
1450 }
1451
Dave Burke0997c5bd2013-08-02 20:25:02 +00001452 void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08001453 XmlPullParserException, IOException {
1454 int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
Jason Monk1c7c3192014-06-26 12:52:18 -04001455 String isPrivilegedString = parser.getAttributeValue(null, "p");
1456 boolean isPrivileged = false;
1457 if (isPrivilegedString == null) {
1458 try {
1459 IPackageManager packageManager = ActivityThread.getPackageManager();
1460 if (packageManager != null) {
1461 ApplicationInfo appInfo = ActivityThread.getPackageManager()
1462 .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
1463 if (appInfo != null) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08001464 isPrivileged = (appInfo.privateFlags
1465 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04001466 }
1467 } else {
1468 // Could not load data, don't add to cache so it will be loaded later.
1469 return;
1470 }
1471 } catch (RemoteException e) {
1472 Slog.w(TAG, "Could not contact PackageManager", e);
1473 }
1474 } else {
1475 isPrivileged = Boolean.parseBoolean(isPrivilegedString);
1476 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001477 int outerDepth = parser.getDepth();
1478 int type;
1479 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1480 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1481 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1482 continue;
1483 }
1484
1485 String tagName = parser.getName();
1486 if (tagName.equals("op")) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001487 Op op = new Op(uid, pkgName, Integer.parseInt(parser.getAttributeValue(null, "n")));
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001488 String mode = parser.getAttributeValue(null, "m");
1489 if (mode != null) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00001490 op.mode = Integer.parseInt(mode);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001491 }
1492 String time = parser.getAttributeValue(null, "t");
1493 if (time != null) {
1494 op.time = Long.parseLong(time);
1495 }
1496 time = parser.getAttributeValue(null, "r");
1497 if (time != null) {
1498 op.rejectTime = Long.parseLong(time);
1499 }
1500 String dur = parser.getAttributeValue(null, "d");
1501 if (dur != null) {
1502 op.duration = Integer.parseInt(dur);
1503 }
Svet Ganov99b60432015-06-27 13:15:22 -07001504 String proxyUid = parser.getAttributeValue(null, "pu");
1505 if (proxyUid != null) {
1506 op.proxyUid = Integer.parseInt(proxyUid);
1507 }
1508 String proxyPackageName = parser.getAttributeValue(null, "pp");
1509 if (proxyPackageName != null) {
1510 op.proxyPackageName = proxyPackageName;
1511 }
Svet Ganov2af57082015-07-30 08:44:20 -07001512
1513 UidState uidState = getUidStateLocked(uid, true);
1514 if (uidState.pkgOps == null) {
1515 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001516 }
Svet Ganov2af57082015-07-30 08:44:20 -07001517
1518 Ops ops = uidState.pkgOps.get(pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001519 if (ops == null) {
Svet Ganov2af57082015-07-30 08:44:20 -07001520 ops = new Ops(pkgName, uidState, isPrivileged);
1521 uidState.pkgOps.put(pkgName, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001522 }
1523 ops.put(op.op, op);
1524 } else {
1525 Slog.w(TAG, "Unknown element under <pkg>: "
1526 + parser.getName());
1527 XmlUtils.skipCurrentTag(parser);
1528 }
1529 }
1530 }
1531
1532 void writeState() {
1533 synchronized (mFile) {
1534 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
1535
1536 FileOutputStream stream;
1537 try {
1538 stream = mFile.startWrite();
1539 } catch (IOException e) {
1540 Slog.w(TAG, "Failed to write state: " + e);
1541 return;
1542 }
1543
1544 try {
1545 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001546 out.setOutput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08001547 out.startDocument(null, true);
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07001548 out.startTag(null, "app-ops");
Svet Ganov2af57082015-07-30 08:44:20 -07001549
1550 final int uidStateCount = mUidStates.size();
1551 for (int i = 0; i < uidStateCount; i++) {
1552 UidState uidState = mUidStates.valueAt(i);
1553 if (uidState.opModes != null && uidState.opModes.size() > 0) {
1554 out.startTag(null, "uid");
1555 out.attribute(null, "n", Integer.toString(uidState.uid));
1556 SparseIntArray uidOpModes = uidState.opModes;
1557 final int opCount = uidOpModes.size();
1558 for (int j = 0; j < opCount; j++) {
1559 final int op = uidOpModes.keyAt(j);
1560 final int mode = uidOpModes.valueAt(j);
1561 out.startTag(null, "op");
1562 out.attribute(null, "n", Integer.toString(op));
1563 out.attribute(null, "m", Integer.toString(mode));
1564 out.endTag(null, "op");
1565 }
1566 out.endTag(null, "uid");
1567 }
1568 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001569
1570 if (allOps != null) {
1571 String lastPkg = null;
1572 for (int i=0; i<allOps.size(); i++) {
1573 AppOpsManager.PackageOps pkg = allOps.get(i);
1574 if (!pkg.getPackageName().equals(lastPkg)) {
1575 if (lastPkg != null) {
1576 out.endTag(null, "pkg");
1577 }
1578 lastPkg = pkg.getPackageName();
1579 out.startTag(null, "pkg");
1580 out.attribute(null, "n", lastPkg);
1581 }
1582 out.startTag(null, "uid");
1583 out.attribute(null, "n", Integer.toString(pkg.getUid()));
Jason Monk1c7c3192014-06-26 12:52:18 -04001584 synchronized (this) {
1585 Ops ops = getOpsLocked(pkg.getUid(), pkg.getPackageName(), false);
1586 // Should always be present as the list of PackageOps is generated
1587 // from Ops.
1588 if (ops != null) {
1589 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
1590 } else {
1591 out.attribute(null, "p", Boolean.toString(false));
1592 }
1593 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001594 List<AppOpsManager.OpEntry> ops = pkg.getOps();
1595 for (int j=0; j<ops.size(); j++) {
1596 AppOpsManager.OpEntry op = ops.get(j);
1597 out.startTag(null, "op");
1598 out.attribute(null, "n", Integer.toString(op.getOp()));
David Braunf5d83192013-09-16 13:43:51 -07001599 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001600 out.attribute(null, "m", Integer.toString(op.getMode()));
1601 }
1602 long time = op.getTime();
1603 if (time != 0) {
1604 out.attribute(null, "t", Long.toString(time));
1605 }
1606 time = op.getRejectTime();
1607 if (time != 0) {
1608 out.attribute(null, "r", Long.toString(time));
1609 }
1610 int dur = op.getDuration();
1611 if (dur != 0) {
1612 out.attribute(null, "d", Integer.toString(dur));
1613 }
Svet Ganov99b60432015-06-27 13:15:22 -07001614 int proxyUid = op.getProxyUid();
1615 if (proxyUid != -1) {
1616 out.attribute(null, "pu", Integer.toString(proxyUid));
1617 }
1618 String proxyPackageName = op.getProxyPackageName();
1619 if (proxyPackageName != null) {
1620 out.attribute(null, "pp", proxyPackageName);
1621 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001622 out.endTag(null, "op");
1623 }
1624 out.endTag(null, "uid");
1625 }
1626 if (lastPkg != null) {
1627 out.endTag(null, "pkg");
1628 }
1629 }
1630
1631 out.endTag(null, "app-ops");
1632 out.endDocument();
1633 mFile.finishWrite(stream);
1634 } catch (IOException e) {
1635 Slog.w(TAG, "Failed to write state, restoring backup.", e);
1636 mFile.failWrite(stream);
1637 }
1638 }
1639 }
1640
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001641 static class Shell extends ShellCommand {
1642 final IAppOpsService mInterface;
1643 final AppOpsService mInternal;
1644
1645 int userId = UserHandle.USER_SYSTEM;
1646 String packageName;
1647 String opStr;
1648 int op;
1649 int packageUid;
1650
1651 Shell(IAppOpsService iface, AppOpsService internal) {
1652 mInterface = iface;
1653 mInternal = internal;
1654 }
1655
1656 @Override
1657 public int onCommand(String cmd) {
1658 return onShellCommand(this, cmd);
1659 }
1660
1661 @Override
1662 public void onHelp() {
1663 PrintWriter pw = getOutPrintWriter();
1664 dumpCommandHelp(pw);
1665 }
1666
1667 private int strOpToOp(String op, PrintWriter err) {
1668 try {
1669 return AppOpsManager.strOpToOp(op);
1670 } catch (IllegalArgumentException e) {
1671 }
1672 try {
1673 return Integer.parseInt(op);
1674 } catch (NumberFormatException e) {
1675 }
1676 try {
1677 return AppOpsManager.strDebugOpToOp(op);
1678 } catch (IllegalArgumentException e) {
1679 err.println("Error: " + e.getMessage());
1680 return -1;
1681 }
1682 }
1683
1684 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
1685 userId = UserHandle.USER_CURRENT;
1686 packageName = null;
1687 opStr = null;
1688 for (String argument; (argument = getNextArg()) != null;) {
1689 if ("--user".equals(argument)) {
1690 userId = UserHandle.parseUserArg(getNextArgRequired());
1691 } else {
1692 if (packageName == null) {
1693 packageName = argument;
1694 } else if (opStr == null) {
1695 opStr = argument;
1696 break;
1697 }
1698 }
1699 }
1700 if (packageName == null) {
1701 err.println("Error: Package name not specified.");
1702 return -1;
1703 } else if (opStr == null && reqOp) {
1704 err.println("Error: Operation not specified.");
1705 return -1;
1706 }
1707 if (opStr != null) {
1708 op = strOpToOp(opStr, err);
1709 if (op < 0) {
1710 return -1;
1711 }
1712 } else {
1713 op = AppOpsManager.OP_NONE;
1714 }
1715 if (userId == UserHandle.USER_CURRENT) {
1716 userId = ActivityManager.getCurrentUser();
1717 }
1718 if ("root".equals(packageName)) {
1719 packageUid = 0;
1720 } else {
Jeff Sharkeycd654482016-01-08 17:42:11 -07001721 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
1722 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001723 }
1724 if (packageUid < 0) {
1725 err.println("Error: No UID for " + packageName + " in user " + userId);
1726 return -1;
1727 }
1728 return 0;
1729 }
1730 }
1731
1732 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
1733 FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
1734 (new Shell(this, this)).exec(this, in, out, err, args, resultReceiver);
1735 }
1736
1737 static void dumpCommandHelp(PrintWriter pw) {
1738 pw.println("AppOps service (appops) commands:");
1739 pw.println(" help");
1740 pw.println(" Print this help text.");
1741 pw.println(" set [--user <USER_ID>] <PACKAGE> <OP> <MODE>");
1742 pw.println(" Set the mode for a particular application and operation.");
1743 pw.println(" get [--user <USER_ID>] <PACKAGE> [<OP>]");
1744 pw.println(" Return the mode for a particular application and optional operation.");
1745 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
1746 pw.println(" Reset the given application or all applications to default modes.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07001747 pw.println(" write-settings");
1748 pw.println(" Immediately write pending changes to storage.");
1749 pw.println(" read-settings");
1750 pw.println(" Read the last written settings, replacing current state in RAM.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001751 pw.println(" options:");
1752 pw.println(" <PACKAGE> an Android package name.");
1753 pw.println(" <OP> an AppOps operation.");
1754 pw.println(" <MODE> one of allow, ignore, deny, or default");
1755 pw.println(" <USER_ID> the user id under which the package is installed. If --user is not");
1756 pw.println(" specified, the current user is assumed.");
1757 }
1758
1759 static int onShellCommand(Shell shell, String cmd) {
1760 if (cmd == null) {
1761 return shell.handleDefaultCommands(cmd);
1762 }
1763 PrintWriter pw = shell.getOutPrintWriter();
1764 PrintWriter err = shell.getErrPrintWriter();
1765 try {
1766 switch (cmd) {
1767 case "set": {
1768 int res = shell.parseUserPackageOp(true, err);
1769 if (res < 0) {
1770 return res;
1771 }
1772 String modeStr = shell.getNextArg();
1773 if (modeStr == null) {
1774 err.println("Error: Mode not specified.");
1775 return -1;
1776 }
1777
1778 final int mode;
1779 switch (modeStr) {
1780 case "allow":
1781 mode = AppOpsManager.MODE_ALLOWED;
1782 break;
1783 case "deny":
1784 mode = AppOpsManager.MODE_ERRORED;
1785 break;
1786 case "ignore":
1787 mode = AppOpsManager.MODE_IGNORED;
1788 break;
1789 case "default":
1790 mode = AppOpsManager.MODE_DEFAULT;
1791 break;
1792 default:
1793 err.println("Error: Mode " + modeStr + " is not valid,");
1794 return -1;
1795 }
1796
1797 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName, mode);
1798 return 0;
1799 }
1800 case "get": {
1801 int res = shell.parseUserPackageOp(false, err);
1802 if (res < 0) {
1803 return res;
1804 }
1805
1806 List<AppOpsManager.PackageOps> ops = shell.mInterface.getOpsForPackage(
1807 shell.packageUid, shell.packageName,
1808 shell.op != AppOpsManager.OP_NONE ? new int[] {shell.op} : null);
1809 if (ops == null || ops.size() <= 0) {
1810 pw.println("No operations.");
1811 return 0;
1812 }
1813 final long now = System.currentTimeMillis();
1814 for (int i=0; i<ops.size(); i++) {
1815 List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
1816 for (int j=0; j<entries.size(); j++) {
1817 AppOpsManager.OpEntry ent = entries.get(j);
1818 pw.print(AppOpsManager.opToName(ent.getOp()));
1819 pw.print(": ");
1820 switch (ent.getMode()) {
1821 case AppOpsManager.MODE_ALLOWED:
1822 pw.print("allow");
1823 break;
1824 case AppOpsManager.MODE_IGNORED:
1825 pw.print("ignore");
1826 break;
1827 case AppOpsManager.MODE_ERRORED:
1828 pw.print("deny");
1829 break;
1830 case AppOpsManager.MODE_DEFAULT:
1831 pw.print("default");
1832 break;
1833 default:
1834 pw.print("mode=");
1835 pw.print(ent.getMode());
1836 break;
1837 }
1838 if (ent.getTime() != 0) {
1839 pw.print("; time=");
1840 TimeUtils.formatDuration(now - ent.getTime(), pw);
1841 pw.print(" ago");
1842 }
1843 if (ent.getRejectTime() != 0) {
1844 pw.print("; rejectTime=");
1845 TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
1846 pw.print(" ago");
1847 }
1848 if (ent.getDuration() == -1) {
1849 pw.print(" (running)");
1850 } else if (ent.getDuration() != 0) {
1851 pw.print("; duration=");
1852 TimeUtils.formatDuration(ent.getDuration(), pw);
1853 }
1854 pw.println();
1855 }
1856 }
1857 return 0;
1858 }
1859 case "reset": {
1860 String packageName = null;
1861 int userId = UserHandle.USER_CURRENT;
1862 for (String argument; (argument = shell.getNextArg()) != null;) {
1863 if ("--user".equals(argument)) {
1864 String userStr = shell.getNextArgRequired();
1865 userId = UserHandle.parseUserArg(userStr);
1866 } else {
1867 if (packageName == null) {
1868 packageName = argument;
1869 } else {
1870 err.println("Error: Unsupported argument: " + argument);
1871 return -1;
1872 }
1873 }
1874 }
1875
1876 if (userId == UserHandle.USER_CURRENT) {
1877 userId = ActivityManager.getCurrentUser();
1878 }
1879
1880 shell.mInterface.resetAllModes(userId, packageName);
1881 pw.print("Reset all modes for: ");
1882 if (userId == UserHandle.USER_ALL) {
1883 pw.print("all users");
1884 } else {
1885 pw.print("user "); pw.print(userId);
1886 }
1887 pw.print(", ");
1888 if (packageName == null) {
1889 pw.println("all packages");
1890 } else {
1891 pw.print("package "); pw.println(packageName);
1892 }
1893 return 0;
1894 }
1895 case "write-settings": {
1896 shell.mInternal.mContext.enforcePermission(
1897 android.Manifest.permission.UPDATE_APP_OPS_STATS,
1898 Binder.getCallingPid(), Binder.getCallingUid(), null);
1899 long token = Binder.clearCallingIdentity();
1900 try {
1901 synchronized (shell.mInternal) {
1902 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
1903 }
1904 shell.mInternal.writeState();
1905 pw.println("Current settings written.");
1906 } finally {
1907 Binder.restoreCallingIdentity(token);
1908 }
1909 return 0;
1910 }
1911 case "read-settings": {
1912 shell.mInternal.mContext.enforcePermission(
1913 android.Manifest.permission.UPDATE_APP_OPS_STATS,
1914 Binder.getCallingPid(), Binder.getCallingUid(), null);
1915 long token = Binder.clearCallingIdentity();
1916 try {
1917 shell.mInternal.readState();
1918 pw.println("Last settings read.");
1919 } finally {
1920 Binder.restoreCallingIdentity(token);
1921 }
1922 return 0;
1923 }
1924 default:
1925 return shell.handleDefaultCommands(cmd);
1926 }
1927 } catch (RemoteException e) {
1928 pw.println("Remote exception: " + e);
1929 }
1930 return -1;
1931 }
1932
1933 private void dumpHelp(PrintWriter pw) {
1934 pw.println("AppOps service (appops) dump options:");
1935 pw.println(" none");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07001936 }
1937
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001938 @Override
1939 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1940 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1941 != PackageManager.PERMISSION_GRANTED) {
1942 pw.println("Permission Denial: can't dump ApOps service from from pid="
1943 + Binder.getCallingPid()
1944 + ", uid=" + Binder.getCallingUid());
1945 return;
1946 }
1947
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07001948 if (args != null) {
1949 for (int i=0; i<args.length; i++) {
1950 String arg = args[i];
1951 if ("-h".equals(arg)) {
1952 dumpHelp(pw);
1953 return;
Tim Kilbourn8f1ea832015-08-26 15:07:37 -07001954 } else if ("-a".equals(arg)) {
1955 // dump all data
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07001956 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
1957 pw.println("Unknown option: " + arg);
1958 return;
1959 } else {
1960 pw.println("Unknown command: " + arg);
1961 return;
1962 }
1963 }
1964 }
1965
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001966 synchronized (this) {
1967 pw.println("Current AppOps Service state:");
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001968 final long now = System.currentTimeMillis();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001969 boolean needSep = false;
1970 if (mOpModeWatchers.size() > 0) {
1971 needSep = true;
1972 pw.println(" Op mode watchers:");
1973 for (int i=0; i<mOpModeWatchers.size(); i++) {
1974 pw.print(" Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
1975 pw.println(":");
1976 ArrayList<Callback> callbacks = mOpModeWatchers.valueAt(i);
1977 for (int j=0; j<callbacks.size(); j++) {
1978 pw.print(" #"); pw.print(j); pw.print(": ");
1979 pw.println(callbacks.get(j));
1980 }
1981 }
1982 }
1983 if (mPackageModeWatchers.size() > 0) {
1984 needSep = true;
1985 pw.println(" Package mode watchers:");
1986 for (int i=0; i<mPackageModeWatchers.size(); i++) {
1987 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
1988 pw.println(":");
1989 ArrayList<Callback> callbacks = mPackageModeWatchers.valueAt(i);
1990 for (int j=0; j<callbacks.size(); j++) {
1991 pw.print(" #"); pw.print(j); pw.print(": ");
1992 pw.println(callbacks.get(j));
1993 }
1994 }
1995 }
1996 if (mModeWatchers.size() > 0) {
1997 needSep = true;
1998 pw.println(" All mode watchers:");
1999 for (int i=0; i<mModeWatchers.size(); i++) {
2000 pw.print(" "); pw.print(mModeWatchers.keyAt(i));
2001 pw.print(" -> "); pw.println(mModeWatchers.valueAt(i));
2002 }
2003 }
2004 if (mClients.size() > 0) {
2005 needSep = true;
2006 pw.println(" Clients:");
2007 for (int i=0; i<mClients.size(); i++) {
2008 pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
2009 ClientState cs = mClients.valueAt(i);
2010 pw.print(" "); pw.println(cs);
2011 if (cs.mStartedOps != null && cs.mStartedOps.size() > 0) {
2012 pw.println(" Started ops:");
2013 for (int j=0; j<cs.mStartedOps.size(); j++) {
2014 Op op = cs.mStartedOps.get(j);
2015 pw.print(" "); pw.print("uid="); pw.print(op.uid);
2016 pw.print(" pkg="); pw.print(op.packageName);
2017 pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
2018 }
2019 }
2020 }
2021 }
John Spurlock1af30c72014-03-10 08:33:35 -04002022 if (mAudioRestrictions.size() > 0) {
2023 boolean printedHeader = false;
2024 for (int o=0; o<mAudioRestrictions.size(); o++) {
2025 final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
2026 final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
2027 for (int i=0; i<restrictions.size(); i++) {
2028 if (!printedHeader){
2029 pw.println(" Audio Restrictions:");
2030 printedHeader = true;
2031 needSep = true;
2032 }
John Spurlock7b414672014-07-18 13:02:39 -04002033 final int usage = restrictions.keyAt(i);
John Spurlock1af30c72014-03-10 08:33:35 -04002034 pw.print(" "); pw.print(op);
John Spurlock7b414672014-07-18 13:02:39 -04002035 pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
John Spurlock1af30c72014-03-10 08:33:35 -04002036 Restriction r = restrictions.valueAt(i);
2037 pw.print(": mode="); pw.println(r.mode);
2038 if (!r.exceptionPackages.isEmpty()) {
2039 pw.println(" Exceptions:");
2040 for (int j=0; j<r.exceptionPackages.size(); j++) {
2041 pw.print(" "); pw.println(r.exceptionPackages.valueAt(j));
2042 }
2043 }
2044 }
2045 }
2046 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002047 if (needSep) {
2048 pw.println();
2049 }
Svet Ganov2af57082015-07-30 08:44:20 -07002050 for (int i=0; i<mUidStates.size(); i++) {
2051 UidState uidState = mUidStates.valueAt(i);
2052
2053 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
2054
2055 SparseIntArray opModes = uidState.opModes;
2056 if (opModes != null) {
2057 final int opModeCount = opModes.size();
2058 for (int j = 0; j < opModeCount; j++) {
2059 final int code = opModes.keyAt(j);
2060 final int mode = opModes.valueAt(j);
2061 pw.print(" "); pw.print(AppOpsManager.opToName(code));
2062 pw.print(": mode="); pw.println(mode);
2063 }
2064 }
2065
2066 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
2067 if (pkgOps == null) {
2068 continue;
2069 }
2070
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002071 for (Ops ops : pkgOps.values()) {
2072 pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
2073 for (int j=0; j<ops.size(); j++) {
2074 Op op = ops.valueAt(j);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002075 pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
2076 pw.print(": mode="); pw.print(op.mode);
2077 if (op.time != 0) {
2078 pw.print("; time="); TimeUtils.formatDuration(now-op.time, pw);
2079 pw.print(" ago");
2080 }
2081 if (op.rejectTime != 0) {
2082 pw.print("; rejectTime="); TimeUtils.formatDuration(now-op.rejectTime, pw);
2083 pw.print(" ago");
2084 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002085 if (op.duration == -1) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002086 pw.print(" (running)");
2087 } else if (op.duration != 0) {
2088 pw.print("; duration="); TimeUtils.formatDuration(op.duration, pw);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002089 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002090 pw.println();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002091 }
2092 }
2093 }
2094 }
2095 }
John Spurlock1af30c72014-03-10 08:33:35 -04002096
2097 private static final class Restriction {
2098 private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
2099 int mode;
2100 ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
2101 }
Jason Monk62062992014-05-06 09:55:28 -04002102
2103 @Override
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002104 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
Jason Monk62062992014-05-06 09:55:28 -04002105 checkSystemUid("setUserRestrictions");
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002106 Preconditions.checkNotNull(token);
2107 final boolean[] opRestrictions = getOrCreateUserRestrictionsForToken(token, userHandle);
Jason Monk62062992014-05-06 09:55:28 -04002108 for (int i = 0; i < opRestrictions.length; ++i) {
2109 String restriction = AppOpsManager.opToRestriction(i);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002110 final boolean restricted = restriction != null
2111 && restrictions.getBoolean(restriction, false);
2112 setUserRestrictionNoCheck(i, restricted, token, userHandle);
2113 }
2114 }
2115
2116 @Override
Ruben Brunk29931bc2016-03-11 00:24:26 -08002117 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
2118 String[] exceptionPackages) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002119 if (Binder.getCallingPid() != Process.myPid()) {
2120 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
2121 Binder.getCallingPid(), Binder.getCallingUid(), null);
2122 }
2123 if (userHandle != UserHandle.getCallingUserId()) {
2124 if (mContext.checkCallingOrSelfPermission(Manifest.permission
2125 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
2126 && mContext.checkCallingOrSelfPermission(Manifest.permission
2127 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
2128 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
2129 + " INTERACT_ACROSS_USERS to interact cross user ");
Jason Monk62062992014-05-06 09:55:28 -04002130 }
2131 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002132 verifyIncomingOp(code);
2133 Preconditions.checkNotNull(token);
Ruben Brunk29931bc2016-03-11 00:24:26 -08002134 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002135 }
2136
2137 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
2138 int userHandle) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08002139 setUserRestrictionNoCheck(code, restricted, token, userHandle, /*exceptionPackages*/null);
2140 }
2141
2142 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
2143 int userHandle, String[] exceptionPackages) {
2144
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002145 final boolean[] opRestrictions = getOrCreateUserRestrictionsForToken(token, userHandle);
Ruben Brunk29931bc2016-03-11 00:24:26 -08002146
2147 if (restricted) {
2148 final SparseArray<ArraySet<String>> opExceptions =
2149 getUserPackageExemptionsForToken(token, userHandle);
2150
Ruben Brunk29931bc2016-03-11 00:24:26 -08002151 ArraySet<String> exceptions = opExceptions.get(code);
Ruben Brunk32f0fa42016-03-11 19:07:07 -08002152 if (exceptionPackages != null && exceptionPackages.length > 0) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08002153 if (exceptions == null) {
2154 exceptions = new ArraySet<>(exceptionPackages.length);
2155 opExceptions.put(code, exceptions);
2156 } else {
2157 exceptions.clear();
2158 }
2159
Ruben Brunk32f0fa42016-03-11 19:07:07 -08002160 for (String p : exceptionPackages) {
2161 exceptions.add(p);
2162 }
2163 } else {
2164 opExceptions.remove(code);
Ruben Brunk29931bc2016-03-11 00:24:26 -08002165 }
2166 }
2167
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002168 if (opRestrictions[code] == restricted) {
2169 return;
2170 }
2171 opRestrictions[code] = restricted;
2172 if (!restricted) {
2173 pruneUserRestrictionsForToken(token, userHandle);
2174 }
2175
2176 final ArrayList<Callback> clonedCallbacks;
2177 synchronized (this) {
2178 ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
2179 if (callbacks == null) {
2180 return;
2181 }
2182 clonedCallbacks = new ArrayList<>(callbacks);
2183 }
2184
2185 // There are components watching for mode changes such as window manager
2186 // and location manager which are in our process. The callbacks in these
2187 // components may require permissions our remote caller does not have.
2188 final long identity = Binder.clearCallingIdentity();
2189 try {
2190 final int callbackCount = clonedCallbacks.size();
2191 for (int i = 0; i < callbackCount; i++) {
2192 Callback callback = clonedCallbacks.get(i);
2193 try {
2194 callback.mCallback.opChanged(code, -1, null);
2195 } catch (RemoteException e) {
2196 Log.w(TAG, "Error dispatching op op change", e);
2197 }
2198 }
2199 } finally {
2200 Binder.restoreCallingIdentity(identity);
2201 }
Jason Monk62062992014-05-06 09:55:28 -04002202 }
2203
2204 @Override
2205 public void removeUser(int userHandle) throws RemoteException {
2206 checkSystemUid("removeUser");
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002207 final int tokenCount = mOpUserRestrictions.size();
2208 for (int i = tokenCount - 1; i >= 0; i--) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08002209 SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>> opRestrictions =
2210 mOpUserRestrictions.valueAt(i);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002211 if (opRestrictions != null) {
2212 opRestrictions.remove(userHandle);
2213 if (opRestrictions.size() <= 0) {
2214 mOpUserRestrictions.removeAt(i);
2215 }
2216 }
2217 }
2218 }
2219
2220
2221 private void pruneUserRestrictionsForToken(IBinder token, int userHandle) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08002222 SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>> perTokenRestrictions =
2223 mOpUserRestrictions.get(token);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002224 if (perTokenRestrictions != null) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08002225 final Pair<boolean[], SparseArray<ArraySet<String>>> restrictions =
2226 perTokenRestrictions.get(userHandle);
2227
2228 if (restrictions != null) {
2229 final boolean[] opRestrictions = restrictions.first;
Ruben Brunk32f0fa42016-03-11 19:07:07 -08002230 final SparseArray<ArraySet<String>> opExceptions = restrictions.second;
2231 boolean stillHasRestrictions = false;
Ruben Brunk29931bc2016-03-11 00:24:26 -08002232 if (opRestrictions != null) {
Ruben Brunk32f0fa42016-03-11 19:07:07 -08002233 for (int i = 0; i < opRestrictions.length; i++) {
2234 boolean restriction = opRestrictions[i];
Ruben Brunk29931bc2016-03-11 00:24:26 -08002235 if (restriction) {
Ruben Brunk32f0fa42016-03-11 19:07:07 -08002236 stillHasRestrictions = true;
2237 } else {
2238 opExceptions.remove(i);
Ruben Brunk29931bc2016-03-11 00:24:26 -08002239 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002240 }
2241 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08002242
Ruben Brunk32f0fa42016-03-11 19:07:07 -08002243 if (stillHasRestrictions) {
2244 return;
2245 }
2246
Ruben Brunk29931bc2016-03-11 00:24:26 -08002247 // No restrictions set for this client
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002248 perTokenRestrictions.remove(userHandle);
2249 if (perTokenRestrictions.size() <= 0) {
2250 mOpUserRestrictions.remove(token);
2251 }
2252 }
2253 }
2254 }
2255
Ruben Brunk29931bc2016-03-11 00:24:26 -08002256 /**
2257 * Get or create the user restrictions array for a given client if it doesn't already exist.
2258 *
2259 * @param token the binder client creating the restriction.
2260 * @param userHandle the user handle to create a restriction for.
2261 *
2262 * @return the array of restriction states for each AppOps code.
2263 */
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002264 private boolean[] getOrCreateUserRestrictionsForToken(IBinder token, int userHandle) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08002265 SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>> perTokenRestrictions =
2266 mOpUserRestrictions.get(token);
2267
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002268 if (perTokenRestrictions == null) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08002269 perTokenRestrictions =
2270 new SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>>();
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002271 mOpUserRestrictions.put(token, perTokenRestrictions);
2272 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08002273
2274 Pair<boolean[], SparseArray<ArraySet<String>>> restrictions =
2275 perTokenRestrictions.get(userHandle);
2276
2277 if (restrictions == null) {
2278 restrictions = new Pair<boolean[], SparseArray<ArraySet<String>>>(
2279 new boolean[AppOpsManager._NUM_OP], new SparseArray<ArraySet<String>>());
2280 perTokenRestrictions.put(userHandle, restrictions);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002281 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08002282
2283 return restrictions.first;
2284 }
2285
2286 /**
2287 * Get the per-package exemptions for each AppOps code for a given client and userHandle.
2288 *
2289 * @param token the binder client to get the exemptions for.
2290 * @param userHandle the user handle to get the exemptions for.
2291 *
2292 * @return a mapping from the AppOps code to a set of packages exempt for that code.
2293 */
2294 private SparseArray<ArraySet<String>> getUserPackageExemptionsForToken(IBinder token,
2295 int userHandle) {
2296 SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>> perTokenRestrictions =
2297 mOpUserRestrictions.get(token);
2298
2299 if (perTokenRestrictions == null) {
2300 return null; // Don't create user restrictions accidentally
2301 }
2302
2303 Pair<boolean[], SparseArray<ArraySet<String>>> restrictions =
2304 perTokenRestrictions.get(userHandle);
2305
2306 if (restrictions == null) {
2307 return null; // Don't create user restrictions accidentally
2308 }
2309
2310 return restrictions.second;
Jason Monk62062992014-05-06 09:55:28 -04002311 }
2312
2313 private void checkSystemUid(String function) {
2314 int uid = Binder.getCallingUid();
2315 if (uid != Process.SYSTEM_UID) {
2316 throw new SecurityException(function + " must by called by the system");
2317 }
2318 }
2319
Svet Ganov2af57082015-07-30 08:44:20 -07002320 private static String[] getPackagesForUid(int uid) {
Svet Ganovf3807aa2015-08-02 10:09:56 -07002321 String[] packageNames = null;
Svet Ganov2af57082015-07-30 08:44:20 -07002322 try {
riddle_hsu40b300f2015-11-23 13:22:03 +08002323 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
Svet Ganov2af57082015-07-30 08:44:20 -07002324 } catch (RemoteException e) {
2325 /* ignore - local call */
2326 }
Svet Ganovf3807aa2015-08-02 10:09:56 -07002327 if (packageNames == null) {
2328 return EmptyArray.STRING;
2329 }
2330 return packageNames;
Svet Ganov2af57082015-07-30 08:44:20 -07002331 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002332}