blob: d818bd6580f7ea81749a50275dcd941298d30fbb [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
Philip P. Moltmanne683f192017-06-23 14:05:04 -070019import android.Manifest;
20import android.app.ActivityManager;
21import android.app.ActivityThread;
22import android.app.AppGlobals;
23import android.app.AppOpsManager;
24import android.content.Context;
25import android.content.pm.ApplicationInfo;
26import android.content.pm.IPackageManager;
27import android.content.pm.PackageManager;
28import android.content.pm.PackageManagerInternal;
29import android.content.pm.UserInfo;
30import android.media.AudioAttributes;
31import android.os.AsyncTask;
32import android.os.Binder;
33import android.os.Bundle;
34import android.os.Handler;
35import android.os.IBinder;
36import android.os.Process;
37import android.os.RemoteException;
38import android.os.ResultReceiver;
39import android.os.ServiceManager;
40import android.os.ShellCallback;
41import android.os.ShellCommand;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070042import android.os.SystemClock;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070043import android.os.UserHandle;
44import android.os.UserManager;
45import android.os.storage.StorageManagerInternal;
46import android.util.ArrayMap;
47import android.util.ArraySet;
48import android.util.AtomicFile;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070049import android.util.Slog;
50import android.util.SparseArray;
51import android.util.SparseIntArray;
52import android.util.TimeUtils;
53import android.util.Xml;
54
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070055import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080056import com.android.internal.app.IAppOpsActiveCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070057import com.android.internal.app.IAppOpsCallback;
58import com.android.internal.app.IAppOpsService;
59import com.android.internal.os.Zygote;
60import com.android.internal.util.ArrayUtils;
61import com.android.internal.util.DumpUtils;
62import com.android.internal.util.FastXmlSerializer;
63import com.android.internal.util.Preconditions;
64import com.android.internal.util.XmlUtils;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080065import com.android.internal.util.function.pooled.PooledLambda;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -050066
Philip P. Moltmanne683f192017-06-23 14:05:04 -070067import libcore.util.EmptyArray;
68
69import org.xmlpull.v1.XmlPullParser;
70import org.xmlpull.v1.XmlPullParserException;
71import org.xmlpull.v1.XmlSerializer;
72
Dianne Hackborna06de0f2012-12-11 16:34:47 -080073import java.io.File;
74import java.io.FileDescriptor;
Dianne Hackborn35654b62013-01-14 17:38:02 -080075import java.io.FileInputStream;
76import java.io.FileNotFoundException;
77import java.io.FileOutputStream;
78import java.io.IOException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080079import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +010080import java.nio.charset.StandardCharsets;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070081import java.text.SimpleDateFormat;
Dianne Hackborn35654b62013-01-14 17:38:02 -080082import java.util.ArrayList;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -070083import java.util.Arrays;
Svetoslav215b44a2015-08-04 19:03:40 -070084import java.util.Collections;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070085import java.util.Date;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080086import java.util.HashMap;
Dianne Hackbornc2293022013-02-06 23:14:49 -080087import java.util.Iterator;
Dianne Hackborn35654b62013-01-14 17:38:02 -080088import java.util.List;
Dianne Hackborn607b4142013-08-02 18:10:10 -070089import java.util.Map;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080090
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070091import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
92import static android.app.AppOpsManager.UID_STATE_CACHED;
93import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
94import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
95import static android.app.AppOpsManager._NUM_UID_STATE;
96import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
97import static android.app.AppOpsManager.UID_STATE_TOP;
98
Dianne Hackborna06de0f2012-12-11 16:34:47 -080099public class AppOpsService extends IAppOpsService.Stub {
100 static final String TAG = "AppOps";
Dianne Hackborn35654b62013-01-14 17:38:02 -0800101 static final boolean DEBUG = false;
102
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700103 private static final int NO_VERSION = -1;
104 /** Increment by one every time and add the corresponding upgrade logic in
105 * {@link #upgradeLocked(int)} below. The first version was 1 */
106 private static final int CURRENT_VERSION = 1;
107
Dianne Hackborn35654b62013-01-14 17:38:02 -0800108 // Write at most every 30 minutes.
109 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800110
Svet Ganov3a95f832018-03-23 17:44:30 -0700111 // Constant meaning that any UID should be matched when dispatching callbacks
112 private static final int UID_ANY = -2;
113
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700114 // Map from process states to the uid states we track.
115 private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
116 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
117 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
118 UID_STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
119 UID_STATE_FOREGROUND_SERVICE, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
120 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
121 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
122 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
123 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
124 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_BACKUP
125 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_SERVICE
126 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_RECEIVER
127 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
128 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
129 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HOME
130 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
131 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
132 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
133 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_RECENT
134 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
135 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT
136 };
137
138 static final String[] UID_STATE_NAMES = new String[] {
139 "pers ", // UID_STATE_PERSISTENT
140 "top ", // UID_STATE_TOP
141 "fgsvc", // UID_STATE_FOREGROUND_SERVICE
142 "fg ", // UID_STATE_FOREGROUND
143 "bg ", // UID_STATE_BACKGROUND
144 "cch ", // UID_STATE_CACHED
145 };
146
147 static final String[] UID_STATE_TIME_ATTRS = new String[] {
148 "tp", // UID_STATE_PERSISTENT
149 "tt", // UID_STATE_TOP
150 "tfs", // UID_STATE_FOREGROUND_SERVICE
151 "tf", // UID_STATE_FOREGROUND
152 "tb", // UID_STATE_BACKGROUND
153 "tc", // UID_STATE_CACHED
154 };
155
156 static final String[] UID_STATE_REJECT_ATTRS = new String[] {
157 "rp", // UID_STATE_PERSISTENT
158 "rt", // UID_STATE_TOP
159 "rfs", // UID_STATE_FOREGROUND_SERVICE
160 "rf", // UID_STATE_FOREGROUND
161 "rb", // UID_STATE_BACKGROUND
162 "rc", // UID_STATE_CACHED
163 };
164
165 static final String[] MODE_NAMES = new String[] {
166 "allow", // MODE_ALLOWED
167 "ignore", // MODE_IGNORED
168 "deny", // MODE_ERRORED
169 "default", // MODE_DEFAULT
170 };
171
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800172 Context mContext;
173 final AtomicFile mFile;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800174 final Handler mHandler;
175
176 boolean mWriteScheduled;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800177 boolean mFastWriteScheduled;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800178 final Runnable mWriteRunner = new Runnable() {
179 public void run() {
180 synchronized (AppOpsService.this) {
181 mWriteScheduled = false;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800182 mFastWriteScheduled = false;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800183 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
184 @Override protected Void doInBackground(Void... params) {
185 writeState();
186 return null;
187 }
188 };
189 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
190 }
191 }
192 };
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800193
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700194 @VisibleForTesting
195 final SparseArray<UidState> mUidStates = new SparseArray<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800196
Ruben Brunk29931bc2016-03-11 00:24:26 -0800197 /*
198 * These are app op restrictions imposed per user from various parties.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800199 */
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700200 private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
Jason Monk62062992014-05-06 09:55:28 -0400201
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700202 @VisibleForTesting
203 static final class UidState {
Svet Ganov2af57082015-07-30 08:44:20 -0700204 public final int uid;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700205 public int state = UID_STATE_CACHED;
206 public int startNesting;
Svet Ganov2af57082015-07-30 08:44:20 -0700207 public ArrayMap<String, Ops> pkgOps;
208 public SparseIntArray opModes;
209
210 public UidState(int uid) {
211 this.uid = uid;
212 }
213
214 public void clear() {
215 pkgOps = null;
216 opModes = null;
217 }
218
219 public boolean isDefault() {
220 return (pkgOps == null || pkgOps.isEmpty())
221 && (opModes == null || opModes.size() <= 0);
222 }
223 }
224
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700225 final static class Ops extends SparseArray<Op> {
226 final String packageName;
227 final UidState uidState;
228 final boolean isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800229
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700230 Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800231 packageName = _packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700232 uidState = _uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400233 isPrivileged = _isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800234 }
235 }
236
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700237 final static class Op {
238 final UidState uidState;
239 final int uid;
240 final String packageName;
241 final int op;
242 int proxyUid = -1;
243 String proxyPackageName;
244 int mode;
245 int duration;
246 long time[] = new long[_NUM_UID_STATE];
247 long rejectTime[] = new long[_NUM_UID_STATE];
248 int startNesting;
249 long startRealtime;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800250
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700251 Op(UidState _uidState, String _packageName, int _op) {
252 uidState = _uidState;
253 uid = _uidState.uid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700254 packageName = _packageName;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800255 op = _op;
David Braunf5d83192013-09-16 13:43:51 -0700256 mode = AppOpsManager.opToDefaultMode(op);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800257 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700258
259 boolean hasAnyTime() {
260 for (int i = 0; i < AppOpsManager._NUM_UID_STATE; i++) {
261 if (time[i] != 0) {
262 return true;
263 }
264 if (rejectTime[i] != 0) {
265 return true;
266 }
267 }
268 return false;
269 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800270 }
271
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800272 final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
273 final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
274 final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
275 final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
Dianne Hackborn68d76552017-02-27 15:32:03 -0800276 final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800277
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700278 final class ModeCallback implements DeathRecipient {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800279 final IAppOpsCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700280 final int mWatchingUid;
281 final int mCallingUid;
282 final int mCallingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800283
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700284 ModeCallback(IAppOpsCallback callback, int watchingUid, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700285 int callingPid) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800286 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700287 mWatchingUid = watchingUid;
288 mCallingUid = callingUid;
289 mCallingPid = callingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800290 try {
291 mCallback.asBinder().linkToDeath(this, 0);
292 } catch (RemoteException e) {
293 }
294 }
295
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700296 @Override
297 public String toString() {
298 StringBuilder sb = new StringBuilder(128);
299 sb.append("ModeCallback{");
300 sb.append(Integer.toHexString(System.identityHashCode(this)));
301 sb.append(" watchinguid=");
302 UserHandle.formatUid(sb, mWatchingUid);
303 sb.append(" from uid=");
304 UserHandle.formatUid(sb, mCallingUid);
305 sb.append(" pid=");
306 sb.append(mCallingPid);
307 sb.append('}');
308 return sb.toString();
309 }
310
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700311 void unlinkToDeath() {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800312 mCallback.asBinder().unlinkToDeath(this, 0);
313 }
314
315 @Override
316 public void binderDied() {
317 stopWatchingMode(mCallback);
318 }
319 }
320
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700321 final class ActiveCallback implements DeathRecipient {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800322 final IAppOpsActiveCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700323 final int mWatchingUid;
324 final int mCallingUid;
325 final int mCallingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800326
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700327 ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700328 int callingPid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800329 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700330 mWatchingUid = watchingUid;
331 mCallingUid = callingUid;
332 mCallingPid = callingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800333 try {
334 mCallback.asBinder().linkToDeath(this, 0);
335 } catch (RemoteException e) {
336 }
337 }
338
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700339 @Override
340 public String toString() {
341 StringBuilder sb = new StringBuilder(128);
342 sb.append("ActiveCallback{");
343 sb.append(Integer.toHexString(System.identityHashCode(this)));
344 sb.append(" watchinguid=");
345 UserHandle.formatUid(sb, mWatchingUid);
346 sb.append(" from uid=");
347 UserHandle.formatUid(sb, mCallingUid);
348 sb.append(" pid=");
349 sb.append(mCallingPid);
350 sb.append('}');
351 return sb.toString();
352 }
353
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700354 void destroy() {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800355 mCallback.asBinder().unlinkToDeath(this, 0);
356 }
357
358 @Override
359 public void binderDied() {
360 stopWatchingActive(mCallback);
361 }
362 }
363
Svet Ganova7a0db62018-02-27 20:08:01 -0800364 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700365
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700366 final class ClientState extends Binder implements DeathRecipient {
Svet Ganovf7b47252018-02-26 11:11:27 -0800367 final ArrayList<Op> mStartedOps = new ArrayList<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700368 final IBinder mAppToken;
369 final int mPid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700370
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700371 ClientState(IBinder appToken) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700372 mAppToken = appToken;
373 mPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -0800374 // Watch only for remote processes dying
375 if (!(appToken instanceof Binder)) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700376 try {
377 mAppToken.linkToDeath(this, 0);
378 } catch (RemoteException e) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800379 /* do nothing */
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700380 }
381 }
382 }
383
384 @Override
385 public String toString() {
386 return "ClientState{" +
387 "mAppToken=" + mAppToken +
Svet Ganovf7b47252018-02-26 11:11:27 -0800388 ", " + "pid=" + mPid +
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700389 '}';
390 }
391
392 @Override
393 public void binderDied() {
394 synchronized (AppOpsService.this) {
395 for (int i=mStartedOps.size()-1; i>=0; i--) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800396 finishOperationLocked(mStartedOps.get(i), /*finishNested*/ true);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700397 }
398 mClients.remove(mAppToken);
399 }
400 }
401 }
402
Jeff Brown6f357d32014-01-15 20:40:55 -0800403 public AppOpsService(File storagePath, Handler handler) {
Jeff Sharkey5f3e9342017-03-13 14:53:11 -0600404 LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
Dianne Hackborne17b4452018-01-10 13:15:40 -0800405 mFile = new AtomicFile(storagePath, "appops");
Jeff Brown6f357d32014-01-15 20:40:55 -0800406 mHandler = handler;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800407 readState();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800408 }
David Braunf5d83192013-09-16 13:43:51 -0700409
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800410 public void publish(Context context) {
411 mContext = context;
412 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
413 }
414
Dianne Hackborn514074f2013-02-11 10:52:46 -0800415 public void systemReady() {
416 synchronized (this) {
417 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700418 for (int i = mUidStates.size() - 1; i >= 0; i--) {
419 UidState uidState = mUidStates.valueAt(i);
420
421 String[] packageNames = getPackagesForUid(uidState.uid);
422 if (ArrayUtils.isEmpty(packageNames)) {
423 uidState.clear();
424 mUidStates.removeAt(i);
425 changed = true;
426 continue;
427 }
428
429 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
430 if (pkgs == null) {
431 continue;
432 }
433
Dianne Hackborn514074f2013-02-11 10:52:46 -0800434 Iterator<Ops> it = pkgs.values().iterator();
435 while (it.hasNext()) {
436 Ops ops = it.next();
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700437 int curUid = -1;
Dianne Hackborn514074f2013-02-11 10:52:46 -0800438 try {
Jeff Sharkeycd654482016-01-08 17:42:11 -0700439 curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
440 PackageManager.MATCH_UNINSTALLED_PACKAGES,
Svet Ganov2af57082015-07-30 08:44:20 -0700441 UserHandle.getUserId(ops.uidState.uid));
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700442 } catch (RemoteException ignored) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800443 }
Svet Ganov2af57082015-07-30 08:44:20 -0700444 if (curUid != ops.uidState.uid) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800445 Slog.i(TAG, "Pruning old package " + ops.packageName
Svet Ganov2af57082015-07-30 08:44:20 -0700446 + "/" + ops.uidState + ": new uid=" + curUid);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800447 it.remove();
448 changed = true;
449 }
450 }
Svet Ganov2af57082015-07-30 08:44:20 -0700451
452 if (uidState.isDefault()) {
453 mUidStates.removeAt(i);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800454 }
455 }
456 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800457 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800458 }
459 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700460
Suprabh Shuklaaef25132017-01-23 18:09:03 -0800461 PackageManagerInternal packageManagerInternal = LocalServices.getService(
462 PackageManagerInternal.class);
463 packageManagerInternal.setExternalSourcesPolicy(
464 new PackageManagerInternal.ExternalSourcesPolicy() {
465 @Override
466 public int getPackageTrustedToInstallApps(String packageName, int uid) {
467 int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
468 uid, packageName);
469 switch (appOpMode) {
470 case AppOpsManager.MODE_ALLOWED:
471 return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
472 case AppOpsManager.MODE_ERRORED:
473 return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
474 default:
475 return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
476 }
477 }
478 });
479
Sudheer Shanka2250d562016-11-07 15:41:02 -0800480 StorageManagerInternal storageManagerInternal = LocalServices.getService(
481 StorageManagerInternal.class);
482 storageManagerInternal.addExternalStoragePolicy(
483 new StorageManagerInternal.ExternalStorageMountPolicy() {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700484 @Override
485 public int getMountMode(int uid, String packageName) {
486 if (Process.isIsolated(uid)) {
487 return Zygote.MOUNT_EXTERNAL_NONE;
488 }
489 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
490 packageName) != AppOpsManager.MODE_ALLOWED) {
491 return Zygote.MOUNT_EXTERNAL_NONE;
492 }
493 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
494 packageName) != AppOpsManager.MODE_ALLOWED) {
495 return Zygote.MOUNT_EXTERNAL_READ;
496 }
497 return Zygote.MOUNT_EXTERNAL_WRITE;
498 }
499
500 @Override
501 public boolean hasExternalStorage(int uid, String packageName) {
502 final int mountMode = getMountMode(uid, packageName);
503 return mountMode == Zygote.MOUNT_EXTERNAL_READ
504 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
505 }
506 });
Dianne Hackborn514074f2013-02-11 10:52:46 -0800507 }
508
509 public void packageRemoved(int uid, String packageName) {
510 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700511 UidState uidState = mUidStates.get(uid);
512 if (uidState == null) {
513 return;
514 }
515
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800516 Ops ops = null;
Svet Ganov2af57082015-07-30 08:44:20 -0700517
518 // Remove any package state if such.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800519 if (uidState.pkgOps != null) {
520 ops = uidState.pkgOps.remove(packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700521 }
522
523 // If we just nuked the last package state check if the UID is valid.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800524 if (ops != null && uidState.pkgOps.isEmpty()
Svet Ganov2af57082015-07-30 08:44:20 -0700525 && getPackagesForUid(uid).length <= 0) {
526 mUidStates.remove(uid);
527 }
528
Svet Ganova7a0db62018-02-27 20:08:01 -0800529 // Finish ops other packages started on behalf of the package.
530 final int clientCount = mClients.size();
531 for (int i = 0; i < clientCount; i++) {
532 final ClientState client = mClients.valueAt(i);
533 if (client.mStartedOps == null) {
534 continue;
535 }
536 final int opCount = client.mStartedOps.size();
537 for (int j = opCount - 1; j >= 0; j--) {
538 final Op op = client.mStartedOps.get(j);
539 if (uid == op.uid && packageName.equals(op.packageName)) {
540 finishOperationLocked(op, /*finishNested*/ true);
541 client.mStartedOps.remove(j);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700542 if (op.startNesting <= 0) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800543 scheduleOpActiveChangedIfNeededLocked(op.op,
544 uid, packageName, false);
545 }
546 }
547 }
548 }
549
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800550 if (ops != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700551 scheduleFastWriteLocked();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800552
553 final int opCount = ops.size();
554 for (int i = 0; i < opCount; i++) {
555 final Op op = ops.valueAt(i);
556 if (op.duration == -1) {
557 scheduleOpActiveChangedIfNeededLocked(
558 op.op, op.uid, op.packageName, false);
559 }
560 }
Dianne Hackborn514074f2013-02-11 10:52:46 -0800561 }
562 }
563 }
564
565 public void uidRemoved(int uid) {
566 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700567 if (mUidStates.indexOfKey(uid) >= 0) {
568 mUidStates.remove(uid);
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800569 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800570 }
571 }
572 }
573
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700574 public void updateUidProcState(int uid, int procState) {
575 synchronized (this) {
576 final UidState uidState = getUidStateLocked(uid, true);
577 final int newState = PROCESS_STATE_TO_UID_STATE[procState];
578 if (uidState != null && uidState.state != newState) {
579 if (uidState.startNesting != 0) {
580 // There is some actively running operation... need to find it
581 // and appropriately update its state.
582 final long now = System.currentTimeMillis();
583 for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
584 final Ops ops = uidState.pkgOps.valueAt(i);
585 for (int j = ops.size() - 1; j >= 0; j--) {
586 final Op op = ops.valueAt(j);
587 if (op.startNesting > 0) {
588 op.time[uidState.state] = now;
589 op.time[newState] = now;
590 }
591 }
592 }
593 }
594 uidState.state = newState;
595 }
596 }
597 }
598
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800599 public void shutdown() {
600 Slog.w(TAG, "Writing app ops before shutdown...");
Dianne Hackborn35654b62013-01-14 17:38:02 -0800601 boolean doWrite = false;
602 synchronized (this) {
603 if (mWriteScheduled) {
604 mWriteScheduled = false;
605 doWrite = true;
606 }
607 }
608 if (doWrite) {
609 writeState();
610 }
611 }
612
Dianne Hackborn72e39832013-01-18 18:36:09 -0800613 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
614 ArrayList<AppOpsManager.OpEntry> resOps = null;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700615 final long elapsedNow = SystemClock.elapsedRealtime();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800616 if (ops == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700617 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800618 for (int j=0; j<pkgOps.size(); j++) {
619 Op curOp = pkgOps.valueAt(j);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700620 long duration = curOp.duration == -1
621 ? (elapsedNow - curOp.startRealtime)
622 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800623 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700624 curOp.rejectTime, (int) duration, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700625 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800626 }
627 } else {
628 for (int j=0; j<ops.length; j++) {
629 Op curOp = pkgOps.get(ops[j]);
630 if (curOp != null) {
631 if (resOps == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700632 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800633 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700634 long duration = curOp.duration == -1
635 ? (elapsedNow - curOp.startRealtime)
636 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800637 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700638 curOp.rejectTime, (int) duration, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700639 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800640 }
641 }
642 }
643 return resOps;
644 }
645
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700646 private ArrayList<AppOpsManager.OpEntry> collectOps(SparseIntArray uidOps, int[] ops) {
647 ArrayList<AppOpsManager.OpEntry> resOps = null;
648 if (ops == null) {
649 resOps = new ArrayList<>();
650 for (int j=0; j<uidOps.size(); j++) {
651 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(j), uidOps.valueAt(j),
652 0, 0, 0, -1, null));
653 }
654 } else {
655 for (int j=0; j<ops.length; j++) {
656 int index = uidOps.indexOfKey(ops[j]);
657 if (index >= 0) {
658 if (resOps == null) {
659 resOps = new ArrayList<>();
660 }
661 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(index), uidOps.valueAt(index),
662 0, 0, 0, -1, null));
663 }
664 }
665 }
666 return resOps;
667 }
668
Dianne Hackborn35654b62013-01-14 17:38:02 -0800669 @Override
670 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
671 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
672 Binder.getCallingPid(), Binder.getCallingUid(), null);
673 ArrayList<AppOpsManager.PackageOps> res = null;
674 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700675 final int uidStateCount = mUidStates.size();
676 for (int i = 0; i < uidStateCount; i++) {
677 UidState uidState = mUidStates.valueAt(i);
678 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
679 continue;
680 }
681 ArrayMap<String, Ops> packages = uidState.pkgOps;
682 final int packageCount = packages.size();
683 for (int j = 0; j < packageCount; j++) {
684 Ops pkgOps = packages.valueAt(j);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800685 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800686 if (resOps != null) {
687 if (res == null) {
688 res = new ArrayList<AppOpsManager.PackageOps>();
689 }
690 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700691 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800692 res.add(resPackage);
693 }
694 }
695 }
696 }
697 return res;
698 }
699
700 @Override
Dianne Hackborn72e39832013-01-18 18:36:09 -0800701 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
702 int[] ops) {
703 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
704 Binder.getCallingPid(), Binder.getCallingUid(), null);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000705 String resolvedPackageName = resolvePackageName(uid, packageName);
706 if (resolvedPackageName == null) {
707 return Collections.emptyList();
708 }
Dianne Hackborn72e39832013-01-18 18:36:09 -0800709 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -0700710 Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
711 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800712 if (pkgOps == null) {
713 return null;
714 }
715 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
716 if (resOps == null) {
717 return null;
718 }
719 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
720 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700721 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800722 res.add(resPackage);
723 return res;
724 }
725 }
726
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700727 @Override
728 public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
729 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
730 Binder.getCallingPid(), Binder.getCallingUid(), null);
731 synchronized (this) {
732 UidState uidState = getUidStateLocked(uid, false);
733 if (uidState == null) {
734 return null;
735 }
736 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState.opModes, ops);
737 if (resOps == null) {
738 return null;
739 }
740 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
741 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
742 null, uidState.uid, resOps);
743 res.add(resPackage);
744 return res;
745 }
746 }
747
Dianne Hackborn607b4142013-08-02 18:10:10 -0700748 private void pruneOp(Op op, int uid, String packageName) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700749 if (!op.hasAnyTime()) {
Yohei Yukawaa965d652017-10-12 15:02:26 -0700750 Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
751 false /* uidMismatchExpected */);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700752 if (ops != null) {
753 ops.remove(op.op);
754 if (ops.size() <= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -0700755 UidState uidState = ops.uidState;
756 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700757 if (pkgOps != null) {
758 pkgOps.remove(ops.packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700759 if (pkgOps.isEmpty()) {
760 uidState.pkgOps = null;
761 }
762 if (uidState.isDefault()) {
763 mUidStates.remove(uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700764 }
765 }
766 }
767 }
768 }
769 }
770
Dianne Hackborn72e39832013-01-18 18:36:09 -0800771 @Override
Svet Ganov2af57082015-07-30 08:44:20 -0700772 public void setUidMode(int code, int uid, int mode) {
773 if (Binder.getCallingPid() != Process.myPid()) {
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -0800774 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
Svet Ganov2af57082015-07-30 08:44:20 -0700775 Binder.getCallingPid(), Binder.getCallingUid(), null);
776 }
777 verifyIncomingOp(code);
778 code = AppOpsManager.opToSwitch(code);
779
780 synchronized (this) {
781 final int defaultMode = AppOpsManager.opToDefaultMode(code);
782
783 UidState uidState = getUidStateLocked(uid, false);
784 if (uidState == null) {
785 if (mode == defaultMode) {
786 return;
787 }
788 uidState = new UidState(uid);
789 uidState.opModes = new SparseIntArray();
790 uidState.opModes.put(code, mode);
791 mUidStates.put(uid, uidState);
792 scheduleWriteLocked();
793 } else if (uidState.opModes == null) {
794 if (mode != defaultMode) {
795 uidState.opModes = new SparseIntArray();
796 uidState.opModes.put(code, mode);
797 scheduleWriteLocked();
798 }
799 } else {
800 if (uidState.opModes.get(code) == mode) {
801 return;
802 }
803 if (mode == defaultMode) {
804 uidState.opModes.delete(code);
805 if (uidState.opModes.size() <= 0) {
806 uidState.opModes = null;
807 }
808 } else {
809 uidState.opModes.put(code, mode);
810 }
811 scheduleWriteLocked();
812 }
813 }
814
Svetoslav215b44a2015-08-04 19:03:40 -0700815 String[] uidPackageNames = getPackagesForUid(uid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800816 ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
Svet Ganov2af57082015-07-30 08:44:20 -0700817
riddle_hsu40b300f2015-11-23 13:22:03 +0800818 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800819 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -0700820 if (callbacks != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700821 final int callbackCount = callbacks.size();
822 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800823 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +0800824 ArraySet<String> changedPackages = new ArraySet<>();
825 Collections.addAll(changedPackages, uidPackageNames);
826 callbackSpecs = new ArrayMap<>();
827 callbackSpecs.put(callback, changedPackages);
828 }
829 }
830
831 for (String uidPackageName : uidPackageNames) {
832 callbacks = mPackageModeWatchers.get(uidPackageName);
833 if (callbacks != null) {
834 if (callbackSpecs == null) {
835 callbackSpecs = new ArrayMap<>();
Svet Ganov2af57082015-07-30 08:44:20 -0700836 }
riddle_hsu40b300f2015-11-23 13:22:03 +0800837 final int callbackCount = callbacks.size();
838 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800839 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +0800840 ArraySet<String> changedPackages = callbackSpecs.get(callback);
841 if (changedPackages == null) {
842 changedPackages = new ArraySet<>();
843 callbackSpecs.put(callback, changedPackages);
844 }
845 changedPackages.add(uidPackageName);
846 }
Svet Ganov2af57082015-07-30 08:44:20 -0700847 }
848 }
849 }
850
851 if (callbackSpecs == null) {
852 return;
853 }
854
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800855 for (int i = 0; i < callbackSpecs.size(); i++) {
856 final ModeCallback callback = callbackSpecs.keyAt(i);
857 final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
858 if (reportedPackageNames == null) {
859 mHandler.sendMessage(PooledLambda.obtainMessage(
860 AppOpsService::notifyOpChanged,
861 this, callback, code, uid, (String) null));
862
863 } else {
864 final int reportedPackageCount = reportedPackageNames.size();
865 for (int j = 0; j < reportedPackageCount; j++) {
866 final String reportedPackageName = reportedPackageNames.valueAt(j);
867 mHandler.sendMessage(PooledLambda.obtainMessage(
868 AppOpsService::notifyOpChanged,
869 this, callback, code, uid, reportedPackageName));
Svet Ganov2af57082015-07-30 08:44:20 -0700870 }
871 }
Svet Ganov2af57082015-07-30 08:44:20 -0700872 }
873 }
874
875 @Override
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800876 public void setMode(int code, int uid, String packageName, int mode) {
Dianne Hackbornb64afe12014-07-22 16:29:04 -0700877 if (Binder.getCallingPid() != Process.myPid()) {
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -0800878 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
Dianne Hackbornb64afe12014-07-22 16:29:04 -0700879 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborn133b9df2014-07-01 13:06:10 -0700880 }
Dianne Hackborn961321f2013-02-05 17:22:41 -0800881 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800882 ArraySet<ModeCallback> repCbs = null;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800883 code = AppOpsManager.opToSwitch(code);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800884 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700885 UidState uidState = getUidStateLocked(uid, false);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800886 Op op = getOpLocked(code, uid, packageName, true);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800887 if (op != null) {
888 if (op.mode != mode) {
889 op.mode = mode;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800890 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800891 if (cbs != null) {
892 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800893 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800894 }
895 repCbs.addAll(cbs);
896 }
897 cbs = mPackageModeWatchers.get(packageName);
898 if (cbs != null) {
899 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800900 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800901 }
902 repCbs.addAll(cbs);
903 }
David Braunf5d83192013-09-16 13:43:51 -0700904 if (mode == AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800905 // If going into the default mode, prune this op
906 // if there is nothing else interesting in it.
Dianne Hackborn607b4142013-08-02 18:10:10 -0700907 pruneOp(op, uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800908 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800909 scheduleFastWriteLocked();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800910 }
911 }
912 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800913 if (repCbs != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800914 mHandler.sendMessage(PooledLambda.obtainMessage(
915 AppOpsService::notifyOpChanged,
916 this, repCbs, code, uid, packageName));
Dianne Hackbornc2293022013-02-06 23:14:49 -0800917 }
918 }
919
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800920 private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
921 int uid, String packageName) {
922 for (int i = 0; i < callbacks.size(); i++) {
923 final ModeCallback callback = callbacks.valueAt(i);
924 notifyOpChanged(callback, code, uid, packageName);
925 }
926 }
927
928 private void notifyOpChanged(ModeCallback callback, int code,
929 int uid, String packageName) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700930 if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800931 return;
932 }
933 // There are components watching for mode changes such as window manager
934 // and location manager which are in our process. The callbacks in these
935 // components may require permissions our remote caller does not have.
936 final long identity = Binder.clearCallingIdentity();
937 try {
938 callback.mCallback.opChanged(code, uid, packageName);
939 } catch (RemoteException e) {
940 /* ignore */
941 } finally {
942 Binder.restoreCallingIdentity(identity);
943 }
944 }
945
946 private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
947 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
948 int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
Dianne Hackborn607b4142013-08-02 18:10:10 -0700949 if (cbs == null) {
950 return callbacks;
951 }
952 if (callbacks == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700953 callbacks = new HashMap<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700954 }
Svet Ganov2af57082015-07-30 08:44:20 -0700955 boolean duplicate = false;
Dianne Hackborn68d76552017-02-27 15:32:03 -0800956 final int N = cbs.size();
957 for (int i=0; i<N; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800958 ModeCallback cb = cbs.valueAt(i);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700959 ArrayList<ChangeRec> reports = callbacks.get(cb);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700960 if (reports == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700961 reports = new ArrayList<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700962 callbacks.put(cb, reports);
Svet Ganov2af57082015-07-30 08:44:20 -0700963 } else {
964 final int reportCount = reports.size();
965 for (int j = 0; j < reportCount; j++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700966 ChangeRec report = reports.get(j);
967 if (report.op == op && report.pkg.equals(packageName)) {
Svet Ganov2af57082015-07-30 08:44:20 -0700968 duplicate = true;
969 break;
970 }
971 }
Dianne Hackborn607b4142013-08-02 18:10:10 -0700972 }
Svet Ganov2af57082015-07-30 08:44:20 -0700973 if (!duplicate) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700974 reports.add(new ChangeRec(op, uid, packageName));
Svet Ganov2af57082015-07-30 08:44:20 -0700975 }
Dianne Hackborn607b4142013-08-02 18:10:10 -0700976 }
977 return callbacks;
978 }
979
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700980 static final class ChangeRec {
981 final int op;
982 final int uid;
983 final String pkg;
984
985 ChangeRec(int _op, int _uid, String _pkg) {
986 op = _op;
987 uid = _uid;
988 pkg = _pkg;
989 }
990 }
991
Dianne Hackborn607b4142013-08-02 18:10:10 -0700992 @Override
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800993 public void resetAllModes(int reqUserId, String reqPackageName) {
994 final int callingPid = Binder.getCallingPid();
995 final int callingUid = Binder.getCallingUid();
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -0800996 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800997 callingPid, callingUid, null);
998 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
999 true, true, "resetAllModes", null);
Svet Ganov2af57082015-07-30 08:44:20 -07001000
1001 int reqUid = -1;
1002 if (reqPackageName != null) {
1003 try {
1004 reqUid = AppGlobals.getPackageManager().getPackageUid(
Jeff Sharkeycd654482016-01-08 17:42:11 -07001005 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
Svet Ganov2af57082015-07-30 08:44:20 -07001006 } catch (RemoteException e) {
1007 /* ignore - local call */
1008 }
1009 }
1010
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001011 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001012 synchronized (this) {
1013 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -07001014 for (int i = mUidStates.size() - 1; i >= 0; i--) {
1015 UidState uidState = mUidStates.valueAt(i);
1016
1017 SparseIntArray opModes = uidState.opModes;
1018 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
1019 final int uidOpCount = opModes.size();
1020 for (int j = uidOpCount - 1; j >= 0; j--) {
1021 final int code = opModes.keyAt(j);
1022 if (AppOpsManager.opAllowsReset(code)) {
1023 opModes.removeAt(j);
1024 if (opModes.size() <= 0) {
1025 uidState.opModes = null;
1026 }
1027 for (String packageName : getPackagesForUid(uidState.uid)) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001028 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001029 mOpModeWatchers.get(code));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001030 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001031 mPackageModeWatchers.get(packageName));
1032 }
1033 }
1034 }
1035 }
1036
1037 if (uidState.pkgOps == null) {
1038 continue;
1039 }
1040
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001041 if (reqUserId != UserHandle.USER_ALL
Svet Ganov2af57082015-07-30 08:44:20 -07001042 && reqUserId != UserHandle.getUserId(uidState.uid)) {
Alexandra Gherghinad6a98972014-08-04 17:05:34 +01001043 // Skip any ops for a different user
1044 continue;
1045 }
Svet Ganov2af57082015-07-30 08:44:20 -07001046
1047 Map<String, Ops> packages = uidState.pkgOps;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001048 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
1049 while (it.hasNext()) {
1050 Map.Entry<String, Ops> ent = it.next();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001051 String packageName = ent.getKey();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001052 if (reqPackageName != null && !reqPackageName.equals(packageName)) {
1053 // Skip any ops for a different package
1054 continue;
1055 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001056 Ops pkgOps = ent.getValue();
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001057 for (int j=pkgOps.size()-1; j>=0; j--) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001058 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn8828d3a2013-09-25 16:47:10 -07001059 if (AppOpsManager.opAllowsReset(curOp.op)
1060 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
David Braunf5d83192013-09-16 13:43:51 -07001061 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001062 changed = true;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001063 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001064 mOpModeWatchers.get(curOp.op));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001065 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001066 mPackageModeWatchers.get(packageName));
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001067 if (!curOp.hasAnyTime()) {
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001068 pkgOps.removeAt(j);
1069 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001070 }
1071 }
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001072 if (pkgOps.size() == 0) {
1073 it.remove();
1074 }
1075 }
Svet Ganov2af57082015-07-30 08:44:20 -07001076 if (uidState.isDefault()) {
1077 mUidStates.remove(uidState.uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001078 }
1079 }
Svet Ganov2af57082015-07-30 08:44:20 -07001080
Dianne Hackborn607b4142013-08-02 18:10:10 -07001081 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001082 scheduleFastWriteLocked();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001083 }
1084 }
1085 if (callbacks != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001086 for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
1087 ModeCallback cb = ent.getKey();
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001088 ArrayList<ChangeRec> reports = ent.getValue();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001089 for (int i=0; i<reports.size(); i++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001090 ChangeRec rep = reports.get(i);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001091 mHandler.sendMessage(PooledLambda.obtainMessage(
1092 AppOpsService::notifyOpChanged,
1093 this, cb, rep.op, rep.uid, rep.pkg));
Dianne Hackborn607b4142013-08-02 18:10:10 -07001094 }
1095 }
1096 }
1097 }
1098
Dianne Hackbornc2293022013-02-06 23:14:49 -08001099 @Override
1100 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001101 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001102 final int callingUid = Binder.getCallingUid();
1103 final int callingPid = Binder.getCallingPid();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001104 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1105 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001106 watchedUid = callingUid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001107 }
1108 Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
1109 AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001110 if (callback == null) {
1111 return;
1112 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001113 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001114 op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001115 ModeCallback cb = mModeWatchers.get(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001116 if (cb == null) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001117 cb = new ModeCallback(callback, watchedUid, callingUid, callingPid);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001118 mModeWatchers.put(callback.asBinder(), cb);
1119 }
1120 if (op != AppOpsManager.OP_NONE) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001121 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001122 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001123 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001124 mOpModeWatchers.put(op, cbs);
1125 }
1126 cbs.add(cb);
1127 }
1128 if (packageName != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001129 ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001130 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001131 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001132 mPackageModeWatchers.put(packageName, cbs);
1133 }
1134 cbs.add(cb);
1135 }
1136 }
1137 }
1138
1139 @Override
1140 public void stopWatchingMode(IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001141 if (callback == null) {
1142 return;
1143 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001144 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001145 ModeCallback cb = mModeWatchers.remove(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001146 if (cb != null) {
1147 cb.unlinkToDeath();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001148 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001149 ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001150 cbs.remove(cb);
1151 if (cbs.size() <= 0) {
1152 mOpModeWatchers.removeAt(i);
1153 }
1154 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001155 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001156 ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001157 cbs.remove(cb);
1158 if (cbs.size() <= 0) {
1159 mPackageModeWatchers.removeAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001160 }
1161 }
1162 }
1163 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001164 }
1165
1166 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001167 public IBinder getToken(IBinder clientToken) {
1168 synchronized (this) {
1169 ClientState cs = mClients.get(clientToken);
1170 if (cs == null) {
1171 cs = new ClientState(clientToken);
1172 mClients.put(clientToken, cs);
1173 }
1174 return cs;
1175 }
1176 }
1177
1178 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -08001179 public int checkOperation(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001180 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001181 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001182 String resolvedPackageName = resolvePackageName(uid, packageName);
1183 if (resolvedPackageName == null) {
1184 return AppOpsManager.MODE_IGNORED;
1185 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001186 synchronized (this) {
Svet Ganov442ed572016-08-17 17:29:43 -07001187 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001188 return AppOpsManager.MODE_IGNORED;
1189 }
Svet Ganov2af57082015-07-30 08:44:20 -07001190 code = AppOpsManager.opToSwitch(code);
1191 UidState uidState = getUidStateLocked(uid, false);
Svet Ganovee438d42017-01-19 18:04:38 -08001192 if (uidState != null && uidState.opModes != null
1193 && uidState.opModes.indexOfKey(code) >= 0) {
1194 return uidState.opModes.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001195 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001196 Op op = getOpLocked(code, uid, resolvedPackageName, false);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001197 if (op == null) {
David Braunf5d83192013-09-16 13:43:51 -07001198 return AppOpsManager.opToDefaultMode(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001199 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001200 return op.mode;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001201 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001202 }
1203
1204 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001205 public int checkAudioOperation(int code, int usage, int uid, String packageName) {
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00001206 boolean suspended;
1207 try {
1208 suspended = isPackageSuspendedForUser(packageName, uid);
1209 } catch (IllegalArgumentException ex) {
1210 // Package not found.
1211 suspended = false;
1212 }
1213
1214 if (suspended) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001215 Slog.i(TAG, "Audio disabled for suspended package=" + packageName + " for uid=" + uid);
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001216 return AppOpsManager.MODE_IGNORED;
1217 }
1218
John Spurlock1af30c72014-03-10 08:33:35 -04001219 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001220 final int mode = checkRestrictionLocked(code, usage, uid, packageName);
John Spurlock1af30c72014-03-10 08:33:35 -04001221 if (mode != AppOpsManager.MODE_ALLOWED) {
1222 return mode;
1223 }
1224 }
1225 return checkOperation(code, uid, packageName);
1226 }
1227
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001228 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001229 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001230 return AppGlobals.getPackageManager().isPackageSuspendedForUser(
1231 pkg, UserHandle.getUserId(uid));
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001232 } catch (RemoteException re) {
1233 throw new SecurityException("Could not talk to package manager service");
1234 }
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001235 }
1236
John Spurlock7b414672014-07-18 13:02:39 -04001237 private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
1238 final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1239 if (usageRestrictions != null) {
1240 final Restriction r = usageRestrictions.get(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001241 if (r != null && !r.exceptionPackages.contains(packageName)) {
1242 return r.mode;
1243 }
1244 }
1245 return AppOpsManager.MODE_ALLOWED;
1246 }
1247
1248 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001249 public void setAudioRestriction(int code, int usage, int uid, int mode,
John Spurlock1af30c72014-03-10 08:33:35 -04001250 String[] exceptionPackages) {
1251 verifyIncomingUid(uid);
1252 verifyIncomingOp(code);
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -08001253 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
1254 Binder.getCallingPid(), Binder.getCallingUid(), null);
John Spurlock1af30c72014-03-10 08:33:35 -04001255 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001256 SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1257 if (usageRestrictions == null) {
1258 usageRestrictions = new SparseArray<Restriction>();
1259 mAudioRestrictions.put(code, usageRestrictions);
John Spurlock1af30c72014-03-10 08:33:35 -04001260 }
John Spurlock7b414672014-07-18 13:02:39 -04001261 usageRestrictions.remove(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001262 if (mode != AppOpsManager.MODE_ALLOWED) {
1263 final Restriction r = new Restriction();
1264 r.mode = mode;
1265 if (exceptionPackages != null) {
1266 final int N = exceptionPackages.length;
1267 r.exceptionPackages = new ArraySet<String>(N);
1268 for (int i = 0; i < N; i++) {
1269 final String pkg = exceptionPackages[i];
1270 if (pkg != null) {
1271 r.exceptionPackages.add(pkg.trim());
1272 }
1273 }
1274 }
John Spurlock7b414672014-07-18 13:02:39 -04001275 usageRestrictions.put(usage, r);
John Spurlock1af30c72014-03-10 08:33:35 -04001276 }
1277 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001278
1279 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07001280 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
John Spurlock1af30c72014-03-10 08:33:35 -04001281 }
1282
1283 @Override
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001284 public int checkPackage(int uid, String packageName) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001285 Preconditions.checkNotNull(packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001286 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001287 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
1288 true /* uidMismatchExpected */);
1289 if (ops != null) {
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001290 return AppOpsManager.MODE_ALLOWED;
1291 } else {
1292 return AppOpsManager.MODE_ERRORED;
1293 }
1294 }
1295 }
1296
1297 @Override
Svet Ganov99b60432015-06-27 13:15:22 -07001298 public int noteProxyOperation(int code, String proxyPackageName,
1299 int proxiedUid, String proxiedPackageName) {
1300 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001301 final int proxyUid = Binder.getCallingUid();
1302 String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
1303 if (resolveProxyPackageName == null) {
1304 return AppOpsManager.MODE_IGNORED;
1305 }
1306 final int proxyMode = noteOperationUnchecked(code, proxyUid,
1307 resolveProxyPackageName, -1, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001308 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
1309 return proxyMode;
1310 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001311 String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
1312 if (resolveProxiedPackageName == null) {
1313 return AppOpsManager.MODE_IGNORED;
1314 }
1315 return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
1316 proxyMode, resolveProxyPackageName);
Svet Ganov99b60432015-06-27 13:15:22 -07001317 }
1318
1319 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001320 public int noteOperation(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001321 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001322 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001323 String resolvedPackageName = resolvePackageName(uid, packageName);
1324 if (resolvedPackageName == null) {
1325 return AppOpsManager.MODE_IGNORED;
1326 }
1327 return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001328 }
1329
1330 private int noteOperationUnchecked(int code, int uid, String packageName,
1331 int proxyUid, String proxyPackageName) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001332 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001333 final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001334 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001335 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001336 if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001337 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001338 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001339 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001340 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001341 if (isOpRestrictedLocked(uid, code, packageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001342 return AppOpsManager.MODE_IGNORED;
1343 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001344 final UidState uidState = ops.uidState;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001345 if (op.duration == -1) {
1346 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001347 + " code " + code + " time=" + op.time[uidState.state]
1348 + " duration=" + op.duration);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001349 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001350 op.duration = 0;
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001351 final int switchCode = AppOpsManager.opToSwitch(code);
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001352 // If there is a non-default per UID policy (we set UID op mode only if
1353 // non-default) it takes over, otherwise use the per package policy.
1354 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -07001355 final int uidMode = uidState.opModes.get(switchCode);
1356 if (uidMode != AppOpsManager.MODE_ALLOWED) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001357 if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + op.mode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001358 + switchCode + " (" + code + ") uid " + uid + " package "
1359 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001360 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov2af57082015-07-30 08:44:20 -07001361 return uidMode;
1362 }
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001363 } else {
1364 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
1365 if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001366 if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + op.mode + " for code "
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001367 + switchCode + " (" + code + ") uid " + uid + " package "
1368 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001369 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001370 return switchOp.mode;
1371 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001372 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001373 if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001374 + " package " + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001375 op.time[uidState.state] = System.currentTimeMillis();
1376 op.rejectTime[uidState.state] = 0;
Svet Ganov99b60432015-06-27 13:15:22 -07001377 op.proxyUid = proxyUid;
1378 op.proxyPackageName = proxyPackageName;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001379 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001380 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001381 }
1382
1383 @Override
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001384 public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001385 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001386 final int callingUid = Binder.getCallingUid();
1387 final int callingPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -08001388 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1389 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001390 watchedUid = callingUid;
Svet Ganovf7b47252018-02-26 11:11:27 -08001391 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001392 if (ops != null) {
1393 Preconditions.checkArrayElementsInRange(ops, 0,
1394 AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
1395 }
1396 if (callback == null) {
1397 return;
1398 }
1399 synchronized (this) {
1400 SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
1401 if (callbacks == null) {
1402 callbacks = new SparseArray<>();
1403 mActiveWatchers.put(callback.asBinder(), callbacks);
1404 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001405 final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
1406 callingUid, callingPid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001407 for (int op : ops) {
1408 callbacks.put(op, activeCallback);
1409 }
1410 }
1411 }
1412
1413 @Override
1414 public void stopWatchingActive(IAppOpsActiveCallback callback) {
1415 if (callback == null) {
1416 return;
1417 }
1418 synchronized (this) {
1419 final SparseArray<ActiveCallback> activeCallbacks =
1420 mActiveWatchers.remove(callback.asBinder());
1421 if (activeCallbacks == null) {
1422 return;
1423 }
1424 final int callbackCount = activeCallbacks.size();
1425 for (int i = 0; i < callbackCount; i++) {
1426 // Apps ops are mapped to a singleton
1427 if (i == 0) {
1428 activeCallbacks.valueAt(i).destroy();
1429 }
1430 }
1431 }
1432 }
1433
1434 @Override
Svet Ganovf7b47252018-02-26 11:11:27 -08001435 public int startOperation(IBinder token, int code, int uid, String packageName,
1436 boolean startIfModeDefault) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001437 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001438 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001439 String resolvedPackageName = resolvePackageName(uid, packageName);
1440 if (resolvedPackageName == null) {
1441 return AppOpsManager.MODE_IGNORED;
1442 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001443 ClientState client = (ClientState)token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001444 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001445 final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001446 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001447 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001448 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001449 + " package " + resolvedPackageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001450 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001451 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001452 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001453 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001454 return AppOpsManager.MODE_IGNORED;
1455 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001456 final int switchCode = AppOpsManager.opToSwitch(code);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001457 final UidState uidState = ops.uidState;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001458 // If there is a non-default per UID policy (we set UID op mode only if
1459 // non-default) it takes over, otherwise use the per package policy.
1460 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -07001461 final int uidMode = uidState.opModes.get(switchCode);
Svet Ganovf7b47252018-02-26 11:11:27 -08001462 if (uidMode != AppOpsManager.MODE_ALLOWED
1463 && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001464 if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + op.mode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001465 + switchCode + " (" + code + ") uid " + uid + " package "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001466 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001467 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov2af57082015-07-30 08:44:20 -07001468 return uidMode;
1469 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001470 } else {
1471 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Svet Ganovf7b47252018-02-26 11:11:27 -08001472 if (switchOp.mode != AppOpsManager.MODE_ALLOWED
1473 && (!startIfModeDefault || switchOp.mode != AppOpsManager.MODE_DEFAULT)) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001474 if (DEBUG) Slog.d(TAG, "startOperation: reject #" + op.mode + " for code "
1475 + switchCode + " (" + code + ") uid " + uid + " package "
1476 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001477 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001478 return switchOp.mode;
1479 }
Svet Ganov2af57082015-07-30 08:44:20 -07001480 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001481 if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001482 + " package " + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001483 if (op.startNesting == 0) {
1484 op.startRealtime = SystemClock.elapsedRealtime();
1485 op.time[uidState.state] = System.currentTimeMillis();
1486 op.rejectTime[uidState.state] = 0;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001487 op.duration = -1;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001488 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001489 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001490 op.startNesting++;
1491 uidState.startNesting++;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001492 if (client.mStartedOps != null) {
1493 client.mStartedOps.add(op);
1494 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001495 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001496
1497 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001498 }
1499
1500 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001501 public void finishOperation(IBinder token, int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001502 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001503 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001504 String resolvedPackageName = resolvePackageName(uid, packageName);
1505 if (resolvedPackageName == null) {
1506 return;
1507 }
1508 if (!(token instanceof ClientState)) {
1509 return;
1510 }
1511 ClientState client = (ClientState) token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001512 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001513 Op op = getOpLocked(code, uid, resolvedPackageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001514 if (op == null) {
1515 return;
1516 }
Svet Ganovf7b47252018-02-26 11:11:27 -08001517 if (!client.mStartedOps.remove(op)) {
Svet Ganovf5d5af12018-03-18 11:51:17 -07001518 // We finish ops when packages get removed to guarantee no dangling
1519 // started ops. However, some part of the system may asynchronously
1520 // finish ops for an already gone package. Hence, finishing an op
1521 // for a non existing package is fine and we don't log as a wtf.
1522 final long identity = Binder.clearCallingIdentity();
1523 try {
1524 if (LocalServices.getService(PackageManagerInternal.class).getPackageUid(
1525 resolvedPackageName, 0, UserHandle.getUserId(uid)) < 0) {
1526 Slog.i(TAG, "Finishing op=" + AppOpsManager.opToName(code)
1527 + " for non-existing package=" + resolvedPackageName
1528 + " in uid=" + uid);
1529 return;
1530 }
1531 } finally {
1532 Binder.restoreCallingIdentity(identity);
1533 }
1534 Slog.wtf(TAG, "Operation not started: uid=" + op.uid + " pkg="
1535 + op.packageName + " op=" + AppOpsManager.opToName(op.op));
Svet Ganov31d83ae2018-03-15 10:45:56 -07001536 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001537 }
Svet Ganova7a0db62018-02-27 20:08:01 -08001538 finishOperationLocked(op, /*finishNested*/ false);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001539 if (op.startNesting <= 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001540 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
1541 }
1542 }
1543 }
1544
1545 private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
1546 boolean active) {
1547 ArraySet<ActiveCallback> dispatchedCallbacks = null;
1548 final int callbackListCount = mActiveWatchers.size();
1549 for (int i = 0; i < callbackListCount; i++) {
1550 final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
1551 ActiveCallback callback = callbacks.get(code);
1552 if (callback != null) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001553 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001554 continue;
1555 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001556 if (dispatchedCallbacks == null) {
1557 dispatchedCallbacks = new ArraySet<>();
1558 }
1559 dispatchedCallbacks.add(callback);
1560 }
1561 }
1562 if (dispatchedCallbacks == null) {
1563 return;
1564 }
1565 mHandler.sendMessage(PooledLambda.obtainMessage(
1566 AppOpsService::notifyOpActiveChanged,
1567 this, dispatchedCallbacks, code, uid, packageName, active));
1568 }
1569
1570 private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
1571 int code, int uid, String packageName, boolean active) {
1572 // There are components watching for mode changes such as window manager
1573 // and location manager which are in our process. The callbacks in these
1574 // components may require permissions our remote caller does not have.
1575 final long identity = Binder.clearCallingIdentity();
1576 try {
1577 final int callbackCount = callbacks.size();
1578 for (int i = 0; i < callbackCount; i++) {
1579 final ActiveCallback callback = callbacks.valueAt(i);
1580 try {
1581 callback.mCallback.opActiveChanged(code, uid, packageName, active);
1582 } catch (RemoteException e) {
1583 /* do nothing */
1584 }
1585 }
1586 } finally {
1587 Binder.restoreCallingIdentity(identity);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001588 }
1589 }
1590
Svet Ganovb9d71a62015-04-30 10:38:13 -07001591 @Override
1592 public int permissionToOpCode(String permission) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001593 if (permission == null) {
1594 return AppOpsManager.OP_NONE;
1595 }
Svet Ganovb9d71a62015-04-30 10:38:13 -07001596 return AppOpsManager.permissionToOpCode(permission);
1597 }
1598
Svet Ganova7a0db62018-02-27 20:08:01 -08001599 void finishOperationLocked(Op op, boolean finishNested) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001600 if (op.startNesting <= 1 || finishNested) {
1601 if (op.startNesting == 1 || finishNested) {
1602 op.duration = (int)(SystemClock.elapsedRealtime() - op.startRealtime);
1603 op.time[op.uidState.state] = System.currentTimeMillis();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001604 } else {
1605 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
1606 + op.packageName + " code " + op.op + " time=" + op.time
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001607 + " duration=" + op.duration + " nesting=" + op.startNesting);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001608 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001609 if (op.startNesting >= 1) {
1610 op.uidState.startNesting -= op.startNesting;
1611 }
1612 op.startNesting = 0;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001613 } else {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001614 op.startNesting--;
1615 op.uidState.startNesting--;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001616 }
1617 }
1618
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001619 private void verifyIncomingUid(int uid) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001620 if (uid == Binder.getCallingUid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001621 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001622 }
1623 if (Binder.getCallingPid() == Process.myPid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001624 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001625 }
1626 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
1627 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001628 }
1629
Dianne Hackborn961321f2013-02-05 17:22:41 -08001630 private void verifyIncomingOp(int op) {
1631 if (op >= 0 && op < AppOpsManager._NUM_OP) {
1632 return;
1633 }
1634 throw new IllegalArgumentException("Bad operation #" + op);
1635 }
1636
Svet Ganov2af57082015-07-30 08:44:20 -07001637 private UidState getUidStateLocked(int uid, boolean edit) {
1638 UidState uidState = mUidStates.get(uid);
1639 if (uidState == null) {
1640 if (!edit) {
1641 return null;
1642 }
1643 uidState = new UidState(uid);
1644 mUidStates.put(uid, uidState);
1645 }
1646 return uidState;
1647 }
1648
Yohei Yukawaa965d652017-10-12 15:02:26 -07001649 private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
1650 boolean uidMismatchExpected) {
Svet Ganov2af57082015-07-30 08:44:20 -07001651 UidState uidState = getUidStateLocked(uid, edit);
1652 if (uidState == null) {
1653 return null;
1654 }
1655
1656 if (uidState.pkgOps == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001657 if (!edit) {
1658 return null;
1659 }
Svet Ganov2af57082015-07-30 08:44:20 -07001660 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001661 }
Svet Ganov2af57082015-07-30 08:44:20 -07001662
1663 Ops ops = uidState.pkgOps.get(packageName);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001664 if (ops == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001665 if (!edit) {
1666 return null;
1667 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001668 boolean isPrivileged = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001669 // This is the first time we have seen this package name under this uid,
1670 // so let's make sure it is valid.
Dianne Hackborn514074f2013-02-11 10:52:46 -08001671 if (uid != 0) {
1672 final long ident = Binder.clearCallingIdentity();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001673 try {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001674 int pkgUid = -1;
1675 try {
Jason Monk1c7c3192014-06-26 12:52:18 -04001676 ApplicationInfo appInfo = ActivityThread.getPackageManager()
Jeff Sharkeycd654482016-01-08 17:42:11 -07001677 .getApplicationInfo(packageName,
1678 PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
1679 UserHandle.getUserId(uid));
Jason Monk1c7c3192014-06-26 12:52:18 -04001680 if (appInfo != null) {
1681 pkgUid = appInfo.uid;
Alex Klyubinb9f8a522015-02-03 11:12:59 -08001682 isPrivileged = (appInfo.privateFlags
1683 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04001684 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08001685 pkgUid = resolveUid(packageName);
1686 if (pkgUid >= 0) {
Chien-Yu Chen75cade02016-01-11 10:56:21 -08001687 isPrivileged = false;
Jason Monk1c7c3192014-06-26 12:52:18 -04001688 }
Dianne Hackborn713df152013-05-17 11:27:57 -07001689 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001690 } catch (RemoteException e) {
1691 Slog.w(TAG, "Could not contact PackageManager", e);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001692 }
1693 if (pkgUid != uid) {
1694 // Oops! The package name is not valid for the uid they are calling
1695 // under. Abort.
Yohei Yukawaa965d652017-10-12 15:02:26 -07001696 if (!uidMismatchExpected) {
1697 RuntimeException ex = new RuntimeException("here");
1698 ex.fillInStackTrace();
1699 Slog.w(TAG, "Bad call: specified package " + packageName
1700 + " under uid " + uid + " but it is really " + pkgUid, ex);
1701 }
Dianne Hackborn514074f2013-02-11 10:52:46 -08001702 return null;
1703 }
1704 } finally {
1705 Binder.restoreCallingIdentity(ident);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001706 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001707 }
Svet Ganov2af57082015-07-30 08:44:20 -07001708 ops = new Ops(packageName, uidState, isPrivileged);
1709 uidState.pkgOps.put(packageName, ops);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001710 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08001711 return ops;
1712 }
1713
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001714 private void scheduleWriteLocked() {
1715 if (!mWriteScheduled) {
1716 mWriteScheduled = true;
1717 mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
1718 }
1719 }
1720
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001721 private void scheduleFastWriteLocked() {
1722 if (!mFastWriteScheduled) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001723 mWriteScheduled = true;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001724 mFastWriteScheduled = true;
1725 mHandler.removeCallbacks(mWriteRunner);
1726 mHandler.postDelayed(mWriteRunner, 10*1000);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001727 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001728 }
1729
Dianne Hackborn72e39832013-01-18 18:36:09 -08001730 private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001731 Ops ops = getOpsRawLocked(uid, packageName, edit,
1732 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001733 if (ops == null) {
1734 return null;
1735 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001736 return getOpLocked(ops, code, edit);
1737 }
1738
1739 private Op getOpLocked(Ops ops, int code, boolean edit) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001740 Op op = ops.get(code);
1741 if (op == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001742 if (!edit) {
1743 return null;
1744 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001745 op = new Op(ops.uidState, ops.packageName, code);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001746 ops.put(code, op);
1747 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001748 if (edit) {
1749 scheduleWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001750 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001751 return op;
1752 }
1753
Svet Ganov442ed572016-08-17 17:29:43 -07001754 private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
Jason Monk62062992014-05-06 09:55:28 -04001755 int userHandle = UserHandle.getUserId(uid);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001756 final int restrictionSetCount = mOpUserRestrictions.size();
Ruben Brunk29931bc2016-03-11 00:24:26 -08001757
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001758 for (int i = 0; i < restrictionSetCount; i++) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08001759 // For each client, check that the given op is not restricted, or that the given
1760 // package is exempt from the restriction.
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07001761 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07001762 if (restrictionState.hasRestriction(code, packageName, userHandle)) {
1763 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
1764 // If we are the system, bypass user restrictions for certain codes
1765 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001766 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
1767 false /* uidMismatchExpected */);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07001768 if ((ops != null) && ops.isPrivileged) {
1769 return false;
1770 }
Ruben Brunk32f0fa42016-03-11 19:07:07 -08001771 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08001772 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001773 return true;
Jason Monk1c7c3192014-06-26 12:52:18 -04001774 }
Jason Monk62062992014-05-06 09:55:28 -04001775 }
1776 return false;
1777 }
1778
Dianne Hackborn35654b62013-01-14 17:38:02 -08001779 void readState() {
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07001780 int oldVersion = NO_VERSION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001781 synchronized (mFile) {
1782 synchronized (this) {
1783 FileInputStream stream;
1784 try {
1785 stream = mFile.openRead();
1786 } catch (FileNotFoundException e) {
1787 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
1788 return;
1789 }
1790 boolean success = false;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07001791 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001792 try {
1793 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001794 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08001795 int type;
1796 while ((type = parser.next()) != XmlPullParser.START_TAG
1797 && type != XmlPullParser.END_DOCUMENT) {
1798 ;
1799 }
1800
1801 if (type != XmlPullParser.START_TAG) {
1802 throw new IllegalStateException("no start tag found");
1803 }
1804
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07001805 final String versionString = parser.getAttributeValue(null, "v");
1806 if (versionString != null) {
1807 oldVersion = Integer.parseInt(versionString);
1808 }
1809
Dianne Hackborn35654b62013-01-14 17:38:02 -08001810 int outerDepth = parser.getDepth();
1811 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1812 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1813 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1814 continue;
1815 }
1816
1817 String tagName = parser.getName();
1818 if (tagName.equals("pkg")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00001819 readPackage(parser);
Svetoslav215b44a2015-08-04 19:03:40 -07001820 } else if (tagName.equals("uid")) {
Svet Ganov2af57082015-07-30 08:44:20 -07001821 readUidOps(parser);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001822 } else {
1823 Slog.w(TAG, "Unknown element under <app-ops>: "
1824 + parser.getName());
1825 XmlUtils.skipCurrentTag(parser);
1826 }
1827 }
1828 success = true;
1829 } catch (IllegalStateException e) {
1830 Slog.w(TAG, "Failed parsing " + e);
1831 } catch (NullPointerException e) {
1832 Slog.w(TAG, "Failed parsing " + e);
1833 } catch (NumberFormatException e) {
1834 Slog.w(TAG, "Failed parsing " + e);
1835 } catch (XmlPullParserException e) {
1836 Slog.w(TAG, "Failed parsing " + e);
1837 } catch (IOException e) {
1838 Slog.w(TAG, "Failed parsing " + e);
1839 } catch (IndexOutOfBoundsException e) {
1840 Slog.w(TAG, "Failed parsing " + e);
1841 } finally {
1842 if (!success) {
Svet Ganov2af57082015-07-30 08:44:20 -07001843 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001844 }
1845 try {
1846 stream.close();
1847 } catch (IOException e) {
1848 }
1849 }
1850 }
1851 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07001852 synchronized (this) {
1853 upgradeLocked(oldVersion);
1854 }
1855 }
1856
1857 private void upgradeRunAnyInBackgroundLocked() {
1858 for (int i = 0; i < mUidStates.size(); i++) {
1859 final UidState uidState = mUidStates.valueAt(i);
1860 if (uidState == null) {
1861 continue;
1862 }
1863 if (uidState.opModes != null) {
1864 final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
1865 if (idx >= 0) {
1866 uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
1867 uidState.opModes.valueAt(idx));
1868 }
1869 }
1870 if (uidState.pkgOps == null) {
1871 continue;
1872 }
1873 for (int j = 0; j < uidState.pkgOps.size(); j++) {
1874 Ops ops = uidState.pkgOps.valueAt(j);
1875 if (ops != null) {
1876 final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
1877 if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001878 final Op copy = new Op(op.uidState, op.packageName,
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07001879 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
1880 copy.mode = op.mode;
1881 ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
1882 }
1883 }
1884 }
1885 }
1886 }
1887
1888 private void upgradeLocked(int oldVersion) {
1889 if (oldVersion >= CURRENT_VERSION) {
1890 return;
1891 }
1892 Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
1893 switch (oldVersion) {
1894 case NO_VERSION:
1895 upgradeRunAnyInBackgroundLocked();
1896 // fall through
1897 case 1:
1898 // for future upgrades
1899 }
1900 scheduleFastWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001901 }
1902
Svet Ganov2af57082015-07-30 08:44:20 -07001903 void readUidOps(XmlPullParser parser) throws NumberFormatException,
1904 XmlPullParserException, IOException {
1905 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
1906 int outerDepth = parser.getDepth();
1907 int type;
1908 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1909 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1910 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1911 continue;
1912 }
1913
1914 String tagName = parser.getName();
1915 if (tagName.equals("op")) {
1916 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
1917 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
1918 UidState uidState = getUidStateLocked(uid, true);
1919 if (uidState.opModes == null) {
1920 uidState.opModes = new SparseIntArray();
1921 }
1922 uidState.opModes.put(code, mode);
1923 } else {
1924 Slog.w(TAG, "Unknown element under <uid-ops>: "
1925 + parser.getName());
1926 XmlUtils.skipCurrentTag(parser);
1927 }
1928 }
1929 }
1930
Dave Burke0997c5bd2013-08-02 20:25:02 +00001931 void readPackage(XmlPullParser parser) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08001932 XmlPullParserException, IOException {
1933 String pkgName = parser.getAttributeValue(null, "n");
1934 int outerDepth = parser.getDepth();
1935 int type;
1936 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1937 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1938 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1939 continue;
1940 }
1941
1942 String tagName = parser.getName();
1943 if (tagName.equals("uid")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00001944 readUid(parser, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001945 } else {
1946 Slog.w(TAG, "Unknown element under <pkg>: "
1947 + parser.getName());
1948 XmlUtils.skipCurrentTag(parser);
1949 }
1950 }
1951 }
1952
Dave Burke0997c5bd2013-08-02 20:25:02 +00001953 void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08001954 XmlPullParserException, IOException {
1955 int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
Jason Monk1c7c3192014-06-26 12:52:18 -04001956 String isPrivilegedString = parser.getAttributeValue(null, "p");
1957 boolean isPrivileged = false;
1958 if (isPrivilegedString == null) {
1959 try {
1960 IPackageManager packageManager = ActivityThread.getPackageManager();
1961 if (packageManager != null) {
1962 ApplicationInfo appInfo = ActivityThread.getPackageManager()
1963 .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
1964 if (appInfo != null) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08001965 isPrivileged = (appInfo.privateFlags
1966 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04001967 }
1968 } else {
1969 // Could not load data, don't add to cache so it will be loaded later.
1970 return;
1971 }
1972 } catch (RemoteException e) {
1973 Slog.w(TAG, "Could not contact PackageManager", e);
1974 }
1975 } else {
1976 isPrivileged = Boolean.parseBoolean(isPrivilegedString);
1977 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001978 int outerDepth = parser.getDepth();
1979 int type;
1980 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1981 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1982 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1983 continue;
1984 }
1985
1986 String tagName = parser.getName();
1987 if (tagName.equals("op")) {
Svet Ganov2af57082015-07-30 08:44:20 -07001988 UidState uidState = getUidStateLocked(uid, true);
1989 if (uidState.pkgOps == null) {
1990 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001991 }
Svet Ganov2af57082015-07-30 08:44:20 -07001992
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001993 Op op = new Op(uidState, pkgName,
1994 Integer.parseInt(parser.getAttributeValue(null, "n")));
1995
1996 for (int i = parser.getAttributeCount()-1; i >= 0; i--) {
1997 final String name = parser.getAttributeName(i);
1998 final String value = parser.getAttributeValue(i);
1999 switch (name) {
2000 case "m":
2001 op.mode = Integer.parseInt(value);
2002 break;
2003 case "d":
2004 op.duration = Integer.parseInt(value);
2005 break;
2006 case "pu":
2007 op.proxyUid = Integer.parseInt(value);
2008 break;
2009 case "pp":
2010 op.proxyPackageName = value;
2011 break;
2012 case "tp":
2013 op.time[AppOpsManager.UID_STATE_PERSISTENT] = Long.parseLong(value);
2014 break;
2015 case "tt":
2016 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2017 break;
2018 case "tfs":
2019 op.time[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2020 = Long.parseLong(value);
2021 break;
2022 case "tf":
2023 op.time[AppOpsManager.UID_STATE_FOREGROUND] = Long.parseLong(value);
2024 break;
2025 case "tb":
2026 op.time[AppOpsManager.UID_STATE_BACKGROUND] = Long.parseLong(value);
2027 break;
2028 case "tc":
2029 op.time[AppOpsManager.UID_STATE_CACHED] = Long.parseLong(value);
2030 break;
2031 case "rp":
2032 op.rejectTime[AppOpsManager.UID_STATE_PERSISTENT]
2033 = Long.parseLong(value);
2034 break;
2035 case "rt":
2036 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2037 break;
2038 case "rfs":
2039 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2040 = Long.parseLong(value);
2041 break;
2042 case "rf":
2043 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND]
2044 = Long.parseLong(value);
2045 break;
2046 case "rb":
2047 op.rejectTime[AppOpsManager.UID_STATE_BACKGROUND]
2048 = Long.parseLong(value);
2049 break;
2050 case "rc":
2051 op.rejectTime[AppOpsManager.UID_STATE_CACHED]
2052 = Long.parseLong(value);
2053 break;
2054 case "t":
2055 // Backwards compat.
2056 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2057 break;
2058 case "r":
2059 // Backwards compat.
2060 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2061 break;
2062 default:
2063 Slog.w(TAG, "Unknown attribute in 'op' tag: " + name);
2064 break;
2065 }
2066 }
2067
Svet Ganov2af57082015-07-30 08:44:20 -07002068 Ops ops = uidState.pkgOps.get(pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002069 if (ops == null) {
Svet Ganov2af57082015-07-30 08:44:20 -07002070 ops = new Ops(pkgName, uidState, isPrivileged);
2071 uidState.pkgOps.put(pkgName, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002072 }
2073 ops.put(op.op, op);
2074 } else {
2075 Slog.w(TAG, "Unknown element under <pkg>: "
2076 + parser.getName());
2077 XmlUtils.skipCurrentTag(parser);
2078 }
2079 }
2080 }
2081
2082 void writeState() {
2083 synchronized (mFile) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002084 FileOutputStream stream;
2085 try {
2086 stream = mFile.startWrite();
2087 } catch (IOException e) {
2088 Slog.w(TAG, "Failed to write state: " + e);
2089 return;
2090 }
2091
Dianne Hackborne17b4452018-01-10 13:15:40 -08002092 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
2093
Dianne Hackborn35654b62013-01-14 17:38:02 -08002094 try {
2095 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002096 out.setOutput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002097 out.startDocument(null, true);
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002098 out.startTag(null, "app-ops");
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002099 out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
Svet Ganov2af57082015-07-30 08:44:20 -07002100
2101 final int uidStateCount = mUidStates.size();
2102 for (int i = 0; i < uidStateCount; i++) {
2103 UidState uidState = mUidStates.valueAt(i);
2104 if (uidState.opModes != null && uidState.opModes.size() > 0) {
2105 out.startTag(null, "uid");
2106 out.attribute(null, "n", Integer.toString(uidState.uid));
2107 SparseIntArray uidOpModes = uidState.opModes;
2108 final int opCount = uidOpModes.size();
2109 for (int j = 0; j < opCount; j++) {
2110 final int op = uidOpModes.keyAt(j);
2111 final int mode = uidOpModes.valueAt(j);
2112 out.startTag(null, "op");
2113 out.attribute(null, "n", Integer.toString(op));
2114 out.attribute(null, "m", Integer.toString(mode));
2115 out.endTag(null, "op");
2116 }
2117 out.endTag(null, "uid");
2118 }
2119 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002120
2121 if (allOps != null) {
2122 String lastPkg = null;
2123 for (int i=0; i<allOps.size(); i++) {
2124 AppOpsManager.PackageOps pkg = allOps.get(i);
2125 if (!pkg.getPackageName().equals(lastPkg)) {
2126 if (lastPkg != null) {
2127 out.endTag(null, "pkg");
2128 }
2129 lastPkg = pkg.getPackageName();
2130 out.startTag(null, "pkg");
2131 out.attribute(null, "n", lastPkg);
2132 }
2133 out.startTag(null, "uid");
2134 out.attribute(null, "n", Integer.toString(pkg.getUid()));
Jason Monk1c7c3192014-06-26 12:52:18 -04002135 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002136 Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
2137 false /* edit */, false /* uidMismatchExpected */);
Jason Monk1c7c3192014-06-26 12:52:18 -04002138 // Should always be present as the list of PackageOps is generated
2139 // from Ops.
2140 if (ops != null) {
2141 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
2142 } else {
2143 out.attribute(null, "p", Boolean.toString(false));
2144 }
2145 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002146 List<AppOpsManager.OpEntry> ops = pkg.getOps();
2147 for (int j=0; j<ops.size(); j++) {
2148 AppOpsManager.OpEntry op = ops.get(j);
2149 out.startTag(null, "op");
2150 out.attribute(null, "n", Integer.toString(op.getOp()));
David Braunf5d83192013-09-16 13:43:51 -07002151 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002152 out.attribute(null, "m", Integer.toString(op.getMode()));
2153 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002154 for (int k = 0; k < _NUM_UID_STATE; k++) {
2155 final long time = op.getTimeFor(k);
2156 if (time != 0) {
2157 out.attribute(null, UID_STATE_TIME_ATTRS[k],
2158 Long.toString(time));
2159 }
2160 final long rejectTime = op.getRejectTimeFor(k);
2161 if (rejectTime != 0) {
2162 out.attribute(null, UID_STATE_REJECT_ATTRS[k],
2163 Long.toString(rejectTime));
2164 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002165 }
2166 int dur = op.getDuration();
2167 if (dur != 0) {
2168 out.attribute(null, "d", Integer.toString(dur));
2169 }
Svet Ganov99b60432015-06-27 13:15:22 -07002170 int proxyUid = op.getProxyUid();
2171 if (proxyUid != -1) {
2172 out.attribute(null, "pu", Integer.toString(proxyUid));
2173 }
2174 String proxyPackageName = op.getProxyPackageName();
2175 if (proxyPackageName != null) {
2176 out.attribute(null, "pp", proxyPackageName);
2177 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002178 out.endTag(null, "op");
2179 }
2180 out.endTag(null, "uid");
2181 }
2182 if (lastPkg != null) {
2183 out.endTag(null, "pkg");
2184 }
2185 }
2186
2187 out.endTag(null, "app-ops");
2188 out.endDocument();
2189 mFile.finishWrite(stream);
2190 } catch (IOException e) {
2191 Slog.w(TAG, "Failed to write state, restoring backup.", e);
2192 mFile.failWrite(stream);
2193 }
2194 }
2195 }
2196
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002197 static class Shell extends ShellCommand {
2198 final IAppOpsService mInterface;
2199 final AppOpsService mInternal;
2200
2201 int userId = UserHandle.USER_SYSTEM;
2202 String packageName;
2203 String opStr;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002204 String modeStr;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002205 int op;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002206 int mode;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002207 int packageUid;
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002208 int nonpackageUid;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002209 final static Binder sBinder = new Binder();
2210 IBinder mToken;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002211
2212 Shell(IAppOpsService iface, AppOpsService internal) {
2213 mInterface = iface;
2214 mInternal = internal;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002215 try {
2216 mToken = mInterface.getToken(sBinder);
2217 } catch (RemoteException e) {
2218 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002219 }
2220
2221 @Override
2222 public int onCommand(String cmd) {
2223 return onShellCommand(this, cmd);
2224 }
2225
2226 @Override
2227 public void onHelp() {
2228 PrintWriter pw = getOutPrintWriter();
2229 dumpCommandHelp(pw);
2230 }
2231
2232 private int strOpToOp(String op, PrintWriter err) {
2233 try {
2234 return AppOpsManager.strOpToOp(op);
2235 } catch (IllegalArgumentException e) {
2236 }
2237 try {
2238 return Integer.parseInt(op);
2239 } catch (NumberFormatException e) {
2240 }
2241 try {
2242 return AppOpsManager.strDebugOpToOp(op);
2243 } catch (IllegalArgumentException e) {
2244 err.println("Error: " + e.getMessage());
2245 return -1;
2246 }
2247 }
2248
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002249 int strModeToMode(String modeStr, PrintWriter err) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002250 for (int i = MODE_NAMES.length - 1; i >= 0; i--) {
2251 if (MODE_NAMES[i].equals(modeStr)) {
2252 return i;
2253 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002254 }
2255 try {
2256 return Integer.parseInt(modeStr);
2257 } catch (NumberFormatException e) {
2258 }
2259 err.println("Error: Mode " + modeStr + " is not valid");
2260 return -1;
2261 }
2262
2263 int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
2264 userId = UserHandle.USER_CURRENT;
2265 opStr = null;
2266 modeStr = null;
2267 for (String argument; (argument = getNextArg()) != null;) {
2268 if ("--user".equals(argument)) {
2269 userId = UserHandle.parseUserArg(getNextArgRequired());
2270 } else {
2271 if (opStr == null) {
2272 opStr = argument;
2273 } else if (modeStr == null) {
2274 modeStr = argument;
2275 break;
2276 }
2277 }
2278 }
2279 if (opStr == null) {
2280 err.println("Error: Operation not specified.");
2281 return -1;
2282 }
2283 op = strOpToOp(opStr, err);
2284 if (op < 0) {
2285 return -1;
2286 }
2287 if (modeStr != null) {
2288 if ((mode=strModeToMode(modeStr, err)) < 0) {
2289 return -1;
2290 }
2291 } else {
2292 mode = defMode;
2293 }
2294 return 0;
2295 }
2296
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002297 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
2298 userId = UserHandle.USER_CURRENT;
2299 packageName = null;
2300 opStr = null;
2301 for (String argument; (argument = getNextArg()) != null;) {
2302 if ("--user".equals(argument)) {
2303 userId = UserHandle.parseUserArg(getNextArgRequired());
2304 } else {
2305 if (packageName == null) {
2306 packageName = argument;
2307 } else if (opStr == null) {
2308 opStr = argument;
2309 break;
2310 }
2311 }
2312 }
2313 if (packageName == null) {
2314 err.println("Error: Package name not specified.");
2315 return -1;
2316 } else if (opStr == null && reqOp) {
2317 err.println("Error: Operation not specified.");
2318 return -1;
2319 }
2320 if (opStr != null) {
2321 op = strOpToOp(opStr, err);
2322 if (op < 0) {
2323 return -1;
2324 }
2325 } else {
2326 op = AppOpsManager.OP_NONE;
2327 }
2328 if (userId == UserHandle.USER_CURRENT) {
2329 userId = ActivityManager.getCurrentUser();
2330 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002331 nonpackageUid = -1;
2332 try {
2333 nonpackageUid = Integer.parseInt(packageName);
2334 } catch (NumberFormatException e) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002335 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002336 if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
2337 && packageName.indexOf('.') < 0) {
2338 int i = 1;
2339 while (i < packageName.length() && packageName.charAt(i) >= '0'
2340 && packageName.charAt(i) <= '9') {
2341 i++;
2342 }
2343 if (i > 1 && i < packageName.length()) {
2344 String userStr = packageName.substring(1, i);
2345 try {
2346 int user = Integer.parseInt(userStr);
2347 char type = packageName.charAt(i);
2348 i++;
2349 int startTypeVal = i;
2350 while (i < packageName.length() && packageName.charAt(i) >= '0'
2351 && packageName.charAt(i) <= '9') {
2352 i++;
2353 }
2354 if (i > startTypeVal) {
2355 String typeValStr = packageName.substring(startTypeVal, i);
2356 try {
2357 int typeVal = Integer.parseInt(typeValStr);
2358 if (type == 'a') {
2359 nonpackageUid = UserHandle.getUid(user,
2360 typeVal + Process.FIRST_APPLICATION_UID);
2361 } else if (type == 's') {
2362 nonpackageUid = UserHandle.getUid(user, typeVal);
2363 }
2364 } catch (NumberFormatException e) {
2365 }
2366 }
2367 } catch (NumberFormatException e) {
2368 }
2369 }
2370 }
2371 if (nonpackageUid != -1) {
2372 packageName = null;
2373 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08002374 packageUid = resolveUid(packageName);
2375 if (packageUid < 0) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002376 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
2377 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
2378 }
2379 if (packageUid < 0) {
2380 err.println("Error: No UID for " + packageName + " in user " + userId);
2381 return -1;
2382 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002383 }
2384 return 0;
2385 }
2386 }
2387
2388 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07002389 FileDescriptor err, String[] args, ShellCallback callback,
2390 ResultReceiver resultReceiver) {
2391 (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002392 }
2393
2394 static void dumpCommandHelp(PrintWriter pw) {
2395 pw.println("AppOps service (appops) commands:");
2396 pw.println(" help");
2397 pw.println(" Print this help text.");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002398 pw.println(" start [--user <USER_ID>] <PACKAGE | UID> <OP> ");
2399 pw.println(" Starts a given operation for a particular application.");
2400 pw.println(" stop [--user <USER_ID>] <PACKAGE | UID> <OP> ");
2401 pw.println(" Stops a given operation for a particular application.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002402 pw.println(" set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002403 pw.println(" Set the mode for a particular application and operation.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002404 pw.println(" get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002405 pw.println(" Return the mode for a particular application and optional operation.");
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002406 pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
2407 pw.println(" Print all packages that currently have the given op in the given mode.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002408 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
2409 pw.println(" Reset the given application or all applications to default modes.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002410 pw.println(" write-settings");
2411 pw.println(" Immediately write pending changes to storage.");
2412 pw.println(" read-settings");
2413 pw.println(" Read the last written settings, replacing current state in RAM.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002414 pw.println(" options:");
2415 pw.println(" <PACKAGE> an Android package name.");
2416 pw.println(" <OP> an AppOps operation.");
2417 pw.println(" <MODE> one of allow, ignore, deny, or default");
2418 pw.println(" <USER_ID> the user id under which the package is installed. If --user is not");
2419 pw.println(" specified, the current user is assumed.");
2420 }
2421
2422 static int onShellCommand(Shell shell, String cmd) {
2423 if (cmd == null) {
2424 return shell.handleDefaultCommands(cmd);
2425 }
2426 PrintWriter pw = shell.getOutPrintWriter();
2427 PrintWriter err = shell.getErrPrintWriter();
2428 try {
2429 switch (cmd) {
2430 case "set": {
2431 int res = shell.parseUserPackageOp(true, err);
2432 if (res < 0) {
2433 return res;
2434 }
2435 String modeStr = shell.getNextArg();
2436 if (modeStr == null) {
2437 err.println("Error: Mode not specified.");
2438 return -1;
2439 }
2440
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002441 final int mode = shell.strModeToMode(modeStr, err);
2442 if (mode < 0) {
2443 return -1;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002444 }
2445
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002446 if (shell.packageName != null) {
2447 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
2448 mode);
2449 } else {
2450 shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
2451 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002452 return 0;
2453 }
2454 case "get": {
2455 int res = shell.parseUserPackageOp(false, err);
2456 if (res < 0) {
2457 return res;
2458 }
2459
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002460 List<AppOpsManager.PackageOps> ops;
2461 if (shell.packageName != null) {
2462 ops = shell.mInterface.getOpsForPackage(
2463 shell.packageUid, shell.packageName,
2464 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
2465 } else {
2466 ops = shell.mInterface.getUidOps(
2467 shell.nonpackageUid,
2468 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
2469 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002470 if (ops == null || ops.size() <= 0) {
2471 pw.println("No operations.");
Svet Ganov82f09bc2018-01-12 22:08:40 -08002472 if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
2473 pw.println("Default mode: " + AppOpsManager.modeToString(
2474 AppOpsManager.opToDefaultMode(shell.op)));
2475 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002476 return 0;
2477 }
2478 final long now = System.currentTimeMillis();
2479 for (int i=0; i<ops.size(); i++) {
2480 List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
2481 for (int j=0; j<entries.size(); j++) {
2482 AppOpsManager.OpEntry ent = entries.get(j);
2483 pw.print(AppOpsManager.opToName(ent.getOp()));
2484 pw.print(": ");
Svet Ganov82f09bc2018-01-12 22:08:40 -08002485 pw.print(AppOpsManager.modeToString(ent.getMode()));
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002486 if (ent.getTime() != 0) {
2487 pw.print("; time=");
2488 TimeUtils.formatDuration(now - ent.getTime(), pw);
2489 pw.print(" ago");
2490 }
2491 if (ent.getRejectTime() != 0) {
2492 pw.print("; rejectTime=");
2493 TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
2494 pw.print(" ago");
2495 }
2496 if (ent.getDuration() == -1) {
2497 pw.print(" (running)");
2498 } else if (ent.getDuration() != 0) {
2499 pw.print("; duration=");
2500 TimeUtils.formatDuration(ent.getDuration(), pw);
2501 }
2502 pw.println();
2503 }
2504 }
2505 return 0;
2506 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002507 case "query-op": {
2508 int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
2509 if (res < 0) {
2510 return res;
2511 }
2512 List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
2513 new int[] {shell.op});
2514 if (ops == null || ops.size() <= 0) {
2515 pw.println("No operations.");
2516 return 0;
2517 }
2518 for (int i=0; i<ops.size(); i++) {
2519 final AppOpsManager.PackageOps pkg = ops.get(i);
2520 boolean hasMatch = false;
2521 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
2522 for (int j=0; j<entries.size(); j++) {
2523 AppOpsManager.OpEntry ent = entries.get(j);
2524 if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
2525 hasMatch = true;
2526 break;
2527 }
2528 }
2529 if (hasMatch) {
2530 pw.println(pkg.getPackageName());
2531 }
2532 }
2533 return 0;
2534 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002535 case "reset": {
2536 String packageName = null;
2537 int userId = UserHandle.USER_CURRENT;
2538 for (String argument; (argument = shell.getNextArg()) != null;) {
2539 if ("--user".equals(argument)) {
2540 String userStr = shell.getNextArgRequired();
2541 userId = UserHandle.parseUserArg(userStr);
2542 } else {
2543 if (packageName == null) {
2544 packageName = argument;
2545 } else {
2546 err.println("Error: Unsupported argument: " + argument);
2547 return -1;
2548 }
2549 }
2550 }
2551
2552 if (userId == UserHandle.USER_CURRENT) {
2553 userId = ActivityManager.getCurrentUser();
2554 }
2555
2556 shell.mInterface.resetAllModes(userId, packageName);
2557 pw.print("Reset all modes for: ");
2558 if (userId == UserHandle.USER_ALL) {
2559 pw.print("all users");
2560 } else {
2561 pw.print("user "); pw.print(userId);
2562 }
2563 pw.print(", ");
2564 if (packageName == null) {
2565 pw.println("all packages");
2566 } else {
2567 pw.print("package "); pw.println(packageName);
2568 }
2569 return 0;
2570 }
2571 case "write-settings": {
2572 shell.mInternal.mContext.enforcePermission(
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -08002573 android.Manifest.permission.MANAGE_APP_OPS_MODES,
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002574 Binder.getCallingPid(), Binder.getCallingUid(), null);
2575 long token = Binder.clearCallingIdentity();
2576 try {
2577 synchronized (shell.mInternal) {
2578 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
2579 }
2580 shell.mInternal.writeState();
2581 pw.println("Current settings written.");
2582 } finally {
2583 Binder.restoreCallingIdentity(token);
2584 }
2585 return 0;
2586 }
2587 case "read-settings": {
2588 shell.mInternal.mContext.enforcePermission(
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -08002589 android.Manifest.permission.MANAGE_APP_OPS_MODES,
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002590 Binder.getCallingPid(), Binder.getCallingUid(), null);
2591 long token = Binder.clearCallingIdentity();
2592 try {
2593 shell.mInternal.readState();
2594 pw.println("Last settings read.");
2595 } finally {
2596 Binder.restoreCallingIdentity(token);
2597 }
2598 return 0;
2599 }
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002600 case "start": {
2601 int res = shell.parseUserPackageOp(true, err);
2602 if (res < 0) {
2603 return res;
2604 }
2605
2606 if (shell.packageName != null) {
2607 shell.mInterface.startOperation(shell.mToken,
2608 shell.op, shell.packageUid, shell.packageName, true);
2609 } else {
2610 return -1;
2611 }
2612 return 0;
2613 }
2614 case "stop": {
2615 int res = shell.parseUserPackageOp(true, err);
2616 if (res < 0) {
2617 return res;
2618 }
2619
2620 if (shell.packageName != null) {
2621 shell.mInterface.finishOperation(shell.mToken,
2622 shell.op, shell.packageUid, shell.packageName);
2623 } else {
2624 return -1;
2625 }
2626 return 0;
2627 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002628 default:
2629 return shell.handleDefaultCommands(cmd);
2630 }
2631 } catch (RemoteException e) {
2632 pw.println("Remote exception: " + e);
2633 }
2634 return -1;
2635 }
2636
2637 private void dumpHelp(PrintWriter pw) {
2638 pw.println("AppOps service (appops) dump options:");
2639 pw.println(" none");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002640 }
2641
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002642 private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
2643 long now, SimpleDateFormat sdf, Date date) {
2644 boolean hasTime = false;
2645 for (int i = 0; i < _NUM_UID_STATE; i++) {
2646 if (times[i] != 0) {
2647 hasTime = true;
2648 break;
2649 }
2650 }
2651 if (!hasTime) {
2652 return;
2653 }
2654 boolean first = true;
2655 for (int i = 0; i < _NUM_UID_STATE; i++) {
2656 if (times[i] != 0) {
2657 pw.print(first ? firstPrefix : prefix);
2658 first = false;
2659 pw.print(UID_STATE_NAMES[i]);
2660 pw.print(" = ");
2661 date.setTime(times[i]);
2662 pw.print(sdf.format(date));
2663 pw.print(" (");
2664 TimeUtils.formatDuration(times[i]-now, pw);
2665 pw.println(")");
2666 }
2667 }
2668 }
2669
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002670 @Override
2671 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06002672 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002673
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002674 if (args != null) {
2675 for (int i=0; i<args.length; i++) {
2676 String arg = args[i];
2677 if ("-h".equals(arg)) {
2678 dumpHelp(pw);
2679 return;
Tim Kilbourn8f1ea832015-08-26 15:07:37 -07002680 } else if ("-a".equals(arg)) {
2681 // dump all data
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002682 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
2683 pw.println("Unknown option: " + arg);
2684 return;
2685 } else {
2686 pw.println("Unknown command: " + arg);
2687 return;
2688 }
2689 }
2690 }
2691
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002692 synchronized (this) {
2693 pw.println("Current AppOps Service state:");
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002694 final long now = System.currentTimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002695 final long nowElapsed = SystemClock.elapsedRealtime();
2696 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
2697 final Date date = new Date();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002698 boolean needSep = false;
2699 if (mOpModeWatchers.size() > 0) {
2700 needSep = true;
2701 pw.println(" Op mode watchers:");
2702 for (int i=0; i<mOpModeWatchers.size(); i++) {
2703 pw.print(" Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
2704 pw.println(":");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002705 ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002706 for (int j=0; j<callbacks.size(); j++) {
2707 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn68d76552017-02-27 15:32:03 -08002708 pw.println(callbacks.valueAt(j));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002709 }
2710 }
2711 }
2712 if (mPackageModeWatchers.size() > 0) {
2713 needSep = true;
2714 pw.println(" Package mode watchers:");
2715 for (int i=0; i<mPackageModeWatchers.size(); i++) {
2716 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
2717 pw.println(":");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002718 ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002719 for (int j=0; j<callbacks.size(); j++) {
2720 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn68d76552017-02-27 15:32:03 -08002721 pw.println(callbacks.valueAt(j));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002722 }
2723 }
2724 }
2725 if (mModeWatchers.size() > 0) {
2726 needSep = true;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002727 pw.println(" All op mode watchers:");
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002728 for (int i=0; i<mModeWatchers.size(); i++) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002729 pw.print(" ");
2730 pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
2731 pw.print(": "); pw.println(mModeWatchers.valueAt(i));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002732 }
2733 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002734 if (mActiveWatchers.size() > 0) {
2735 needSep = true;
2736 pw.println(" All op active watchers:");
2737 for (int i = 0; i < mActiveWatchers.size(); i++) {
2738 final SparseArray<ActiveCallback> activeWatchers = mActiveWatchers.valueAt(i);
2739 if (activeWatchers.size() <= 0) {
2740 continue;
2741 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002742 pw.print(" ");
2743 pw.print(Integer.toHexString(System.identityHashCode(
2744 mActiveWatchers.keyAt(i))));
2745 pw.println(" ->");
2746 pw.print(" [");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002747 final int opCount = activeWatchers.size();
2748 for (i = 0; i < opCount; i++) {
2749 pw.print(AppOpsManager.opToName(activeWatchers.keyAt(i)));
2750 if (i < opCount - 1) {
2751 pw.print(',');
2752 }
2753 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002754 pw.println("]");
2755 pw.print(" ");
2756 pw.println(activeWatchers.valueAt(0));
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002757 }
2758 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002759 if (mClients.size() > 0) {
2760 needSep = true;
2761 pw.println(" Clients:");
2762 for (int i=0; i<mClients.size(); i++) {
2763 pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
2764 ClientState cs = mClients.valueAt(i);
2765 pw.print(" "); pw.println(cs);
Svet Ganovf7b47252018-02-26 11:11:27 -08002766 if (cs.mStartedOps.size() > 0) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002767 pw.println(" Started ops:");
2768 for (int j=0; j<cs.mStartedOps.size(); j++) {
2769 Op op = cs.mStartedOps.get(j);
2770 pw.print(" "); pw.print("uid="); pw.print(op.uid);
2771 pw.print(" pkg="); pw.print(op.packageName);
2772 pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
2773 }
2774 }
2775 }
2776 }
John Spurlock1af30c72014-03-10 08:33:35 -04002777 if (mAudioRestrictions.size() > 0) {
2778 boolean printedHeader = false;
2779 for (int o=0; o<mAudioRestrictions.size(); o++) {
2780 final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
2781 final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
2782 for (int i=0; i<restrictions.size(); i++) {
2783 if (!printedHeader){
2784 pw.println(" Audio Restrictions:");
2785 printedHeader = true;
2786 needSep = true;
2787 }
John Spurlock7b414672014-07-18 13:02:39 -04002788 final int usage = restrictions.keyAt(i);
John Spurlock1af30c72014-03-10 08:33:35 -04002789 pw.print(" "); pw.print(op);
John Spurlock7b414672014-07-18 13:02:39 -04002790 pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
John Spurlock1af30c72014-03-10 08:33:35 -04002791 Restriction r = restrictions.valueAt(i);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002792 pw.print(": mode="); pw.println(MODE_NAMES[r.mode]);
John Spurlock1af30c72014-03-10 08:33:35 -04002793 if (!r.exceptionPackages.isEmpty()) {
2794 pw.println(" Exceptions:");
2795 for (int j=0; j<r.exceptionPackages.size(); j++) {
2796 pw.print(" "); pw.println(r.exceptionPackages.valueAt(j));
2797 }
2798 }
2799 }
2800 }
2801 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002802 if (needSep) {
2803 pw.println();
2804 }
Svet Ganov2af57082015-07-30 08:44:20 -07002805 for (int i=0; i<mUidStates.size(); i++) {
2806 UidState uidState = mUidStates.valueAt(i);
2807
2808 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002809 pw.print(" state=");
2810 pw.println(UID_STATE_NAMES[uidState.state]);
2811 if (uidState.startNesting != 0) {
2812 pw.print(" startNesting=");
2813 pw.println(uidState.startNesting);
2814 }
Svet Ganovee438d42017-01-19 18:04:38 -08002815 needSep = true;
Svet Ganov2af57082015-07-30 08:44:20 -07002816
2817 SparseIntArray opModes = uidState.opModes;
2818 if (opModes != null) {
2819 final int opModeCount = opModes.size();
2820 for (int j = 0; j < opModeCount; j++) {
2821 final int code = opModes.keyAt(j);
2822 final int mode = opModes.valueAt(j);
2823 pw.print(" "); pw.print(AppOpsManager.opToName(code));
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002824 pw.print(": mode="); pw.println(MODE_NAMES[mode]);
Svet Ganov2af57082015-07-30 08:44:20 -07002825 }
2826 }
2827
2828 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
2829 if (pkgOps == null) {
2830 continue;
2831 }
2832
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002833 for (Ops ops : pkgOps.values()) {
2834 pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
2835 for (int j=0; j<ops.size(); j++) {
2836 Op op = ops.valueAt(j);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002837 pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002838 pw.print(" ("); pw.print(MODE_NAMES[op.mode]); pw.println("): ");
2839 dumpTimesLocked(pw,
2840 " Access: ",
2841 " ", op.time, now, sdf, date);
2842 dumpTimesLocked(pw,
2843 " Reject: ",
2844 " ", op.rejectTime, now, sdf, date);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002845 if (op.duration == -1) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002846 pw.print(" Running start at: ");
2847 TimeUtils.formatDuration(nowElapsed-op.startRealtime, pw);
2848 pw.println();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002849 } else if (op.duration != 0) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002850 pw.print(" duration=");
2851 TimeUtils.formatDuration(op.duration, pw);
2852 pw.println();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002853 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002854 if (op.startNesting != 0) {
2855 pw.print(" startNesting=");
2856 pw.println(op.startNesting);
2857 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002858 }
2859 }
2860 }
Svet Ganovee438d42017-01-19 18:04:38 -08002861 if (needSep) {
2862 pw.println();
2863 }
2864
2865 final int userRestrictionCount = mOpUserRestrictions.size();
2866 for (int i = 0; i < userRestrictionCount; i++) {
2867 IBinder token = mOpUserRestrictions.keyAt(i);
2868 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
2869 pw.println(" User restrictions for token " + token + ":");
2870
2871 final int restrictionCount = restrictionState.perUserRestrictions != null
2872 ? restrictionState.perUserRestrictions.size() : 0;
2873 if (restrictionCount > 0) {
2874 pw.println(" Restricted ops:");
2875 for (int j = 0; j < restrictionCount; j++) {
2876 int userId = restrictionState.perUserRestrictions.keyAt(j);
2877 boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
2878 if (restrictedOps == null) {
2879 continue;
2880 }
2881 StringBuilder restrictedOpsValue = new StringBuilder();
2882 restrictedOpsValue.append("[");
2883 final int restrictedOpCount = restrictedOps.length;
2884 for (int k = 0; k < restrictedOpCount; k++) {
2885 if (restrictedOps[k]) {
2886 if (restrictedOpsValue.length() > 1) {
2887 restrictedOpsValue.append(", ");
2888 }
2889 restrictedOpsValue.append(AppOpsManager.opToName(k));
2890 }
2891 }
2892 restrictedOpsValue.append("]");
2893 pw.print(" "); pw.print("user: "); pw.print(userId);
2894 pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
2895 }
2896 }
2897
2898 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
2899 ? restrictionState.perUserExcludedPackages.size() : 0;
2900 if (excludedPackageCount > 0) {
2901 pw.println(" Excluded packages:");
2902 for (int j = 0; j < excludedPackageCount; j++) {
2903 int userId = restrictionState.perUserExcludedPackages.keyAt(j);
2904 String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
2905 pw.print(" "); pw.print("user: "); pw.print(userId);
2906 pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
2907 }
2908 }
2909 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002910 }
2911 }
John Spurlock1af30c72014-03-10 08:33:35 -04002912
2913 private static final class Restriction {
2914 private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
2915 int mode;
2916 ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
2917 }
Jason Monk62062992014-05-06 09:55:28 -04002918
2919 @Override
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002920 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
Jason Monk62062992014-05-06 09:55:28 -04002921 checkSystemUid("setUserRestrictions");
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002922 Preconditions.checkNotNull(restrictions);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002923 Preconditions.checkNotNull(token);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002924 for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
Jason Monk62062992014-05-06 09:55:28 -04002925 String restriction = AppOpsManager.opToRestriction(i);
Suprabh Shukla64e0dcb2016-05-24 16:23:11 -07002926 if (restriction != null) {
2927 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
2928 userHandle, null);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002929 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002930 }
2931 }
2932
2933 @Override
Ruben Brunk29931bc2016-03-11 00:24:26 -08002934 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
2935 String[] exceptionPackages) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002936 if (Binder.getCallingPid() != Process.myPid()) {
2937 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
2938 Binder.getCallingPid(), Binder.getCallingUid(), null);
2939 }
2940 if (userHandle != UserHandle.getCallingUserId()) {
2941 if (mContext.checkCallingOrSelfPermission(Manifest.permission
2942 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
2943 && mContext.checkCallingOrSelfPermission(Manifest.permission
2944 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
2945 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
2946 + " INTERACT_ACROSS_USERS to interact cross user ");
Jason Monk62062992014-05-06 09:55:28 -04002947 }
2948 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002949 verifyIncomingOp(code);
2950 Preconditions.checkNotNull(token);
Ruben Brunk29931bc2016-03-11 00:24:26 -08002951 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002952 }
2953
2954 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
Ruben Brunk29931bc2016-03-11 00:24:26 -08002955 int userHandle, String[] exceptionPackages) {
Svet Ganov442ed572016-08-17 17:29:43 -07002956 synchronized (AppOpsService.this) {
2957 ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
2958
2959 if (restrictionState == null) {
2960 try {
2961 restrictionState = new ClientRestrictionState(token);
2962 } catch (RemoteException e) {
2963 return;
2964 }
2965 mOpUserRestrictions.put(token, restrictionState);
Ruben Brunk29931bc2016-03-11 00:24:26 -08002966 }
Svet Ganov442ed572016-08-17 17:29:43 -07002967
2968 if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002969 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07002970 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
Svet Ganov442ed572016-08-17 17:29:43 -07002971 }
2972
2973 if (restrictionState.isDefault()) {
2974 mOpUserRestrictions.remove(token);
2975 restrictionState.destroy();
2976 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08002977 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -04002978 }
2979
Svet Ganov3a95f832018-03-23 17:44:30 -07002980 private void notifyWatchersOfChange(int code, int uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002981 final ArraySet<ModeCallback> clonedCallbacks;
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002982 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002983 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002984 if (callbacks == null) {
2985 return;
2986 }
Dianne Hackborn68d76552017-02-27 15:32:03 -08002987 clonedCallbacks = new ArraySet<>(callbacks);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002988 }
2989
Svet Ganov3a95f832018-03-23 17:44:30 -07002990 notifyOpChanged(clonedCallbacks, code, uid, null);
Jason Monk62062992014-05-06 09:55:28 -04002991 }
2992
2993 @Override
2994 public void removeUser(int userHandle) throws RemoteException {
2995 checkSystemUid("removeUser");
Svet Ganov442ed572016-08-17 17:29:43 -07002996 synchronized (AppOpsService.this) {
2997 final int tokenCount = mOpUserRestrictions.size();
2998 for (int i = tokenCount - 1; i >= 0; i--) {
2999 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
3000 opRestrictions.removeUser(userHandle);
3001 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003002 removeUidsForUserLocked(userHandle);
3003 }
3004 }
3005
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003006 @Override
3007 public boolean isOperationActive(int code, int uid, String packageName) {
Svet Ganovf7b47252018-02-26 11:11:27 -08003008 if (Binder.getCallingUid() != uid) {
3009 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
3010 != PackageManager.PERMISSION_GRANTED) {
3011 return false;
3012 }
3013 }
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003014 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003015 final String resolvedPackageName = resolvePackageName(uid, packageName);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003016 if (resolvedPackageName == null) {
3017 return false;
3018 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003019 synchronized (AppOpsService.this) {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003020 for (int i = mClients.size() - 1; i >= 0; i--) {
3021 final ClientState client = mClients.valueAt(i);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003022 for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
3023 final Op op = client.mStartedOps.get(j);
3024 if (op.op == code && op.uid == uid) return true;
3025 }
3026 }
3027 }
3028 return false;
3029 }
3030
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003031 private void removeUidsForUserLocked(int userHandle) {
3032 for (int i = mUidStates.size() - 1; i >= 0; --i) {
3033 final int uid = mUidStates.keyAt(i);
3034 if (UserHandle.getUserId(uid) == userHandle) {
3035 mUidStates.removeAt(i);
3036 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003037 }
3038 }
3039
Jason Monk62062992014-05-06 09:55:28 -04003040 private void checkSystemUid(String function) {
3041 int uid = Binder.getCallingUid();
3042 if (uid != Process.SYSTEM_UID) {
3043 throw new SecurityException(function + " must by called by the system");
3044 }
3045 }
3046
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003047 private static String resolvePackageName(int uid, String packageName) {
Svet Ganov82f09bc2018-01-12 22:08:40 -08003048 if (uid == Process.ROOT_UID) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003049 return "root";
3050 } else if (uid == Process.SHELL_UID) {
3051 return "com.android.shell";
Svet Ganov82f09bc2018-01-12 22:08:40 -08003052 } else if (uid == Process.MEDIA_UID) {
3053 return "media";
3054 } else if (uid == Process.AUDIOSERVER_UID) {
3055 return "audioserver";
3056 } else if (uid == Process.CAMERASERVER_UID) {
3057 return "cameraserver";
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003058 } else if (uid == Process.SYSTEM_UID && packageName == null) {
3059 return "android";
3060 }
3061 return packageName;
3062 }
3063
Svet Ganov82f09bc2018-01-12 22:08:40 -08003064 private static int resolveUid(String packageName) {
3065 if (packageName == null) {
3066 return -1;
3067 }
3068 switch (packageName) {
3069 case "root":
3070 return Process.ROOT_UID;
3071 case "shell":
3072 return Process.SHELL_UID;
3073 case "media":
3074 return Process.MEDIA_UID;
3075 case "audioserver":
3076 return Process.AUDIOSERVER_UID;
3077 case "cameraserver":
3078 return Process.CAMERASERVER_UID;
3079 }
3080 return -1;
3081 }
3082
Svet Ganov2af57082015-07-30 08:44:20 -07003083 private static String[] getPackagesForUid(int uid) {
Svet Ganovf3807aa2015-08-02 10:09:56 -07003084 String[] packageNames = null;
Svet Ganov2af57082015-07-30 08:44:20 -07003085 try {
riddle_hsu40b300f2015-11-23 13:22:03 +08003086 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
Svet Ganov2af57082015-07-30 08:44:20 -07003087 } catch (RemoteException e) {
3088 /* ignore - local call */
3089 }
Svet Ganovf3807aa2015-08-02 10:09:56 -07003090 if (packageNames == null) {
3091 return EmptyArray.STRING;
3092 }
3093 return packageNames;
Svet Ganov2af57082015-07-30 08:44:20 -07003094 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003095
3096 private final class ClientRestrictionState implements DeathRecipient {
3097 private final IBinder token;
3098 SparseArray<boolean[]> perUserRestrictions;
3099 SparseArray<String[]> perUserExcludedPackages;
3100
3101 public ClientRestrictionState(IBinder token)
3102 throws RemoteException {
3103 token.linkToDeath(this, 0);
3104 this.token = token;
3105 }
3106
3107 public boolean setRestriction(int code, boolean restricted,
3108 String[] excludedPackages, int userId) {
3109 boolean changed = false;
3110
3111 if (perUserRestrictions == null && restricted) {
3112 perUserRestrictions = new SparseArray<>();
3113 }
3114
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003115 int[] users;
3116 if (userId == UserHandle.USER_ALL) {
3117 List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003118
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003119 users = new int[liveUsers.size()];
3120 for (int i = 0; i < liveUsers.size(); i++) {
3121 users[i] = liveUsers.get(i).id;
3122 }
3123 } else {
3124 users = new int[]{userId};
3125 }
3126
3127 if (perUserRestrictions != null) {
3128 int numUsers = users.length;
3129
3130 for (int i = 0; i < numUsers; i++) {
3131 int thisUserId = users[i];
3132
3133 boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
3134 if (userRestrictions == null && restricted) {
3135 userRestrictions = new boolean[AppOpsManager._NUM_OP];
3136 perUserRestrictions.put(thisUserId, userRestrictions);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003137 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003138 if (userRestrictions != null && userRestrictions[code] != restricted) {
3139 userRestrictions[code] = restricted;
3140 if (!restricted && isDefault(userRestrictions)) {
3141 perUserRestrictions.remove(thisUserId);
3142 userRestrictions = null;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003143 }
3144 changed = true;
3145 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003146
3147 if (userRestrictions != null) {
3148 final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
3149 if (perUserExcludedPackages == null && !noExcludedPackages) {
3150 perUserExcludedPackages = new SparseArray<>();
3151 }
3152 if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
3153 perUserExcludedPackages.get(thisUserId))) {
3154 if (noExcludedPackages) {
3155 perUserExcludedPackages.remove(thisUserId);
3156 if (perUserExcludedPackages.size() <= 0) {
3157 perUserExcludedPackages = null;
3158 }
3159 } else {
3160 perUserExcludedPackages.put(thisUserId, excludedPackages);
3161 }
3162 changed = true;
3163 }
3164 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003165 }
3166 }
3167
3168 return changed;
3169 }
3170
3171 public boolean hasRestriction(int restriction, String packageName, int userId) {
3172 if (perUserRestrictions == null) {
3173 return false;
3174 }
3175 boolean[] restrictions = perUserRestrictions.get(userId);
3176 if (restrictions == null) {
3177 return false;
3178 }
3179 if (!restrictions[restriction]) {
3180 return false;
3181 }
3182 if (perUserExcludedPackages == null) {
3183 return true;
3184 }
3185 String[] perUserExclusions = perUserExcludedPackages.get(userId);
3186 if (perUserExclusions == null) {
3187 return true;
3188 }
3189 return !ArrayUtils.contains(perUserExclusions, packageName);
3190 }
3191
3192 public void removeUser(int userId) {
3193 if (perUserExcludedPackages != null) {
3194 perUserExcludedPackages.remove(userId);
3195 if (perUserExcludedPackages.size() <= 0) {
3196 perUserExcludedPackages = null;
3197 }
3198 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003199 if (perUserRestrictions != null) {
3200 perUserRestrictions.remove(userId);
3201 if (perUserRestrictions.size() <= 0) {
3202 perUserRestrictions = null;
3203 }
3204 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003205 }
3206
3207 public boolean isDefault() {
3208 return perUserRestrictions == null || perUserRestrictions.size() <= 0;
3209 }
3210
3211 @Override
3212 public void binderDied() {
3213 synchronized (AppOpsService.this) {
3214 mOpUserRestrictions.remove(token);
3215 if (perUserRestrictions == null) {
3216 return;
3217 }
3218 final int userCount = perUserRestrictions.size();
3219 for (int i = 0; i < userCount; i++) {
3220 final boolean[] restrictions = perUserRestrictions.valueAt(i);
3221 final int restrictionCount = restrictions.length;
3222 for (int j = 0; j < restrictionCount; j++) {
3223 if (restrictions[j]) {
3224 final int changedCode = j;
Svet Ganov3a95f832018-03-23 17:44:30 -07003225 mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003226 }
3227 }
3228 }
3229 destroy();
3230 }
3231 }
3232
3233 public void destroy() {
3234 token.unlinkToDeath(this, 0);
3235 }
3236
3237 private boolean isDefault(boolean[] array) {
3238 if (ArrayUtils.isEmpty(array)) {
3239 return true;
3240 }
3241 for (boolean value : array) {
3242 if (value) {
3243 return false;
3244 }
3245 }
3246 return true;
3247 }
3248 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003249}