blob: b06454cb4bc96c3c2a95a137b205c3dc54bba737 [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;
Dianne Hackbornd5254412018-05-11 18:02:58 -070024import android.app.AppOpsManagerInternal;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070025import android.content.ContentResolver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070026import android.content.Context;
27import android.content.pm.ApplicationInfo;
28import android.content.pm.IPackageManager;
29import android.content.pm.PackageManager;
30import android.content.pm.PackageManagerInternal;
31import android.content.pm.UserInfo;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070032import android.database.ContentObserver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070033import android.media.AudioAttributes;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070034import android.net.Uri;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070035import android.os.AsyncTask;
36import android.os.Binder;
37import android.os.Bundle;
38import android.os.Handler;
39import android.os.IBinder;
40import android.os.Process;
41import android.os.RemoteException;
42import android.os.ResultReceiver;
43import android.os.ServiceManager;
44import android.os.ShellCallback;
45import android.os.ShellCommand;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070046import android.os.SystemClock;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070047import android.os.UserHandle;
48import android.os.UserManager;
49import android.os.storage.StorageManagerInternal;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070050import android.provider.Settings;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070051import android.util.ArrayMap;
52import android.util.ArraySet;
53import android.util.AtomicFile;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070054import android.util.KeyValueListParser;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070055import android.util.Slog;
56import android.util.SparseArray;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -070057import android.util.SparseBooleanArray;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070058import android.util.SparseIntArray;
59import android.util.TimeUtils;
60import android.util.Xml;
61
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070062import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080063import com.android.internal.app.IAppOpsActiveCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070064import com.android.internal.app.IAppOpsCallback;
65import com.android.internal.app.IAppOpsService;
66import com.android.internal.os.Zygote;
67import com.android.internal.util.ArrayUtils;
68import com.android.internal.util.DumpUtils;
69import com.android.internal.util.FastXmlSerializer;
70import com.android.internal.util.Preconditions;
71import com.android.internal.util.XmlUtils;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080072import com.android.internal.util.function.pooled.PooledLambda;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -050073
Philip P. Moltmanne683f192017-06-23 14:05:04 -070074import libcore.util.EmptyArray;
75
76import org.xmlpull.v1.XmlPullParser;
77import org.xmlpull.v1.XmlPullParserException;
78import org.xmlpull.v1.XmlSerializer;
79
Dianne Hackborna06de0f2012-12-11 16:34:47 -080080import java.io.File;
81import java.io.FileDescriptor;
Dianne Hackborn35654b62013-01-14 17:38:02 -080082import java.io.FileInputStream;
83import java.io.FileNotFoundException;
84import java.io.FileOutputStream;
85import java.io.IOException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080086import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +010087import java.nio.charset.StandardCharsets;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070088import java.text.SimpleDateFormat;
Dianne Hackborn35654b62013-01-14 17:38:02 -080089import java.util.ArrayList;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -070090import java.util.Arrays;
Svetoslav215b44a2015-08-04 19:03:40 -070091import java.util.Collections;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070092import java.util.Date;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080093import java.util.HashMap;
Dianne Hackbornc2293022013-02-06 23:14:49 -080094import java.util.Iterator;
Dianne Hackborn35654b62013-01-14 17:38:02 -080095import java.util.List;
Dianne Hackborn607b4142013-08-02 18:10:10 -070096import java.util.Map;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080097
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070098import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
99import static android.app.AppOpsManager.UID_STATE_CACHED;
100import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
101import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
102import static android.app.AppOpsManager._NUM_UID_STATE;
103import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
104import static android.app.AppOpsManager.UID_STATE_TOP;
105
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800106public class AppOpsService extends IAppOpsService.Stub {
107 static final String TAG = "AppOps";
Dianne Hackborn35654b62013-01-14 17:38:02 -0800108 static final boolean DEBUG = false;
109
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700110 private static final int NO_VERSION = -1;
111 /** Increment by one every time and add the corresponding upgrade logic in
112 * {@link #upgradeLocked(int)} below. The first version was 1 */
113 private static final int CURRENT_VERSION = 1;
114
Dianne Hackborn35654b62013-01-14 17:38:02 -0800115 // Write at most every 30 minutes.
116 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800117
Svet Ganov3a95f832018-03-23 17:44:30 -0700118 // Constant meaning that any UID should be matched when dispatching callbacks
119 private static final int UID_ANY = -2;
120
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700121 // Map from process states to the uid states we track.
122 private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
123 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
124 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
125 UID_STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
126 UID_STATE_FOREGROUND_SERVICE, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
127 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
128 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
129 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
130 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
131 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_BACKUP
132 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_SERVICE
133 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_RECEIVER
134 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
135 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
136 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HOME
137 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
138 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
139 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
140 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_RECENT
141 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
142 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT
143 };
144
145 static final String[] UID_STATE_NAMES = new String[] {
146 "pers ", // UID_STATE_PERSISTENT
147 "top ", // UID_STATE_TOP
148 "fgsvc", // UID_STATE_FOREGROUND_SERVICE
149 "fg ", // UID_STATE_FOREGROUND
150 "bg ", // UID_STATE_BACKGROUND
151 "cch ", // UID_STATE_CACHED
152 };
153
154 static final String[] UID_STATE_TIME_ATTRS = new String[] {
155 "tp", // UID_STATE_PERSISTENT
156 "tt", // UID_STATE_TOP
157 "tfs", // UID_STATE_FOREGROUND_SERVICE
158 "tf", // UID_STATE_FOREGROUND
159 "tb", // UID_STATE_BACKGROUND
160 "tc", // UID_STATE_CACHED
161 };
162
163 static final String[] UID_STATE_REJECT_ATTRS = new String[] {
164 "rp", // UID_STATE_PERSISTENT
165 "rt", // UID_STATE_TOP
166 "rfs", // UID_STATE_FOREGROUND_SERVICE
167 "rf", // UID_STATE_FOREGROUND
168 "rb", // UID_STATE_BACKGROUND
169 "rc", // UID_STATE_CACHED
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
Dianne Hackbornd5254412018-05-11 18:02:58 -0700176 private final AppOpsManagerInternalImpl mAppOpsManagerInternal
177 = new AppOpsManagerInternalImpl();
178
Dianne Hackborn35654b62013-01-14 17:38:02 -0800179 boolean mWriteScheduled;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800180 boolean mFastWriteScheduled;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800181 final Runnable mWriteRunner = new Runnable() {
182 public void run() {
183 synchronized (AppOpsService.this) {
184 mWriteScheduled = false;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800185 mFastWriteScheduled = false;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800186 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
187 @Override protected Void doInBackground(Void... params) {
188 writeState();
189 return null;
190 }
191 };
192 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
193 }
194 }
195 };
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800196
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700197 @VisibleForTesting
198 final SparseArray<UidState> mUidStates = new SparseArray<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800199
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700200 long mLastUptime;
201
Ruben Brunk29931bc2016-03-11 00:24:26 -0800202 /*
203 * These are app op restrictions imposed per user from various parties.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800204 */
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700205 private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
Jason Monk62062992014-05-06 09:55:28 -0400206
Dianne Hackbornd5254412018-05-11 18:02:58 -0700207 SparseIntArray mProfileOwners;
208
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700209 /**
210 * All times are in milliseconds. These constants are kept synchronized with the system
211 * global Settings. Any access to this class or its fields should be done while
212 * holding the AppOpsService lock.
213 */
214 private final class Constants extends ContentObserver {
215 // Key names stored in the settings value.
216 private static final String KEY_STATE_SETTLE_TIME = "state_settle_time";
217
218 /**
219 * How long we want for a drop in uid state to settle before applying it.
220 * @see Settings.Global#APP_OPS_CONSTANTS
221 * @see #KEY_STATE_SETTLE_TIME
222 */
223 public long STATE_SETTLE_TIME;
224
225
226 private final KeyValueListParser mParser = new KeyValueListParser(',');
227 private ContentResolver mResolver;
228
229 public Constants(Handler handler) {
230 super(handler);
231 updateConstants();
232 }
233
234 public void startMonitoring(ContentResolver resolver) {
235 mResolver = resolver;
236 mResolver.registerContentObserver(
237 Settings.Global.getUriFor(Settings.Global.DEVICE_IDLE_CONSTANTS),
238 false, this);
239 updateConstants();
240 }
241
242 @Override
243 public void onChange(boolean selfChange, Uri uri) {
244 updateConstants();
245 }
246
247 private void updateConstants() {
248 synchronized (AppOpsService.this) {
249 try {
250 if (mResolver != null) {
251 mParser.setString(Settings.Global.getString(mResolver,
252 Settings.Global.APP_OPS_CONSTANTS));
253 } else {
254 mParser.setString("");
255 }
256 } catch (IllegalArgumentException e) {
257 // Failed to parse the settings string, log this and move on
258 // with defaults.
259 Slog.e(TAG, "Bad app ops settings", e);
260 }
261
262 STATE_SETTLE_TIME = mParser.getDurationMillis(
263 KEY_STATE_SETTLE_TIME, 10 * 1000L);
264 }
265 }
266
267 void dump(PrintWriter pw) {
268 pw.println(" Settings:");
269
270 pw.print(" "); pw.print(KEY_STATE_SETTLE_TIME); pw.print("=");
271 TimeUtils.formatDuration(STATE_SETTLE_TIME, pw);
272 pw.println();
273 }
274 }
275
276 private final Constants mConstants;
277
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700278 @VisibleForTesting
279 static final class UidState {
Svet Ganov2af57082015-07-30 08:44:20 -0700280 public final int uid;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700281
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700282 public int state = UID_STATE_CACHED;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700283 public int pendingState = UID_STATE_CACHED;
284 public long pendingStateCommitTime;
285
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700286 public int startNesting;
Svet Ganov2af57082015-07-30 08:44:20 -0700287 public ArrayMap<String, Ops> pkgOps;
288 public SparseIntArray opModes;
289
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700290 // true indicates there is an interested observer, false there isn't but it has such an op
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700291 public SparseBooleanArray foregroundOps;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700292 public boolean hasForegroundWatchers;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700293
Svet Ganov2af57082015-07-30 08:44:20 -0700294 public UidState(int uid) {
295 this.uid = uid;
296 }
297
298 public void clear() {
299 pkgOps = null;
300 opModes = null;
301 }
302
303 public boolean isDefault() {
304 return (pkgOps == null || pkgOps.isEmpty())
305 && (opModes == null || opModes.size() <= 0);
306 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700307
308 int evalMode(int mode) {
309 if (mode == AppOpsManager.MODE_FOREGROUND) {
310 return state <= UID_STATE_FOREGROUND_SERVICE
311 ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
312 }
313 return mode;
314 }
315
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700316 private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
317 SparseBooleanArray which) {
318 boolean curValue = which.get(op, false);
319 ArraySet<ModeCallback> callbacks = watchers.get(op);
320 if (callbacks != null) {
321 for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
322 if ((callbacks.valueAt(cbi).mFlags
323 & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
324 hasForegroundWatchers = true;
325 curValue = true;
326 }
327 }
328 }
329 which.put(op, curValue);
330 }
331
332 public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700333 SparseBooleanArray which = null;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700334 hasForegroundWatchers = false;
335 if (opModes != null) {
336 for (int i = opModes.size() - 1; i >= 0; i--) {
337 if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
338 if (which == null) {
339 which = new SparseBooleanArray();
340 }
341 evalForegroundWatchers(opModes.keyAt(i), watchers, which);
342 }
343 }
344 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700345 if (pkgOps != null) {
346 for (int i = pkgOps.size() - 1; i >= 0; i--) {
347 Ops ops = pkgOps.valueAt(i);
348 for (int j = ops.size() - 1; j >= 0; j--) {
349 if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
350 if (which == null) {
351 which = new SparseBooleanArray();
352 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700353 evalForegroundWatchers(ops.keyAt(j), watchers, which);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700354 }
355 }
356 }
357 }
358 foregroundOps = which;
359 }
Svet Ganov2af57082015-07-30 08:44:20 -0700360 }
361
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700362 final static class Ops extends SparseArray<Op> {
363 final String packageName;
364 final UidState uidState;
365 final boolean isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800366
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700367 Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800368 packageName = _packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700369 uidState = _uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400370 isPrivileged = _isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800371 }
372 }
373
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700374 final static class Op {
375 final UidState uidState;
376 final int uid;
377 final String packageName;
378 final int op;
379 int proxyUid = -1;
380 String proxyPackageName;
381 int mode;
382 int duration;
383 long time[] = new long[_NUM_UID_STATE];
384 long rejectTime[] = new long[_NUM_UID_STATE];
385 int startNesting;
386 long startRealtime;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800387
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700388 Op(UidState _uidState, String _packageName, int _op) {
389 uidState = _uidState;
390 uid = _uidState.uid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700391 packageName = _packageName;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800392 op = _op;
David Braunf5d83192013-09-16 13:43:51 -0700393 mode = AppOpsManager.opToDefaultMode(op);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800394 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700395
396 boolean hasAnyTime() {
397 for (int i = 0; i < AppOpsManager._NUM_UID_STATE; i++) {
398 if (time[i] != 0) {
399 return true;
400 }
401 if (rejectTime[i] != 0) {
402 return true;
403 }
404 }
405 return false;
406 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700407
408 int getMode() {
409 return uidState.evalMode(mode);
410 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800411 }
412
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800413 final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
414 final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
415 final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
416 final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
Dianne Hackborn68d76552017-02-27 15:32:03 -0800417 final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800418
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700419 final class ModeCallback implements DeathRecipient {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800420 final IAppOpsCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700421 final int mWatchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700422 final int mFlags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700423 final int mCallingUid;
424 final int mCallingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800425
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700426 ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700427 int callingPid) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800428 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700429 mWatchingUid = watchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700430 mFlags = flags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700431 mCallingUid = callingUid;
432 mCallingPid = callingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800433 try {
434 mCallback.asBinder().linkToDeath(this, 0);
435 } catch (RemoteException e) {
436 }
437 }
438
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700439 public boolean isWatchingUid(int uid) {
440 return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
441 }
442
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700443 @Override
444 public String toString() {
445 StringBuilder sb = new StringBuilder(128);
446 sb.append("ModeCallback{");
447 sb.append(Integer.toHexString(System.identityHashCode(this)));
448 sb.append(" watchinguid=");
449 UserHandle.formatUid(sb, mWatchingUid);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700450 sb.append(" flags=0x");
451 sb.append(Integer.toHexString(mFlags));
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700452 sb.append(" from uid=");
453 UserHandle.formatUid(sb, mCallingUid);
454 sb.append(" pid=");
455 sb.append(mCallingPid);
456 sb.append('}');
457 return sb.toString();
458 }
459
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700460 void unlinkToDeath() {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800461 mCallback.asBinder().unlinkToDeath(this, 0);
462 }
463
464 @Override
465 public void binderDied() {
466 stopWatchingMode(mCallback);
467 }
468 }
469
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700470 final class ActiveCallback implements DeathRecipient {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800471 final IAppOpsActiveCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700472 final int mWatchingUid;
473 final int mCallingUid;
474 final int mCallingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800475
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700476 ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700477 int callingPid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800478 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700479 mWatchingUid = watchingUid;
480 mCallingUid = callingUid;
481 mCallingPid = callingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800482 try {
483 mCallback.asBinder().linkToDeath(this, 0);
484 } catch (RemoteException e) {
485 }
486 }
487
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700488 @Override
489 public String toString() {
490 StringBuilder sb = new StringBuilder(128);
491 sb.append("ActiveCallback{");
492 sb.append(Integer.toHexString(System.identityHashCode(this)));
493 sb.append(" watchinguid=");
494 UserHandle.formatUid(sb, mWatchingUid);
495 sb.append(" from uid=");
496 UserHandle.formatUid(sb, mCallingUid);
497 sb.append(" pid=");
498 sb.append(mCallingPid);
499 sb.append('}');
500 return sb.toString();
501 }
502
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700503 void destroy() {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800504 mCallback.asBinder().unlinkToDeath(this, 0);
505 }
506
507 @Override
508 public void binderDied() {
509 stopWatchingActive(mCallback);
510 }
511 }
512
Svet Ganova7a0db62018-02-27 20:08:01 -0800513 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700514
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700515 final class ClientState extends Binder implements DeathRecipient {
Svet Ganovf7b47252018-02-26 11:11:27 -0800516 final ArrayList<Op> mStartedOps = new ArrayList<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700517 final IBinder mAppToken;
518 final int mPid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700519
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700520 ClientState(IBinder appToken) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700521 mAppToken = appToken;
522 mPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -0800523 // Watch only for remote processes dying
524 if (!(appToken instanceof Binder)) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700525 try {
526 mAppToken.linkToDeath(this, 0);
527 } catch (RemoteException e) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800528 /* do nothing */
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700529 }
530 }
531 }
532
533 @Override
534 public String toString() {
535 return "ClientState{" +
536 "mAppToken=" + mAppToken +
Svet Ganovf7b47252018-02-26 11:11:27 -0800537 ", " + "pid=" + mPid +
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700538 '}';
539 }
540
541 @Override
542 public void binderDied() {
543 synchronized (AppOpsService.this) {
544 for (int i=mStartedOps.size()-1; i>=0; i--) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800545 finishOperationLocked(mStartedOps.get(i), /*finishNested*/ true);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700546 }
547 mClients.remove(mAppToken);
548 }
549 }
550 }
551
Jeff Brown6f357d32014-01-15 20:40:55 -0800552 public AppOpsService(File storagePath, Handler handler) {
Jeff Sharkey5f3e9342017-03-13 14:53:11 -0600553 LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
Dianne Hackborne17b4452018-01-10 13:15:40 -0800554 mFile = new AtomicFile(storagePath, "appops");
Jeff Brown6f357d32014-01-15 20:40:55 -0800555 mHandler = handler;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700556 mConstants = new Constants(mHandler);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800557 readState();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800558 }
David Braunf5d83192013-09-16 13:43:51 -0700559
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800560 public void publish(Context context) {
561 mContext = context;
562 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
Dianne Hackbornd5254412018-05-11 18:02:58 -0700563 LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800564 }
565
Dianne Hackborn514074f2013-02-11 10:52:46 -0800566 public void systemReady() {
567 synchronized (this) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700568 mConstants.startMonitoring(mContext.getContentResolver());
Dianne Hackborn514074f2013-02-11 10:52:46 -0800569 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700570 for (int i = mUidStates.size() - 1; i >= 0; i--) {
571 UidState uidState = mUidStates.valueAt(i);
572
573 String[] packageNames = getPackagesForUid(uidState.uid);
574 if (ArrayUtils.isEmpty(packageNames)) {
575 uidState.clear();
576 mUidStates.removeAt(i);
577 changed = true;
578 continue;
579 }
580
581 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
582 if (pkgs == null) {
583 continue;
584 }
585
Dianne Hackborn514074f2013-02-11 10:52:46 -0800586 Iterator<Ops> it = pkgs.values().iterator();
587 while (it.hasNext()) {
588 Ops ops = it.next();
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700589 int curUid = -1;
Dianne Hackborn514074f2013-02-11 10:52:46 -0800590 try {
Jeff Sharkeycd654482016-01-08 17:42:11 -0700591 curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
592 PackageManager.MATCH_UNINSTALLED_PACKAGES,
Svet Ganov2af57082015-07-30 08:44:20 -0700593 UserHandle.getUserId(ops.uidState.uid));
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700594 } catch (RemoteException ignored) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800595 }
Svet Ganov2af57082015-07-30 08:44:20 -0700596 if (curUid != ops.uidState.uid) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800597 Slog.i(TAG, "Pruning old package " + ops.packageName
Svet Ganov2af57082015-07-30 08:44:20 -0700598 + "/" + ops.uidState + ": new uid=" + curUid);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800599 it.remove();
600 changed = true;
601 }
602 }
Svet Ganov2af57082015-07-30 08:44:20 -0700603
604 if (uidState.isDefault()) {
605 mUidStates.removeAt(i);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800606 }
607 }
608 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800609 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800610 }
611 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700612
Suprabh Shuklaaef25132017-01-23 18:09:03 -0800613 PackageManagerInternal packageManagerInternal = LocalServices.getService(
614 PackageManagerInternal.class);
615 packageManagerInternal.setExternalSourcesPolicy(
616 new PackageManagerInternal.ExternalSourcesPolicy() {
617 @Override
618 public int getPackageTrustedToInstallApps(String packageName, int uid) {
619 int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
620 uid, packageName);
621 switch (appOpMode) {
622 case AppOpsManager.MODE_ALLOWED:
623 return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
624 case AppOpsManager.MODE_ERRORED:
625 return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
626 default:
627 return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
628 }
629 }
630 });
631
Sudheer Shanka2250d562016-11-07 15:41:02 -0800632 StorageManagerInternal storageManagerInternal = LocalServices.getService(
633 StorageManagerInternal.class);
634 storageManagerInternal.addExternalStoragePolicy(
635 new StorageManagerInternal.ExternalStorageMountPolicy() {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700636 @Override
637 public int getMountMode(int uid, String packageName) {
638 if (Process.isIsolated(uid)) {
639 return Zygote.MOUNT_EXTERNAL_NONE;
640 }
641 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
642 packageName) != AppOpsManager.MODE_ALLOWED) {
643 return Zygote.MOUNT_EXTERNAL_NONE;
644 }
645 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
646 packageName) != AppOpsManager.MODE_ALLOWED) {
647 return Zygote.MOUNT_EXTERNAL_READ;
648 }
649 return Zygote.MOUNT_EXTERNAL_WRITE;
650 }
651
652 @Override
653 public boolean hasExternalStorage(int uid, String packageName) {
654 final int mountMode = getMountMode(uid, packageName);
655 return mountMode == Zygote.MOUNT_EXTERNAL_READ
656 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
657 }
658 });
Dianne Hackborn514074f2013-02-11 10:52:46 -0800659 }
660
661 public void packageRemoved(int uid, String packageName) {
662 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700663 UidState uidState = mUidStates.get(uid);
664 if (uidState == null) {
665 return;
666 }
667
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800668 Ops ops = null;
Svet Ganov2af57082015-07-30 08:44:20 -0700669
670 // Remove any package state if such.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800671 if (uidState.pkgOps != null) {
672 ops = uidState.pkgOps.remove(packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700673 }
674
675 // If we just nuked the last package state check if the UID is valid.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800676 if (ops != null && uidState.pkgOps.isEmpty()
Svet Ganov2af57082015-07-30 08:44:20 -0700677 && getPackagesForUid(uid).length <= 0) {
678 mUidStates.remove(uid);
679 }
680
Svet Ganova7a0db62018-02-27 20:08:01 -0800681 // Finish ops other packages started on behalf of the package.
682 final int clientCount = mClients.size();
683 for (int i = 0; i < clientCount; i++) {
684 final ClientState client = mClients.valueAt(i);
685 if (client.mStartedOps == null) {
686 continue;
687 }
688 final int opCount = client.mStartedOps.size();
689 for (int j = opCount - 1; j >= 0; j--) {
690 final Op op = client.mStartedOps.get(j);
691 if (uid == op.uid && packageName.equals(op.packageName)) {
692 finishOperationLocked(op, /*finishNested*/ true);
693 client.mStartedOps.remove(j);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700694 if (op.startNesting <= 0) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800695 scheduleOpActiveChangedIfNeededLocked(op.op,
696 uid, packageName, false);
697 }
698 }
699 }
700 }
701
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800702 if (ops != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700703 scheduleFastWriteLocked();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800704
705 final int opCount = ops.size();
706 for (int i = 0; i < opCount; i++) {
707 final Op op = ops.valueAt(i);
708 if (op.duration == -1) {
709 scheduleOpActiveChangedIfNeededLocked(
710 op.op, op.uid, op.packageName, false);
711 }
712 }
Dianne Hackborn514074f2013-02-11 10:52:46 -0800713 }
714 }
715 }
716
717 public void uidRemoved(int uid) {
718 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700719 if (mUidStates.indexOfKey(uid) >= 0) {
720 mUidStates.remove(uid);
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800721 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800722 }
723 }
724 }
725
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700726 public void updateUidProcState(int uid, int procState) {
727 synchronized (this) {
728 final UidState uidState = getUidStateLocked(uid, true);
729 final int newState = PROCESS_STATE_TO_UID_STATE[procState];
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700730 if (uidState != null && uidState.pendingState != newState) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700731 final int oldPendingState = uidState.pendingState;
732 uidState.pendingState = newState;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700733 if (newState < uidState.state) {
734 // We are moving to a more important state, always do it immediately.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700735 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700736 } else if (uidState.pendingStateCommitTime == 0) {
737 // We are moving to a less important state for the first time,
738 // delay the application for a bit.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700739 uidState.pendingStateCommitTime = SystemClock.uptimeMillis() +
740 mConstants.STATE_SETTLE_TIME;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700741 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700742 if (uidState.startNesting != 0) {
743 // There is some actively running operation... need to find it
744 // and appropriately update its state.
745 final long now = System.currentTimeMillis();
746 for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
747 final Ops ops = uidState.pkgOps.valueAt(i);
748 for (int j = ops.size() - 1; j >= 0; j--) {
749 final Op op = ops.valueAt(j);
750 if (op.startNesting > 0) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700751 op.time[oldPendingState] = now;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700752 op.time[newState] = now;
753 }
754 }
755 }
756 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700757 }
758 }
759 }
760
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800761 public void shutdown() {
762 Slog.w(TAG, "Writing app ops before shutdown...");
Dianne Hackborn35654b62013-01-14 17:38:02 -0800763 boolean doWrite = false;
764 synchronized (this) {
765 if (mWriteScheduled) {
766 mWriteScheduled = false;
767 doWrite = true;
768 }
769 }
770 if (doWrite) {
771 writeState();
772 }
773 }
774
Dianne Hackborn72e39832013-01-18 18:36:09 -0800775 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
776 ArrayList<AppOpsManager.OpEntry> resOps = null;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700777 final long elapsedNow = SystemClock.elapsedRealtime();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800778 if (ops == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700779 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800780 for (int j=0; j<pkgOps.size(); j++) {
781 Op curOp = pkgOps.valueAt(j);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700782 long duration = curOp.duration == -1
783 ? (elapsedNow - curOp.startRealtime)
784 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800785 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700786 curOp.rejectTime, (int) duration, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700787 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800788 }
789 } else {
790 for (int j=0; j<ops.length; j++) {
791 Op curOp = pkgOps.get(ops[j]);
792 if (curOp != null) {
793 if (resOps == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700794 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800795 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700796 long duration = curOp.duration == -1
797 ? (elapsedNow - curOp.startRealtime)
798 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800799 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700800 curOp.rejectTime, (int) duration, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700801 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800802 }
803 }
804 }
805 return resOps;
806 }
807
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700808 private ArrayList<AppOpsManager.OpEntry> collectOps(SparseIntArray uidOps, int[] ops) {
809 ArrayList<AppOpsManager.OpEntry> resOps = null;
810 if (ops == null) {
811 resOps = new ArrayList<>();
812 for (int j=0; j<uidOps.size(); j++) {
813 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(j), uidOps.valueAt(j),
814 0, 0, 0, -1, null));
815 }
816 } else {
817 for (int j=0; j<ops.length; j++) {
818 int index = uidOps.indexOfKey(ops[j]);
819 if (index >= 0) {
820 if (resOps == null) {
821 resOps = new ArrayList<>();
822 }
823 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(index), uidOps.valueAt(index),
824 0, 0, 0, -1, null));
825 }
826 }
827 }
828 return resOps;
829 }
830
Dianne Hackborn35654b62013-01-14 17:38:02 -0800831 @Override
832 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
833 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
834 Binder.getCallingPid(), Binder.getCallingUid(), null);
835 ArrayList<AppOpsManager.PackageOps> res = null;
836 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700837 final int uidStateCount = mUidStates.size();
838 for (int i = 0; i < uidStateCount; i++) {
839 UidState uidState = mUidStates.valueAt(i);
840 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
841 continue;
842 }
843 ArrayMap<String, Ops> packages = uidState.pkgOps;
844 final int packageCount = packages.size();
845 for (int j = 0; j < packageCount; j++) {
846 Ops pkgOps = packages.valueAt(j);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800847 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800848 if (resOps != null) {
849 if (res == null) {
850 res = new ArrayList<AppOpsManager.PackageOps>();
851 }
852 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700853 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800854 res.add(resPackage);
855 }
856 }
857 }
858 }
859 return res;
860 }
861
862 @Override
Dianne Hackborn72e39832013-01-18 18:36:09 -0800863 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
864 int[] ops) {
865 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
866 Binder.getCallingPid(), Binder.getCallingUid(), null);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000867 String resolvedPackageName = resolvePackageName(uid, packageName);
868 if (resolvedPackageName == null) {
869 return Collections.emptyList();
870 }
Dianne Hackborn72e39832013-01-18 18:36:09 -0800871 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -0700872 Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
873 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800874 if (pkgOps == null) {
875 return null;
876 }
877 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
878 if (resOps == null) {
879 return null;
880 }
881 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
882 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700883 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800884 res.add(resPackage);
885 return res;
886 }
887 }
888
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700889 @Override
890 public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
891 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
892 Binder.getCallingPid(), Binder.getCallingUid(), null);
893 synchronized (this) {
894 UidState uidState = getUidStateLocked(uid, false);
895 if (uidState == null) {
896 return null;
897 }
898 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState.opModes, ops);
899 if (resOps == null) {
900 return null;
901 }
902 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
903 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
904 null, uidState.uid, resOps);
905 res.add(resPackage);
906 return res;
907 }
908 }
909
Dianne Hackborn607b4142013-08-02 18:10:10 -0700910 private void pruneOp(Op op, int uid, String packageName) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700911 if (!op.hasAnyTime()) {
Yohei Yukawaa965d652017-10-12 15:02:26 -0700912 Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
913 false /* uidMismatchExpected */);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700914 if (ops != null) {
915 ops.remove(op.op);
916 if (ops.size() <= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -0700917 UidState uidState = ops.uidState;
918 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700919 if (pkgOps != null) {
920 pkgOps.remove(ops.packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700921 if (pkgOps.isEmpty()) {
922 uidState.pkgOps = null;
923 }
924 if (uidState.isDefault()) {
925 mUidStates.remove(uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700926 }
927 }
928 }
929 }
930 }
931 }
932
Dianne Hackbornd5254412018-05-11 18:02:58 -0700933 void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
934 if (callingPid == Process.myPid()) {
935 return;
936 }
937 final int callingUser = UserHandle.getUserId(callingUid);
938 synchronized (this) {
939 if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
940 if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
941 // Profile owners are allowed to change modes but only for apps
942 // within their user.
943 return;
944 }
945 }
946 }
947 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
948 Binder.getCallingPid(), Binder.getCallingUid(), null);
949 }
950
Dianne Hackborn72e39832013-01-18 18:36:09 -0800951 @Override
Svet Ganov2af57082015-07-30 08:44:20 -0700952 public void setUidMode(int code, int uid, int mode) {
Dianne Hackbornd5254412018-05-11 18:02:58 -0700953 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Svet Ganov2af57082015-07-30 08:44:20 -0700954 verifyIncomingOp(code);
955 code = AppOpsManager.opToSwitch(code);
956
957 synchronized (this) {
958 final int defaultMode = AppOpsManager.opToDefaultMode(code);
959
960 UidState uidState = getUidStateLocked(uid, false);
961 if (uidState == null) {
962 if (mode == defaultMode) {
963 return;
964 }
965 uidState = new UidState(uid);
966 uidState.opModes = new SparseIntArray();
967 uidState.opModes.put(code, mode);
968 mUidStates.put(uid, uidState);
969 scheduleWriteLocked();
970 } else if (uidState.opModes == null) {
971 if (mode != defaultMode) {
972 uidState.opModes = new SparseIntArray();
973 uidState.opModes.put(code, mode);
974 scheduleWriteLocked();
975 }
976 } else {
977 if (uidState.opModes.get(code) == mode) {
978 return;
979 }
980 if (mode == defaultMode) {
981 uidState.opModes.delete(code);
982 if (uidState.opModes.size() <= 0) {
983 uidState.opModes = null;
984 }
985 } else {
986 uidState.opModes.put(code, mode);
987 }
988 scheduleWriteLocked();
989 }
990 }
991
Svetoslav215b44a2015-08-04 19:03:40 -0700992 String[] uidPackageNames = getPackagesForUid(uid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800993 ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
Svet Ganov2af57082015-07-30 08:44:20 -0700994
riddle_hsu40b300f2015-11-23 13:22:03 +0800995 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800996 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -0700997 if (callbacks != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700998 final int callbackCount = callbacks.size();
999 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001000 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08001001 ArraySet<String> changedPackages = new ArraySet<>();
1002 Collections.addAll(changedPackages, uidPackageNames);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001003 if (callbackSpecs == null) {
1004 callbackSpecs = new ArrayMap<>();
1005 }
riddle_hsu40b300f2015-11-23 13:22:03 +08001006 callbackSpecs.put(callback, changedPackages);
1007 }
1008 }
1009
1010 for (String uidPackageName : uidPackageNames) {
1011 callbacks = mPackageModeWatchers.get(uidPackageName);
1012 if (callbacks != null) {
1013 if (callbackSpecs == null) {
1014 callbackSpecs = new ArrayMap<>();
Svet Ganov2af57082015-07-30 08:44:20 -07001015 }
riddle_hsu40b300f2015-11-23 13:22:03 +08001016 final int callbackCount = callbacks.size();
1017 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001018 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08001019 ArraySet<String> changedPackages = callbackSpecs.get(callback);
1020 if (changedPackages == null) {
1021 changedPackages = new ArraySet<>();
1022 callbackSpecs.put(callback, changedPackages);
1023 }
1024 changedPackages.add(uidPackageName);
1025 }
Svet Ganov2af57082015-07-30 08:44:20 -07001026 }
1027 }
1028 }
1029
1030 if (callbackSpecs == null) {
1031 return;
1032 }
1033
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001034 for (int i = 0; i < callbackSpecs.size(); i++) {
1035 final ModeCallback callback = callbackSpecs.keyAt(i);
1036 final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
1037 if (reportedPackageNames == null) {
1038 mHandler.sendMessage(PooledLambda.obtainMessage(
1039 AppOpsService::notifyOpChanged,
1040 this, callback, code, uid, (String) null));
1041
1042 } else {
1043 final int reportedPackageCount = reportedPackageNames.size();
1044 for (int j = 0; j < reportedPackageCount; j++) {
1045 final String reportedPackageName = reportedPackageNames.valueAt(j);
1046 mHandler.sendMessage(PooledLambda.obtainMessage(
1047 AppOpsService::notifyOpChanged,
1048 this, callback, code, uid, reportedPackageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001049 }
1050 }
Svet Ganov2af57082015-07-30 08:44:20 -07001051 }
1052 }
1053
1054 @Override
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001055 public void setMode(int code, int uid, String packageName, int mode) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001056 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001057 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001058 ArraySet<ModeCallback> repCbs = null;
Dianne Hackbornc2293022013-02-06 23:14:49 -08001059 code = AppOpsManager.opToSwitch(code);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001060 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001061 UidState uidState = getUidStateLocked(uid, false);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001062 Op op = getOpLocked(code, uid, packageName, true);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001063 if (op != null) {
1064 if (op.mode != mode) {
1065 op.mode = mode;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001066 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001067 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001068 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001069 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001070 if (cbs != null) {
1071 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001072 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001073 }
1074 repCbs.addAll(cbs);
1075 }
1076 cbs = mPackageModeWatchers.get(packageName);
1077 if (cbs != null) {
1078 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001079 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001080 }
1081 repCbs.addAll(cbs);
1082 }
David Braunf5d83192013-09-16 13:43:51 -07001083 if (mode == AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001084 // If going into the default mode, prune this op
1085 // if there is nothing else interesting in it.
Dianne Hackborn607b4142013-08-02 18:10:10 -07001086 pruneOp(op, uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001087 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001088 scheduleFastWriteLocked();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001089 }
1090 }
1091 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001092 if (repCbs != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001093 mHandler.sendMessage(PooledLambda.obtainMessage(
1094 AppOpsService::notifyOpChanged,
1095 this, repCbs, code, uid, packageName));
Dianne Hackbornc2293022013-02-06 23:14:49 -08001096 }
1097 }
1098
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001099 private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
1100 int uid, String packageName) {
1101 for (int i = 0; i < callbacks.size(); i++) {
1102 final ModeCallback callback = callbacks.valueAt(i);
1103 notifyOpChanged(callback, code, uid, packageName);
1104 }
1105 }
1106
1107 private void notifyOpChanged(ModeCallback callback, int code,
1108 int uid, String packageName) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001109 if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001110 return;
1111 }
1112 // There are components watching for mode changes such as window manager
1113 // and location manager which are in our process. The callbacks in these
1114 // components may require permissions our remote caller does not have.
1115 final long identity = Binder.clearCallingIdentity();
1116 try {
1117 callback.mCallback.opChanged(code, uid, packageName);
1118 } catch (RemoteException e) {
1119 /* ignore */
1120 } finally {
1121 Binder.restoreCallingIdentity(identity);
1122 }
1123 }
1124
1125 private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
1126 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
1127 int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001128 if (cbs == null) {
1129 return callbacks;
1130 }
1131 if (callbacks == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001132 callbacks = new HashMap<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001133 }
Svet Ganov2af57082015-07-30 08:44:20 -07001134 boolean duplicate = false;
Dianne Hackborn68d76552017-02-27 15:32:03 -08001135 final int N = cbs.size();
1136 for (int i=0; i<N; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001137 ModeCallback cb = cbs.valueAt(i);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001138 ArrayList<ChangeRec> reports = callbacks.get(cb);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001139 if (reports == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001140 reports = new ArrayList<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001141 callbacks.put(cb, reports);
Svet Ganov2af57082015-07-30 08:44:20 -07001142 } else {
1143 final int reportCount = reports.size();
1144 for (int j = 0; j < reportCount; j++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001145 ChangeRec report = reports.get(j);
1146 if (report.op == op && report.pkg.equals(packageName)) {
Svet Ganov2af57082015-07-30 08:44:20 -07001147 duplicate = true;
1148 break;
1149 }
1150 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001151 }
Svet Ganov2af57082015-07-30 08:44:20 -07001152 if (!duplicate) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001153 reports.add(new ChangeRec(op, uid, packageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001154 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001155 }
1156 return callbacks;
1157 }
1158
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001159 static final class ChangeRec {
1160 final int op;
1161 final int uid;
1162 final String pkg;
1163
1164 ChangeRec(int _op, int _uid, String _pkg) {
1165 op = _op;
1166 uid = _uid;
1167 pkg = _pkg;
1168 }
1169 }
1170
Dianne Hackborn607b4142013-08-02 18:10:10 -07001171 @Override
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001172 public void resetAllModes(int reqUserId, String reqPackageName) {
1173 final int callingPid = Binder.getCallingPid();
1174 final int callingUid = Binder.getCallingUid();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001175 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
1176 true, true, "resetAllModes", null);
Svet Ganov2af57082015-07-30 08:44:20 -07001177
1178 int reqUid = -1;
1179 if (reqPackageName != null) {
1180 try {
1181 reqUid = AppGlobals.getPackageManager().getPackageUid(
Jeff Sharkeycd654482016-01-08 17:42:11 -07001182 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
Svet Ganov2af57082015-07-30 08:44:20 -07001183 } catch (RemoteException e) {
1184 /* ignore - local call */
1185 }
1186 }
1187
Dianne Hackbornd5254412018-05-11 18:02:58 -07001188 enforceManageAppOpsModes(callingPid, callingUid, reqUid);
1189
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001190 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001191 synchronized (this) {
1192 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -07001193 for (int i = mUidStates.size() - 1; i >= 0; i--) {
1194 UidState uidState = mUidStates.valueAt(i);
1195
1196 SparseIntArray opModes = uidState.opModes;
1197 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
1198 final int uidOpCount = opModes.size();
1199 for (int j = uidOpCount - 1; j >= 0; j--) {
1200 final int code = opModes.keyAt(j);
1201 if (AppOpsManager.opAllowsReset(code)) {
1202 opModes.removeAt(j);
1203 if (opModes.size() <= 0) {
1204 uidState.opModes = null;
1205 }
1206 for (String packageName : getPackagesForUid(uidState.uid)) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001207 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001208 mOpModeWatchers.get(code));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001209 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001210 mPackageModeWatchers.get(packageName));
1211 }
1212 }
1213 }
1214 }
1215
1216 if (uidState.pkgOps == null) {
1217 continue;
1218 }
1219
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001220 if (reqUserId != UserHandle.USER_ALL
Svet Ganov2af57082015-07-30 08:44:20 -07001221 && reqUserId != UserHandle.getUserId(uidState.uid)) {
Alexandra Gherghinad6a98972014-08-04 17:05:34 +01001222 // Skip any ops for a different user
1223 continue;
1224 }
Svet Ganov2af57082015-07-30 08:44:20 -07001225
1226 Map<String, Ops> packages = uidState.pkgOps;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001227 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001228 boolean uidChanged = false;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001229 while (it.hasNext()) {
1230 Map.Entry<String, Ops> ent = it.next();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001231 String packageName = ent.getKey();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001232 if (reqPackageName != null && !reqPackageName.equals(packageName)) {
1233 // Skip any ops for a different package
1234 continue;
1235 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001236 Ops pkgOps = ent.getValue();
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001237 for (int j=pkgOps.size()-1; j>=0; j--) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001238 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn8828d3a2013-09-25 16:47:10 -07001239 if (AppOpsManager.opAllowsReset(curOp.op)
1240 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
David Braunf5d83192013-09-16 13:43:51 -07001241 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001242 changed = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001243 uidChanged = true;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001244 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001245 mOpModeWatchers.get(curOp.op));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001246 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001247 mPackageModeWatchers.get(packageName));
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001248 if (!curOp.hasAnyTime()) {
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001249 pkgOps.removeAt(j);
1250 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001251 }
1252 }
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001253 if (pkgOps.size() == 0) {
1254 it.remove();
1255 }
1256 }
Svet Ganov2af57082015-07-30 08:44:20 -07001257 if (uidState.isDefault()) {
1258 mUidStates.remove(uidState.uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001259 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001260 if (uidChanged) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001261 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001262 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001263 }
Svet Ganov2af57082015-07-30 08:44:20 -07001264
Dianne Hackborn607b4142013-08-02 18:10:10 -07001265 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001266 scheduleFastWriteLocked();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001267 }
1268 }
1269 if (callbacks != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001270 for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
1271 ModeCallback cb = ent.getKey();
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001272 ArrayList<ChangeRec> reports = ent.getValue();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001273 for (int i=0; i<reports.size(); i++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001274 ChangeRec rep = reports.get(i);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001275 mHandler.sendMessage(PooledLambda.obtainMessage(
1276 AppOpsService::notifyOpChanged,
1277 this, cb, rep.op, rep.uid, rep.pkg));
Dianne Hackborn607b4142013-08-02 18:10:10 -07001278 }
1279 }
1280 }
1281 }
1282
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001283 private void evalAllForegroundOpsLocked() {
1284 for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
1285 final UidState uidState = mUidStates.valueAt(uidi);
1286 if (uidState.foregroundOps != null) {
1287 uidState.evalForegroundOps(mOpModeWatchers);
1288 }
1289 }
1290 }
1291
Dianne Hackbornc2293022013-02-06 23:14:49 -08001292 @Override
1293 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001294 startWatchingModeWithFlags(op, packageName, 0, callback);
1295 }
1296
1297 @Override
1298 public void startWatchingModeWithFlags(int op, String packageName, int flags,
1299 IAppOpsCallback callback) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001300 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001301 final int callingUid = Binder.getCallingUid();
1302 final int callingPid = Binder.getCallingPid();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001303 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1304 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001305 watchedUid = callingUid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001306 }
1307 Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
1308 AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001309 if (callback == null) {
1310 return;
1311 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001312 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001313 op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001314 ModeCallback cb = mModeWatchers.get(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001315 if (cb == null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001316 cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001317 mModeWatchers.put(callback.asBinder(), cb);
1318 }
1319 if (op != AppOpsManager.OP_NONE) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001320 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001321 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001322 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001323 mOpModeWatchers.put(op, cbs);
1324 }
1325 cbs.add(cb);
1326 }
1327 if (packageName != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001328 ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001329 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001330 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001331 mPackageModeWatchers.put(packageName, cbs);
1332 }
1333 cbs.add(cb);
1334 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001335 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001336 }
1337 }
1338
1339 @Override
1340 public void stopWatchingMode(IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001341 if (callback == null) {
1342 return;
1343 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001344 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001345 ModeCallback cb = mModeWatchers.remove(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001346 if (cb != null) {
1347 cb.unlinkToDeath();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001348 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001349 ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001350 cbs.remove(cb);
1351 if (cbs.size() <= 0) {
1352 mOpModeWatchers.removeAt(i);
1353 }
1354 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001355 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001356 ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001357 cbs.remove(cb);
1358 if (cbs.size() <= 0) {
1359 mPackageModeWatchers.removeAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001360 }
1361 }
1362 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001363 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001364 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001365 }
1366
1367 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001368 public IBinder getToken(IBinder clientToken) {
1369 synchronized (this) {
1370 ClientState cs = mClients.get(clientToken);
1371 if (cs == null) {
1372 cs = new ClientState(clientToken);
1373 mClients.put(clientToken, cs);
1374 }
1375 return cs;
1376 }
1377 }
1378
1379 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -08001380 public int checkOperation(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001381 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001382 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001383 String resolvedPackageName = resolvePackageName(uid, packageName);
1384 if (resolvedPackageName == null) {
1385 return AppOpsManager.MODE_IGNORED;
1386 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001387 synchronized (this) {
Svet Ganov442ed572016-08-17 17:29:43 -07001388 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001389 return AppOpsManager.MODE_IGNORED;
1390 }
Svet Ganov2af57082015-07-30 08:44:20 -07001391 code = AppOpsManager.opToSwitch(code);
1392 UidState uidState = getUidStateLocked(uid, false);
Svet Ganovee438d42017-01-19 18:04:38 -08001393 if (uidState != null && uidState.opModes != null
1394 && uidState.opModes.indexOfKey(code) >= 0) {
1395 return uidState.opModes.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001396 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001397 Op op = getOpLocked(code, uid, resolvedPackageName, false);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001398 if (op == null) {
David Braunf5d83192013-09-16 13:43:51 -07001399 return AppOpsManager.opToDefaultMode(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001400 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001401 return op.mode;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001402 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001403 }
1404
1405 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001406 public int checkAudioOperation(int code, int usage, int uid, String packageName) {
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00001407 boolean suspended;
1408 try {
1409 suspended = isPackageSuspendedForUser(packageName, uid);
1410 } catch (IllegalArgumentException ex) {
1411 // Package not found.
1412 suspended = false;
1413 }
1414
1415 if (suspended) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001416 Slog.i(TAG, "Audio disabled for suspended package=" + packageName + " for uid=" + uid);
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001417 return AppOpsManager.MODE_IGNORED;
1418 }
1419
John Spurlock1af30c72014-03-10 08:33:35 -04001420 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001421 final int mode = checkRestrictionLocked(code, usage, uid, packageName);
John Spurlock1af30c72014-03-10 08:33:35 -04001422 if (mode != AppOpsManager.MODE_ALLOWED) {
1423 return mode;
1424 }
1425 }
1426 return checkOperation(code, uid, packageName);
1427 }
1428
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001429 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001430 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001431 return AppGlobals.getPackageManager().isPackageSuspendedForUser(
1432 pkg, UserHandle.getUserId(uid));
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001433 } catch (RemoteException re) {
1434 throw new SecurityException("Could not talk to package manager service");
1435 }
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001436 }
1437
John Spurlock7b414672014-07-18 13:02:39 -04001438 private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
1439 final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1440 if (usageRestrictions != null) {
1441 final Restriction r = usageRestrictions.get(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001442 if (r != null && !r.exceptionPackages.contains(packageName)) {
1443 return r.mode;
1444 }
1445 }
1446 return AppOpsManager.MODE_ALLOWED;
1447 }
1448
1449 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001450 public void setAudioRestriction(int code, int usage, int uid, int mode,
John Spurlock1af30c72014-03-10 08:33:35 -04001451 String[] exceptionPackages) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001452 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
John Spurlock1af30c72014-03-10 08:33:35 -04001453 verifyIncomingUid(uid);
1454 verifyIncomingOp(code);
1455 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001456 SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1457 if (usageRestrictions == null) {
1458 usageRestrictions = new SparseArray<Restriction>();
1459 mAudioRestrictions.put(code, usageRestrictions);
John Spurlock1af30c72014-03-10 08:33:35 -04001460 }
John Spurlock7b414672014-07-18 13:02:39 -04001461 usageRestrictions.remove(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001462 if (mode != AppOpsManager.MODE_ALLOWED) {
1463 final Restriction r = new Restriction();
1464 r.mode = mode;
1465 if (exceptionPackages != null) {
1466 final int N = exceptionPackages.length;
1467 r.exceptionPackages = new ArraySet<String>(N);
1468 for (int i = 0; i < N; i++) {
1469 final String pkg = exceptionPackages[i];
1470 if (pkg != null) {
1471 r.exceptionPackages.add(pkg.trim());
1472 }
1473 }
1474 }
John Spurlock7b414672014-07-18 13:02:39 -04001475 usageRestrictions.put(usage, r);
John Spurlock1af30c72014-03-10 08:33:35 -04001476 }
1477 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001478
1479 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07001480 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
John Spurlock1af30c72014-03-10 08:33:35 -04001481 }
1482
1483 @Override
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001484 public int checkPackage(int uid, String packageName) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001485 Preconditions.checkNotNull(packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001486 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001487 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
1488 true /* uidMismatchExpected */);
1489 if (ops != null) {
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001490 return AppOpsManager.MODE_ALLOWED;
1491 } else {
1492 return AppOpsManager.MODE_ERRORED;
1493 }
1494 }
1495 }
1496
1497 @Override
Svet Ganov99b60432015-06-27 13:15:22 -07001498 public int noteProxyOperation(int code, String proxyPackageName,
1499 int proxiedUid, String proxiedPackageName) {
1500 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001501 final int proxyUid = Binder.getCallingUid();
1502 String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
1503 if (resolveProxyPackageName == null) {
1504 return AppOpsManager.MODE_IGNORED;
1505 }
1506 final int proxyMode = noteOperationUnchecked(code, proxyUid,
1507 resolveProxyPackageName, -1, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001508 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
1509 return proxyMode;
1510 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001511 String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
1512 if (resolveProxiedPackageName == null) {
1513 return AppOpsManager.MODE_IGNORED;
1514 }
1515 return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
1516 proxyMode, resolveProxyPackageName);
Svet Ganov99b60432015-06-27 13:15:22 -07001517 }
1518
1519 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001520 public int noteOperation(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001521 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001522 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001523 String resolvedPackageName = resolvePackageName(uid, packageName);
1524 if (resolvedPackageName == null) {
1525 return AppOpsManager.MODE_IGNORED;
1526 }
1527 return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001528 }
1529
1530 private int noteOperationUnchecked(int code, int uid, String packageName,
1531 int proxyUid, String proxyPackageName) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001532 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001533 final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001534 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001535 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001536 if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001537 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001538 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001539 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001540 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001541 if (isOpRestrictedLocked(uid, code, packageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001542 return AppOpsManager.MODE_IGNORED;
1543 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001544 final UidState uidState = ops.uidState;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001545 if (op.duration == -1) {
1546 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001547 + " code " + code + " time=" + op.time[uidState.state]
1548 + " duration=" + op.duration);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001549 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001550 op.duration = 0;
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001551 final int switchCode = AppOpsManager.opToSwitch(code);
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001552 // If there is a non-default per UID policy (we set UID op mode only if
1553 // non-default) it takes over, otherwise use the per package policy.
1554 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001555 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganov2af57082015-07-30 08:44:20 -07001556 if (uidMode != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001557 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001558 + switchCode + " (" + code + ") uid " + uid + " package "
1559 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001560 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov2af57082015-07-30 08:44:20 -07001561 return uidMode;
1562 }
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001563 } else {
1564 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001565 final int mode = switchOp.getMode();
1566 if (mode != AppOpsManager.MODE_ALLOWED) {
1567 if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001568 + switchCode + " (" + code + ") uid " + uid + " package "
1569 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001570 op.rejectTime[uidState.state] = System.currentTimeMillis();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001571 return mode;
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001572 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001573 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001574 if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001575 + " package " + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001576 op.time[uidState.state] = System.currentTimeMillis();
1577 op.rejectTime[uidState.state] = 0;
Svet Ganov99b60432015-06-27 13:15:22 -07001578 op.proxyUid = proxyUid;
1579 op.proxyPackageName = proxyPackageName;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001580 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001581 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001582 }
1583
1584 @Override
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001585 public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001586 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001587 final int callingUid = Binder.getCallingUid();
1588 final int callingPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -08001589 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1590 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001591 watchedUid = callingUid;
Svet Ganovf7b47252018-02-26 11:11:27 -08001592 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001593 if (ops != null) {
1594 Preconditions.checkArrayElementsInRange(ops, 0,
1595 AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
1596 }
1597 if (callback == null) {
1598 return;
1599 }
1600 synchronized (this) {
1601 SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
1602 if (callbacks == null) {
1603 callbacks = new SparseArray<>();
1604 mActiveWatchers.put(callback.asBinder(), callbacks);
1605 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001606 final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
1607 callingUid, callingPid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001608 for (int op : ops) {
1609 callbacks.put(op, activeCallback);
1610 }
1611 }
1612 }
1613
1614 @Override
1615 public void stopWatchingActive(IAppOpsActiveCallback callback) {
1616 if (callback == null) {
1617 return;
1618 }
1619 synchronized (this) {
1620 final SparseArray<ActiveCallback> activeCallbacks =
1621 mActiveWatchers.remove(callback.asBinder());
1622 if (activeCallbacks == null) {
1623 return;
1624 }
1625 final int callbackCount = activeCallbacks.size();
1626 for (int i = 0; i < callbackCount; i++) {
1627 // Apps ops are mapped to a singleton
1628 if (i == 0) {
1629 activeCallbacks.valueAt(i).destroy();
1630 }
1631 }
1632 }
1633 }
1634
1635 @Override
Svet Ganovf7b47252018-02-26 11:11:27 -08001636 public int startOperation(IBinder token, int code, int uid, String packageName,
1637 boolean startIfModeDefault) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001638 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001639 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001640 String resolvedPackageName = resolvePackageName(uid, packageName);
1641 if (resolvedPackageName == null) {
1642 return AppOpsManager.MODE_IGNORED;
1643 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001644 ClientState client = (ClientState)token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001645 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001646 final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001647 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001648 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001649 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001650 + " package " + resolvedPackageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001651 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001652 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001653 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001654 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001655 return AppOpsManager.MODE_IGNORED;
1656 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001657 final int switchCode = AppOpsManager.opToSwitch(code);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001658 final UidState uidState = ops.uidState;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001659 // If there is a non-default per UID policy (we set UID op mode only if
1660 // non-default) it takes over, otherwise use the per package policy.
1661 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001662 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganovf7b47252018-02-26 11:11:27 -08001663 if (uidMode != AppOpsManager.MODE_ALLOWED
1664 && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001665 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001666 + switchCode + " (" + code + ") uid " + uid + " package "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001667 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001668 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov2af57082015-07-30 08:44:20 -07001669 return uidMode;
1670 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001671 } else {
1672 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001673 final int mode = switchOp.getMode();
1674 if (mode != AppOpsManager.MODE_ALLOWED
1675 && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
1676 if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001677 + switchCode + " (" + code + ") uid " + uid + " package "
1678 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001679 op.rejectTime[uidState.state] = System.currentTimeMillis();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001680 return mode;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001681 }
Svet Ganov2af57082015-07-30 08:44:20 -07001682 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001683 if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001684 + " package " + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001685 if (op.startNesting == 0) {
1686 op.startRealtime = SystemClock.elapsedRealtime();
1687 op.time[uidState.state] = System.currentTimeMillis();
1688 op.rejectTime[uidState.state] = 0;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001689 op.duration = -1;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001690 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001691 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001692 op.startNesting++;
1693 uidState.startNesting++;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001694 if (client.mStartedOps != null) {
1695 client.mStartedOps.add(op);
1696 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001697 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001698
1699 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001700 }
1701
1702 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001703 public void finishOperation(IBinder token, int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001704 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001705 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001706 String resolvedPackageName = resolvePackageName(uid, packageName);
1707 if (resolvedPackageName == null) {
1708 return;
1709 }
1710 if (!(token instanceof ClientState)) {
1711 return;
1712 }
1713 ClientState client = (ClientState) token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001714 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001715 Op op = getOpLocked(code, uid, resolvedPackageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001716 if (op == null) {
1717 return;
1718 }
Svet Ganovf7b47252018-02-26 11:11:27 -08001719 if (!client.mStartedOps.remove(op)) {
Svet Ganovf5d5af12018-03-18 11:51:17 -07001720 // We finish ops when packages get removed to guarantee no dangling
1721 // started ops. However, some part of the system may asynchronously
1722 // finish ops for an already gone package. Hence, finishing an op
1723 // for a non existing package is fine and we don't log as a wtf.
1724 final long identity = Binder.clearCallingIdentity();
1725 try {
1726 if (LocalServices.getService(PackageManagerInternal.class).getPackageUid(
1727 resolvedPackageName, 0, UserHandle.getUserId(uid)) < 0) {
1728 Slog.i(TAG, "Finishing op=" + AppOpsManager.opToName(code)
1729 + " for non-existing package=" + resolvedPackageName
1730 + " in uid=" + uid);
1731 return;
1732 }
1733 } finally {
1734 Binder.restoreCallingIdentity(identity);
1735 }
1736 Slog.wtf(TAG, "Operation not started: uid=" + op.uid + " pkg="
1737 + op.packageName + " op=" + AppOpsManager.opToName(op.op));
Svet Ganov31d83ae2018-03-15 10:45:56 -07001738 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001739 }
Svet Ganova7a0db62018-02-27 20:08:01 -08001740 finishOperationLocked(op, /*finishNested*/ false);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001741 if (op.startNesting <= 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001742 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
1743 }
1744 }
1745 }
1746
1747 private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
1748 boolean active) {
1749 ArraySet<ActiveCallback> dispatchedCallbacks = null;
1750 final int callbackListCount = mActiveWatchers.size();
1751 for (int i = 0; i < callbackListCount; i++) {
1752 final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
1753 ActiveCallback callback = callbacks.get(code);
1754 if (callback != null) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001755 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001756 continue;
1757 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001758 if (dispatchedCallbacks == null) {
1759 dispatchedCallbacks = new ArraySet<>();
1760 }
1761 dispatchedCallbacks.add(callback);
1762 }
1763 }
1764 if (dispatchedCallbacks == null) {
1765 return;
1766 }
1767 mHandler.sendMessage(PooledLambda.obtainMessage(
1768 AppOpsService::notifyOpActiveChanged,
1769 this, dispatchedCallbacks, code, uid, packageName, active));
1770 }
1771
1772 private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
1773 int code, int uid, String packageName, boolean active) {
1774 // There are components watching for mode changes such as window manager
1775 // and location manager which are in our process. The callbacks in these
1776 // components may require permissions our remote caller does not have.
1777 final long identity = Binder.clearCallingIdentity();
1778 try {
1779 final int callbackCount = callbacks.size();
1780 for (int i = 0; i < callbackCount; i++) {
1781 final ActiveCallback callback = callbacks.valueAt(i);
1782 try {
1783 callback.mCallback.opActiveChanged(code, uid, packageName, active);
1784 } catch (RemoteException e) {
1785 /* do nothing */
1786 }
1787 }
1788 } finally {
1789 Binder.restoreCallingIdentity(identity);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001790 }
1791 }
1792
Svet Ganovb9d71a62015-04-30 10:38:13 -07001793 @Override
1794 public int permissionToOpCode(String permission) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001795 if (permission == null) {
1796 return AppOpsManager.OP_NONE;
1797 }
Svet Ganovb9d71a62015-04-30 10:38:13 -07001798 return AppOpsManager.permissionToOpCode(permission);
1799 }
1800
Svet Ganova7a0db62018-02-27 20:08:01 -08001801 void finishOperationLocked(Op op, boolean finishNested) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001802 if (op.startNesting <= 1 || finishNested) {
1803 if (op.startNesting == 1 || finishNested) {
1804 op.duration = (int)(SystemClock.elapsedRealtime() - op.startRealtime);
1805 op.time[op.uidState.state] = System.currentTimeMillis();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001806 } else {
1807 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
1808 + op.packageName + " code " + op.op + " time=" + op.time
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001809 + " duration=" + op.duration + " nesting=" + op.startNesting);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001810 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001811 if (op.startNesting >= 1) {
1812 op.uidState.startNesting -= op.startNesting;
1813 }
1814 op.startNesting = 0;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001815 } else {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001816 op.startNesting--;
1817 op.uidState.startNesting--;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001818 }
1819 }
1820
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001821 private void verifyIncomingUid(int uid) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001822 if (uid == Binder.getCallingUid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001823 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001824 }
1825 if (Binder.getCallingPid() == Process.myPid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001826 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001827 }
1828 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
1829 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001830 }
1831
Dianne Hackborn961321f2013-02-05 17:22:41 -08001832 private void verifyIncomingOp(int op) {
1833 if (op >= 0 && op < AppOpsManager._NUM_OP) {
1834 return;
1835 }
1836 throw new IllegalArgumentException("Bad operation #" + op);
1837 }
1838
Svet Ganov2af57082015-07-30 08:44:20 -07001839 private UidState getUidStateLocked(int uid, boolean edit) {
1840 UidState uidState = mUidStates.get(uid);
1841 if (uidState == null) {
1842 if (!edit) {
1843 return null;
1844 }
1845 uidState = new UidState(uid);
1846 mUidStates.put(uid, uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001847 } else {
1848 if (uidState.pendingStateCommitTime != 0) {
1849 if (uidState.pendingStateCommitTime < mLastUptime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001850 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001851 } else {
1852 mLastUptime = SystemClock.uptimeMillis();
1853 if (uidState.pendingStateCommitTime < mLastUptime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001854 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001855 }
1856 }
1857 }
Svet Ganov2af57082015-07-30 08:44:20 -07001858 }
1859 return uidState;
1860 }
1861
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001862 private void commitUidPendingStateLocked(UidState uidState) {
1863 uidState.state = uidState.pendingState;
1864 uidState.pendingStateCommitTime = 0;
1865 if (uidState.hasForegroundWatchers) {
1866 for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
1867 if (!uidState.foregroundOps.valueAt(fgi)) {
1868 continue;
1869 }
1870 final int code = uidState.foregroundOps.keyAt(fgi);
1871
1872 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
1873 if (callbacks != null) {
1874 for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
1875 final ModeCallback callback = callbacks.valueAt(cbi);
1876 if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
1877 || !callback.isWatchingUid(uidState.uid)) {
1878 continue;
1879 }
1880 boolean doAllPackages = uidState.opModes != null
1881 && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
1882 if (uidState.pkgOps != null) {
1883 for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
1884 final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
1885 if (doAllPackages || (op != null
1886 && op.mode == AppOpsManager.MODE_FOREGROUND)) {
1887 mHandler.sendMessage(PooledLambda.obtainMessage(
1888 AppOpsService::notifyOpChanged,
1889 this, callback, code, uidState.uid,
1890 uidState.pkgOps.keyAt(pkgi)));
1891 }
1892 }
1893 }
1894 }
1895 }
1896 }
1897 }
1898 }
1899
Yohei Yukawaa965d652017-10-12 15:02:26 -07001900 private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
1901 boolean uidMismatchExpected) {
Svet Ganov2af57082015-07-30 08:44:20 -07001902 UidState uidState = getUidStateLocked(uid, edit);
1903 if (uidState == null) {
1904 return null;
1905 }
1906
1907 if (uidState.pkgOps == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001908 if (!edit) {
1909 return null;
1910 }
Svet Ganov2af57082015-07-30 08:44:20 -07001911 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001912 }
Svet Ganov2af57082015-07-30 08:44:20 -07001913
1914 Ops ops = uidState.pkgOps.get(packageName);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001915 if (ops == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001916 if (!edit) {
1917 return null;
1918 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001919 boolean isPrivileged = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001920 // This is the first time we have seen this package name under this uid,
1921 // so let's make sure it is valid.
Dianne Hackborn514074f2013-02-11 10:52:46 -08001922 if (uid != 0) {
1923 final long ident = Binder.clearCallingIdentity();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001924 try {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001925 int pkgUid = -1;
1926 try {
Jason Monk1c7c3192014-06-26 12:52:18 -04001927 ApplicationInfo appInfo = ActivityThread.getPackageManager()
Jeff Sharkeycd654482016-01-08 17:42:11 -07001928 .getApplicationInfo(packageName,
1929 PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
1930 UserHandle.getUserId(uid));
Jason Monk1c7c3192014-06-26 12:52:18 -04001931 if (appInfo != null) {
1932 pkgUid = appInfo.uid;
Alex Klyubinb9f8a522015-02-03 11:12:59 -08001933 isPrivileged = (appInfo.privateFlags
1934 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04001935 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08001936 pkgUid = resolveUid(packageName);
1937 if (pkgUid >= 0) {
Chien-Yu Chen75cade02016-01-11 10:56:21 -08001938 isPrivileged = false;
Jason Monk1c7c3192014-06-26 12:52:18 -04001939 }
Dianne Hackborn713df152013-05-17 11:27:57 -07001940 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001941 } catch (RemoteException e) {
1942 Slog.w(TAG, "Could not contact PackageManager", e);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001943 }
1944 if (pkgUid != uid) {
1945 // Oops! The package name is not valid for the uid they are calling
1946 // under. Abort.
Yohei Yukawaa965d652017-10-12 15:02:26 -07001947 if (!uidMismatchExpected) {
1948 RuntimeException ex = new RuntimeException("here");
1949 ex.fillInStackTrace();
1950 Slog.w(TAG, "Bad call: specified package " + packageName
1951 + " under uid " + uid + " but it is really " + pkgUid, ex);
1952 }
Dianne Hackborn514074f2013-02-11 10:52:46 -08001953 return null;
1954 }
1955 } finally {
1956 Binder.restoreCallingIdentity(ident);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001957 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001958 }
Svet Ganov2af57082015-07-30 08:44:20 -07001959 ops = new Ops(packageName, uidState, isPrivileged);
1960 uidState.pkgOps.put(packageName, ops);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001961 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08001962 return ops;
1963 }
1964
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001965 private void scheduleWriteLocked() {
1966 if (!mWriteScheduled) {
1967 mWriteScheduled = true;
1968 mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
1969 }
1970 }
1971
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001972 private void scheduleFastWriteLocked() {
1973 if (!mFastWriteScheduled) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001974 mWriteScheduled = true;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001975 mFastWriteScheduled = true;
1976 mHandler.removeCallbacks(mWriteRunner);
1977 mHandler.postDelayed(mWriteRunner, 10*1000);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001978 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001979 }
1980
Dianne Hackborn72e39832013-01-18 18:36:09 -08001981 private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001982 Ops ops = getOpsRawLocked(uid, packageName, edit,
1983 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001984 if (ops == null) {
1985 return null;
1986 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001987 return getOpLocked(ops, code, edit);
1988 }
1989
1990 private Op getOpLocked(Ops ops, int code, boolean edit) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001991 Op op = ops.get(code);
1992 if (op == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001993 if (!edit) {
1994 return null;
1995 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001996 op = new Op(ops.uidState, ops.packageName, code);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001997 ops.put(code, op);
1998 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001999 if (edit) {
2000 scheduleWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002001 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002002 return op;
2003 }
2004
Svet Ganov442ed572016-08-17 17:29:43 -07002005 private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
Jason Monk62062992014-05-06 09:55:28 -04002006 int userHandle = UserHandle.getUserId(uid);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002007 final int restrictionSetCount = mOpUserRestrictions.size();
Ruben Brunk29931bc2016-03-11 00:24:26 -08002008
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002009 for (int i = 0; i < restrictionSetCount; i++) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08002010 // For each client, check that the given op is not restricted, or that the given
2011 // package is exempt from the restriction.
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002012 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07002013 if (restrictionState.hasRestriction(code, packageName, userHandle)) {
2014 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
2015 // If we are the system, bypass user restrictions for certain codes
2016 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002017 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
2018 false /* uidMismatchExpected */);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07002019 if ((ops != null) && ops.isPrivileged) {
2020 return false;
2021 }
Ruben Brunk32f0fa42016-03-11 19:07:07 -08002022 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08002023 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002024 return true;
Jason Monk1c7c3192014-06-26 12:52:18 -04002025 }
Jason Monk62062992014-05-06 09:55:28 -04002026 }
2027 return false;
2028 }
2029
Dianne Hackborn35654b62013-01-14 17:38:02 -08002030 void readState() {
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002031 int oldVersion = NO_VERSION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08002032 synchronized (mFile) {
2033 synchronized (this) {
2034 FileInputStream stream;
2035 try {
2036 stream = mFile.openRead();
2037 } catch (FileNotFoundException e) {
2038 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
2039 return;
2040 }
2041 boolean success = false;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002042 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002043 try {
2044 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002045 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002046 int type;
2047 while ((type = parser.next()) != XmlPullParser.START_TAG
2048 && type != XmlPullParser.END_DOCUMENT) {
2049 ;
2050 }
2051
2052 if (type != XmlPullParser.START_TAG) {
2053 throw new IllegalStateException("no start tag found");
2054 }
2055
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002056 final String versionString = parser.getAttributeValue(null, "v");
2057 if (versionString != null) {
2058 oldVersion = Integer.parseInt(versionString);
2059 }
2060
Dianne Hackborn35654b62013-01-14 17:38:02 -08002061 int outerDepth = parser.getDepth();
2062 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2063 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2064 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2065 continue;
2066 }
2067
2068 String tagName = parser.getName();
2069 if (tagName.equals("pkg")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002070 readPackage(parser);
Svetoslav215b44a2015-08-04 19:03:40 -07002071 } else if (tagName.equals("uid")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002072 readUidOps(parser);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002073 } else {
2074 Slog.w(TAG, "Unknown element under <app-ops>: "
2075 + parser.getName());
2076 XmlUtils.skipCurrentTag(parser);
2077 }
2078 }
2079 success = true;
2080 } catch (IllegalStateException e) {
2081 Slog.w(TAG, "Failed parsing " + e);
2082 } catch (NullPointerException e) {
2083 Slog.w(TAG, "Failed parsing " + e);
2084 } catch (NumberFormatException e) {
2085 Slog.w(TAG, "Failed parsing " + e);
2086 } catch (XmlPullParserException e) {
2087 Slog.w(TAG, "Failed parsing " + e);
2088 } catch (IOException e) {
2089 Slog.w(TAG, "Failed parsing " + e);
2090 } catch (IndexOutOfBoundsException e) {
2091 Slog.w(TAG, "Failed parsing " + e);
2092 } finally {
2093 if (!success) {
Svet Ganov2af57082015-07-30 08:44:20 -07002094 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002095 }
2096 try {
2097 stream.close();
2098 } catch (IOException e) {
2099 }
2100 }
2101 }
2102 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002103 synchronized (this) {
2104 upgradeLocked(oldVersion);
2105 }
2106 }
2107
2108 private void upgradeRunAnyInBackgroundLocked() {
2109 for (int i = 0; i < mUidStates.size(); i++) {
2110 final UidState uidState = mUidStates.valueAt(i);
2111 if (uidState == null) {
2112 continue;
2113 }
2114 if (uidState.opModes != null) {
2115 final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
2116 if (idx >= 0) {
2117 uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
2118 uidState.opModes.valueAt(idx));
2119 }
2120 }
2121 if (uidState.pkgOps == null) {
2122 continue;
2123 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002124 boolean changed = false;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002125 for (int j = 0; j < uidState.pkgOps.size(); j++) {
2126 Ops ops = uidState.pkgOps.valueAt(j);
2127 if (ops != null) {
2128 final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
2129 if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002130 final Op copy = new Op(op.uidState, op.packageName,
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002131 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
2132 copy.mode = op.mode;
2133 ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002134 changed = true;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002135 }
2136 }
2137 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002138 if (changed) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002139 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002140 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002141 }
2142 }
2143
2144 private void upgradeLocked(int oldVersion) {
2145 if (oldVersion >= CURRENT_VERSION) {
2146 return;
2147 }
2148 Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
2149 switch (oldVersion) {
2150 case NO_VERSION:
2151 upgradeRunAnyInBackgroundLocked();
2152 // fall through
2153 case 1:
2154 // for future upgrades
2155 }
2156 scheduleFastWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002157 }
2158
Svet Ganov2af57082015-07-30 08:44:20 -07002159 void readUidOps(XmlPullParser parser) throws NumberFormatException,
2160 XmlPullParserException, IOException {
2161 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
2162 int outerDepth = parser.getDepth();
2163 int type;
2164 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2165 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2166 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2167 continue;
2168 }
2169
2170 String tagName = parser.getName();
2171 if (tagName.equals("op")) {
2172 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
2173 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
2174 UidState uidState = getUidStateLocked(uid, true);
2175 if (uidState.opModes == null) {
2176 uidState.opModes = new SparseIntArray();
2177 }
2178 uidState.opModes.put(code, mode);
2179 } else {
2180 Slog.w(TAG, "Unknown element under <uid-ops>: "
2181 + parser.getName());
2182 XmlUtils.skipCurrentTag(parser);
2183 }
2184 }
2185 }
2186
Dave Burke0997c5bd2013-08-02 20:25:02 +00002187 void readPackage(XmlPullParser parser) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002188 XmlPullParserException, IOException {
2189 String pkgName = parser.getAttributeValue(null, "n");
2190 int outerDepth = parser.getDepth();
2191 int type;
2192 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2193 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2194 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2195 continue;
2196 }
2197
2198 String tagName = parser.getName();
2199 if (tagName.equals("uid")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002200 readUid(parser, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002201 } else {
2202 Slog.w(TAG, "Unknown element under <pkg>: "
2203 + parser.getName());
2204 XmlUtils.skipCurrentTag(parser);
2205 }
2206 }
2207 }
2208
Dave Burke0997c5bd2013-08-02 20:25:02 +00002209 void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002210 XmlPullParserException, IOException {
2211 int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
Jason Monk1c7c3192014-06-26 12:52:18 -04002212 String isPrivilegedString = parser.getAttributeValue(null, "p");
2213 boolean isPrivileged = false;
2214 if (isPrivilegedString == null) {
2215 try {
2216 IPackageManager packageManager = ActivityThread.getPackageManager();
2217 if (packageManager != null) {
2218 ApplicationInfo appInfo = ActivityThread.getPackageManager()
2219 .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
2220 if (appInfo != null) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08002221 isPrivileged = (appInfo.privateFlags
2222 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04002223 }
2224 } else {
2225 // Could not load data, don't add to cache so it will be loaded later.
2226 return;
2227 }
2228 } catch (RemoteException e) {
2229 Slog.w(TAG, "Could not contact PackageManager", e);
2230 }
2231 } else {
2232 isPrivileged = Boolean.parseBoolean(isPrivilegedString);
2233 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002234 int outerDepth = parser.getDepth();
2235 int type;
2236 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2237 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2238 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2239 continue;
2240 }
2241
2242 String tagName = parser.getName();
2243 if (tagName.equals("op")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002244 UidState uidState = getUidStateLocked(uid, true);
2245 if (uidState.pkgOps == null) {
2246 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002247 }
Svet Ganov2af57082015-07-30 08:44:20 -07002248
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002249 Op op = new Op(uidState, pkgName,
2250 Integer.parseInt(parser.getAttributeValue(null, "n")));
2251
2252 for (int i = parser.getAttributeCount()-1; i >= 0; i--) {
2253 final String name = parser.getAttributeName(i);
2254 final String value = parser.getAttributeValue(i);
2255 switch (name) {
2256 case "m":
2257 op.mode = Integer.parseInt(value);
2258 break;
2259 case "d":
2260 op.duration = Integer.parseInt(value);
2261 break;
2262 case "pu":
2263 op.proxyUid = Integer.parseInt(value);
2264 break;
2265 case "pp":
2266 op.proxyPackageName = value;
2267 break;
2268 case "tp":
2269 op.time[AppOpsManager.UID_STATE_PERSISTENT] = Long.parseLong(value);
2270 break;
2271 case "tt":
2272 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2273 break;
2274 case "tfs":
2275 op.time[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2276 = Long.parseLong(value);
2277 break;
2278 case "tf":
2279 op.time[AppOpsManager.UID_STATE_FOREGROUND] = Long.parseLong(value);
2280 break;
2281 case "tb":
2282 op.time[AppOpsManager.UID_STATE_BACKGROUND] = Long.parseLong(value);
2283 break;
2284 case "tc":
2285 op.time[AppOpsManager.UID_STATE_CACHED] = Long.parseLong(value);
2286 break;
2287 case "rp":
2288 op.rejectTime[AppOpsManager.UID_STATE_PERSISTENT]
2289 = Long.parseLong(value);
2290 break;
2291 case "rt":
2292 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2293 break;
2294 case "rfs":
2295 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2296 = Long.parseLong(value);
2297 break;
2298 case "rf":
2299 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND]
2300 = Long.parseLong(value);
2301 break;
2302 case "rb":
2303 op.rejectTime[AppOpsManager.UID_STATE_BACKGROUND]
2304 = Long.parseLong(value);
2305 break;
2306 case "rc":
2307 op.rejectTime[AppOpsManager.UID_STATE_CACHED]
2308 = Long.parseLong(value);
2309 break;
2310 case "t":
2311 // Backwards compat.
2312 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2313 break;
2314 case "r":
2315 // Backwards compat.
2316 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2317 break;
2318 default:
2319 Slog.w(TAG, "Unknown attribute in 'op' tag: " + name);
2320 break;
2321 }
2322 }
2323
Svet Ganov2af57082015-07-30 08:44:20 -07002324 Ops ops = uidState.pkgOps.get(pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002325 if (ops == null) {
Svet Ganov2af57082015-07-30 08:44:20 -07002326 ops = new Ops(pkgName, uidState, isPrivileged);
2327 uidState.pkgOps.put(pkgName, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002328 }
2329 ops.put(op.op, op);
2330 } else {
2331 Slog.w(TAG, "Unknown element under <pkg>: "
2332 + parser.getName());
2333 XmlUtils.skipCurrentTag(parser);
2334 }
2335 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002336 UidState uidState = getUidStateLocked(uid, false);
2337 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002338 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002339 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002340 }
2341
2342 void writeState() {
2343 synchronized (mFile) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002344 FileOutputStream stream;
2345 try {
2346 stream = mFile.startWrite();
2347 } catch (IOException e) {
2348 Slog.w(TAG, "Failed to write state: " + e);
2349 return;
2350 }
2351
Dianne Hackborne17b4452018-01-10 13:15:40 -08002352 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
2353
Dianne Hackborn35654b62013-01-14 17:38:02 -08002354 try {
2355 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002356 out.setOutput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002357 out.startDocument(null, true);
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002358 out.startTag(null, "app-ops");
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002359 out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
Svet Ganov2af57082015-07-30 08:44:20 -07002360
2361 final int uidStateCount = mUidStates.size();
2362 for (int i = 0; i < uidStateCount; i++) {
2363 UidState uidState = mUidStates.valueAt(i);
2364 if (uidState.opModes != null && uidState.opModes.size() > 0) {
2365 out.startTag(null, "uid");
2366 out.attribute(null, "n", Integer.toString(uidState.uid));
2367 SparseIntArray uidOpModes = uidState.opModes;
2368 final int opCount = uidOpModes.size();
2369 for (int j = 0; j < opCount; j++) {
2370 final int op = uidOpModes.keyAt(j);
2371 final int mode = uidOpModes.valueAt(j);
2372 out.startTag(null, "op");
2373 out.attribute(null, "n", Integer.toString(op));
2374 out.attribute(null, "m", Integer.toString(mode));
2375 out.endTag(null, "op");
2376 }
2377 out.endTag(null, "uid");
2378 }
2379 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002380
2381 if (allOps != null) {
2382 String lastPkg = null;
2383 for (int i=0; i<allOps.size(); i++) {
2384 AppOpsManager.PackageOps pkg = allOps.get(i);
2385 if (!pkg.getPackageName().equals(lastPkg)) {
2386 if (lastPkg != null) {
2387 out.endTag(null, "pkg");
2388 }
2389 lastPkg = pkg.getPackageName();
2390 out.startTag(null, "pkg");
2391 out.attribute(null, "n", lastPkg);
2392 }
2393 out.startTag(null, "uid");
2394 out.attribute(null, "n", Integer.toString(pkg.getUid()));
Jason Monk1c7c3192014-06-26 12:52:18 -04002395 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002396 Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
2397 false /* edit */, false /* uidMismatchExpected */);
Jason Monk1c7c3192014-06-26 12:52:18 -04002398 // Should always be present as the list of PackageOps is generated
2399 // from Ops.
2400 if (ops != null) {
2401 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
2402 } else {
2403 out.attribute(null, "p", Boolean.toString(false));
2404 }
2405 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002406 List<AppOpsManager.OpEntry> ops = pkg.getOps();
2407 for (int j=0; j<ops.size(); j++) {
2408 AppOpsManager.OpEntry op = ops.get(j);
2409 out.startTag(null, "op");
2410 out.attribute(null, "n", Integer.toString(op.getOp()));
David Braunf5d83192013-09-16 13:43:51 -07002411 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002412 out.attribute(null, "m", Integer.toString(op.getMode()));
2413 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002414 for (int k = 0; k < _NUM_UID_STATE; k++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002415 final long time = op.getLastTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002416 if (time != 0) {
2417 out.attribute(null, UID_STATE_TIME_ATTRS[k],
2418 Long.toString(time));
2419 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002420 final long rejectTime = op.getLastRejectTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002421 if (rejectTime != 0) {
2422 out.attribute(null, UID_STATE_REJECT_ATTRS[k],
2423 Long.toString(rejectTime));
2424 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002425 }
2426 int dur = op.getDuration();
2427 if (dur != 0) {
2428 out.attribute(null, "d", Integer.toString(dur));
2429 }
Svet Ganov99b60432015-06-27 13:15:22 -07002430 int proxyUid = op.getProxyUid();
2431 if (proxyUid != -1) {
2432 out.attribute(null, "pu", Integer.toString(proxyUid));
2433 }
2434 String proxyPackageName = op.getProxyPackageName();
2435 if (proxyPackageName != null) {
2436 out.attribute(null, "pp", proxyPackageName);
2437 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002438 out.endTag(null, "op");
2439 }
2440 out.endTag(null, "uid");
2441 }
2442 if (lastPkg != null) {
2443 out.endTag(null, "pkg");
2444 }
2445 }
2446
2447 out.endTag(null, "app-ops");
2448 out.endDocument();
2449 mFile.finishWrite(stream);
2450 } catch (IOException e) {
2451 Slog.w(TAG, "Failed to write state, restoring backup.", e);
2452 mFile.failWrite(stream);
2453 }
2454 }
2455 }
2456
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002457 static class Shell extends ShellCommand {
2458 final IAppOpsService mInterface;
2459 final AppOpsService mInternal;
2460
2461 int userId = UserHandle.USER_SYSTEM;
2462 String packageName;
2463 String opStr;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002464 String modeStr;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002465 int op;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002466 int mode;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002467 int packageUid;
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002468 int nonpackageUid;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002469 final static Binder sBinder = new Binder();
2470 IBinder mToken;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002471
2472 Shell(IAppOpsService iface, AppOpsService internal) {
2473 mInterface = iface;
2474 mInternal = internal;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002475 try {
2476 mToken = mInterface.getToken(sBinder);
2477 } catch (RemoteException e) {
2478 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002479 }
2480
2481 @Override
2482 public int onCommand(String cmd) {
2483 return onShellCommand(this, cmd);
2484 }
2485
2486 @Override
2487 public void onHelp() {
2488 PrintWriter pw = getOutPrintWriter();
2489 dumpCommandHelp(pw);
2490 }
2491
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002492 static private int strOpToOp(String op, PrintWriter err) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002493 try {
2494 return AppOpsManager.strOpToOp(op);
2495 } catch (IllegalArgumentException e) {
2496 }
2497 try {
2498 return Integer.parseInt(op);
2499 } catch (NumberFormatException e) {
2500 }
2501 try {
2502 return AppOpsManager.strDebugOpToOp(op);
2503 } catch (IllegalArgumentException e) {
2504 err.println("Error: " + e.getMessage());
2505 return -1;
2506 }
2507 }
2508
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002509 static int strModeToMode(String modeStr, PrintWriter err) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002510 for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
2511 if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002512 return i;
2513 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002514 }
2515 try {
2516 return Integer.parseInt(modeStr);
2517 } catch (NumberFormatException e) {
2518 }
2519 err.println("Error: Mode " + modeStr + " is not valid");
2520 return -1;
2521 }
2522
2523 int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
2524 userId = UserHandle.USER_CURRENT;
2525 opStr = null;
2526 modeStr = null;
2527 for (String argument; (argument = getNextArg()) != null;) {
2528 if ("--user".equals(argument)) {
2529 userId = UserHandle.parseUserArg(getNextArgRequired());
2530 } else {
2531 if (opStr == null) {
2532 opStr = argument;
2533 } else if (modeStr == null) {
2534 modeStr = argument;
2535 break;
2536 }
2537 }
2538 }
2539 if (opStr == null) {
2540 err.println("Error: Operation not specified.");
2541 return -1;
2542 }
2543 op = strOpToOp(opStr, err);
2544 if (op < 0) {
2545 return -1;
2546 }
2547 if (modeStr != null) {
2548 if ((mode=strModeToMode(modeStr, err)) < 0) {
2549 return -1;
2550 }
2551 } else {
2552 mode = defMode;
2553 }
2554 return 0;
2555 }
2556
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002557 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
2558 userId = UserHandle.USER_CURRENT;
2559 packageName = null;
2560 opStr = null;
2561 for (String argument; (argument = getNextArg()) != null;) {
2562 if ("--user".equals(argument)) {
2563 userId = UserHandle.parseUserArg(getNextArgRequired());
2564 } else {
2565 if (packageName == null) {
2566 packageName = argument;
2567 } else if (opStr == null) {
2568 opStr = argument;
2569 break;
2570 }
2571 }
2572 }
2573 if (packageName == null) {
2574 err.println("Error: Package name not specified.");
2575 return -1;
2576 } else if (opStr == null && reqOp) {
2577 err.println("Error: Operation not specified.");
2578 return -1;
2579 }
2580 if (opStr != null) {
2581 op = strOpToOp(opStr, err);
2582 if (op < 0) {
2583 return -1;
2584 }
2585 } else {
2586 op = AppOpsManager.OP_NONE;
2587 }
2588 if (userId == UserHandle.USER_CURRENT) {
2589 userId = ActivityManager.getCurrentUser();
2590 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002591 nonpackageUid = -1;
2592 try {
2593 nonpackageUid = Integer.parseInt(packageName);
2594 } catch (NumberFormatException e) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002595 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002596 if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
2597 && packageName.indexOf('.') < 0) {
2598 int i = 1;
2599 while (i < packageName.length() && packageName.charAt(i) >= '0'
2600 && packageName.charAt(i) <= '9') {
2601 i++;
2602 }
2603 if (i > 1 && i < packageName.length()) {
2604 String userStr = packageName.substring(1, i);
2605 try {
2606 int user = Integer.parseInt(userStr);
2607 char type = packageName.charAt(i);
2608 i++;
2609 int startTypeVal = i;
2610 while (i < packageName.length() && packageName.charAt(i) >= '0'
2611 && packageName.charAt(i) <= '9') {
2612 i++;
2613 }
2614 if (i > startTypeVal) {
2615 String typeValStr = packageName.substring(startTypeVal, i);
2616 try {
2617 int typeVal = Integer.parseInt(typeValStr);
2618 if (type == 'a') {
2619 nonpackageUid = UserHandle.getUid(user,
2620 typeVal + Process.FIRST_APPLICATION_UID);
2621 } else if (type == 's') {
2622 nonpackageUid = UserHandle.getUid(user, typeVal);
2623 }
2624 } catch (NumberFormatException e) {
2625 }
2626 }
2627 } catch (NumberFormatException e) {
2628 }
2629 }
2630 }
2631 if (nonpackageUid != -1) {
2632 packageName = null;
2633 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08002634 packageUid = resolveUid(packageName);
2635 if (packageUid < 0) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002636 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
2637 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
2638 }
2639 if (packageUid < 0) {
2640 err.println("Error: No UID for " + packageName + " in user " + userId);
2641 return -1;
2642 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002643 }
2644 return 0;
2645 }
2646 }
2647
2648 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07002649 FileDescriptor err, String[] args, ShellCallback callback,
2650 ResultReceiver resultReceiver) {
2651 (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002652 }
2653
2654 static void dumpCommandHelp(PrintWriter pw) {
2655 pw.println("AppOps service (appops) commands:");
2656 pw.println(" help");
2657 pw.println(" Print this help text.");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002658 pw.println(" start [--user <USER_ID>] <PACKAGE | UID> <OP> ");
2659 pw.println(" Starts a given operation for a particular application.");
2660 pw.println(" stop [--user <USER_ID>] <PACKAGE | UID> <OP> ");
2661 pw.println(" Stops a given operation for a particular application.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002662 pw.println(" set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002663 pw.println(" Set the mode for a particular application and operation.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002664 pw.println(" get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002665 pw.println(" Return the mode for a particular application and optional operation.");
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002666 pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
2667 pw.println(" Print all packages that currently have the given op in the given mode.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002668 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
2669 pw.println(" Reset the given application or all applications to default modes.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002670 pw.println(" write-settings");
2671 pw.println(" Immediately write pending changes to storage.");
2672 pw.println(" read-settings");
2673 pw.println(" Read the last written settings, replacing current state in RAM.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002674 pw.println(" options:");
2675 pw.println(" <PACKAGE> an Android package name.");
2676 pw.println(" <OP> an AppOps operation.");
2677 pw.println(" <MODE> one of allow, ignore, deny, or default");
2678 pw.println(" <USER_ID> the user id under which the package is installed. If --user is not");
2679 pw.println(" specified, the current user is assumed.");
2680 }
2681
2682 static int onShellCommand(Shell shell, String cmd) {
2683 if (cmd == null) {
2684 return shell.handleDefaultCommands(cmd);
2685 }
2686 PrintWriter pw = shell.getOutPrintWriter();
2687 PrintWriter err = shell.getErrPrintWriter();
2688 try {
2689 switch (cmd) {
2690 case "set": {
2691 int res = shell.parseUserPackageOp(true, err);
2692 if (res < 0) {
2693 return res;
2694 }
2695 String modeStr = shell.getNextArg();
2696 if (modeStr == null) {
2697 err.println("Error: Mode not specified.");
2698 return -1;
2699 }
2700
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002701 final int mode = shell.strModeToMode(modeStr, err);
2702 if (mode < 0) {
2703 return -1;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002704 }
2705
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002706 if (shell.packageName != null) {
2707 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
2708 mode);
2709 } else {
2710 shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
2711 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002712 return 0;
2713 }
2714 case "get": {
2715 int res = shell.parseUserPackageOp(false, err);
2716 if (res < 0) {
2717 return res;
2718 }
2719
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002720 List<AppOpsManager.PackageOps> ops;
2721 if (shell.packageName != null) {
2722 ops = shell.mInterface.getOpsForPackage(
2723 shell.packageUid, shell.packageName,
2724 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
2725 } else {
2726 ops = shell.mInterface.getUidOps(
2727 shell.nonpackageUid,
2728 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
2729 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002730 if (ops == null || ops.size() <= 0) {
2731 pw.println("No operations.");
Svet Ganov82f09bc2018-01-12 22:08:40 -08002732 if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002733 pw.println("Default mode: " + AppOpsManager.modeToName(
Svet Ganov82f09bc2018-01-12 22:08:40 -08002734 AppOpsManager.opToDefaultMode(shell.op)));
2735 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002736 return 0;
2737 }
2738 final long now = System.currentTimeMillis();
2739 for (int i=0; i<ops.size(); i++) {
2740 List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
2741 for (int j=0; j<entries.size(); j++) {
2742 AppOpsManager.OpEntry ent = entries.get(j);
2743 pw.print(AppOpsManager.opToName(ent.getOp()));
2744 pw.print(": ");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002745 pw.print(AppOpsManager.modeToName(ent.getMode()));
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002746 if (ent.getTime() != 0) {
2747 pw.print("; time=");
2748 TimeUtils.formatDuration(now - ent.getTime(), pw);
2749 pw.print(" ago");
2750 }
2751 if (ent.getRejectTime() != 0) {
2752 pw.print("; rejectTime=");
2753 TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
2754 pw.print(" ago");
2755 }
2756 if (ent.getDuration() == -1) {
2757 pw.print(" (running)");
2758 } else if (ent.getDuration() != 0) {
2759 pw.print("; duration=");
2760 TimeUtils.formatDuration(ent.getDuration(), pw);
2761 }
2762 pw.println();
2763 }
2764 }
2765 return 0;
2766 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002767 case "query-op": {
2768 int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
2769 if (res < 0) {
2770 return res;
2771 }
2772 List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
2773 new int[] {shell.op});
2774 if (ops == null || ops.size() <= 0) {
2775 pw.println("No operations.");
2776 return 0;
2777 }
2778 for (int i=0; i<ops.size(); i++) {
2779 final AppOpsManager.PackageOps pkg = ops.get(i);
2780 boolean hasMatch = false;
2781 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
2782 for (int j=0; j<entries.size(); j++) {
2783 AppOpsManager.OpEntry ent = entries.get(j);
2784 if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
2785 hasMatch = true;
2786 break;
2787 }
2788 }
2789 if (hasMatch) {
2790 pw.println(pkg.getPackageName());
2791 }
2792 }
2793 return 0;
2794 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002795 case "reset": {
2796 String packageName = null;
2797 int userId = UserHandle.USER_CURRENT;
2798 for (String argument; (argument = shell.getNextArg()) != null;) {
2799 if ("--user".equals(argument)) {
2800 String userStr = shell.getNextArgRequired();
2801 userId = UserHandle.parseUserArg(userStr);
2802 } else {
2803 if (packageName == null) {
2804 packageName = argument;
2805 } else {
2806 err.println("Error: Unsupported argument: " + argument);
2807 return -1;
2808 }
2809 }
2810 }
2811
2812 if (userId == UserHandle.USER_CURRENT) {
2813 userId = ActivityManager.getCurrentUser();
2814 }
2815
2816 shell.mInterface.resetAllModes(userId, packageName);
2817 pw.print("Reset all modes for: ");
2818 if (userId == UserHandle.USER_ALL) {
2819 pw.print("all users");
2820 } else {
2821 pw.print("user "); pw.print(userId);
2822 }
2823 pw.print(", ");
2824 if (packageName == null) {
2825 pw.println("all packages");
2826 } else {
2827 pw.print("package "); pw.println(packageName);
2828 }
2829 return 0;
2830 }
2831 case "write-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07002832 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
2833 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002834 long token = Binder.clearCallingIdentity();
2835 try {
2836 synchronized (shell.mInternal) {
2837 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
2838 }
2839 shell.mInternal.writeState();
2840 pw.println("Current settings written.");
2841 } finally {
2842 Binder.restoreCallingIdentity(token);
2843 }
2844 return 0;
2845 }
2846 case "read-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07002847 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
2848 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002849 long token = Binder.clearCallingIdentity();
2850 try {
2851 shell.mInternal.readState();
2852 pw.println("Last settings read.");
2853 } finally {
2854 Binder.restoreCallingIdentity(token);
2855 }
2856 return 0;
2857 }
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002858 case "start": {
2859 int res = shell.parseUserPackageOp(true, err);
2860 if (res < 0) {
2861 return res;
2862 }
2863
2864 if (shell.packageName != null) {
2865 shell.mInterface.startOperation(shell.mToken,
2866 shell.op, shell.packageUid, shell.packageName, true);
2867 } else {
2868 return -1;
2869 }
2870 return 0;
2871 }
2872 case "stop": {
2873 int res = shell.parseUserPackageOp(true, err);
2874 if (res < 0) {
2875 return res;
2876 }
2877
2878 if (shell.packageName != null) {
2879 shell.mInterface.finishOperation(shell.mToken,
2880 shell.op, shell.packageUid, shell.packageName);
2881 } else {
2882 return -1;
2883 }
2884 return 0;
2885 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002886 default:
2887 return shell.handleDefaultCommands(cmd);
2888 }
2889 } catch (RemoteException e) {
2890 pw.println("Remote exception: " + e);
2891 }
2892 return -1;
2893 }
2894
2895 private void dumpHelp(PrintWriter pw) {
2896 pw.println("AppOps service (appops) dump options:");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002897 pw.println(" -h");
2898 pw.println(" Print this help text.");
2899 pw.println(" --op [OP]");
2900 pw.println(" Limit output to data associated with the given app op code.");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002901 pw.println(" --mode [MODE]");
2902 pw.println(" Limit output to data associated with the given app op mode.");
2903 pw.println(" --package [PACKAGE]");
2904 pw.println(" Limit output to data associated with the given package name.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002905 }
2906
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002907 private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
2908 long now, SimpleDateFormat sdf, Date date) {
2909 boolean hasTime = false;
2910 for (int i = 0; i < _NUM_UID_STATE; i++) {
2911 if (times[i] != 0) {
2912 hasTime = true;
2913 break;
2914 }
2915 }
2916 if (!hasTime) {
2917 return;
2918 }
2919 boolean first = true;
2920 for (int i = 0; i < _NUM_UID_STATE; i++) {
2921 if (times[i] != 0) {
2922 pw.print(first ? firstPrefix : prefix);
2923 first = false;
2924 pw.print(UID_STATE_NAMES[i]);
2925 pw.print(" = ");
2926 date.setTime(times[i]);
2927 pw.print(sdf.format(date));
2928 pw.print(" (");
2929 TimeUtils.formatDuration(times[i]-now, pw);
2930 pw.println(")");
2931 }
2932 }
2933 }
2934
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002935 @Override
2936 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06002937 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002938
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002939 int dumpOp = -1;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002940 String dumpPackage = null;
2941 int dumpUid = -1;
2942 int dumpMode = -1;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002943
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002944 if (args != null) {
2945 for (int i=0; i<args.length; i++) {
2946 String arg = args[i];
2947 if ("-h".equals(arg)) {
2948 dumpHelp(pw);
2949 return;
Tim Kilbourn8f1ea832015-08-26 15:07:37 -07002950 } else if ("-a".equals(arg)) {
2951 // dump all data
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002952 } else if ("--op".equals(arg)) {
2953 i++;
2954 if (i >= args.length) {
2955 pw.println("No argument for --op option");
2956 return;
2957 }
2958 dumpOp = Shell.strOpToOp(args[i], pw);
2959 if (dumpOp < 0) {
2960 return;
2961 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002962 } else if ("--package".equals(arg)) {
2963 i++;
2964 if (i >= args.length) {
2965 pw.println("No argument for --package option");
2966 return;
2967 }
2968 dumpPackage = args[i];
2969 try {
2970 dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
2971 PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
2972 0);
2973 } catch (RemoteException e) {
2974 }
2975 if (dumpUid < 0) {
2976 pw.println("Unknown package: " + dumpPackage);
2977 return;
2978 }
2979 dumpUid = UserHandle.getAppId(dumpUid);
2980 } else if ("--mode".equals(arg)) {
2981 i++;
2982 if (i >= args.length) {
2983 pw.println("No argument for --mode option");
2984 return;
2985 }
2986 dumpMode = Shell.strModeToMode(args[i], pw);
2987 if (dumpMode < 0) {
2988 return;
2989 }
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002990 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
2991 pw.println("Unknown option: " + arg);
2992 return;
2993 } else {
2994 pw.println("Unknown command: " + arg);
2995 return;
2996 }
2997 }
2998 }
2999
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003000 synchronized (this) {
3001 pw.println("Current AppOps Service state:");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003002 mConstants.dump(pw);
3003 pw.println();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003004 final long now = System.currentTimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003005 final long nowElapsed = SystemClock.elapsedRealtime();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003006 final long nowUptime = SystemClock.uptimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003007 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
3008 final Date date = new Date();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003009 boolean needSep = false;
Dianne Hackbornd5254412018-05-11 18:02:58 -07003010 if (dumpOp < 0 && dumpMode < 0 && dumpPackage == null && mProfileOwners != null) {
3011 pw.println(" Profile owners:");
3012 for (int poi = 0; poi < mProfileOwners.size(); poi++) {
3013 pw.print(" User #");
3014 pw.print(mProfileOwners.keyAt(poi));
3015 pw.print(": ");
3016 UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
3017 pw.println();
3018 }
3019 pw.println();
3020 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003021 if (mOpModeWatchers.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003022 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003023 for (int i=0; i<mOpModeWatchers.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003024 if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
3025 continue;
3026 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003027 boolean printedOpHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003028 ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003029 for (int j=0; j<callbacks.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003030 final ModeCallback cb = callbacks.valueAt(j);
3031 if (dumpPackage != null && cb.mWatchingUid >= 0
3032 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3033 continue;
3034 }
3035 needSep = true;
3036 if (!printedHeader) {
3037 pw.println(" Op mode watchers:");
3038 printedHeader = true;
3039 }
3040 if (!printedOpHeader) {
3041 pw.print(" Op ");
3042 pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
3043 pw.println(":");
3044 printedOpHeader = true;
3045 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003046 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003047 pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003048 }
3049 }
3050 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003051 if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
3052 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003053 for (int i=0; i<mPackageModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003054 if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
3055 continue;
3056 }
3057 needSep = true;
3058 if (!printedHeader) {
3059 pw.println(" Package mode watchers:");
3060 printedHeader = true;
3061 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003062 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
3063 pw.println(":");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003064 ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003065 for (int j=0; j<callbacks.size(); j++) {
3066 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn68d76552017-02-27 15:32:03 -08003067 pw.println(callbacks.valueAt(j));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003068 }
3069 }
3070 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003071 if (mModeWatchers.size() > 0 && dumpOp < 0) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003072 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003073 for (int i=0; i<mModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003074 final ModeCallback cb = mModeWatchers.valueAt(i);
3075 if (dumpPackage != null && cb.mWatchingUid >= 0
3076 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3077 continue;
3078 }
3079 needSep = true;
3080 if (!printedHeader) {
3081 pw.println(" All op mode watchers:");
3082 printedHeader = true;
3083 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003084 pw.print(" ");
3085 pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003086 pw.print(": "); pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003087 }
3088 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003089 if (mActiveWatchers.size() > 0 && dumpMode < 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003090 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003091 boolean printedHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003092 for (int i = 0; i < mActiveWatchers.size(); i++) {
3093 final SparseArray<ActiveCallback> activeWatchers = mActiveWatchers.valueAt(i);
3094 if (activeWatchers.size() <= 0) {
3095 continue;
3096 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003097 final ActiveCallback cb = activeWatchers.valueAt(0);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003098 if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
3099 continue;
3100 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003101 if (dumpPackage != null && cb.mWatchingUid >= 0
3102 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3103 continue;
3104 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003105 if (!printedHeader) {
3106 pw.println(" All op active watchers:");
3107 printedHeader = true;
3108 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003109 pw.print(" ");
3110 pw.print(Integer.toHexString(System.identityHashCode(
3111 mActiveWatchers.keyAt(i))));
3112 pw.println(" ->");
3113 pw.print(" [");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003114 final int opCount = activeWatchers.size();
3115 for (i = 0; i < opCount; i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003116 if (i > 0) {
3117 pw.print(' ');
3118 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003119 pw.print(AppOpsManager.opToName(activeWatchers.keyAt(i)));
3120 if (i < opCount - 1) {
3121 pw.print(',');
3122 }
3123 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003124 pw.println("]");
3125 pw.print(" ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003126 pw.println(cb);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003127 }
3128 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003129 if (mClients.size() > 0 && dumpMode < 0) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003130 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003131 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003132 for (int i=0; i<mClients.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003133 boolean printedClient = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003134 ClientState cs = mClients.valueAt(i);
Svet Ganovf7b47252018-02-26 11:11:27 -08003135 if (cs.mStartedOps.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003136 boolean printedStarted = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003137 for (int j=0; j<cs.mStartedOps.size(); j++) {
3138 Op op = cs.mStartedOps.get(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003139 if (dumpOp >= 0 && op.op != dumpOp) {
3140 continue;
3141 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003142 if (dumpPackage != null && !dumpPackage.equals(op.packageName)) {
3143 continue;
3144 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003145 if (!printedHeader) {
3146 pw.println(" Clients:");
3147 printedHeader = true;
3148 }
3149 if (!printedClient) {
3150 pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
3151 pw.print(" "); pw.println(cs);
3152 printedClient = true;
3153 }
3154 if (!printedStarted) {
3155 pw.println(" Started ops:");
3156 printedStarted = true;
3157 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003158 pw.print(" "); pw.print("uid="); pw.print(op.uid);
3159 pw.print(" pkg="); pw.print(op.packageName);
3160 pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
3161 }
3162 }
3163 }
3164 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003165 if (mAudioRestrictions.size() > 0 && dumpOp < 0 && dumpPackage != null
3166 && dumpMode < 0) {
John Spurlock1af30c72014-03-10 08:33:35 -04003167 boolean printedHeader = false;
3168 for (int o=0; o<mAudioRestrictions.size(); o++) {
3169 final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
3170 final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
3171 for (int i=0; i<restrictions.size(); i++) {
3172 if (!printedHeader){
3173 pw.println(" Audio Restrictions:");
3174 printedHeader = true;
3175 needSep = true;
3176 }
John Spurlock7b414672014-07-18 13:02:39 -04003177 final int usage = restrictions.keyAt(i);
John Spurlock1af30c72014-03-10 08:33:35 -04003178 pw.print(" "); pw.print(op);
John Spurlock7b414672014-07-18 13:02:39 -04003179 pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
John Spurlock1af30c72014-03-10 08:33:35 -04003180 Restriction r = restrictions.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003181 pw.print(": mode="); pw.println(AppOpsManager.modeToName(r.mode));
John Spurlock1af30c72014-03-10 08:33:35 -04003182 if (!r.exceptionPackages.isEmpty()) {
3183 pw.println(" Exceptions:");
3184 for (int j=0; j<r.exceptionPackages.size(); j++) {
3185 pw.print(" "); pw.println(r.exceptionPackages.valueAt(j));
3186 }
3187 }
3188 }
3189 }
3190 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003191 if (needSep) {
3192 pw.println();
3193 }
Svet Ganov2af57082015-07-30 08:44:20 -07003194 for (int i=0; i<mUidStates.size(); i++) {
3195 UidState uidState = mUidStates.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003196 final SparseIntArray opModes = uidState.opModes;
3197 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
3198
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003199 if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
3200 boolean hasOp = dumpOp < 0 || (uidState.opModes != null
3201 && uidState.opModes.indexOfKey(dumpOp) >= 0);
3202 boolean hasPackage = dumpPackage == null;
3203 boolean hasMode = dumpMode < 0;
3204 if (!hasMode && opModes != null) {
3205 for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
3206 if (opModes.valueAt(opi) == dumpMode) {
3207 hasMode = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003208 }
3209 }
3210 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003211 if (pkgOps != null) {
3212 for (int pkgi = 0;
3213 (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
3214 pkgi++) {
3215 Ops ops = pkgOps.valueAt(pkgi);
3216 if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
3217 hasOp = true;
3218 }
3219 if (!hasMode) {
3220 for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
3221 if (ops.valueAt(opi).mode == dumpMode) {
3222 hasMode = true;
3223 }
3224 }
3225 }
3226 if (!hasPackage && dumpPackage.equals(ops.packageName)) {
3227 hasPackage = true;
3228 }
3229 }
3230 }
3231 if (uidState.foregroundOps != null && !hasOp) {
3232 if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
3233 hasOp = true;
3234 }
3235 }
3236 if (!hasOp || !hasPackage || !hasMode) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003237 continue;
3238 }
3239 }
Svet Ganov2af57082015-07-30 08:44:20 -07003240
3241 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003242 pw.print(" state=");
3243 pw.println(UID_STATE_NAMES[uidState.state]);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003244 if (uidState.state != uidState.pendingState) {
3245 pw.print(" pendingState=");
3246 pw.println(UID_STATE_NAMES[uidState.pendingState]);
3247 }
3248 if (uidState.pendingStateCommitTime != 0) {
3249 pw.print(" pendingStateCommitTime=");
3250 TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowUptime, pw);
3251 pw.println();
3252 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003253 if (uidState.startNesting != 0) {
3254 pw.print(" startNesting=");
3255 pw.println(uidState.startNesting);
3256 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003257 if (uidState.foregroundOps != null && (dumpMode < 0
3258 || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003259 pw.println(" foregroundOps:");
3260 for (int j = 0; j < uidState.foregroundOps.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003261 if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
3262 continue;
3263 }
3264 pw.print(" ");
3265 pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
3266 pw.print(": ");
3267 pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003268 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003269 pw.print(" hasForegroundWatchers=");
3270 pw.println(uidState.hasForegroundWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003271 }
Svet Ganovee438d42017-01-19 18:04:38 -08003272 needSep = true;
Svet Ganov2af57082015-07-30 08:44:20 -07003273
Svet Ganov2af57082015-07-30 08:44:20 -07003274 if (opModes != null) {
3275 final int opModeCount = opModes.size();
3276 for (int j = 0; j < opModeCount; j++) {
3277 final int code = opModes.keyAt(j);
3278 final int mode = opModes.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003279 if (dumpOp >= 0 && dumpOp != code) {
3280 continue;
3281 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003282 if (dumpMode >= 0 && dumpMode != mode) {
3283 continue;
3284 }
Svet Ganov2af57082015-07-30 08:44:20 -07003285 pw.print(" "); pw.print(AppOpsManager.opToName(code));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003286 pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
Svet Ganov2af57082015-07-30 08:44:20 -07003287 }
3288 }
3289
Svet Ganov2af57082015-07-30 08:44:20 -07003290 if (pkgOps == null) {
3291 continue;
3292 }
3293
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003294 for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003295 final Ops ops = pkgOps.valueAt(pkgi);
3296 if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
3297 continue;
3298 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003299 boolean printedPackage = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003300 for (int j=0; j<ops.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003301 final Op op = ops.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003302 if (dumpOp >= 0 && dumpOp != op.op) {
3303 continue;
3304 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003305 if (dumpMode >= 0 && dumpMode != op.mode) {
3306 continue;
3307 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003308 if (!printedPackage) {
3309 pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
3310 printedPackage = true;
3311 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003312 pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003313 pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003314 final int switchOp = AppOpsManager.opToSwitch(op.op);
3315 if (switchOp != op.op) {
3316 pw.print(" / switch ");
3317 pw.print(AppOpsManager.opToName(switchOp));
3318 final Op switchObj = ops.get(switchOp);
3319 int mode = switchObj != null
3320 ? switchObj.mode : AppOpsManager.opToDefaultMode(switchOp);
3321 pw.print("="); pw.print(AppOpsManager.modeToName(mode));
3322 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003323 pw.println("): ");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003324 dumpTimesLocked(pw,
3325 " Access: ",
3326 " ", op.time, now, sdf, date);
3327 dumpTimesLocked(pw,
3328 " Reject: ",
3329 " ", op.rejectTime, now, sdf, date);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003330 if (op.duration == -1) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003331 pw.print(" Running start at: ");
3332 TimeUtils.formatDuration(nowElapsed-op.startRealtime, pw);
3333 pw.println();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08003334 } else if (op.duration != 0) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003335 pw.print(" duration=");
3336 TimeUtils.formatDuration(op.duration, pw);
3337 pw.println();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003338 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003339 if (op.startNesting != 0) {
3340 pw.print(" startNesting=");
3341 pw.println(op.startNesting);
3342 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003343 }
3344 }
3345 }
Svet Ganovee438d42017-01-19 18:04:38 -08003346 if (needSep) {
3347 pw.println();
3348 }
3349
3350 final int userRestrictionCount = mOpUserRestrictions.size();
3351 for (int i = 0; i < userRestrictionCount; i++) {
3352 IBinder token = mOpUserRestrictions.keyAt(i);
3353 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
3354 pw.println(" User restrictions for token " + token + ":");
3355
3356 final int restrictionCount = restrictionState.perUserRestrictions != null
3357 ? restrictionState.perUserRestrictions.size() : 0;
3358 if (restrictionCount > 0) {
3359 pw.println(" Restricted ops:");
3360 for (int j = 0; j < restrictionCount; j++) {
3361 int userId = restrictionState.perUserRestrictions.keyAt(j);
3362 boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
3363 if (restrictedOps == null) {
3364 continue;
3365 }
3366 StringBuilder restrictedOpsValue = new StringBuilder();
3367 restrictedOpsValue.append("[");
3368 final int restrictedOpCount = restrictedOps.length;
3369 for (int k = 0; k < restrictedOpCount; k++) {
3370 if (restrictedOps[k]) {
3371 if (restrictedOpsValue.length() > 1) {
3372 restrictedOpsValue.append(", ");
3373 }
3374 restrictedOpsValue.append(AppOpsManager.opToName(k));
3375 }
3376 }
3377 restrictedOpsValue.append("]");
3378 pw.print(" "); pw.print("user: "); pw.print(userId);
3379 pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
3380 }
3381 }
3382
3383 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
3384 ? restrictionState.perUserExcludedPackages.size() : 0;
3385 if (excludedPackageCount > 0) {
3386 pw.println(" Excluded packages:");
3387 for (int j = 0; j < excludedPackageCount; j++) {
3388 int userId = restrictionState.perUserExcludedPackages.keyAt(j);
3389 String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
3390 pw.print(" "); pw.print("user: "); pw.print(userId);
3391 pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
3392 }
3393 }
3394 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003395 }
3396 }
John Spurlock1af30c72014-03-10 08:33:35 -04003397
3398 private static final class Restriction {
3399 private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
3400 int mode;
3401 ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
3402 }
Jason Monk62062992014-05-06 09:55:28 -04003403
3404 @Override
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003405 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
Jason Monk62062992014-05-06 09:55:28 -04003406 checkSystemUid("setUserRestrictions");
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003407 Preconditions.checkNotNull(restrictions);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003408 Preconditions.checkNotNull(token);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003409 for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
Jason Monk62062992014-05-06 09:55:28 -04003410 String restriction = AppOpsManager.opToRestriction(i);
Suprabh Shukla64e0dcb2016-05-24 16:23:11 -07003411 if (restriction != null) {
3412 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
3413 userHandle, null);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003414 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003415 }
3416 }
3417
3418 @Override
Ruben Brunk29931bc2016-03-11 00:24:26 -08003419 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
3420 String[] exceptionPackages) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003421 if (Binder.getCallingPid() != Process.myPid()) {
3422 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
3423 Binder.getCallingPid(), Binder.getCallingUid(), null);
3424 }
3425 if (userHandle != UserHandle.getCallingUserId()) {
3426 if (mContext.checkCallingOrSelfPermission(Manifest.permission
3427 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
3428 && mContext.checkCallingOrSelfPermission(Manifest.permission
3429 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
3430 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
3431 + " INTERACT_ACROSS_USERS to interact cross user ");
Jason Monk62062992014-05-06 09:55:28 -04003432 }
3433 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003434 verifyIncomingOp(code);
3435 Preconditions.checkNotNull(token);
Ruben Brunk29931bc2016-03-11 00:24:26 -08003436 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003437 }
3438
3439 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
Ruben Brunk29931bc2016-03-11 00:24:26 -08003440 int userHandle, String[] exceptionPackages) {
Svet Ganov442ed572016-08-17 17:29:43 -07003441 synchronized (AppOpsService.this) {
3442 ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
3443
3444 if (restrictionState == null) {
3445 try {
3446 restrictionState = new ClientRestrictionState(token);
3447 } catch (RemoteException e) {
3448 return;
3449 }
3450 mOpUserRestrictions.put(token, restrictionState);
Ruben Brunk29931bc2016-03-11 00:24:26 -08003451 }
Svet Ganov442ed572016-08-17 17:29:43 -07003452
3453 if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003454 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07003455 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
Svet Ganov442ed572016-08-17 17:29:43 -07003456 }
3457
3458 if (restrictionState.isDefault()) {
3459 mOpUserRestrictions.remove(token);
3460 restrictionState.destroy();
3461 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08003462 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -04003463 }
3464
Svet Ganov3a95f832018-03-23 17:44:30 -07003465 private void notifyWatchersOfChange(int code, int uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003466 final ArraySet<ModeCallback> clonedCallbacks;
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003467 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003468 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003469 if (callbacks == null) {
3470 return;
3471 }
Dianne Hackborn68d76552017-02-27 15:32:03 -08003472 clonedCallbacks = new ArraySet<>(callbacks);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003473 }
3474
Svet Ganov3a95f832018-03-23 17:44:30 -07003475 notifyOpChanged(clonedCallbacks, code, uid, null);
Jason Monk62062992014-05-06 09:55:28 -04003476 }
3477
3478 @Override
3479 public void removeUser(int userHandle) throws RemoteException {
3480 checkSystemUid("removeUser");
Svet Ganov442ed572016-08-17 17:29:43 -07003481 synchronized (AppOpsService.this) {
3482 final int tokenCount = mOpUserRestrictions.size();
3483 for (int i = tokenCount - 1; i >= 0; i--) {
3484 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
3485 opRestrictions.removeUser(userHandle);
3486 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003487 removeUidsForUserLocked(userHandle);
3488 }
3489 }
3490
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003491 @Override
3492 public boolean isOperationActive(int code, int uid, String packageName) {
Svet Ganovf7b47252018-02-26 11:11:27 -08003493 if (Binder.getCallingUid() != uid) {
3494 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
3495 != PackageManager.PERMISSION_GRANTED) {
3496 return false;
3497 }
3498 }
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003499 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003500 final String resolvedPackageName = resolvePackageName(uid, packageName);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003501 if (resolvedPackageName == null) {
3502 return false;
3503 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003504 synchronized (AppOpsService.this) {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003505 for (int i = mClients.size() - 1; i >= 0; i--) {
3506 final ClientState client = mClients.valueAt(i);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003507 for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
3508 final Op op = client.mStartedOps.get(j);
3509 if (op.op == code && op.uid == uid) return true;
3510 }
3511 }
3512 }
3513 return false;
3514 }
3515
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003516 private void removeUidsForUserLocked(int userHandle) {
3517 for (int i = mUidStates.size() - 1; i >= 0; --i) {
3518 final int uid = mUidStates.keyAt(i);
3519 if (UserHandle.getUserId(uid) == userHandle) {
3520 mUidStates.removeAt(i);
3521 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003522 }
3523 }
3524
Jason Monk62062992014-05-06 09:55:28 -04003525 private void checkSystemUid(String function) {
3526 int uid = Binder.getCallingUid();
3527 if (uid != Process.SYSTEM_UID) {
3528 throw new SecurityException(function + " must by called by the system");
3529 }
3530 }
3531
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003532 private static String resolvePackageName(int uid, String packageName) {
Svet Ganov82f09bc2018-01-12 22:08:40 -08003533 if (uid == Process.ROOT_UID) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003534 return "root";
3535 } else if (uid == Process.SHELL_UID) {
3536 return "com.android.shell";
Svet Ganov82f09bc2018-01-12 22:08:40 -08003537 } else if (uid == Process.MEDIA_UID) {
3538 return "media";
3539 } else if (uid == Process.AUDIOSERVER_UID) {
3540 return "audioserver";
3541 } else if (uid == Process.CAMERASERVER_UID) {
3542 return "cameraserver";
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003543 } else if (uid == Process.SYSTEM_UID && packageName == null) {
3544 return "android";
3545 }
3546 return packageName;
3547 }
3548
Svet Ganov82f09bc2018-01-12 22:08:40 -08003549 private static int resolveUid(String packageName) {
3550 if (packageName == null) {
3551 return -1;
3552 }
3553 switch (packageName) {
3554 case "root":
3555 return Process.ROOT_UID;
3556 case "shell":
3557 return Process.SHELL_UID;
3558 case "media":
3559 return Process.MEDIA_UID;
3560 case "audioserver":
3561 return Process.AUDIOSERVER_UID;
3562 case "cameraserver":
3563 return Process.CAMERASERVER_UID;
3564 }
3565 return -1;
3566 }
3567
Svet Ganov2af57082015-07-30 08:44:20 -07003568 private static String[] getPackagesForUid(int uid) {
Svet Ganovf3807aa2015-08-02 10:09:56 -07003569 String[] packageNames = null;
Svet Ganov2af57082015-07-30 08:44:20 -07003570 try {
riddle_hsu40b300f2015-11-23 13:22:03 +08003571 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
Svet Ganov2af57082015-07-30 08:44:20 -07003572 } catch (RemoteException e) {
3573 /* ignore - local call */
3574 }
Svet Ganovf3807aa2015-08-02 10:09:56 -07003575 if (packageNames == null) {
3576 return EmptyArray.STRING;
3577 }
3578 return packageNames;
Svet Ganov2af57082015-07-30 08:44:20 -07003579 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003580
3581 private final class ClientRestrictionState implements DeathRecipient {
3582 private final IBinder token;
3583 SparseArray<boolean[]> perUserRestrictions;
3584 SparseArray<String[]> perUserExcludedPackages;
3585
3586 public ClientRestrictionState(IBinder token)
3587 throws RemoteException {
3588 token.linkToDeath(this, 0);
3589 this.token = token;
3590 }
3591
3592 public boolean setRestriction(int code, boolean restricted,
3593 String[] excludedPackages, int userId) {
3594 boolean changed = false;
3595
3596 if (perUserRestrictions == null && restricted) {
3597 perUserRestrictions = new SparseArray<>();
3598 }
3599
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003600 int[] users;
3601 if (userId == UserHandle.USER_ALL) {
3602 List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003603
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003604 users = new int[liveUsers.size()];
3605 for (int i = 0; i < liveUsers.size(); i++) {
3606 users[i] = liveUsers.get(i).id;
3607 }
3608 } else {
3609 users = new int[]{userId};
3610 }
3611
3612 if (perUserRestrictions != null) {
3613 int numUsers = users.length;
3614
3615 for (int i = 0; i < numUsers; i++) {
3616 int thisUserId = users[i];
3617
3618 boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
3619 if (userRestrictions == null && restricted) {
3620 userRestrictions = new boolean[AppOpsManager._NUM_OP];
3621 perUserRestrictions.put(thisUserId, userRestrictions);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003622 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003623 if (userRestrictions != null && userRestrictions[code] != restricted) {
3624 userRestrictions[code] = restricted;
3625 if (!restricted && isDefault(userRestrictions)) {
3626 perUserRestrictions.remove(thisUserId);
3627 userRestrictions = null;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003628 }
3629 changed = true;
3630 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003631
3632 if (userRestrictions != null) {
3633 final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
3634 if (perUserExcludedPackages == null && !noExcludedPackages) {
3635 perUserExcludedPackages = new SparseArray<>();
3636 }
3637 if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
3638 perUserExcludedPackages.get(thisUserId))) {
3639 if (noExcludedPackages) {
3640 perUserExcludedPackages.remove(thisUserId);
3641 if (perUserExcludedPackages.size() <= 0) {
3642 perUserExcludedPackages = null;
3643 }
3644 } else {
3645 perUserExcludedPackages.put(thisUserId, excludedPackages);
3646 }
3647 changed = true;
3648 }
3649 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003650 }
3651 }
3652
3653 return changed;
3654 }
3655
3656 public boolean hasRestriction(int restriction, String packageName, int userId) {
3657 if (perUserRestrictions == null) {
3658 return false;
3659 }
3660 boolean[] restrictions = perUserRestrictions.get(userId);
3661 if (restrictions == null) {
3662 return false;
3663 }
3664 if (!restrictions[restriction]) {
3665 return false;
3666 }
3667 if (perUserExcludedPackages == null) {
3668 return true;
3669 }
3670 String[] perUserExclusions = perUserExcludedPackages.get(userId);
3671 if (perUserExclusions == null) {
3672 return true;
3673 }
3674 return !ArrayUtils.contains(perUserExclusions, packageName);
3675 }
3676
3677 public void removeUser(int userId) {
3678 if (perUserExcludedPackages != null) {
3679 perUserExcludedPackages.remove(userId);
3680 if (perUserExcludedPackages.size() <= 0) {
3681 perUserExcludedPackages = null;
3682 }
3683 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003684 if (perUserRestrictions != null) {
3685 perUserRestrictions.remove(userId);
3686 if (perUserRestrictions.size() <= 0) {
3687 perUserRestrictions = null;
3688 }
3689 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003690 }
3691
3692 public boolean isDefault() {
3693 return perUserRestrictions == null || perUserRestrictions.size() <= 0;
3694 }
3695
3696 @Override
3697 public void binderDied() {
3698 synchronized (AppOpsService.this) {
3699 mOpUserRestrictions.remove(token);
3700 if (perUserRestrictions == null) {
3701 return;
3702 }
3703 final int userCount = perUserRestrictions.size();
3704 for (int i = 0; i < userCount; i++) {
3705 final boolean[] restrictions = perUserRestrictions.valueAt(i);
3706 final int restrictionCount = restrictions.length;
3707 for (int j = 0; j < restrictionCount; j++) {
3708 if (restrictions[j]) {
3709 final int changedCode = j;
Svet Ganov3a95f832018-03-23 17:44:30 -07003710 mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003711 }
3712 }
3713 }
3714 destroy();
3715 }
3716 }
3717
3718 public void destroy() {
3719 token.unlinkToDeath(this, 0);
3720 }
3721
3722 private boolean isDefault(boolean[] array) {
3723 if (ArrayUtils.isEmpty(array)) {
3724 return true;
3725 }
3726 for (boolean value : array) {
3727 if (value) {
3728 return false;
3729 }
3730 }
3731 return true;
3732 }
3733 }
Dianne Hackbornd5254412018-05-11 18:02:58 -07003734
3735 private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
3736 @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
3737 synchronized (AppOpsService.this) {
3738 mProfileOwners = owners;
3739 }
3740 }
3741 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003742}