blob: 1f6294533e95137abe231b35c3975c7bd86d04e1 [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;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -070028import 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 Hackborn354736e2016-08-22 17:00:05 -070054import android.os.ShellCallback;
Dianne Hackborn268e4e32015-11-18 16:29:56 -080055import android.os.ShellCommand;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080056import android.os.UserHandle;
Sudheer Shanka2250d562016-11-07 15:41:02 -080057import android.os.storage.StorageManagerInternal;
Dianne Hackborne98f5db2013-07-17 17:23:25 -070058import android.util.ArrayMap;
John Spurlock1af30c72014-03-10 08:33:35 -040059import android.util.ArraySet;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080060import android.util.AtomicFile;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -080061import android.util.Log;
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.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800114 */
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700115 private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
Jason Monk62062992014-05-06 09:55:28 -0400116
Svet Ganov2af57082015-07-30 08:44:20 -0700117 private static final class UidState {
118 public final int uid;
119 public ArrayMap<String, Ops> pkgOps;
120 public SparseIntArray opModes;
121
122 public UidState(int uid) {
123 this.uid = uid;
124 }
125
126 public void clear() {
127 pkgOps = null;
128 opModes = null;
129 }
130
131 public boolean isDefault() {
132 return (pkgOps == null || pkgOps.isEmpty())
133 && (opModes == null || opModes.size() <= 0);
134 }
135 }
136
Dianne Hackbornc2293022013-02-06 23:14:49 -0800137 public final static class Ops extends SparseArray<Op> {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800138 public final String packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700139 public final UidState uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400140 public final boolean isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800141
Svet Ganov2af57082015-07-30 08:44:20 -0700142 public Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800143 packageName = _packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700144 uidState = _uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400145 isPrivileged = _isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800146 }
147 }
148
Dianne Hackbornc2293022013-02-06 23:14:49 -0800149 public final static class Op {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700150 public final int uid;
151 public final String packageName;
Svet Ganov99b60432015-06-27 13:15:22 -0700152 public int proxyUid = -1;
153 public String proxyPackageName;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800154 public final int op;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800155 public int mode;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800156 public int duration;
157 public long time;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800158 public long rejectTime;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800159 public int nesting;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800160
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700161 public Op(int _uid, String _packageName, int _op) {
162 uid = _uid;
163 packageName = _packageName;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800164 op = _op;
David Braunf5d83192013-09-16 13:43:51 -0700165 mode = AppOpsManager.opToDefaultMode(op);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800166 }
167 }
168
Dianne Hackbornc2293022013-02-06 23:14:49 -0800169 final SparseArray<ArrayList<Callback>> mOpModeWatchers
170 = new SparseArray<ArrayList<Callback>>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700171 final ArrayMap<String, ArrayList<Callback>> mPackageModeWatchers
172 = new ArrayMap<String, ArrayList<Callback>>();
173 final ArrayMap<IBinder, Callback> mModeWatchers
174 = new ArrayMap<IBinder, Callback>();
John Spurlock1af30c72014-03-10 08:33:35 -0400175 final SparseArray<SparseArray<Restriction>> mAudioRestrictions
176 = new SparseArray<SparseArray<Restriction>>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800177
178 public final class Callback implements DeathRecipient {
179 final IAppOpsCallback mCallback;
180
181 public Callback(IAppOpsCallback callback) {
182 mCallback = callback;
183 try {
184 mCallback.asBinder().linkToDeath(this, 0);
185 } catch (RemoteException e) {
186 }
187 }
188
189 public void unlinkToDeath() {
190 mCallback.asBinder().unlinkToDeath(this, 0);
191 }
192
193 @Override
194 public void binderDied() {
195 stopWatchingMode(mCallback);
196 }
197 }
198
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700199 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<IBinder, ClientState>();
200
201 public final class ClientState extends Binder implements DeathRecipient {
202 final IBinder mAppToken;
203 final int mPid;
204 final ArrayList<Op> mStartedOps;
205
206 public ClientState(IBinder appToken) {
207 mAppToken = appToken;
208 mPid = Binder.getCallingPid();
209 if (appToken instanceof Binder) {
210 // For local clients, there is no reason to track them.
211 mStartedOps = null;
212 } else {
213 mStartedOps = new ArrayList<Op>();
214 try {
215 mAppToken.linkToDeath(this, 0);
216 } catch (RemoteException e) {
217 }
218 }
219 }
220
221 @Override
222 public String toString() {
223 return "ClientState{" +
224 "mAppToken=" + mAppToken +
225 ", " + (mStartedOps != null ? ("pid=" + mPid) : "local") +
226 '}';
227 }
228
229 @Override
230 public void binderDied() {
231 synchronized (AppOpsService.this) {
232 for (int i=mStartedOps.size()-1; i>=0; i--) {
233 finishOperationLocked(mStartedOps.get(i));
234 }
235 mClients.remove(mAppToken);
236 }
237 }
238 }
239
Jeff Brown6f357d32014-01-15 20:40:55 -0800240 public AppOpsService(File storagePath, Handler handler) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800241 mFile = new AtomicFile(storagePath);
Jeff Brown6f357d32014-01-15 20:40:55 -0800242 mHandler = handler;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800243 readState();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800244 }
David Braunf5d83192013-09-16 13:43:51 -0700245
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800246 public void publish(Context context) {
247 mContext = context;
248 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
249 }
250
Dianne Hackborn514074f2013-02-11 10:52:46 -0800251 public void systemReady() {
252 synchronized (this) {
253 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700254 for (int i = mUidStates.size() - 1; i >= 0; i--) {
255 UidState uidState = mUidStates.valueAt(i);
256
257 String[] packageNames = getPackagesForUid(uidState.uid);
258 if (ArrayUtils.isEmpty(packageNames)) {
259 uidState.clear();
260 mUidStates.removeAt(i);
261 changed = true;
262 continue;
263 }
264
265 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
266 if (pkgs == null) {
267 continue;
268 }
269
Dianne Hackborn514074f2013-02-11 10:52:46 -0800270 Iterator<Ops> it = pkgs.values().iterator();
271 while (it.hasNext()) {
272 Ops ops = it.next();
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700273 int curUid = -1;
Dianne Hackborn514074f2013-02-11 10:52:46 -0800274 try {
Jeff Sharkeycd654482016-01-08 17:42:11 -0700275 curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
276 PackageManager.MATCH_UNINSTALLED_PACKAGES,
Svet Ganov2af57082015-07-30 08:44:20 -0700277 UserHandle.getUserId(ops.uidState.uid));
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700278 } catch (RemoteException ignored) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800279 }
Svet Ganov2af57082015-07-30 08:44:20 -0700280 if (curUid != ops.uidState.uid) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800281 Slog.i(TAG, "Pruning old package " + ops.packageName
Svet Ganov2af57082015-07-30 08:44:20 -0700282 + "/" + ops.uidState + ": new uid=" + curUid);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800283 it.remove();
284 changed = true;
285 }
286 }
Svet Ganov2af57082015-07-30 08:44:20 -0700287
288 if (uidState.isDefault()) {
289 mUidStates.removeAt(i);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800290 }
291 }
292 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800293 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800294 }
295 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700296
Sudheer Shanka2250d562016-11-07 15:41:02 -0800297 StorageManagerInternal storageManagerInternal = LocalServices.getService(
298 StorageManagerInternal.class);
299 storageManagerInternal.addExternalStoragePolicy(
300 new StorageManagerInternal.ExternalStorageMountPolicy() {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700301 @Override
302 public int getMountMode(int uid, String packageName) {
303 if (Process.isIsolated(uid)) {
304 return Zygote.MOUNT_EXTERNAL_NONE;
305 }
306 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
307 packageName) != AppOpsManager.MODE_ALLOWED) {
308 return Zygote.MOUNT_EXTERNAL_NONE;
309 }
310 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
311 packageName) != AppOpsManager.MODE_ALLOWED) {
312 return Zygote.MOUNT_EXTERNAL_READ;
313 }
314 return Zygote.MOUNT_EXTERNAL_WRITE;
315 }
316
317 @Override
318 public boolean hasExternalStorage(int uid, String packageName) {
319 final int mountMode = getMountMode(uid, packageName);
320 return mountMode == Zygote.MOUNT_EXTERNAL_READ
321 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
322 }
323 });
Dianne Hackborn514074f2013-02-11 10:52:46 -0800324 }
325
326 public void packageRemoved(int uid, String packageName) {
327 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700328 UidState uidState = mUidStates.get(uid);
329 if (uidState == null) {
330 return;
331 }
332
333 boolean changed = false;
334
335 // Remove any package state if such.
336 if (uidState.pkgOps != null && uidState.pkgOps.remove(packageName) != null) {
337 changed = true;
338 }
339
340 // If we just nuked the last package state check if the UID is valid.
341 if (changed && uidState.pkgOps.isEmpty()
342 && getPackagesForUid(uid).length <= 0) {
343 mUidStates.remove(uid);
344 }
345
346 if (changed) {
347 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800348 }
349 }
350 }
351
352 public void uidRemoved(int uid) {
353 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700354 if (mUidStates.indexOfKey(uid) >= 0) {
355 mUidStates.remove(uid);
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800356 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800357 }
358 }
359 }
360
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800361 public void shutdown() {
362 Slog.w(TAG, "Writing app ops before shutdown...");
Dianne Hackborn35654b62013-01-14 17:38:02 -0800363 boolean doWrite = false;
364 synchronized (this) {
365 if (mWriteScheduled) {
366 mWriteScheduled = false;
367 doWrite = true;
368 }
369 }
370 if (doWrite) {
371 writeState();
372 }
373 }
374
Dianne Hackborn72e39832013-01-18 18:36:09 -0800375 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
376 ArrayList<AppOpsManager.OpEntry> resOps = null;
377 if (ops == null) {
378 resOps = new ArrayList<AppOpsManager.OpEntry>();
379 for (int j=0; j<pkgOps.size(); j++) {
380 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800381 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Svet Ganov99b60432015-06-27 13:15:22 -0700382 curOp.rejectTime, curOp.duration, curOp.proxyUid,
383 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800384 }
385 } else {
386 for (int j=0; j<ops.length; j++) {
387 Op curOp = pkgOps.get(ops[j]);
388 if (curOp != null) {
389 if (resOps == null) {
390 resOps = new ArrayList<AppOpsManager.OpEntry>();
391 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800392 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Svet Ganov99b60432015-06-27 13:15:22 -0700393 curOp.rejectTime, curOp.duration, curOp.proxyUid,
394 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800395 }
396 }
397 }
398 return resOps;
399 }
400
Dianne Hackborn35654b62013-01-14 17:38:02 -0800401 @Override
402 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
403 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
404 Binder.getCallingPid(), Binder.getCallingUid(), null);
405 ArrayList<AppOpsManager.PackageOps> res = null;
406 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700407 final int uidStateCount = mUidStates.size();
408 for (int i = 0; i < uidStateCount; i++) {
409 UidState uidState = mUidStates.valueAt(i);
410 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
411 continue;
412 }
413 ArrayMap<String, Ops> packages = uidState.pkgOps;
414 final int packageCount = packages.size();
415 for (int j = 0; j < packageCount; j++) {
416 Ops pkgOps = packages.valueAt(j);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800417 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800418 if (resOps != null) {
419 if (res == null) {
420 res = new ArrayList<AppOpsManager.PackageOps>();
421 }
422 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700423 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800424 res.add(resPackage);
425 }
426 }
427 }
428 }
429 return res;
430 }
431
432 @Override
Dianne Hackborn72e39832013-01-18 18:36:09 -0800433 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
434 int[] ops) {
435 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
436 Binder.getCallingPid(), Binder.getCallingUid(), null);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000437 String resolvedPackageName = resolvePackageName(uid, packageName);
438 if (resolvedPackageName == null) {
439 return Collections.emptyList();
440 }
Dianne Hackborn72e39832013-01-18 18:36:09 -0800441 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000442 Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800443 if (pkgOps == null) {
444 return null;
445 }
446 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
447 if (resOps == null) {
448 return null;
449 }
450 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
451 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700452 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800453 res.add(resPackage);
454 return res;
455 }
456 }
457
Dianne Hackborn607b4142013-08-02 18:10:10 -0700458 private void pruneOp(Op op, int uid, String packageName) {
459 if (op.time == 0 && op.rejectTime == 0) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000460 Ops ops = getOpsRawLocked(uid, packageName, false);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700461 if (ops != null) {
462 ops.remove(op.op);
463 if (ops.size() <= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -0700464 UidState uidState = ops.uidState;
465 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700466 if (pkgOps != null) {
467 pkgOps.remove(ops.packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700468 if (pkgOps.isEmpty()) {
469 uidState.pkgOps = null;
470 }
471 if (uidState.isDefault()) {
472 mUidStates.remove(uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700473 }
474 }
475 }
476 }
477 }
478 }
479
Dianne Hackborn72e39832013-01-18 18:36:09 -0800480 @Override
Svet Ganov2af57082015-07-30 08:44:20 -0700481 public void setUidMode(int code, int uid, int mode) {
482 if (Binder.getCallingPid() != Process.myPid()) {
483 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
484 Binder.getCallingPid(), Binder.getCallingUid(), null);
485 }
486 verifyIncomingOp(code);
487 code = AppOpsManager.opToSwitch(code);
488
489 synchronized (this) {
490 final int defaultMode = AppOpsManager.opToDefaultMode(code);
491
492 UidState uidState = getUidStateLocked(uid, false);
493 if (uidState == null) {
494 if (mode == defaultMode) {
495 return;
496 }
497 uidState = new UidState(uid);
498 uidState.opModes = new SparseIntArray();
499 uidState.opModes.put(code, mode);
500 mUidStates.put(uid, uidState);
501 scheduleWriteLocked();
502 } else if (uidState.opModes == null) {
503 if (mode != defaultMode) {
504 uidState.opModes = new SparseIntArray();
505 uidState.opModes.put(code, mode);
506 scheduleWriteLocked();
507 }
508 } else {
509 if (uidState.opModes.get(code) == mode) {
510 return;
511 }
512 if (mode == defaultMode) {
513 uidState.opModes.delete(code);
514 if (uidState.opModes.size() <= 0) {
515 uidState.opModes = null;
516 }
517 } else {
518 uidState.opModes.put(code, mode);
519 }
520 scheduleWriteLocked();
521 }
522 }
523
Svetoslav215b44a2015-08-04 19:03:40 -0700524 String[] uidPackageNames = getPackagesForUid(uid);
Svet Ganov2af57082015-07-30 08:44:20 -0700525 ArrayMap<Callback, ArraySet<String>> callbackSpecs = null;
526
riddle_hsu40b300f2015-11-23 13:22:03 +0800527 synchronized (this) {
528 ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -0700529 if (callbacks != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700530 final int callbackCount = callbacks.size();
531 for (int i = 0; i < callbackCount; i++) {
532 Callback callback = callbacks.get(i);
riddle_hsu40b300f2015-11-23 13:22:03 +0800533 ArraySet<String> changedPackages = new ArraySet<>();
534 Collections.addAll(changedPackages, uidPackageNames);
535 callbackSpecs = new ArrayMap<>();
536 callbackSpecs.put(callback, changedPackages);
537 }
538 }
539
540 for (String uidPackageName : uidPackageNames) {
541 callbacks = mPackageModeWatchers.get(uidPackageName);
542 if (callbacks != null) {
543 if (callbackSpecs == null) {
544 callbackSpecs = new ArrayMap<>();
Svet Ganov2af57082015-07-30 08:44:20 -0700545 }
riddle_hsu40b300f2015-11-23 13:22:03 +0800546 final int callbackCount = callbacks.size();
547 for (int i = 0; i < callbackCount; i++) {
548 Callback callback = callbacks.get(i);
549 ArraySet<String> changedPackages = callbackSpecs.get(callback);
550 if (changedPackages == null) {
551 changedPackages = new ArraySet<>();
552 callbackSpecs.put(callback, changedPackages);
553 }
554 changedPackages.add(uidPackageName);
555 }
Svet Ganov2af57082015-07-30 08:44:20 -0700556 }
557 }
558 }
559
560 if (callbackSpecs == null) {
561 return;
562 }
563
564 // There are components watching for mode changes such as window manager
565 // and location manager which are in our process. The callbacks in these
566 // components may require permissions our remote caller does not have.
567 final long identity = Binder.clearCallingIdentity();
568 try {
569 for (int i = 0; i < callbackSpecs.size(); i++) {
570 Callback callback = callbackSpecs.keyAt(i);
571 ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
572 try {
573 if (reportedPackageNames == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700574 callback.mCallback.opChanged(code, uid, null);
Svet Ganov2af57082015-07-30 08:44:20 -0700575 } else {
576 final int reportedPackageCount = reportedPackageNames.size();
577 for (int j = 0; j < reportedPackageCount; j++) {
578 String reportedPackageName = reportedPackageNames.valueAt(j);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700579 callback.mCallback.opChanged(code, uid, reportedPackageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700580 }
581 }
582 } catch (RemoteException e) {
583 Log.w(TAG, "Error dispatching op op change", e);
584 }
585 }
586 } finally {
587 Binder.restoreCallingIdentity(identity);
588 }
589 }
590
591 @Override
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800592 public void setMode(int code, int uid, String packageName, int mode) {
Dianne Hackbornb64afe12014-07-22 16:29:04 -0700593 if (Binder.getCallingPid() != Process.myPid()) {
594 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
595 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborn133b9df2014-07-01 13:06:10 -0700596 }
Dianne Hackborn961321f2013-02-05 17:22:41 -0800597 verifyIncomingOp(code);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800598 ArrayList<Callback> repCbs = null;
599 code = AppOpsManager.opToSwitch(code);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800600 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700601 UidState uidState = getUidStateLocked(uid, false);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800602 Op op = getOpLocked(code, uid, packageName, true);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800603 if (op != null) {
604 if (op.mode != mode) {
605 op.mode = mode;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800606 ArrayList<Callback> cbs = mOpModeWatchers.get(code);
607 if (cbs != null) {
608 if (repCbs == null) {
609 repCbs = new ArrayList<Callback>();
610 }
611 repCbs.addAll(cbs);
612 }
613 cbs = mPackageModeWatchers.get(packageName);
614 if (cbs != null) {
615 if (repCbs == null) {
616 repCbs = new ArrayList<Callback>();
617 }
618 repCbs.addAll(cbs);
619 }
David Braunf5d83192013-09-16 13:43:51 -0700620 if (mode == AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800621 // If going into the default mode, prune this op
622 // if there is nothing else interesting in it.
Dianne Hackborn607b4142013-08-02 18:10:10 -0700623 pruneOp(op, uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800624 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800625 scheduleFastWriteLocked();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800626 }
627 }
628 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800629 if (repCbs != null) {
Svet Ganov38536112015-05-19 12:45:52 -0700630 // There are components watching for mode changes such as window manager
631 // and location manager which are in our process. The callbacks in these
632 // components may require permissions our remote caller does not have.
633 final long identity = Binder.clearCallingIdentity();
634 try {
635 for (int i = 0; i < repCbs.size(); i++) {
636 try {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700637 repCbs.get(i).mCallback.opChanged(code, uid, packageName);
Svet Ganov38536112015-05-19 12:45:52 -0700638 } catch (RemoteException e) {
639 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800640 }
Svet Ganov38536112015-05-19 12:45:52 -0700641 } finally {
642 Binder.restoreCallingIdentity(identity);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800643 }
644 }
645 }
646
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700647 private static HashMap<Callback, ArrayList<ChangeRec>> addCallbacks(
648 HashMap<Callback, ArrayList<ChangeRec>> callbacks,
649 int op, int uid, String packageName, ArrayList<Callback> cbs) {
Dianne Hackborn607b4142013-08-02 18:10:10 -0700650 if (cbs == null) {
651 return callbacks;
652 }
653 if (callbacks == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700654 callbacks = new HashMap<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700655 }
Svet Ganov2af57082015-07-30 08:44:20 -0700656 boolean duplicate = false;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700657 for (int i=0; i<cbs.size(); i++) {
658 Callback cb = cbs.get(i);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700659 ArrayList<ChangeRec> reports = callbacks.get(cb);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700660 if (reports == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700661 reports = new ArrayList<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700662 callbacks.put(cb, reports);
Svet Ganov2af57082015-07-30 08:44:20 -0700663 } else {
664 final int reportCount = reports.size();
665 for (int j = 0; j < reportCount; j++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700666 ChangeRec report = reports.get(j);
667 if (report.op == op && report.pkg.equals(packageName)) {
Svet Ganov2af57082015-07-30 08:44:20 -0700668 duplicate = true;
669 break;
670 }
671 }
Dianne Hackborn607b4142013-08-02 18:10:10 -0700672 }
Svet Ganov2af57082015-07-30 08:44:20 -0700673 if (!duplicate) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700674 reports.add(new ChangeRec(op, uid, packageName));
Svet Ganov2af57082015-07-30 08:44:20 -0700675 }
Dianne Hackborn607b4142013-08-02 18:10:10 -0700676 }
677 return callbacks;
678 }
679
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700680 static final class ChangeRec {
681 final int op;
682 final int uid;
683 final String pkg;
684
685 ChangeRec(int _op, int _uid, String _pkg) {
686 op = _op;
687 uid = _uid;
688 pkg = _pkg;
689 }
690 }
691
Dianne Hackborn607b4142013-08-02 18:10:10 -0700692 @Override
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800693 public void resetAllModes(int reqUserId, String reqPackageName) {
694 final int callingPid = Binder.getCallingPid();
695 final int callingUid = Binder.getCallingUid();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700696 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800697 callingPid, callingUid, null);
698 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
699 true, true, "resetAllModes", null);
Svet Ganov2af57082015-07-30 08:44:20 -0700700
701 int reqUid = -1;
702 if (reqPackageName != null) {
703 try {
704 reqUid = AppGlobals.getPackageManager().getPackageUid(
Jeff Sharkeycd654482016-01-08 17:42:11 -0700705 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
Svet Ganov2af57082015-07-30 08:44:20 -0700706 } catch (RemoteException e) {
707 /* ignore - local call */
708 }
709 }
710
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700711 HashMap<Callback, ArrayList<ChangeRec>> callbacks = null;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700712 synchronized (this) {
713 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700714 for (int i = mUidStates.size() - 1; i >= 0; i--) {
715 UidState uidState = mUidStates.valueAt(i);
716
717 SparseIntArray opModes = uidState.opModes;
718 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
719 final int uidOpCount = opModes.size();
720 for (int j = uidOpCount - 1; j >= 0; j--) {
721 final int code = opModes.keyAt(j);
722 if (AppOpsManager.opAllowsReset(code)) {
723 opModes.removeAt(j);
724 if (opModes.size() <= 0) {
725 uidState.opModes = null;
726 }
727 for (String packageName : getPackagesForUid(uidState.uid)) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700728 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -0700729 mOpModeWatchers.get(code));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700730 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -0700731 mPackageModeWatchers.get(packageName));
732 }
733 }
734 }
735 }
736
737 if (uidState.pkgOps == null) {
738 continue;
739 }
740
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800741 if (reqUserId != UserHandle.USER_ALL
Svet Ganov2af57082015-07-30 08:44:20 -0700742 && reqUserId != UserHandle.getUserId(uidState.uid)) {
Alexandra Gherghinad6a98972014-08-04 17:05:34 +0100743 // Skip any ops for a different user
744 continue;
745 }
Svet Ganov2af57082015-07-30 08:44:20 -0700746
747 Map<String, Ops> packages = uidState.pkgOps;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -0700748 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
749 while (it.hasNext()) {
750 Map.Entry<String, Ops> ent = it.next();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700751 String packageName = ent.getKey();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800752 if (reqPackageName != null && !reqPackageName.equals(packageName)) {
753 // Skip any ops for a different package
754 continue;
755 }
Dianne Hackborn607b4142013-08-02 18:10:10 -0700756 Ops pkgOps = ent.getValue();
Dianne Hackborn7f09ec32013-08-07 15:36:08 -0700757 for (int j=pkgOps.size()-1; j>=0; j--) {
Dianne Hackborn607b4142013-08-02 18:10:10 -0700758 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn8828d3a2013-09-25 16:47:10 -0700759 if (AppOpsManager.opAllowsReset(curOp.op)
760 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
David Braunf5d83192013-09-16 13:43:51 -0700761 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700762 changed = true;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700763 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -0700764 mOpModeWatchers.get(curOp.op));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700765 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -0700766 mPackageModeWatchers.get(packageName));
Dianne Hackborn7f09ec32013-08-07 15:36:08 -0700767 if (curOp.time == 0 && curOp.rejectTime == 0) {
768 pkgOps.removeAt(j);
769 }
Dianne Hackborn607b4142013-08-02 18:10:10 -0700770 }
771 }
Dianne Hackborn7f09ec32013-08-07 15:36:08 -0700772 if (pkgOps.size() == 0) {
773 it.remove();
774 }
775 }
Svet Ganov2af57082015-07-30 08:44:20 -0700776 if (uidState.isDefault()) {
777 mUidStates.remove(uidState.uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700778 }
779 }
Svet Ganov2af57082015-07-30 08:44:20 -0700780
Dianne Hackborn607b4142013-08-02 18:10:10 -0700781 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800782 scheduleFastWriteLocked();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700783 }
784 }
785 if (callbacks != null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700786 for (Map.Entry<Callback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
Dianne Hackborn607b4142013-08-02 18:10:10 -0700787 Callback cb = ent.getKey();
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700788 ArrayList<ChangeRec> reports = ent.getValue();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700789 for (int i=0; i<reports.size(); i++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700790 ChangeRec rep = reports.get(i);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700791 try {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700792 cb.mCallback.opChanged(rep.op, rep.uid, rep.pkg);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700793 } catch (RemoteException e) {
794 }
795 }
796 }
797 }
798 }
799
Dianne Hackbornc2293022013-02-06 23:14:49 -0800800 @Override
801 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -0800802 if (callback == null) {
803 return;
804 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800805 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700806 op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800807 Callback cb = mModeWatchers.get(callback.asBinder());
808 if (cb == null) {
809 cb = new Callback(callback);
810 mModeWatchers.put(callback.asBinder(), cb);
811 }
812 if (op != AppOpsManager.OP_NONE) {
813 ArrayList<Callback> cbs = mOpModeWatchers.get(op);
814 if (cbs == null) {
815 cbs = new ArrayList<Callback>();
816 mOpModeWatchers.put(op, cbs);
817 }
818 cbs.add(cb);
819 }
820 if (packageName != null) {
821 ArrayList<Callback> cbs = mPackageModeWatchers.get(packageName);
822 if (cbs == null) {
823 cbs = new ArrayList<Callback>();
824 mPackageModeWatchers.put(packageName, cbs);
825 }
826 cbs.add(cb);
827 }
828 }
829 }
830
831 @Override
832 public void stopWatchingMode(IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -0800833 if (callback == null) {
834 return;
835 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800836 synchronized (this) {
837 Callback cb = mModeWatchers.remove(callback.asBinder());
838 if (cb != null) {
839 cb.unlinkToDeath();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700840 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800841 ArrayList<Callback> cbs = mOpModeWatchers.valueAt(i);
842 cbs.remove(cb);
843 if (cbs.size() <= 0) {
844 mOpModeWatchers.removeAt(i);
845 }
846 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700847 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
848 ArrayList<Callback> cbs = mPackageModeWatchers.valueAt(i);
849 cbs.remove(cb);
850 if (cbs.size() <= 0) {
851 mPackageModeWatchers.removeAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800852 }
853 }
854 }
855 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800856 }
857
858 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700859 public IBinder getToken(IBinder clientToken) {
860 synchronized (this) {
861 ClientState cs = mClients.get(clientToken);
862 if (cs == null) {
863 cs = new ClientState(clientToken);
864 mClients.put(clientToken, cs);
865 }
866 return cs;
867 }
868 }
869
870 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -0800871 public int checkOperation(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800872 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -0800873 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000874 String resolvedPackageName = resolvePackageName(uid, packageName);
875 if (resolvedPackageName == null) {
876 return AppOpsManager.MODE_IGNORED;
877 }
Dianne Hackborn35654b62013-01-14 17:38:02 -0800878 synchronized (this) {
Svet Ganov442ed572016-08-17 17:29:43 -0700879 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -0400880 return AppOpsManager.MODE_IGNORED;
881 }
Svet Ganov2af57082015-07-30 08:44:20 -0700882 code = AppOpsManager.opToSwitch(code);
883 UidState uidState = getUidStateLocked(uid, false);
Svet Ganovee438d42017-01-19 18:04:38 -0800884 if (uidState != null && uidState.opModes != null
885 && uidState.opModes.indexOfKey(code) >= 0) {
886 return uidState.opModes.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -0700887 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000888 Op op = getOpLocked(code, uid, resolvedPackageName, false);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800889 if (op == null) {
David Braunf5d83192013-09-16 13:43:51 -0700890 return AppOpsManager.opToDefaultMode(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800891 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800892 return op.mode;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800893 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800894 }
895
896 @Override
John Spurlock7b414672014-07-18 13:02:39 -0400897 public int checkAudioOperation(int code, int usage, int uid, String packageName) {
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +0000898 boolean suspended;
899 try {
900 suspended = isPackageSuspendedForUser(packageName, uid);
901 } catch (IllegalArgumentException ex) {
902 // Package not found.
903 suspended = false;
904 }
905
906 if (suspended) {
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +0000907 Log.i(TAG, "Audio disabled for suspended package=" + packageName + " for uid=" + uid);
908 return AppOpsManager.MODE_IGNORED;
909 }
910
John Spurlock1af30c72014-03-10 08:33:35 -0400911 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -0400912 final int mode = checkRestrictionLocked(code, usage, uid, packageName);
John Spurlock1af30c72014-03-10 08:33:35 -0400913 if (mode != AppOpsManager.MODE_ALLOWED) {
914 return mode;
915 }
916 }
917 return checkOperation(code, uid, packageName);
918 }
919
Andrei Stingaceanu355b2322016-02-12 16:43:51 +0000920 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +0000921 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +0000922 return AppGlobals.getPackageManager().isPackageSuspendedForUser(
923 pkg, UserHandle.getUserId(uid));
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +0000924 } catch (RemoteException re) {
925 throw new SecurityException("Could not talk to package manager service");
926 }
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +0000927 }
928
John Spurlock7b414672014-07-18 13:02:39 -0400929 private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
930 final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
931 if (usageRestrictions != null) {
932 final Restriction r = usageRestrictions.get(usage);
John Spurlock1af30c72014-03-10 08:33:35 -0400933 if (r != null && !r.exceptionPackages.contains(packageName)) {
934 return r.mode;
935 }
936 }
937 return AppOpsManager.MODE_ALLOWED;
938 }
939
940 @Override
John Spurlock7b414672014-07-18 13:02:39 -0400941 public void setAudioRestriction(int code, int usage, int uid, int mode,
John Spurlock1af30c72014-03-10 08:33:35 -0400942 String[] exceptionPackages) {
943 verifyIncomingUid(uid);
944 verifyIncomingOp(code);
945 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -0400946 SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
947 if (usageRestrictions == null) {
948 usageRestrictions = new SparseArray<Restriction>();
949 mAudioRestrictions.put(code, usageRestrictions);
John Spurlock1af30c72014-03-10 08:33:35 -0400950 }
John Spurlock7b414672014-07-18 13:02:39 -0400951 usageRestrictions.remove(usage);
John Spurlock1af30c72014-03-10 08:33:35 -0400952 if (mode != AppOpsManager.MODE_ALLOWED) {
953 final Restriction r = new Restriction();
954 r.mode = mode;
955 if (exceptionPackages != null) {
956 final int N = exceptionPackages.length;
957 r.exceptionPackages = new ArraySet<String>(N);
958 for (int i = 0; i < N; i++) {
959 final String pkg = exceptionPackages[i];
960 if (pkg != null) {
961 r.exceptionPackages.add(pkg.trim());
962 }
963 }
964 }
John Spurlock7b414672014-07-18 13:02:39 -0400965 usageRestrictions.put(usage, r);
John Spurlock1af30c72014-03-10 08:33:35 -0400966 }
967 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -0400968 notifyWatchersOfChange(code);
John Spurlock1af30c72014-03-10 08:33:35 -0400969 }
970
971 @Override
Jeff Sharkey911d7f42013-09-05 18:11:45 -0700972 public int checkPackage(int uid, String packageName) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000973 Preconditions.checkNotNull(packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -0700974 synchronized (this) {
Dianne Hackborn0fcef842014-09-12 15:38:33 -0700975 if (getOpsRawLocked(uid, packageName, true) != null) {
Jeff Sharkey911d7f42013-09-05 18:11:45 -0700976 return AppOpsManager.MODE_ALLOWED;
977 } else {
978 return AppOpsManager.MODE_ERRORED;
979 }
980 }
981 }
982
983 @Override
Svet Ganov99b60432015-06-27 13:15:22 -0700984 public int noteProxyOperation(int code, String proxyPackageName,
985 int proxiedUid, String proxiedPackageName) {
986 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000987 final int proxyUid = Binder.getCallingUid();
988 String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
989 if (resolveProxyPackageName == null) {
990 return AppOpsManager.MODE_IGNORED;
991 }
992 final int proxyMode = noteOperationUnchecked(code, proxyUid,
993 resolveProxyPackageName, -1, null);
Svet Ganov99b60432015-06-27 13:15:22 -0700994 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
995 return proxyMode;
996 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000997 String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
998 if (resolveProxiedPackageName == null) {
999 return AppOpsManager.MODE_IGNORED;
1000 }
1001 return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
1002 proxyMode, resolveProxyPackageName);
Svet Ganov99b60432015-06-27 13:15:22 -07001003 }
1004
1005 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001006 public int noteOperation(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001007 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001008 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001009 String resolvedPackageName = resolvePackageName(uid, packageName);
1010 if (resolvedPackageName == null) {
1011 return AppOpsManager.MODE_IGNORED;
1012 }
1013 return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001014 }
1015
1016 private int noteOperationUnchecked(int code, int uid, String packageName,
1017 int proxyUid, String proxyPackageName) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001018 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001019 Ops ops = getOpsRawLocked(uid, packageName, true);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001020 if (ops == null) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001021 if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
1022 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001023 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001024 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001025 Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001026 if (isOpRestrictedLocked(uid, code, packageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001027 return AppOpsManager.MODE_IGNORED;
1028 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001029 if (op.duration == -1) {
1030 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
1031 + " code " + code + " time=" + op.time + " duration=" + op.duration);
1032 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001033 op.duration = 0;
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001034 final int switchCode = AppOpsManager.opToSwitch(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001035 UidState uidState = ops.uidState;
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001036 // If there is a non-default per UID policy (we set UID op mode only if
1037 // non-default) it takes over, otherwise use the per package policy.
1038 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -07001039 final int uidMode = uidState.opModes.get(switchCode);
1040 if (uidMode != AppOpsManager.MODE_ALLOWED) {
1041 if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
1042 + switchCode + " (" + code + ") uid " + uid + " package "
1043 + packageName);
1044 op.rejectTime = System.currentTimeMillis();
1045 return uidMode;
1046 }
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001047 } else {
1048 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
1049 if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
1050 if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
1051 + switchCode + " (" + code + ") uid " + uid + " package "
1052 + packageName);
1053 op.rejectTime = System.currentTimeMillis();
1054 return switchOp.mode;
1055 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001056 }
1057 if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
1058 + " package " + packageName);
1059 op.time = System.currentTimeMillis();
Dianne Hackborn514074f2013-02-11 10:52:46 -08001060 op.rejectTime = 0;
Svet Ganov99b60432015-06-27 13:15:22 -07001061 op.proxyUid = proxyUid;
1062 op.proxyPackageName = proxyPackageName;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001063 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001064 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001065 }
1066
1067 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001068 public int startOperation(IBinder token, int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001069 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001070 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001071 String resolvedPackageName = resolvePackageName(uid, packageName);
1072 if (resolvedPackageName == null) {
1073 return AppOpsManager.MODE_IGNORED;
1074 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001075 ClientState client = (ClientState)token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001076 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001077 Ops ops = getOpsRawLocked(uid, resolvedPackageName, true);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001078 if (ops == null) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001079 if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001080 + " package " + resolvedPackageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001081 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001082 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001083 Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001084 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001085 return AppOpsManager.MODE_IGNORED;
1086 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001087 final int switchCode = AppOpsManager.opToSwitch(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001088 UidState uidState = ops.uidState;
1089 if (uidState.opModes != null) {
1090 final int uidMode = uidState.opModes.get(switchCode);
1091 if (uidMode != AppOpsManager.MODE_ALLOWED) {
1092 if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
1093 + switchCode + " (" + code + ") uid " + uid + " package "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001094 + resolvedPackageName);
Svet Ganov2af57082015-07-30 08:44:20 -07001095 op.rejectTime = System.currentTimeMillis();
1096 return uidMode;
1097 }
1098 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001099 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
1100 if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
1101 if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001102 + switchCode + " (" + code + ") uid " + uid + " package "
1103 + resolvedPackageName);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001104 op.rejectTime = System.currentTimeMillis();
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001105 return switchOp.mode;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001106 }
1107 if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001108 + " package " + resolvedPackageName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001109 if (op.nesting == 0) {
1110 op.time = System.currentTimeMillis();
Dianne Hackborn514074f2013-02-11 10:52:46 -08001111 op.rejectTime = 0;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001112 op.duration = -1;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001113 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001114 op.nesting++;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001115 if (client.mStartedOps != null) {
1116 client.mStartedOps.add(op);
1117 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001118 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001119 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001120 }
1121
1122 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001123 public void finishOperation(IBinder token, int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001124 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001125 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001126 String resolvedPackageName = resolvePackageName(uid, packageName);
1127 if (resolvedPackageName == null) {
1128 return;
1129 }
1130 if (!(token instanceof ClientState)) {
1131 return;
1132 }
1133 ClientState client = (ClientState) token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001134 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001135 Op op = getOpLocked(code, uid, resolvedPackageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001136 if (op == null) {
1137 return;
1138 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001139 if (client.mStartedOps != null) {
1140 if (!client.mStartedOps.remove(op)) {
1141 throw new IllegalStateException("Operation not started: uid" + op.uid
1142 + " pkg=" + op.packageName + " op=" + op.op);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001143 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001144 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001145 finishOperationLocked(op);
1146 }
1147 }
1148
Svet Ganovb9d71a62015-04-30 10:38:13 -07001149 @Override
1150 public int permissionToOpCode(String permission) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001151 if (permission == null) {
1152 return AppOpsManager.OP_NONE;
1153 }
Svet Ganovb9d71a62015-04-30 10:38:13 -07001154 return AppOpsManager.permissionToOpCode(permission);
1155 }
1156
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001157 void finishOperationLocked(Op op) {
1158 if (op.nesting <= 1) {
1159 if (op.nesting == 1) {
1160 op.duration = (int)(System.currentTimeMillis() - op.time);
1161 op.time += op.duration;
1162 } else {
1163 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
1164 + op.packageName + " code " + op.op + " time=" + op.time
1165 + " duration=" + op.duration + " nesting=" + op.nesting);
1166 }
1167 op.nesting = 0;
1168 } else {
1169 op.nesting--;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001170 }
1171 }
1172
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001173 private void verifyIncomingUid(int uid) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001174 if (uid == Binder.getCallingUid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001175 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001176 }
1177 if (Binder.getCallingPid() == Process.myPid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001178 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001179 }
1180 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
1181 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001182 }
1183
Dianne Hackborn961321f2013-02-05 17:22:41 -08001184 private void verifyIncomingOp(int op) {
1185 if (op >= 0 && op < AppOpsManager._NUM_OP) {
1186 return;
1187 }
1188 throw new IllegalArgumentException("Bad operation #" + op);
1189 }
1190
Svet Ganov2af57082015-07-30 08:44:20 -07001191 private UidState getUidStateLocked(int uid, boolean edit) {
1192 UidState uidState = mUidStates.get(uid);
1193 if (uidState == null) {
1194 if (!edit) {
1195 return null;
1196 }
1197 uidState = new UidState(uid);
1198 mUidStates.put(uid, uidState);
1199 }
1200 return uidState;
1201 }
1202
Dianne Hackborn0fcef842014-09-12 15:38:33 -07001203 private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
Svet Ganov2af57082015-07-30 08:44:20 -07001204 UidState uidState = getUidStateLocked(uid, edit);
1205 if (uidState == null) {
1206 return null;
1207 }
1208
1209 if (uidState.pkgOps == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001210 if (!edit) {
1211 return null;
1212 }
Svet Ganov2af57082015-07-30 08:44:20 -07001213 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001214 }
Svet Ganov2af57082015-07-30 08:44:20 -07001215
1216 Ops ops = uidState.pkgOps.get(packageName);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001217 if (ops == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001218 if (!edit) {
1219 return null;
1220 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001221 boolean isPrivileged = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001222 // This is the first time we have seen this package name under this uid,
1223 // so let's make sure it is valid.
Dianne Hackborn514074f2013-02-11 10:52:46 -08001224 if (uid != 0) {
1225 final long ident = Binder.clearCallingIdentity();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001226 try {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001227 int pkgUid = -1;
1228 try {
Jason Monk1c7c3192014-06-26 12:52:18 -04001229 ApplicationInfo appInfo = ActivityThread.getPackageManager()
Jeff Sharkeycd654482016-01-08 17:42:11 -07001230 .getApplicationInfo(packageName,
1231 PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
1232 UserHandle.getUserId(uid));
Jason Monk1c7c3192014-06-26 12:52:18 -04001233 if (appInfo != null) {
1234 pkgUid = appInfo.uid;
Alex Klyubinb9f8a522015-02-03 11:12:59 -08001235 isPrivileged = (appInfo.privateFlags
1236 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04001237 } else {
1238 if ("media".equals(packageName)) {
1239 pkgUid = Process.MEDIA_UID;
1240 isPrivileged = false;
Andy Hunged0ea402015-10-30 14:11:46 -07001241 } else if ("audioserver".equals(packageName)) {
1242 pkgUid = Process.AUDIOSERVER_UID;
1243 isPrivileged = false;
Chien-Yu Chen75cade02016-01-11 10:56:21 -08001244 } else if ("cameraserver".equals(packageName)) {
1245 pkgUid = Process.CAMERASERVER_UID;
1246 isPrivileged = false;
Jason Monk1c7c3192014-06-26 12:52:18 -04001247 }
Dianne Hackborn713df152013-05-17 11:27:57 -07001248 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001249 } catch (RemoteException e) {
1250 Slog.w(TAG, "Could not contact PackageManager", e);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001251 }
1252 if (pkgUid != uid) {
1253 // Oops! The package name is not valid for the uid they are calling
1254 // under. Abort.
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001255 RuntimeException ex = new RuntimeException("here");
1256 ex.fillInStackTrace();
Dianne Hackborn514074f2013-02-11 10:52:46 -08001257 Slog.w(TAG, "Bad call: specified package " + packageName
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001258 + " under uid " + uid + " but it is really " + pkgUid, ex);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001259 return null;
1260 }
1261 } finally {
1262 Binder.restoreCallingIdentity(ident);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001263 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001264 }
Svet Ganov2af57082015-07-30 08:44:20 -07001265 ops = new Ops(packageName, uidState, isPrivileged);
1266 uidState.pkgOps.put(packageName, ops);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001267 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08001268 return ops;
1269 }
1270
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001271 private void scheduleWriteLocked() {
1272 if (!mWriteScheduled) {
1273 mWriteScheduled = true;
1274 mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
1275 }
1276 }
1277
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001278 private void scheduleFastWriteLocked() {
1279 if (!mFastWriteScheduled) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001280 mWriteScheduled = true;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001281 mFastWriteScheduled = true;
1282 mHandler.removeCallbacks(mWriteRunner);
1283 mHandler.postDelayed(mWriteRunner, 10*1000);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001284 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001285 }
1286
Dianne Hackborn72e39832013-01-18 18:36:09 -08001287 private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001288 Ops ops = getOpsRawLocked(uid, packageName, edit);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001289 if (ops == null) {
1290 return null;
1291 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001292 return getOpLocked(ops, code, edit);
1293 }
1294
1295 private Op getOpLocked(Ops ops, int code, boolean edit) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001296 Op op = ops.get(code);
1297 if (op == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001298 if (!edit) {
1299 return null;
1300 }
Svet Ganov2af57082015-07-30 08:44:20 -07001301 op = new Op(ops.uidState.uid, ops.packageName, code);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001302 ops.put(code, op);
1303 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001304 if (edit) {
1305 scheduleWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001306 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001307 return op;
1308 }
1309
Svet Ganov442ed572016-08-17 17:29:43 -07001310 private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
Jason Monk62062992014-05-06 09:55:28 -04001311 int userHandle = UserHandle.getUserId(uid);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001312 final int restrictionSetCount = mOpUserRestrictions.size();
Ruben Brunk29931bc2016-03-11 00:24:26 -08001313
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001314 for (int i = 0; i < restrictionSetCount; i++) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08001315 // For each client, check that the given op is not restricted, or that the given
1316 // package is exempt from the restriction.
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07001317 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07001318 if (restrictionState.hasRestriction(code, packageName, userHandle)) {
1319 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
1320 // If we are the system, bypass user restrictions for certain codes
1321 synchronized (this) {
1322 Ops ops = getOpsRawLocked(uid, packageName, true);
1323 if ((ops != null) && ops.isPrivileged) {
1324 return false;
1325 }
Ruben Brunk32f0fa42016-03-11 19:07:07 -08001326 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08001327 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001328 return true;
Jason Monk1c7c3192014-06-26 12:52:18 -04001329 }
Jason Monk62062992014-05-06 09:55:28 -04001330 }
1331 return false;
1332 }
1333
Dianne Hackborn35654b62013-01-14 17:38:02 -08001334 void readState() {
1335 synchronized (mFile) {
1336 synchronized (this) {
1337 FileInputStream stream;
1338 try {
1339 stream = mFile.openRead();
1340 } catch (FileNotFoundException e) {
1341 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
1342 return;
1343 }
1344 boolean success = false;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07001345 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001346 try {
1347 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001348 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08001349 int type;
1350 while ((type = parser.next()) != XmlPullParser.START_TAG
1351 && type != XmlPullParser.END_DOCUMENT) {
1352 ;
1353 }
1354
1355 if (type != XmlPullParser.START_TAG) {
1356 throw new IllegalStateException("no start tag found");
1357 }
1358
1359 int outerDepth = parser.getDepth();
1360 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1361 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1362 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1363 continue;
1364 }
1365
1366 String tagName = parser.getName();
1367 if (tagName.equals("pkg")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00001368 readPackage(parser);
Svetoslav215b44a2015-08-04 19:03:40 -07001369 } else if (tagName.equals("uid")) {
Svet Ganov2af57082015-07-30 08:44:20 -07001370 readUidOps(parser);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001371 } else {
1372 Slog.w(TAG, "Unknown element under <app-ops>: "
1373 + parser.getName());
1374 XmlUtils.skipCurrentTag(parser);
1375 }
1376 }
1377 success = true;
1378 } catch (IllegalStateException e) {
1379 Slog.w(TAG, "Failed parsing " + e);
1380 } catch (NullPointerException e) {
1381 Slog.w(TAG, "Failed parsing " + e);
1382 } catch (NumberFormatException e) {
1383 Slog.w(TAG, "Failed parsing " + e);
1384 } catch (XmlPullParserException e) {
1385 Slog.w(TAG, "Failed parsing " + e);
1386 } catch (IOException e) {
1387 Slog.w(TAG, "Failed parsing " + e);
1388 } catch (IndexOutOfBoundsException e) {
1389 Slog.w(TAG, "Failed parsing " + e);
1390 } finally {
1391 if (!success) {
Svet Ganov2af57082015-07-30 08:44:20 -07001392 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001393 }
1394 try {
1395 stream.close();
1396 } catch (IOException e) {
1397 }
1398 }
1399 }
1400 }
1401 }
1402
Svet Ganov2af57082015-07-30 08:44:20 -07001403 void readUidOps(XmlPullParser parser) throws NumberFormatException,
1404 XmlPullParserException, IOException {
1405 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
1406 int outerDepth = parser.getDepth();
1407 int type;
1408 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1409 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1410 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1411 continue;
1412 }
1413
1414 String tagName = parser.getName();
1415 if (tagName.equals("op")) {
1416 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
1417 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
1418 UidState uidState = getUidStateLocked(uid, true);
1419 if (uidState.opModes == null) {
1420 uidState.opModes = new SparseIntArray();
1421 }
1422 uidState.opModes.put(code, mode);
1423 } else {
1424 Slog.w(TAG, "Unknown element under <uid-ops>: "
1425 + parser.getName());
1426 XmlUtils.skipCurrentTag(parser);
1427 }
1428 }
1429 }
1430
Dave Burke0997c5bd2013-08-02 20:25:02 +00001431 void readPackage(XmlPullParser parser) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08001432 XmlPullParserException, IOException {
1433 String pkgName = parser.getAttributeValue(null, "n");
1434 int outerDepth = parser.getDepth();
1435 int type;
1436 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1437 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1438 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1439 continue;
1440 }
1441
1442 String tagName = parser.getName();
1443 if (tagName.equals("uid")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00001444 readUid(parser, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001445 } else {
1446 Slog.w(TAG, "Unknown element under <pkg>: "
1447 + parser.getName());
1448 XmlUtils.skipCurrentTag(parser);
1449 }
1450 }
1451 }
1452
Dave Burke0997c5bd2013-08-02 20:25:02 +00001453 void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08001454 XmlPullParserException, IOException {
1455 int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
Jason Monk1c7c3192014-06-26 12:52:18 -04001456 String isPrivilegedString = parser.getAttributeValue(null, "p");
1457 boolean isPrivileged = false;
1458 if (isPrivilegedString == null) {
1459 try {
1460 IPackageManager packageManager = ActivityThread.getPackageManager();
1461 if (packageManager != null) {
1462 ApplicationInfo appInfo = ActivityThread.getPackageManager()
1463 .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
1464 if (appInfo != null) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08001465 isPrivileged = (appInfo.privateFlags
1466 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04001467 }
1468 } else {
1469 // Could not load data, don't add to cache so it will be loaded later.
1470 return;
1471 }
1472 } catch (RemoteException e) {
1473 Slog.w(TAG, "Could not contact PackageManager", e);
1474 }
1475 } else {
1476 isPrivileged = Boolean.parseBoolean(isPrivilegedString);
1477 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001478 int outerDepth = parser.getDepth();
1479 int type;
1480 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1481 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1482 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1483 continue;
1484 }
1485
1486 String tagName = parser.getName();
1487 if (tagName.equals("op")) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001488 Op op = new Op(uid, pkgName, Integer.parseInt(parser.getAttributeValue(null, "n")));
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001489 String mode = parser.getAttributeValue(null, "m");
1490 if (mode != null) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00001491 op.mode = Integer.parseInt(mode);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001492 }
1493 String time = parser.getAttributeValue(null, "t");
1494 if (time != null) {
1495 op.time = Long.parseLong(time);
1496 }
1497 time = parser.getAttributeValue(null, "r");
1498 if (time != null) {
1499 op.rejectTime = Long.parseLong(time);
1500 }
1501 String dur = parser.getAttributeValue(null, "d");
1502 if (dur != null) {
1503 op.duration = Integer.parseInt(dur);
1504 }
Svet Ganov99b60432015-06-27 13:15:22 -07001505 String proxyUid = parser.getAttributeValue(null, "pu");
1506 if (proxyUid != null) {
1507 op.proxyUid = Integer.parseInt(proxyUid);
1508 }
1509 String proxyPackageName = parser.getAttributeValue(null, "pp");
1510 if (proxyPackageName != null) {
1511 op.proxyPackageName = proxyPackageName;
1512 }
Svet Ganov2af57082015-07-30 08:44:20 -07001513
1514 UidState uidState = getUidStateLocked(uid, true);
1515 if (uidState.pkgOps == null) {
1516 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001517 }
Svet Ganov2af57082015-07-30 08:44:20 -07001518
1519 Ops ops = uidState.pkgOps.get(pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001520 if (ops == null) {
Svet Ganov2af57082015-07-30 08:44:20 -07001521 ops = new Ops(pkgName, uidState, isPrivileged);
1522 uidState.pkgOps.put(pkgName, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001523 }
1524 ops.put(op.op, op);
1525 } else {
1526 Slog.w(TAG, "Unknown element under <pkg>: "
1527 + parser.getName());
1528 XmlUtils.skipCurrentTag(parser);
1529 }
1530 }
1531 }
1532
1533 void writeState() {
1534 synchronized (mFile) {
1535 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
1536
1537 FileOutputStream stream;
1538 try {
1539 stream = mFile.startWrite();
1540 } catch (IOException e) {
1541 Slog.w(TAG, "Failed to write state: " + e);
1542 return;
1543 }
1544
1545 try {
1546 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001547 out.setOutput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08001548 out.startDocument(null, true);
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07001549 out.startTag(null, "app-ops");
Svet Ganov2af57082015-07-30 08:44:20 -07001550
1551 final int uidStateCount = mUidStates.size();
1552 for (int i = 0; i < uidStateCount; i++) {
1553 UidState uidState = mUidStates.valueAt(i);
1554 if (uidState.opModes != null && uidState.opModes.size() > 0) {
1555 out.startTag(null, "uid");
1556 out.attribute(null, "n", Integer.toString(uidState.uid));
1557 SparseIntArray uidOpModes = uidState.opModes;
1558 final int opCount = uidOpModes.size();
1559 for (int j = 0; j < opCount; j++) {
1560 final int op = uidOpModes.keyAt(j);
1561 final int mode = uidOpModes.valueAt(j);
1562 out.startTag(null, "op");
1563 out.attribute(null, "n", Integer.toString(op));
1564 out.attribute(null, "m", Integer.toString(mode));
1565 out.endTag(null, "op");
1566 }
1567 out.endTag(null, "uid");
1568 }
1569 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001570
1571 if (allOps != null) {
1572 String lastPkg = null;
1573 for (int i=0; i<allOps.size(); i++) {
1574 AppOpsManager.PackageOps pkg = allOps.get(i);
1575 if (!pkg.getPackageName().equals(lastPkg)) {
1576 if (lastPkg != null) {
1577 out.endTag(null, "pkg");
1578 }
1579 lastPkg = pkg.getPackageName();
1580 out.startTag(null, "pkg");
1581 out.attribute(null, "n", lastPkg);
1582 }
1583 out.startTag(null, "uid");
1584 out.attribute(null, "n", Integer.toString(pkg.getUid()));
Jason Monk1c7c3192014-06-26 12:52:18 -04001585 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001586 Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), false);
Jason Monk1c7c3192014-06-26 12:52:18 -04001587 // Should always be present as the list of PackageOps is generated
1588 // from Ops.
1589 if (ops != null) {
1590 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
1591 } else {
1592 out.attribute(null, "p", Boolean.toString(false));
1593 }
1594 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001595 List<AppOpsManager.OpEntry> ops = pkg.getOps();
1596 for (int j=0; j<ops.size(); j++) {
1597 AppOpsManager.OpEntry op = ops.get(j);
1598 out.startTag(null, "op");
1599 out.attribute(null, "n", Integer.toString(op.getOp()));
David Braunf5d83192013-09-16 13:43:51 -07001600 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001601 out.attribute(null, "m", Integer.toString(op.getMode()));
1602 }
1603 long time = op.getTime();
1604 if (time != 0) {
1605 out.attribute(null, "t", Long.toString(time));
1606 }
1607 time = op.getRejectTime();
1608 if (time != 0) {
1609 out.attribute(null, "r", Long.toString(time));
1610 }
1611 int dur = op.getDuration();
1612 if (dur != 0) {
1613 out.attribute(null, "d", Integer.toString(dur));
1614 }
Svet Ganov99b60432015-06-27 13:15:22 -07001615 int proxyUid = op.getProxyUid();
1616 if (proxyUid != -1) {
1617 out.attribute(null, "pu", Integer.toString(proxyUid));
1618 }
1619 String proxyPackageName = op.getProxyPackageName();
1620 if (proxyPackageName != null) {
1621 out.attribute(null, "pp", proxyPackageName);
1622 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001623 out.endTag(null, "op");
1624 }
1625 out.endTag(null, "uid");
1626 }
1627 if (lastPkg != null) {
1628 out.endTag(null, "pkg");
1629 }
1630 }
1631
1632 out.endTag(null, "app-ops");
1633 out.endDocument();
1634 mFile.finishWrite(stream);
1635 } catch (IOException e) {
1636 Slog.w(TAG, "Failed to write state, restoring backup.", e);
1637 mFile.failWrite(stream);
1638 }
1639 }
1640 }
1641
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001642 static class Shell extends ShellCommand {
1643 final IAppOpsService mInterface;
1644 final AppOpsService mInternal;
1645
1646 int userId = UserHandle.USER_SYSTEM;
1647 String packageName;
1648 String opStr;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07001649 String modeStr;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001650 int op;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07001651 int mode;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001652 int packageUid;
1653
1654 Shell(IAppOpsService iface, AppOpsService internal) {
1655 mInterface = iface;
1656 mInternal = internal;
1657 }
1658
1659 @Override
1660 public int onCommand(String cmd) {
1661 return onShellCommand(this, cmd);
1662 }
1663
1664 @Override
1665 public void onHelp() {
1666 PrintWriter pw = getOutPrintWriter();
1667 dumpCommandHelp(pw);
1668 }
1669
1670 private int strOpToOp(String op, PrintWriter err) {
1671 try {
1672 return AppOpsManager.strOpToOp(op);
1673 } catch (IllegalArgumentException e) {
1674 }
1675 try {
1676 return Integer.parseInt(op);
1677 } catch (NumberFormatException e) {
1678 }
1679 try {
1680 return AppOpsManager.strDebugOpToOp(op);
1681 } catch (IllegalArgumentException e) {
1682 err.println("Error: " + e.getMessage());
1683 return -1;
1684 }
1685 }
1686
Dianne Hackborne91f3e72016-03-25 18:48:15 -07001687 int strModeToMode(String modeStr, PrintWriter err) {
1688 switch (modeStr) {
1689 case "allow":
1690 return AppOpsManager.MODE_ALLOWED;
1691 case "deny":
1692 return AppOpsManager.MODE_ERRORED;
1693 case "ignore":
1694 return AppOpsManager.MODE_IGNORED;
1695 case "default":
1696 return AppOpsManager.MODE_DEFAULT;
1697 }
1698 try {
1699 return Integer.parseInt(modeStr);
1700 } catch (NumberFormatException e) {
1701 }
1702 err.println("Error: Mode " + modeStr + " is not valid");
1703 return -1;
1704 }
1705
1706 int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
1707 userId = UserHandle.USER_CURRENT;
1708 opStr = null;
1709 modeStr = null;
1710 for (String argument; (argument = getNextArg()) != null;) {
1711 if ("--user".equals(argument)) {
1712 userId = UserHandle.parseUserArg(getNextArgRequired());
1713 } else {
1714 if (opStr == null) {
1715 opStr = argument;
1716 } else if (modeStr == null) {
1717 modeStr = argument;
1718 break;
1719 }
1720 }
1721 }
1722 if (opStr == null) {
1723 err.println("Error: Operation not specified.");
1724 return -1;
1725 }
1726 op = strOpToOp(opStr, err);
1727 if (op < 0) {
1728 return -1;
1729 }
1730 if (modeStr != null) {
1731 if ((mode=strModeToMode(modeStr, err)) < 0) {
1732 return -1;
1733 }
1734 } else {
1735 mode = defMode;
1736 }
1737 return 0;
1738 }
1739
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001740 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
1741 userId = UserHandle.USER_CURRENT;
1742 packageName = null;
1743 opStr = null;
1744 for (String argument; (argument = getNextArg()) != null;) {
1745 if ("--user".equals(argument)) {
1746 userId = UserHandle.parseUserArg(getNextArgRequired());
1747 } else {
1748 if (packageName == null) {
1749 packageName = argument;
1750 } else if (opStr == null) {
1751 opStr = argument;
1752 break;
1753 }
1754 }
1755 }
1756 if (packageName == null) {
1757 err.println("Error: Package name not specified.");
1758 return -1;
1759 } else if (opStr == null && reqOp) {
1760 err.println("Error: Operation not specified.");
1761 return -1;
1762 }
1763 if (opStr != null) {
1764 op = strOpToOp(opStr, err);
1765 if (op < 0) {
1766 return -1;
1767 }
1768 } else {
1769 op = AppOpsManager.OP_NONE;
1770 }
1771 if (userId == UserHandle.USER_CURRENT) {
1772 userId = ActivityManager.getCurrentUser();
1773 }
1774 if ("root".equals(packageName)) {
1775 packageUid = 0;
1776 } else {
Jeff Sharkeycd654482016-01-08 17:42:11 -07001777 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
1778 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001779 }
1780 if (packageUid < 0) {
1781 err.println("Error: No UID for " + packageName + " in user " + userId);
1782 return -1;
1783 }
1784 return 0;
1785 }
1786 }
1787
1788 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07001789 FileDescriptor err, String[] args, ShellCallback callback,
1790 ResultReceiver resultReceiver) {
1791 (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001792 }
1793
1794 static void dumpCommandHelp(PrintWriter pw) {
1795 pw.println("AppOps service (appops) commands:");
1796 pw.println(" help");
1797 pw.println(" Print this help text.");
1798 pw.println(" set [--user <USER_ID>] <PACKAGE> <OP> <MODE>");
1799 pw.println(" Set the mode for a particular application and operation.");
1800 pw.println(" get [--user <USER_ID>] <PACKAGE> [<OP>]");
1801 pw.println(" Return the mode for a particular application and optional operation.");
Dianne Hackborne91f3e72016-03-25 18:48:15 -07001802 pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
1803 pw.println(" Print all packages that currently have the given op in the given mode.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001804 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
1805 pw.println(" Reset the given application or all applications to default modes.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07001806 pw.println(" write-settings");
1807 pw.println(" Immediately write pending changes to storage.");
1808 pw.println(" read-settings");
1809 pw.println(" Read the last written settings, replacing current state in RAM.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001810 pw.println(" options:");
1811 pw.println(" <PACKAGE> an Android package name.");
1812 pw.println(" <OP> an AppOps operation.");
1813 pw.println(" <MODE> one of allow, ignore, deny, or default");
1814 pw.println(" <USER_ID> the user id under which the package is installed. If --user is not");
1815 pw.println(" specified, the current user is assumed.");
1816 }
1817
1818 static int onShellCommand(Shell shell, String cmd) {
1819 if (cmd == null) {
1820 return shell.handleDefaultCommands(cmd);
1821 }
1822 PrintWriter pw = shell.getOutPrintWriter();
1823 PrintWriter err = shell.getErrPrintWriter();
1824 try {
1825 switch (cmd) {
1826 case "set": {
1827 int res = shell.parseUserPackageOp(true, err);
1828 if (res < 0) {
1829 return res;
1830 }
1831 String modeStr = shell.getNextArg();
1832 if (modeStr == null) {
1833 err.println("Error: Mode not specified.");
1834 return -1;
1835 }
1836
Dianne Hackborne91f3e72016-03-25 18:48:15 -07001837 final int mode = shell.strModeToMode(modeStr, err);
1838 if (mode < 0) {
1839 return -1;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001840 }
1841
1842 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName, mode);
1843 return 0;
1844 }
1845 case "get": {
1846 int res = shell.parseUserPackageOp(false, err);
1847 if (res < 0) {
1848 return res;
1849 }
1850
1851 List<AppOpsManager.PackageOps> ops = shell.mInterface.getOpsForPackage(
1852 shell.packageUid, shell.packageName,
1853 shell.op != AppOpsManager.OP_NONE ? new int[] {shell.op} : null);
1854 if (ops == null || ops.size() <= 0) {
1855 pw.println("No operations.");
1856 return 0;
1857 }
1858 final long now = System.currentTimeMillis();
1859 for (int i=0; i<ops.size(); i++) {
1860 List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
1861 for (int j=0; j<entries.size(); j++) {
1862 AppOpsManager.OpEntry ent = entries.get(j);
1863 pw.print(AppOpsManager.opToName(ent.getOp()));
1864 pw.print(": ");
1865 switch (ent.getMode()) {
1866 case AppOpsManager.MODE_ALLOWED:
1867 pw.print("allow");
1868 break;
1869 case AppOpsManager.MODE_IGNORED:
1870 pw.print("ignore");
1871 break;
1872 case AppOpsManager.MODE_ERRORED:
1873 pw.print("deny");
1874 break;
1875 case AppOpsManager.MODE_DEFAULT:
1876 pw.print("default");
1877 break;
1878 default:
1879 pw.print("mode=");
1880 pw.print(ent.getMode());
1881 break;
1882 }
1883 if (ent.getTime() != 0) {
1884 pw.print("; time=");
1885 TimeUtils.formatDuration(now - ent.getTime(), pw);
1886 pw.print(" ago");
1887 }
1888 if (ent.getRejectTime() != 0) {
1889 pw.print("; rejectTime=");
1890 TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
1891 pw.print(" ago");
1892 }
1893 if (ent.getDuration() == -1) {
1894 pw.print(" (running)");
1895 } else if (ent.getDuration() != 0) {
1896 pw.print("; duration=");
1897 TimeUtils.formatDuration(ent.getDuration(), pw);
1898 }
1899 pw.println();
1900 }
1901 }
1902 return 0;
1903 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07001904 case "query-op": {
1905 int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
1906 if (res < 0) {
1907 return res;
1908 }
1909 List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
1910 new int[] {shell.op});
1911 if (ops == null || ops.size() <= 0) {
1912 pw.println("No operations.");
1913 return 0;
1914 }
1915 for (int i=0; i<ops.size(); i++) {
1916 final AppOpsManager.PackageOps pkg = ops.get(i);
1917 boolean hasMatch = false;
1918 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
1919 for (int j=0; j<entries.size(); j++) {
1920 AppOpsManager.OpEntry ent = entries.get(j);
1921 if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
1922 hasMatch = true;
1923 break;
1924 }
1925 }
1926 if (hasMatch) {
1927 pw.println(pkg.getPackageName());
1928 }
1929 }
1930 return 0;
1931 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001932 case "reset": {
1933 String packageName = null;
1934 int userId = UserHandle.USER_CURRENT;
1935 for (String argument; (argument = shell.getNextArg()) != null;) {
1936 if ("--user".equals(argument)) {
1937 String userStr = shell.getNextArgRequired();
1938 userId = UserHandle.parseUserArg(userStr);
1939 } else {
1940 if (packageName == null) {
1941 packageName = argument;
1942 } else {
1943 err.println("Error: Unsupported argument: " + argument);
1944 return -1;
1945 }
1946 }
1947 }
1948
1949 if (userId == UserHandle.USER_CURRENT) {
1950 userId = ActivityManager.getCurrentUser();
1951 }
1952
1953 shell.mInterface.resetAllModes(userId, packageName);
1954 pw.print("Reset all modes for: ");
1955 if (userId == UserHandle.USER_ALL) {
1956 pw.print("all users");
1957 } else {
1958 pw.print("user "); pw.print(userId);
1959 }
1960 pw.print(", ");
1961 if (packageName == null) {
1962 pw.println("all packages");
1963 } else {
1964 pw.print("package "); pw.println(packageName);
1965 }
1966 return 0;
1967 }
1968 case "write-settings": {
1969 shell.mInternal.mContext.enforcePermission(
1970 android.Manifest.permission.UPDATE_APP_OPS_STATS,
1971 Binder.getCallingPid(), Binder.getCallingUid(), null);
1972 long token = Binder.clearCallingIdentity();
1973 try {
1974 synchronized (shell.mInternal) {
1975 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
1976 }
1977 shell.mInternal.writeState();
1978 pw.println("Current settings written.");
1979 } finally {
1980 Binder.restoreCallingIdentity(token);
1981 }
1982 return 0;
1983 }
1984 case "read-settings": {
1985 shell.mInternal.mContext.enforcePermission(
1986 android.Manifest.permission.UPDATE_APP_OPS_STATS,
1987 Binder.getCallingPid(), Binder.getCallingUid(), null);
1988 long token = Binder.clearCallingIdentity();
1989 try {
1990 shell.mInternal.readState();
1991 pw.println("Last settings read.");
1992 } finally {
1993 Binder.restoreCallingIdentity(token);
1994 }
1995 return 0;
1996 }
1997 default:
1998 return shell.handleDefaultCommands(cmd);
1999 }
2000 } catch (RemoteException e) {
2001 pw.println("Remote exception: " + e);
2002 }
2003 return -1;
2004 }
2005
2006 private void dumpHelp(PrintWriter pw) {
2007 pw.println("AppOps service (appops) dump options:");
2008 pw.println(" none");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002009 }
2010
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002011 @Override
2012 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2013 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2014 != PackageManager.PERMISSION_GRANTED) {
2015 pw.println("Permission Denial: can't dump ApOps service from from pid="
2016 + Binder.getCallingPid()
2017 + ", uid=" + Binder.getCallingUid());
2018 return;
2019 }
2020
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002021 if (args != null) {
2022 for (int i=0; i<args.length; i++) {
2023 String arg = args[i];
2024 if ("-h".equals(arg)) {
2025 dumpHelp(pw);
2026 return;
Tim Kilbourn8f1ea832015-08-26 15:07:37 -07002027 } else if ("-a".equals(arg)) {
2028 // dump all data
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002029 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
2030 pw.println("Unknown option: " + arg);
2031 return;
2032 } else {
2033 pw.println("Unknown command: " + arg);
2034 return;
2035 }
2036 }
2037 }
2038
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002039 synchronized (this) {
2040 pw.println("Current AppOps Service state:");
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002041 final long now = System.currentTimeMillis();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002042 boolean needSep = false;
2043 if (mOpModeWatchers.size() > 0) {
2044 needSep = true;
2045 pw.println(" Op mode watchers:");
2046 for (int i=0; i<mOpModeWatchers.size(); i++) {
2047 pw.print(" Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
2048 pw.println(":");
2049 ArrayList<Callback> callbacks = mOpModeWatchers.valueAt(i);
2050 for (int j=0; j<callbacks.size(); j++) {
2051 pw.print(" #"); pw.print(j); pw.print(": ");
2052 pw.println(callbacks.get(j));
2053 }
2054 }
2055 }
2056 if (mPackageModeWatchers.size() > 0) {
2057 needSep = true;
2058 pw.println(" Package mode watchers:");
2059 for (int i=0; i<mPackageModeWatchers.size(); i++) {
2060 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
2061 pw.println(":");
2062 ArrayList<Callback> callbacks = mPackageModeWatchers.valueAt(i);
2063 for (int j=0; j<callbacks.size(); j++) {
2064 pw.print(" #"); pw.print(j); pw.print(": ");
2065 pw.println(callbacks.get(j));
2066 }
2067 }
2068 }
2069 if (mModeWatchers.size() > 0) {
2070 needSep = true;
2071 pw.println(" All mode watchers:");
2072 for (int i=0; i<mModeWatchers.size(); i++) {
2073 pw.print(" "); pw.print(mModeWatchers.keyAt(i));
2074 pw.print(" -> "); pw.println(mModeWatchers.valueAt(i));
2075 }
2076 }
2077 if (mClients.size() > 0) {
2078 needSep = true;
2079 pw.println(" Clients:");
2080 for (int i=0; i<mClients.size(); i++) {
2081 pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
2082 ClientState cs = mClients.valueAt(i);
2083 pw.print(" "); pw.println(cs);
2084 if (cs.mStartedOps != null && cs.mStartedOps.size() > 0) {
2085 pw.println(" Started ops:");
2086 for (int j=0; j<cs.mStartedOps.size(); j++) {
2087 Op op = cs.mStartedOps.get(j);
2088 pw.print(" "); pw.print("uid="); pw.print(op.uid);
2089 pw.print(" pkg="); pw.print(op.packageName);
2090 pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
2091 }
2092 }
2093 }
2094 }
John Spurlock1af30c72014-03-10 08:33:35 -04002095 if (mAudioRestrictions.size() > 0) {
2096 boolean printedHeader = false;
2097 for (int o=0; o<mAudioRestrictions.size(); o++) {
2098 final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
2099 final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
2100 for (int i=0; i<restrictions.size(); i++) {
2101 if (!printedHeader){
2102 pw.println(" Audio Restrictions:");
2103 printedHeader = true;
2104 needSep = true;
2105 }
John Spurlock7b414672014-07-18 13:02:39 -04002106 final int usage = restrictions.keyAt(i);
John Spurlock1af30c72014-03-10 08:33:35 -04002107 pw.print(" "); pw.print(op);
John Spurlock7b414672014-07-18 13:02:39 -04002108 pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
John Spurlock1af30c72014-03-10 08:33:35 -04002109 Restriction r = restrictions.valueAt(i);
2110 pw.print(": mode="); pw.println(r.mode);
2111 if (!r.exceptionPackages.isEmpty()) {
2112 pw.println(" Exceptions:");
2113 for (int j=0; j<r.exceptionPackages.size(); j++) {
2114 pw.print(" "); pw.println(r.exceptionPackages.valueAt(j));
2115 }
2116 }
2117 }
2118 }
2119 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002120 if (needSep) {
2121 pw.println();
2122 }
Svet Ganov2af57082015-07-30 08:44:20 -07002123 for (int i=0; i<mUidStates.size(); i++) {
2124 UidState uidState = mUidStates.valueAt(i);
2125
2126 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
Svet Ganovee438d42017-01-19 18:04:38 -08002127 needSep = true;
Svet Ganov2af57082015-07-30 08:44:20 -07002128
2129 SparseIntArray opModes = uidState.opModes;
2130 if (opModes != null) {
2131 final int opModeCount = opModes.size();
2132 for (int j = 0; j < opModeCount; j++) {
2133 final int code = opModes.keyAt(j);
2134 final int mode = opModes.valueAt(j);
2135 pw.print(" "); pw.print(AppOpsManager.opToName(code));
2136 pw.print(": mode="); pw.println(mode);
2137 }
2138 }
2139
2140 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
2141 if (pkgOps == null) {
2142 continue;
2143 }
2144
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002145 for (Ops ops : pkgOps.values()) {
2146 pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
2147 for (int j=0; j<ops.size(); j++) {
2148 Op op = ops.valueAt(j);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002149 pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
2150 pw.print(": mode="); pw.print(op.mode);
2151 if (op.time != 0) {
2152 pw.print("; time="); TimeUtils.formatDuration(now-op.time, pw);
2153 pw.print(" ago");
2154 }
2155 if (op.rejectTime != 0) {
2156 pw.print("; rejectTime="); TimeUtils.formatDuration(now-op.rejectTime, pw);
2157 pw.print(" ago");
2158 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002159 if (op.duration == -1) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002160 pw.print(" (running)");
2161 } else if (op.duration != 0) {
2162 pw.print("; duration="); TimeUtils.formatDuration(op.duration, pw);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002163 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002164 pw.println();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002165 }
2166 }
2167 }
Svet Ganovee438d42017-01-19 18:04:38 -08002168 if (needSep) {
2169 pw.println();
2170 }
2171
2172 final int userRestrictionCount = mOpUserRestrictions.size();
2173 for (int i = 0; i < userRestrictionCount; i++) {
2174 IBinder token = mOpUserRestrictions.keyAt(i);
2175 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
2176 pw.println(" User restrictions for token " + token + ":");
2177
2178 final int restrictionCount = restrictionState.perUserRestrictions != null
2179 ? restrictionState.perUserRestrictions.size() : 0;
2180 if (restrictionCount > 0) {
2181 pw.println(" Restricted ops:");
2182 for (int j = 0; j < restrictionCount; j++) {
2183 int userId = restrictionState.perUserRestrictions.keyAt(j);
2184 boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
2185 if (restrictedOps == null) {
2186 continue;
2187 }
2188 StringBuilder restrictedOpsValue = new StringBuilder();
2189 restrictedOpsValue.append("[");
2190 final int restrictedOpCount = restrictedOps.length;
2191 for (int k = 0; k < restrictedOpCount; k++) {
2192 if (restrictedOps[k]) {
2193 if (restrictedOpsValue.length() > 1) {
2194 restrictedOpsValue.append(", ");
2195 }
2196 restrictedOpsValue.append(AppOpsManager.opToName(k));
2197 }
2198 }
2199 restrictedOpsValue.append("]");
2200 pw.print(" "); pw.print("user: "); pw.print(userId);
2201 pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
2202 }
2203 }
2204
2205 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
2206 ? restrictionState.perUserExcludedPackages.size() : 0;
2207 if (excludedPackageCount > 0) {
2208 pw.println(" Excluded packages:");
2209 for (int j = 0; j < excludedPackageCount; j++) {
2210 int userId = restrictionState.perUserExcludedPackages.keyAt(j);
2211 String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
2212 pw.print(" "); pw.print("user: "); pw.print(userId);
2213 pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
2214 }
2215 }
2216 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002217 }
2218 }
John Spurlock1af30c72014-03-10 08:33:35 -04002219
2220 private static final class Restriction {
2221 private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
2222 int mode;
2223 ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
2224 }
Jason Monk62062992014-05-06 09:55:28 -04002225
2226 @Override
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002227 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
Jason Monk62062992014-05-06 09:55:28 -04002228 checkSystemUid("setUserRestrictions");
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002229 Preconditions.checkNotNull(restrictions);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002230 Preconditions.checkNotNull(token);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002231 for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
Jason Monk62062992014-05-06 09:55:28 -04002232 String restriction = AppOpsManager.opToRestriction(i);
Suprabh Shukla64e0dcb2016-05-24 16:23:11 -07002233 if (restriction != null) {
2234 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
2235 userHandle, null);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002236 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002237 }
2238 }
2239
2240 @Override
Ruben Brunk29931bc2016-03-11 00:24:26 -08002241 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
2242 String[] exceptionPackages) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002243 if (Binder.getCallingPid() != Process.myPid()) {
2244 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
2245 Binder.getCallingPid(), Binder.getCallingUid(), null);
2246 }
2247 if (userHandle != UserHandle.getCallingUserId()) {
2248 if (mContext.checkCallingOrSelfPermission(Manifest.permission
2249 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
2250 && mContext.checkCallingOrSelfPermission(Manifest.permission
2251 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
2252 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
2253 + " INTERACT_ACROSS_USERS to interact cross user ");
Jason Monk62062992014-05-06 09:55:28 -04002254 }
2255 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002256 verifyIncomingOp(code);
2257 Preconditions.checkNotNull(token);
Ruben Brunk29931bc2016-03-11 00:24:26 -08002258 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002259 }
2260
2261 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
Ruben Brunk29931bc2016-03-11 00:24:26 -08002262 int userHandle, String[] exceptionPackages) {
Svet Ganov442ed572016-08-17 17:29:43 -07002263 boolean notifyChange = false;
Ruben Brunk29931bc2016-03-11 00:24:26 -08002264
Svet Ganov442ed572016-08-17 17:29:43 -07002265 synchronized (AppOpsService.this) {
2266 ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
2267
2268 if (restrictionState == null) {
2269 try {
2270 restrictionState = new ClientRestrictionState(token);
2271 } catch (RemoteException e) {
2272 return;
2273 }
2274 mOpUserRestrictions.put(token, restrictionState);
Ruben Brunk29931bc2016-03-11 00:24:26 -08002275 }
Svet Ganov442ed572016-08-17 17:29:43 -07002276
2277 if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
2278 notifyChange = true;
2279 }
2280
2281 if (restrictionState.isDefault()) {
2282 mOpUserRestrictions.remove(token);
2283 restrictionState.destroy();
2284 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08002285 }
2286
Svet Ganov442ed572016-08-17 17:29:43 -07002287 if (notifyChange) {
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002288 notifyWatchersOfChange(code);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002289 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -04002290 }
2291
2292 private void notifyWatchersOfChange(int code) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002293 final ArrayList<Callback> clonedCallbacks;
2294 synchronized (this) {
2295 ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
2296 if (callbacks == null) {
2297 return;
2298 }
2299 clonedCallbacks = new ArrayList<>(callbacks);
2300 }
2301
2302 // There are components watching for mode changes such as window manager
2303 // and location manager which are in our process. The callbacks in these
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002304 // components may require permissions our remote caller does not have.s
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002305 final long identity = Binder.clearCallingIdentity();
2306 try {
2307 final int callbackCount = clonedCallbacks.size();
2308 for (int i = 0; i < callbackCount; i++) {
2309 Callback callback = clonedCallbacks.get(i);
2310 try {
2311 callback.mCallback.opChanged(code, -1, null);
2312 } catch (RemoteException e) {
2313 Log.w(TAG, "Error dispatching op op change", e);
2314 }
2315 }
2316 } finally {
2317 Binder.restoreCallingIdentity(identity);
2318 }
Jason Monk62062992014-05-06 09:55:28 -04002319 }
2320
2321 @Override
2322 public void removeUser(int userHandle) throws RemoteException {
2323 checkSystemUid("removeUser");
Svet Ganov442ed572016-08-17 17:29:43 -07002324 synchronized (AppOpsService.this) {
2325 final int tokenCount = mOpUserRestrictions.size();
2326 for (int i = tokenCount - 1; i >= 0; i--) {
2327 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
2328 opRestrictions.removeUser(userHandle);
2329 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07002330 removeUidsForUserLocked(userHandle);
2331 }
2332 }
2333
2334 private void removeUidsForUserLocked(int userHandle) {
2335 for (int i = mUidStates.size() - 1; i >= 0; --i) {
2336 final int uid = mUidStates.keyAt(i);
2337 if (UserHandle.getUserId(uid) == userHandle) {
2338 mUidStates.removeAt(i);
2339 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002340 }
2341 }
2342
Jason Monk62062992014-05-06 09:55:28 -04002343 private void checkSystemUid(String function) {
2344 int uid = Binder.getCallingUid();
2345 if (uid != Process.SYSTEM_UID) {
2346 throw new SecurityException(function + " must by called by the system");
2347 }
2348 }
2349
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002350 private static String resolvePackageName(int uid, String packageName) {
2351 if (uid == 0) {
2352 return "root";
2353 } else if (uid == Process.SHELL_UID) {
2354 return "com.android.shell";
2355 } else if (uid == Process.SYSTEM_UID && packageName == null) {
2356 return "android";
2357 }
2358 return packageName;
2359 }
2360
Svet Ganov2af57082015-07-30 08:44:20 -07002361 private static String[] getPackagesForUid(int uid) {
Svet Ganovf3807aa2015-08-02 10:09:56 -07002362 String[] packageNames = null;
Svet Ganov2af57082015-07-30 08:44:20 -07002363 try {
riddle_hsu40b300f2015-11-23 13:22:03 +08002364 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
Svet Ganov2af57082015-07-30 08:44:20 -07002365 } catch (RemoteException e) {
2366 /* ignore - local call */
2367 }
Svet Ganovf3807aa2015-08-02 10:09:56 -07002368 if (packageNames == null) {
2369 return EmptyArray.STRING;
2370 }
2371 return packageNames;
Svet Ganov2af57082015-07-30 08:44:20 -07002372 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002373
2374 private final class ClientRestrictionState implements DeathRecipient {
2375 private final IBinder token;
2376 SparseArray<boolean[]> perUserRestrictions;
2377 SparseArray<String[]> perUserExcludedPackages;
2378
2379 public ClientRestrictionState(IBinder token)
2380 throws RemoteException {
2381 token.linkToDeath(this, 0);
2382 this.token = token;
2383 }
2384
2385 public boolean setRestriction(int code, boolean restricted,
2386 String[] excludedPackages, int userId) {
2387 boolean changed = false;
2388
2389 if (perUserRestrictions == null && restricted) {
2390 perUserRestrictions = new SparseArray<>();
2391 }
2392
2393 if (perUserRestrictions != null) {
2394 boolean[] userRestrictions = perUserRestrictions.get(userId);
2395 if (userRestrictions == null && restricted) {
2396 userRestrictions = new boolean[AppOpsManager._NUM_OP];
2397 perUserRestrictions.put(userId, userRestrictions);
2398 }
2399 if (userRestrictions != null && userRestrictions[code] != restricted) {
2400 userRestrictions[code] = restricted;
2401 if (!restricted && isDefault(userRestrictions)) {
2402 perUserRestrictions.remove(userId);
2403 userRestrictions = null;
2404 }
2405 changed = true;
2406 }
2407
2408 if (userRestrictions != null) {
2409 final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
2410 if (perUserExcludedPackages == null && !noExcludedPackages) {
2411 perUserExcludedPackages = new SparseArray<>();
2412 }
2413 if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
2414 perUserExcludedPackages.get(userId))) {
2415 if (noExcludedPackages) {
2416 perUserExcludedPackages.remove(userId);
2417 if (perUserExcludedPackages.size() <= 0) {
2418 perUserExcludedPackages = null;
2419 }
2420 } else {
2421 perUserExcludedPackages.put(userId, excludedPackages);
2422 }
2423 changed = true;
2424 }
2425 }
2426 }
2427
2428 return changed;
2429 }
2430
2431 public boolean hasRestriction(int restriction, String packageName, int userId) {
2432 if (perUserRestrictions == null) {
2433 return false;
2434 }
2435 boolean[] restrictions = perUserRestrictions.get(userId);
2436 if (restrictions == null) {
2437 return false;
2438 }
2439 if (!restrictions[restriction]) {
2440 return false;
2441 }
2442 if (perUserExcludedPackages == null) {
2443 return true;
2444 }
2445 String[] perUserExclusions = perUserExcludedPackages.get(userId);
2446 if (perUserExclusions == null) {
2447 return true;
2448 }
2449 return !ArrayUtils.contains(perUserExclusions, packageName);
2450 }
2451
2452 public void removeUser(int userId) {
2453 if (perUserExcludedPackages != null) {
2454 perUserExcludedPackages.remove(userId);
2455 if (perUserExcludedPackages.size() <= 0) {
2456 perUserExcludedPackages = null;
2457 }
2458 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07002459 if (perUserRestrictions != null) {
2460 perUserRestrictions.remove(userId);
2461 if (perUserRestrictions.size() <= 0) {
2462 perUserRestrictions = null;
2463 }
2464 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002465 }
2466
2467 public boolean isDefault() {
2468 return perUserRestrictions == null || perUserRestrictions.size() <= 0;
2469 }
2470
2471 @Override
2472 public void binderDied() {
2473 synchronized (AppOpsService.this) {
2474 mOpUserRestrictions.remove(token);
2475 if (perUserRestrictions == null) {
2476 return;
2477 }
2478 final int userCount = perUserRestrictions.size();
2479 for (int i = 0; i < userCount; i++) {
2480 final boolean[] restrictions = perUserRestrictions.valueAt(i);
2481 final int restrictionCount = restrictions.length;
2482 for (int j = 0; j < restrictionCount; j++) {
2483 if (restrictions[j]) {
2484 final int changedCode = j;
2485 mHandler.post(() -> notifyWatchersOfChange(changedCode));
2486 }
2487 }
2488 }
2489 destroy();
2490 }
2491 }
2492
2493 public void destroy() {
2494 token.unlinkToDeath(this, 0);
2495 }
2496
2497 private boolean isDefault(boolean[] array) {
2498 if (ArrayUtils.isEmpty(array)) {
2499 return true;
2500 }
2501 for (boolean value : array) {
2502 if (value) {
2503 return false;
2504 }
2505 }
2506 return true;
2507 }
2508 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002509}