blob: 786d757557d161bee47e25973726df1cde31daa9 [file] [log] [blame]
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Philip P. Moltmanne683f192017-06-23 14:05:04 -070019import android.Manifest;
20import android.app.ActivityManager;
21import android.app.ActivityThread;
22import android.app.AppGlobals;
23import android.app.AppOpsManager;
Dianne Hackbornd5254412018-05-11 18:02:58 -070024import android.app.AppOpsManagerInternal;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070025import android.content.ContentResolver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070026import android.content.Context;
27import android.content.pm.ApplicationInfo;
28import android.content.pm.IPackageManager;
29import android.content.pm.PackageManager;
30import android.content.pm.PackageManagerInternal;
31import android.content.pm.UserInfo;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070032import android.database.ContentObserver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070033import android.media.AudioAttributes;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070034import android.net.Uri;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070035import android.os.AsyncTask;
36import android.os.Binder;
37import android.os.Bundle;
38import android.os.Handler;
39import android.os.IBinder;
40import android.os.Process;
41import android.os.RemoteException;
42import android.os.ResultReceiver;
43import android.os.ServiceManager;
44import android.os.ShellCallback;
45import android.os.ShellCommand;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070046import android.os.SystemClock;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070047import android.os.UserHandle;
48import android.os.UserManager;
49import android.os.storage.StorageManagerInternal;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070050import android.provider.Settings;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070051import android.util.ArrayMap;
52import android.util.ArraySet;
53import android.util.AtomicFile;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070054import android.util.KeyValueListParser;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070055import android.util.Slog;
56import android.util.SparseArray;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -070057import android.util.SparseBooleanArray;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070058import android.util.SparseIntArray;
59import android.util.TimeUtils;
60import android.util.Xml;
61
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070062import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080063import com.android.internal.app.IAppOpsActiveCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070064import com.android.internal.app.IAppOpsCallback;
65import com.android.internal.app.IAppOpsService;
66import com.android.internal.os.Zygote;
67import com.android.internal.util.ArrayUtils;
68import com.android.internal.util.DumpUtils;
69import com.android.internal.util.FastXmlSerializer;
70import com.android.internal.util.Preconditions;
71import com.android.internal.util.XmlUtils;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080072import com.android.internal.util.function.pooled.PooledLambda;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -050073
Philip P. Moltmanne683f192017-06-23 14:05:04 -070074import libcore.util.EmptyArray;
75
76import org.xmlpull.v1.XmlPullParser;
77import org.xmlpull.v1.XmlPullParserException;
78import org.xmlpull.v1.XmlSerializer;
79
Dianne Hackborna06de0f2012-12-11 16:34:47 -080080import java.io.File;
81import java.io.FileDescriptor;
Dianne Hackborn35654b62013-01-14 17:38:02 -080082import java.io.FileInputStream;
83import java.io.FileNotFoundException;
84import java.io.FileOutputStream;
85import java.io.IOException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080086import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +010087import java.nio.charset.StandardCharsets;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070088import java.text.SimpleDateFormat;
Dianne Hackborn35654b62013-01-14 17:38:02 -080089import java.util.ArrayList;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -070090import java.util.Arrays;
Svetoslav215b44a2015-08-04 19:03:40 -070091import java.util.Collections;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070092import java.util.Date;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080093import java.util.HashMap;
Dianne Hackbornc2293022013-02-06 23:14:49 -080094import java.util.Iterator;
Dianne Hackborn35654b62013-01-14 17:38:02 -080095import java.util.List;
Dianne Hackborn607b4142013-08-02 18:10:10 -070096import java.util.Map;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080097
Dianne Hackborne93ab412018-05-14 17:52:30 -070098import static android.app.AppOpsManager._NUM_UID_STATE;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070099import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
100import static android.app.AppOpsManager.UID_STATE_CACHED;
101import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
102import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
Dianne Hackborne93ab412018-05-14 17:52:30 -0700103import static android.app.AppOpsManager.UID_STATE_LAST_NON_RESTRICTED;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700104import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
105import static android.app.AppOpsManager.UID_STATE_TOP;
106
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800107public class AppOpsService extends IAppOpsService.Stub {
108 static final String TAG = "AppOps";
Dianne Hackborn35654b62013-01-14 17:38:02 -0800109 static final boolean DEBUG = false;
110
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700111 private static final int NO_VERSION = -1;
112 /** Increment by one every time and add the corresponding upgrade logic in
113 * {@link #upgradeLocked(int)} below. The first version was 1 */
114 private static final int CURRENT_VERSION = 1;
115
Dianne Hackborn35654b62013-01-14 17:38:02 -0800116 // Write at most every 30 minutes.
117 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800118
Svet Ganov3a95f832018-03-23 17:44:30 -0700119 // Constant meaning that any UID should be matched when dispatching callbacks
120 private static final int UID_ANY = -2;
121
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700122 // Map from process states to the uid states we track.
123 private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
124 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
125 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
126 UID_STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
127 UID_STATE_FOREGROUND_SERVICE, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
128 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
129 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
130 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
131 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
132 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_BACKUP
133 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_SERVICE
134 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_RECEIVER
135 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
136 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
137 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HOME
138 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
139 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
140 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
141 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_RECENT
142 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
143 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT
144 };
145
146 static final String[] UID_STATE_NAMES = new String[] {
147 "pers ", // UID_STATE_PERSISTENT
148 "top ", // UID_STATE_TOP
149 "fgsvc", // UID_STATE_FOREGROUND_SERVICE
150 "fg ", // UID_STATE_FOREGROUND
151 "bg ", // UID_STATE_BACKGROUND
152 "cch ", // UID_STATE_CACHED
153 };
154
155 static final String[] UID_STATE_TIME_ATTRS = new String[] {
156 "tp", // UID_STATE_PERSISTENT
157 "tt", // UID_STATE_TOP
158 "tfs", // UID_STATE_FOREGROUND_SERVICE
159 "tf", // UID_STATE_FOREGROUND
160 "tb", // UID_STATE_BACKGROUND
161 "tc", // UID_STATE_CACHED
162 };
163
164 static final String[] UID_STATE_REJECT_ATTRS = new String[] {
165 "rp", // UID_STATE_PERSISTENT
166 "rt", // UID_STATE_TOP
167 "rfs", // UID_STATE_FOREGROUND_SERVICE
168 "rf", // UID_STATE_FOREGROUND
169 "rb", // UID_STATE_BACKGROUND
170 "rc", // UID_STATE_CACHED
171 };
172
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800173 Context mContext;
174 final AtomicFile mFile;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800175 final Handler mHandler;
176
Dianne Hackbornd5254412018-05-11 18:02:58 -0700177 private final AppOpsManagerInternalImpl mAppOpsManagerInternal
178 = new AppOpsManagerInternalImpl();
179
Dianne Hackborn35654b62013-01-14 17:38:02 -0800180 boolean mWriteScheduled;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800181 boolean mFastWriteScheduled;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800182 final Runnable mWriteRunner = new Runnable() {
183 public void run() {
184 synchronized (AppOpsService.this) {
185 mWriteScheduled = false;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800186 mFastWriteScheduled = false;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800187 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
188 @Override protected Void doInBackground(Void... params) {
189 writeState();
190 return null;
191 }
192 };
193 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
194 }
195 }
196 };
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800197
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700198 @VisibleForTesting
199 final SparseArray<UidState> mUidStates = new SparseArray<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800200
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700201 long mLastUptime;
202
Ruben Brunk29931bc2016-03-11 00:24:26 -0800203 /*
204 * These are app op restrictions imposed per user from various parties.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800205 */
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700206 private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
Jason Monk62062992014-05-06 09:55:28 -0400207
Dianne Hackbornd5254412018-05-11 18:02:58 -0700208 SparseIntArray mProfileOwners;
209
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700210 /**
211 * All times are in milliseconds. These constants are kept synchronized with the system
212 * global Settings. Any access to this class or its fields should be done while
213 * holding the AppOpsService lock.
214 */
215 private final class Constants extends ContentObserver {
216 // Key names stored in the settings value.
Dianne Hackborne93ab412018-05-14 17:52:30 -0700217 private static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
218 private static final String KEY_FG_SERVICE_STATE_SETTLE_TIME
219 = "fg_service_state_settle_time";
220 private static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700221
222 /**
Dianne Hackborne93ab412018-05-14 17:52:30 -0700223 * How long we want for a drop in uid state from top to settle before applying it.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700224 * @see Settings.Global#APP_OPS_CONSTANTS
Dianne Hackborne93ab412018-05-14 17:52:30 -0700225 * @see #KEY_TOP_STATE_SETTLE_TIME
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700226 */
Dianne Hackborne93ab412018-05-14 17:52:30 -0700227 public long TOP_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700228
Dianne Hackborne93ab412018-05-14 17:52:30 -0700229 /**
230 * How long we want for a drop in uid state from foreground to settle before applying it.
231 * @see Settings.Global#APP_OPS_CONSTANTS
232 * @see #KEY_FG_SERVICE_STATE_SETTLE_TIME
233 */
234 public long FG_SERVICE_STATE_SETTLE_TIME;
235
236 /**
237 * How long we want for a drop in uid state from background to settle before applying it.
238 * @see Settings.Global#APP_OPS_CONSTANTS
239 * @see #KEY_BG_STATE_SETTLE_TIME
240 */
241 public long BG_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700242
243 private final KeyValueListParser mParser = new KeyValueListParser(',');
244 private ContentResolver mResolver;
245
246 public Constants(Handler handler) {
247 super(handler);
248 updateConstants();
249 }
250
251 public void startMonitoring(ContentResolver resolver) {
252 mResolver = resolver;
253 mResolver.registerContentObserver(
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700254 Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700255 false, this);
256 updateConstants();
257 }
258
259 @Override
260 public void onChange(boolean selfChange, Uri uri) {
261 updateConstants();
262 }
263
264 private void updateConstants() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700265 String value = mResolver != null ? Settings.Global.getString(mResolver,
266 Settings.Global.APP_OPS_CONSTANTS) : "";
267
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700268 synchronized (AppOpsService.this) {
269 try {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700270 mParser.setString(value);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700271 } catch (IllegalArgumentException e) {
272 // Failed to parse the settings string, log this and move on
273 // with defaults.
274 Slog.e(TAG, "Bad app ops settings", e);
275 }
Dianne Hackborne93ab412018-05-14 17:52:30 -0700276 TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
277 KEY_TOP_STATE_SETTLE_TIME, 30 * 1000L);
278 FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
279 KEY_FG_SERVICE_STATE_SETTLE_TIME, 10 * 1000L);
280 BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
281 KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700282 }
283 }
284
285 void dump(PrintWriter pw) {
286 pw.println(" Settings:");
287
Dianne Hackborne93ab412018-05-14 17:52:30 -0700288 pw.print(" "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("=");
289 TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700290 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700291 pw.print(" "); pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME); pw.print("=");
292 TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700293 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700294 pw.print(" "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("=");
295 TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700296 pw.println();
297 }
298 }
299
300 private final Constants mConstants;
301
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700302 @VisibleForTesting
303 static final class UidState {
Svet Ganov2af57082015-07-30 08:44:20 -0700304 public final int uid;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700305
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700306 public int state = UID_STATE_CACHED;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700307 public int pendingState = UID_STATE_CACHED;
308 public long pendingStateCommitTime;
309
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700310 public int startNesting;
Svet Ganov2af57082015-07-30 08:44:20 -0700311 public ArrayMap<String, Ops> pkgOps;
312 public SparseIntArray opModes;
313
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700314 // true indicates there is an interested observer, false there isn't but it has such an op
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700315 public SparseBooleanArray foregroundOps;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700316 public boolean hasForegroundWatchers;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700317
Svet Ganov2af57082015-07-30 08:44:20 -0700318 public UidState(int uid) {
319 this.uid = uid;
320 }
321
322 public void clear() {
323 pkgOps = null;
324 opModes = null;
325 }
326
327 public boolean isDefault() {
328 return (pkgOps == null || pkgOps.isEmpty())
329 && (opModes == null || opModes.size() <= 0);
330 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700331
332 int evalMode(int mode) {
333 if (mode == AppOpsManager.MODE_FOREGROUND) {
Dianne Hackborne93ab412018-05-14 17:52:30 -0700334 return state <= UID_STATE_LAST_NON_RESTRICTED
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700335 ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
336 }
337 return mode;
338 }
339
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700340 private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
341 SparseBooleanArray which) {
342 boolean curValue = which.get(op, false);
343 ArraySet<ModeCallback> callbacks = watchers.get(op);
344 if (callbacks != null) {
345 for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
346 if ((callbacks.valueAt(cbi).mFlags
347 & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
348 hasForegroundWatchers = true;
349 curValue = true;
350 }
351 }
352 }
353 which.put(op, curValue);
354 }
355
356 public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700357 SparseBooleanArray which = null;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700358 hasForegroundWatchers = false;
359 if (opModes != null) {
360 for (int i = opModes.size() - 1; i >= 0; i--) {
361 if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
362 if (which == null) {
363 which = new SparseBooleanArray();
364 }
365 evalForegroundWatchers(opModes.keyAt(i), watchers, which);
366 }
367 }
368 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700369 if (pkgOps != null) {
370 for (int i = pkgOps.size() - 1; i >= 0; i--) {
371 Ops ops = pkgOps.valueAt(i);
372 for (int j = ops.size() - 1; j >= 0; j--) {
373 if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
374 if (which == null) {
375 which = new SparseBooleanArray();
376 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700377 evalForegroundWatchers(ops.keyAt(j), watchers, which);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700378 }
379 }
380 }
381 }
382 foregroundOps = which;
383 }
Svet Ganov2af57082015-07-30 08:44:20 -0700384 }
385
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700386 final static class Ops extends SparseArray<Op> {
387 final String packageName;
388 final UidState uidState;
389 final boolean isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800390
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700391 Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800392 packageName = _packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700393 uidState = _uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400394 isPrivileged = _isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800395 }
396 }
397
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700398 final static class Op {
399 final UidState uidState;
400 final int uid;
401 final String packageName;
402 final int op;
403 int proxyUid = -1;
404 String proxyPackageName;
405 int mode;
406 int duration;
407 long time[] = new long[_NUM_UID_STATE];
408 long rejectTime[] = new long[_NUM_UID_STATE];
409 int startNesting;
410 long startRealtime;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800411
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700412 Op(UidState _uidState, String _packageName, int _op) {
413 uidState = _uidState;
414 uid = _uidState.uid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700415 packageName = _packageName;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800416 op = _op;
David Braunf5d83192013-09-16 13:43:51 -0700417 mode = AppOpsManager.opToDefaultMode(op);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800418 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700419
420 boolean hasAnyTime() {
421 for (int i = 0; i < AppOpsManager._NUM_UID_STATE; i++) {
422 if (time[i] != 0) {
423 return true;
424 }
425 if (rejectTime[i] != 0) {
426 return true;
427 }
428 }
429 return false;
430 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700431
432 int getMode() {
433 return uidState.evalMode(mode);
434 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800435 }
436
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800437 final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
438 final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
439 final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
440 final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
Dianne Hackborn68d76552017-02-27 15:32:03 -0800441 final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800442
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700443 final class ModeCallback implements DeathRecipient {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800444 final IAppOpsCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700445 final int mWatchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700446 final int mFlags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700447 final int mCallingUid;
448 final int mCallingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800449
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700450 ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700451 int callingPid) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800452 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700453 mWatchingUid = watchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700454 mFlags = flags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700455 mCallingUid = callingUid;
456 mCallingPid = callingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800457 try {
458 mCallback.asBinder().linkToDeath(this, 0);
459 } catch (RemoteException e) {
460 }
461 }
462
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700463 public boolean isWatchingUid(int uid) {
464 return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
465 }
466
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700467 @Override
468 public String toString() {
469 StringBuilder sb = new StringBuilder(128);
470 sb.append("ModeCallback{");
471 sb.append(Integer.toHexString(System.identityHashCode(this)));
472 sb.append(" watchinguid=");
473 UserHandle.formatUid(sb, mWatchingUid);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700474 sb.append(" flags=0x");
475 sb.append(Integer.toHexString(mFlags));
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700476 sb.append(" from uid=");
477 UserHandle.formatUid(sb, mCallingUid);
478 sb.append(" pid=");
479 sb.append(mCallingPid);
480 sb.append('}');
481 return sb.toString();
482 }
483
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700484 void unlinkToDeath() {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800485 mCallback.asBinder().unlinkToDeath(this, 0);
486 }
487
488 @Override
489 public void binderDied() {
490 stopWatchingMode(mCallback);
491 }
492 }
493
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700494 final class ActiveCallback implements DeathRecipient {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800495 final IAppOpsActiveCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700496 final int mWatchingUid;
497 final int mCallingUid;
498 final int mCallingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800499
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700500 ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700501 int callingPid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800502 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700503 mWatchingUid = watchingUid;
504 mCallingUid = callingUid;
505 mCallingPid = callingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800506 try {
507 mCallback.asBinder().linkToDeath(this, 0);
508 } catch (RemoteException e) {
509 }
510 }
511
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700512 @Override
513 public String toString() {
514 StringBuilder sb = new StringBuilder(128);
515 sb.append("ActiveCallback{");
516 sb.append(Integer.toHexString(System.identityHashCode(this)));
517 sb.append(" watchinguid=");
518 UserHandle.formatUid(sb, mWatchingUid);
519 sb.append(" from uid=");
520 UserHandle.formatUid(sb, mCallingUid);
521 sb.append(" pid=");
522 sb.append(mCallingPid);
523 sb.append('}');
524 return sb.toString();
525 }
526
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700527 void destroy() {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800528 mCallback.asBinder().unlinkToDeath(this, 0);
529 }
530
531 @Override
532 public void binderDied() {
533 stopWatchingActive(mCallback);
534 }
535 }
536
Svet Ganova7a0db62018-02-27 20:08:01 -0800537 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700538
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700539 final class ClientState extends Binder implements DeathRecipient {
Svet Ganovf7b47252018-02-26 11:11:27 -0800540 final ArrayList<Op> mStartedOps = new ArrayList<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700541 final IBinder mAppToken;
542 final int mPid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700543
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700544 ClientState(IBinder appToken) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700545 mAppToken = appToken;
546 mPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -0800547 // Watch only for remote processes dying
548 if (!(appToken instanceof Binder)) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700549 try {
550 mAppToken.linkToDeath(this, 0);
551 } catch (RemoteException e) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800552 /* do nothing */
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700553 }
554 }
555 }
556
557 @Override
558 public String toString() {
559 return "ClientState{" +
560 "mAppToken=" + mAppToken +
Svet Ganovf7b47252018-02-26 11:11:27 -0800561 ", " + "pid=" + mPid +
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700562 '}';
563 }
564
565 @Override
566 public void binderDied() {
567 synchronized (AppOpsService.this) {
568 for (int i=mStartedOps.size()-1; i>=0; i--) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800569 finishOperationLocked(mStartedOps.get(i), /*finishNested*/ true);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700570 }
571 mClients.remove(mAppToken);
572 }
573 }
574 }
575
Jeff Brown6f357d32014-01-15 20:40:55 -0800576 public AppOpsService(File storagePath, Handler handler) {
Jeff Sharkey5f3e9342017-03-13 14:53:11 -0600577 LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
Dianne Hackborne17b4452018-01-10 13:15:40 -0800578 mFile = new AtomicFile(storagePath, "appops");
Jeff Brown6f357d32014-01-15 20:40:55 -0800579 mHandler = handler;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700580 mConstants = new Constants(mHandler);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800581 readState();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800582 }
David Braunf5d83192013-09-16 13:43:51 -0700583
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800584 public void publish(Context context) {
585 mContext = context;
586 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
Dianne Hackbornd5254412018-05-11 18:02:58 -0700587 LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800588 }
589
Dianne Hackborn514074f2013-02-11 10:52:46 -0800590 public void systemReady() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700591 mConstants.startMonitoring(mContext.getContentResolver());
592
Dianne Hackborn514074f2013-02-11 10:52:46 -0800593 synchronized (this) {
594 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700595 for (int i = mUidStates.size() - 1; i >= 0; i--) {
596 UidState uidState = mUidStates.valueAt(i);
597
598 String[] packageNames = getPackagesForUid(uidState.uid);
599 if (ArrayUtils.isEmpty(packageNames)) {
600 uidState.clear();
601 mUidStates.removeAt(i);
602 changed = true;
603 continue;
604 }
605
606 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
607 if (pkgs == null) {
608 continue;
609 }
610
Dianne Hackborn514074f2013-02-11 10:52:46 -0800611 Iterator<Ops> it = pkgs.values().iterator();
612 while (it.hasNext()) {
613 Ops ops = it.next();
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700614 int curUid = -1;
Dianne Hackborn514074f2013-02-11 10:52:46 -0800615 try {
Jeff Sharkeycd654482016-01-08 17:42:11 -0700616 curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
617 PackageManager.MATCH_UNINSTALLED_PACKAGES,
Svet Ganov2af57082015-07-30 08:44:20 -0700618 UserHandle.getUserId(ops.uidState.uid));
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700619 } catch (RemoteException ignored) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800620 }
Svet Ganov2af57082015-07-30 08:44:20 -0700621 if (curUid != ops.uidState.uid) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800622 Slog.i(TAG, "Pruning old package " + ops.packageName
Svet Ganov2af57082015-07-30 08:44:20 -0700623 + "/" + ops.uidState + ": new uid=" + curUid);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800624 it.remove();
625 changed = true;
626 }
627 }
Svet Ganov2af57082015-07-30 08:44:20 -0700628
629 if (uidState.isDefault()) {
630 mUidStates.removeAt(i);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800631 }
632 }
633 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800634 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800635 }
636 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700637
Suprabh Shuklaaef25132017-01-23 18:09:03 -0800638 PackageManagerInternal packageManagerInternal = LocalServices.getService(
639 PackageManagerInternal.class);
640 packageManagerInternal.setExternalSourcesPolicy(
641 new PackageManagerInternal.ExternalSourcesPolicy() {
642 @Override
643 public int getPackageTrustedToInstallApps(String packageName, int uid) {
644 int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
645 uid, packageName);
646 switch (appOpMode) {
647 case AppOpsManager.MODE_ALLOWED:
648 return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
649 case AppOpsManager.MODE_ERRORED:
650 return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
651 default:
652 return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
653 }
654 }
655 });
656
Sudheer Shanka2250d562016-11-07 15:41:02 -0800657 StorageManagerInternal storageManagerInternal = LocalServices.getService(
658 StorageManagerInternal.class);
659 storageManagerInternal.addExternalStoragePolicy(
660 new StorageManagerInternal.ExternalStorageMountPolicy() {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700661 @Override
662 public int getMountMode(int uid, String packageName) {
663 if (Process.isIsolated(uid)) {
664 return Zygote.MOUNT_EXTERNAL_NONE;
665 }
666 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
667 packageName) != AppOpsManager.MODE_ALLOWED) {
668 return Zygote.MOUNT_EXTERNAL_NONE;
669 }
670 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
671 packageName) != AppOpsManager.MODE_ALLOWED) {
672 return Zygote.MOUNT_EXTERNAL_READ;
673 }
674 return Zygote.MOUNT_EXTERNAL_WRITE;
675 }
676
677 @Override
678 public boolean hasExternalStorage(int uid, String packageName) {
679 final int mountMode = getMountMode(uid, packageName);
680 return mountMode == Zygote.MOUNT_EXTERNAL_READ
681 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
682 }
683 });
Dianne Hackborn514074f2013-02-11 10:52:46 -0800684 }
685
686 public void packageRemoved(int uid, String packageName) {
687 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700688 UidState uidState = mUidStates.get(uid);
689 if (uidState == null) {
690 return;
691 }
692
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800693 Ops ops = null;
Svet Ganov2af57082015-07-30 08:44:20 -0700694
695 // Remove any package state if such.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800696 if (uidState.pkgOps != null) {
697 ops = uidState.pkgOps.remove(packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700698 }
699
700 // If we just nuked the last package state check if the UID is valid.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800701 if (ops != null && uidState.pkgOps.isEmpty()
Svet Ganov2af57082015-07-30 08:44:20 -0700702 && getPackagesForUid(uid).length <= 0) {
703 mUidStates.remove(uid);
704 }
705
Svet Ganova7a0db62018-02-27 20:08:01 -0800706 // Finish ops other packages started on behalf of the package.
707 final int clientCount = mClients.size();
708 for (int i = 0; i < clientCount; i++) {
709 final ClientState client = mClients.valueAt(i);
710 if (client.mStartedOps == null) {
711 continue;
712 }
713 final int opCount = client.mStartedOps.size();
714 for (int j = opCount - 1; j >= 0; j--) {
715 final Op op = client.mStartedOps.get(j);
716 if (uid == op.uid && packageName.equals(op.packageName)) {
717 finishOperationLocked(op, /*finishNested*/ true);
718 client.mStartedOps.remove(j);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700719 if (op.startNesting <= 0) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800720 scheduleOpActiveChangedIfNeededLocked(op.op,
721 uid, packageName, false);
722 }
723 }
724 }
725 }
726
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800727 if (ops != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700728 scheduleFastWriteLocked();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800729
730 final int opCount = ops.size();
731 for (int i = 0; i < opCount; i++) {
732 final Op op = ops.valueAt(i);
733 if (op.duration == -1) {
734 scheduleOpActiveChangedIfNeededLocked(
735 op.op, op.uid, op.packageName, false);
736 }
737 }
Dianne Hackborn514074f2013-02-11 10:52:46 -0800738 }
739 }
740 }
741
742 public void uidRemoved(int uid) {
743 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700744 if (mUidStates.indexOfKey(uid) >= 0) {
745 mUidStates.remove(uid);
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800746 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800747 }
748 }
749 }
750
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700751 public void updateUidProcState(int uid, int procState) {
752 synchronized (this) {
753 final UidState uidState = getUidStateLocked(uid, true);
754 final int newState = PROCESS_STATE_TO_UID_STATE[procState];
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700755 if (uidState != null && uidState.pendingState != newState) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700756 final int oldPendingState = uidState.pendingState;
757 uidState.pendingState = newState;
Dianne Hackborne93ab412018-05-14 17:52:30 -0700758 if (newState < uidState.state || newState <= UID_STATE_LAST_NON_RESTRICTED) {
759 // We are moving to a more important state, or the new state is in the
760 // foreground, then always do it immediately.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700761 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700762 } else if (uidState.pendingStateCommitTime == 0) {
763 // We are moving to a less important state for the first time,
764 // delay the application for a bit.
Dianne Hackborne93ab412018-05-14 17:52:30 -0700765 final long settleTime;
766 if (uidState.state <= UID_STATE_TOP) {
767 settleTime = mConstants.TOP_STATE_SETTLE_TIME;
768 } else if (uidState.state <= UID_STATE_FOREGROUND_SERVICE) {
769 settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
770 } else {
771 settleTime = mConstants.BG_STATE_SETTLE_TIME;
772 }
773 uidState.pendingStateCommitTime = SystemClock.uptimeMillis() + settleTime;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700774 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700775 if (uidState.startNesting != 0) {
776 // There is some actively running operation... need to find it
777 // and appropriately update its state.
778 final long now = System.currentTimeMillis();
779 for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
780 final Ops ops = uidState.pkgOps.valueAt(i);
781 for (int j = ops.size() - 1; j >= 0; j--) {
782 final Op op = ops.valueAt(j);
783 if (op.startNesting > 0) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700784 op.time[oldPendingState] = now;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700785 op.time[newState] = now;
786 }
787 }
788 }
789 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700790 }
791 }
792 }
793
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800794 public void shutdown() {
795 Slog.w(TAG, "Writing app ops before shutdown...");
Dianne Hackborn35654b62013-01-14 17:38:02 -0800796 boolean doWrite = false;
797 synchronized (this) {
798 if (mWriteScheduled) {
799 mWriteScheduled = false;
800 doWrite = true;
801 }
802 }
803 if (doWrite) {
804 writeState();
805 }
806 }
807
Dianne Hackborn72e39832013-01-18 18:36:09 -0800808 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
809 ArrayList<AppOpsManager.OpEntry> resOps = null;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700810 final long elapsedNow = SystemClock.elapsedRealtime();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800811 if (ops == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700812 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800813 for (int j=0; j<pkgOps.size(); j++) {
814 Op curOp = pkgOps.valueAt(j);
Amith Yamasania1ce9632018-05-28 20:50:48 -0700815 final boolean running = curOp.duration == -1;
816 long duration = running
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700817 ? (elapsedNow - curOp.startRealtime)
818 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800819 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Amith Yamasania1ce9632018-05-28 20:50:48 -0700820 curOp.rejectTime, (int) duration, running, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700821 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800822 }
823 } else {
824 for (int j=0; j<ops.length; j++) {
825 Op curOp = pkgOps.get(ops[j]);
826 if (curOp != null) {
827 if (resOps == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700828 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800829 }
Amith Yamasania1ce9632018-05-28 20:50:48 -0700830 final boolean running = curOp.duration == -1;
831 final long duration = running
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700832 ? (elapsedNow - curOp.startRealtime)
833 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800834 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Amith Yamasania1ce9632018-05-28 20:50:48 -0700835 curOp.rejectTime, (int) duration, running, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700836 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800837 }
838 }
839 }
840 return resOps;
841 }
842
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700843 private ArrayList<AppOpsManager.OpEntry> collectOps(SparseIntArray uidOps, int[] ops) {
844 ArrayList<AppOpsManager.OpEntry> resOps = null;
845 if (ops == null) {
846 resOps = new ArrayList<>();
847 for (int j=0; j<uidOps.size(); j++) {
848 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(j), uidOps.valueAt(j),
849 0, 0, 0, -1, null));
850 }
851 } else {
852 for (int j=0; j<ops.length; j++) {
853 int index = uidOps.indexOfKey(ops[j]);
854 if (index >= 0) {
855 if (resOps == null) {
856 resOps = new ArrayList<>();
857 }
858 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(index), uidOps.valueAt(index),
859 0, 0, 0, -1, null));
860 }
861 }
862 }
863 return resOps;
864 }
865
Dianne Hackborn35654b62013-01-14 17:38:02 -0800866 @Override
867 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
868 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
869 Binder.getCallingPid(), Binder.getCallingUid(), null);
870 ArrayList<AppOpsManager.PackageOps> res = null;
871 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700872 final int uidStateCount = mUidStates.size();
873 for (int i = 0; i < uidStateCount; i++) {
874 UidState uidState = mUidStates.valueAt(i);
875 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
876 continue;
877 }
878 ArrayMap<String, Ops> packages = uidState.pkgOps;
879 final int packageCount = packages.size();
880 for (int j = 0; j < packageCount; j++) {
881 Ops pkgOps = packages.valueAt(j);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800882 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800883 if (resOps != null) {
884 if (res == null) {
885 res = new ArrayList<AppOpsManager.PackageOps>();
886 }
887 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700888 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800889 res.add(resPackage);
890 }
891 }
892 }
893 }
894 return res;
895 }
896
897 @Override
Dianne Hackborn72e39832013-01-18 18:36:09 -0800898 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
899 int[] ops) {
900 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
901 Binder.getCallingPid(), Binder.getCallingUid(), null);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000902 String resolvedPackageName = resolvePackageName(uid, packageName);
903 if (resolvedPackageName == null) {
904 return Collections.emptyList();
905 }
Dianne Hackborn72e39832013-01-18 18:36:09 -0800906 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -0700907 Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
908 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800909 if (pkgOps == null) {
910 return null;
911 }
912 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
913 if (resOps == null) {
914 return null;
915 }
916 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
917 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700918 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800919 res.add(resPackage);
920 return res;
921 }
922 }
923
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700924 @Override
925 public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
926 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
927 Binder.getCallingPid(), Binder.getCallingUid(), null);
928 synchronized (this) {
929 UidState uidState = getUidStateLocked(uid, false);
930 if (uidState == null) {
931 return null;
932 }
933 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState.opModes, ops);
934 if (resOps == null) {
935 return null;
936 }
937 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
938 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
939 null, uidState.uid, resOps);
940 res.add(resPackage);
941 return res;
942 }
943 }
944
Dianne Hackborn607b4142013-08-02 18:10:10 -0700945 private void pruneOp(Op op, int uid, String packageName) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700946 if (!op.hasAnyTime()) {
Yohei Yukawaa965d652017-10-12 15:02:26 -0700947 Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
948 false /* uidMismatchExpected */);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700949 if (ops != null) {
950 ops.remove(op.op);
951 if (ops.size() <= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -0700952 UidState uidState = ops.uidState;
953 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700954 if (pkgOps != null) {
955 pkgOps.remove(ops.packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700956 if (pkgOps.isEmpty()) {
957 uidState.pkgOps = null;
958 }
959 if (uidState.isDefault()) {
960 mUidStates.remove(uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700961 }
962 }
963 }
964 }
965 }
966 }
967
Dianne Hackbornd5254412018-05-11 18:02:58 -0700968 void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
969 if (callingPid == Process.myPid()) {
970 return;
971 }
972 final int callingUser = UserHandle.getUserId(callingUid);
973 synchronized (this) {
974 if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
975 if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
976 // Profile owners are allowed to change modes but only for apps
977 // within their user.
978 return;
979 }
980 }
981 }
982 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
983 Binder.getCallingPid(), Binder.getCallingUid(), null);
984 }
985
Dianne Hackborn72e39832013-01-18 18:36:09 -0800986 @Override
Svet Ganov2af57082015-07-30 08:44:20 -0700987 public void setUidMode(int code, int uid, int mode) {
Dianne Hackbornd5254412018-05-11 18:02:58 -0700988 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Svet Ganov2af57082015-07-30 08:44:20 -0700989 verifyIncomingOp(code);
990 code = AppOpsManager.opToSwitch(code);
991
992 synchronized (this) {
993 final int defaultMode = AppOpsManager.opToDefaultMode(code);
994
995 UidState uidState = getUidStateLocked(uid, false);
996 if (uidState == null) {
997 if (mode == defaultMode) {
998 return;
999 }
1000 uidState = new UidState(uid);
1001 uidState.opModes = new SparseIntArray();
1002 uidState.opModes.put(code, mode);
1003 mUidStates.put(uid, uidState);
1004 scheduleWriteLocked();
1005 } else if (uidState.opModes == null) {
1006 if (mode != defaultMode) {
1007 uidState.opModes = new SparseIntArray();
1008 uidState.opModes.put(code, mode);
1009 scheduleWriteLocked();
1010 }
1011 } else {
1012 if (uidState.opModes.get(code) == mode) {
1013 return;
1014 }
1015 if (mode == defaultMode) {
1016 uidState.opModes.delete(code);
1017 if (uidState.opModes.size() <= 0) {
1018 uidState.opModes = null;
1019 }
1020 } else {
1021 uidState.opModes.put(code, mode);
1022 }
1023 scheduleWriteLocked();
1024 }
1025 }
1026
Svetoslav215b44a2015-08-04 19:03:40 -07001027 String[] uidPackageNames = getPackagesForUid(uid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001028 ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
Svet Ganov2af57082015-07-30 08:44:20 -07001029
riddle_hsu40b300f2015-11-23 13:22:03 +08001030 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001031 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001032 if (callbacks != null) {
Svet Ganov2af57082015-07-30 08:44:20 -07001033 final int callbackCount = callbacks.size();
1034 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001035 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08001036 ArraySet<String> changedPackages = new ArraySet<>();
1037 Collections.addAll(changedPackages, uidPackageNames);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001038 if (callbackSpecs == null) {
1039 callbackSpecs = new ArrayMap<>();
1040 }
riddle_hsu40b300f2015-11-23 13:22:03 +08001041 callbackSpecs.put(callback, changedPackages);
1042 }
1043 }
1044
1045 for (String uidPackageName : uidPackageNames) {
1046 callbacks = mPackageModeWatchers.get(uidPackageName);
1047 if (callbacks != null) {
1048 if (callbackSpecs == null) {
1049 callbackSpecs = new ArrayMap<>();
Svet Ganov2af57082015-07-30 08:44:20 -07001050 }
riddle_hsu40b300f2015-11-23 13:22:03 +08001051 final int callbackCount = callbacks.size();
1052 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001053 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08001054 ArraySet<String> changedPackages = callbackSpecs.get(callback);
1055 if (changedPackages == null) {
1056 changedPackages = new ArraySet<>();
1057 callbackSpecs.put(callback, changedPackages);
1058 }
1059 changedPackages.add(uidPackageName);
1060 }
Svet Ganov2af57082015-07-30 08:44:20 -07001061 }
1062 }
1063 }
1064
1065 if (callbackSpecs == null) {
1066 return;
1067 }
1068
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001069 for (int i = 0; i < callbackSpecs.size(); i++) {
1070 final ModeCallback callback = callbackSpecs.keyAt(i);
1071 final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
1072 if (reportedPackageNames == null) {
1073 mHandler.sendMessage(PooledLambda.obtainMessage(
1074 AppOpsService::notifyOpChanged,
1075 this, callback, code, uid, (String) null));
1076
1077 } else {
1078 final int reportedPackageCount = reportedPackageNames.size();
1079 for (int j = 0; j < reportedPackageCount; j++) {
1080 final String reportedPackageName = reportedPackageNames.valueAt(j);
1081 mHandler.sendMessage(PooledLambda.obtainMessage(
1082 AppOpsService::notifyOpChanged,
1083 this, callback, code, uid, reportedPackageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001084 }
1085 }
Svet Ganov2af57082015-07-30 08:44:20 -07001086 }
1087 }
1088
1089 @Override
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001090 public void setMode(int code, int uid, String packageName, int mode) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001091 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001092 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001093 ArraySet<ModeCallback> repCbs = null;
Dianne Hackbornc2293022013-02-06 23:14:49 -08001094 code = AppOpsManager.opToSwitch(code);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001095 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001096 UidState uidState = getUidStateLocked(uid, false);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001097 Op op = getOpLocked(code, uid, packageName, true);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001098 if (op != null) {
1099 if (op.mode != mode) {
1100 op.mode = mode;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001101 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001102 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001103 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001104 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001105 if (cbs != null) {
1106 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001107 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001108 }
1109 repCbs.addAll(cbs);
1110 }
1111 cbs = mPackageModeWatchers.get(packageName);
1112 if (cbs != null) {
1113 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001114 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001115 }
1116 repCbs.addAll(cbs);
1117 }
David Braunf5d83192013-09-16 13:43:51 -07001118 if (mode == AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001119 // If going into the default mode, prune this op
1120 // if there is nothing else interesting in it.
Dianne Hackborn607b4142013-08-02 18:10:10 -07001121 pruneOp(op, uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001122 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001123 scheduleFastWriteLocked();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001124 }
1125 }
1126 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001127 if (repCbs != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001128 mHandler.sendMessage(PooledLambda.obtainMessage(
1129 AppOpsService::notifyOpChanged,
1130 this, repCbs, code, uid, packageName));
Dianne Hackbornc2293022013-02-06 23:14:49 -08001131 }
1132 }
1133
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001134 private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
1135 int uid, String packageName) {
1136 for (int i = 0; i < callbacks.size(); i++) {
1137 final ModeCallback callback = callbacks.valueAt(i);
1138 notifyOpChanged(callback, code, uid, packageName);
1139 }
1140 }
1141
1142 private void notifyOpChanged(ModeCallback callback, int code,
1143 int uid, String packageName) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001144 if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001145 return;
1146 }
1147 // There are components watching for mode changes such as window manager
1148 // and location manager which are in our process. The callbacks in these
1149 // components may require permissions our remote caller does not have.
1150 final long identity = Binder.clearCallingIdentity();
1151 try {
1152 callback.mCallback.opChanged(code, uid, packageName);
1153 } catch (RemoteException e) {
1154 /* ignore */
1155 } finally {
1156 Binder.restoreCallingIdentity(identity);
1157 }
1158 }
1159
1160 private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
1161 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
1162 int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001163 if (cbs == null) {
1164 return callbacks;
1165 }
1166 if (callbacks == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001167 callbacks = new HashMap<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001168 }
Svet Ganov2af57082015-07-30 08:44:20 -07001169 boolean duplicate = false;
Dianne Hackborn68d76552017-02-27 15:32:03 -08001170 final int N = cbs.size();
1171 for (int i=0; i<N; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001172 ModeCallback cb = cbs.valueAt(i);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001173 ArrayList<ChangeRec> reports = callbacks.get(cb);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001174 if (reports == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001175 reports = new ArrayList<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001176 callbacks.put(cb, reports);
Svet Ganov2af57082015-07-30 08:44:20 -07001177 } else {
1178 final int reportCount = reports.size();
1179 for (int j = 0; j < reportCount; j++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001180 ChangeRec report = reports.get(j);
1181 if (report.op == op && report.pkg.equals(packageName)) {
Svet Ganov2af57082015-07-30 08:44:20 -07001182 duplicate = true;
1183 break;
1184 }
1185 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001186 }
Svet Ganov2af57082015-07-30 08:44:20 -07001187 if (!duplicate) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001188 reports.add(new ChangeRec(op, uid, packageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001189 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001190 }
1191 return callbacks;
1192 }
1193
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001194 static final class ChangeRec {
1195 final int op;
1196 final int uid;
1197 final String pkg;
1198
1199 ChangeRec(int _op, int _uid, String _pkg) {
1200 op = _op;
1201 uid = _uid;
1202 pkg = _pkg;
1203 }
1204 }
1205
Dianne Hackborn607b4142013-08-02 18:10:10 -07001206 @Override
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001207 public void resetAllModes(int reqUserId, String reqPackageName) {
1208 final int callingPid = Binder.getCallingPid();
1209 final int callingUid = Binder.getCallingUid();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001210 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
1211 true, true, "resetAllModes", null);
Svet Ganov2af57082015-07-30 08:44:20 -07001212
1213 int reqUid = -1;
1214 if (reqPackageName != null) {
1215 try {
1216 reqUid = AppGlobals.getPackageManager().getPackageUid(
Jeff Sharkeycd654482016-01-08 17:42:11 -07001217 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
Svet Ganov2af57082015-07-30 08:44:20 -07001218 } catch (RemoteException e) {
1219 /* ignore - local call */
1220 }
1221 }
1222
Dianne Hackbornd5254412018-05-11 18:02:58 -07001223 enforceManageAppOpsModes(callingPid, callingUid, reqUid);
1224
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001225 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001226 synchronized (this) {
1227 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -07001228 for (int i = mUidStates.size() - 1; i >= 0; i--) {
1229 UidState uidState = mUidStates.valueAt(i);
1230
1231 SparseIntArray opModes = uidState.opModes;
1232 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
1233 final int uidOpCount = opModes.size();
1234 for (int j = uidOpCount - 1; j >= 0; j--) {
1235 final int code = opModes.keyAt(j);
1236 if (AppOpsManager.opAllowsReset(code)) {
1237 opModes.removeAt(j);
1238 if (opModes.size() <= 0) {
1239 uidState.opModes = null;
1240 }
1241 for (String packageName : getPackagesForUid(uidState.uid)) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001242 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001243 mOpModeWatchers.get(code));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001244 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001245 mPackageModeWatchers.get(packageName));
1246 }
1247 }
1248 }
1249 }
1250
1251 if (uidState.pkgOps == null) {
1252 continue;
1253 }
1254
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001255 if (reqUserId != UserHandle.USER_ALL
Svet Ganov2af57082015-07-30 08:44:20 -07001256 && reqUserId != UserHandle.getUserId(uidState.uid)) {
Alexandra Gherghinad6a98972014-08-04 17:05:34 +01001257 // Skip any ops for a different user
1258 continue;
1259 }
Svet Ganov2af57082015-07-30 08:44:20 -07001260
1261 Map<String, Ops> packages = uidState.pkgOps;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001262 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001263 boolean uidChanged = false;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001264 while (it.hasNext()) {
1265 Map.Entry<String, Ops> ent = it.next();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001266 String packageName = ent.getKey();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001267 if (reqPackageName != null && !reqPackageName.equals(packageName)) {
1268 // Skip any ops for a different package
1269 continue;
1270 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001271 Ops pkgOps = ent.getValue();
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001272 for (int j=pkgOps.size()-1; j>=0; j--) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001273 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn8828d3a2013-09-25 16:47:10 -07001274 if (AppOpsManager.opAllowsReset(curOp.op)
1275 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
David Braunf5d83192013-09-16 13:43:51 -07001276 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001277 changed = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001278 uidChanged = true;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001279 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001280 mOpModeWatchers.get(curOp.op));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001281 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001282 mPackageModeWatchers.get(packageName));
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001283 if (!curOp.hasAnyTime()) {
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001284 pkgOps.removeAt(j);
1285 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001286 }
1287 }
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001288 if (pkgOps.size() == 0) {
1289 it.remove();
1290 }
1291 }
Svet Ganov2af57082015-07-30 08:44:20 -07001292 if (uidState.isDefault()) {
1293 mUidStates.remove(uidState.uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001294 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001295 if (uidChanged) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001296 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001297 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001298 }
Svet Ganov2af57082015-07-30 08:44:20 -07001299
Dianne Hackborn607b4142013-08-02 18:10:10 -07001300 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001301 scheduleFastWriteLocked();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001302 }
1303 }
1304 if (callbacks != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001305 for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
1306 ModeCallback cb = ent.getKey();
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001307 ArrayList<ChangeRec> reports = ent.getValue();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001308 for (int i=0; i<reports.size(); i++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001309 ChangeRec rep = reports.get(i);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001310 mHandler.sendMessage(PooledLambda.obtainMessage(
1311 AppOpsService::notifyOpChanged,
1312 this, cb, rep.op, rep.uid, rep.pkg));
Dianne Hackborn607b4142013-08-02 18:10:10 -07001313 }
1314 }
1315 }
1316 }
1317
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001318 private void evalAllForegroundOpsLocked() {
1319 for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
1320 final UidState uidState = mUidStates.valueAt(uidi);
1321 if (uidState.foregroundOps != null) {
1322 uidState.evalForegroundOps(mOpModeWatchers);
1323 }
1324 }
1325 }
1326
Dianne Hackbornc2293022013-02-06 23:14:49 -08001327 @Override
1328 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001329 startWatchingModeWithFlags(op, packageName, 0, callback);
1330 }
1331
1332 @Override
1333 public void startWatchingModeWithFlags(int op, String packageName, int flags,
1334 IAppOpsCallback callback) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001335 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001336 final int callingUid = Binder.getCallingUid();
1337 final int callingPid = Binder.getCallingPid();
Dianne Hackborn5376edd2018-06-05 13:21:16 -07001338 // TODO: should have a privileged permission to protect this.
1339 // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require
1340 // the USAGE_STATS permission since this can provide information about when an
1341 // app is in the foreground?
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001342 Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
1343 AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001344 if (callback == null) {
1345 return;
1346 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001347 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001348 op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001349 ModeCallback cb = mModeWatchers.get(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001350 if (cb == null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001351 cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001352 mModeWatchers.put(callback.asBinder(), cb);
1353 }
1354 if (op != AppOpsManager.OP_NONE) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001355 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001356 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001357 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001358 mOpModeWatchers.put(op, cbs);
1359 }
1360 cbs.add(cb);
1361 }
1362 if (packageName != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001363 ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001364 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001365 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001366 mPackageModeWatchers.put(packageName, cbs);
1367 }
1368 cbs.add(cb);
1369 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001370 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001371 }
1372 }
1373
1374 @Override
1375 public void stopWatchingMode(IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001376 if (callback == null) {
1377 return;
1378 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001379 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001380 ModeCallback cb = mModeWatchers.remove(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001381 if (cb != null) {
1382 cb.unlinkToDeath();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001383 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001384 ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001385 cbs.remove(cb);
1386 if (cbs.size() <= 0) {
1387 mOpModeWatchers.removeAt(i);
1388 }
1389 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001390 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001391 ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001392 cbs.remove(cb);
1393 if (cbs.size() <= 0) {
1394 mPackageModeWatchers.removeAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001395 }
1396 }
1397 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001398 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001399 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001400 }
1401
1402 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001403 public IBinder getToken(IBinder clientToken) {
1404 synchronized (this) {
1405 ClientState cs = mClients.get(clientToken);
1406 if (cs == null) {
1407 cs = new ClientState(clientToken);
1408 mClients.put(clientToken, cs);
1409 }
1410 return cs;
1411 }
1412 }
1413
1414 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -08001415 public int checkOperation(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001416 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001417 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001418 String resolvedPackageName = resolvePackageName(uid, packageName);
1419 if (resolvedPackageName == null) {
1420 return AppOpsManager.MODE_IGNORED;
1421 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001422 synchronized (this) {
Svet Ganov442ed572016-08-17 17:29:43 -07001423 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001424 return AppOpsManager.MODE_IGNORED;
1425 }
Svet Ganov2af57082015-07-30 08:44:20 -07001426 code = AppOpsManager.opToSwitch(code);
1427 UidState uidState = getUidStateLocked(uid, false);
Svet Ganovee438d42017-01-19 18:04:38 -08001428 if (uidState != null && uidState.opModes != null
1429 && uidState.opModes.indexOfKey(code) >= 0) {
1430 return uidState.opModes.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001431 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001432 Op op = getOpLocked(code, uid, resolvedPackageName, false);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001433 if (op == null) {
David Braunf5d83192013-09-16 13:43:51 -07001434 return AppOpsManager.opToDefaultMode(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001435 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001436 return op.mode;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001437 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001438 }
1439
1440 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001441 public int checkAudioOperation(int code, int usage, int uid, String packageName) {
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00001442 boolean suspended;
1443 try {
1444 suspended = isPackageSuspendedForUser(packageName, uid);
1445 } catch (IllegalArgumentException ex) {
1446 // Package not found.
1447 suspended = false;
1448 }
1449
1450 if (suspended) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001451 Slog.i(TAG, "Audio disabled for suspended package=" + packageName + " for uid=" + uid);
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001452 return AppOpsManager.MODE_IGNORED;
1453 }
1454
John Spurlock1af30c72014-03-10 08:33:35 -04001455 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001456 final int mode = checkRestrictionLocked(code, usage, uid, packageName);
John Spurlock1af30c72014-03-10 08:33:35 -04001457 if (mode != AppOpsManager.MODE_ALLOWED) {
1458 return mode;
1459 }
1460 }
1461 return checkOperation(code, uid, packageName);
1462 }
1463
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001464 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001465 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001466 return AppGlobals.getPackageManager().isPackageSuspendedForUser(
1467 pkg, UserHandle.getUserId(uid));
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001468 } catch (RemoteException re) {
1469 throw new SecurityException("Could not talk to package manager service");
1470 }
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001471 }
1472
John Spurlock7b414672014-07-18 13:02:39 -04001473 private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
1474 final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1475 if (usageRestrictions != null) {
1476 final Restriction r = usageRestrictions.get(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001477 if (r != null && !r.exceptionPackages.contains(packageName)) {
1478 return r.mode;
1479 }
1480 }
1481 return AppOpsManager.MODE_ALLOWED;
1482 }
1483
1484 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001485 public void setAudioRestriction(int code, int usage, int uid, int mode,
John Spurlock1af30c72014-03-10 08:33:35 -04001486 String[] exceptionPackages) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001487 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
John Spurlock1af30c72014-03-10 08:33:35 -04001488 verifyIncomingUid(uid);
1489 verifyIncomingOp(code);
1490 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001491 SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1492 if (usageRestrictions == null) {
1493 usageRestrictions = new SparseArray<Restriction>();
1494 mAudioRestrictions.put(code, usageRestrictions);
John Spurlock1af30c72014-03-10 08:33:35 -04001495 }
John Spurlock7b414672014-07-18 13:02:39 -04001496 usageRestrictions.remove(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001497 if (mode != AppOpsManager.MODE_ALLOWED) {
1498 final Restriction r = new Restriction();
1499 r.mode = mode;
1500 if (exceptionPackages != null) {
1501 final int N = exceptionPackages.length;
1502 r.exceptionPackages = new ArraySet<String>(N);
1503 for (int i = 0; i < N; i++) {
1504 final String pkg = exceptionPackages[i];
1505 if (pkg != null) {
1506 r.exceptionPackages.add(pkg.trim());
1507 }
1508 }
1509 }
John Spurlock7b414672014-07-18 13:02:39 -04001510 usageRestrictions.put(usage, r);
John Spurlock1af30c72014-03-10 08:33:35 -04001511 }
1512 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001513
1514 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07001515 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
John Spurlock1af30c72014-03-10 08:33:35 -04001516 }
1517
1518 @Override
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001519 public int checkPackage(int uid, String packageName) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001520 Preconditions.checkNotNull(packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001521 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001522 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
1523 true /* uidMismatchExpected */);
1524 if (ops != null) {
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001525 return AppOpsManager.MODE_ALLOWED;
1526 } else {
1527 return AppOpsManager.MODE_ERRORED;
1528 }
1529 }
1530 }
1531
1532 @Override
Svet Ganov99b60432015-06-27 13:15:22 -07001533 public int noteProxyOperation(int code, String proxyPackageName,
1534 int proxiedUid, String proxiedPackageName) {
1535 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001536 final int proxyUid = Binder.getCallingUid();
1537 String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
1538 if (resolveProxyPackageName == null) {
1539 return AppOpsManager.MODE_IGNORED;
1540 }
1541 final int proxyMode = noteOperationUnchecked(code, proxyUid,
1542 resolveProxyPackageName, -1, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001543 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
1544 return proxyMode;
1545 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001546 String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
1547 if (resolveProxiedPackageName == null) {
1548 return AppOpsManager.MODE_IGNORED;
1549 }
1550 return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
1551 proxyMode, resolveProxyPackageName);
Svet Ganov99b60432015-06-27 13:15:22 -07001552 }
1553
1554 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001555 public int noteOperation(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001556 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001557 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001558 String resolvedPackageName = resolvePackageName(uid, packageName);
1559 if (resolvedPackageName == null) {
1560 return AppOpsManager.MODE_IGNORED;
1561 }
1562 return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001563 }
1564
1565 private int noteOperationUnchecked(int code, int uid, String packageName,
1566 int proxyUid, String proxyPackageName) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001567 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001568 final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001569 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001570 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001571 if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001572 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001573 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001574 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001575 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001576 if (isOpRestrictedLocked(uid, code, packageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001577 return AppOpsManager.MODE_IGNORED;
1578 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001579 final UidState uidState = ops.uidState;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001580 if (op.duration == -1) {
1581 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001582 + " code " + code + " time=" + op.time[uidState.state]
1583 + " duration=" + op.duration);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001584 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001585 op.duration = 0;
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001586 final int switchCode = AppOpsManager.opToSwitch(code);
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001587 // If there is a non-default per UID policy (we set UID op mode only if
1588 // non-default) it takes over, otherwise use the per package policy.
1589 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001590 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganov2af57082015-07-30 08:44:20 -07001591 if (uidMode != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001592 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001593 + switchCode + " (" + code + ") uid " + uid + " package "
1594 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001595 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov2af57082015-07-30 08:44:20 -07001596 return uidMode;
1597 }
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001598 } else {
1599 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001600 final int mode = switchOp.getMode();
1601 if (mode != AppOpsManager.MODE_ALLOWED) {
1602 if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001603 + switchCode + " (" + code + ") uid " + uid + " package "
1604 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001605 op.rejectTime[uidState.state] = System.currentTimeMillis();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001606 return mode;
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001607 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001608 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001609 if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001610 + " package " + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001611 op.time[uidState.state] = System.currentTimeMillis();
1612 op.rejectTime[uidState.state] = 0;
Svet Ganov99b60432015-06-27 13:15:22 -07001613 op.proxyUid = proxyUid;
1614 op.proxyPackageName = proxyPackageName;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001615 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001616 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001617 }
1618
1619 @Override
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001620 public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001621 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001622 final int callingUid = Binder.getCallingUid();
1623 final int callingPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -08001624 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1625 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001626 watchedUid = callingUid;
Svet Ganovf7b47252018-02-26 11:11:27 -08001627 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001628 if (ops != null) {
1629 Preconditions.checkArrayElementsInRange(ops, 0,
1630 AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
1631 }
1632 if (callback == null) {
1633 return;
1634 }
1635 synchronized (this) {
1636 SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
1637 if (callbacks == null) {
1638 callbacks = new SparseArray<>();
1639 mActiveWatchers.put(callback.asBinder(), callbacks);
1640 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001641 final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
1642 callingUid, callingPid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001643 for (int op : ops) {
1644 callbacks.put(op, activeCallback);
1645 }
1646 }
1647 }
1648
1649 @Override
1650 public void stopWatchingActive(IAppOpsActiveCallback callback) {
1651 if (callback == null) {
1652 return;
1653 }
1654 synchronized (this) {
1655 final SparseArray<ActiveCallback> activeCallbacks =
1656 mActiveWatchers.remove(callback.asBinder());
1657 if (activeCallbacks == null) {
1658 return;
1659 }
1660 final int callbackCount = activeCallbacks.size();
1661 for (int i = 0; i < callbackCount; i++) {
1662 // Apps ops are mapped to a singleton
1663 if (i == 0) {
1664 activeCallbacks.valueAt(i).destroy();
1665 }
1666 }
1667 }
1668 }
1669
1670 @Override
Svet Ganovf7b47252018-02-26 11:11:27 -08001671 public int startOperation(IBinder token, int code, int uid, String packageName,
1672 boolean startIfModeDefault) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001673 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001674 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001675 String resolvedPackageName = resolvePackageName(uid, packageName);
1676 if (resolvedPackageName == null) {
1677 return AppOpsManager.MODE_IGNORED;
1678 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001679 ClientState client = (ClientState)token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001680 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001681 final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001682 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001683 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001684 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001685 + " package " + resolvedPackageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001686 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001687 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001688 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001689 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001690 return AppOpsManager.MODE_IGNORED;
1691 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001692 final int switchCode = AppOpsManager.opToSwitch(code);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001693 final UidState uidState = ops.uidState;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001694 // If there is a non-default per UID policy (we set UID op mode only if
1695 // non-default) it takes over, otherwise use the per package policy.
1696 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001697 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganovf7b47252018-02-26 11:11:27 -08001698 if (uidMode != AppOpsManager.MODE_ALLOWED
1699 && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001700 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001701 + switchCode + " (" + code + ") uid " + uid + " package "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001702 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001703 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov2af57082015-07-30 08:44:20 -07001704 return uidMode;
1705 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001706 } else {
1707 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001708 final int mode = switchOp.getMode();
1709 if (mode != AppOpsManager.MODE_ALLOWED
1710 && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
1711 if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001712 + switchCode + " (" + code + ") uid " + uid + " package "
1713 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001714 op.rejectTime[uidState.state] = System.currentTimeMillis();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001715 return mode;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001716 }
Svet Ganov2af57082015-07-30 08:44:20 -07001717 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001718 if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001719 + " package " + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001720 if (op.startNesting == 0) {
1721 op.startRealtime = SystemClock.elapsedRealtime();
1722 op.time[uidState.state] = System.currentTimeMillis();
1723 op.rejectTime[uidState.state] = 0;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001724 op.duration = -1;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001725 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001726 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001727 op.startNesting++;
1728 uidState.startNesting++;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001729 if (client.mStartedOps != null) {
1730 client.mStartedOps.add(op);
1731 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001732 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001733
1734 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001735 }
1736
1737 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001738 public void finishOperation(IBinder token, int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001739 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001740 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001741 String resolvedPackageName = resolvePackageName(uid, packageName);
1742 if (resolvedPackageName == null) {
1743 return;
1744 }
1745 if (!(token instanceof ClientState)) {
1746 return;
1747 }
1748 ClientState client = (ClientState) token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001749 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001750 Op op = getOpLocked(code, uid, resolvedPackageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001751 if (op == null) {
1752 return;
1753 }
Svet Ganovf7b47252018-02-26 11:11:27 -08001754 if (!client.mStartedOps.remove(op)) {
Svet Ganovf5d5af12018-03-18 11:51:17 -07001755 // We finish ops when packages get removed to guarantee no dangling
1756 // started ops. However, some part of the system may asynchronously
1757 // finish ops for an already gone package. Hence, finishing an op
1758 // for a non existing package is fine and we don't log as a wtf.
1759 final long identity = Binder.clearCallingIdentity();
1760 try {
1761 if (LocalServices.getService(PackageManagerInternal.class).getPackageUid(
1762 resolvedPackageName, 0, UserHandle.getUserId(uid)) < 0) {
1763 Slog.i(TAG, "Finishing op=" + AppOpsManager.opToName(code)
1764 + " for non-existing package=" + resolvedPackageName
1765 + " in uid=" + uid);
1766 return;
1767 }
1768 } finally {
1769 Binder.restoreCallingIdentity(identity);
1770 }
1771 Slog.wtf(TAG, "Operation not started: uid=" + op.uid + " pkg="
1772 + op.packageName + " op=" + AppOpsManager.opToName(op.op));
Svet Ganov31d83ae2018-03-15 10:45:56 -07001773 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001774 }
Svet Ganova7a0db62018-02-27 20:08:01 -08001775 finishOperationLocked(op, /*finishNested*/ false);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001776 if (op.startNesting <= 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001777 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
1778 }
1779 }
1780 }
1781
1782 private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
1783 boolean active) {
1784 ArraySet<ActiveCallback> dispatchedCallbacks = null;
1785 final int callbackListCount = mActiveWatchers.size();
1786 for (int i = 0; i < callbackListCount; i++) {
1787 final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
1788 ActiveCallback callback = callbacks.get(code);
1789 if (callback != null) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001790 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001791 continue;
1792 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001793 if (dispatchedCallbacks == null) {
1794 dispatchedCallbacks = new ArraySet<>();
1795 }
1796 dispatchedCallbacks.add(callback);
1797 }
1798 }
1799 if (dispatchedCallbacks == null) {
1800 return;
1801 }
1802 mHandler.sendMessage(PooledLambda.obtainMessage(
1803 AppOpsService::notifyOpActiveChanged,
1804 this, dispatchedCallbacks, code, uid, packageName, active));
1805 }
1806
1807 private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
1808 int code, int uid, String packageName, boolean active) {
1809 // There are components watching for mode changes such as window manager
1810 // and location manager which are in our process. The callbacks in these
1811 // components may require permissions our remote caller does not have.
1812 final long identity = Binder.clearCallingIdentity();
1813 try {
1814 final int callbackCount = callbacks.size();
1815 for (int i = 0; i < callbackCount; i++) {
1816 final ActiveCallback callback = callbacks.valueAt(i);
1817 try {
1818 callback.mCallback.opActiveChanged(code, uid, packageName, active);
1819 } catch (RemoteException e) {
1820 /* do nothing */
1821 }
1822 }
1823 } finally {
1824 Binder.restoreCallingIdentity(identity);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001825 }
1826 }
1827
Svet Ganovb9d71a62015-04-30 10:38:13 -07001828 @Override
1829 public int permissionToOpCode(String permission) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001830 if (permission == null) {
1831 return AppOpsManager.OP_NONE;
1832 }
Svet Ganovb9d71a62015-04-30 10:38:13 -07001833 return AppOpsManager.permissionToOpCode(permission);
1834 }
1835
Svet Ganova7a0db62018-02-27 20:08:01 -08001836 void finishOperationLocked(Op op, boolean finishNested) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001837 if (op.startNesting <= 1 || finishNested) {
1838 if (op.startNesting == 1 || finishNested) {
1839 op.duration = (int)(SystemClock.elapsedRealtime() - op.startRealtime);
1840 op.time[op.uidState.state] = System.currentTimeMillis();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001841 } else {
1842 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
1843 + op.packageName + " code " + op.op + " time=" + op.time
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001844 + " duration=" + op.duration + " nesting=" + op.startNesting);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001845 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001846 if (op.startNesting >= 1) {
1847 op.uidState.startNesting -= op.startNesting;
1848 }
1849 op.startNesting = 0;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001850 } else {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001851 op.startNesting--;
1852 op.uidState.startNesting--;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001853 }
1854 }
1855
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001856 private void verifyIncomingUid(int uid) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001857 if (uid == Binder.getCallingUid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001858 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001859 }
1860 if (Binder.getCallingPid() == Process.myPid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001861 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001862 }
1863 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
1864 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001865 }
1866
Dianne Hackborn961321f2013-02-05 17:22:41 -08001867 private void verifyIncomingOp(int op) {
1868 if (op >= 0 && op < AppOpsManager._NUM_OP) {
1869 return;
1870 }
1871 throw new IllegalArgumentException("Bad operation #" + op);
1872 }
1873
Svet Ganov2af57082015-07-30 08:44:20 -07001874 private UidState getUidStateLocked(int uid, boolean edit) {
1875 UidState uidState = mUidStates.get(uid);
1876 if (uidState == null) {
1877 if (!edit) {
1878 return null;
1879 }
1880 uidState = new UidState(uid);
1881 mUidStates.put(uid, uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001882 } else {
1883 if (uidState.pendingStateCommitTime != 0) {
1884 if (uidState.pendingStateCommitTime < mLastUptime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001885 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001886 } else {
1887 mLastUptime = SystemClock.uptimeMillis();
1888 if (uidState.pendingStateCommitTime < mLastUptime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001889 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001890 }
1891 }
1892 }
Svet Ganov2af57082015-07-30 08:44:20 -07001893 }
1894 return uidState;
1895 }
1896
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001897 private void commitUidPendingStateLocked(UidState uidState) {
Dianne Hackborne93ab412018-05-14 17:52:30 -07001898 final boolean lastForeground = uidState.state <= UID_STATE_LAST_NON_RESTRICTED;
1899 final boolean nowForeground = uidState.pendingState <= UID_STATE_LAST_NON_RESTRICTED;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001900 uidState.state = uidState.pendingState;
1901 uidState.pendingStateCommitTime = 0;
Dianne Hackborne93ab412018-05-14 17:52:30 -07001902 if (uidState.hasForegroundWatchers && lastForeground != nowForeground) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001903 for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
1904 if (!uidState.foregroundOps.valueAt(fgi)) {
1905 continue;
1906 }
1907 final int code = uidState.foregroundOps.keyAt(fgi);
1908
1909 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
1910 if (callbacks != null) {
1911 for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
1912 final ModeCallback callback = callbacks.valueAt(cbi);
1913 if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
1914 || !callback.isWatchingUid(uidState.uid)) {
1915 continue;
1916 }
1917 boolean doAllPackages = uidState.opModes != null
1918 && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
1919 if (uidState.pkgOps != null) {
1920 for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
1921 final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
1922 if (doAllPackages || (op != null
1923 && op.mode == AppOpsManager.MODE_FOREGROUND)) {
1924 mHandler.sendMessage(PooledLambda.obtainMessage(
1925 AppOpsService::notifyOpChanged,
1926 this, callback, code, uidState.uid,
1927 uidState.pkgOps.keyAt(pkgi)));
1928 }
1929 }
1930 }
1931 }
1932 }
1933 }
1934 }
1935 }
1936
Yohei Yukawaa965d652017-10-12 15:02:26 -07001937 private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
1938 boolean uidMismatchExpected) {
Svet Ganov2af57082015-07-30 08:44:20 -07001939 UidState uidState = getUidStateLocked(uid, edit);
1940 if (uidState == null) {
1941 return null;
1942 }
1943
1944 if (uidState.pkgOps == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001945 if (!edit) {
1946 return null;
1947 }
Svet Ganov2af57082015-07-30 08:44:20 -07001948 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001949 }
Svet Ganov2af57082015-07-30 08:44:20 -07001950
1951 Ops ops = uidState.pkgOps.get(packageName);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001952 if (ops == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001953 if (!edit) {
1954 return null;
1955 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001956 boolean isPrivileged = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001957 // This is the first time we have seen this package name under this uid,
1958 // so let's make sure it is valid.
Dianne Hackborn514074f2013-02-11 10:52:46 -08001959 if (uid != 0) {
1960 final long ident = Binder.clearCallingIdentity();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001961 try {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001962 int pkgUid = -1;
1963 try {
Jason Monk1c7c3192014-06-26 12:52:18 -04001964 ApplicationInfo appInfo = ActivityThread.getPackageManager()
Jeff Sharkeycd654482016-01-08 17:42:11 -07001965 .getApplicationInfo(packageName,
1966 PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
1967 UserHandle.getUserId(uid));
Jason Monk1c7c3192014-06-26 12:52:18 -04001968 if (appInfo != null) {
1969 pkgUid = appInfo.uid;
Alex Klyubinb9f8a522015-02-03 11:12:59 -08001970 isPrivileged = (appInfo.privateFlags
1971 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04001972 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08001973 pkgUid = resolveUid(packageName);
1974 if (pkgUid >= 0) {
Chien-Yu Chen75cade02016-01-11 10:56:21 -08001975 isPrivileged = false;
Jason Monk1c7c3192014-06-26 12:52:18 -04001976 }
Dianne Hackborn713df152013-05-17 11:27:57 -07001977 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001978 } catch (RemoteException e) {
1979 Slog.w(TAG, "Could not contact PackageManager", e);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001980 }
1981 if (pkgUid != uid) {
1982 // Oops! The package name is not valid for the uid they are calling
1983 // under. Abort.
Yohei Yukawaa965d652017-10-12 15:02:26 -07001984 if (!uidMismatchExpected) {
1985 RuntimeException ex = new RuntimeException("here");
1986 ex.fillInStackTrace();
1987 Slog.w(TAG, "Bad call: specified package " + packageName
1988 + " under uid " + uid + " but it is really " + pkgUid, ex);
1989 }
Dianne Hackborn514074f2013-02-11 10:52:46 -08001990 return null;
1991 }
1992 } finally {
1993 Binder.restoreCallingIdentity(ident);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001994 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001995 }
Svet Ganov2af57082015-07-30 08:44:20 -07001996 ops = new Ops(packageName, uidState, isPrivileged);
1997 uidState.pkgOps.put(packageName, ops);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001998 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08001999 return ops;
2000 }
2001
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002002 private void scheduleWriteLocked() {
2003 if (!mWriteScheduled) {
2004 mWriteScheduled = true;
2005 mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
2006 }
2007 }
2008
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002009 private void scheduleFastWriteLocked() {
2010 if (!mFastWriteScheduled) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002011 mWriteScheduled = true;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002012 mFastWriteScheduled = true;
2013 mHandler.removeCallbacks(mWriteRunner);
2014 mHandler.postDelayed(mWriteRunner, 10*1000);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002015 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002016 }
2017
Dianne Hackborn72e39832013-01-18 18:36:09 -08002018 private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002019 Ops ops = getOpsRawLocked(uid, packageName, edit,
2020 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -08002021 if (ops == null) {
2022 return null;
2023 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002024 return getOpLocked(ops, code, edit);
2025 }
2026
2027 private Op getOpLocked(Ops ops, int code, boolean edit) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002028 Op op = ops.get(code);
2029 if (op == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002030 if (!edit) {
2031 return null;
2032 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002033 op = new Op(ops.uidState, ops.packageName, code);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002034 ops.put(code, op);
2035 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002036 if (edit) {
2037 scheduleWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002038 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002039 return op;
2040 }
2041
Svet Ganov442ed572016-08-17 17:29:43 -07002042 private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
Jason Monk62062992014-05-06 09:55:28 -04002043 int userHandle = UserHandle.getUserId(uid);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002044 final int restrictionSetCount = mOpUserRestrictions.size();
Ruben Brunk29931bc2016-03-11 00:24:26 -08002045
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002046 for (int i = 0; i < restrictionSetCount; i++) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08002047 // For each client, check that the given op is not restricted, or that the given
2048 // package is exempt from the restriction.
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002049 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07002050 if (restrictionState.hasRestriction(code, packageName, userHandle)) {
2051 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
2052 // If we are the system, bypass user restrictions for certain codes
2053 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002054 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
2055 false /* uidMismatchExpected */);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07002056 if ((ops != null) && ops.isPrivileged) {
2057 return false;
2058 }
Ruben Brunk32f0fa42016-03-11 19:07:07 -08002059 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08002060 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002061 return true;
Jason Monk1c7c3192014-06-26 12:52:18 -04002062 }
Jason Monk62062992014-05-06 09:55:28 -04002063 }
2064 return false;
2065 }
2066
Dianne Hackborn35654b62013-01-14 17:38:02 -08002067 void readState() {
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002068 int oldVersion = NO_VERSION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08002069 synchronized (mFile) {
2070 synchronized (this) {
2071 FileInputStream stream;
2072 try {
2073 stream = mFile.openRead();
2074 } catch (FileNotFoundException e) {
2075 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
2076 return;
2077 }
2078 boolean success = false;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002079 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002080 try {
2081 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002082 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002083 int type;
2084 while ((type = parser.next()) != XmlPullParser.START_TAG
2085 && type != XmlPullParser.END_DOCUMENT) {
2086 ;
2087 }
2088
2089 if (type != XmlPullParser.START_TAG) {
2090 throw new IllegalStateException("no start tag found");
2091 }
2092
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002093 final String versionString = parser.getAttributeValue(null, "v");
2094 if (versionString != null) {
2095 oldVersion = Integer.parseInt(versionString);
2096 }
2097
Dianne Hackborn35654b62013-01-14 17:38:02 -08002098 int outerDepth = parser.getDepth();
2099 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2100 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2101 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2102 continue;
2103 }
2104
2105 String tagName = parser.getName();
2106 if (tagName.equals("pkg")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002107 readPackage(parser);
Svetoslav215b44a2015-08-04 19:03:40 -07002108 } else if (tagName.equals("uid")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002109 readUidOps(parser);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002110 } else {
2111 Slog.w(TAG, "Unknown element under <app-ops>: "
2112 + parser.getName());
2113 XmlUtils.skipCurrentTag(parser);
2114 }
2115 }
2116 success = true;
2117 } catch (IllegalStateException e) {
2118 Slog.w(TAG, "Failed parsing " + e);
2119 } catch (NullPointerException e) {
2120 Slog.w(TAG, "Failed parsing " + e);
2121 } catch (NumberFormatException e) {
2122 Slog.w(TAG, "Failed parsing " + e);
2123 } catch (XmlPullParserException e) {
2124 Slog.w(TAG, "Failed parsing " + e);
2125 } catch (IOException e) {
2126 Slog.w(TAG, "Failed parsing " + e);
2127 } catch (IndexOutOfBoundsException e) {
2128 Slog.w(TAG, "Failed parsing " + e);
2129 } finally {
2130 if (!success) {
Svet Ganov2af57082015-07-30 08:44:20 -07002131 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002132 }
2133 try {
2134 stream.close();
2135 } catch (IOException e) {
2136 }
2137 }
2138 }
2139 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002140 synchronized (this) {
2141 upgradeLocked(oldVersion);
2142 }
2143 }
2144
2145 private void upgradeRunAnyInBackgroundLocked() {
2146 for (int i = 0; i < mUidStates.size(); i++) {
2147 final UidState uidState = mUidStates.valueAt(i);
2148 if (uidState == null) {
2149 continue;
2150 }
2151 if (uidState.opModes != null) {
2152 final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
2153 if (idx >= 0) {
2154 uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
2155 uidState.opModes.valueAt(idx));
2156 }
2157 }
2158 if (uidState.pkgOps == null) {
2159 continue;
2160 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002161 boolean changed = false;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002162 for (int j = 0; j < uidState.pkgOps.size(); j++) {
2163 Ops ops = uidState.pkgOps.valueAt(j);
2164 if (ops != null) {
2165 final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
2166 if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002167 final Op copy = new Op(op.uidState, op.packageName,
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002168 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
2169 copy.mode = op.mode;
2170 ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002171 changed = true;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002172 }
2173 }
2174 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002175 if (changed) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002176 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002177 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002178 }
2179 }
2180
2181 private void upgradeLocked(int oldVersion) {
2182 if (oldVersion >= CURRENT_VERSION) {
2183 return;
2184 }
2185 Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
2186 switch (oldVersion) {
2187 case NO_VERSION:
2188 upgradeRunAnyInBackgroundLocked();
2189 // fall through
2190 case 1:
2191 // for future upgrades
2192 }
2193 scheduleFastWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002194 }
2195
Svet Ganov2af57082015-07-30 08:44:20 -07002196 void readUidOps(XmlPullParser parser) throws NumberFormatException,
2197 XmlPullParserException, IOException {
2198 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
2199 int outerDepth = parser.getDepth();
2200 int type;
2201 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2202 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2203 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2204 continue;
2205 }
2206
2207 String tagName = parser.getName();
2208 if (tagName.equals("op")) {
2209 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
2210 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
2211 UidState uidState = getUidStateLocked(uid, true);
2212 if (uidState.opModes == null) {
2213 uidState.opModes = new SparseIntArray();
2214 }
2215 uidState.opModes.put(code, mode);
2216 } else {
2217 Slog.w(TAG, "Unknown element under <uid-ops>: "
2218 + parser.getName());
2219 XmlUtils.skipCurrentTag(parser);
2220 }
2221 }
2222 }
2223
Dave Burke0997c5bd2013-08-02 20:25:02 +00002224 void readPackage(XmlPullParser parser) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002225 XmlPullParserException, IOException {
2226 String pkgName = parser.getAttributeValue(null, "n");
2227 int outerDepth = parser.getDepth();
2228 int type;
2229 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2230 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2231 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2232 continue;
2233 }
2234
2235 String tagName = parser.getName();
2236 if (tagName.equals("uid")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002237 readUid(parser, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002238 } else {
2239 Slog.w(TAG, "Unknown element under <pkg>: "
2240 + parser.getName());
2241 XmlUtils.skipCurrentTag(parser);
2242 }
2243 }
2244 }
2245
Dave Burke0997c5bd2013-08-02 20:25:02 +00002246 void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002247 XmlPullParserException, IOException {
2248 int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
Jason Monk1c7c3192014-06-26 12:52:18 -04002249 String isPrivilegedString = parser.getAttributeValue(null, "p");
2250 boolean isPrivileged = false;
2251 if (isPrivilegedString == null) {
2252 try {
2253 IPackageManager packageManager = ActivityThread.getPackageManager();
2254 if (packageManager != null) {
2255 ApplicationInfo appInfo = ActivityThread.getPackageManager()
2256 .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
2257 if (appInfo != null) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08002258 isPrivileged = (appInfo.privateFlags
2259 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04002260 }
2261 } else {
2262 // Could not load data, don't add to cache so it will be loaded later.
2263 return;
2264 }
2265 } catch (RemoteException e) {
2266 Slog.w(TAG, "Could not contact PackageManager", e);
2267 }
2268 } else {
2269 isPrivileged = Boolean.parseBoolean(isPrivilegedString);
2270 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002271 int outerDepth = parser.getDepth();
2272 int type;
2273 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2274 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2275 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2276 continue;
2277 }
2278
2279 String tagName = parser.getName();
2280 if (tagName.equals("op")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002281 UidState uidState = getUidStateLocked(uid, true);
2282 if (uidState.pkgOps == null) {
2283 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002284 }
Svet Ganov2af57082015-07-30 08:44:20 -07002285
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002286 Op op = new Op(uidState, pkgName,
2287 Integer.parseInt(parser.getAttributeValue(null, "n")));
2288
2289 for (int i = parser.getAttributeCount()-1; i >= 0; i--) {
2290 final String name = parser.getAttributeName(i);
2291 final String value = parser.getAttributeValue(i);
2292 switch (name) {
2293 case "m":
2294 op.mode = Integer.parseInt(value);
2295 break;
2296 case "d":
2297 op.duration = Integer.parseInt(value);
2298 break;
2299 case "pu":
2300 op.proxyUid = Integer.parseInt(value);
2301 break;
2302 case "pp":
2303 op.proxyPackageName = value;
2304 break;
2305 case "tp":
2306 op.time[AppOpsManager.UID_STATE_PERSISTENT] = Long.parseLong(value);
2307 break;
2308 case "tt":
2309 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2310 break;
2311 case "tfs":
2312 op.time[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2313 = Long.parseLong(value);
2314 break;
2315 case "tf":
2316 op.time[AppOpsManager.UID_STATE_FOREGROUND] = Long.parseLong(value);
2317 break;
2318 case "tb":
2319 op.time[AppOpsManager.UID_STATE_BACKGROUND] = Long.parseLong(value);
2320 break;
2321 case "tc":
2322 op.time[AppOpsManager.UID_STATE_CACHED] = Long.parseLong(value);
2323 break;
2324 case "rp":
2325 op.rejectTime[AppOpsManager.UID_STATE_PERSISTENT]
2326 = Long.parseLong(value);
2327 break;
2328 case "rt":
2329 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2330 break;
2331 case "rfs":
2332 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2333 = Long.parseLong(value);
2334 break;
2335 case "rf":
2336 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND]
2337 = Long.parseLong(value);
2338 break;
2339 case "rb":
2340 op.rejectTime[AppOpsManager.UID_STATE_BACKGROUND]
2341 = Long.parseLong(value);
2342 break;
2343 case "rc":
2344 op.rejectTime[AppOpsManager.UID_STATE_CACHED]
2345 = Long.parseLong(value);
2346 break;
2347 case "t":
2348 // Backwards compat.
2349 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2350 break;
2351 case "r":
2352 // Backwards compat.
2353 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2354 break;
2355 default:
2356 Slog.w(TAG, "Unknown attribute in 'op' tag: " + name);
2357 break;
2358 }
2359 }
2360
Svet Ganov2af57082015-07-30 08:44:20 -07002361 Ops ops = uidState.pkgOps.get(pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002362 if (ops == null) {
Svet Ganov2af57082015-07-30 08:44:20 -07002363 ops = new Ops(pkgName, uidState, isPrivileged);
2364 uidState.pkgOps.put(pkgName, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002365 }
2366 ops.put(op.op, op);
2367 } else {
2368 Slog.w(TAG, "Unknown element under <pkg>: "
2369 + parser.getName());
2370 XmlUtils.skipCurrentTag(parser);
2371 }
2372 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002373 UidState uidState = getUidStateLocked(uid, false);
2374 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002375 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002376 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002377 }
2378
2379 void writeState() {
2380 synchronized (mFile) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002381 FileOutputStream stream;
2382 try {
2383 stream = mFile.startWrite();
2384 } catch (IOException e) {
2385 Slog.w(TAG, "Failed to write state: " + e);
2386 return;
2387 }
2388
Dianne Hackborne17b4452018-01-10 13:15:40 -08002389 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
2390
Dianne Hackborn35654b62013-01-14 17:38:02 -08002391 try {
2392 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002393 out.setOutput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002394 out.startDocument(null, true);
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002395 out.startTag(null, "app-ops");
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002396 out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
Svet Ganov2af57082015-07-30 08:44:20 -07002397
2398 final int uidStateCount = mUidStates.size();
2399 for (int i = 0; i < uidStateCount; i++) {
2400 UidState uidState = mUidStates.valueAt(i);
2401 if (uidState.opModes != null && uidState.opModes.size() > 0) {
2402 out.startTag(null, "uid");
2403 out.attribute(null, "n", Integer.toString(uidState.uid));
2404 SparseIntArray uidOpModes = uidState.opModes;
2405 final int opCount = uidOpModes.size();
2406 for (int j = 0; j < opCount; j++) {
2407 final int op = uidOpModes.keyAt(j);
2408 final int mode = uidOpModes.valueAt(j);
2409 out.startTag(null, "op");
2410 out.attribute(null, "n", Integer.toString(op));
2411 out.attribute(null, "m", Integer.toString(mode));
2412 out.endTag(null, "op");
2413 }
2414 out.endTag(null, "uid");
2415 }
2416 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002417
2418 if (allOps != null) {
2419 String lastPkg = null;
2420 for (int i=0; i<allOps.size(); i++) {
2421 AppOpsManager.PackageOps pkg = allOps.get(i);
2422 if (!pkg.getPackageName().equals(lastPkg)) {
2423 if (lastPkg != null) {
2424 out.endTag(null, "pkg");
2425 }
2426 lastPkg = pkg.getPackageName();
2427 out.startTag(null, "pkg");
2428 out.attribute(null, "n", lastPkg);
2429 }
2430 out.startTag(null, "uid");
2431 out.attribute(null, "n", Integer.toString(pkg.getUid()));
Jason Monk1c7c3192014-06-26 12:52:18 -04002432 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002433 Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
2434 false /* edit */, false /* uidMismatchExpected */);
Jason Monk1c7c3192014-06-26 12:52:18 -04002435 // Should always be present as the list of PackageOps is generated
2436 // from Ops.
2437 if (ops != null) {
2438 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
2439 } else {
2440 out.attribute(null, "p", Boolean.toString(false));
2441 }
2442 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002443 List<AppOpsManager.OpEntry> ops = pkg.getOps();
2444 for (int j=0; j<ops.size(); j++) {
2445 AppOpsManager.OpEntry op = ops.get(j);
2446 out.startTag(null, "op");
2447 out.attribute(null, "n", Integer.toString(op.getOp()));
David Braunf5d83192013-09-16 13:43:51 -07002448 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002449 out.attribute(null, "m", Integer.toString(op.getMode()));
2450 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002451 for (int k = 0; k < _NUM_UID_STATE; k++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002452 final long time = op.getLastTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002453 if (time != 0) {
2454 out.attribute(null, UID_STATE_TIME_ATTRS[k],
2455 Long.toString(time));
2456 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002457 final long rejectTime = op.getLastRejectTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002458 if (rejectTime != 0) {
2459 out.attribute(null, UID_STATE_REJECT_ATTRS[k],
2460 Long.toString(rejectTime));
2461 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002462 }
2463 int dur = op.getDuration();
2464 if (dur != 0) {
2465 out.attribute(null, "d", Integer.toString(dur));
2466 }
Svet Ganov99b60432015-06-27 13:15:22 -07002467 int proxyUid = op.getProxyUid();
2468 if (proxyUid != -1) {
2469 out.attribute(null, "pu", Integer.toString(proxyUid));
2470 }
2471 String proxyPackageName = op.getProxyPackageName();
2472 if (proxyPackageName != null) {
2473 out.attribute(null, "pp", proxyPackageName);
2474 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002475 out.endTag(null, "op");
2476 }
2477 out.endTag(null, "uid");
2478 }
2479 if (lastPkg != null) {
2480 out.endTag(null, "pkg");
2481 }
2482 }
2483
2484 out.endTag(null, "app-ops");
2485 out.endDocument();
2486 mFile.finishWrite(stream);
2487 } catch (IOException e) {
2488 Slog.w(TAG, "Failed to write state, restoring backup.", e);
2489 mFile.failWrite(stream);
2490 }
2491 }
2492 }
2493
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002494 static class Shell extends ShellCommand {
2495 final IAppOpsService mInterface;
2496 final AppOpsService mInternal;
2497
2498 int userId = UserHandle.USER_SYSTEM;
2499 String packageName;
2500 String opStr;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002501 String modeStr;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002502 int op;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002503 int mode;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002504 int packageUid;
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002505 int nonpackageUid;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002506 final static Binder sBinder = new Binder();
2507 IBinder mToken;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002508
2509 Shell(IAppOpsService iface, AppOpsService internal) {
2510 mInterface = iface;
2511 mInternal = internal;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002512 try {
2513 mToken = mInterface.getToken(sBinder);
2514 } catch (RemoteException e) {
2515 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002516 }
2517
2518 @Override
2519 public int onCommand(String cmd) {
2520 return onShellCommand(this, cmd);
2521 }
2522
2523 @Override
2524 public void onHelp() {
2525 PrintWriter pw = getOutPrintWriter();
2526 dumpCommandHelp(pw);
2527 }
2528
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002529 static private int strOpToOp(String op, PrintWriter err) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002530 try {
2531 return AppOpsManager.strOpToOp(op);
2532 } catch (IllegalArgumentException e) {
2533 }
2534 try {
2535 return Integer.parseInt(op);
2536 } catch (NumberFormatException e) {
2537 }
2538 try {
2539 return AppOpsManager.strDebugOpToOp(op);
2540 } catch (IllegalArgumentException e) {
2541 err.println("Error: " + e.getMessage());
2542 return -1;
2543 }
2544 }
2545
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002546 static int strModeToMode(String modeStr, PrintWriter err) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002547 for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
2548 if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002549 return i;
2550 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002551 }
2552 try {
2553 return Integer.parseInt(modeStr);
2554 } catch (NumberFormatException e) {
2555 }
2556 err.println("Error: Mode " + modeStr + " is not valid");
2557 return -1;
2558 }
2559
2560 int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
2561 userId = UserHandle.USER_CURRENT;
2562 opStr = null;
2563 modeStr = null;
2564 for (String argument; (argument = getNextArg()) != null;) {
2565 if ("--user".equals(argument)) {
2566 userId = UserHandle.parseUserArg(getNextArgRequired());
2567 } else {
2568 if (opStr == null) {
2569 opStr = argument;
2570 } else if (modeStr == null) {
2571 modeStr = argument;
2572 break;
2573 }
2574 }
2575 }
2576 if (opStr == null) {
2577 err.println("Error: Operation not specified.");
2578 return -1;
2579 }
2580 op = strOpToOp(opStr, err);
2581 if (op < 0) {
2582 return -1;
2583 }
2584 if (modeStr != null) {
2585 if ((mode=strModeToMode(modeStr, err)) < 0) {
2586 return -1;
2587 }
2588 } else {
2589 mode = defMode;
2590 }
2591 return 0;
2592 }
2593
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002594 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
2595 userId = UserHandle.USER_CURRENT;
2596 packageName = null;
2597 opStr = null;
2598 for (String argument; (argument = getNextArg()) != null;) {
2599 if ("--user".equals(argument)) {
2600 userId = UserHandle.parseUserArg(getNextArgRequired());
2601 } else {
2602 if (packageName == null) {
2603 packageName = argument;
2604 } else if (opStr == null) {
2605 opStr = argument;
2606 break;
2607 }
2608 }
2609 }
2610 if (packageName == null) {
2611 err.println("Error: Package name not specified.");
2612 return -1;
2613 } else if (opStr == null && reqOp) {
2614 err.println("Error: Operation not specified.");
2615 return -1;
2616 }
2617 if (opStr != null) {
2618 op = strOpToOp(opStr, err);
2619 if (op < 0) {
2620 return -1;
2621 }
2622 } else {
2623 op = AppOpsManager.OP_NONE;
2624 }
2625 if (userId == UserHandle.USER_CURRENT) {
2626 userId = ActivityManager.getCurrentUser();
2627 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002628 nonpackageUid = -1;
2629 try {
2630 nonpackageUid = Integer.parseInt(packageName);
2631 } catch (NumberFormatException e) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002632 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002633 if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
2634 && packageName.indexOf('.') < 0) {
2635 int i = 1;
2636 while (i < packageName.length() && packageName.charAt(i) >= '0'
2637 && packageName.charAt(i) <= '9') {
2638 i++;
2639 }
2640 if (i > 1 && i < packageName.length()) {
2641 String userStr = packageName.substring(1, i);
2642 try {
2643 int user = Integer.parseInt(userStr);
2644 char type = packageName.charAt(i);
2645 i++;
2646 int startTypeVal = i;
2647 while (i < packageName.length() && packageName.charAt(i) >= '0'
2648 && packageName.charAt(i) <= '9') {
2649 i++;
2650 }
2651 if (i > startTypeVal) {
2652 String typeValStr = packageName.substring(startTypeVal, i);
2653 try {
2654 int typeVal = Integer.parseInt(typeValStr);
2655 if (type == 'a') {
2656 nonpackageUid = UserHandle.getUid(user,
2657 typeVal + Process.FIRST_APPLICATION_UID);
2658 } else if (type == 's') {
2659 nonpackageUid = UserHandle.getUid(user, typeVal);
2660 }
2661 } catch (NumberFormatException e) {
2662 }
2663 }
2664 } catch (NumberFormatException e) {
2665 }
2666 }
2667 }
2668 if (nonpackageUid != -1) {
2669 packageName = null;
2670 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08002671 packageUid = resolveUid(packageName);
2672 if (packageUid < 0) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002673 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
2674 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
2675 }
2676 if (packageUid < 0) {
2677 err.println("Error: No UID for " + packageName + " in user " + userId);
2678 return -1;
2679 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002680 }
2681 return 0;
2682 }
2683 }
2684
2685 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07002686 FileDescriptor err, String[] args, ShellCallback callback,
2687 ResultReceiver resultReceiver) {
2688 (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002689 }
2690
2691 static void dumpCommandHelp(PrintWriter pw) {
2692 pw.println("AppOps service (appops) commands:");
2693 pw.println(" help");
2694 pw.println(" Print this help text.");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002695 pw.println(" start [--user <USER_ID>] <PACKAGE | UID> <OP> ");
2696 pw.println(" Starts a given operation for a particular application.");
2697 pw.println(" stop [--user <USER_ID>] <PACKAGE | UID> <OP> ");
2698 pw.println(" Stops a given operation for a particular application.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002699 pw.println(" set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002700 pw.println(" Set the mode for a particular application and operation.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002701 pw.println(" get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002702 pw.println(" Return the mode for a particular application and optional operation.");
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002703 pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
2704 pw.println(" Print all packages that currently have the given op in the given mode.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002705 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
2706 pw.println(" Reset the given application or all applications to default modes.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002707 pw.println(" write-settings");
2708 pw.println(" Immediately write pending changes to storage.");
2709 pw.println(" read-settings");
2710 pw.println(" Read the last written settings, replacing current state in RAM.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002711 pw.println(" options:");
2712 pw.println(" <PACKAGE> an Android package name.");
2713 pw.println(" <OP> an AppOps operation.");
2714 pw.println(" <MODE> one of allow, ignore, deny, or default");
2715 pw.println(" <USER_ID> the user id under which the package is installed. If --user is not");
2716 pw.println(" specified, the current user is assumed.");
2717 }
2718
2719 static int onShellCommand(Shell shell, String cmd) {
2720 if (cmd == null) {
2721 return shell.handleDefaultCommands(cmd);
2722 }
2723 PrintWriter pw = shell.getOutPrintWriter();
2724 PrintWriter err = shell.getErrPrintWriter();
2725 try {
2726 switch (cmd) {
2727 case "set": {
2728 int res = shell.parseUserPackageOp(true, err);
2729 if (res < 0) {
2730 return res;
2731 }
2732 String modeStr = shell.getNextArg();
2733 if (modeStr == null) {
2734 err.println("Error: Mode not specified.");
2735 return -1;
2736 }
2737
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002738 final int mode = shell.strModeToMode(modeStr, err);
2739 if (mode < 0) {
2740 return -1;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002741 }
2742
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002743 if (shell.packageName != null) {
2744 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
2745 mode);
2746 } else {
2747 shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
2748 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002749 return 0;
2750 }
2751 case "get": {
2752 int res = shell.parseUserPackageOp(false, err);
2753 if (res < 0) {
2754 return res;
2755 }
2756
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002757 List<AppOpsManager.PackageOps> ops;
2758 if (shell.packageName != null) {
2759 ops = shell.mInterface.getOpsForPackage(
2760 shell.packageUid, shell.packageName,
2761 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
2762 } else {
2763 ops = shell.mInterface.getUidOps(
2764 shell.nonpackageUid,
2765 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
2766 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002767 if (ops == null || ops.size() <= 0) {
2768 pw.println("No operations.");
Svet Ganov82f09bc2018-01-12 22:08:40 -08002769 if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002770 pw.println("Default mode: " + AppOpsManager.modeToName(
Svet Ganov82f09bc2018-01-12 22:08:40 -08002771 AppOpsManager.opToDefaultMode(shell.op)));
2772 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002773 return 0;
2774 }
2775 final long now = System.currentTimeMillis();
2776 for (int i=0; i<ops.size(); i++) {
2777 List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
2778 for (int j=0; j<entries.size(); j++) {
2779 AppOpsManager.OpEntry ent = entries.get(j);
2780 pw.print(AppOpsManager.opToName(ent.getOp()));
2781 pw.print(": ");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002782 pw.print(AppOpsManager.modeToName(ent.getMode()));
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002783 if (ent.getTime() != 0) {
2784 pw.print("; time=");
2785 TimeUtils.formatDuration(now - ent.getTime(), pw);
2786 pw.print(" ago");
2787 }
2788 if (ent.getRejectTime() != 0) {
2789 pw.print("; rejectTime=");
2790 TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
2791 pw.print(" ago");
2792 }
2793 if (ent.getDuration() == -1) {
2794 pw.print(" (running)");
2795 } else if (ent.getDuration() != 0) {
2796 pw.print("; duration=");
2797 TimeUtils.formatDuration(ent.getDuration(), pw);
2798 }
2799 pw.println();
2800 }
2801 }
2802 return 0;
2803 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002804 case "query-op": {
2805 int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
2806 if (res < 0) {
2807 return res;
2808 }
2809 List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
2810 new int[] {shell.op});
2811 if (ops == null || ops.size() <= 0) {
2812 pw.println("No operations.");
2813 return 0;
2814 }
2815 for (int i=0; i<ops.size(); i++) {
2816 final AppOpsManager.PackageOps pkg = ops.get(i);
2817 boolean hasMatch = false;
2818 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
2819 for (int j=0; j<entries.size(); j++) {
2820 AppOpsManager.OpEntry ent = entries.get(j);
2821 if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
2822 hasMatch = true;
2823 break;
2824 }
2825 }
2826 if (hasMatch) {
2827 pw.println(pkg.getPackageName());
2828 }
2829 }
2830 return 0;
2831 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002832 case "reset": {
2833 String packageName = null;
2834 int userId = UserHandle.USER_CURRENT;
2835 for (String argument; (argument = shell.getNextArg()) != null;) {
2836 if ("--user".equals(argument)) {
2837 String userStr = shell.getNextArgRequired();
2838 userId = UserHandle.parseUserArg(userStr);
2839 } else {
2840 if (packageName == null) {
2841 packageName = argument;
2842 } else {
2843 err.println("Error: Unsupported argument: " + argument);
2844 return -1;
2845 }
2846 }
2847 }
2848
2849 if (userId == UserHandle.USER_CURRENT) {
2850 userId = ActivityManager.getCurrentUser();
2851 }
2852
2853 shell.mInterface.resetAllModes(userId, packageName);
2854 pw.print("Reset all modes for: ");
2855 if (userId == UserHandle.USER_ALL) {
2856 pw.print("all users");
2857 } else {
2858 pw.print("user "); pw.print(userId);
2859 }
2860 pw.print(", ");
2861 if (packageName == null) {
2862 pw.println("all packages");
2863 } else {
2864 pw.print("package "); pw.println(packageName);
2865 }
2866 return 0;
2867 }
2868 case "write-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07002869 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
2870 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002871 long token = Binder.clearCallingIdentity();
2872 try {
2873 synchronized (shell.mInternal) {
2874 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
2875 }
2876 shell.mInternal.writeState();
2877 pw.println("Current settings written.");
2878 } finally {
2879 Binder.restoreCallingIdentity(token);
2880 }
2881 return 0;
2882 }
2883 case "read-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07002884 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
2885 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002886 long token = Binder.clearCallingIdentity();
2887 try {
2888 shell.mInternal.readState();
2889 pw.println("Last settings read.");
2890 } finally {
2891 Binder.restoreCallingIdentity(token);
2892 }
2893 return 0;
2894 }
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002895 case "start": {
2896 int res = shell.parseUserPackageOp(true, err);
2897 if (res < 0) {
2898 return res;
2899 }
2900
2901 if (shell.packageName != null) {
2902 shell.mInterface.startOperation(shell.mToken,
2903 shell.op, shell.packageUid, shell.packageName, true);
2904 } else {
2905 return -1;
2906 }
2907 return 0;
2908 }
2909 case "stop": {
2910 int res = shell.parseUserPackageOp(true, err);
2911 if (res < 0) {
2912 return res;
2913 }
2914
2915 if (shell.packageName != null) {
2916 shell.mInterface.finishOperation(shell.mToken,
2917 shell.op, shell.packageUid, shell.packageName);
2918 } else {
2919 return -1;
2920 }
2921 return 0;
2922 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002923 default:
2924 return shell.handleDefaultCommands(cmd);
2925 }
2926 } catch (RemoteException e) {
2927 pw.println("Remote exception: " + e);
2928 }
2929 return -1;
2930 }
2931
2932 private void dumpHelp(PrintWriter pw) {
2933 pw.println("AppOps service (appops) dump options:");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002934 pw.println(" -h");
2935 pw.println(" Print this help text.");
2936 pw.println(" --op [OP]");
2937 pw.println(" Limit output to data associated with the given app op code.");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002938 pw.println(" --mode [MODE]");
2939 pw.println(" Limit output to data associated with the given app op mode.");
2940 pw.println(" --package [PACKAGE]");
2941 pw.println(" Limit output to data associated with the given package name.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002942 }
2943
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002944 private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
2945 long now, SimpleDateFormat sdf, Date date) {
2946 boolean hasTime = false;
2947 for (int i = 0; i < _NUM_UID_STATE; i++) {
2948 if (times[i] != 0) {
2949 hasTime = true;
2950 break;
2951 }
2952 }
2953 if (!hasTime) {
2954 return;
2955 }
2956 boolean first = true;
2957 for (int i = 0; i < _NUM_UID_STATE; i++) {
2958 if (times[i] != 0) {
2959 pw.print(first ? firstPrefix : prefix);
2960 first = false;
2961 pw.print(UID_STATE_NAMES[i]);
2962 pw.print(" = ");
2963 date.setTime(times[i]);
2964 pw.print(sdf.format(date));
2965 pw.print(" (");
2966 TimeUtils.formatDuration(times[i]-now, pw);
2967 pw.println(")");
2968 }
2969 }
2970 }
2971
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002972 @Override
2973 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06002974 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002975
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002976 int dumpOp = -1;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002977 String dumpPackage = null;
2978 int dumpUid = -1;
2979 int dumpMode = -1;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002980
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002981 if (args != null) {
2982 for (int i=0; i<args.length; i++) {
2983 String arg = args[i];
2984 if ("-h".equals(arg)) {
2985 dumpHelp(pw);
2986 return;
Tim Kilbourn8f1ea832015-08-26 15:07:37 -07002987 } else if ("-a".equals(arg)) {
2988 // dump all data
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002989 } else if ("--op".equals(arg)) {
2990 i++;
2991 if (i >= args.length) {
2992 pw.println("No argument for --op option");
2993 return;
2994 }
2995 dumpOp = Shell.strOpToOp(args[i], pw);
2996 if (dumpOp < 0) {
2997 return;
2998 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002999 } else if ("--package".equals(arg)) {
3000 i++;
3001 if (i >= args.length) {
3002 pw.println("No argument for --package option");
3003 return;
3004 }
3005 dumpPackage = args[i];
3006 try {
3007 dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
3008 PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
3009 0);
3010 } catch (RemoteException e) {
3011 }
3012 if (dumpUid < 0) {
3013 pw.println("Unknown package: " + dumpPackage);
3014 return;
3015 }
3016 dumpUid = UserHandle.getAppId(dumpUid);
3017 } else if ("--mode".equals(arg)) {
3018 i++;
3019 if (i >= args.length) {
3020 pw.println("No argument for --mode option");
3021 return;
3022 }
3023 dumpMode = Shell.strModeToMode(args[i], pw);
3024 if (dumpMode < 0) {
3025 return;
3026 }
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003027 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
3028 pw.println("Unknown option: " + arg);
3029 return;
3030 } else {
3031 pw.println("Unknown command: " + arg);
3032 return;
3033 }
3034 }
3035 }
3036
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003037 synchronized (this) {
3038 pw.println("Current AppOps Service state:");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003039 mConstants.dump(pw);
3040 pw.println();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003041 final long now = System.currentTimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003042 final long nowElapsed = SystemClock.elapsedRealtime();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003043 final long nowUptime = SystemClock.uptimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003044 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
3045 final Date date = new Date();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003046 boolean needSep = false;
Dianne Hackbornd5254412018-05-11 18:02:58 -07003047 if (dumpOp < 0 && dumpMode < 0 && dumpPackage == null && mProfileOwners != null) {
3048 pw.println(" Profile owners:");
3049 for (int poi = 0; poi < mProfileOwners.size(); poi++) {
3050 pw.print(" User #");
3051 pw.print(mProfileOwners.keyAt(poi));
3052 pw.print(": ");
3053 UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
3054 pw.println();
3055 }
3056 pw.println();
3057 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003058 if (mOpModeWatchers.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003059 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003060 for (int i=0; i<mOpModeWatchers.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003061 if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
3062 continue;
3063 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003064 boolean printedOpHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003065 ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003066 for (int j=0; j<callbacks.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003067 final ModeCallback cb = callbacks.valueAt(j);
3068 if (dumpPackage != null && cb.mWatchingUid >= 0
3069 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3070 continue;
3071 }
3072 needSep = true;
3073 if (!printedHeader) {
3074 pw.println(" Op mode watchers:");
3075 printedHeader = true;
3076 }
3077 if (!printedOpHeader) {
3078 pw.print(" Op ");
3079 pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
3080 pw.println(":");
3081 printedOpHeader = true;
3082 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003083 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003084 pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003085 }
3086 }
3087 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003088 if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
3089 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003090 for (int i=0; i<mPackageModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003091 if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
3092 continue;
3093 }
3094 needSep = true;
3095 if (!printedHeader) {
3096 pw.println(" Package mode watchers:");
3097 printedHeader = true;
3098 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003099 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
3100 pw.println(":");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003101 ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003102 for (int j=0; j<callbacks.size(); j++) {
3103 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn68d76552017-02-27 15:32:03 -08003104 pw.println(callbacks.valueAt(j));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003105 }
3106 }
3107 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003108 if (mModeWatchers.size() > 0 && dumpOp < 0) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003109 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003110 for (int i=0; i<mModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003111 final ModeCallback cb = mModeWatchers.valueAt(i);
3112 if (dumpPackage != null && cb.mWatchingUid >= 0
3113 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3114 continue;
3115 }
3116 needSep = true;
3117 if (!printedHeader) {
3118 pw.println(" All op mode watchers:");
3119 printedHeader = true;
3120 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003121 pw.print(" ");
3122 pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003123 pw.print(": "); pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003124 }
3125 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003126 if (mActiveWatchers.size() > 0 && dumpMode < 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003127 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003128 boolean printedHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003129 for (int i = 0; i < mActiveWatchers.size(); i++) {
3130 final SparseArray<ActiveCallback> activeWatchers = mActiveWatchers.valueAt(i);
3131 if (activeWatchers.size() <= 0) {
3132 continue;
3133 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003134 final ActiveCallback cb = activeWatchers.valueAt(0);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003135 if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
3136 continue;
3137 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003138 if (dumpPackage != null && cb.mWatchingUid >= 0
3139 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3140 continue;
3141 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003142 if (!printedHeader) {
3143 pw.println(" All op active watchers:");
3144 printedHeader = true;
3145 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003146 pw.print(" ");
3147 pw.print(Integer.toHexString(System.identityHashCode(
3148 mActiveWatchers.keyAt(i))));
3149 pw.println(" ->");
3150 pw.print(" [");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003151 final int opCount = activeWatchers.size();
3152 for (i = 0; i < opCount; i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003153 if (i > 0) {
3154 pw.print(' ');
3155 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003156 pw.print(AppOpsManager.opToName(activeWatchers.keyAt(i)));
3157 if (i < opCount - 1) {
3158 pw.print(',');
3159 }
3160 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003161 pw.println("]");
3162 pw.print(" ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003163 pw.println(cb);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003164 }
3165 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003166 if (mClients.size() > 0 && dumpMode < 0) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003167 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003168 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003169 for (int i=0; i<mClients.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003170 boolean printedClient = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003171 ClientState cs = mClients.valueAt(i);
Svet Ganovf7b47252018-02-26 11:11:27 -08003172 if (cs.mStartedOps.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003173 boolean printedStarted = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003174 for (int j=0; j<cs.mStartedOps.size(); j++) {
3175 Op op = cs.mStartedOps.get(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003176 if (dumpOp >= 0 && op.op != dumpOp) {
3177 continue;
3178 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003179 if (dumpPackage != null && !dumpPackage.equals(op.packageName)) {
3180 continue;
3181 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003182 if (!printedHeader) {
3183 pw.println(" Clients:");
3184 printedHeader = true;
3185 }
3186 if (!printedClient) {
3187 pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
3188 pw.print(" "); pw.println(cs);
3189 printedClient = true;
3190 }
3191 if (!printedStarted) {
3192 pw.println(" Started ops:");
3193 printedStarted = true;
3194 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003195 pw.print(" "); pw.print("uid="); pw.print(op.uid);
3196 pw.print(" pkg="); pw.print(op.packageName);
3197 pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
3198 }
3199 }
3200 }
3201 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003202 if (mAudioRestrictions.size() > 0 && dumpOp < 0 && dumpPackage != null
3203 && dumpMode < 0) {
John Spurlock1af30c72014-03-10 08:33:35 -04003204 boolean printedHeader = false;
3205 for (int o=0; o<mAudioRestrictions.size(); o++) {
3206 final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
3207 final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
3208 for (int i=0; i<restrictions.size(); i++) {
3209 if (!printedHeader){
3210 pw.println(" Audio Restrictions:");
3211 printedHeader = true;
3212 needSep = true;
3213 }
John Spurlock7b414672014-07-18 13:02:39 -04003214 final int usage = restrictions.keyAt(i);
John Spurlock1af30c72014-03-10 08:33:35 -04003215 pw.print(" "); pw.print(op);
John Spurlock7b414672014-07-18 13:02:39 -04003216 pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
John Spurlock1af30c72014-03-10 08:33:35 -04003217 Restriction r = restrictions.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003218 pw.print(": mode="); pw.println(AppOpsManager.modeToName(r.mode));
John Spurlock1af30c72014-03-10 08:33:35 -04003219 if (!r.exceptionPackages.isEmpty()) {
3220 pw.println(" Exceptions:");
3221 for (int j=0; j<r.exceptionPackages.size(); j++) {
3222 pw.print(" "); pw.println(r.exceptionPackages.valueAt(j));
3223 }
3224 }
3225 }
3226 }
3227 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003228 if (needSep) {
3229 pw.println();
3230 }
Svet Ganov2af57082015-07-30 08:44:20 -07003231 for (int i=0; i<mUidStates.size(); i++) {
3232 UidState uidState = mUidStates.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003233 final SparseIntArray opModes = uidState.opModes;
3234 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
3235
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003236 if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
3237 boolean hasOp = dumpOp < 0 || (uidState.opModes != null
3238 && uidState.opModes.indexOfKey(dumpOp) >= 0);
3239 boolean hasPackage = dumpPackage == null;
3240 boolean hasMode = dumpMode < 0;
3241 if (!hasMode && opModes != null) {
3242 for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
3243 if (opModes.valueAt(opi) == dumpMode) {
3244 hasMode = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003245 }
3246 }
3247 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003248 if (pkgOps != null) {
3249 for (int pkgi = 0;
3250 (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
3251 pkgi++) {
3252 Ops ops = pkgOps.valueAt(pkgi);
3253 if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
3254 hasOp = true;
3255 }
3256 if (!hasMode) {
3257 for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
3258 if (ops.valueAt(opi).mode == dumpMode) {
3259 hasMode = true;
3260 }
3261 }
3262 }
3263 if (!hasPackage && dumpPackage.equals(ops.packageName)) {
3264 hasPackage = true;
3265 }
3266 }
3267 }
3268 if (uidState.foregroundOps != null && !hasOp) {
3269 if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
3270 hasOp = true;
3271 }
3272 }
3273 if (!hasOp || !hasPackage || !hasMode) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003274 continue;
3275 }
3276 }
Svet Ganov2af57082015-07-30 08:44:20 -07003277
3278 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003279 pw.print(" state=");
3280 pw.println(UID_STATE_NAMES[uidState.state]);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003281 if (uidState.state != uidState.pendingState) {
3282 pw.print(" pendingState=");
3283 pw.println(UID_STATE_NAMES[uidState.pendingState]);
3284 }
3285 if (uidState.pendingStateCommitTime != 0) {
3286 pw.print(" pendingStateCommitTime=");
3287 TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowUptime, pw);
3288 pw.println();
3289 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003290 if (uidState.startNesting != 0) {
3291 pw.print(" startNesting=");
3292 pw.println(uidState.startNesting);
3293 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003294 if (uidState.foregroundOps != null && (dumpMode < 0
3295 || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003296 pw.println(" foregroundOps:");
3297 for (int j = 0; j < uidState.foregroundOps.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003298 if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
3299 continue;
3300 }
3301 pw.print(" ");
3302 pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
3303 pw.print(": ");
3304 pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003305 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003306 pw.print(" hasForegroundWatchers=");
3307 pw.println(uidState.hasForegroundWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003308 }
Svet Ganovee438d42017-01-19 18:04:38 -08003309 needSep = true;
Svet Ganov2af57082015-07-30 08:44:20 -07003310
Svet Ganov2af57082015-07-30 08:44:20 -07003311 if (opModes != null) {
3312 final int opModeCount = opModes.size();
3313 for (int j = 0; j < opModeCount; j++) {
3314 final int code = opModes.keyAt(j);
3315 final int mode = opModes.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003316 if (dumpOp >= 0 && dumpOp != code) {
3317 continue;
3318 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003319 if (dumpMode >= 0 && dumpMode != mode) {
3320 continue;
3321 }
Svet Ganov2af57082015-07-30 08:44:20 -07003322 pw.print(" "); pw.print(AppOpsManager.opToName(code));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003323 pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
Svet Ganov2af57082015-07-30 08:44:20 -07003324 }
3325 }
3326
Svet Ganov2af57082015-07-30 08:44:20 -07003327 if (pkgOps == null) {
3328 continue;
3329 }
3330
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003331 for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003332 final Ops ops = pkgOps.valueAt(pkgi);
3333 if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
3334 continue;
3335 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003336 boolean printedPackage = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003337 for (int j=0; j<ops.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003338 final Op op = ops.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003339 if (dumpOp >= 0 && dumpOp != op.op) {
3340 continue;
3341 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003342 if (dumpMode >= 0 && dumpMode != op.mode) {
3343 continue;
3344 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003345 if (!printedPackage) {
3346 pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
3347 printedPackage = true;
3348 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003349 pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003350 pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003351 final int switchOp = AppOpsManager.opToSwitch(op.op);
3352 if (switchOp != op.op) {
3353 pw.print(" / switch ");
3354 pw.print(AppOpsManager.opToName(switchOp));
3355 final Op switchObj = ops.get(switchOp);
3356 int mode = switchObj != null
3357 ? switchObj.mode : AppOpsManager.opToDefaultMode(switchOp);
3358 pw.print("="); pw.print(AppOpsManager.modeToName(mode));
3359 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003360 pw.println("): ");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003361 dumpTimesLocked(pw,
3362 " Access: ",
3363 " ", op.time, now, sdf, date);
3364 dumpTimesLocked(pw,
3365 " Reject: ",
3366 " ", op.rejectTime, now, sdf, date);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003367 if (op.duration == -1) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003368 pw.print(" Running start at: ");
3369 TimeUtils.formatDuration(nowElapsed-op.startRealtime, pw);
3370 pw.println();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08003371 } else if (op.duration != 0) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003372 pw.print(" duration=");
3373 TimeUtils.formatDuration(op.duration, pw);
3374 pw.println();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003375 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003376 if (op.startNesting != 0) {
3377 pw.print(" startNesting=");
3378 pw.println(op.startNesting);
3379 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003380 }
3381 }
3382 }
Svet Ganovee438d42017-01-19 18:04:38 -08003383 if (needSep) {
3384 pw.println();
3385 }
3386
3387 final int userRestrictionCount = mOpUserRestrictions.size();
3388 for (int i = 0; i < userRestrictionCount; i++) {
3389 IBinder token = mOpUserRestrictions.keyAt(i);
3390 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
3391 pw.println(" User restrictions for token " + token + ":");
3392
3393 final int restrictionCount = restrictionState.perUserRestrictions != null
3394 ? restrictionState.perUserRestrictions.size() : 0;
3395 if (restrictionCount > 0) {
3396 pw.println(" Restricted ops:");
3397 for (int j = 0; j < restrictionCount; j++) {
3398 int userId = restrictionState.perUserRestrictions.keyAt(j);
3399 boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
3400 if (restrictedOps == null) {
3401 continue;
3402 }
3403 StringBuilder restrictedOpsValue = new StringBuilder();
3404 restrictedOpsValue.append("[");
3405 final int restrictedOpCount = restrictedOps.length;
3406 for (int k = 0; k < restrictedOpCount; k++) {
3407 if (restrictedOps[k]) {
3408 if (restrictedOpsValue.length() > 1) {
3409 restrictedOpsValue.append(", ");
3410 }
3411 restrictedOpsValue.append(AppOpsManager.opToName(k));
3412 }
3413 }
3414 restrictedOpsValue.append("]");
3415 pw.print(" "); pw.print("user: "); pw.print(userId);
3416 pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
3417 }
3418 }
3419
3420 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
3421 ? restrictionState.perUserExcludedPackages.size() : 0;
3422 if (excludedPackageCount > 0) {
3423 pw.println(" Excluded packages:");
3424 for (int j = 0; j < excludedPackageCount; j++) {
3425 int userId = restrictionState.perUserExcludedPackages.keyAt(j);
3426 String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
3427 pw.print(" "); pw.print("user: "); pw.print(userId);
3428 pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
3429 }
3430 }
3431 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003432 }
3433 }
John Spurlock1af30c72014-03-10 08:33:35 -04003434
3435 private static final class Restriction {
3436 private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
3437 int mode;
3438 ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
3439 }
Jason Monk62062992014-05-06 09:55:28 -04003440
3441 @Override
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003442 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
Jason Monk62062992014-05-06 09:55:28 -04003443 checkSystemUid("setUserRestrictions");
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003444 Preconditions.checkNotNull(restrictions);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003445 Preconditions.checkNotNull(token);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003446 for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
Jason Monk62062992014-05-06 09:55:28 -04003447 String restriction = AppOpsManager.opToRestriction(i);
Suprabh Shukla64e0dcb2016-05-24 16:23:11 -07003448 if (restriction != null) {
3449 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
3450 userHandle, null);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003451 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003452 }
3453 }
3454
3455 @Override
Ruben Brunk29931bc2016-03-11 00:24:26 -08003456 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
3457 String[] exceptionPackages) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003458 if (Binder.getCallingPid() != Process.myPid()) {
3459 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
3460 Binder.getCallingPid(), Binder.getCallingUid(), null);
3461 }
3462 if (userHandle != UserHandle.getCallingUserId()) {
3463 if (mContext.checkCallingOrSelfPermission(Manifest.permission
3464 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
3465 && mContext.checkCallingOrSelfPermission(Manifest.permission
3466 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
3467 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
3468 + " INTERACT_ACROSS_USERS to interact cross user ");
Jason Monk62062992014-05-06 09:55:28 -04003469 }
3470 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003471 verifyIncomingOp(code);
3472 Preconditions.checkNotNull(token);
Ruben Brunk29931bc2016-03-11 00:24:26 -08003473 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003474 }
3475
3476 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
Ruben Brunk29931bc2016-03-11 00:24:26 -08003477 int userHandle, String[] exceptionPackages) {
Svet Ganov442ed572016-08-17 17:29:43 -07003478 synchronized (AppOpsService.this) {
3479 ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
3480
3481 if (restrictionState == null) {
3482 try {
3483 restrictionState = new ClientRestrictionState(token);
3484 } catch (RemoteException e) {
3485 return;
3486 }
3487 mOpUserRestrictions.put(token, restrictionState);
Ruben Brunk29931bc2016-03-11 00:24:26 -08003488 }
Svet Ganov442ed572016-08-17 17:29:43 -07003489
3490 if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003491 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07003492 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
Svet Ganov442ed572016-08-17 17:29:43 -07003493 }
3494
3495 if (restrictionState.isDefault()) {
3496 mOpUserRestrictions.remove(token);
3497 restrictionState.destroy();
3498 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08003499 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -04003500 }
3501
Svet Ganov3a95f832018-03-23 17:44:30 -07003502 private void notifyWatchersOfChange(int code, int uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003503 final ArraySet<ModeCallback> clonedCallbacks;
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003504 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003505 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003506 if (callbacks == null) {
3507 return;
3508 }
Dianne Hackborn68d76552017-02-27 15:32:03 -08003509 clonedCallbacks = new ArraySet<>(callbacks);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003510 }
3511
Svet Ganov3a95f832018-03-23 17:44:30 -07003512 notifyOpChanged(clonedCallbacks, code, uid, null);
Jason Monk62062992014-05-06 09:55:28 -04003513 }
3514
3515 @Override
3516 public void removeUser(int userHandle) throws RemoteException {
3517 checkSystemUid("removeUser");
Svet Ganov442ed572016-08-17 17:29:43 -07003518 synchronized (AppOpsService.this) {
3519 final int tokenCount = mOpUserRestrictions.size();
3520 for (int i = tokenCount - 1; i >= 0; i--) {
3521 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
3522 opRestrictions.removeUser(userHandle);
3523 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003524 removeUidsForUserLocked(userHandle);
3525 }
3526 }
3527
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003528 @Override
3529 public boolean isOperationActive(int code, int uid, String packageName) {
Svet Ganovf7b47252018-02-26 11:11:27 -08003530 if (Binder.getCallingUid() != uid) {
3531 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
3532 != PackageManager.PERMISSION_GRANTED) {
3533 return false;
3534 }
3535 }
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003536 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003537 final String resolvedPackageName = resolvePackageName(uid, packageName);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003538 if (resolvedPackageName == null) {
3539 return false;
3540 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003541 synchronized (AppOpsService.this) {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003542 for (int i = mClients.size() - 1; i >= 0; i--) {
3543 final ClientState client = mClients.valueAt(i);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003544 for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
3545 final Op op = client.mStartedOps.get(j);
3546 if (op.op == code && op.uid == uid) return true;
3547 }
3548 }
3549 }
3550 return false;
3551 }
3552
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003553 private void removeUidsForUserLocked(int userHandle) {
3554 for (int i = mUidStates.size() - 1; i >= 0; --i) {
3555 final int uid = mUidStates.keyAt(i);
3556 if (UserHandle.getUserId(uid) == userHandle) {
3557 mUidStates.removeAt(i);
3558 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003559 }
3560 }
3561
Jason Monk62062992014-05-06 09:55:28 -04003562 private void checkSystemUid(String function) {
3563 int uid = Binder.getCallingUid();
3564 if (uid != Process.SYSTEM_UID) {
3565 throw new SecurityException(function + " must by called by the system");
3566 }
3567 }
3568
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003569 private static String resolvePackageName(int uid, String packageName) {
Svet Ganov82f09bc2018-01-12 22:08:40 -08003570 if (uid == Process.ROOT_UID) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003571 return "root";
3572 } else if (uid == Process.SHELL_UID) {
3573 return "com.android.shell";
Svet Ganov82f09bc2018-01-12 22:08:40 -08003574 } else if (uid == Process.MEDIA_UID) {
3575 return "media";
3576 } else if (uid == Process.AUDIOSERVER_UID) {
3577 return "audioserver";
3578 } else if (uid == Process.CAMERASERVER_UID) {
3579 return "cameraserver";
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003580 } else if (uid == Process.SYSTEM_UID && packageName == null) {
3581 return "android";
3582 }
3583 return packageName;
3584 }
3585
Svet Ganov82f09bc2018-01-12 22:08:40 -08003586 private static int resolveUid(String packageName) {
3587 if (packageName == null) {
3588 return -1;
3589 }
3590 switch (packageName) {
3591 case "root":
3592 return Process.ROOT_UID;
3593 case "shell":
3594 return Process.SHELL_UID;
3595 case "media":
3596 return Process.MEDIA_UID;
3597 case "audioserver":
3598 return Process.AUDIOSERVER_UID;
3599 case "cameraserver":
3600 return Process.CAMERASERVER_UID;
3601 }
3602 return -1;
3603 }
3604
Svet Ganov2af57082015-07-30 08:44:20 -07003605 private static String[] getPackagesForUid(int uid) {
Svet Ganovf3807aa2015-08-02 10:09:56 -07003606 String[] packageNames = null;
Svet Ganov2af57082015-07-30 08:44:20 -07003607 try {
riddle_hsu40b300f2015-11-23 13:22:03 +08003608 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
Svet Ganov2af57082015-07-30 08:44:20 -07003609 } catch (RemoteException e) {
3610 /* ignore - local call */
3611 }
Svet Ganovf3807aa2015-08-02 10:09:56 -07003612 if (packageNames == null) {
3613 return EmptyArray.STRING;
3614 }
3615 return packageNames;
Svet Ganov2af57082015-07-30 08:44:20 -07003616 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003617
3618 private final class ClientRestrictionState implements DeathRecipient {
3619 private final IBinder token;
3620 SparseArray<boolean[]> perUserRestrictions;
3621 SparseArray<String[]> perUserExcludedPackages;
3622
3623 public ClientRestrictionState(IBinder token)
3624 throws RemoteException {
3625 token.linkToDeath(this, 0);
3626 this.token = token;
3627 }
3628
3629 public boolean setRestriction(int code, boolean restricted,
3630 String[] excludedPackages, int userId) {
3631 boolean changed = false;
3632
3633 if (perUserRestrictions == null && restricted) {
3634 perUserRestrictions = new SparseArray<>();
3635 }
3636
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003637 int[] users;
3638 if (userId == UserHandle.USER_ALL) {
3639 List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003640
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003641 users = new int[liveUsers.size()];
3642 for (int i = 0; i < liveUsers.size(); i++) {
3643 users[i] = liveUsers.get(i).id;
3644 }
3645 } else {
3646 users = new int[]{userId};
3647 }
3648
3649 if (perUserRestrictions != null) {
3650 int numUsers = users.length;
3651
3652 for (int i = 0; i < numUsers; i++) {
3653 int thisUserId = users[i];
3654
3655 boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
3656 if (userRestrictions == null && restricted) {
3657 userRestrictions = new boolean[AppOpsManager._NUM_OP];
3658 perUserRestrictions.put(thisUserId, userRestrictions);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003659 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003660 if (userRestrictions != null && userRestrictions[code] != restricted) {
3661 userRestrictions[code] = restricted;
3662 if (!restricted && isDefault(userRestrictions)) {
3663 perUserRestrictions.remove(thisUserId);
3664 userRestrictions = null;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003665 }
3666 changed = true;
3667 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003668
3669 if (userRestrictions != null) {
3670 final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
3671 if (perUserExcludedPackages == null && !noExcludedPackages) {
3672 perUserExcludedPackages = new SparseArray<>();
3673 }
3674 if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
3675 perUserExcludedPackages.get(thisUserId))) {
3676 if (noExcludedPackages) {
3677 perUserExcludedPackages.remove(thisUserId);
3678 if (perUserExcludedPackages.size() <= 0) {
3679 perUserExcludedPackages = null;
3680 }
3681 } else {
3682 perUserExcludedPackages.put(thisUserId, excludedPackages);
3683 }
3684 changed = true;
3685 }
3686 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003687 }
3688 }
3689
3690 return changed;
3691 }
3692
3693 public boolean hasRestriction(int restriction, String packageName, int userId) {
3694 if (perUserRestrictions == null) {
3695 return false;
3696 }
3697 boolean[] restrictions = perUserRestrictions.get(userId);
3698 if (restrictions == null) {
3699 return false;
3700 }
3701 if (!restrictions[restriction]) {
3702 return false;
3703 }
3704 if (perUserExcludedPackages == null) {
3705 return true;
3706 }
3707 String[] perUserExclusions = perUserExcludedPackages.get(userId);
3708 if (perUserExclusions == null) {
3709 return true;
3710 }
3711 return !ArrayUtils.contains(perUserExclusions, packageName);
3712 }
3713
3714 public void removeUser(int userId) {
3715 if (perUserExcludedPackages != null) {
3716 perUserExcludedPackages.remove(userId);
3717 if (perUserExcludedPackages.size() <= 0) {
3718 perUserExcludedPackages = null;
3719 }
3720 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003721 if (perUserRestrictions != null) {
3722 perUserRestrictions.remove(userId);
3723 if (perUserRestrictions.size() <= 0) {
3724 perUserRestrictions = null;
3725 }
3726 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003727 }
3728
3729 public boolean isDefault() {
3730 return perUserRestrictions == null || perUserRestrictions.size() <= 0;
3731 }
3732
3733 @Override
3734 public void binderDied() {
3735 synchronized (AppOpsService.this) {
3736 mOpUserRestrictions.remove(token);
3737 if (perUserRestrictions == null) {
3738 return;
3739 }
3740 final int userCount = perUserRestrictions.size();
3741 for (int i = 0; i < userCount; i++) {
3742 final boolean[] restrictions = perUserRestrictions.valueAt(i);
3743 final int restrictionCount = restrictions.length;
3744 for (int j = 0; j < restrictionCount; j++) {
3745 if (restrictions[j]) {
3746 final int changedCode = j;
Svet Ganov3a95f832018-03-23 17:44:30 -07003747 mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003748 }
3749 }
3750 }
3751 destroy();
3752 }
3753 }
3754
3755 public void destroy() {
3756 token.unlinkToDeath(this, 0);
3757 }
3758
3759 private boolean isDefault(boolean[] array) {
3760 if (ArrayUtils.isEmpty(array)) {
3761 return true;
3762 }
3763 for (boolean value : array) {
3764 if (value) {
3765 return false;
3766 }
3767 }
3768 return true;
3769 }
3770 }
Dianne Hackbornd5254412018-05-11 18:02:58 -07003771
3772 private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
3773 @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
3774 synchronized (AppOpsService.this) {
3775 mProfileOwners = owners;
3776 }
3777 }
3778 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003779}