blob: 169f2a863e96fda7c0bde071f916c39fe1432233 [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 Hackborn65a4f252018-05-08 17:30:48 -070024import android.content.ContentResolver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070025import android.content.Context;
26import android.content.pm.ApplicationInfo;
27import android.content.pm.IPackageManager;
28import android.content.pm.PackageManager;
29import android.content.pm.PackageManagerInternal;
30import android.content.pm.UserInfo;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070031import android.database.ContentObserver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070032import android.media.AudioAttributes;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070033import android.net.Uri;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070034import android.os.AsyncTask;
35import android.os.Binder;
36import android.os.Bundle;
37import android.os.Handler;
38import android.os.IBinder;
39import android.os.Process;
40import android.os.RemoteException;
41import android.os.ResultReceiver;
42import android.os.ServiceManager;
43import android.os.ShellCallback;
44import android.os.ShellCommand;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070045import android.os.SystemClock;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070046import android.os.UserHandle;
47import android.os.UserManager;
48import android.os.storage.StorageManagerInternal;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070049import android.provider.Settings;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070050import android.util.ArrayMap;
51import android.util.ArraySet;
52import android.util.AtomicFile;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070053import android.util.KeyValueListParser;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070054import android.util.Slog;
55import android.util.SparseArray;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -070056import android.util.SparseBooleanArray;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070057import android.util.SparseIntArray;
58import android.util.TimeUtils;
59import android.util.Xml;
60
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070061import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080062import com.android.internal.app.IAppOpsActiveCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070063import com.android.internal.app.IAppOpsCallback;
64import com.android.internal.app.IAppOpsService;
65import com.android.internal.os.Zygote;
66import com.android.internal.util.ArrayUtils;
67import com.android.internal.util.DumpUtils;
68import com.android.internal.util.FastXmlSerializer;
69import com.android.internal.util.Preconditions;
70import com.android.internal.util.XmlUtils;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080071import com.android.internal.util.function.pooled.PooledLambda;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -050072
Philip P. Moltmanne683f192017-06-23 14:05:04 -070073import libcore.util.EmptyArray;
74
75import org.xmlpull.v1.XmlPullParser;
76import org.xmlpull.v1.XmlPullParserException;
77import org.xmlpull.v1.XmlSerializer;
78
Dianne Hackborna06de0f2012-12-11 16:34:47 -080079import java.io.File;
80import java.io.FileDescriptor;
Dianne Hackborn35654b62013-01-14 17:38:02 -080081import java.io.FileInputStream;
82import java.io.FileNotFoundException;
83import java.io.FileOutputStream;
84import java.io.IOException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080085import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +010086import java.nio.charset.StandardCharsets;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070087import java.text.SimpleDateFormat;
Dianne Hackborn35654b62013-01-14 17:38:02 -080088import java.util.ArrayList;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -070089import java.util.Arrays;
Svetoslav215b44a2015-08-04 19:03:40 -070090import java.util.Collections;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070091import java.util.Date;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080092import java.util.HashMap;
Dianne Hackbornc2293022013-02-06 23:14:49 -080093import java.util.Iterator;
Dianne Hackborn35654b62013-01-14 17:38:02 -080094import java.util.List;
Dianne Hackborn607b4142013-08-02 18:10:10 -070095import java.util.Map;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080096
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070097import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
98import static android.app.AppOpsManager.UID_STATE_CACHED;
99import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
100import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
101import static android.app.AppOpsManager._NUM_UID_STATE;
102import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
103import static android.app.AppOpsManager.UID_STATE_TOP;
104
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800105public class AppOpsService extends IAppOpsService.Stub {
106 static final String TAG = "AppOps";
Dianne Hackborn35654b62013-01-14 17:38:02 -0800107 static final boolean DEBUG = false;
108
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700109 private static final int NO_VERSION = -1;
110 /** Increment by one every time and add the corresponding upgrade logic in
111 * {@link #upgradeLocked(int)} below. The first version was 1 */
112 private static final int CURRENT_VERSION = 1;
113
Dianne Hackborn35654b62013-01-14 17:38:02 -0800114 // Write at most every 30 minutes.
115 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800116
Svet Ganov3a95f832018-03-23 17:44:30 -0700117 // Constant meaning that any UID should be matched when dispatching callbacks
118 private static final int UID_ANY = -2;
119
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700120 // Map from process states to the uid states we track.
121 private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
122 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
123 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
124 UID_STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
125 UID_STATE_FOREGROUND_SERVICE, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
126 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
127 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
128 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
129 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
130 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_BACKUP
131 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_SERVICE
132 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_RECEIVER
133 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
134 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
135 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HOME
136 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
137 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
138 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
139 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_RECENT
140 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
141 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT
142 };
143
144 static final String[] UID_STATE_NAMES = new String[] {
145 "pers ", // UID_STATE_PERSISTENT
146 "top ", // UID_STATE_TOP
147 "fgsvc", // UID_STATE_FOREGROUND_SERVICE
148 "fg ", // UID_STATE_FOREGROUND
149 "bg ", // UID_STATE_BACKGROUND
150 "cch ", // UID_STATE_CACHED
151 };
152
153 static final String[] UID_STATE_TIME_ATTRS = new String[] {
154 "tp", // UID_STATE_PERSISTENT
155 "tt", // UID_STATE_TOP
156 "tfs", // UID_STATE_FOREGROUND_SERVICE
157 "tf", // UID_STATE_FOREGROUND
158 "tb", // UID_STATE_BACKGROUND
159 "tc", // UID_STATE_CACHED
160 };
161
162 static final String[] UID_STATE_REJECT_ATTRS = new String[] {
163 "rp", // UID_STATE_PERSISTENT
164 "rt", // UID_STATE_TOP
165 "rfs", // UID_STATE_FOREGROUND_SERVICE
166 "rf", // UID_STATE_FOREGROUND
167 "rb", // UID_STATE_BACKGROUND
168 "rc", // UID_STATE_CACHED
169 };
170
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800171 Context mContext;
172 final AtomicFile mFile;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800173 final Handler mHandler;
174
175 boolean mWriteScheduled;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800176 boolean mFastWriteScheduled;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800177 final Runnable mWriteRunner = new Runnable() {
178 public void run() {
179 synchronized (AppOpsService.this) {
180 mWriteScheduled = false;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800181 mFastWriteScheduled = false;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800182 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
183 @Override protected Void doInBackground(Void... params) {
184 writeState();
185 return null;
186 }
187 };
188 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
189 }
190 }
191 };
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800192
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700193 @VisibleForTesting
194 final SparseArray<UidState> mUidStates = new SparseArray<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800195
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700196 long mLastUptime;
197
Ruben Brunk29931bc2016-03-11 00:24:26 -0800198 /*
199 * These are app op restrictions imposed per user from various parties.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800200 */
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700201 private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
Jason Monk62062992014-05-06 09:55:28 -0400202
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700203 /**
204 * All times are in milliseconds. These constants are kept synchronized with the system
205 * global Settings. Any access to this class or its fields should be done while
206 * holding the AppOpsService lock.
207 */
208 private final class Constants extends ContentObserver {
209 // Key names stored in the settings value.
210 private static final String KEY_STATE_SETTLE_TIME = "state_settle_time";
211
212 /**
213 * How long we want for a drop in uid state to settle before applying it.
214 * @see Settings.Global#APP_OPS_CONSTANTS
215 * @see #KEY_STATE_SETTLE_TIME
216 */
217 public long STATE_SETTLE_TIME;
218
219
220 private final KeyValueListParser mParser = new KeyValueListParser(',');
221 private ContentResolver mResolver;
222
223 public Constants(Handler handler) {
224 super(handler);
225 updateConstants();
226 }
227
228 public void startMonitoring(ContentResolver resolver) {
229 mResolver = resolver;
230 mResolver.registerContentObserver(
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700231 Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700232 false, this);
233 updateConstants();
234 }
235
236 @Override
237 public void onChange(boolean selfChange, Uri uri) {
238 updateConstants();
239 }
240
241 private void updateConstants() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700242 String value = mResolver != null ? Settings.Global.getString(mResolver,
243 Settings.Global.APP_OPS_CONSTANTS) : "";
244
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700245 synchronized (AppOpsService.this) {
246 try {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700247 mParser.setString(value);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700248 } catch (IllegalArgumentException e) {
249 // Failed to parse the settings string, log this and move on
250 // with defaults.
251 Slog.e(TAG, "Bad app ops settings", e);
252 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700253 STATE_SETTLE_TIME = mParser.getDurationMillis(
254 KEY_STATE_SETTLE_TIME, 10 * 1000L);
255 }
256 }
257
258 void dump(PrintWriter pw) {
259 pw.println(" Settings:");
260
261 pw.print(" "); pw.print(KEY_STATE_SETTLE_TIME); pw.print("=");
262 TimeUtils.formatDuration(STATE_SETTLE_TIME, pw);
263 pw.println();
264 }
265 }
266
267 private final Constants mConstants;
268
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700269 @VisibleForTesting
270 static final class UidState {
Svet Ganov2af57082015-07-30 08:44:20 -0700271 public final int uid;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700272
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700273 public int state = UID_STATE_CACHED;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700274 public int pendingState = UID_STATE_CACHED;
275 public long pendingStateCommitTime;
276
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700277 public int startNesting;
Svet Ganov2af57082015-07-30 08:44:20 -0700278 public ArrayMap<String, Ops> pkgOps;
279 public SparseIntArray opModes;
280
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700281 // true indicates there is an interested observer, false there isn't but it has such an op
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700282 public SparseBooleanArray foregroundOps;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700283 public boolean hasForegroundWatchers;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700284
Svet Ganov2af57082015-07-30 08:44:20 -0700285 public UidState(int uid) {
286 this.uid = uid;
287 }
288
289 public void clear() {
290 pkgOps = null;
291 opModes = null;
292 }
293
294 public boolean isDefault() {
295 return (pkgOps == null || pkgOps.isEmpty())
296 && (opModes == null || opModes.size() <= 0);
297 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700298
299 int evalMode(int mode) {
300 if (mode == AppOpsManager.MODE_FOREGROUND) {
301 return state <= UID_STATE_FOREGROUND_SERVICE
302 ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
303 }
304 return mode;
305 }
306
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700307 private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
308 SparseBooleanArray which) {
309 boolean curValue = which.get(op, false);
310 ArraySet<ModeCallback> callbacks = watchers.get(op);
311 if (callbacks != null) {
312 for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
313 if ((callbacks.valueAt(cbi).mFlags
314 & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
315 hasForegroundWatchers = true;
316 curValue = true;
317 }
318 }
319 }
320 which.put(op, curValue);
321 }
322
323 public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700324 SparseBooleanArray which = null;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700325 hasForegroundWatchers = false;
326 if (opModes != null) {
327 for (int i = opModes.size() - 1; i >= 0; i--) {
328 if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
329 if (which == null) {
330 which = new SparseBooleanArray();
331 }
332 evalForegroundWatchers(opModes.keyAt(i), watchers, which);
333 }
334 }
335 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700336 if (pkgOps != null) {
337 for (int i = pkgOps.size() - 1; i >= 0; i--) {
338 Ops ops = pkgOps.valueAt(i);
339 for (int j = ops.size() - 1; j >= 0; j--) {
340 if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
341 if (which == null) {
342 which = new SparseBooleanArray();
343 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700344 evalForegroundWatchers(ops.keyAt(j), watchers, which);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700345 }
346 }
347 }
348 }
349 foregroundOps = which;
350 }
Svet Ganov2af57082015-07-30 08:44:20 -0700351 }
352
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700353 final static class Ops extends SparseArray<Op> {
354 final String packageName;
355 final UidState uidState;
356 final boolean isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800357
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700358 Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800359 packageName = _packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700360 uidState = _uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400361 isPrivileged = _isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800362 }
363 }
364
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700365 final static class Op {
366 final UidState uidState;
367 final int uid;
368 final String packageName;
369 final int op;
370 int proxyUid = -1;
371 String proxyPackageName;
372 int mode;
373 int duration;
374 long time[] = new long[_NUM_UID_STATE];
375 long rejectTime[] = new long[_NUM_UID_STATE];
376 int startNesting;
377 long startRealtime;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800378
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700379 Op(UidState _uidState, String _packageName, int _op) {
380 uidState = _uidState;
381 uid = _uidState.uid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700382 packageName = _packageName;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800383 op = _op;
David Braunf5d83192013-09-16 13:43:51 -0700384 mode = AppOpsManager.opToDefaultMode(op);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800385 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700386
387 boolean hasAnyTime() {
388 for (int i = 0; i < AppOpsManager._NUM_UID_STATE; i++) {
389 if (time[i] != 0) {
390 return true;
391 }
392 if (rejectTime[i] != 0) {
393 return true;
394 }
395 }
396 return false;
397 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700398
399 int getMode() {
400 return uidState.evalMode(mode);
401 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800402 }
403
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800404 final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
405 final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
406 final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
407 final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
Dianne Hackborn68d76552017-02-27 15:32:03 -0800408 final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800409
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700410 final class ModeCallback implements DeathRecipient {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800411 final IAppOpsCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700412 final int mWatchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700413 final int mFlags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700414 final int mCallingUid;
415 final int mCallingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800416
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700417 ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700418 int callingPid) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800419 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700420 mWatchingUid = watchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700421 mFlags = flags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700422 mCallingUid = callingUid;
423 mCallingPid = callingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800424 try {
425 mCallback.asBinder().linkToDeath(this, 0);
426 } catch (RemoteException e) {
427 }
428 }
429
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700430 public boolean isWatchingUid(int uid) {
431 return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
432 }
433
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700434 @Override
435 public String toString() {
436 StringBuilder sb = new StringBuilder(128);
437 sb.append("ModeCallback{");
438 sb.append(Integer.toHexString(System.identityHashCode(this)));
439 sb.append(" watchinguid=");
440 UserHandle.formatUid(sb, mWatchingUid);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700441 sb.append(" flags=0x");
442 sb.append(Integer.toHexString(mFlags));
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700443 sb.append(" from uid=");
444 UserHandle.formatUid(sb, mCallingUid);
445 sb.append(" pid=");
446 sb.append(mCallingPid);
447 sb.append('}');
448 return sb.toString();
449 }
450
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700451 void unlinkToDeath() {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800452 mCallback.asBinder().unlinkToDeath(this, 0);
453 }
454
455 @Override
456 public void binderDied() {
457 stopWatchingMode(mCallback);
458 }
459 }
460
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700461 final class ActiveCallback implements DeathRecipient {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800462 final IAppOpsActiveCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700463 final int mWatchingUid;
464 final int mCallingUid;
465 final int mCallingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800466
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700467 ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700468 int callingPid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800469 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700470 mWatchingUid = watchingUid;
471 mCallingUid = callingUid;
472 mCallingPid = callingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800473 try {
474 mCallback.asBinder().linkToDeath(this, 0);
475 } catch (RemoteException e) {
476 }
477 }
478
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700479 @Override
480 public String toString() {
481 StringBuilder sb = new StringBuilder(128);
482 sb.append("ActiveCallback{");
483 sb.append(Integer.toHexString(System.identityHashCode(this)));
484 sb.append(" watchinguid=");
485 UserHandle.formatUid(sb, mWatchingUid);
486 sb.append(" from uid=");
487 UserHandle.formatUid(sb, mCallingUid);
488 sb.append(" pid=");
489 sb.append(mCallingPid);
490 sb.append('}');
491 return sb.toString();
492 }
493
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700494 void destroy() {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800495 mCallback.asBinder().unlinkToDeath(this, 0);
496 }
497
498 @Override
499 public void binderDied() {
500 stopWatchingActive(mCallback);
501 }
502 }
503
Svet Ganova7a0db62018-02-27 20:08:01 -0800504 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700505
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700506 final class ClientState extends Binder implements DeathRecipient {
Svet Ganovf7b47252018-02-26 11:11:27 -0800507 final ArrayList<Op> mStartedOps = new ArrayList<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700508 final IBinder mAppToken;
509 final int mPid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700510
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700511 ClientState(IBinder appToken) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700512 mAppToken = appToken;
513 mPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -0800514 // Watch only for remote processes dying
515 if (!(appToken instanceof Binder)) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700516 try {
517 mAppToken.linkToDeath(this, 0);
518 } catch (RemoteException e) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800519 /* do nothing */
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700520 }
521 }
522 }
523
524 @Override
525 public String toString() {
526 return "ClientState{" +
527 "mAppToken=" + mAppToken +
Svet Ganovf7b47252018-02-26 11:11:27 -0800528 ", " + "pid=" + mPid +
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700529 '}';
530 }
531
532 @Override
533 public void binderDied() {
534 synchronized (AppOpsService.this) {
535 for (int i=mStartedOps.size()-1; i>=0; i--) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800536 finishOperationLocked(mStartedOps.get(i), /*finishNested*/ true);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700537 }
538 mClients.remove(mAppToken);
539 }
540 }
541 }
542
Jeff Brown6f357d32014-01-15 20:40:55 -0800543 public AppOpsService(File storagePath, Handler handler) {
Jeff Sharkey5f3e9342017-03-13 14:53:11 -0600544 LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
Dianne Hackborne17b4452018-01-10 13:15:40 -0800545 mFile = new AtomicFile(storagePath, "appops");
Jeff Brown6f357d32014-01-15 20:40:55 -0800546 mHandler = handler;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700547 mConstants = new Constants(mHandler);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800548 readState();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800549 }
David Braunf5d83192013-09-16 13:43:51 -0700550
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800551 public void publish(Context context) {
552 mContext = context;
553 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
554 }
555
Dianne Hackborn514074f2013-02-11 10:52:46 -0800556 public void systemReady() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700557 mConstants.startMonitoring(mContext.getContentResolver());
558
Dianne Hackborn514074f2013-02-11 10:52:46 -0800559 synchronized (this) {
560 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700561 for (int i = mUidStates.size() - 1; i >= 0; i--) {
562 UidState uidState = mUidStates.valueAt(i);
563
564 String[] packageNames = getPackagesForUid(uidState.uid);
565 if (ArrayUtils.isEmpty(packageNames)) {
566 uidState.clear();
567 mUidStates.removeAt(i);
568 changed = true;
569 continue;
570 }
571
572 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
573 if (pkgs == null) {
574 continue;
575 }
576
Dianne Hackborn514074f2013-02-11 10:52:46 -0800577 Iterator<Ops> it = pkgs.values().iterator();
578 while (it.hasNext()) {
579 Ops ops = it.next();
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700580 int curUid = -1;
Dianne Hackborn514074f2013-02-11 10:52:46 -0800581 try {
Jeff Sharkeycd654482016-01-08 17:42:11 -0700582 curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
583 PackageManager.MATCH_UNINSTALLED_PACKAGES,
Svet Ganov2af57082015-07-30 08:44:20 -0700584 UserHandle.getUserId(ops.uidState.uid));
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700585 } catch (RemoteException ignored) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800586 }
Svet Ganov2af57082015-07-30 08:44:20 -0700587 if (curUid != ops.uidState.uid) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800588 Slog.i(TAG, "Pruning old package " + ops.packageName
Svet Ganov2af57082015-07-30 08:44:20 -0700589 + "/" + ops.uidState + ": new uid=" + curUid);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800590 it.remove();
591 changed = true;
592 }
593 }
Svet Ganov2af57082015-07-30 08:44:20 -0700594
595 if (uidState.isDefault()) {
596 mUidStates.removeAt(i);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800597 }
598 }
599 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800600 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800601 }
602 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700603
Suprabh Shuklaaef25132017-01-23 18:09:03 -0800604 PackageManagerInternal packageManagerInternal = LocalServices.getService(
605 PackageManagerInternal.class);
606 packageManagerInternal.setExternalSourcesPolicy(
607 new PackageManagerInternal.ExternalSourcesPolicy() {
608 @Override
609 public int getPackageTrustedToInstallApps(String packageName, int uid) {
610 int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
611 uid, packageName);
612 switch (appOpMode) {
613 case AppOpsManager.MODE_ALLOWED:
614 return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
615 case AppOpsManager.MODE_ERRORED:
616 return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
617 default:
618 return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
619 }
620 }
621 });
622
Sudheer Shanka2250d562016-11-07 15:41:02 -0800623 StorageManagerInternal storageManagerInternal = LocalServices.getService(
624 StorageManagerInternal.class);
625 storageManagerInternal.addExternalStoragePolicy(
626 new StorageManagerInternal.ExternalStorageMountPolicy() {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700627 @Override
628 public int getMountMode(int uid, String packageName) {
629 if (Process.isIsolated(uid)) {
630 return Zygote.MOUNT_EXTERNAL_NONE;
631 }
632 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
633 packageName) != AppOpsManager.MODE_ALLOWED) {
634 return Zygote.MOUNT_EXTERNAL_NONE;
635 }
636 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
637 packageName) != AppOpsManager.MODE_ALLOWED) {
638 return Zygote.MOUNT_EXTERNAL_READ;
639 }
640 return Zygote.MOUNT_EXTERNAL_WRITE;
641 }
642
643 @Override
644 public boolean hasExternalStorage(int uid, String packageName) {
645 final int mountMode = getMountMode(uid, packageName);
646 return mountMode == Zygote.MOUNT_EXTERNAL_READ
647 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
648 }
649 });
Dianne Hackborn514074f2013-02-11 10:52:46 -0800650 }
651
652 public void packageRemoved(int uid, String packageName) {
653 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700654 UidState uidState = mUidStates.get(uid);
655 if (uidState == null) {
656 return;
657 }
658
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800659 Ops ops = null;
Svet Ganov2af57082015-07-30 08:44:20 -0700660
661 // Remove any package state if such.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800662 if (uidState.pkgOps != null) {
663 ops = uidState.pkgOps.remove(packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700664 }
665
666 // If we just nuked the last package state check if the UID is valid.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800667 if (ops != null && uidState.pkgOps.isEmpty()
Svet Ganov2af57082015-07-30 08:44:20 -0700668 && getPackagesForUid(uid).length <= 0) {
669 mUidStates.remove(uid);
670 }
671
Svet Ganova7a0db62018-02-27 20:08:01 -0800672 // Finish ops other packages started on behalf of the package.
673 final int clientCount = mClients.size();
674 for (int i = 0; i < clientCount; i++) {
675 final ClientState client = mClients.valueAt(i);
676 if (client.mStartedOps == null) {
677 continue;
678 }
679 final int opCount = client.mStartedOps.size();
680 for (int j = opCount - 1; j >= 0; j--) {
681 final Op op = client.mStartedOps.get(j);
682 if (uid == op.uid && packageName.equals(op.packageName)) {
683 finishOperationLocked(op, /*finishNested*/ true);
684 client.mStartedOps.remove(j);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700685 if (op.startNesting <= 0) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800686 scheduleOpActiveChangedIfNeededLocked(op.op,
687 uid, packageName, false);
688 }
689 }
690 }
691 }
692
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800693 if (ops != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700694 scheduleFastWriteLocked();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800695
696 final int opCount = ops.size();
697 for (int i = 0; i < opCount; i++) {
698 final Op op = ops.valueAt(i);
699 if (op.duration == -1) {
700 scheduleOpActiveChangedIfNeededLocked(
701 op.op, op.uid, op.packageName, false);
702 }
703 }
Dianne Hackborn514074f2013-02-11 10:52:46 -0800704 }
705 }
706 }
707
708 public void uidRemoved(int uid) {
709 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700710 if (mUidStates.indexOfKey(uid) >= 0) {
711 mUidStates.remove(uid);
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800712 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800713 }
714 }
715 }
716
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700717 public void updateUidProcState(int uid, int procState) {
718 synchronized (this) {
719 final UidState uidState = getUidStateLocked(uid, true);
720 final int newState = PROCESS_STATE_TO_UID_STATE[procState];
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700721 if (uidState != null && uidState.pendingState != newState) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700722 final int oldPendingState = uidState.pendingState;
723 uidState.pendingState = newState;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700724 if (newState < uidState.state) {
725 // We are moving to a more important state, always do it immediately.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700726 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700727 } else if (uidState.pendingStateCommitTime == 0) {
728 // We are moving to a less important state for the first time,
729 // delay the application for a bit.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700730 uidState.pendingStateCommitTime = SystemClock.uptimeMillis() +
731 mConstants.STATE_SETTLE_TIME;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700732 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700733 if (uidState.startNesting != 0) {
734 // There is some actively running operation... need to find it
735 // and appropriately update its state.
736 final long now = System.currentTimeMillis();
737 for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
738 final Ops ops = uidState.pkgOps.valueAt(i);
739 for (int j = ops.size() - 1; j >= 0; j--) {
740 final Op op = ops.valueAt(j);
741 if (op.startNesting > 0) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700742 op.time[oldPendingState] = now;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700743 op.time[newState] = now;
744 }
745 }
746 }
747 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700748 }
749 }
750 }
751
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800752 public void shutdown() {
753 Slog.w(TAG, "Writing app ops before shutdown...");
Dianne Hackborn35654b62013-01-14 17:38:02 -0800754 boolean doWrite = false;
755 synchronized (this) {
756 if (mWriteScheduled) {
757 mWriteScheduled = false;
758 doWrite = true;
759 }
760 }
761 if (doWrite) {
762 writeState();
763 }
764 }
765
Dianne Hackborn72e39832013-01-18 18:36:09 -0800766 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
767 ArrayList<AppOpsManager.OpEntry> resOps = null;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700768 final long elapsedNow = SystemClock.elapsedRealtime();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800769 if (ops == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700770 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800771 for (int j=0; j<pkgOps.size(); j++) {
772 Op curOp = pkgOps.valueAt(j);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700773 long duration = curOp.duration == -1
774 ? (elapsedNow - curOp.startRealtime)
775 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800776 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700777 curOp.rejectTime, (int) duration, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700778 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800779 }
780 } else {
781 for (int j=0; j<ops.length; j++) {
782 Op curOp = pkgOps.get(ops[j]);
783 if (curOp != null) {
784 if (resOps == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700785 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800786 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700787 long duration = curOp.duration == -1
788 ? (elapsedNow - curOp.startRealtime)
789 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800790 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700791 curOp.rejectTime, (int) duration, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700792 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800793 }
794 }
795 }
796 return resOps;
797 }
798
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700799 private ArrayList<AppOpsManager.OpEntry> collectOps(SparseIntArray uidOps, int[] ops) {
800 ArrayList<AppOpsManager.OpEntry> resOps = null;
801 if (ops == null) {
802 resOps = new ArrayList<>();
803 for (int j=0; j<uidOps.size(); j++) {
804 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(j), uidOps.valueAt(j),
805 0, 0, 0, -1, null));
806 }
807 } else {
808 for (int j=0; j<ops.length; j++) {
809 int index = uidOps.indexOfKey(ops[j]);
810 if (index >= 0) {
811 if (resOps == null) {
812 resOps = new ArrayList<>();
813 }
814 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(index), uidOps.valueAt(index),
815 0, 0, 0, -1, null));
816 }
817 }
818 }
819 return resOps;
820 }
821
Dianne Hackborn35654b62013-01-14 17:38:02 -0800822 @Override
823 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
824 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
825 Binder.getCallingPid(), Binder.getCallingUid(), null);
826 ArrayList<AppOpsManager.PackageOps> res = null;
827 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700828 final int uidStateCount = mUidStates.size();
829 for (int i = 0; i < uidStateCount; i++) {
830 UidState uidState = mUidStates.valueAt(i);
831 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
832 continue;
833 }
834 ArrayMap<String, Ops> packages = uidState.pkgOps;
835 final int packageCount = packages.size();
836 for (int j = 0; j < packageCount; j++) {
837 Ops pkgOps = packages.valueAt(j);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800838 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800839 if (resOps != null) {
840 if (res == null) {
841 res = new ArrayList<AppOpsManager.PackageOps>();
842 }
843 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700844 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800845 res.add(resPackage);
846 }
847 }
848 }
849 }
850 return res;
851 }
852
853 @Override
Dianne Hackborn72e39832013-01-18 18:36:09 -0800854 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
855 int[] ops) {
856 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
857 Binder.getCallingPid(), Binder.getCallingUid(), null);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000858 String resolvedPackageName = resolvePackageName(uid, packageName);
859 if (resolvedPackageName == null) {
860 return Collections.emptyList();
861 }
Dianne Hackborn72e39832013-01-18 18:36:09 -0800862 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -0700863 Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
864 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800865 if (pkgOps == null) {
866 return null;
867 }
868 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
869 if (resOps == null) {
870 return null;
871 }
872 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
873 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700874 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800875 res.add(resPackage);
876 return res;
877 }
878 }
879
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700880 @Override
881 public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
882 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
883 Binder.getCallingPid(), Binder.getCallingUid(), null);
884 synchronized (this) {
885 UidState uidState = getUidStateLocked(uid, false);
886 if (uidState == null) {
887 return null;
888 }
889 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState.opModes, ops);
890 if (resOps == null) {
891 return null;
892 }
893 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
894 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
895 null, uidState.uid, resOps);
896 res.add(resPackage);
897 return res;
898 }
899 }
900
Dianne Hackborn607b4142013-08-02 18:10:10 -0700901 private void pruneOp(Op op, int uid, String packageName) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700902 if (!op.hasAnyTime()) {
Yohei Yukawaa965d652017-10-12 15:02:26 -0700903 Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
904 false /* uidMismatchExpected */);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700905 if (ops != null) {
906 ops.remove(op.op);
907 if (ops.size() <= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -0700908 UidState uidState = ops.uidState;
909 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700910 if (pkgOps != null) {
911 pkgOps.remove(ops.packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700912 if (pkgOps.isEmpty()) {
913 uidState.pkgOps = null;
914 }
915 if (uidState.isDefault()) {
916 mUidStates.remove(uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700917 }
918 }
919 }
920 }
921 }
922 }
923
Dianne Hackborn72e39832013-01-18 18:36:09 -0800924 @Override
Svet Ganov2af57082015-07-30 08:44:20 -0700925 public void setUidMode(int code, int uid, int mode) {
926 if (Binder.getCallingPid() != Process.myPid()) {
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -0800927 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
Svet Ganov2af57082015-07-30 08:44:20 -0700928 Binder.getCallingPid(), Binder.getCallingUid(), null);
929 }
930 verifyIncomingOp(code);
931 code = AppOpsManager.opToSwitch(code);
932
933 synchronized (this) {
934 final int defaultMode = AppOpsManager.opToDefaultMode(code);
935
936 UidState uidState = getUidStateLocked(uid, false);
937 if (uidState == null) {
938 if (mode == defaultMode) {
939 return;
940 }
941 uidState = new UidState(uid);
942 uidState.opModes = new SparseIntArray();
943 uidState.opModes.put(code, mode);
944 mUidStates.put(uid, uidState);
945 scheduleWriteLocked();
946 } else if (uidState.opModes == null) {
947 if (mode != defaultMode) {
948 uidState.opModes = new SparseIntArray();
949 uidState.opModes.put(code, mode);
950 scheduleWriteLocked();
951 }
952 } else {
953 if (uidState.opModes.get(code) == mode) {
954 return;
955 }
956 if (mode == defaultMode) {
957 uidState.opModes.delete(code);
958 if (uidState.opModes.size() <= 0) {
959 uidState.opModes = null;
960 }
961 } else {
962 uidState.opModes.put(code, mode);
963 }
964 scheduleWriteLocked();
965 }
966 }
967
Svetoslav215b44a2015-08-04 19:03:40 -0700968 String[] uidPackageNames = getPackagesForUid(uid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800969 ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
Svet Ganov2af57082015-07-30 08:44:20 -0700970
riddle_hsu40b300f2015-11-23 13:22:03 +0800971 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800972 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -0700973 if (callbacks != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700974 final int callbackCount = callbacks.size();
975 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800976 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +0800977 ArraySet<String> changedPackages = new ArraySet<>();
978 Collections.addAll(changedPackages, uidPackageNames);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700979 if (callbackSpecs == null) {
980 callbackSpecs = new ArrayMap<>();
981 }
riddle_hsu40b300f2015-11-23 13:22:03 +0800982 callbackSpecs.put(callback, changedPackages);
983 }
984 }
985
986 for (String uidPackageName : uidPackageNames) {
987 callbacks = mPackageModeWatchers.get(uidPackageName);
988 if (callbacks != null) {
989 if (callbackSpecs == null) {
990 callbackSpecs = new ArrayMap<>();
Svet Ganov2af57082015-07-30 08:44:20 -0700991 }
riddle_hsu40b300f2015-11-23 13:22:03 +0800992 final int callbackCount = callbacks.size();
993 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800994 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +0800995 ArraySet<String> changedPackages = callbackSpecs.get(callback);
996 if (changedPackages == null) {
997 changedPackages = new ArraySet<>();
998 callbackSpecs.put(callback, changedPackages);
999 }
1000 changedPackages.add(uidPackageName);
1001 }
Svet Ganov2af57082015-07-30 08:44:20 -07001002 }
1003 }
1004 }
1005
1006 if (callbackSpecs == null) {
1007 return;
1008 }
1009
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001010 for (int i = 0; i < callbackSpecs.size(); i++) {
1011 final ModeCallback callback = callbackSpecs.keyAt(i);
1012 final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
1013 if (reportedPackageNames == null) {
1014 mHandler.sendMessage(PooledLambda.obtainMessage(
1015 AppOpsService::notifyOpChanged,
1016 this, callback, code, uid, (String) null));
1017
1018 } else {
1019 final int reportedPackageCount = reportedPackageNames.size();
1020 for (int j = 0; j < reportedPackageCount; j++) {
1021 final String reportedPackageName = reportedPackageNames.valueAt(j);
1022 mHandler.sendMessage(PooledLambda.obtainMessage(
1023 AppOpsService::notifyOpChanged,
1024 this, callback, code, uid, reportedPackageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001025 }
1026 }
Svet Ganov2af57082015-07-30 08:44:20 -07001027 }
1028 }
1029
1030 @Override
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001031 public void setMode(int code, int uid, String packageName, int mode) {
Dianne Hackbornb64afe12014-07-22 16:29:04 -07001032 if (Binder.getCallingPid() != Process.myPid()) {
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -08001033 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
Dianne Hackbornb64afe12014-07-22 16:29:04 -07001034 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborn133b9df2014-07-01 13:06:10 -07001035 }
Dianne Hackborn961321f2013-02-05 17:22:41 -08001036 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001037 ArraySet<ModeCallback> repCbs = null;
Dianne Hackbornc2293022013-02-06 23:14:49 -08001038 code = AppOpsManager.opToSwitch(code);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001039 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001040 UidState uidState = getUidStateLocked(uid, false);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001041 Op op = getOpLocked(code, uid, packageName, true);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001042 if (op != null) {
1043 if (op.mode != mode) {
1044 op.mode = mode;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001045 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001046 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001047 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001048 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001049 if (cbs != null) {
1050 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001051 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001052 }
1053 repCbs.addAll(cbs);
1054 }
1055 cbs = mPackageModeWatchers.get(packageName);
1056 if (cbs != null) {
1057 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001058 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001059 }
1060 repCbs.addAll(cbs);
1061 }
David Braunf5d83192013-09-16 13:43:51 -07001062 if (mode == AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001063 // If going into the default mode, prune this op
1064 // if there is nothing else interesting in it.
Dianne Hackborn607b4142013-08-02 18:10:10 -07001065 pruneOp(op, uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001066 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001067 scheduleFastWriteLocked();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001068 }
1069 }
1070 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001071 if (repCbs != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001072 mHandler.sendMessage(PooledLambda.obtainMessage(
1073 AppOpsService::notifyOpChanged,
1074 this, repCbs, code, uid, packageName));
Dianne Hackbornc2293022013-02-06 23:14:49 -08001075 }
1076 }
1077
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001078 private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
1079 int uid, String packageName) {
1080 for (int i = 0; i < callbacks.size(); i++) {
1081 final ModeCallback callback = callbacks.valueAt(i);
1082 notifyOpChanged(callback, code, uid, packageName);
1083 }
1084 }
1085
1086 private void notifyOpChanged(ModeCallback callback, int code,
1087 int uid, String packageName) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001088 if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001089 return;
1090 }
1091 // There are components watching for mode changes such as window manager
1092 // and location manager which are in our process. The callbacks in these
1093 // components may require permissions our remote caller does not have.
1094 final long identity = Binder.clearCallingIdentity();
1095 try {
1096 callback.mCallback.opChanged(code, uid, packageName);
1097 } catch (RemoteException e) {
1098 /* ignore */
1099 } finally {
1100 Binder.restoreCallingIdentity(identity);
1101 }
1102 }
1103
1104 private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
1105 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
1106 int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001107 if (cbs == null) {
1108 return callbacks;
1109 }
1110 if (callbacks == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001111 callbacks = new HashMap<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001112 }
Svet Ganov2af57082015-07-30 08:44:20 -07001113 boolean duplicate = false;
Dianne Hackborn68d76552017-02-27 15:32:03 -08001114 final int N = cbs.size();
1115 for (int i=0; i<N; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001116 ModeCallback cb = cbs.valueAt(i);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001117 ArrayList<ChangeRec> reports = callbacks.get(cb);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001118 if (reports == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001119 reports = new ArrayList<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001120 callbacks.put(cb, reports);
Svet Ganov2af57082015-07-30 08:44:20 -07001121 } else {
1122 final int reportCount = reports.size();
1123 for (int j = 0; j < reportCount; j++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001124 ChangeRec report = reports.get(j);
1125 if (report.op == op && report.pkg.equals(packageName)) {
Svet Ganov2af57082015-07-30 08:44:20 -07001126 duplicate = true;
1127 break;
1128 }
1129 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001130 }
Svet Ganov2af57082015-07-30 08:44:20 -07001131 if (!duplicate) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001132 reports.add(new ChangeRec(op, uid, packageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001133 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001134 }
1135 return callbacks;
1136 }
1137
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001138 static final class ChangeRec {
1139 final int op;
1140 final int uid;
1141 final String pkg;
1142
1143 ChangeRec(int _op, int _uid, String _pkg) {
1144 op = _op;
1145 uid = _uid;
1146 pkg = _pkg;
1147 }
1148 }
1149
Dianne Hackborn607b4142013-08-02 18:10:10 -07001150 @Override
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001151 public void resetAllModes(int reqUserId, String reqPackageName) {
1152 final int callingPid = Binder.getCallingPid();
1153 final int callingUid = Binder.getCallingUid();
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -08001154 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001155 callingPid, callingUid, null);
1156 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
1157 true, true, "resetAllModes", null);
Svet Ganov2af57082015-07-30 08:44:20 -07001158
1159 int reqUid = -1;
1160 if (reqPackageName != null) {
1161 try {
1162 reqUid = AppGlobals.getPackageManager().getPackageUid(
Jeff Sharkeycd654482016-01-08 17:42:11 -07001163 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
Svet Ganov2af57082015-07-30 08:44:20 -07001164 } catch (RemoteException e) {
1165 /* ignore - local call */
1166 }
1167 }
1168
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001169 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001170 synchronized (this) {
1171 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -07001172 for (int i = mUidStates.size() - 1; i >= 0; i--) {
1173 UidState uidState = mUidStates.valueAt(i);
1174
1175 SparseIntArray opModes = uidState.opModes;
1176 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
1177 final int uidOpCount = opModes.size();
1178 for (int j = uidOpCount - 1; j >= 0; j--) {
1179 final int code = opModes.keyAt(j);
1180 if (AppOpsManager.opAllowsReset(code)) {
1181 opModes.removeAt(j);
1182 if (opModes.size() <= 0) {
1183 uidState.opModes = null;
1184 }
1185 for (String packageName : getPackagesForUid(uidState.uid)) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001186 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001187 mOpModeWatchers.get(code));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001188 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001189 mPackageModeWatchers.get(packageName));
1190 }
1191 }
1192 }
1193 }
1194
1195 if (uidState.pkgOps == null) {
1196 continue;
1197 }
1198
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001199 if (reqUserId != UserHandle.USER_ALL
Svet Ganov2af57082015-07-30 08:44:20 -07001200 && reqUserId != UserHandle.getUserId(uidState.uid)) {
Alexandra Gherghinad6a98972014-08-04 17:05:34 +01001201 // Skip any ops for a different user
1202 continue;
1203 }
Svet Ganov2af57082015-07-30 08:44:20 -07001204
1205 Map<String, Ops> packages = uidState.pkgOps;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001206 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001207 boolean uidChanged = false;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001208 while (it.hasNext()) {
1209 Map.Entry<String, Ops> ent = it.next();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001210 String packageName = ent.getKey();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001211 if (reqPackageName != null && !reqPackageName.equals(packageName)) {
1212 // Skip any ops for a different package
1213 continue;
1214 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001215 Ops pkgOps = ent.getValue();
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001216 for (int j=pkgOps.size()-1; j>=0; j--) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001217 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn8828d3a2013-09-25 16:47:10 -07001218 if (AppOpsManager.opAllowsReset(curOp.op)
1219 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
David Braunf5d83192013-09-16 13:43:51 -07001220 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001221 changed = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001222 uidChanged = true;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001223 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001224 mOpModeWatchers.get(curOp.op));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001225 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001226 mPackageModeWatchers.get(packageName));
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001227 if (!curOp.hasAnyTime()) {
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001228 pkgOps.removeAt(j);
1229 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001230 }
1231 }
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001232 if (pkgOps.size() == 0) {
1233 it.remove();
1234 }
1235 }
Svet Ganov2af57082015-07-30 08:44:20 -07001236 if (uidState.isDefault()) {
1237 mUidStates.remove(uidState.uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001238 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001239 if (uidChanged) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001240 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001241 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001242 }
Svet Ganov2af57082015-07-30 08:44:20 -07001243
Dianne Hackborn607b4142013-08-02 18:10:10 -07001244 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001245 scheduleFastWriteLocked();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001246 }
1247 }
1248 if (callbacks != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001249 for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
1250 ModeCallback cb = ent.getKey();
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001251 ArrayList<ChangeRec> reports = ent.getValue();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001252 for (int i=0; i<reports.size(); i++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001253 ChangeRec rep = reports.get(i);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001254 mHandler.sendMessage(PooledLambda.obtainMessage(
1255 AppOpsService::notifyOpChanged,
1256 this, cb, rep.op, rep.uid, rep.pkg));
Dianne Hackborn607b4142013-08-02 18:10:10 -07001257 }
1258 }
1259 }
1260 }
1261
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001262 private void evalAllForegroundOpsLocked() {
1263 for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
1264 final UidState uidState = mUidStates.valueAt(uidi);
1265 if (uidState.foregroundOps != null) {
1266 uidState.evalForegroundOps(mOpModeWatchers);
1267 }
1268 }
1269 }
1270
Dianne Hackbornc2293022013-02-06 23:14:49 -08001271 @Override
1272 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001273 startWatchingModeWithFlags(op, packageName, 0, callback);
1274 }
1275
1276 @Override
1277 public void startWatchingModeWithFlags(int op, String packageName, int flags,
1278 IAppOpsCallback callback) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001279 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001280 final int callingUid = Binder.getCallingUid();
1281 final int callingPid = Binder.getCallingPid();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001282 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1283 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001284 watchedUid = callingUid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001285 }
1286 Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
1287 AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001288 if (callback == null) {
1289 return;
1290 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001291 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001292 op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001293 ModeCallback cb = mModeWatchers.get(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001294 if (cb == null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001295 cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001296 mModeWatchers.put(callback.asBinder(), cb);
1297 }
1298 if (op != AppOpsManager.OP_NONE) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001299 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001300 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001301 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001302 mOpModeWatchers.put(op, cbs);
1303 }
1304 cbs.add(cb);
1305 }
1306 if (packageName != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001307 ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001308 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001309 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001310 mPackageModeWatchers.put(packageName, cbs);
1311 }
1312 cbs.add(cb);
1313 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001314 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001315 }
1316 }
1317
1318 @Override
1319 public void stopWatchingMode(IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001320 if (callback == null) {
1321 return;
1322 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001323 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001324 ModeCallback cb = mModeWatchers.remove(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001325 if (cb != null) {
1326 cb.unlinkToDeath();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001327 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001328 ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001329 cbs.remove(cb);
1330 if (cbs.size() <= 0) {
1331 mOpModeWatchers.removeAt(i);
1332 }
1333 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001334 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001335 ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001336 cbs.remove(cb);
1337 if (cbs.size() <= 0) {
1338 mPackageModeWatchers.removeAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001339 }
1340 }
1341 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001342 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001343 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001344 }
1345
1346 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001347 public IBinder getToken(IBinder clientToken) {
1348 synchronized (this) {
1349 ClientState cs = mClients.get(clientToken);
1350 if (cs == null) {
1351 cs = new ClientState(clientToken);
1352 mClients.put(clientToken, cs);
1353 }
1354 return cs;
1355 }
1356 }
1357
1358 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -08001359 public int checkOperation(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001360 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001361 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001362 String resolvedPackageName = resolvePackageName(uid, packageName);
1363 if (resolvedPackageName == null) {
1364 return AppOpsManager.MODE_IGNORED;
1365 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001366 synchronized (this) {
Svet Ganov442ed572016-08-17 17:29:43 -07001367 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001368 return AppOpsManager.MODE_IGNORED;
1369 }
Svet Ganov2af57082015-07-30 08:44:20 -07001370 code = AppOpsManager.opToSwitch(code);
1371 UidState uidState = getUidStateLocked(uid, false);
Svet Ganovee438d42017-01-19 18:04:38 -08001372 if (uidState != null && uidState.opModes != null
1373 && uidState.opModes.indexOfKey(code) >= 0) {
1374 return uidState.opModes.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001375 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001376 Op op = getOpLocked(code, uid, resolvedPackageName, false);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001377 if (op == null) {
David Braunf5d83192013-09-16 13:43:51 -07001378 return AppOpsManager.opToDefaultMode(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001379 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001380 return op.mode;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001381 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001382 }
1383
1384 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001385 public int checkAudioOperation(int code, int usage, int uid, String packageName) {
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00001386 boolean suspended;
1387 try {
1388 suspended = isPackageSuspendedForUser(packageName, uid);
1389 } catch (IllegalArgumentException ex) {
1390 // Package not found.
1391 suspended = false;
1392 }
1393
1394 if (suspended) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001395 Slog.i(TAG, "Audio disabled for suspended package=" + packageName + " for uid=" + uid);
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001396 return AppOpsManager.MODE_IGNORED;
1397 }
1398
John Spurlock1af30c72014-03-10 08:33:35 -04001399 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001400 final int mode = checkRestrictionLocked(code, usage, uid, packageName);
John Spurlock1af30c72014-03-10 08:33:35 -04001401 if (mode != AppOpsManager.MODE_ALLOWED) {
1402 return mode;
1403 }
1404 }
1405 return checkOperation(code, uid, packageName);
1406 }
1407
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001408 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001409 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001410 return AppGlobals.getPackageManager().isPackageSuspendedForUser(
1411 pkg, UserHandle.getUserId(uid));
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001412 } catch (RemoteException re) {
1413 throw new SecurityException("Could not talk to package manager service");
1414 }
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001415 }
1416
John Spurlock7b414672014-07-18 13:02:39 -04001417 private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
1418 final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1419 if (usageRestrictions != null) {
1420 final Restriction r = usageRestrictions.get(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001421 if (r != null && !r.exceptionPackages.contains(packageName)) {
1422 return r.mode;
1423 }
1424 }
1425 return AppOpsManager.MODE_ALLOWED;
1426 }
1427
1428 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001429 public void setAudioRestriction(int code, int usage, int uid, int mode,
John Spurlock1af30c72014-03-10 08:33:35 -04001430 String[] exceptionPackages) {
1431 verifyIncomingUid(uid);
1432 verifyIncomingOp(code);
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -08001433 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
1434 Binder.getCallingPid(), Binder.getCallingUid(), null);
John Spurlock1af30c72014-03-10 08:33:35 -04001435 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001436 SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1437 if (usageRestrictions == null) {
1438 usageRestrictions = new SparseArray<Restriction>();
1439 mAudioRestrictions.put(code, usageRestrictions);
John Spurlock1af30c72014-03-10 08:33:35 -04001440 }
John Spurlock7b414672014-07-18 13:02:39 -04001441 usageRestrictions.remove(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001442 if (mode != AppOpsManager.MODE_ALLOWED) {
1443 final Restriction r = new Restriction();
1444 r.mode = mode;
1445 if (exceptionPackages != null) {
1446 final int N = exceptionPackages.length;
1447 r.exceptionPackages = new ArraySet<String>(N);
1448 for (int i = 0; i < N; i++) {
1449 final String pkg = exceptionPackages[i];
1450 if (pkg != null) {
1451 r.exceptionPackages.add(pkg.trim());
1452 }
1453 }
1454 }
John Spurlock7b414672014-07-18 13:02:39 -04001455 usageRestrictions.put(usage, r);
John Spurlock1af30c72014-03-10 08:33:35 -04001456 }
1457 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001458
1459 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07001460 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
John Spurlock1af30c72014-03-10 08:33:35 -04001461 }
1462
1463 @Override
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001464 public int checkPackage(int uid, String packageName) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001465 Preconditions.checkNotNull(packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001466 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001467 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
1468 true /* uidMismatchExpected */);
1469 if (ops != null) {
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001470 return AppOpsManager.MODE_ALLOWED;
1471 } else {
1472 return AppOpsManager.MODE_ERRORED;
1473 }
1474 }
1475 }
1476
1477 @Override
Svet Ganov99b60432015-06-27 13:15:22 -07001478 public int noteProxyOperation(int code, String proxyPackageName,
1479 int proxiedUid, String proxiedPackageName) {
1480 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001481 final int proxyUid = Binder.getCallingUid();
1482 String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
1483 if (resolveProxyPackageName == null) {
1484 return AppOpsManager.MODE_IGNORED;
1485 }
1486 final int proxyMode = noteOperationUnchecked(code, proxyUid,
1487 resolveProxyPackageName, -1, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001488 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
1489 return proxyMode;
1490 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001491 String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
1492 if (resolveProxiedPackageName == null) {
1493 return AppOpsManager.MODE_IGNORED;
1494 }
1495 return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
1496 proxyMode, resolveProxyPackageName);
Svet Ganov99b60432015-06-27 13:15:22 -07001497 }
1498
1499 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001500 public int noteOperation(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001501 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001502 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001503 String resolvedPackageName = resolvePackageName(uid, packageName);
1504 if (resolvedPackageName == null) {
1505 return AppOpsManager.MODE_IGNORED;
1506 }
1507 return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001508 }
1509
1510 private int noteOperationUnchecked(int code, int uid, String packageName,
1511 int proxyUid, String proxyPackageName) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001512 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001513 final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001514 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001515 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001516 if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001517 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001518 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001519 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001520 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001521 if (isOpRestrictedLocked(uid, code, packageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001522 return AppOpsManager.MODE_IGNORED;
1523 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001524 final UidState uidState = ops.uidState;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001525 if (op.duration == -1) {
1526 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001527 + " code " + code + " time=" + op.time[uidState.state]
1528 + " duration=" + op.duration);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001529 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001530 op.duration = 0;
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001531 final int switchCode = AppOpsManager.opToSwitch(code);
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001532 // If there is a non-default per UID policy (we set UID op mode only if
1533 // non-default) it takes over, otherwise use the per package policy.
1534 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001535 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganov2af57082015-07-30 08:44:20 -07001536 if (uidMode != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001537 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001538 + switchCode + " (" + code + ") uid " + uid + " package "
1539 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001540 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov2af57082015-07-30 08:44:20 -07001541 return uidMode;
1542 }
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001543 } else {
1544 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001545 final int mode = switchOp.getMode();
1546 if (mode != AppOpsManager.MODE_ALLOWED) {
1547 if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001548 + switchCode + " (" + code + ") uid " + uid + " package "
1549 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001550 op.rejectTime[uidState.state] = System.currentTimeMillis();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001551 return mode;
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001552 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001553 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001554 if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001555 + " package " + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001556 op.time[uidState.state] = System.currentTimeMillis();
1557 op.rejectTime[uidState.state] = 0;
Svet Ganov99b60432015-06-27 13:15:22 -07001558 op.proxyUid = proxyUid;
1559 op.proxyPackageName = proxyPackageName;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001560 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001561 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001562 }
1563
1564 @Override
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001565 public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001566 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001567 final int callingUid = Binder.getCallingUid();
1568 final int callingPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -08001569 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1570 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001571 watchedUid = callingUid;
Svet Ganovf7b47252018-02-26 11:11:27 -08001572 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001573 if (ops != null) {
1574 Preconditions.checkArrayElementsInRange(ops, 0,
1575 AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
1576 }
1577 if (callback == null) {
1578 return;
1579 }
1580 synchronized (this) {
1581 SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
1582 if (callbacks == null) {
1583 callbacks = new SparseArray<>();
1584 mActiveWatchers.put(callback.asBinder(), callbacks);
1585 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001586 final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
1587 callingUid, callingPid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001588 for (int op : ops) {
1589 callbacks.put(op, activeCallback);
1590 }
1591 }
1592 }
1593
1594 @Override
1595 public void stopWatchingActive(IAppOpsActiveCallback callback) {
1596 if (callback == null) {
1597 return;
1598 }
1599 synchronized (this) {
1600 final SparseArray<ActiveCallback> activeCallbacks =
1601 mActiveWatchers.remove(callback.asBinder());
1602 if (activeCallbacks == null) {
1603 return;
1604 }
1605 final int callbackCount = activeCallbacks.size();
1606 for (int i = 0; i < callbackCount; i++) {
1607 // Apps ops are mapped to a singleton
1608 if (i == 0) {
1609 activeCallbacks.valueAt(i).destroy();
1610 }
1611 }
1612 }
1613 }
1614
1615 @Override
Svet Ganovf7b47252018-02-26 11:11:27 -08001616 public int startOperation(IBinder token, int code, int uid, String packageName,
1617 boolean startIfModeDefault) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001618 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001619 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001620 String resolvedPackageName = resolvePackageName(uid, packageName);
1621 if (resolvedPackageName == null) {
1622 return AppOpsManager.MODE_IGNORED;
1623 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001624 ClientState client = (ClientState)token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001625 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001626 final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001627 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001628 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001629 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001630 + " package " + resolvedPackageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001631 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001632 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001633 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001634 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001635 return AppOpsManager.MODE_IGNORED;
1636 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001637 final int switchCode = AppOpsManager.opToSwitch(code);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001638 final UidState uidState = ops.uidState;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001639 // If there is a non-default per UID policy (we set UID op mode only if
1640 // non-default) it takes over, otherwise use the per package policy.
1641 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001642 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganovf7b47252018-02-26 11:11:27 -08001643 if (uidMode != AppOpsManager.MODE_ALLOWED
1644 && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001645 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001646 + switchCode + " (" + code + ") uid " + uid + " package "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001647 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001648 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov2af57082015-07-30 08:44:20 -07001649 return uidMode;
1650 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001651 } else {
1652 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001653 final int mode = switchOp.getMode();
1654 if (mode != AppOpsManager.MODE_ALLOWED
1655 && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
1656 if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001657 + switchCode + " (" + code + ") uid " + uid + " package "
1658 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001659 op.rejectTime[uidState.state] = System.currentTimeMillis();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001660 return mode;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001661 }
Svet Ganov2af57082015-07-30 08:44:20 -07001662 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001663 if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001664 + " package " + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001665 if (op.startNesting == 0) {
1666 op.startRealtime = SystemClock.elapsedRealtime();
1667 op.time[uidState.state] = System.currentTimeMillis();
1668 op.rejectTime[uidState.state] = 0;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001669 op.duration = -1;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001670 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001671 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001672 op.startNesting++;
1673 uidState.startNesting++;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001674 if (client.mStartedOps != null) {
1675 client.mStartedOps.add(op);
1676 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001677 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001678
1679 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001680 }
1681
1682 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001683 public void finishOperation(IBinder token, int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001684 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001685 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001686 String resolvedPackageName = resolvePackageName(uid, packageName);
1687 if (resolvedPackageName == null) {
1688 return;
1689 }
1690 if (!(token instanceof ClientState)) {
1691 return;
1692 }
1693 ClientState client = (ClientState) token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001694 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001695 Op op = getOpLocked(code, uid, resolvedPackageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001696 if (op == null) {
1697 return;
1698 }
Svet Ganovf7b47252018-02-26 11:11:27 -08001699 if (!client.mStartedOps.remove(op)) {
Svet Ganovf5d5af12018-03-18 11:51:17 -07001700 // We finish ops when packages get removed to guarantee no dangling
1701 // started ops. However, some part of the system may asynchronously
1702 // finish ops for an already gone package. Hence, finishing an op
1703 // for a non existing package is fine and we don't log as a wtf.
1704 final long identity = Binder.clearCallingIdentity();
1705 try {
1706 if (LocalServices.getService(PackageManagerInternal.class).getPackageUid(
1707 resolvedPackageName, 0, UserHandle.getUserId(uid)) < 0) {
1708 Slog.i(TAG, "Finishing op=" + AppOpsManager.opToName(code)
1709 + " for non-existing package=" + resolvedPackageName
1710 + " in uid=" + uid);
1711 return;
1712 }
1713 } finally {
1714 Binder.restoreCallingIdentity(identity);
1715 }
1716 Slog.wtf(TAG, "Operation not started: uid=" + op.uid + " pkg="
1717 + op.packageName + " op=" + AppOpsManager.opToName(op.op));
Svet Ganov31d83ae2018-03-15 10:45:56 -07001718 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001719 }
Svet Ganova7a0db62018-02-27 20:08:01 -08001720 finishOperationLocked(op, /*finishNested*/ false);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001721 if (op.startNesting <= 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001722 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
1723 }
1724 }
1725 }
1726
1727 private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
1728 boolean active) {
1729 ArraySet<ActiveCallback> dispatchedCallbacks = null;
1730 final int callbackListCount = mActiveWatchers.size();
1731 for (int i = 0; i < callbackListCount; i++) {
1732 final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
1733 ActiveCallback callback = callbacks.get(code);
1734 if (callback != null) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001735 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001736 continue;
1737 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001738 if (dispatchedCallbacks == null) {
1739 dispatchedCallbacks = new ArraySet<>();
1740 }
1741 dispatchedCallbacks.add(callback);
1742 }
1743 }
1744 if (dispatchedCallbacks == null) {
1745 return;
1746 }
1747 mHandler.sendMessage(PooledLambda.obtainMessage(
1748 AppOpsService::notifyOpActiveChanged,
1749 this, dispatchedCallbacks, code, uid, packageName, active));
1750 }
1751
1752 private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
1753 int code, int uid, String packageName, boolean active) {
1754 // There are components watching for mode changes such as window manager
1755 // and location manager which are in our process. The callbacks in these
1756 // components may require permissions our remote caller does not have.
1757 final long identity = Binder.clearCallingIdentity();
1758 try {
1759 final int callbackCount = callbacks.size();
1760 for (int i = 0; i < callbackCount; i++) {
1761 final ActiveCallback callback = callbacks.valueAt(i);
1762 try {
1763 callback.mCallback.opActiveChanged(code, uid, packageName, active);
1764 } catch (RemoteException e) {
1765 /* do nothing */
1766 }
1767 }
1768 } finally {
1769 Binder.restoreCallingIdentity(identity);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001770 }
1771 }
1772
Svet Ganovb9d71a62015-04-30 10:38:13 -07001773 @Override
1774 public int permissionToOpCode(String permission) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001775 if (permission == null) {
1776 return AppOpsManager.OP_NONE;
1777 }
Svet Ganovb9d71a62015-04-30 10:38:13 -07001778 return AppOpsManager.permissionToOpCode(permission);
1779 }
1780
Svet Ganova7a0db62018-02-27 20:08:01 -08001781 void finishOperationLocked(Op op, boolean finishNested) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001782 if (op.startNesting <= 1 || finishNested) {
1783 if (op.startNesting == 1 || finishNested) {
1784 op.duration = (int)(SystemClock.elapsedRealtime() - op.startRealtime);
1785 op.time[op.uidState.state] = System.currentTimeMillis();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001786 } else {
1787 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
1788 + op.packageName + " code " + op.op + " time=" + op.time
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001789 + " duration=" + op.duration + " nesting=" + op.startNesting);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001790 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001791 if (op.startNesting >= 1) {
1792 op.uidState.startNesting -= op.startNesting;
1793 }
1794 op.startNesting = 0;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001795 } else {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001796 op.startNesting--;
1797 op.uidState.startNesting--;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001798 }
1799 }
1800
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001801 private void verifyIncomingUid(int uid) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001802 if (uid == Binder.getCallingUid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001803 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001804 }
1805 if (Binder.getCallingPid() == Process.myPid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001806 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001807 }
1808 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
1809 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001810 }
1811
Dianne Hackborn961321f2013-02-05 17:22:41 -08001812 private void verifyIncomingOp(int op) {
1813 if (op >= 0 && op < AppOpsManager._NUM_OP) {
1814 return;
1815 }
1816 throw new IllegalArgumentException("Bad operation #" + op);
1817 }
1818
Svet Ganov2af57082015-07-30 08:44:20 -07001819 private UidState getUidStateLocked(int uid, boolean edit) {
1820 UidState uidState = mUidStates.get(uid);
1821 if (uidState == null) {
1822 if (!edit) {
1823 return null;
1824 }
1825 uidState = new UidState(uid);
1826 mUidStates.put(uid, uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001827 } else {
1828 if (uidState.pendingStateCommitTime != 0) {
1829 if (uidState.pendingStateCommitTime < mLastUptime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001830 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001831 } else {
1832 mLastUptime = SystemClock.uptimeMillis();
1833 if (uidState.pendingStateCommitTime < mLastUptime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001834 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001835 }
1836 }
1837 }
Svet Ganov2af57082015-07-30 08:44:20 -07001838 }
1839 return uidState;
1840 }
1841
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001842 private void commitUidPendingStateLocked(UidState uidState) {
1843 uidState.state = uidState.pendingState;
1844 uidState.pendingStateCommitTime = 0;
1845 if (uidState.hasForegroundWatchers) {
1846 for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
1847 if (!uidState.foregroundOps.valueAt(fgi)) {
1848 continue;
1849 }
1850 final int code = uidState.foregroundOps.keyAt(fgi);
1851
1852 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
1853 if (callbacks != null) {
1854 for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
1855 final ModeCallback callback = callbacks.valueAt(cbi);
1856 if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
1857 || !callback.isWatchingUid(uidState.uid)) {
1858 continue;
1859 }
1860 boolean doAllPackages = uidState.opModes != null
1861 && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
1862 if (uidState.pkgOps != null) {
1863 for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
1864 final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
1865 if (doAllPackages || (op != null
1866 && op.mode == AppOpsManager.MODE_FOREGROUND)) {
1867 mHandler.sendMessage(PooledLambda.obtainMessage(
1868 AppOpsService::notifyOpChanged,
1869 this, callback, code, uidState.uid,
1870 uidState.pkgOps.keyAt(pkgi)));
1871 }
1872 }
1873 }
1874 }
1875 }
1876 }
1877 }
1878 }
1879
Yohei Yukawaa965d652017-10-12 15:02:26 -07001880 private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
1881 boolean uidMismatchExpected) {
Svet Ganov2af57082015-07-30 08:44:20 -07001882 UidState uidState = getUidStateLocked(uid, edit);
1883 if (uidState == null) {
1884 return null;
1885 }
1886
1887 if (uidState.pkgOps == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001888 if (!edit) {
1889 return null;
1890 }
Svet Ganov2af57082015-07-30 08:44:20 -07001891 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001892 }
Svet Ganov2af57082015-07-30 08:44:20 -07001893
1894 Ops ops = uidState.pkgOps.get(packageName);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001895 if (ops == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001896 if (!edit) {
1897 return null;
1898 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001899 boolean isPrivileged = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001900 // This is the first time we have seen this package name under this uid,
1901 // so let's make sure it is valid.
Dianne Hackborn514074f2013-02-11 10:52:46 -08001902 if (uid != 0) {
1903 final long ident = Binder.clearCallingIdentity();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001904 try {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001905 int pkgUid = -1;
1906 try {
Jason Monk1c7c3192014-06-26 12:52:18 -04001907 ApplicationInfo appInfo = ActivityThread.getPackageManager()
Jeff Sharkeycd654482016-01-08 17:42:11 -07001908 .getApplicationInfo(packageName,
1909 PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
1910 UserHandle.getUserId(uid));
Jason Monk1c7c3192014-06-26 12:52:18 -04001911 if (appInfo != null) {
1912 pkgUid = appInfo.uid;
Alex Klyubinb9f8a522015-02-03 11:12:59 -08001913 isPrivileged = (appInfo.privateFlags
1914 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04001915 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08001916 pkgUid = resolveUid(packageName);
1917 if (pkgUid >= 0) {
Chien-Yu Chen75cade02016-01-11 10:56:21 -08001918 isPrivileged = false;
Jason Monk1c7c3192014-06-26 12:52:18 -04001919 }
Dianne Hackborn713df152013-05-17 11:27:57 -07001920 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001921 } catch (RemoteException e) {
1922 Slog.w(TAG, "Could not contact PackageManager", e);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001923 }
1924 if (pkgUid != uid) {
1925 // Oops! The package name is not valid for the uid they are calling
1926 // under. Abort.
Yohei Yukawaa965d652017-10-12 15:02:26 -07001927 if (!uidMismatchExpected) {
1928 RuntimeException ex = new RuntimeException("here");
1929 ex.fillInStackTrace();
1930 Slog.w(TAG, "Bad call: specified package " + packageName
1931 + " under uid " + uid + " but it is really " + pkgUid, ex);
1932 }
Dianne Hackborn514074f2013-02-11 10:52:46 -08001933 return null;
1934 }
1935 } finally {
1936 Binder.restoreCallingIdentity(ident);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001937 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001938 }
Svet Ganov2af57082015-07-30 08:44:20 -07001939 ops = new Ops(packageName, uidState, isPrivileged);
1940 uidState.pkgOps.put(packageName, ops);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001941 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08001942 return ops;
1943 }
1944
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001945 private void scheduleWriteLocked() {
1946 if (!mWriteScheduled) {
1947 mWriteScheduled = true;
1948 mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
1949 }
1950 }
1951
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001952 private void scheduleFastWriteLocked() {
1953 if (!mFastWriteScheduled) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001954 mWriteScheduled = true;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001955 mFastWriteScheduled = true;
1956 mHandler.removeCallbacks(mWriteRunner);
1957 mHandler.postDelayed(mWriteRunner, 10*1000);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001958 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001959 }
1960
Dianne Hackborn72e39832013-01-18 18:36:09 -08001961 private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001962 Ops ops = getOpsRawLocked(uid, packageName, edit,
1963 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001964 if (ops == null) {
1965 return null;
1966 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001967 return getOpLocked(ops, code, edit);
1968 }
1969
1970 private Op getOpLocked(Ops ops, int code, boolean edit) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001971 Op op = ops.get(code);
1972 if (op == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001973 if (!edit) {
1974 return null;
1975 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001976 op = new Op(ops.uidState, ops.packageName, code);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001977 ops.put(code, op);
1978 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001979 if (edit) {
1980 scheduleWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001981 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001982 return op;
1983 }
1984
Svet Ganov442ed572016-08-17 17:29:43 -07001985 private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
Jason Monk62062992014-05-06 09:55:28 -04001986 int userHandle = UserHandle.getUserId(uid);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001987 final int restrictionSetCount = mOpUserRestrictions.size();
Ruben Brunk29931bc2016-03-11 00:24:26 -08001988
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001989 for (int i = 0; i < restrictionSetCount; i++) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08001990 // For each client, check that the given op is not restricted, or that the given
1991 // package is exempt from the restriction.
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07001992 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07001993 if (restrictionState.hasRestriction(code, packageName, userHandle)) {
1994 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
1995 // If we are the system, bypass user restrictions for certain codes
1996 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001997 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
1998 false /* uidMismatchExpected */);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07001999 if ((ops != null) && ops.isPrivileged) {
2000 return false;
2001 }
Ruben Brunk32f0fa42016-03-11 19:07:07 -08002002 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08002003 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002004 return true;
Jason Monk1c7c3192014-06-26 12:52:18 -04002005 }
Jason Monk62062992014-05-06 09:55:28 -04002006 }
2007 return false;
2008 }
2009
Dianne Hackborn35654b62013-01-14 17:38:02 -08002010 void readState() {
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002011 int oldVersion = NO_VERSION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08002012 synchronized (mFile) {
2013 synchronized (this) {
2014 FileInputStream stream;
2015 try {
2016 stream = mFile.openRead();
2017 } catch (FileNotFoundException e) {
2018 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
2019 return;
2020 }
2021 boolean success = false;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002022 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002023 try {
2024 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002025 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002026 int type;
2027 while ((type = parser.next()) != XmlPullParser.START_TAG
2028 && type != XmlPullParser.END_DOCUMENT) {
2029 ;
2030 }
2031
2032 if (type != XmlPullParser.START_TAG) {
2033 throw new IllegalStateException("no start tag found");
2034 }
2035
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002036 final String versionString = parser.getAttributeValue(null, "v");
2037 if (versionString != null) {
2038 oldVersion = Integer.parseInt(versionString);
2039 }
2040
Dianne Hackborn35654b62013-01-14 17:38:02 -08002041 int outerDepth = parser.getDepth();
2042 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2043 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2044 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2045 continue;
2046 }
2047
2048 String tagName = parser.getName();
2049 if (tagName.equals("pkg")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002050 readPackage(parser);
Svetoslav215b44a2015-08-04 19:03:40 -07002051 } else if (tagName.equals("uid")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002052 readUidOps(parser);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002053 } else {
2054 Slog.w(TAG, "Unknown element under <app-ops>: "
2055 + parser.getName());
2056 XmlUtils.skipCurrentTag(parser);
2057 }
2058 }
2059 success = true;
2060 } catch (IllegalStateException e) {
2061 Slog.w(TAG, "Failed parsing " + e);
2062 } catch (NullPointerException e) {
2063 Slog.w(TAG, "Failed parsing " + e);
2064 } catch (NumberFormatException e) {
2065 Slog.w(TAG, "Failed parsing " + e);
2066 } catch (XmlPullParserException e) {
2067 Slog.w(TAG, "Failed parsing " + e);
2068 } catch (IOException e) {
2069 Slog.w(TAG, "Failed parsing " + e);
2070 } catch (IndexOutOfBoundsException e) {
2071 Slog.w(TAG, "Failed parsing " + e);
2072 } finally {
2073 if (!success) {
Svet Ganov2af57082015-07-30 08:44:20 -07002074 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002075 }
2076 try {
2077 stream.close();
2078 } catch (IOException e) {
2079 }
2080 }
2081 }
2082 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002083 synchronized (this) {
2084 upgradeLocked(oldVersion);
2085 }
2086 }
2087
2088 private void upgradeRunAnyInBackgroundLocked() {
2089 for (int i = 0; i < mUidStates.size(); i++) {
2090 final UidState uidState = mUidStates.valueAt(i);
2091 if (uidState == null) {
2092 continue;
2093 }
2094 if (uidState.opModes != null) {
2095 final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
2096 if (idx >= 0) {
2097 uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
2098 uidState.opModes.valueAt(idx));
2099 }
2100 }
2101 if (uidState.pkgOps == null) {
2102 continue;
2103 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002104 boolean changed = false;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002105 for (int j = 0; j < uidState.pkgOps.size(); j++) {
2106 Ops ops = uidState.pkgOps.valueAt(j);
2107 if (ops != null) {
2108 final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
2109 if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002110 final Op copy = new Op(op.uidState, op.packageName,
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002111 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
2112 copy.mode = op.mode;
2113 ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002114 changed = true;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002115 }
2116 }
2117 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002118 if (changed) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002119 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002120 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002121 }
2122 }
2123
2124 private void upgradeLocked(int oldVersion) {
2125 if (oldVersion >= CURRENT_VERSION) {
2126 return;
2127 }
2128 Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
2129 switch (oldVersion) {
2130 case NO_VERSION:
2131 upgradeRunAnyInBackgroundLocked();
2132 // fall through
2133 case 1:
2134 // for future upgrades
2135 }
2136 scheduleFastWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002137 }
2138
Svet Ganov2af57082015-07-30 08:44:20 -07002139 void readUidOps(XmlPullParser parser) throws NumberFormatException,
2140 XmlPullParserException, IOException {
2141 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
2142 int outerDepth = parser.getDepth();
2143 int type;
2144 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2145 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2146 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2147 continue;
2148 }
2149
2150 String tagName = parser.getName();
2151 if (tagName.equals("op")) {
2152 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
2153 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
2154 UidState uidState = getUidStateLocked(uid, true);
2155 if (uidState.opModes == null) {
2156 uidState.opModes = new SparseIntArray();
2157 }
2158 uidState.opModes.put(code, mode);
2159 } else {
2160 Slog.w(TAG, "Unknown element under <uid-ops>: "
2161 + parser.getName());
2162 XmlUtils.skipCurrentTag(parser);
2163 }
2164 }
2165 }
2166
Dave Burke0997c5bd2013-08-02 20:25:02 +00002167 void readPackage(XmlPullParser parser) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002168 XmlPullParserException, IOException {
2169 String pkgName = parser.getAttributeValue(null, "n");
2170 int outerDepth = parser.getDepth();
2171 int type;
2172 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2173 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2174 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2175 continue;
2176 }
2177
2178 String tagName = parser.getName();
2179 if (tagName.equals("uid")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002180 readUid(parser, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002181 } else {
2182 Slog.w(TAG, "Unknown element under <pkg>: "
2183 + parser.getName());
2184 XmlUtils.skipCurrentTag(parser);
2185 }
2186 }
2187 }
2188
Dave Burke0997c5bd2013-08-02 20:25:02 +00002189 void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002190 XmlPullParserException, IOException {
2191 int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
Jason Monk1c7c3192014-06-26 12:52:18 -04002192 String isPrivilegedString = parser.getAttributeValue(null, "p");
2193 boolean isPrivileged = false;
2194 if (isPrivilegedString == null) {
2195 try {
2196 IPackageManager packageManager = ActivityThread.getPackageManager();
2197 if (packageManager != null) {
2198 ApplicationInfo appInfo = ActivityThread.getPackageManager()
2199 .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
2200 if (appInfo != null) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08002201 isPrivileged = (appInfo.privateFlags
2202 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04002203 }
2204 } else {
2205 // Could not load data, don't add to cache so it will be loaded later.
2206 return;
2207 }
2208 } catch (RemoteException e) {
2209 Slog.w(TAG, "Could not contact PackageManager", e);
2210 }
2211 } else {
2212 isPrivileged = Boolean.parseBoolean(isPrivilegedString);
2213 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002214 int outerDepth = parser.getDepth();
2215 int type;
2216 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2217 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2218 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2219 continue;
2220 }
2221
2222 String tagName = parser.getName();
2223 if (tagName.equals("op")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002224 UidState uidState = getUidStateLocked(uid, true);
2225 if (uidState.pkgOps == null) {
2226 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002227 }
Svet Ganov2af57082015-07-30 08:44:20 -07002228
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002229 Op op = new Op(uidState, pkgName,
2230 Integer.parseInt(parser.getAttributeValue(null, "n")));
2231
2232 for (int i = parser.getAttributeCount()-1; i >= 0; i--) {
2233 final String name = parser.getAttributeName(i);
2234 final String value = parser.getAttributeValue(i);
2235 switch (name) {
2236 case "m":
2237 op.mode = Integer.parseInt(value);
2238 break;
2239 case "d":
2240 op.duration = Integer.parseInt(value);
2241 break;
2242 case "pu":
2243 op.proxyUid = Integer.parseInt(value);
2244 break;
2245 case "pp":
2246 op.proxyPackageName = value;
2247 break;
2248 case "tp":
2249 op.time[AppOpsManager.UID_STATE_PERSISTENT] = Long.parseLong(value);
2250 break;
2251 case "tt":
2252 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2253 break;
2254 case "tfs":
2255 op.time[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2256 = Long.parseLong(value);
2257 break;
2258 case "tf":
2259 op.time[AppOpsManager.UID_STATE_FOREGROUND] = Long.parseLong(value);
2260 break;
2261 case "tb":
2262 op.time[AppOpsManager.UID_STATE_BACKGROUND] = Long.parseLong(value);
2263 break;
2264 case "tc":
2265 op.time[AppOpsManager.UID_STATE_CACHED] = Long.parseLong(value);
2266 break;
2267 case "rp":
2268 op.rejectTime[AppOpsManager.UID_STATE_PERSISTENT]
2269 = Long.parseLong(value);
2270 break;
2271 case "rt":
2272 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2273 break;
2274 case "rfs":
2275 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2276 = Long.parseLong(value);
2277 break;
2278 case "rf":
2279 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND]
2280 = Long.parseLong(value);
2281 break;
2282 case "rb":
2283 op.rejectTime[AppOpsManager.UID_STATE_BACKGROUND]
2284 = Long.parseLong(value);
2285 break;
2286 case "rc":
2287 op.rejectTime[AppOpsManager.UID_STATE_CACHED]
2288 = Long.parseLong(value);
2289 break;
2290 case "t":
2291 // Backwards compat.
2292 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2293 break;
2294 case "r":
2295 // Backwards compat.
2296 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2297 break;
2298 default:
2299 Slog.w(TAG, "Unknown attribute in 'op' tag: " + name);
2300 break;
2301 }
2302 }
2303
Svet Ganov2af57082015-07-30 08:44:20 -07002304 Ops ops = uidState.pkgOps.get(pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002305 if (ops == null) {
Svet Ganov2af57082015-07-30 08:44:20 -07002306 ops = new Ops(pkgName, uidState, isPrivileged);
2307 uidState.pkgOps.put(pkgName, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002308 }
2309 ops.put(op.op, op);
2310 } else {
2311 Slog.w(TAG, "Unknown element under <pkg>: "
2312 + parser.getName());
2313 XmlUtils.skipCurrentTag(parser);
2314 }
2315 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002316 UidState uidState = getUidStateLocked(uid, false);
2317 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002318 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002319 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002320 }
2321
2322 void writeState() {
2323 synchronized (mFile) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002324 FileOutputStream stream;
2325 try {
2326 stream = mFile.startWrite();
2327 } catch (IOException e) {
2328 Slog.w(TAG, "Failed to write state: " + e);
2329 return;
2330 }
2331
Dianne Hackborne17b4452018-01-10 13:15:40 -08002332 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
2333
Dianne Hackborn35654b62013-01-14 17:38:02 -08002334 try {
2335 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002336 out.setOutput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002337 out.startDocument(null, true);
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002338 out.startTag(null, "app-ops");
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002339 out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
Svet Ganov2af57082015-07-30 08:44:20 -07002340
2341 final int uidStateCount = mUidStates.size();
2342 for (int i = 0; i < uidStateCount; i++) {
2343 UidState uidState = mUidStates.valueAt(i);
2344 if (uidState.opModes != null && uidState.opModes.size() > 0) {
2345 out.startTag(null, "uid");
2346 out.attribute(null, "n", Integer.toString(uidState.uid));
2347 SparseIntArray uidOpModes = uidState.opModes;
2348 final int opCount = uidOpModes.size();
2349 for (int j = 0; j < opCount; j++) {
2350 final int op = uidOpModes.keyAt(j);
2351 final int mode = uidOpModes.valueAt(j);
2352 out.startTag(null, "op");
2353 out.attribute(null, "n", Integer.toString(op));
2354 out.attribute(null, "m", Integer.toString(mode));
2355 out.endTag(null, "op");
2356 }
2357 out.endTag(null, "uid");
2358 }
2359 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002360
2361 if (allOps != null) {
2362 String lastPkg = null;
2363 for (int i=0; i<allOps.size(); i++) {
2364 AppOpsManager.PackageOps pkg = allOps.get(i);
2365 if (!pkg.getPackageName().equals(lastPkg)) {
2366 if (lastPkg != null) {
2367 out.endTag(null, "pkg");
2368 }
2369 lastPkg = pkg.getPackageName();
2370 out.startTag(null, "pkg");
2371 out.attribute(null, "n", lastPkg);
2372 }
2373 out.startTag(null, "uid");
2374 out.attribute(null, "n", Integer.toString(pkg.getUid()));
Jason Monk1c7c3192014-06-26 12:52:18 -04002375 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002376 Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
2377 false /* edit */, false /* uidMismatchExpected */);
Jason Monk1c7c3192014-06-26 12:52:18 -04002378 // Should always be present as the list of PackageOps is generated
2379 // from Ops.
2380 if (ops != null) {
2381 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
2382 } else {
2383 out.attribute(null, "p", Boolean.toString(false));
2384 }
2385 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002386 List<AppOpsManager.OpEntry> ops = pkg.getOps();
2387 for (int j=0; j<ops.size(); j++) {
2388 AppOpsManager.OpEntry op = ops.get(j);
2389 out.startTag(null, "op");
2390 out.attribute(null, "n", Integer.toString(op.getOp()));
David Braunf5d83192013-09-16 13:43:51 -07002391 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002392 out.attribute(null, "m", Integer.toString(op.getMode()));
2393 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002394 for (int k = 0; k < _NUM_UID_STATE; k++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002395 final long time = op.getLastTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002396 if (time != 0) {
2397 out.attribute(null, UID_STATE_TIME_ATTRS[k],
2398 Long.toString(time));
2399 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002400 final long rejectTime = op.getLastRejectTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002401 if (rejectTime != 0) {
2402 out.attribute(null, UID_STATE_REJECT_ATTRS[k],
2403 Long.toString(rejectTime));
2404 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002405 }
2406 int dur = op.getDuration();
2407 if (dur != 0) {
2408 out.attribute(null, "d", Integer.toString(dur));
2409 }
Svet Ganov99b60432015-06-27 13:15:22 -07002410 int proxyUid = op.getProxyUid();
2411 if (proxyUid != -1) {
2412 out.attribute(null, "pu", Integer.toString(proxyUid));
2413 }
2414 String proxyPackageName = op.getProxyPackageName();
2415 if (proxyPackageName != null) {
2416 out.attribute(null, "pp", proxyPackageName);
2417 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002418 out.endTag(null, "op");
2419 }
2420 out.endTag(null, "uid");
2421 }
2422 if (lastPkg != null) {
2423 out.endTag(null, "pkg");
2424 }
2425 }
2426
2427 out.endTag(null, "app-ops");
2428 out.endDocument();
2429 mFile.finishWrite(stream);
2430 } catch (IOException e) {
2431 Slog.w(TAG, "Failed to write state, restoring backup.", e);
2432 mFile.failWrite(stream);
2433 }
2434 }
2435 }
2436
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002437 static class Shell extends ShellCommand {
2438 final IAppOpsService mInterface;
2439 final AppOpsService mInternal;
2440
2441 int userId = UserHandle.USER_SYSTEM;
2442 String packageName;
2443 String opStr;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002444 String modeStr;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002445 int op;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002446 int mode;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002447 int packageUid;
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002448 int nonpackageUid;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002449 final static Binder sBinder = new Binder();
2450 IBinder mToken;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002451
2452 Shell(IAppOpsService iface, AppOpsService internal) {
2453 mInterface = iface;
2454 mInternal = internal;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002455 try {
2456 mToken = mInterface.getToken(sBinder);
2457 } catch (RemoteException e) {
2458 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002459 }
2460
2461 @Override
2462 public int onCommand(String cmd) {
2463 return onShellCommand(this, cmd);
2464 }
2465
2466 @Override
2467 public void onHelp() {
2468 PrintWriter pw = getOutPrintWriter();
2469 dumpCommandHelp(pw);
2470 }
2471
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002472 static private int strOpToOp(String op, PrintWriter err) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002473 try {
2474 return AppOpsManager.strOpToOp(op);
2475 } catch (IllegalArgumentException e) {
2476 }
2477 try {
2478 return Integer.parseInt(op);
2479 } catch (NumberFormatException e) {
2480 }
2481 try {
2482 return AppOpsManager.strDebugOpToOp(op);
2483 } catch (IllegalArgumentException e) {
2484 err.println("Error: " + e.getMessage());
2485 return -1;
2486 }
2487 }
2488
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002489 static int strModeToMode(String modeStr, PrintWriter err) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002490 for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
2491 if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002492 return i;
2493 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002494 }
2495 try {
2496 return Integer.parseInt(modeStr);
2497 } catch (NumberFormatException e) {
2498 }
2499 err.println("Error: Mode " + modeStr + " is not valid");
2500 return -1;
2501 }
2502
2503 int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
2504 userId = UserHandle.USER_CURRENT;
2505 opStr = null;
2506 modeStr = null;
2507 for (String argument; (argument = getNextArg()) != null;) {
2508 if ("--user".equals(argument)) {
2509 userId = UserHandle.parseUserArg(getNextArgRequired());
2510 } else {
2511 if (opStr == null) {
2512 opStr = argument;
2513 } else if (modeStr == null) {
2514 modeStr = argument;
2515 break;
2516 }
2517 }
2518 }
2519 if (opStr == null) {
2520 err.println("Error: Operation not specified.");
2521 return -1;
2522 }
2523 op = strOpToOp(opStr, err);
2524 if (op < 0) {
2525 return -1;
2526 }
2527 if (modeStr != null) {
2528 if ((mode=strModeToMode(modeStr, err)) < 0) {
2529 return -1;
2530 }
2531 } else {
2532 mode = defMode;
2533 }
2534 return 0;
2535 }
2536
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002537 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
2538 userId = UserHandle.USER_CURRENT;
2539 packageName = null;
2540 opStr = null;
2541 for (String argument; (argument = getNextArg()) != null;) {
2542 if ("--user".equals(argument)) {
2543 userId = UserHandle.parseUserArg(getNextArgRequired());
2544 } else {
2545 if (packageName == null) {
2546 packageName = argument;
2547 } else if (opStr == null) {
2548 opStr = argument;
2549 break;
2550 }
2551 }
2552 }
2553 if (packageName == null) {
2554 err.println("Error: Package name not specified.");
2555 return -1;
2556 } else if (opStr == null && reqOp) {
2557 err.println("Error: Operation not specified.");
2558 return -1;
2559 }
2560 if (opStr != null) {
2561 op = strOpToOp(opStr, err);
2562 if (op < 0) {
2563 return -1;
2564 }
2565 } else {
2566 op = AppOpsManager.OP_NONE;
2567 }
2568 if (userId == UserHandle.USER_CURRENT) {
2569 userId = ActivityManager.getCurrentUser();
2570 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002571 nonpackageUid = -1;
2572 try {
2573 nonpackageUid = Integer.parseInt(packageName);
2574 } catch (NumberFormatException e) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002575 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002576 if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
2577 && packageName.indexOf('.') < 0) {
2578 int i = 1;
2579 while (i < packageName.length() && packageName.charAt(i) >= '0'
2580 && packageName.charAt(i) <= '9') {
2581 i++;
2582 }
2583 if (i > 1 && i < packageName.length()) {
2584 String userStr = packageName.substring(1, i);
2585 try {
2586 int user = Integer.parseInt(userStr);
2587 char type = packageName.charAt(i);
2588 i++;
2589 int startTypeVal = i;
2590 while (i < packageName.length() && packageName.charAt(i) >= '0'
2591 && packageName.charAt(i) <= '9') {
2592 i++;
2593 }
2594 if (i > startTypeVal) {
2595 String typeValStr = packageName.substring(startTypeVal, i);
2596 try {
2597 int typeVal = Integer.parseInt(typeValStr);
2598 if (type == 'a') {
2599 nonpackageUid = UserHandle.getUid(user,
2600 typeVal + Process.FIRST_APPLICATION_UID);
2601 } else if (type == 's') {
2602 nonpackageUid = UserHandle.getUid(user, typeVal);
2603 }
2604 } catch (NumberFormatException e) {
2605 }
2606 }
2607 } catch (NumberFormatException e) {
2608 }
2609 }
2610 }
2611 if (nonpackageUid != -1) {
2612 packageName = null;
2613 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08002614 packageUid = resolveUid(packageName);
2615 if (packageUid < 0) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002616 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
2617 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
2618 }
2619 if (packageUid < 0) {
2620 err.println("Error: No UID for " + packageName + " in user " + userId);
2621 return -1;
2622 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002623 }
2624 return 0;
2625 }
2626 }
2627
2628 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07002629 FileDescriptor err, String[] args, ShellCallback callback,
2630 ResultReceiver resultReceiver) {
2631 (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002632 }
2633
2634 static void dumpCommandHelp(PrintWriter pw) {
2635 pw.println("AppOps service (appops) commands:");
2636 pw.println(" help");
2637 pw.println(" Print this help text.");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002638 pw.println(" start [--user <USER_ID>] <PACKAGE | UID> <OP> ");
2639 pw.println(" Starts a given operation for a particular application.");
2640 pw.println(" stop [--user <USER_ID>] <PACKAGE | UID> <OP> ");
2641 pw.println(" Stops a given operation for a particular application.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002642 pw.println(" set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002643 pw.println(" Set the mode for a particular application and operation.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002644 pw.println(" get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002645 pw.println(" Return the mode for a particular application and optional operation.");
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002646 pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
2647 pw.println(" Print all packages that currently have the given op in the given mode.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002648 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
2649 pw.println(" Reset the given application or all applications to default modes.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002650 pw.println(" write-settings");
2651 pw.println(" Immediately write pending changes to storage.");
2652 pw.println(" read-settings");
2653 pw.println(" Read the last written settings, replacing current state in RAM.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002654 pw.println(" options:");
2655 pw.println(" <PACKAGE> an Android package name.");
2656 pw.println(" <OP> an AppOps operation.");
2657 pw.println(" <MODE> one of allow, ignore, deny, or default");
2658 pw.println(" <USER_ID> the user id under which the package is installed. If --user is not");
2659 pw.println(" specified, the current user is assumed.");
2660 }
2661
2662 static int onShellCommand(Shell shell, String cmd) {
2663 if (cmd == null) {
2664 return shell.handleDefaultCommands(cmd);
2665 }
2666 PrintWriter pw = shell.getOutPrintWriter();
2667 PrintWriter err = shell.getErrPrintWriter();
2668 try {
2669 switch (cmd) {
2670 case "set": {
2671 int res = shell.parseUserPackageOp(true, err);
2672 if (res < 0) {
2673 return res;
2674 }
2675 String modeStr = shell.getNextArg();
2676 if (modeStr == null) {
2677 err.println("Error: Mode not specified.");
2678 return -1;
2679 }
2680
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002681 final int mode = shell.strModeToMode(modeStr, err);
2682 if (mode < 0) {
2683 return -1;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002684 }
2685
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002686 if (shell.packageName != null) {
2687 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
2688 mode);
2689 } else {
2690 shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
2691 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002692 return 0;
2693 }
2694 case "get": {
2695 int res = shell.parseUserPackageOp(false, err);
2696 if (res < 0) {
2697 return res;
2698 }
2699
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002700 List<AppOpsManager.PackageOps> ops;
2701 if (shell.packageName != null) {
2702 ops = shell.mInterface.getOpsForPackage(
2703 shell.packageUid, shell.packageName,
2704 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
2705 } else {
2706 ops = shell.mInterface.getUidOps(
2707 shell.nonpackageUid,
2708 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
2709 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002710 if (ops == null || ops.size() <= 0) {
2711 pw.println("No operations.");
Svet Ganov82f09bc2018-01-12 22:08:40 -08002712 if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002713 pw.println("Default mode: " + AppOpsManager.modeToName(
Svet Ganov82f09bc2018-01-12 22:08:40 -08002714 AppOpsManager.opToDefaultMode(shell.op)));
2715 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002716 return 0;
2717 }
2718 final long now = System.currentTimeMillis();
2719 for (int i=0; i<ops.size(); i++) {
2720 List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
2721 for (int j=0; j<entries.size(); j++) {
2722 AppOpsManager.OpEntry ent = entries.get(j);
2723 pw.print(AppOpsManager.opToName(ent.getOp()));
2724 pw.print(": ");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002725 pw.print(AppOpsManager.modeToName(ent.getMode()));
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002726 if (ent.getTime() != 0) {
2727 pw.print("; time=");
2728 TimeUtils.formatDuration(now - ent.getTime(), pw);
2729 pw.print(" ago");
2730 }
2731 if (ent.getRejectTime() != 0) {
2732 pw.print("; rejectTime=");
2733 TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
2734 pw.print(" ago");
2735 }
2736 if (ent.getDuration() == -1) {
2737 pw.print(" (running)");
2738 } else if (ent.getDuration() != 0) {
2739 pw.print("; duration=");
2740 TimeUtils.formatDuration(ent.getDuration(), pw);
2741 }
2742 pw.println();
2743 }
2744 }
2745 return 0;
2746 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002747 case "query-op": {
2748 int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
2749 if (res < 0) {
2750 return res;
2751 }
2752 List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
2753 new int[] {shell.op});
2754 if (ops == null || ops.size() <= 0) {
2755 pw.println("No operations.");
2756 return 0;
2757 }
2758 for (int i=0; i<ops.size(); i++) {
2759 final AppOpsManager.PackageOps pkg = ops.get(i);
2760 boolean hasMatch = false;
2761 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
2762 for (int j=0; j<entries.size(); j++) {
2763 AppOpsManager.OpEntry ent = entries.get(j);
2764 if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
2765 hasMatch = true;
2766 break;
2767 }
2768 }
2769 if (hasMatch) {
2770 pw.println(pkg.getPackageName());
2771 }
2772 }
2773 return 0;
2774 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002775 case "reset": {
2776 String packageName = null;
2777 int userId = UserHandle.USER_CURRENT;
2778 for (String argument; (argument = shell.getNextArg()) != null;) {
2779 if ("--user".equals(argument)) {
2780 String userStr = shell.getNextArgRequired();
2781 userId = UserHandle.parseUserArg(userStr);
2782 } else {
2783 if (packageName == null) {
2784 packageName = argument;
2785 } else {
2786 err.println("Error: Unsupported argument: " + argument);
2787 return -1;
2788 }
2789 }
2790 }
2791
2792 if (userId == UserHandle.USER_CURRENT) {
2793 userId = ActivityManager.getCurrentUser();
2794 }
2795
2796 shell.mInterface.resetAllModes(userId, packageName);
2797 pw.print("Reset all modes for: ");
2798 if (userId == UserHandle.USER_ALL) {
2799 pw.print("all users");
2800 } else {
2801 pw.print("user "); pw.print(userId);
2802 }
2803 pw.print(", ");
2804 if (packageName == null) {
2805 pw.println("all packages");
2806 } else {
2807 pw.print("package "); pw.println(packageName);
2808 }
2809 return 0;
2810 }
2811 case "write-settings": {
2812 shell.mInternal.mContext.enforcePermission(
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -08002813 android.Manifest.permission.MANAGE_APP_OPS_MODES,
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002814 Binder.getCallingPid(), Binder.getCallingUid(), null);
2815 long token = Binder.clearCallingIdentity();
2816 try {
2817 synchronized (shell.mInternal) {
2818 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
2819 }
2820 shell.mInternal.writeState();
2821 pw.println("Current settings written.");
2822 } finally {
2823 Binder.restoreCallingIdentity(token);
2824 }
2825 return 0;
2826 }
2827 case "read-settings": {
2828 shell.mInternal.mContext.enforcePermission(
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -08002829 android.Manifest.permission.MANAGE_APP_OPS_MODES,
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002830 Binder.getCallingPid(), Binder.getCallingUid(), null);
2831 long token = Binder.clearCallingIdentity();
2832 try {
2833 shell.mInternal.readState();
2834 pw.println("Last settings read.");
2835 } finally {
2836 Binder.restoreCallingIdentity(token);
2837 }
2838 return 0;
2839 }
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002840 case "start": {
2841 int res = shell.parseUserPackageOp(true, err);
2842 if (res < 0) {
2843 return res;
2844 }
2845
2846 if (shell.packageName != null) {
2847 shell.mInterface.startOperation(shell.mToken,
2848 shell.op, shell.packageUid, shell.packageName, true);
2849 } else {
2850 return -1;
2851 }
2852 return 0;
2853 }
2854 case "stop": {
2855 int res = shell.parseUserPackageOp(true, err);
2856 if (res < 0) {
2857 return res;
2858 }
2859
2860 if (shell.packageName != null) {
2861 shell.mInterface.finishOperation(shell.mToken,
2862 shell.op, shell.packageUid, shell.packageName);
2863 } else {
2864 return -1;
2865 }
2866 return 0;
2867 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002868 default:
2869 return shell.handleDefaultCommands(cmd);
2870 }
2871 } catch (RemoteException e) {
2872 pw.println("Remote exception: " + e);
2873 }
2874 return -1;
2875 }
2876
2877 private void dumpHelp(PrintWriter pw) {
2878 pw.println("AppOps service (appops) dump options:");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002879 pw.println(" -h");
2880 pw.println(" Print this help text.");
2881 pw.println(" --op [OP]");
2882 pw.println(" Limit output to data associated with the given app op code.");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002883 pw.println(" --mode [MODE]");
2884 pw.println(" Limit output to data associated with the given app op mode.");
2885 pw.println(" --package [PACKAGE]");
2886 pw.println(" Limit output to data associated with the given package name.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002887 }
2888
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002889 private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
2890 long now, SimpleDateFormat sdf, Date date) {
2891 boolean hasTime = false;
2892 for (int i = 0; i < _NUM_UID_STATE; i++) {
2893 if (times[i] != 0) {
2894 hasTime = true;
2895 break;
2896 }
2897 }
2898 if (!hasTime) {
2899 return;
2900 }
2901 boolean first = true;
2902 for (int i = 0; i < _NUM_UID_STATE; i++) {
2903 if (times[i] != 0) {
2904 pw.print(first ? firstPrefix : prefix);
2905 first = false;
2906 pw.print(UID_STATE_NAMES[i]);
2907 pw.print(" = ");
2908 date.setTime(times[i]);
2909 pw.print(sdf.format(date));
2910 pw.print(" (");
2911 TimeUtils.formatDuration(times[i]-now, pw);
2912 pw.println(")");
2913 }
2914 }
2915 }
2916
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002917 @Override
2918 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06002919 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002920
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002921 int dumpOp = -1;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002922 String dumpPackage = null;
2923 int dumpUid = -1;
2924 int dumpMode = -1;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002925
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002926 if (args != null) {
2927 for (int i=0; i<args.length; i++) {
2928 String arg = args[i];
2929 if ("-h".equals(arg)) {
2930 dumpHelp(pw);
2931 return;
Tim Kilbourn8f1ea832015-08-26 15:07:37 -07002932 } else if ("-a".equals(arg)) {
2933 // dump all data
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002934 } else if ("--op".equals(arg)) {
2935 i++;
2936 if (i >= args.length) {
2937 pw.println("No argument for --op option");
2938 return;
2939 }
2940 dumpOp = Shell.strOpToOp(args[i], pw);
2941 if (dumpOp < 0) {
2942 return;
2943 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002944 } else if ("--package".equals(arg)) {
2945 i++;
2946 if (i >= args.length) {
2947 pw.println("No argument for --package option");
2948 return;
2949 }
2950 dumpPackage = args[i];
2951 try {
2952 dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
2953 PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
2954 0);
2955 } catch (RemoteException e) {
2956 }
2957 if (dumpUid < 0) {
2958 pw.println("Unknown package: " + dumpPackage);
2959 return;
2960 }
2961 dumpUid = UserHandle.getAppId(dumpUid);
2962 } else if ("--mode".equals(arg)) {
2963 i++;
2964 if (i >= args.length) {
2965 pw.println("No argument for --mode option");
2966 return;
2967 }
2968 dumpMode = Shell.strModeToMode(args[i], pw);
2969 if (dumpMode < 0) {
2970 return;
2971 }
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002972 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
2973 pw.println("Unknown option: " + arg);
2974 return;
2975 } else {
2976 pw.println("Unknown command: " + arg);
2977 return;
2978 }
2979 }
2980 }
2981
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002982 synchronized (this) {
2983 pw.println("Current AppOps Service state:");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002984 mConstants.dump(pw);
2985 pw.println();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002986 final long now = System.currentTimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002987 final long nowElapsed = SystemClock.elapsedRealtime();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002988 final long nowUptime = SystemClock.uptimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002989 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
2990 final Date date = new Date();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002991 boolean needSep = false;
2992 if (mOpModeWatchers.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002993 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002994 for (int i=0; i<mOpModeWatchers.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002995 if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
2996 continue;
2997 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002998 boolean printedOpHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002999 ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003000 for (int j=0; j<callbacks.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003001 final ModeCallback cb = callbacks.valueAt(j);
3002 if (dumpPackage != null && cb.mWatchingUid >= 0
3003 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3004 continue;
3005 }
3006 needSep = true;
3007 if (!printedHeader) {
3008 pw.println(" Op mode watchers:");
3009 printedHeader = true;
3010 }
3011 if (!printedOpHeader) {
3012 pw.print(" Op ");
3013 pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
3014 pw.println(":");
3015 printedOpHeader = true;
3016 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003017 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003018 pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003019 }
3020 }
3021 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003022 if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
3023 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003024 for (int i=0; i<mPackageModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003025 if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
3026 continue;
3027 }
3028 needSep = true;
3029 if (!printedHeader) {
3030 pw.println(" Package mode watchers:");
3031 printedHeader = true;
3032 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003033 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
3034 pw.println(":");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003035 ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003036 for (int j=0; j<callbacks.size(); j++) {
3037 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn68d76552017-02-27 15:32:03 -08003038 pw.println(callbacks.valueAt(j));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003039 }
3040 }
3041 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003042 if (mModeWatchers.size() > 0 && dumpOp < 0) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003043 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003044 for (int i=0; i<mModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003045 final ModeCallback cb = mModeWatchers.valueAt(i);
3046 if (dumpPackage != null && cb.mWatchingUid >= 0
3047 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3048 continue;
3049 }
3050 needSep = true;
3051 if (!printedHeader) {
3052 pw.println(" All op mode watchers:");
3053 printedHeader = true;
3054 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003055 pw.print(" ");
3056 pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003057 pw.print(": "); pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003058 }
3059 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003060 if (mActiveWatchers.size() > 0 && dumpMode < 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003061 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003062 boolean printedHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003063 for (int i = 0; i < mActiveWatchers.size(); i++) {
3064 final SparseArray<ActiveCallback> activeWatchers = mActiveWatchers.valueAt(i);
3065 if (activeWatchers.size() <= 0) {
3066 continue;
3067 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003068 final ActiveCallback cb = activeWatchers.valueAt(0);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003069 if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
3070 continue;
3071 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003072 if (dumpPackage != null && cb.mWatchingUid >= 0
3073 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3074 continue;
3075 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003076 if (!printedHeader) {
3077 pw.println(" All op active watchers:");
3078 printedHeader = true;
3079 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003080 pw.print(" ");
3081 pw.print(Integer.toHexString(System.identityHashCode(
3082 mActiveWatchers.keyAt(i))));
3083 pw.println(" ->");
3084 pw.print(" [");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003085 final int opCount = activeWatchers.size();
3086 for (i = 0; i < opCount; i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003087 if (i > 0) {
3088 pw.print(' ');
3089 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003090 pw.print(AppOpsManager.opToName(activeWatchers.keyAt(i)));
3091 if (i < opCount - 1) {
3092 pw.print(',');
3093 }
3094 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003095 pw.println("]");
3096 pw.print(" ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003097 pw.println(cb);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003098 }
3099 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003100 if (mClients.size() > 0 && dumpMode < 0) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003101 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003102 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003103 for (int i=0; i<mClients.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003104 boolean printedClient = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003105 ClientState cs = mClients.valueAt(i);
Svet Ganovf7b47252018-02-26 11:11:27 -08003106 if (cs.mStartedOps.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003107 boolean printedStarted = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003108 for (int j=0; j<cs.mStartedOps.size(); j++) {
3109 Op op = cs.mStartedOps.get(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003110 if (dumpOp >= 0 && op.op != dumpOp) {
3111 continue;
3112 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003113 if (dumpPackage != null && !dumpPackage.equals(op.packageName)) {
3114 continue;
3115 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003116 if (!printedHeader) {
3117 pw.println(" Clients:");
3118 printedHeader = true;
3119 }
3120 if (!printedClient) {
3121 pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
3122 pw.print(" "); pw.println(cs);
3123 printedClient = true;
3124 }
3125 if (!printedStarted) {
3126 pw.println(" Started ops:");
3127 printedStarted = true;
3128 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003129 pw.print(" "); pw.print("uid="); pw.print(op.uid);
3130 pw.print(" pkg="); pw.print(op.packageName);
3131 pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
3132 }
3133 }
3134 }
3135 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003136 if (mAudioRestrictions.size() > 0 && dumpOp < 0 && dumpPackage != null
3137 && dumpMode < 0) {
John Spurlock1af30c72014-03-10 08:33:35 -04003138 boolean printedHeader = false;
3139 for (int o=0; o<mAudioRestrictions.size(); o++) {
3140 final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
3141 final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
3142 for (int i=0; i<restrictions.size(); i++) {
3143 if (!printedHeader){
3144 pw.println(" Audio Restrictions:");
3145 printedHeader = true;
3146 needSep = true;
3147 }
John Spurlock7b414672014-07-18 13:02:39 -04003148 final int usage = restrictions.keyAt(i);
John Spurlock1af30c72014-03-10 08:33:35 -04003149 pw.print(" "); pw.print(op);
John Spurlock7b414672014-07-18 13:02:39 -04003150 pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
John Spurlock1af30c72014-03-10 08:33:35 -04003151 Restriction r = restrictions.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003152 pw.print(": mode="); pw.println(AppOpsManager.modeToName(r.mode));
John Spurlock1af30c72014-03-10 08:33:35 -04003153 if (!r.exceptionPackages.isEmpty()) {
3154 pw.println(" Exceptions:");
3155 for (int j=0; j<r.exceptionPackages.size(); j++) {
3156 pw.print(" "); pw.println(r.exceptionPackages.valueAt(j));
3157 }
3158 }
3159 }
3160 }
3161 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003162 if (needSep) {
3163 pw.println();
3164 }
Svet Ganov2af57082015-07-30 08:44:20 -07003165 for (int i=0; i<mUidStates.size(); i++) {
3166 UidState uidState = mUidStates.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003167 final SparseIntArray opModes = uidState.opModes;
3168 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
3169
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003170 if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
3171 boolean hasOp = dumpOp < 0 || (uidState.opModes != null
3172 && uidState.opModes.indexOfKey(dumpOp) >= 0);
3173 boolean hasPackage = dumpPackage == null;
3174 boolean hasMode = dumpMode < 0;
3175 if (!hasMode && opModes != null) {
3176 for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
3177 if (opModes.valueAt(opi) == dumpMode) {
3178 hasMode = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003179 }
3180 }
3181 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003182 if (pkgOps != null) {
3183 for (int pkgi = 0;
3184 (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
3185 pkgi++) {
3186 Ops ops = pkgOps.valueAt(pkgi);
3187 if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
3188 hasOp = true;
3189 }
3190 if (!hasMode) {
3191 for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
3192 if (ops.valueAt(opi).mode == dumpMode) {
3193 hasMode = true;
3194 }
3195 }
3196 }
3197 if (!hasPackage && dumpPackage.equals(ops.packageName)) {
3198 hasPackage = true;
3199 }
3200 }
3201 }
3202 if (uidState.foregroundOps != null && !hasOp) {
3203 if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
3204 hasOp = true;
3205 }
3206 }
3207 if (!hasOp || !hasPackage || !hasMode) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003208 continue;
3209 }
3210 }
Svet Ganov2af57082015-07-30 08:44:20 -07003211
3212 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003213 pw.print(" state=");
3214 pw.println(UID_STATE_NAMES[uidState.state]);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003215 if (uidState.state != uidState.pendingState) {
3216 pw.print(" pendingState=");
3217 pw.println(UID_STATE_NAMES[uidState.pendingState]);
3218 }
3219 if (uidState.pendingStateCommitTime != 0) {
3220 pw.print(" pendingStateCommitTime=");
3221 TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowUptime, pw);
3222 pw.println();
3223 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003224 if (uidState.startNesting != 0) {
3225 pw.print(" startNesting=");
3226 pw.println(uidState.startNesting);
3227 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003228 if (uidState.foregroundOps != null && (dumpMode < 0
3229 || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003230 pw.println(" foregroundOps:");
3231 for (int j = 0; j < uidState.foregroundOps.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003232 if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
3233 continue;
3234 }
3235 pw.print(" ");
3236 pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
3237 pw.print(": ");
3238 pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003239 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003240 pw.print(" hasForegroundWatchers=");
3241 pw.println(uidState.hasForegroundWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003242 }
Svet Ganovee438d42017-01-19 18:04:38 -08003243 needSep = true;
Svet Ganov2af57082015-07-30 08:44:20 -07003244
Svet Ganov2af57082015-07-30 08:44:20 -07003245 if (opModes != null) {
3246 final int opModeCount = opModes.size();
3247 for (int j = 0; j < opModeCount; j++) {
3248 final int code = opModes.keyAt(j);
3249 final int mode = opModes.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003250 if (dumpOp >= 0 && dumpOp != code) {
3251 continue;
3252 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003253 if (dumpMode >= 0 && dumpMode != mode) {
3254 continue;
3255 }
Svet Ganov2af57082015-07-30 08:44:20 -07003256 pw.print(" "); pw.print(AppOpsManager.opToName(code));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003257 pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
Svet Ganov2af57082015-07-30 08:44:20 -07003258 }
3259 }
3260
Svet Ganov2af57082015-07-30 08:44:20 -07003261 if (pkgOps == null) {
3262 continue;
3263 }
3264
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003265 for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003266 final Ops ops = pkgOps.valueAt(pkgi);
3267 if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
3268 continue;
3269 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003270 boolean printedPackage = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003271 for (int j=0; j<ops.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003272 final Op op = ops.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003273 if (dumpOp >= 0 && dumpOp != op.op) {
3274 continue;
3275 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003276 if (dumpMode >= 0 && dumpMode != op.mode) {
3277 continue;
3278 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003279 if (!printedPackage) {
3280 pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
3281 printedPackage = true;
3282 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003283 pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003284 pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003285 final int switchOp = AppOpsManager.opToSwitch(op.op);
3286 if (switchOp != op.op) {
3287 pw.print(" / switch ");
3288 pw.print(AppOpsManager.opToName(switchOp));
3289 final Op switchObj = ops.get(switchOp);
3290 int mode = switchObj != null
3291 ? switchObj.mode : AppOpsManager.opToDefaultMode(switchOp);
3292 pw.print("="); pw.print(AppOpsManager.modeToName(mode));
3293 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003294 pw.println("): ");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003295 dumpTimesLocked(pw,
3296 " Access: ",
3297 " ", op.time, now, sdf, date);
3298 dumpTimesLocked(pw,
3299 " Reject: ",
3300 " ", op.rejectTime, now, sdf, date);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003301 if (op.duration == -1) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003302 pw.print(" Running start at: ");
3303 TimeUtils.formatDuration(nowElapsed-op.startRealtime, pw);
3304 pw.println();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08003305 } else if (op.duration != 0) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003306 pw.print(" duration=");
3307 TimeUtils.formatDuration(op.duration, pw);
3308 pw.println();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003309 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003310 if (op.startNesting != 0) {
3311 pw.print(" startNesting=");
3312 pw.println(op.startNesting);
3313 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003314 }
3315 }
3316 }
Svet Ganovee438d42017-01-19 18:04:38 -08003317 if (needSep) {
3318 pw.println();
3319 }
3320
3321 final int userRestrictionCount = mOpUserRestrictions.size();
3322 for (int i = 0; i < userRestrictionCount; i++) {
3323 IBinder token = mOpUserRestrictions.keyAt(i);
3324 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
3325 pw.println(" User restrictions for token " + token + ":");
3326
3327 final int restrictionCount = restrictionState.perUserRestrictions != null
3328 ? restrictionState.perUserRestrictions.size() : 0;
3329 if (restrictionCount > 0) {
3330 pw.println(" Restricted ops:");
3331 for (int j = 0; j < restrictionCount; j++) {
3332 int userId = restrictionState.perUserRestrictions.keyAt(j);
3333 boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
3334 if (restrictedOps == null) {
3335 continue;
3336 }
3337 StringBuilder restrictedOpsValue = new StringBuilder();
3338 restrictedOpsValue.append("[");
3339 final int restrictedOpCount = restrictedOps.length;
3340 for (int k = 0; k < restrictedOpCount; k++) {
3341 if (restrictedOps[k]) {
3342 if (restrictedOpsValue.length() > 1) {
3343 restrictedOpsValue.append(", ");
3344 }
3345 restrictedOpsValue.append(AppOpsManager.opToName(k));
3346 }
3347 }
3348 restrictedOpsValue.append("]");
3349 pw.print(" "); pw.print("user: "); pw.print(userId);
3350 pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
3351 }
3352 }
3353
3354 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
3355 ? restrictionState.perUserExcludedPackages.size() : 0;
3356 if (excludedPackageCount > 0) {
3357 pw.println(" Excluded packages:");
3358 for (int j = 0; j < excludedPackageCount; j++) {
3359 int userId = restrictionState.perUserExcludedPackages.keyAt(j);
3360 String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
3361 pw.print(" "); pw.print("user: "); pw.print(userId);
3362 pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
3363 }
3364 }
3365 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003366 }
3367 }
John Spurlock1af30c72014-03-10 08:33:35 -04003368
3369 private static final class Restriction {
3370 private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
3371 int mode;
3372 ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
3373 }
Jason Monk62062992014-05-06 09:55:28 -04003374
3375 @Override
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003376 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
Jason Monk62062992014-05-06 09:55:28 -04003377 checkSystemUid("setUserRestrictions");
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003378 Preconditions.checkNotNull(restrictions);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003379 Preconditions.checkNotNull(token);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003380 for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
Jason Monk62062992014-05-06 09:55:28 -04003381 String restriction = AppOpsManager.opToRestriction(i);
Suprabh Shukla64e0dcb2016-05-24 16:23:11 -07003382 if (restriction != null) {
3383 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
3384 userHandle, null);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003385 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003386 }
3387 }
3388
3389 @Override
Ruben Brunk29931bc2016-03-11 00:24:26 -08003390 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
3391 String[] exceptionPackages) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003392 if (Binder.getCallingPid() != Process.myPid()) {
3393 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
3394 Binder.getCallingPid(), Binder.getCallingUid(), null);
3395 }
3396 if (userHandle != UserHandle.getCallingUserId()) {
3397 if (mContext.checkCallingOrSelfPermission(Manifest.permission
3398 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
3399 && mContext.checkCallingOrSelfPermission(Manifest.permission
3400 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
3401 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
3402 + " INTERACT_ACROSS_USERS to interact cross user ");
Jason Monk62062992014-05-06 09:55:28 -04003403 }
3404 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003405 verifyIncomingOp(code);
3406 Preconditions.checkNotNull(token);
Ruben Brunk29931bc2016-03-11 00:24:26 -08003407 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003408 }
3409
3410 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
Ruben Brunk29931bc2016-03-11 00:24:26 -08003411 int userHandle, String[] exceptionPackages) {
Svet Ganov442ed572016-08-17 17:29:43 -07003412 synchronized (AppOpsService.this) {
3413 ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
3414
3415 if (restrictionState == null) {
3416 try {
3417 restrictionState = new ClientRestrictionState(token);
3418 } catch (RemoteException e) {
3419 return;
3420 }
3421 mOpUserRestrictions.put(token, restrictionState);
Ruben Brunk29931bc2016-03-11 00:24:26 -08003422 }
Svet Ganov442ed572016-08-17 17:29:43 -07003423
3424 if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003425 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07003426 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
Svet Ganov442ed572016-08-17 17:29:43 -07003427 }
3428
3429 if (restrictionState.isDefault()) {
3430 mOpUserRestrictions.remove(token);
3431 restrictionState.destroy();
3432 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08003433 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -04003434 }
3435
Svet Ganov3a95f832018-03-23 17:44:30 -07003436 private void notifyWatchersOfChange(int code, int uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003437 final ArraySet<ModeCallback> clonedCallbacks;
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003438 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003439 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003440 if (callbacks == null) {
3441 return;
3442 }
Dianne Hackborn68d76552017-02-27 15:32:03 -08003443 clonedCallbacks = new ArraySet<>(callbacks);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003444 }
3445
Svet Ganov3a95f832018-03-23 17:44:30 -07003446 notifyOpChanged(clonedCallbacks, code, uid, null);
Jason Monk62062992014-05-06 09:55:28 -04003447 }
3448
3449 @Override
3450 public void removeUser(int userHandle) throws RemoteException {
3451 checkSystemUid("removeUser");
Svet Ganov442ed572016-08-17 17:29:43 -07003452 synchronized (AppOpsService.this) {
3453 final int tokenCount = mOpUserRestrictions.size();
3454 for (int i = tokenCount - 1; i >= 0; i--) {
3455 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
3456 opRestrictions.removeUser(userHandle);
3457 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003458 removeUidsForUserLocked(userHandle);
3459 }
3460 }
3461
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003462 @Override
3463 public boolean isOperationActive(int code, int uid, String packageName) {
Svet Ganovf7b47252018-02-26 11:11:27 -08003464 if (Binder.getCallingUid() != uid) {
3465 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
3466 != PackageManager.PERMISSION_GRANTED) {
3467 return false;
3468 }
3469 }
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003470 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003471 final String resolvedPackageName = resolvePackageName(uid, packageName);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003472 if (resolvedPackageName == null) {
3473 return false;
3474 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003475 synchronized (AppOpsService.this) {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003476 for (int i = mClients.size() - 1; i >= 0; i--) {
3477 final ClientState client = mClients.valueAt(i);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003478 for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
3479 final Op op = client.mStartedOps.get(j);
3480 if (op.op == code && op.uid == uid) return true;
3481 }
3482 }
3483 }
3484 return false;
3485 }
3486
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003487 private void removeUidsForUserLocked(int userHandle) {
3488 for (int i = mUidStates.size() - 1; i >= 0; --i) {
3489 final int uid = mUidStates.keyAt(i);
3490 if (UserHandle.getUserId(uid) == userHandle) {
3491 mUidStates.removeAt(i);
3492 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003493 }
3494 }
3495
Jason Monk62062992014-05-06 09:55:28 -04003496 private void checkSystemUid(String function) {
3497 int uid = Binder.getCallingUid();
3498 if (uid != Process.SYSTEM_UID) {
3499 throw new SecurityException(function + " must by called by the system");
3500 }
3501 }
3502
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003503 private static String resolvePackageName(int uid, String packageName) {
Svet Ganov82f09bc2018-01-12 22:08:40 -08003504 if (uid == Process.ROOT_UID) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003505 return "root";
3506 } else if (uid == Process.SHELL_UID) {
3507 return "com.android.shell";
Svet Ganov82f09bc2018-01-12 22:08:40 -08003508 } else if (uid == Process.MEDIA_UID) {
3509 return "media";
3510 } else if (uid == Process.AUDIOSERVER_UID) {
3511 return "audioserver";
3512 } else if (uid == Process.CAMERASERVER_UID) {
3513 return "cameraserver";
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003514 } else if (uid == Process.SYSTEM_UID && packageName == null) {
3515 return "android";
3516 }
3517 return packageName;
3518 }
3519
Svet Ganov82f09bc2018-01-12 22:08:40 -08003520 private static int resolveUid(String packageName) {
3521 if (packageName == null) {
3522 return -1;
3523 }
3524 switch (packageName) {
3525 case "root":
3526 return Process.ROOT_UID;
3527 case "shell":
3528 return Process.SHELL_UID;
3529 case "media":
3530 return Process.MEDIA_UID;
3531 case "audioserver":
3532 return Process.AUDIOSERVER_UID;
3533 case "cameraserver":
3534 return Process.CAMERASERVER_UID;
3535 }
3536 return -1;
3537 }
3538
Svet Ganov2af57082015-07-30 08:44:20 -07003539 private static String[] getPackagesForUid(int uid) {
Svet Ganovf3807aa2015-08-02 10:09:56 -07003540 String[] packageNames = null;
Svet Ganov2af57082015-07-30 08:44:20 -07003541 try {
riddle_hsu40b300f2015-11-23 13:22:03 +08003542 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
Svet Ganov2af57082015-07-30 08:44:20 -07003543 } catch (RemoteException e) {
3544 /* ignore - local call */
3545 }
Svet Ganovf3807aa2015-08-02 10:09:56 -07003546 if (packageNames == null) {
3547 return EmptyArray.STRING;
3548 }
3549 return packageNames;
Svet Ganov2af57082015-07-30 08:44:20 -07003550 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003551
3552 private final class ClientRestrictionState implements DeathRecipient {
3553 private final IBinder token;
3554 SparseArray<boolean[]> perUserRestrictions;
3555 SparseArray<String[]> perUserExcludedPackages;
3556
3557 public ClientRestrictionState(IBinder token)
3558 throws RemoteException {
3559 token.linkToDeath(this, 0);
3560 this.token = token;
3561 }
3562
3563 public boolean setRestriction(int code, boolean restricted,
3564 String[] excludedPackages, int userId) {
3565 boolean changed = false;
3566
3567 if (perUserRestrictions == null && restricted) {
3568 perUserRestrictions = new SparseArray<>();
3569 }
3570
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003571 int[] users;
3572 if (userId == UserHandle.USER_ALL) {
3573 List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003574
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003575 users = new int[liveUsers.size()];
3576 for (int i = 0; i < liveUsers.size(); i++) {
3577 users[i] = liveUsers.get(i).id;
3578 }
3579 } else {
3580 users = new int[]{userId};
3581 }
3582
3583 if (perUserRestrictions != null) {
3584 int numUsers = users.length;
3585
3586 for (int i = 0; i < numUsers; i++) {
3587 int thisUserId = users[i];
3588
3589 boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
3590 if (userRestrictions == null && restricted) {
3591 userRestrictions = new boolean[AppOpsManager._NUM_OP];
3592 perUserRestrictions.put(thisUserId, userRestrictions);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003593 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003594 if (userRestrictions != null && userRestrictions[code] != restricted) {
3595 userRestrictions[code] = restricted;
3596 if (!restricted && isDefault(userRestrictions)) {
3597 perUserRestrictions.remove(thisUserId);
3598 userRestrictions = null;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003599 }
3600 changed = true;
3601 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003602
3603 if (userRestrictions != null) {
3604 final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
3605 if (perUserExcludedPackages == null && !noExcludedPackages) {
3606 perUserExcludedPackages = new SparseArray<>();
3607 }
3608 if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
3609 perUserExcludedPackages.get(thisUserId))) {
3610 if (noExcludedPackages) {
3611 perUserExcludedPackages.remove(thisUserId);
3612 if (perUserExcludedPackages.size() <= 0) {
3613 perUserExcludedPackages = null;
3614 }
3615 } else {
3616 perUserExcludedPackages.put(thisUserId, excludedPackages);
3617 }
3618 changed = true;
3619 }
3620 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003621 }
3622 }
3623
3624 return changed;
3625 }
3626
3627 public boolean hasRestriction(int restriction, String packageName, int userId) {
3628 if (perUserRestrictions == null) {
3629 return false;
3630 }
3631 boolean[] restrictions = perUserRestrictions.get(userId);
3632 if (restrictions == null) {
3633 return false;
3634 }
3635 if (!restrictions[restriction]) {
3636 return false;
3637 }
3638 if (perUserExcludedPackages == null) {
3639 return true;
3640 }
3641 String[] perUserExclusions = perUserExcludedPackages.get(userId);
3642 if (perUserExclusions == null) {
3643 return true;
3644 }
3645 return !ArrayUtils.contains(perUserExclusions, packageName);
3646 }
3647
3648 public void removeUser(int userId) {
3649 if (perUserExcludedPackages != null) {
3650 perUserExcludedPackages.remove(userId);
3651 if (perUserExcludedPackages.size() <= 0) {
3652 perUserExcludedPackages = null;
3653 }
3654 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003655 if (perUserRestrictions != null) {
3656 perUserRestrictions.remove(userId);
3657 if (perUserRestrictions.size() <= 0) {
3658 perUserRestrictions = null;
3659 }
3660 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003661 }
3662
3663 public boolean isDefault() {
3664 return perUserRestrictions == null || perUserRestrictions.size() <= 0;
3665 }
3666
3667 @Override
3668 public void binderDied() {
3669 synchronized (AppOpsService.this) {
3670 mOpUserRestrictions.remove(token);
3671 if (perUserRestrictions == null) {
3672 return;
3673 }
3674 final int userCount = perUserRestrictions.size();
3675 for (int i = 0; i < userCount; i++) {
3676 final boolean[] restrictions = perUserRestrictions.valueAt(i);
3677 final int restrictionCount = restrictions.length;
3678 for (int j = 0; j < restrictionCount; j++) {
3679 if (restrictions[j]) {
3680 final int changedCode = j;
Svet Ganov3a95f832018-03-23 17:44:30 -07003681 mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003682 }
3683 }
3684 }
3685 destroy();
3686 }
3687 }
3688
3689 public void destroy() {
3690 token.unlinkToDeath(this, 0);
3691 }
3692
3693 private boolean isDefault(boolean[] array) {
3694 if (ArrayUtils.isEmpty(array)) {
3695 return true;
3696 }
3697 for (boolean value : array) {
3698 if (value) {
3699 return false;
3700 }
3701 }
3702 return true;
3703 }
3704 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003705}