blob: b3f6bd1d41cc21528775efcee9f9600eb474a4f8 [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;
Svet Ganovd873ae62018-06-25 16:39:23 -070025import android.app.AppOpsManagerInternal.CheckOpsDelegate;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070026import android.content.ContentResolver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070027import android.content.Context;
28import android.content.pm.ApplicationInfo;
29import android.content.pm.IPackageManager;
30import android.content.pm.PackageManager;
31import android.content.pm.PackageManagerInternal;
32import android.content.pm.UserInfo;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070033import android.database.ContentObserver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070034import android.media.AudioAttributes;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070035import android.net.Uri;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070036import android.os.AsyncTask;
37import android.os.Binder;
38import android.os.Bundle;
39import android.os.Handler;
40import android.os.IBinder;
41import android.os.Process;
42import android.os.RemoteException;
43import android.os.ResultReceiver;
44import android.os.ServiceManager;
45import android.os.ShellCallback;
46import android.os.ShellCommand;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070047import android.os.SystemClock;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070048import android.os.UserHandle;
49import android.os.UserManager;
50import android.os.storage.StorageManagerInternal;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070051import android.provider.Settings;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070052import android.util.ArrayMap;
53import android.util.ArraySet;
54import android.util.AtomicFile;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070055import android.util.KeyValueListParser;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070056import android.util.Slog;
57import android.util.SparseArray;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -070058import android.util.SparseBooleanArray;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070059import android.util.SparseIntArray;
60import android.util.TimeUtils;
61import android.util.Xml;
62
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070063import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080064import com.android.internal.app.IAppOpsActiveCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070065import com.android.internal.app.IAppOpsCallback;
66import com.android.internal.app.IAppOpsService;
67import com.android.internal.os.Zygote;
68import com.android.internal.util.ArrayUtils;
69import com.android.internal.util.DumpUtils;
70import com.android.internal.util.FastXmlSerializer;
71import com.android.internal.util.Preconditions;
72import com.android.internal.util.XmlUtils;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080073import com.android.internal.util.function.pooled.PooledLambda;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -050074
Philip P. Moltmanne683f192017-06-23 14:05:04 -070075import libcore.util.EmptyArray;
76
77import org.xmlpull.v1.XmlPullParser;
78import org.xmlpull.v1.XmlPullParserException;
79import org.xmlpull.v1.XmlSerializer;
80
Dianne Hackborna06de0f2012-12-11 16:34:47 -080081import java.io.File;
82import java.io.FileDescriptor;
Dianne Hackborn35654b62013-01-14 17:38:02 -080083import java.io.FileInputStream;
84import java.io.FileNotFoundException;
85import java.io.FileOutputStream;
86import java.io.IOException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080087import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +010088import java.nio.charset.StandardCharsets;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070089import java.text.SimpleDateFormat;
Dianne Hackborn35654b62013-01-14 17:38:02 -080090import java.util.ArrayList;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -070091import java.util.Arrays;
Svetoslav215b44a2015-08-04 19:03:40 -070092import java.util.Collections;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070093import java.util.Date;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080094import java.util.HashMap;
Dianne Hackbornc2293022013-02-06 23:14:49 -080095import java.util.Iterator;
Dianne Hackborn35654b62013-01-14 17:38:02 -080096import java.util.List;
Dianne Hackborn607b4142013-08-02 18:10:10 -070097import java.util.Map;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080098
Dianne Hackborne93ab412018-05-14 17:52:30 -070099import static android.app.AppOpsManager._NUM_UID_STATE;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700100import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
101import static android.app.AppOpsManager.UID_STATE_CACHED;
102import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
103import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
Dianne Hackborne93ab412018-05-14 17:52:30 -0700104import static android.app.AppOpsManager.UID_STATE_LAST_NON_RESTRICTED;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700105import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
106import static android.app.AppOpsManager.UID_STATE_TOP;
107
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800108public class AppOpsService extends IAppOpsService.Stub {
109 static final String TAG = "AppOps";
Dianne Hackborn35654b62013-01-14 17:38:02 -0800110 static final boolean DEBUG = false;
111
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700112 private static final int NO_VERSION = -1;
113 /** Increment by one every time and add the corresponding upgrade logic in
114 * {@link #upgradeLocked(int)} below. The first version was 1 */
115 private static final int CURRENT_VERSION = 1;
116
Dianne Hackborn35654b62013-01-14 17:38:02 -0800117 // Write at most every 30 minutes.
118 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800119
Svet Ganov3a95f832018-03-23 17:44:30 -0700120 // Constant meaning that any UID should be matched when dispatching callbacks
121 private static final int UID_ANY = -2;
122
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700123 // Map from process states to the uid states we track.
124 private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
125 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
126 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
127 UID_STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
128 UID_STATE_FOREGROUND_SERVICE, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
129 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
130 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
131 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
132 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
133 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_BACKUP
134 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_SERVICE
135 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_RECEIVER
136 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
137 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
138 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HOME
139 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
140 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
141 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
142 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_RECENT
143 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
144 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT
145 };
146
147 static final String[] UID_STATE_NAMES = new String[] {
148 "pers ", // UID_STATE_PERSISTENT
149 "top ", // UID_STATE_TOP
150 "fgsvc", // UID_STATE_FOREGROUND_SERVICE
151 "fg ", // UID_STATE_FOREGROUND
152 "bg ", // UID_STATE_BACKGROUND
153 "cch ", // UID_STATE_CACHED
154 };
155
156 static final String[] UID_STATE_TIME_ATTRS = new String[] {
157 "tp", // UID_STATE_PERSISTENT
158 "tt", // UID_STATE_TOP
159 "tfs", // UID_STATE_FOREGROUND_SERVICE
160 "tf", // UID_STATE_FOREGROUND
161 "tb", // UID_STATE_BACKGROUND
162 "tc", // UID_STATE_CACHED
163 };
164
165 static final String[] UID_STATE_REJECT_ATTRS = new String[] {
166 "rp", // UID_STATE_PERSISTENT
167 "rt", // UID_STATE_TOP
168 "rfs", // UID_STATE_FOREGROUND_SERVICE
169 "rf", // UID_STATE_FOREGROUND
170 "rb", // UID_STATE_BACKGROUND
171 "rc", // UID_STATE_CACHED
172 };
173
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800174 Context mContext;
175 final AtomicFile mFile;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800176 final Handler mHandler;
177
Dianne Hackbornd5254412018-05-11 18:02:58 -0700178 private final AppOpsManagerInternalImpl mAppOpsManagerInternal
179 = new AppOpsManagerInternalImpl();
180
Dianne Hackborn35654b62013-01-14 17:38:02 -0800181 boolean mWriteScheduled;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800182 boolean mFastWriteScheduled;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800183 final Runnable mWriteRunner = new Runnable() {
184 public void run() {
185 synchronized (AppOpsService.this) {
186 mWriteScheduled = false;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800187 mFastWriteScheduled = false;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800188 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
189 @Override protected Void doInBackground(Void... params) {
190 writeState();
191 return null;
192 }
193 };
194 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
195 }
196 }
197 };
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800198
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700199 @VisibleForTesting
200 final SparseArray<UidState> mUidStates = new SparseArray<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800201
Dianne Hackborn9fb93502018-06-18 12:29:44 -0700202 long mLastRealtime;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700203
Ruben Brunk29931bc2016-03-11 00:24:26 -0800204 /*
205 * These are app op restrictions imposed per user from various parties.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800206 */
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700207 private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
Jason Monk62062992014-05-06 09:55:28 -0400208
Dianne Hackbornd5254412018-05-11 18:02:58 -0700209 SparseIntArray mProfileOwners;
210
Svet Ganovd873ae62018-06-25 16:39:23 -0700211 private CheckOpsDelegate mCheckOpsDelegate;
212
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700213 /**
214 * All times are in milliseconds. These constants are kept synchronized with the system
215 * global Settings. Any access to this class or its fields should be done while
216 * holding the AppOpsService lock.
217 */
218 private final class Constants extends ContentObserver {
219 // Key names stored in the settings value.
Dianne Hackborne93ab412018-05-14 17:52:30 -0700220 private static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
221 private static final String KEY_FG_SERVICE_STATE_SETTLE_TIME
222 = "fg_service_state_settle_time";
223 private static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700224
225 /**
Dianne Hackborne93ab412018-05-14 17:52:30 -0700226 * How long we want for a drop in uid state from top to settle before applying it.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700227 * @see Settings.Global#APP_OPS_CONSTANTS
Dianne Hackborne93ab412018-05-14 17:52:30 -0700228 * @see #KEY_TOP_STATE_SETTLE_TIME
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700229 */
Dianne Hackborne93ab412018-05-14 17:52:30 -0700230 public long TOP_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700231
Dianne Hackborne93ab412018-05-14 17:52:30 -0700232 /**
233 * How long we want for a drop in uid state from foreground to settle before applying it.
234 * @see Settings.Global#APP_OPS_CONSTANTS
235 * @see #KEY_FG_SERVICE_STATE_SETTLE_TIME
236 */
237 public long FG_SERVICE_STATE_SETTLE_TIME;
238
239 /**
240 * How long we want for a drop in uid state from background to settle before applying it.
241 * @see Settings.Global#APP_OPS_CONSTANTS
242 * @see #KEY_BG_STATE_SETTLE_TIME
243 */
244 public long BG_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700245
246 private final KeyValueListParser mParser = new KeyValueListParser(',');
247 private ContentResolver mResolver;
248
249 public Constants(Handler handler) {
250 super(handler);
251 updateConstants();
252 }
253
254 public void startMonitoring(ContentResolver resolver) {
255 mResolver = resolver;
256 mResolver.registerContentObserver(
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700257 Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700258 false, this);
259 updateConstants();
260 }
261
262 @Override
263 public void onChange(boolean selfChange, Uri uri) {
264 updateConstants();
265 }
266
267 private void updateConstants() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700268 String value = mResolver != null ? Settings.Global.getString(mResolver,
269 Settings.Global.APP_OPS_CONSTANTS) : "";
270
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700271 synchronized (AppOpsService.this) {
272 try {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700273 mParser.setString(value);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700274 } catch (IllegalArgumentException e) {
275 // Failed to parse the settings string, log this and move on
276 // with defaults.
277 Slog.e(TAG, "Bad app ops settings", e);
278 }
Dianne Hackborne93ab412018-05-14 17:52:30 -0700279 TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
280 KEY_TOP_STATE_SETTLE_TIME, 30 * 1000L);
281 FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
282 KEY_FG_SERVICE_STATE_SETTLE_TIME, 10 * 1000L);
283 BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
284 KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700285 }
286 }
287
288 void dump(PrintWriter pw) {
289 pw.println(" Settings:");
290
Dianne Hackborne93ab412018-05-14 17:52:30 -0700291 pw.print(" "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("=");
292 TimeUtils.formatDuration(TOP_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_FG_SERVICE_STATE_SETTLE_TIME); pw.print("=");
295 TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700296 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700297 pw.print(" "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("=");
298 TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700299 pw.println();
300 }
301 }
302
303 private final Constants mConstants;
304
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700305 @VisibleForTesting
306 static final class UidState {
Svet Ganov2af57082015-07-30 08:44:20 -0700307 public final int uid;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700308
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700309 public int state = UID_STATE_CACHED;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700310 public int pendingState = UID_STATE_CACHED;
311 public long pendingStateCommitTime;
312
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700313 public int startNesting;
Svet Ganov2af57082015-07-30 08:44:20 -0700314 public ArrayMap<String, Ops> pkgOps;
315 public SparseIntArray opModes;
316
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700317 // true indicates there is an interested observer, false there isn't but it has such an op
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700318 public SparseBooleanArray foregroundOps;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700319 public boolean hasForegroundWatchers;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700320
Svet Ganov2af57082015-07-30 08:44:20 -0700321 public UidState(int uid) {
322 this.uid = uid;
323 }
324
325 public void clear() {
326 pkgOps = null;
327 opModes = null;
328 }
329
330 public boolean isDefault() {
331 return (pkgOps == null || pkgOps.isEmpty())
332 && (opModes == null || opModes.size() <= 0);
333 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700334
335 int evalMode(int mode) {
336 if (mode == AppOpsManager.MODE_FOREGROUND) {
Dianne Hackborne93ab412018-05-14 17:52:30 -0700337 return state <= UID_STATE_LAST_NON_RESTRICTED
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700338 ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
339 }
340 return mode;
341 }
342
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700343 private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
344 SparseBooleanArray which) {
345 boolean curValue = which.get(op, false);
346 ArraySet<ModeCallback> callbacks = watchers.get(op);
347 if (callbacks != null) {
348 for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
349 if ((callbacks.valueAt(cbi).mFlags
350 & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
351 hasForegroundWatchers = true;
352 curValue = true;
353 }
354 }
355 }
356 which.put(op, curValue);
357 }
358
359 public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700360 SparseBooleanArray which = null;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700361 hasForegroundWatchers = false;
362 if (opModes != null) {
363 for (int i = opModes.size() - 1; i >= 0; i--) {
364 if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
365 if (which == null) {
366 which = new SparseBooleanArray();
367 }
368 evalForegroundWatchers(opModes.keyAt(i), watchers, which);
369 }
370 }
371 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700372 if (pkgOps != null) {
373 for (int i = pkgOps.size() - 1; i >= 0; i--) {
374 Ops ops = pkgOps.valueAt(i);
375 for (int j = ops.size() - 1; j >= 0; j--) {
376 if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
377 if (which == null) {
378 which = new SparseBooleanArray();
379 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700380 evalForegroundWatchers(ops.keyAt(j), watchers, which);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700381 }
382 }
383 }
384 }
385 foregroundOps = which;
386 }
Svet Ganov2af57082015-07-30 08:44:20 -0700387 }
388
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700389 final static class Ops extends SparseArray<Op> {
390 final String packageName;
391 final UidState uidState;
392 final boolean isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800393
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700394 Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800395 packageName = _packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700396 uidState = _uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400397 isPrivileged = _isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800398 }
399 }
400
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700401 final static class Op {
402 final UidState uidState;
403 final int uid;
404 final String packageName;
405 final int op;
406 int proxyUid = -1;
407 String proxyPackageName;
408 int mode;
409 int duration;
410 long time[] = new long[_NUM_UID_STATE];
411 long rejectTime[] = new long[_NUM_UID_STATE];
412 int startNesting;
413 long startRealtime;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800414
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700415 Op(UidState _uidState, String _packageName, int _op) {
416 uidState = _uidState;
417 uid = _uidState.uid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700418 packageName = _packageName;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800419 op = _op;
David Braunf5d83192013-09-16 13:43:51 -0700420 mode = AppOpsManager.opToDefaultMode(op);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800421 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700422
423 boolean hasAnyTime() {
424 for (int i = 0; i < AppOpsManager._NUM_UID_STATE; i++) {
425 if (time[i] != 0) {
426 return true;
427 }
428 if (rejectTime[i] != 0) {
429 return true;
430 }
431 }
432 return false;
433 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700434
435 int getMode() {
436 return uidState.evalMode(mode);
437 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800438 }
439
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800440 final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
441 final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
442 final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
443 final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
Dianne Hackborn68d76552017-02-27 15:32:03 -0800444 final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800445
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700446 final class ModeCallback implements DeathRecipient {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800447 final IAppOpsCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700448 final int mWatchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700449 final int mFlags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700450 final int mCallingUid;
451 final int mCallingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800452
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700453 ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700454 int callingPid) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800455 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700456 mWatchingUid = watchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700457 mFlags = flags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700458 mCallingUid = callingUid;
459 mCallingPid = callingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800460 try {
461 mCallback.asBinder().linkToDeath(this, 0);
462 } catch (RemoteException e) {
463 }
464 }
465
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700466 public boolean isWatchingUid(int uid) {
467 return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
468 }
469
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700470 @Override
471 public String toString() {
472 StringBuilder sb = new StringBuilder(128);
473 sb.append("ModeCallback{");
474 sb.append(Integer.toHexString(System.identityHashCode(this)));
475 sb.append(" watchinguid=");
476 UserHandle.formatUid(sb, mWatchingUid);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700477 sb.append(" flags=0x");
478 sb.append(Integer.toHexString(mFlags));
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700479 sb.append(" from uid=");
480 UserHandle.formatUid(sb, mCallingUid);
481 sb.append(" pid=");
482 sb.append(mCallingPid);
483 sb.append('}');
484 return sb.toString();
485 }
486
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700487 void unlinkToDeath() {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800488 mCallback.asBinder().unlinkToDeath(this, 0);
489 }
490
491 @Override
492 public void binderDied() {
493 stopWatchingMode(mCallback);
494 }
495 }
496
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700497 final class ActiveCallback implements DeathRecipient {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800498 final IAppOpsActiveCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700499 final int mWatchingUid;
500 final int mCallingUid;
501 final int mCallingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800502
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700503 ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700504 int callingPid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800505 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700506 mWatchingUid = watchingUid;
507 mCallingUid = callingUid;
508 mCallingPid = callingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800509 try {
510 mCallback.asBinder().linkToDeath(this, 0);
511 } catch (RemoteException e) {
512 }
513 }
514
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700515 @Override
516 public String toString() {
517 StringBuilder sb = new StringBuilder(128);
518 sb.append("ActiveCallback{");
519 sb.append(Integer.toHexString(System.identityHashCode(this)));
520 sb.append(" watchinguid=");
521 UserHandle.formatUid(sb, mWatchingUid);
522 sb.append(" from uid=");
523 UserHandle.formatUid(sb, mCallingUid);
524 sb.append(" pid=");
525 sb.append(mCallingPid);
526 sb.append('}');
527 return sb.toString();
528 }
529
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700530 void destroy() {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800531 mCallback.asBinder().unlinkToDeath(this, 0);
532 }
533
534 @Override
535 public void binderDied() {
536 stopWatchingActive(mCallback);
537 }
538 }
539
Svet Ganova7a0db62018-02-27 20:08:01 -0800540 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700541
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700542 final class ClientState extends Binder implements DeathRecipient {
Svet Ganovf7b47252018-02-26 11:11:27 -0800543 final ArrayList<Op> mStartedOps = new ArrayList<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700544 final IBinder mAppToken;
545 final int mPid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700546
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700547 ClientState(IBinder appToken) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700548 mAppToken = appToken;
549 mPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -0800550 // Watch only for remote processes dying
551 if (!(appToken instanceof Binder)) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700552 try {
553 mAppToken.linkToDeath(this, 0);
554 } catch (RemoteException e) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800555 /* do nothing */
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700556 }
557 }
558 }
559
560 @Override
561 public String toString() {
562 return "ClientState{" +
563 "mAppToken=" + mAppToken +
Svet Ganovf7b47252018-02-26 11:11:27 -0800564 ", " + "pid=" + mPid +
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700565 '}';
566 }
567
568 @Override
569 public void binderDied() {
570 synchronized (AppOpsService.this) {
571 for (int i=mStartedOps.size()-1; i>=0; i--) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800572 finishOperationLocked(mStartedOps.get(i), /*finishNested*/ true);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700573 }
574 mClients.remove(mAppToken);
575 }
576 }
577 }
578
Jeff Brown6f357d32014-01-15 20:40:55 -0800579 public AppOpsService(File storagePath, Handler handler) {
Jeff Sharkey5f3e9342017-03-13 14:53:11 -0600580 LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
Dianne Hackborne17b4452018-01-10 13:15:40 -0800581 mFile = new AtomicFile(storagePath, "appops");
Jeff Brown6f357d32014-01-15 20:40:55 -0800582 mHandler = handler;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700583 mConstants = new Constants(mHandler);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800584 readState();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800585 }
David Braunf5d83192013-09-16 13:43:51 -0700586
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800587 public void publish(Context context) {
588 mContext = context;
589 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
Dianne Hackbornd5254412018-05-11 18:02:58 -0700590 LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800591 }
592
Dianne Hackborn514074f2013-02-11 10:52:46 -0800593 public void systemReady() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700594 mConstants.startMonitoring(mContext.getContentResolver());
595
Dianne Hackborn514074f2013-02-11 10:52:46 -0800596 synchronized (this) {
597 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700598 for (int i = mUidStates.size() - 1; i >= 0; i--) {
599 UidState uidState = mUidStates.valueAt(i);
600
601 String[] packageNames = getPackagesForUid(uidState.uid);
602 if (ArrayUtils.isEmpty(packageNames)) {
603 uidState.clear();
604 mUidStates.removeAt(i);
605 changed = true;
606 continue;
607 }
608
609 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
610 if (pkgs == null) {
611 continue;
612 }
613
Dianne Hackborn514074f2013-02-11 10:52:46 -0800614 Iterator<Ops> it = pkgs.values().iterator();
615 while (it.hasNext()) {
616 Ops ops = it.next();
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700617 int curUid = -1;
Dianne Hackborn514074f2013-02-11 10:52:46 -0800618 try {
Jeff Sharkeycd654482016-01-08 17:42:11 -0700619 curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
620 PackageManager.MATCH_UNINSTALLED_PACKAGES,
Svet Ganov2af57082015-07-30 08:44:20 -0700621 UserHandle.getUserId(ops.uidState.uid));
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700622 } catch (RemoteException ignored) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800623 }
Svet Ganov2af57082015-07-30 08:44:20 -0700624 if (curUid != ops.uidState.uid) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800625 Slog.i(TAG, "Pruning old package " + ops.packageName
Svet Ganov2af57082015-07-30 08:44:20 -0700626 + "/" + ops.uidState + ": new uid=" + curUid);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800627 it.remove();
628 changed = true;
629 }
630 }
Svet Ganov2af57082015-07-30 08:44:20 -0700631
632 if (uidState.isDefault()) {
633 mUidStates.removeAt(i);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800634 }
635 }
636 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800637 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800638 }
639 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700640
Suprabh Shuklaaef25132017-01-23 18:09:03 -0800641 PackageManagerInternal packageManagerInternal = LocalServices.getService(
642 PackageManagerInternal.class);
643 packageManagerInternal.setExternalSourcesPolicy(
644 new PackageManagerInternal.ExternalSourcesPolicy() {
645 @Override
646 public int getPackageTrustedToInstallApps(String packageName, int uid) {
647 int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
648 uid, packageName);
649 switch (appOpMode) {
650 case AppOpsManager.MODE_ALLOWED:
651 return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
652 case AppOpsManager.MODE_ERRORED:
653 return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
654 default:
655 return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
656 }
657 }
658 });
659
Sudheer Shanka2250d562016-11-07 15:41:02 -0800660 StorageManagerInternal storageManagerInternal = LocalServices.getService(
661 StorageManagerInternal.class);
662 storageManagerInternal.addExternalStoragePolicy(
663 new StorageManagerInternal.ExternalStorageMountPolicy() {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700664 @Override
665 public int getMountMode(int uid, String packageName) {
666 if (Process.isIsolated(uid)) {
667 return Zygote.MOUNT_EXTERNAL_NONE;
668 }
669 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
670 packageName) != AppOpsManager.MODE_ALLOWED) {
671 return Zygote.MOUNT_EXTERNAL_NONE;
672 }
673 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
674 packageName) != AppOpsManager.MODE_ALLOWED) {
675 return Zygote.MOUNT_EXTERNAL_READ;
676 }
677 return Zygote.MOUNT_EXTERNAL_WRITE;
678 }
679
680 @Override
681 public boolean hasExternalStorage(int uid, String packageName) {
682 final int mountMode = getMountMode(uid, packageName);
683 return mountMode == Zygote.MOUNT_EXTERNAL_READ
684 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
685 }
686 });
Dianne Hackborn514074f2013-02-11 10:52:46 -0800687 }
688
689 public void packageRemoved(int uid, String packageName) {
690 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700691 UidState uidState = mUidStates.get(uid);
692 if (uidState == null) {
693 return;
694 }
695
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800696 Ops ops = null;
Svet Ganov2af57082015-07-30 08:44:20 -0700697
698 // Remove any package state if such.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800699 if (uidState.pkgOps != null) {
700 ops = uidState.pkgOps.remove(packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700701 }
702
703 // If we just nuked the last package state check if the UID is valid.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800704 if (ops != null && uidState.pkgOps.isEmpty()
Svet Ganov2af57082015-07-30 08:44:20 -0700705 && getPackagesForUid(uid).length <= 0) {
706 mUidStates.remove(uid);
707 }
708
Svet Ganova7a0db62018-02-27 20:08:01 -0800709 // Finish ops other packages started on behalf of the package.
710 final int clientCount = mClients.size();
711 for (int i = 0; i < clientCount; i++) {
712 final ClientState client = mClients.valueAt(i);
713 if (client.mStartedOps == null) {
714 continue;
715 }
716 final int opCount = client.mStartedOps.size();
717 for (int j = opCount - 1; j >= 0; j--) {
718 final Op op = client.mStartedOps.get(j);
719 if (uid == op.uid && packageName.equals(op.packageName)) {
720 finishOperationLocked(op, /*finishNested*/ true);
721 client.mStartedOps.remove(j);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700722 if (op.startNesting <= 0) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800723 scheduleOpActiveChangedIfNeededLocked(op.op,
724 uid, packageName, false);
725 }
726 }
727 }
728 }
729
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800730 if (ops != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700731 scheduleFastWriteLocked();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800732
733 final int opCount = ops.size();
734 for (int i = 0; i < opCount; i++) {
735 final Op op = ops.valueAt(i);
736 if (op.duration == -1) {
737 scheduleOpActiveChangedIfNeededLocked(
738 op.op, op.uid, op.packageName, false);
739 }
740 }
Dianne Hackborn514074f2013-02-11 10:52:46 -0800741 }
742 }
743 }
744
745 public void uidRemoved(int uid) {
746 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700747 if (mUidStates.indexOfKey(uid) >= 0) {
748 mUidStates.remove(uid);
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800749 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800750 }
751 }
752 }
753
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700754 public void updateUidProcState(int uid, int procState) {
755 synchronized (this) {
756 final UidState uidState = getUidStateLocked(uid, true);
757 final int newState = PROCESS_STATE_TO_UID_STATE[procState];
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700758 if (uidState != null && uidState.pendingState != newState) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700759 final int oldPendingState = uidState.pendingState;
760 uidState.pendingState = newState;
Dianne Hackborne93ab412018-05-14 17:52:30 -0700761 if (newState < uidState.state || newState <= UID_STATE_LAST_NON_RESTRICTED) {
762 // We are moving to a more important state, or the new state is in the
763 // foreground, then always do it immediately.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700764 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700765 } else if (uidState.pendingStateCommitTime == 0) {
766 // We are moving to a less important state for the first time,
767 // delay the application for a bit.
Dianne Hackborne93ab412018-05-14 17:52:30 -0700768 final long settleTime;
769 if (uidState.state <= UID_STATE_TOP) {
770 settleTime = mConstants.TOP_STATE_SETTLE_TIME;
771 } else if (uidState.state <= UID_STATE_FOREGROUND_SERVICE) {
772 settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
773 } else {
774 settleTime = mConstants.BG_STATE_SETTLE_TIME;
775 }
Dianne Hackborn9fb93502018-06-18 12:29:44 -0700776 uidState.pendingStateCommitTime = SystemClock.elapsedRealtime() + settleTime;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700777 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700778 if (uidState.startNesting != 0) {
779 // There is some actively running operation... need to find it
780 // and appropriately update its state.
781 final long now = System.currentTimeMillis();
782 for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
783 final Ops ops = uidState.pkgOps.valueAt(i);
784 for (int j = ops.size() - 1; j >= 0; j--) {
785 final Op op = ops.valueAt(j);
786 if (op.startNesting > 0) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700787 op.time[oldPendingState] = now;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700788 op.time[newState] = now;
789 }
790 }
791 }
792 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700793 }
794 }
795 }
796
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800797 public void shutdown() {
798 Slog.w(TAG, "Writing app ops before shutdown...");
Dianne Hackborn35654b62013-01-14 17:38:02 -0800799 boolean doWrite = false;
800 synchronized (this) {
801 if (mWriteScheduled) {
802 mWriteScheduled = false;
803 doWrite = true;
804 }
805 }
806 if (doWrite) {
807 writeState();
808 }
809 }
810
Dianne Hackborn72e39832013-01-18 18:36:09 -0800811 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
812 ArrayList<AppOpsManager.OpEntry> resOps = null;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700813 final long elapsedNow = SystemClock.elapsedRealtime();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800814 if (ops == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700815 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800816 for (int j=0; j<pkgOps.size(); j++) {
817 Op curOp = pkgOps.valueAt(j);
Amith Yamasania1ce9632018-05-28 20:50:48 -0700818 final boolean running = curOp.duration == -1;
819 long duration = running
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700820 ? (elapsedNow - curOp.startRealtime)
821 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800822 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Amith Yamasania1ce9632018-05-28 20:50:48 -0700823 curOp.rejectTime, (int) duration, running, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700824 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800825 }
826 } else {
827 for (int j=0; j<ops.length; j++) {
828 Op curOp = pkgOps.get(ops[j]);
829 if (curOp != null) {
830 if (resOps == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700831 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800832 }
Amith Yamasania1ce9632018-05-28 20:50:48 -0700833 final boolean running = curOp.duration == -1;
834 final long duration = running
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700835 ? (elapsedNow - curOp.startRealtime)
836 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800837 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Amith Yamasania1ce9632018-05-28 20:50:48 -0700838 curOp.rejectTime, (int) duration, running, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700839 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800840 }
841 }
842 }
843 return resOps;
844 }
845
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700846 private ArrayList<AppOpsManager.OpEntry> collectOps(SparseIntArray uidOps, int[] ops) {
847 ArrayList<AppOpsManager.OpEntry> resOps = null;
848 if (ops == null) {
849 resOps = new ArrayList<>();
850 for (int j=0; j<uidOps.size(); j++) {
851 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(j), uidOps.valueAt(j),
852 0, 0, 0, -1, null));
853 }
854 } else {
855 for (int j=0; j<ops.length; j++) {
856 int index = uidOps.indexOfKey(ops[j]);
857 if (index >= 0) {
858 if (resOps == null) {
859 resOps = new ArrayList<>();
860 }
861 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(index), uidOps.valueAt(index),
862 0, 0, 0, -1, null));
863 }
864 }
865 }
866 return resOps;
867 }
868
Dianne Hackborn35654b62013-01-14 17:38:02 -0800869 @Override
870 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
871 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
872 Binder.getCallingPid(), Binder.getCallingUid(), null);
873 ArrayList<AppOpsManager.PackageOps> res = null;
874 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700875 final int uidStateCount = mUidStates.size();
876 for (int i = 0; i < uidStateCount; i++) {
877 UidState uidState = mUidStates.valueAt(i);
878 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
879 continue;
880 }
881 ArrayMap<String, Ops> packages = uidState.pkgOps;
882 final int packageCount = packages.size();
883 for (int j = 0; j < packageCount; j++) {
884 Ops pkgOps = packages.valueAt(j);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800885 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800886 if (resOps != null) {
887 if (res == null) {
888 res = new ArrayList<AppOpsManager.PackageOps>();
889 }
890 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700891 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800892 res.add(resPackage);
893 }
894 }
895 }
896 }
897 return res;
898 }
899
900 @Override
Dianne Hackborn72e39832013-01-18 18:36:09 -0800901 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
902 int[] ops) {
903 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
904 Binder.getCallingPid(), Binder.getCallingUid(), null);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000905 String resolvedPackageName = resolvePackageName(uid, packageName);
906 if (resolvedPackageName == null) {
907 return Collections.emptyList();
908 }
Dianne Hackborn72e39832013-01-18 18:36:09 -0800909 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -0700910 Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
911 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800912 if (pkgOps == null) {
913 return null;
914 }
915 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
916 if (resOps == null) {
917 return null;
918 }
919 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
920 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700921 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800922 res.add(resPackage);
923 return res;
924 }
925 }
926
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700927 @Override
928 public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
929 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
930 Binder.getCallingPid(), Binder.getCallingUid(), null);
931 synchronized (this) {
932 UidState uidState = getUidStateLocked(uid, false);
933 if (uidState == null) {
934 return null;
935 }
936 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState.opModes, ops);
937 if (resOps == null) {
938 return null;
939 }
940 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
941 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
942 null, uidState.uid, resOps);
943 res.add(resPackage);
944 return res;
945 }
946 }
947
Dianne Hackborn607b4142013-08-02 18:10:10 -0700948 private void pruneOp(Op op, int uid, String packageName) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700949 if (!op.hasAnyTime()) {
Yohei Yukawaa965d652017-10-12 15:02:26 -0700950 Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
951 false /* uidMismatchExpected */);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700952 if (ops != null) {
953 ops.remove(op.op);
954 if (ops.size() <= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -0700955 UidState uidState = ops.uidState;
956 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700957 if (pkgOps != null) {
958 pkgOps.remove(ops.packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700959 if (pkgOps.isEmpty()) {
960 uidState.pkgOps = null;
961 }
962 if (uidState.isDefault()) {
963 mUidStates.remove(uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700964 }
965 }
966 }
967 }
968 }
969 }
970
Dianne Hackbornd5254412018-05-11 18:02:58 -0700971 void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
972 if (callingPid == Process.myPid()) {
973 return;
974 }
975 final int callingUser = UserHandle.getUserId(callingUid);
976 synchronized (this) {
977 if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
978 if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
979 // Profile owners are allowed to change modes but only for apps
980 // within their user.
981 return;
982 }
983 }
984 }
985 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
986 Binder.getCallingPid(), Binder.getCallingUid(), null);
987 }
988
Dianne Hackborn72e39832013-01-18 18:36:09 -0800989 @Override
Svet Ganov2af57082015-07-30 08:44:20 -0700990 public void setUidMode(int code, int uid, int mode) {
Dianne Hackbornd5254412018-05-11 18:02:58 -0700991 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Svet Ganov2af57082015-07-30 08:44:20 -0700992 verifyIncomingOp(code);
993 code = AppOpsManager.opToSwitch(code);
994
995 synchronized (this) {
996 final int defaultMode = AppOpsManager.opToDefaultMode(code);
997
998 UidState uidState = getUidStateLocked(uid, false);
999 if (uidState == null) {
1000 if (mode == defaultMode) {
1001 return;
1002 }
1003 uidState = new UidState(uid);
1004 uidState.opModes = new SparseIntArray();
1005 uidState.opModes.put(code, mode);
1006 mUidStates.put(uid, uidState);
1007 scheduleWriteLocked();
1008 } else if (uidState.opModes == null) {
1009 if (mode != defaultMode) {
1010 uidState.opModes = new SparseIntArray();
1011 uidState.opModes.put(code, mode);
1012 scheduleWriteLocked();
1013 }
1014 } else {
1015 if (uidState.opModes.get(code) == mode) {
1016 return;
1017 }
1018 if (mode == defaultMode) {
1019 uidState.opModes.delete(code);
1020 if (uidState.opModes.size() <= 0) {
1021 uidState.opModes = null;
1022 }
1023 } else {
1024 uidState.opModes.put(code, mode);
1025 }
1026 scheduleWriteLocked();
1027 }
1028 }
1029
Svetoslav215b44a2015-08-04 19:03:40 -07001030 String[] uidPackageNames = getPackagesForUid(uid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001031 ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
Svet Ganov2af57082015-07-30 08:44:20 -07001032
riddle_hsu40b300f2015-11-23 13:22:03 +08001033 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001034 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001035 if (callbacks != null) {
Svet Ganov2af57082015-07-30 08:44:20 -07001036 final int callbackCount = callbacks.size();
1037 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001038 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08001039 ArraySet<String> changedPackages = new ArraySet<>();
1040 Collections.addAll(changedPackages, uidPackageNames);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001041 if (callbackSpecs == null) {
1042 callbackSpecs = new ArrayMap<>();
1043 }
riddle_hsu40b300f2015-11-23 13:22:03 +08001044 callbackSpecs.put(callback, changedPackages);
1045 }
1046 }
1047
1048 for (String uidPackageName : uidPackageNames) {
1049 callbacks = mPackageModeWatchers.get(uidPackageName);
1050 if (callbacks != null) {
1051 if (callbackSpecs == null) {
1052 callbackSpecs = new ArrayMap<>();
Svet Ganov2af57082015-07-30 08:44:20 -07001053 }
riddle_hsu40b300f2015-11-23 13:22:03 +08001054 final int callbackCount = callbacks.size();
1055 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001056 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08001057 ArraySet<String> changedPackages = callbackSpecs.get(callback);
1058 if (changedPackages == null) {
1059 changedPackages = new ArraySet<>();
1060 callbackSpecs.put(callback, changedPackages);
1061 }
1062 changedPackages.add(uidPackageName);
1063 }
Svet Ganov2af57082015-07-30 08:44:20 -07001064 }
1065 }
1066 }
1067
1068 if (callbackSpecs == null) {
1069 return;
1070 }
1071
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001072 for (int i = 0; i < callbackSpecs.size(); i++) {
1073 final ModeCallback callback = callbackSpecs.keyAt(i);
1074 final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
1075 if (reportedPackageNames == null) {
1076 mHandler.sendMessage(PooledLambda.obtainMessage(
1077 AppOpsService::notifyOpChanged,
1078 this, callback, code, uid, (String) null));
1079
1080 } else {
1081 final int reportedPackageCount = reportedPackageNames.size();
1082 for (int j = 0; j < reportedPackageCount; j++) {
1083 final String reportedPackageName = reportedPackageNames.valueAt(j);
1084 mHandler.sendMessage(PooledLambda.obtainMessage(
1085 AppOpsService::notifyOpChanged,
1086 this, callback, code, uid, reportedPackageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001087 }
1088 }
Svet Ganov2af57082015-07-30 08:44:20 -07001089 }
1090 }
1091
1092 @Override
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001093 public void setMode(int code, int uid, String packageName, int mode) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001094 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001095 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001096 ArraySet<ModeCallback> repCbs = null;
Dianne Hackbornc2293022013-02-06 23:14:49 -08001097 code = AppOpsManager.opToSwitch(code);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001098 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001099 UidState uidState = getUidStateLocked(uid, false);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001100 Op op = getOpLocked(code, uid, packageName, true);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001101 if (op != null) {
1102 if (op.mode != mode) {
1103 op.mode = mode;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001104 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001105 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001106 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001107 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001108 if (cbs != null) {
1109 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001110 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001111 }
1112 repCbs.addAll(cbs);
1113 }
1114 cbs = mPackageModeWatchers.get(packageName);
1115 if (cbs != null) {
1116 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001117 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001118 }
1119 repCbs.addAll(cbs);
1120 }
David Braunf5d83192013-09-16 13:43:51 -07001121 if (mode == AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001122 // If going into the default mode, prune this op
1123 // if there is nothing else interesting in it.
Dianne Hackborn607b4142013-08-02 18:10:10 -07001124 pruneOp(op, uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001125 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001126 scheduleFastWriteLocked();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001127 }
1128 }
1129 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001130 if (repCbs != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001131 mHandler.sendMessage(PooledLambda.obtainMessage(
1132 AppOpsService::notifyOpChanged,
1133 this, repCbs, code, uid, packageName));
Dianne Hackbornc2293022013-02-06 23:14:49 -08001134 }
1135 }
1136
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001137 private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
1138 int uid, String packageName) {
1139 for (int i = 0; i < callbacks.size(); i++) {
1140 final ModeCallback callback = callbacks.valueAt(i);
1141 notifyOpChanged(callback, code, uid, packageName);
1142 }
1143 }
1144
1145 private void notifyOpChanged(ModeCallback callback, int code,
1146 int uid, String packageName) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001147 if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001148 return;
1149 }
1150 // There are components watching for mode changes such as window manager
1151 // and location manager which are in our process. The callbacks in these
1152 // components may require permissions our remote caller does not have.
1153 final long identity = Binder.clearCallingIdentity();
1154 try {
1155 callback.mCallback.opChanged(code, uid, packageName);
1156 } catch (RemoteException e) {
1157 /* ignore */
1158 } finally {
1159 Binder.restoreCallingIdentity(identity);
1160 }
1161 }
1162
1163 private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
1164 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
1165 int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001166 if (cbs == null) {
1167 return callbacks;
1168 }
1169 if (callbacks == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001170 callbacks = new HashMap<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001171 }
Svet Ganov2af57082015-07-30 08:44:20 -07001172 boolean duplicate = false;
Dianne Hackborn68d76552017-02-27 15:32:03 -08001173 final int N = cbs.size();
1174 for (int i=0; i<N; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001175 ModeCallback cb = cbs.valueAt(i);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001176 ArrayList<ChangeRec> reports = callbacks.get(cb);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001177 if (reports == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001178 reports = new ArrayList<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001179 callbacks.put(cb, reports);
Svet Ganov2af57082015-07-30 08:44:20 -07001180 } else {
1181 final int reportCount = reports.size();
1182 for (int j = 0; j < reportCount; j++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001183 ChangeRec report = reports.get(j);
1184 if (report.op == op && report.pkg.equals(packageName)) {
Svet Ganov2af57082015-07-30 08:44:20 -07001185 duplicate = true;
1186 break;
1187 }
1188 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001189 }
Svet Ganov2af57082015-07-30 08:44:20 -07001190 if (!duplicate) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001191 reports.add(new ChangeRec(op, uid, packageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001192 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001193 }
1194 return callbacks;
1195 }
1196
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001197 static final class ChangeRec {
1198 final int op;
1199 final int uid;
1200 final String pkg;
1201
1202 ChangeRec(int _op, int _uid, String _pkg) {
1203 op = _op;
1204 uid = _uid;
1205 pkg = _pkg;
1206 }
1207 }
1208
Dianne Hackborn607b4142013-08-02 18:10:10 -07001209 @Override
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001210 public void resetAllModes(int reqUserId, String reqPackageName) {
1211 final int callingPid = Binder.getCallingPid();
1212 final int callingUid = Binder.getCallingUid();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001213 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
1214 true, true, "resetAllModes", null);
Svet Ganov2af57082015-07-30 08:44:20 -07001215
1216 int reqUid = -1;
1217 if (reqPackageName != null) {
1218 try {
1219 reqUid = AppGlobals.getPackageManager().getPackageUid(
Jeff Sharkeycd654482016-01-08 17:42:11 -07001220 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
Svet Ganov2af57082015-07-30 08:44:20 -07001221 } catch (RemoteException e) {
1222 /* ignore - local call */
1223 }
1224 }
1225
Dianne Hackbornd5254412018-05-11 18:02:58 -07001226 enforceManageAppOpsModes(callingPid, callingUid, reqUid);
1227
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001228 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001229 synchronized (this) {
1230 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -07001231 for (int i = mUidStates.size() - 1; i >= 0; i--) {
1232 UidState uidState = mUidStates.valueAt(i);
1233
1234 SparseIntArray opModes = uidState.opModes;
1235 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
1236 final int uidOpCount = opModes.size();
1237 for (int j = uidOpCount - 1; j >= 0; j--) {
1238 final int code = opModes.keyAt(j);
1239 if (AppOpsManager.opAllowsReset(code)) {
1240 opModes.removeAt(j);
1241 if (opModes.size() <= 0) {
1242 uidState.opModes = null;
1243 }
1244 for (String packageName : getPackagesForUid(uidState.uid)) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001245 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001246 mOpModeWatchers.get(code));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001247 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001248 mPackageModeWatchers.get(packageName));
1249 }
1250 }
1251 }
1252 }
1253
1254 if (uidState.pkgOps == null) {
1255 continue;
1256 }
1257
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001258 if (reqUserId != UserHandle.USER_ALL
Svet Ganov2af57082015-07-30 08:44:20 -07001259 && reqUserId != UserHandle.getUserId(uidState.uid)) {
Alexandra Gherghinad6a98972014-08-04 17:05:34 +01001260 // Skip any ops for a different user
1261 continue;
1262 }
Svet Ganov2af57082015-07-30 08:44:20 -07001263
1264 Map<String, Ops> packages = uidState.pkgOps;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001265 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001266 boolean uidChanged = false;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001267 while (it.hasNext()) {
1268 Map.Entry<String, Ops> ent = it.next();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001269 String packageName = ent.getKey();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001270 if (reqPackageName != null && !reqPackageName.equals(packageName)) {
1271 // Skip any ops for a different package
1272 continue;
1273 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001274 Ops pkgOps = ent.getValue();
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001275 for (int j=pkgOps.size()-1; j>=0; j--) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001276 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn8828d3a2013-09-25 16:47:10 -07001277 if (AppOpsManager.opAllowsReset(curOp.op)
1278 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
David Braunf5d83192013-09-16 13:43:51 -07001279 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001280 changed = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001281 uidChanged = true;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001282 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001283 mOpModeWatchers.get(curOp.op));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001284 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001285 mPackageModeWatchers.get(packageName));
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001286 if (!curOp.hasAnyTime()) {
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001287 pkgOps.removeAt(j);
1288 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001289 }
1290 }
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001291 if (pkgOps.size() == 0) {
1292 it.remove();
1293 }
1294 }
Svet Ganov2af57082015-07-30 08:44:20 -07001295 if (uidState.isDefault()) {
1296 mUidStates.remove(uidState.uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001297 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001298 if (uidChanged) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001299 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001300 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001301 }
Svet Ganov2af57082015-07-30 08:44:20 -07001302
Dianne Hackborn607b4142013-08-02 18:10:10 -07001303 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001304 scheduleFastWriteLocked();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001305 }
1306 }
1307 if (callbacks != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001308 for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
1309 ModeCallback cb = ent.getKey();
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001310 ArrayList<ChangeRec> reports = ent.getValue();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001311 for (int i=0; i<reports.size(); i++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001312 ChangeRec rep = reports.get(i);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001313 mHandler.sendMessage(PooledLambda.obtainMessage(
1314 AppOpsService::notifyOpChanged,
1315 this, cb, rep.op, rep.uid, rep.pkg));
Dianne Hackborn607b4142013-08-02 18:10:10 -07001316 }
1317 }
1318 }
1319 }
1320
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001321 private void evalAllForegroundOpsLocked() {
1322 for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
1323 final UidState uidState = mUidStates.valueAt(uidi);
1324 if (uidState.foregroundOps != null) {
1325 uidState.evalForegroundOps(mOpModeWatchers);
1326 }
1327 }
1328 }
1329
Dianne Hackbornc2293022013-02-06 23:14:49 -08001330 @Override
1331 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001332 startWatchingModeWithFlags(op, packageName, 0, callback);
1333 }
1334
1335 @Override
1336 public void startWatchingModeWithFlags(int op, String packageName, int flags,
1337 IAppOpsCallback callback) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001338 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001339 final int callingUid = Binder.getCallingUid();
1340 final int callingPid = Binder.getCallingPid();
Dianne Hackborn5376edd2018-06-05 13:21:16 -07001341 // TODO: should have a privileged permission to protect this.
1342 // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require
1343 // the USAGE_STATS permission since this can provide information about when an
1344 // app is in the foreground?
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001345 Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
1346 AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001347 if (callback == null) {
1348 return;
1349 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001350 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001351 op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001352 ModeCallback cb = mModeWatchers.get(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001353 if (cb == null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001354 cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001355 mModeWatchers.put(callback.asBinder(), cb);
1356 }
1357 if (op != AppOpsManager.OP_NONE) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001358 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001359 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001360 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001361 mOpModeWatchers.put(op, cbs);
1362 }
1363 cbs.add(cb);
1364 }
1365 if (packageName != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001366 ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001367 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001368 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001369 mPackageModeWatchers.put(packageName, cbs);
1370 }
1371 cbs.add(cb);
1372 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001373 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001374 }
1375 }
1376
1377 @Override
1378 public void stopWatchingMode(IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001379 if (callback == null) {
1380 return;
1381 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001382 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001383 ModeCallback cb = mModeWatchers.remove(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001384 if (cb != null) {
1385 cb.unlinkToDeath();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001386 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001387 ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001388 cbs.remove(cb);
1389 if (cbs.size() <= 0) {
1390 mOpModeWatchers.removeAt(i);
1391 }
1392 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001393 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001394 ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001395 cbs.remove(cb);
1396 if (cbs.size() <= 0) {
1397 mPackageModeWatchers.removeAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001398 }
1399 }
1400 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001401 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001402 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001403 }
1404
1405 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001406 public IBinder getToken(IBinder clientToken) {
1407 synchronized (this) {
1408 ClientState cs = mClients.get(clientToken);
1409 if (cs == null) {
1410 cs = new ClientState(clientToken);
1411 mClients.put(clientToken, cs);
1412 }
1413 return cs;
1414 }
1415 }
1416
Svet Ganovd873ae62018-06-25 16:39:23 -07001417 public CheckOpsDelegate getAppOpsServiceDelegate() {
1418 synchronized (this) {
1419 return mCheckOpsDelegate;
1420 }
1421 }
1422
1423 public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) {
1424 synchronized (this) {
1425 mCheckOpsDelegate = delegate;
1426 }
1427 }
1428
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001429 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -08001430 public int checkOperation(int code, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001431 final CheckOpsDelegate delegate;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001432 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001433 if (mCheckOpsDelegate == null) {
1434 return checkOperationImpl(code, uid, packageName);
1435 }
1436 delegate = mCheckOpsDelegate;
1437 }
1438 return delegate.checkOperation(code, uid, packageName,
1439 AppOpsService.this::checkOperationImpl);
1440 }
1441
1442 private int checkOperationImpl(int code, int uid, String packageName) {
1443 synchronized (this) {
1444 verifyIncomingUid(uid);
1445 verifyIncomingOp(code);
1446 String resolvedPackageName = resolvePackageName(uid, packageName);
1447 if (resolvedPackageName == null) {
1448 return AppOpsManager.MODE_IGNORED;
1449 }
Svet Ganov442ed572016-08-17 17:29:43 -07001450 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001451 return AppOpsManager.MODE_IGNORED;
1452 }
Svet Ganov2af57082015-07-30 08:44:20 -07001453 code = AppOpsManager.opToSwitch(code);
1454 UidState uidState = getUidStateLocked(uid, false);
Svet Ganovee438d42017-01-19 18:04:38 -08001455 if (uidState != null && uidState.opModes != null
1456 && uidState.opModes.indexOfKey(code) >= 0) {
1457 return uidState.opModes.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001458 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001459 Op op = getOpLocked(code, uid, resolvedPackageName, false);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001460 if (op == null) {
David Braunf5d83192013-09-16 13:43:51 -07001461 return AppOpsManager.opToDefaultMode(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001462 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001463 return op.mode;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001464 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001465 }
1466
1467 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001468 public int checkAudioOperation(int code, int usage, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001469 final CheckOpsDelegate delegate;
John Spurlock1af30c72014-03-10 08:33:35 -04001470 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001471 if (mCheckOpsDelegate == null) {
1472 return checkAudioOperationImpl(code, usage, uid, packageName);
1473 }
1474 delegate = mCheckOpsDelegate;
1475 }
1476 return delegate.checkAudioOperation(code, usage, uid, packageName,
1477 AppOpsService.this::checkAudioOperationImpl);
1478 }
1479
1480 private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
1481 synchronized (this) {
1482 boolean suspended;
1483 try {
1484 suspended = isPackageSuspendedForUser(packageName, uid);
1485 } catch (IllegalArgumentException ex) {
1486 // Package not found.
1487 suspended = false;
1488 }
1489
1490 if (suspended) {
1491 Slog.i(TAG, "Audio disabled for suspended package=" + packageName
1492 + " for uid=" + uid);
1493 return AppOpsManager.MODE_IGNORED;
1494 }
1495
John Spurlock7b414672014-07-18 13:02:39 -04001496 final int mode = checkRestrictionLocked(code, usage, uid, packageName);
John Spurlock1af30c72014-03-10 08:33:35 -04001497 if (mode != AppOpsManager.MODE_ALLOWED) {
1498 return mode;
1499 }
1500 }
1501 return checkOperation(code, uid, packageName);
1502 }
1503
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001504 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001505 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001506 return AppGlobals.getPackageManager().isPackageSuspendedForUser(
1507 pkg, UserHandle.getUserId(uid));
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001508 } catch (RemoteException re) {
1509 throw new SecurityException("Could not talk to package manager service");
1510 }
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001511 }
1512
John Spurlock7b414672014-07-18 13:02:39 -04001513 private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
1514 final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1515 if (usageRestrictions != null) {
1516 final Restriction r = usageRestrictions.get(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001517 if (r != null && !r.exceptionPackages.contains(packageName)) {
1518 return r.mode;
1519 }
1520 }
1521 return AppOpsManager.MODE_ALLOWED;
1522 }
1523
1524 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001525 public void setAudioRestriction(int code, int usage, int uid, int mode,
John Spurlock1af30c72014-03-10 08:33:35 -04001526 String[] exceptionPackages) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001527 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
John Spurlock1af30c72014-03-10 08:33:35 -04001528 verifyIncomingUid(uid);
1529 verifyIncomingOp(code);
1530 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001531 SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1532 if (usageRestrictions == null) {
1533 usageRestrictions = new SparseArray<Restriction>();
1534 mAudioRestrictions.put(code, usageRestrictions);
John Spurlock1af30c72014-03-10 08:33:35 -04001535 }
John Spurlock7b414672014-07-18 13:02:39 -04001536 usageRestrictions.remove(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001537 if (mode != AppOpsManager.MODE_ALLOWED) {
1538 final Restriction r = new Restriction();
1539 r.mode = mode;
1540 if (exceptionPackages != null) {
1541 final int N = exceptionPackages.length;
1542 r.exceptionPackages = new ArraySet<String>(N);
1543 for (int i = 0; i < N; i++) {
1544 final String pkg = exceptionPackages[i];
1545 if (pkg != null) {
1546 r.exceptionPackages.add(pkg.trim());
1547 }
1548 }
1549 }
John Spurlock7b414672014-07-18 13:02:39 -04001550 usageRestrictions.put(usage, r);
John Spurlock1af30c72014-03-10 08:33:35 -04001551 }
1552 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001553
1554 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07001555 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
John Spurlock1af30c72014-03-10 08:33:35 -04001556 }
1557
1558 @Override
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001559 public int checkPackage(int uid, String packageName) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001560 Preconditions.checkNotNull(packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001561 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001562 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
1563 true /* uidMismatchExpected */);
1564 if (ops != null) {
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001565 return AppOpsManager.MODE_ALLOWED;
1566 } else {
1567 return AppOpsManager.MODE_ERRORED;
1568 }
1569 }
1570 }
1571
1572 @Override
Svet Ganovd873ae62018-06-25 16:39:23 -07001573 public int noteProxyOperation(int code, int proxyUid,
1574 String proxyPackageName, int proxiedUid, String proxiedPackageName) {
1575 verifyIncomingUid(proxyUid);
Svet Ganov99b60432015-06-27 13:15:22 -07001576 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001577 String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
1578 if (resolveProxyPackageName == null) {
1579 return AppOpsManager.MODE_IGNORED;
1580 }
1581 final int proxyMode = noteOperationUnchecked(code, proxyUid,
1582 resolveProxyPackageName, -1, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001583 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
1584 return proxyMode;
1585 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001586 String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
1587 if (resolveProxiedPackageName == null) {
1588 return AppOpsManager.MODE_IGNORED;
1589 }
1590 return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
1591 proxyMode, resolveProxyPackageName);
Svet Ganov99b60432015-06-27 13:15:22 -07001592 }
1593
1594 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001595 public int noteOperation(int code, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001596 final CheckOpsDelegate delegate;
1597 synchronized (this) {
1598 if (mCheckOpsDelegate == null) {
1599 return noteOperationImpl(code, uid, packageName);
1600 }
1601 delegate = mCheckOpsDelegate;
1602 }
1603 return delegate.noteOperation(code, uid, packageName,
1604 AppOpsService.this::noteOperationImpl);
1605 }
1606
1607 private int noteOperationImpl(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001608 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001609 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001610 String resolvedPackageName = resolvePackageName(uid, packageName);
1611 if (resolvedPackageName == null) {
1612 return AppOpsManager.MODE_IGNORED;
1613 }
1614 return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001615 }
1616
1617 private int noteOperationUnchecked(int code, int uid, String packageName,
1618 int proxyUid, String proxyPackageName) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001619 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001620 final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001621 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001622 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001623 if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001624 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001625 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001626 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001627 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001628 if (isOpRestrictedLocked(uid, code, packageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001629 return AppOpsManager.MODE_IGNORED;
1630 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001631 final UidState uidState = ops.uidState;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001632 if (op.duration == -1) {
1633 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001634 + " code " + code + " time=" + op.time[uidState.state]
1635 + " duration=" + op.duration);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001636 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001637 op.duration = 0;
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001638 final int switchCode = AppOpsManager.opToSwitch(code);
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001639 // If there is a non-default per UID policy (we set UID op mode only if
1640 // non-default) it takes over, otherwise use the per package policy.
1641 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001642 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganov2af57082015-07-30 08:44:20 -07001643 if (uidMode != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001644 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001645 + switchCode + " (" + code + ") uid " + uid + " package "
1646 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001647 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov2af57082015-07-30 08:44:20 -07001648 return uidMode;
1649 }
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001650 } else {
1651 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001652 final int mode = switchOp.getMode();
1653 if (mode != AppOpsManager.MODE_ALLOWED) {
1654 if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001655 + switchCode + " (" + code + ") uid " + uid + " package "
1656 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001657 op.rejectTime[uidState.state] = System.currentTimeMillis();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001658 return mode;
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001659 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001660 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001661 if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001662 + " package " + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001663 op.time[uidState.state] = System.currentTimeMillis();
1664 op.rejectTime[uidState.state] = 0;
Svet Ganov99b60432015-06-27 13:15:22 -07001665 op.proxyUid = proxyUid;
1666 op.proxyPackageName = proxyPackageName;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001667 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001668 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001669 }
1670
1671 @Override
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001672 public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001673 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001674 final int callingUid = Binder.getCallingUid();
1675 final int callingPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -08001676 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1677 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001678 watchedUid = callingUid;
Svet Ganovf7b47252018-02-26 11:11:27 -08001679 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001680 if (ops != null) {
1681 Preconditions.checkArrayElementsInRange(ops, 0,
1682 AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
1683 }
1684 if (callback == null) {
1685 return;
1686 }
1687 synchronized (this) {
1688 SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
1689 if (callbacks == null) {
1690 callbacks = new SparseArray<>();
1691 mActiveWatchers.put(callback.asBinder(), callbacks);
1692 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001693 final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
1694 callingUid, callingPid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001695 for (int op : ops) {
1696 callbacks.put(op, activeCallback);
1697 }
1698 }
1699 }
1700
1701 @Override
1702 public void stopWatchingActive(IAppOpsActiveCallback callback) {
1703 if (callback == null) {
1704 return;
1705 }
1706 synchronized (this) {
1707 final SparseArray<ActiveCallback> activeCallbacks =
1708 mActiveWatchers.remove(callback.asBinder());
1709 if (activeCallbacks == null) {
1710 return;
1711 }
1712 final int callbackCount = activeCallbacks.size();
1713 for (int i = 0; i < callbackCount; i++) {
1714 // Apps ops are mapped to a singleton
1715 if (i == 0) {
1716 activeCallbacks.valueAt(i).destroy();
1717 }
1718 }
1719 }
1720 }
1721
1722 @Override
Svet Ganovf7b47252018-02-26 11:11:27 -08001723 public int startOperation(IBinder token, int code, int uid, String packageName,
1724 boolean startIfModeDefault) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001725 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001726 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001727 String resolvedPackageName = resolvePackageName(uid, packageName);
1728 if (resolvedPackageName == null) {
1729 return AppOpsManager.MODE_IGNORED;
1730 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001731 ClientState client = (ClientState)token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001732 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001733 final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001734 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001735 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001736 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001737 + " package " + resolvedPackageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001738 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001739 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001740 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001741 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001742 return AppOpsManager.MODE_IGNORED;
1743 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001744 final int switchCode = AppOpsManager.opToSwitch(code);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001745 final UidState uidState = ops.uidState;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001746 // If there is a non-default per UID policy (we set UID op mode only if
1747 // non-default) it takes over, otherwise use the per package policy.
1748 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001749 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganovf7b47252018-02-26 11:11:27 -08001750 if (uidMode != AppOpsManager.MODE_ALLOWED
1751 && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001752 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001753 + switchCode + " (" + code + ") uid " + uid + " package "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001754 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001755 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov2af57082015-07-30 08:44:20 -07001756 return uidMode;
1757 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001758 } else {
1759 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001760 final int mode = switchOp.getMode();
1761 if (mode != AppOpsManager.MODE_ALLOWED
1762 && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
1763 if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001764 + switchCode + " (" + code + ") uid " + uid + " package "
1765 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001766 op.rejectTime[uidState.state] = System.currentTimeMillis();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001767 return mode;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001768 }
Svet Ganov2af57082015-07-30 08:44:20 -07001769 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001770 if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001771 + " package " + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001772 if (op.startNesting == 0) {
1773 op.startRealtime = SystemClock.elapsedRealtime();
1774 op.time[uidState.state] = System.currentTimeMillis();
1775 op.rejectTime[uidState.state] = 0;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001776 op.duration = -1;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001777 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001778 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001779 op.startNesting++;
1780 uidState.startNesting++;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001781 if (client.mStartedOps != null) {
1782 client.mStartedOps.add(op);
1783 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001784 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001785
1786 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001787 }
1788
1789 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001790 public void finishOperation(IBinder token, int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001791 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001792 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001793 String resolvedPackageName = resolvePackageName(uid, packageName);
1794 if (resolvedPackageName == null) {
1795 return;
1796 }
1797 if (!(token instanceof ClientState)) {
1798 return;
1799 }
1800 ClientState client = (ClientState) token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001801 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001802 Op op = getOpLocked(code, uid, resolvedPackageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001803 if (op == null) {
1804 return;
1805 }
Svet Ganovf7b47252018-02-26 11:11:27 -08001806 if (!client.mStartedOps.remove(op)) {
Svet Ganovf5d5af12018-03-18 11:51:17 -07001807 // We finish ops when packages get removed to guarantee no dangling
1808 // started ops. However, some part of the system may asynchronously
1809 // finish ops for an already gone package. Hence, finishing an op
1810 // for a non existing package is fine and we don't log as a wtf.
1811 final long identity = Binder.clearCallingIdentity();
1812 try {
1813 if (LocalServices.getService(PackageManagerInternal.class).getPackageUid(
1814 resolvedPackageName, 0, UserHandle.getUserId(uid)) < 0) {
1815 Slog.i(TAG, "Finishing op=" + AppOpsManager.opToName(code)
1816 + " for non-existing package=" + resolvedPackageName
1817 + " in uid=" + uid);
1818 return;
1819 }
1820 } finally {
1821 Binder.restoreCallingIdentity(identity);
1822 }
1823 Slog.wtf(TAG, "Operation not started: uid=" + op.uid + " pkg="
1824 + op.packageName + " op=" + AppOpsManager.opToName(op.op));
Svet Ganov31d83ae2018-03-15 10:45:56 -07001825 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001826 }
Svet Ganova7a0db62018-02-27 20:08:01 -08001827 finishOperationLocked(op, /*finishNested*/ false);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001828 if (op.startNesting <= 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001829 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
1830 }
1831 }
1832 }
1833
1834 private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
1835 boolean active) {
1836 ArraySet<ActiveCallback> dispatchedCallbacks = null;
1837 final int callbackListCount = mActiveWatchers.size();
1838 for (int i = 0; i < callbackListCount; i++) {
1839 final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
1840 ActiveCallback callback = callbacks.get(code);
1841 if (callback != null) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001842 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001843 continue;
1844 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001845 if (dispatchedCallbacks == null) {
1846 dispatchedCallbacks = new ArraySet<>();
1847 }
1848 dispatchedCallbacks.add(callback);
1849 }
1850 }
1851 if (dispatchedCallbacks == null) {
1852 return;
1853 }
1854 mHandler.sendMessage(PooledLambda.obtainMessage(
1855 AppOpsService::notifyOpActiveChanged,
1856 this, dispatchedCallbacks, code, uid, packageName, active));
1857 }
1858
1859 private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
1860 int code, int uid, String packageName, boolean active) {
1861 // There are components watching for mode changes such as window manager
1862 // and location manager which are in our process. The callbacks in these
1863 // components may require permissions our remote caller does not have.
1864 final long identity = Binder.clearCallingIdentity();
1865 try {
1866 final int callbackCount = callbacks.size();
1867 for (int i = 0; i < callbackCount; i++) {
1868 final ActiveCallback callback = callbacks.valueAt(i);
1869 try {
1870 callback.mCallback.opActiveChanged(code, uid, packageName, active);
1871 } catch (RemoteException e) {
1872 /* do nothing */
1873 }
1874 }
1875 } finally {
1876 Binder.restoreCallingIdentity(identity);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001877 }
1878 }
1879
Svet Ganovb9d71a62015-04-30 10:38:13 -07001880 @Override
1881 public int permissionToOpCode(String permission) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001882 if (permission == null) {
1883 return AppOpsManager.OP_NONE;
1884 }
Svet Ganovb9d71a62015-04-30 10:38:13 -07001885 return AppOpsManager.permissionToOpCode(permission);
1886 }
1887
Svet Ganova7a0db62018-02-27 20:08:01 -08001888 void finishOperationLocked(Op op, boolean finishNested) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001889 if (op.startNesting <= 1 || finishNested) {
1890 if (op.startNesting == 1 || finishNested) {
1891 op.duration = (int)(SystemClock.elapsedRealtime() - op.startRealtime);
1892 op.time[op.uidState.state] = System.currentTimeMillis();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001893 } else {
1894 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
1895 + op.packageName + " code " + op.op + " time=" + op.time
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001896 + " duration=" + op.duration + " nesting=" + op.startNesting);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001897 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001898 if (op.startNesting >= 1) {
1899 op.uidState.startNesting -= op.startNesting;
1900 }
1901 op.startNesting = 0;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001902 } else {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001903 op.startNesting--;
1904 op.uidState.startNesting--;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001905 }
1906 }
1907
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001908 private void verifyIncomingUid(int uid) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001909 if (uid == Binder.getCallingUid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001910 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001911 }
1912 if (Binder.getCallingPid() == Process.myPid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001913 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001914 }
1915 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
1916 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001917 }
1918
Dianne Hackborn961321f2013-02-05 17:22:41 -08001919 private void verifyIncomingOp(int op) {
1920 if (op >= 0 && op < AppOpsManager._NUM_OP) {
1921 return;
1922 }
1923 throw new IllegalArgumentException("Bad operation #" + op);
1924 }
1925
Svet Ganov2af57082015-07-30 08:44:20 -07001926 private UidState getUidStateLocked(int uid, boolean edit) {
1927 UidState uidState = mUidStates.get(uid);
1928 if (uidState == null) {
1929 if (!edit) {
1930 return null;
1931 }
1932 uidState = new UidState(uid);
1933 mUidStates.put(uid, uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001934 } else {
1935 if (uidState.pendingStateCommitTime != 0) {
Dianne Hackborn9fb93502018-06-18 12:29:44 -07001936 if (uidState.pendingStateCommitTime < mLastRealtime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001937 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001938 } else {
Dianne Hackborn9fb93502018-06-18 12:29:44 -07001939 mLastRealtime = SystemClock.elapsedRealtime();
1940 if (uidState.pendingStateCommitTime < mLastRealtime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001941 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001942 }
1943 }
1944 }
Svet Ganov2af57082015-07-30 08:44:20 -07001945 }
1946 return uidState;
1947 }
1948
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001949 private void commitUidPendingStateLocked(UidState uidState) {
Dianne Hackborne93ab412018-05-14 17:52:30 -07001950 final boolean lastForeground = uidState.state <= UID_STATE_LAST_NON_RESTRICTED;
1951 final boolean nowForeground = uidState.pendingState <= UID_STATE_LAST_NON_RESTRICTED;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001952 uidState.state = uidState.pendingState;
1953 uidState.pendingStateCommitTime = 0;
Dianne Hackborne93ab412018-05-14 17:52:30 -07001954 if (uidState.hasForegroundWatchers && lastForeground != nowForeground) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001955 for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
1956 if (!uidState.foregroundOps.valueAt(fgi)) {
1957 continue;
1958 }
1959 final int code = uidState.foregroundOps.keyAt(fgi);
1960
1961 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
1962 if (callbacks != null) {
1963 for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
1964 final ModeCallback callback = callbacks.valueAt(cbi);
1965 if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
1966 || !callback.isWatchingUid(uidState.uid)) {
1967 continue;
1968 }
1969 boolean doAllPackages = uidState.opModes != null
1970 && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
1971 if (uidState.pkgOps != null) {
1972 for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
1973 final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
1974 if (doAllPackages || (op != null
1975 && op.mode == AppOpsManager.MODE_FOREGROUND)) {
1976 mHandler.sendMessage(PooledLambda.obtainMessage(
1977 AppOpsService::notifyOpChanged,
1978 this, callback, code, uidState.uid,
1979 uidState.pkgOps.keyAt(pkgi)));
1980 }
1981 }
1982 }
1983 }
1984 }
1985 }
1986 }
1987 }
1988
Yohei Yukawaa965d652017-10-12 15:02:26 -07001989 private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
1990 boolean uidMismatchExpected) {
Svet Ganov2af57082015-07-30 08:44:20 -07001991 UidState uidState = getUidStateLocked(uid, edit);
1992 if (uidState == null) {
1993 return null;
1994 }
1995
1996 if (uidState.pkgOps == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001997 if (!edit) {
1998 return null;
1999 }
Svet Ganov2af57082015-07-30 08:44:20 -07002000 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002001 }
Svet Ganov2af57082015-07-30 08:44:20 -07002002
2003 Ops ops = uidState.pkgOps.get(packageName);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002004 if (ops == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002005 if (!edit) {
2006 return null;
2007 }
Jason Monk1c7c3192014-06-26 12:52:18 -04002008 boolean isPrivileged = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002009 // This is the first time we have seen this package name under this uid,
2010 // so let's make sure it is valid.
Dianne Hackborn514074f2013-02-11 10:52:46 -08002011 if (uid != 0) {
2012 final long ident = Binder.clearCallingIdentity();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002013 try {
Dianne Hackborn514074f2013-02-11 10:52:46 -08002014 int pkgUid = -1;
2015 try {
Jason Monk1c7c3192014-06-26 12:52:18 -04002016 ApplicationInfo appInfo = ActivityThread.getPackageManager()
Jeff Sharkeycd654482016-01-08 17:42:11 -07002017 .getApplicationInfo(packageName,
2018 PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
2019 UserHandle.getUserId(uid));
Jason Monk1c7c3192014-06-26 12:52:18 -04002020 if (appInfo != null) {
2021 pkgUid = appInfo.uid;
Alex Klyubinb9f8a522015-02-03 11:12:59 -08002022 isPrivileged = (appInfo.privateFlags
2023 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04002024 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08002025 pkgUid = resolveUid(packageName);
2026 if (pkgUid >= 0) {
Chien-Yu Chen75cade02016-01-11 10:56:21 -08002027 isPrivileged = false;
Jason Monk1c7c3192014-06-26 12:52:18 -04002028 }
Dianne Hackborn713df152013-05-17 11:27:57 -07002029 }
Jason Monk1c7c3192014-06-26 12:52:18 -04002030 } catch (RemoteException e) {
2031 Slog.w(TAG, "Could not contact PackageManager", e);
Dianne Hackborn514074f2013-02-11 10:52:46 -08002032 }
2033 if (pkgUid != uid) {
2034 // Oops! The package name is not valid for the uid they are calling
2035 // under. Abort.
Yohei Yukawaa965d652017-10-12 15:02:26 -07002036 if (!uidMismatchExpected) {
2037 RuntimeException ex = new RuntimeException("here");
2038 ex.fillInStackTrace();
2039 Slog.w(TAG, "Bad call: specified package " + packageName
2040 + " under uid " + uid + " but it is really " + pkgUid, ex);
2041 }
Dianne Hackborn514074f2013-02-11 10:52:46 -08002042 return null;
2043 }
2044 } finally {
2045 Binder.restoreCallingIdentity(ident);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002046 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002047 }
Svet Ganov2af57082015-07-30 08:44:20 -07002048 ops = new Ops(packageName, uidState, isPrivileged);
2049 uidState.pkgOps.put(packageName, ops);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002050 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08002051 return ops;
2052 }
2053
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002054 private void scheduleWriteLocked() {
2055 if (!mWriteScheduled) {
2056 mWriteScheduled = true;
2057 mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
2058 }
2059 }
2060
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002061 private void scheduleFastWriteLocked() {
2062 if (!mFastWriteScheduled) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002063 mWriteScheduled = true;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002064 mFastWriteScheduled = true;
2065 mHandler.removeCallbacks(mWriteRunner);
2066 mHandler.postDelayed(mWriteRunner, 10*1000);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002067 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002068 }
2069
Dianne Hackborn72e39832013-01-18 18:36:09 -08002070 private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002071 Ops ops = getOpsRawLocked(uid, packageName, edit,
2072 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -08002073 if (ops == null) {
2074 return null;
2075 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002076 return getOpLocked(ops, code, edit);
2077 }
2078
2079 private Op getOpLocked(Ops ops, int code, boolean edit) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002080 Op op = ops.get(code);
2081 if (op == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002082 if (!edit) {
2083 return null;
2084 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002085 op = new Op(ops.uidState, ops.packageName, code);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002086 ops.put(code, op);
2087 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002088 if (edit) {
2089 scheduleWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002090 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002091 return op;
2092 }
2093
Svet Ganov442ed572016-08-17 17:29:43 -07002094 private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
Jason Monk62062992014-05-06 09:55:28 -04002095 int userHandle = UserHandle.getUserId(uid);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002096 final int restrictionSetCount = mOpUserRestrictions.size();
Ruben Brunk29931bc2016-03-11 00:24:26 -08002097
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002098 for (int i = 0; i < restrictionSetCount; i++) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08002099 // For each client, check that the given op is not restricted, or that the given
2100 // package is exempt from the restriction.
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002101 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07002102 if (restrictionState.hasRestriction(code, packageName, userHandle)) {
2103 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
2104 // If we are the system, bypass user restrictions for certain codes
2105 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002106 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
2107 false /* uidMismatchExpected */);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07002108 if ((ops != null) && ops.isPrivileged) {
2109 return false;
2110 }
Ruben Brunk32f0fa42016-03-11 19:07:07 -08002111 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08002112 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002113 return true;
Jason Monk1c7c3192014-06-26 12:52:18 -04002114 }
Jason Monk62062992014-05-06 09:55:28 -04002115 }
2116 return false;
2117 }
2118
Dianne Hackborn35654b62013-01-14 17:38:02 -08002119 void readState() {
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002120 int oldVersion = NO_VERSION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08002121 synchronized (mFile) {
2122 synchronized (this) {
2123 FileInputStream stream;
2124 try {
2125 stream = mFile.openRead();
2126 } catch (FileNotFoundException e) {
2127 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
2128 return;
2129 }
2130 boolean success = false;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002131 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002132 try {
2133 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002134 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002135 int type;
2136 while ((type = parser.next()) != XmlPullParser.START_TAG
2137 && type != XmlPullParser.END_DOCUMENT) {
2138 ;
2139 }
2140
2141 if (type != XmlPullParser.START_TAG) {
2142 throw new IllegalStateException("no start tag found");
2143 }
2144
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002145 final String versionString = parser.getAttributeValue(null, "v");
2146 if (versionString != null) {
2147 oldVersion = Integer.parseInt(versionString);
2148 }
2149
Dianne Hackborn35654b62013-01-14 17:38:02 -08002150 int outerDepth = parser.getDepth();
2151 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2152 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2153 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2154 continue;
2155 }
2156
2157 String tagName = parser.getName();
2158 if (tagName.equals("pkg")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002159 readPackage(parser);
Svetoslav215b44a2015-08-04 19:03:40 -07002160 } else if (tagName.equals("uid")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002161 readUidOps(parser);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002162 } else {
2163 Slog.w(TAG, "Unknown element under <app-ops>: "
2164 + parser.getName());
2165 XmlUtils.skipCurrentTag(parser);
2166 }
2167 }
2168 success = true;
2169 } catch (IllegalStateException e) {
2170 Slog.w(TAG, "Failed parsing " + e);
2171 } catch (NullPointerException e) {
2172 Slog.w(TAG, "Failed parsing " + e);
2173 } catch (NumberFormatException e) {
2174 Slog.w(TAG, "Failed parsing " + e);
2175 } catch (XmlPullParserException e) {
2176 Slog.w(TAG, "Failed parsing " + e);
2177 } catch (IOException e) {
2178 Slog.w(TAG, "Failed parsing " + e);
2179 } catch (IndexOutOfBoundsException e) {
2180 Slog.w(TAG, "Failed parsing " + e);
2181 } finally {
2182 if (!success) {
Svet Ganov2af57082015-07-30 08:44:20 -07002183 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002184 }
2185 try {
2186 stream.close();
2187 } catch (IOException e) {
2188 }
2189 }
2190 }
2191 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002192 synchronized (this) {
2193 upgradeLocked(oldVersion);
2194 }
2195 }
2196
2197 private void upgradeRunAnyInBackgroundLocked() {
2198 for (int i = 0; i < mUidStates.size(); i++) {
2199 final UidState uidState = mUidStates.valueAt(i);
2200 if (uidState == null) {
2201 continue;
2202 }
2203 if (uidState.opModes != null) {
2204 final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
2205 if (idx >= 0) {
2206 uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
2207 uidState.opModes.valueAt(idx));
2208 }
2209 }
2210 if (uidState.pkgOps == null) {
2211 continue;
2212 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002213 boolean changed = false;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002214 for (int j = 0; j < uidState.pkgOps.size(); j++) {
2215 Ops ops = uidState.pkgOps.valueAt(j);
2216 if (ops != null) {
2217 final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
2218 if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002219 final Op copy = new Op(op.uidState, op.packageName,
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002220 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
2221 copy.mode = op.mode;
2222 ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002223 changed = true;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002224 }
2225 }
2226 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002227 if (changed) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002228 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002229 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002230 }
2231 }
2232
2233 private void upgradeLocked(int oldVersion) {
2234 if (oldVersion >= CURRENT_VERSION) {
2235 return;
2236 }
2237 Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
2238 switch (oldVersion) {
2239 case NO_VERSION:
2240 upgradeRunAnyInBackgroundLocked();
2241 // fall through
2242 case 1:
2243 // for future upgrades
2244 }
2245 scheduleFastWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002246 }
2247
Svet Ganov2af57082015-07-30 08:44:20 -07002248 void readUidOps(XmlPullParser parser) throws NumberFormatException,
2249 XmlPullParserException, IOException {
2250 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
2251 int outerDepth = parser.getDepth();
2252 int type;
2253 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2254 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2255 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2256 continue;
2257 }
2258
2259 String tagName = parser.getName();
2260 if (tagName.equals("op")) {
2261 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
2262 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
2263 UidState uidState = getUidStateLocked(uid, true);
2264 if (uidState.opModes == null) {
2265 uidState.opModes = new SparseIntArray();
2266 }
2267 uidState.opModes.put(code, mode);
2268 } else {
2269 Slog.w(TAG, "Unknown element under <uid-ops>: "
2270 + parser.getName());
2271 XmlUtils.skipCurrentTag(parser);
2272 }
2273 }
2274 }
2275
Dave Burke0997c5bd2013-08-02 20:25:02 +00002276 void readPackage(XmlPullParser parser) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002277 XmlPullParserException, IOException {
2278 String pkgName = parser.getAttributeValue(null, "n");
2279 int outerDepth = parser.getDepth();
2280 int type;
2281 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2282 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2283 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2284 continue;
2285 }
2286
2287 String tagName = parser.getName();
2288 if (tagName.equals("uid")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002289 readUid(parser, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002290 } else {
2291 Slog.w(TAG, "Unknown element under <pkg>: "
2292 + parser.getName());
2293 XmlUtils.skipCurrentTag(parser);
2294 }
2295 }
2296 }
2297
Dave Burke0997c5bd2013-08-02 20:25:02 +00002298 void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002299 XmlPullParserException, IOException {
2300 int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
Jason Monk1c7c3192014-06-26 12:52:18 -04002301 String isPrivilegedString = parser.getAttributeValue(null, "p");
2302 boolean isPrivileged = false;
2303 if (isPrivilegedString == null) {
2304 try {
2305 IPackageManager packageManager = ActivityThread.getPackageManager();
2306 if (packageManager != null) {
2307 ApplicationInfo appInfo = ActivityThread.getPackageManager()
2308 .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
2309 if (appInfo != null) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08002310 isPrivileged = (appInfo.privateFlags
2311 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04002312 }
2313 } else {
2314 // Could not load data, don't add to cache so it will be loaded later.
2315 return;
2316 }
2317 } catch (RemoteException e) {
2318 Slog.w(TAG, "Could not contact PackageManager", e);
2319 }
2320 } else {
2321 isPrivileged = Boolean.parseBoolean(isPrivilegedString);
2322 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002323 int outerDepth = parser.getDepth();
2324 int type;
2325 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2326 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2327 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2328 continue;
2329 }
2330
2331 String tagName = parser.getName();
2332 if (tagName.equals("op")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002333 UidState uidState = getUidStateLocked(uid, true);
2334 if (uidState.pkgOps == null) {
2335 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002336 }
Svet Ganov2af57082015-07-30 08:44:20 -07002337
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002338 Op op = new Op(uidState, pkgName,
2339 Integer.parseInt(parser.getAttributeValue(null, "n")));
2340
2341 for (int i = parser.getAttributeCount()-1; i >= 0; i--) {
2342 final String name = parser.getAttributeName(i);
2343 final String value = parser.getAttributeValue(i);
2344 switch (name) {
2345 case "m":
2346 op.mode = Integer.parseInt(value);
2347 break;
2348 case "d":
2349 op.duration = Integer.parseInt(value);
2350 break;
2351 case "pu":
2352 op.proxyUid = Integer.parseInt(value);
2353 break;
2354 case "pp":
2355 op.proxyPackageName = value;
2356 break;
2357 case "tp":
2358 op.time[AppOpsManager.UID_STATE_PERSISTENT] = Long.parseLong(value);
2359 break;
2360 case "tt":
2361 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2362 break;
2363 case "tfs":
2364 op.time[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2365 = Long.parseLong(value);
2366 break;
2367 case "tf":
2368 op.time[AppOpsManager.UID_STATE_FOREGROUND] = Long.parseLong(value);
2369 break;
2370 case "tb":
2371 op.time[AppOpsManager.UID_STATE_BACKGROUND] = Long.parseLong(value);
2372 break;
2373 case "tc":
2374 op.time[AppOpsManager.UID_STATE_CACHED] = Long.parseLong(value);
2375 break;
2376 case "rp":
2377 op.rejectTime[AppOpsManager.UID_STATE_PERSISTENT]
2378 = Long.parseLong(value);
2379 break;
2380 case "rt":
2381 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2382 break;
2383 case "rfs":
2384 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2385 = Long.parseLong(value);
2386 break;
2387 case "rf":
2388 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND]
2389 = Long.parseLong(value);
2390 break;
2391 case "rb":
2392 op.rejectTime[AppOpsManager.UID_STATE_BACKGROUND]
2393 = Long.parseLong(value);
2394 break;
2395 case "rc":
2396 op.rejectTime[AppOpsManager.UID_STATE_CACHED]
2397 = Long.parseLong(value);
2398 break;
2399 case "t":
2400 // Backwards compat.
2401 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2402 break;
2403 case "r":
2404 // Backwards compat.
2405 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2406 break;
2407 default:
2408 Slog.w(TAG, "Unknown attribute in 'op' tag: " + name);
2409 break;
2410 }
2411 }
2412
Svet Ganov2af57082015-07-30 08:44:20 -07002413 Ops ops = uidState.pkgOps.get(pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002414 if (ops == null) {
Svet Ganov2af57082015-07-30 08:44:20 -07002415 ops = new Ops(pkgName, uidState, isPrivileged);
2416 uidState.pkgOps.put(pkgName, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002417 }
2418 ops.put(op.op, op);
2419 } else {
2420 Slog.w(TAG, "Unknown element under <pkg>: "
2421 + parser.getName());
2422 XmlUtils.skipCurrentTag(parser);
2423 }
2424 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002425 UidState uidState = getUidStateLocked(uid, false);
2426 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002427 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002428 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002429 }
2430
2431 void writeState() {
2432 synchronized (mFile) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002433 FileOutputStream stream;
2434 try {
2435 stream = mFile.startWrite();
2436 } catch (IOException e) {
2437 Slog.w(TAG, "Failed to write state: " + e);
2438 return;
2439 }
2440
Dianne Hackborne17b4452018-01-10 13:15:40 -08002441 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
2442
Dianne Hackborn35654b62013-01-14 17:38:02 -08002443 try {
2444 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002445 out.setOutput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002446 out.startDocument(null, true);
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002447 out.startTag(null, "app-ops");
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002448 out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
Svet Ganov2af57082015-07-30 08:44:20 -07002449
2450 final int uidStateCount = mUidStates.size();
2451 for (int i = 0; i < uidStateCount; i++) {
2452 UidState uidState = mUidStates.valueAt(i);
2453 if (uidState.opModes != null && uidState.opModes.size() > 0) {
2454 out.startTag(null, "uid");
2455 out.attribute(null, "n", Integer.toString(uidState.uid));
2456 SparseIntArray uidOpModes = uidState.opModes;
2457 final int opCount = uidOpModes.size();
2458 for (int j = 0; j < opCount; j++) {
2459 final int op = uidOpModes.keyAt(j);
2460 final int mode = uidOpModes.valueAt(j);
2461 out.startTag(null, "op");
2462 out.attribute(null, "n", Integer.toString(op));
2463 out.attribute(null, "m", Integer.toString(mode));
2464 out.endTag(null, "op");
2465 }
2466 out.endTag(null, "uid");
2467 }
2468 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002469
2470 if (allOps != null) {
2471 String lastPkg = null;
2472 for (int i=0; i<allOps.size(); i++) {
2473 AppOpsManager.PackageOps pkg = allOps.get(i);
2474 if (!pkg.getPackageName().equals(lastPkg)) {
2475 if (lastPkg != null) {
2476 out.endTag(null, "pkg");
2477 }
2478 lastPkg = pkg.getPackageName();
2479 out.startTag(null, "pkg");
2480 out.attribute(null, "n", lastPkg);
2481 }
2482 out.startTag(null, "uid");
2483 out.attribute(null, "n", Integer.toString(pkg.getUid()));
Jason Monk1c7c3192014-06-26 12:52:18 -04002484 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002485 Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
2486 false /* edit */, false /* uidMismatchExpected */);
Jason Monk1c7c3192014-06-26 12:52:18 -04002487 // Should always be present as the list of PackageOps is generated
2488 // from Ops.
2489 if (ops != null) {
2490 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
2491 } else {
2492 out.attribute(null, "p", Boolean.toString(false));
2493 }
2494 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002495 List<AppOpsManager.OpEntry> ops = pkg.getOps();
2496 for (int j=0; j<ops.size(); j++) {
2497 AppOpsManager.OpEntry op = ops.get(j);
2498 out.startTag(null, "op");
2499 out.attribute(null, "n", Integer.toString(op.getOp()));
David Braunf5d83192013-09-16 13:43:51 -07002500 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002501 out.attribute(null, "m", Integer.toString(op.getMode()));
2502 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002503 for (int k = 0; k < _NUM_UID_STATE; k++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002504 final long time = op.getLastTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002505 if (time != 0) {
2506 out.attribute(null, UID_STATE_TIME_ATTRS[k],
2507 Long.toString(time));
2508 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002509 final long rejectTime = op.getLastRejectTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002510 if (rejectTime != 0) {
2511 out.attribute(null, UID_STATE_REJECT_ATTRS[k],
2512 Long.toString(rejectTime));
2513 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002514 }
2515 int dur = op.getDuration();
2516 if (dur != 0) {
2517 out.attribute(null, "d", Integer.toString(dur));
2518 }
Svet Ganov99b60432015-06-27 13:15:22 -07002519 int proxyUid = op.getProxyUid();
2520 if (proxyUid != -1) {
2521 out.attribute(null, "pu", Integer.toString(proxyUid));
2522 }
2523 String proxyPackageName = op.getProxyPackageName();
2524 if (proxyPackageName != null) {
2525 out.attribute(null, "pp", proxyPackageName);
2526 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002527 out.endTag(null, "op");
2528 }
2529 out.endTag(null, "uid");
2530 }
2531 if (lastPkg != null) {
2532 out.endTag(null, "pkg");
2533 }
2534 }
2535
2536 out.endTag(null, "app-ops");
2537 out.endDocument();
2538 mFile.finishWrite(stream);
2539 } catch (IOException e) {
2540 Slog.w(TAG, "Failed to write state, restoring backup.", e);
2541 mFile.failWrite(stream);
2542 }
2543 }
2544 }
2545
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002546 static class Shell extends ShellCommand {
2547 final IAppOpsService mInterface;
2548 final AppOpsService mInternal;
2549
2550 int userId = UserHandle.USER_SYSTEM;
2551 String packageName;
2552 String opStr;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002553 String modeStr;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002554 int op;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002555 int mode;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002556 int packageUid;
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002557 int nonpackageUid;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002558 final static Binder sBinder = new Binder();
2559 IBinder mToken;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002560
2561 Shell(IAppOpsService iface, AppOpsService internal) {
2562 mInterface = iface;
2563 mInternal = internal;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002564 try {
2565 mToken = mInterface.getToken(sBinder);
2566 } catch (RemoteException e) {
2567 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002568 }
2569
2570 @Override
2571 public int onCommand(String cmd) {
2572 return onShellCommand(this, cmd);
2573 }
2574
2575 @Override
2576 public void onHelp() {
2577 PrintWriter pw = getOutPrintWriter();
2578 dumpCommandHelp(pw);
2579 }
2580
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002581 static private int strOpToOp(String op, PrintWriter err) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002582 try {
2583 return AppOpsManager.strOpToOp(op);
2584 } catch (IllegalArgumentException e) {
2585 }
2586 try {
2587 return Integer.parseInt(op);
2588 } catch (NumberFormatException e) {
2589 }
2590 try {
2591 return AppOpsManager.strDebugOpToOp(op);
2592 } catch (IllegalArgumentException e) {
2593 err.println("Error: " + e.getMessage());
2594 return -1;
2595 }
2596 }
2597
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002598 static int strModeToMode(String modeStr, PrintWriter err) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002599 for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
2600 if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002601 return i;
2602 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002603 }
2604 try {
2605 return Integer.parseInt(modeStr);
2606 } catch (NumberFormatException e) {
2607 }
2608 err.println("Error: Mode " + modeStr + " is not valid");
2609 return -1;
2610 }
2611
2612 int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
2613 userId = UserHandle.USER_CURRENT;
2614 opStr = null;
2615 modeStr = null;
2616 for (String argument; (argument = getNextArg()) != null;) {
2617 if ("--user".equals(argument)) {
2618 userId = UserHandle.parseUserArg(getNextArgRequired());
2619 } else {
2620 if (opStr == null) {
2621 opStr = argument;
2622 } else if (modeStr == null) {
2623 modeStr = argument;
2624 break;
2625 }
2626 }
2627 }
2628 if (opStr == null) {
2629 err.println("Error: Operation not specified.");
2630 return -1;
2631 }
2632 op = strOpToOp(opStr, err);
2633 if (op < 0) {
2634 return -1;
2635 }
2636 if (modeStr != null) {
2637 if ((mode=strModeToMode(modeStr, err)) < 0) {
2638 return -1;
2639 }
2640 } else {
2641 mode = defMode;
2642 }
2643 return 0;
2644 }
2645
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002646 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
2647 userId = UserHandle.USER_CURRENT;
2648 packageName = null;
2649 opStr = null;
2650 for (String argument; (argument = getNextArg()) != null;) {
2651 if ("--user".equals(argument)) {
2652 userId = UserHandle.parseUserArg(getNextArgRequired());
2653 } else {
2654 if (packageName == null) {
2655 packageName = argument;
2656 } else if (opStr == null) {
2657 opStr = argument;
2658 break;
2659 }
2660 }
2661 }
2662 if (packageName == null) {
2663 err.println("Error: Package name not specified.");
2664 return -1;
2665 } else if (opStr == null && reqOp) {
2666 err.println("Error: Operation not specified.");
2667 return -1;
2668 }
2669 if (opStr != null) {
2670 op = strOpToOp(opStr, err);
2671 if (op < 0) {
2672 return -1;
2673 }
2674 } else {
2675 op = AppOpsManager.OP_NONE;
2676 }
2677 if (userId == UserHandle.USER_CURRENT) {
2678 userId = ActivityManager.getCurrentUser();
2679 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002680 nonpackageUid = -1;
2681 try {
2682 nonpackageUid = Integer.parseInt(packageName);
2683 } catch (NumberFormatException e) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002684 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002685 if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
2686 && packageName.indexOf('.') < 0) {
2687 int i = 1;
2688 while (i < packageName.length() && packageName.charAt(i) >= '0'
2689 && packageName.charAt(i) <= '9') {
2690 i++;
2691 }
2692 if (i > 1 && i < packageName.length()) {
2693 String userStr = packageName.substring(1, i);
2694 try {
2695 int user = Integer.parseInt(userStr);
2696 char type = packageName.charAt(i);
2697 i++;
2698 int startTypeVal = i;
2699 while (i < packageName.length() && packageName.charAt(i) >= '0'
2700 && packageName.charAt(i) <= '9') {
2701 i++;
2702 }
2703 if (i > startTypeVal) {
2704 String typeValStr = packageName.substring(startTypeVal, i);
2705 try {
2706 int typeVal = Integer.parseInt(typeValStr);
2707 if (type == 'a') {
2708 nonpackageUid = UserHandle.getUid(user,
2709 typeVal + Process.FIRST_APPLICATION_UID);
2710 } else if (type == 's') {
2711 nonpackageUid = UserHandle.getUid(user, typeVal);
2712 }
2713 } catch (NumberFormatException e) {
2714 }
2715 }
2716 } catch (NumberFormatException e) {
2717 }
2718 }
2719 }
2720 if (nonpackageUid != -1) {
2721 packageName = null;
2722 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08002723 packageUid = resolveUid(packageName);
2724 if (packageUid < 0) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002725 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
2726 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
2727 }
2728 if (packageUid < 0) {
2729 err.println("Error: No UID for " + packageName + " in user " + userId);
2730 return -1;
2731 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002732 }
2733 return 0;
2734 }
2735 }
2736
2737 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07002738 FileDescriptor err, String[] args, ShellCallback callback,
2739 ResultReceiver resultReceiver) {
2740 (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002741 }
2742
2743 static void dumpCommandHelp(PrintWriter pw) {
2744 pw.println("AppOps service (appops) commands:");
2745 pw.println(" help");
2746 pw.println(" Print this help text.");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002747 pw.println(" start [--user <USER_ID>] <PACKAGE | UID> <OP> ");
2748 pw.println(" Starts a given operation for a particular application.");
2749 pw.println(" stop [--user <USER_ID>] <PACKAGE | UID> <OP> ");
2750 pw.println(" Stops a given operation for a particular application.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002751 pw.println(" set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002752 pw.println(" Set the mode for a particular application and operation.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002753 pw.println(" get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002754 pw.println(" Return the mode for a particular application and optional operation.");
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002755 pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
2756 pw.println(" Print all packages that currently have the given op in the given mode.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002757 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
2758 pw.println(" Reset the given application or all applications to default modes.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002759 pw.println(" write-settings");
2760 pw.println(" Immediately write pending changes to storage.");
2761 pw.println(" read-settings");
2762 pw.println(" Read the last written settings, replacing current state in RAM.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002763 pw.println(" options:");
2764 pw.println(" <PACKAGE> an Android package name.");
2765 pw.println(" <OP> an AppOps operation.");
2766 pw.println(" <MODE> one of allow, ignore, deny, or default");
2767 pw.println(" <USER_ID> the user id under which the package is installed. If --user is not");
2768 pw.println(" specified, the current user is assumed.");
2769 }
2770
2771 static int onShellCommand(Shell shell, String cmd) {
2772 if (cmd == null) {
2773 return shell.handleDefaultCommands(cmd);
2774 }
2775 PrintWriter pw = shell.getOutPrintWriter();
2776 PrintWriter err = shell.getErrPrintWriter();
2777 try {
2778 switch (cmd) {
2779 case "set": {
2780 int res = shell.parseUserPackageOp(true, err);
2781 if (res < 0) {
2782 return res;
2783 }
2784 String modeStr = shell.getNextArg();
2785 if (modeStr == null) {
2786 err.println("Error: Mode not specified.");
2787 return -1;
2788 }
2789
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002790 final int mode = shell.strModeToMode(modeStr, err);
2791 if (mode < 0) {
2792 return -1;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002793 }
2794
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002795 if (shell.packageName != null) {
2796 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
2797 mode);
2798 } else {
2799 shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
2800 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002801 return 0;
2802 }
2803 case "get": {
2804 int res = shell.parseUserPackageOp(false, err);
2805 if (res < 0) {
2806 return res;
2807 }
2808
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002809 List<AppOpsManager.PackageOps> ops;
2810 if (shell.packageName != null) {
2811 ops = shell.mInterface.getOpsForPackage(
2812 shell.packageUid, shell.packageName,
2813 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
2814 } else {
2815 ops = shell.mInterface.getUidOps(
2816 shell.nonpackageUid,
2817 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
2818 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002819 if (ops == null || ops.size() <= 0) {
2820 pw.println("No operations.");
Svet Ganov82f09bc2018-01-12 22:08:40 -08002821 if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002822 pw.println("Default mode: " + AppOpsManager.modeToName(
Svet Ganov82f09bc2018-01-12 22:08:40 -08002823 AppOpsManager.opToDefaultMode(shell.op)));
2824 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002825 return 0;
2826 }
2827 final long now = System.currentTimeMillis();
2828 for (int i=0; i<ops.size(); i++) {
2829 List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
2830 for (int j=0; j<entries.size(); j++) {
2831 AppOpsManager.OpEntry ent = entries.get(j);
2832 pw.print(AppOpsManager.opToName(ent.getOp()));
2833 pw.print(": ");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002834 pw.print(AppOpsManager.modeToName(ent.getMode()));
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002835 if (ent.getTime() != 0) {
2836 pw.print("; time=");
2837 TimeUtils.formatDuration(now - ent.getTime(), pw);
2838 pw.print(" ago");
2839 }
2840 if (ent.getRejectTime() != 0) {
2841 pw.print("; rejectTime=");
2842 TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
2843 pw.print(" ago");
2844 }
2845 if (ent.getDuration() == -1) {
2846 pw.print(" (running)");
2847 } else if (ent.getDuration() != 0) {
2848 pw.print("; duration=");
2849 TimeUtils.formatDuration(ent.getDuration(), pw);
2850 }
2851 pw.println();
2852 }
2853 }
2854 return 0;
2855 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002856 case "query-op": {
2857 int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
2858 if (res < 0) {
2859 return res;
2860 }
2861 List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
2862 new int[] {shell.op});
2863 if (ops == null || ops.size() <= 0) {
2864 pw.println("No operations.");
2865 return 0;
2866 }
2867 for (int i=0; i<ops.size(); i++) {
2868 final AppOpsManager.PackageOps pkg = ops.get(i);
2869 boolean hasMatch = false;
2870 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
2871 for (int j=0; j<entries.size(); j++) {
2872 AppOpsManager.OpEntry ent = entries.get(j);
2873 if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
2874 hasMatch = true;
2875 break;
2876 }
2877 }
2878 if (hasMatch) {
2879 pw.println(pkg.getPackageName());
2880 }
2881 }
2882 return 0;
2883 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002884 case "reset": {
2885 String packageName = null;
2886 int userId = UserHandle.USER_CURRENT;
2887 for (String argument; (argument = shell.getNextArg()) != null;) {
2888 if ("--user".equals(argument)) {
2889 String userStr = shell.getNextArgRequired();
2890 userId = UserHandle.parseUserArg(userStr);
2891 } else {
2892 if (packageName == null) {
2893 packageName = argument;
2894 } else {
2895 err.println("Error: Unsupported argument: " + argument);
2896 return -1;
2897 }
2898 }
2899 }
2900
2901 if (userId == UserHandle.USER_CURRENT) {
2902 userId = ActivityManager.getCurrentUser();
2903 }
2904
2905 shell.mInterface.resetAllModes(userId, packageName);
2906 pw.print("Reset all modes for: ");
2907 if (userId == UserHandle.USER_ALL) {
2908 pw.print("all users");
2909 } else {
2910 pw.print("user "); pw.print(userId);
2911 }
2912 pw.print(", ");
2913 if (packageName == null) {
2914 pw.println("all packages");
2915 } else {
2916 pw.print("package "); pw.println(packageName);
2917 }
2918 return 0;
2919 }
2920 case "write-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07002921 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
2922 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002923 long token = Binder.clearCallingIdentity();
2924 try {
2925 synchronized (shell.mInternal) {
2926 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
2927 }
2928 shell.mInternal.writeState();
2929 pw.println("Current settings written.");
2930 } finally {
2931 Binder.restoreCallingIdentity(token);
2932 }
2933 return 0;
2934 }
2935 case "read-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07002936 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
2937 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002938 long token = Binder.clearCallingIdentity();
2939 try {
2940 shell.mInternal.readState();
2941 pw.println("Last settings read.");
2942 } finally {
2943 Binder.restoreCallingIdentity(token);
2944 }
2945 return 0;
2946 }
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002947 case "start": {
2948 int res = shell.parseUserPackageOp(true, err);
2949 if (res < 0) {
2950 return res;
2951 }
2952
2953 if (shell.packageName != null) {
2954 shell.mInterface.startOperation(shell.mToken,
2955 shell.op, shell.packageUid, shell.packageName, true);
2956 } else {
2957 return -1;
2958 }
2959 return 0;
2960 }
2961 case "stop": {
2962 int res = shell.parseUserPackageOp(true, err);
2963 if (res < 0) {
2964 return res;
2965 }
2966
2967 if (shell.packageName != null) {
2968 shell.mInterface.finishOperation(shell.mToken,
2969 shell.op, shell.packageUid, shell.packageName);
2970 } else {
2971 return -1;
2972 }
2973 return 0;
2974 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002975 default:
2976 return shell.handleDefaultCommands(cmd);
2977 }
2978 } catch (RemoteException e) {
2979 pw.println("Remote exception: " + e);
2980 }
2981 return -1;
2982 }
2983
2984 private void dumpHelp(PrintWriter pw) {
2985 pw.println("AppOps service (appops) dump options:");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002986 pw.println(" -h");
2987 pw.println(" Print this help text.");
2988 pw.println(" --op [OP]");
2989 pw.println(" Limit output to data associated with the given app op code.");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002990 pw.println(" --mode [MODE]");
2991 pw.println(" Limit output to data associated with the given app op mode.");
2992 pw.println(" --package [PACKAGE]");
2993 pw.println(" Limit output to data associated with the given package name.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002994 }
2995
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002996 private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
2997 long now, SimpleDateFormat sdf, Date date) {
2998 boolean hasTime = false;
2999 for (int i = 0; i < _NUM_UID_STATE; i++) {
3000 if (times[i] != 0) {
3001 hasTime = true;
3002 break;
3003 }
3004 }
3005 if (!hasTime) {
3006 return;
3007 }
3008 boolean first = true;
3009 for (int i = 0; i < _NUM_UID_STATE; i++) {
3010 if (times[i] != 0) {
3011 pw.print(first ? firstPrefix : prefix);
3012 first = false;
3013 pw.print(UID_STATE_NAMES[i]);
3014 pw.print(" = ");
3015 date.setTime(times[i]);
3016 pw.print(sdf.format(date));
3017 pw.print(" (");
3018 TimeUtils.formatDuration(times[i]-now, pw);
3019 pw.println(")");
3020 }
3021 }
3022 }
3023
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003024 @Override
3025 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003026 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003027
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003028 int dumpOp = -1;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003029 String dumpPackage = null;
3030 int dumpUid = -1;
3031 int dumpMode = -1;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003032
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003033 if (args != null) {
3034 for (int i=0; i<args.length; i++) {
3035 String arg = args[i];
3036 if ("-h".equals(arg)) {
3037 dumpHelp(pw);
3038 return;
Tim Kilbourn8f1ea832015-08-26 15:07:37 -07003039 } else if ("-a".equals(arg)) {
3040 // dump all data
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003041 } else if ("--op".equals(arg)) {
3042 i++;
3043 if (i >= args.length) {
3044 pw.println("No argument for --op option");
3045 return;
3046 }
3047 dumpOp = Shell.strOpToOp(args[i], pw);
3048 if (dumpOp < 0) {
3049 return;
3050 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003051 } else if ("--package".equals(arg)) {
3052 i++;
3053 if (i >= args.length) {
3054 pw.println("No argument for --package option");
3055 return;
3056 }
3057 dumpPackage = args[i];
3058 try {
3059 dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
3060 PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
3061 0);
3062 } catch (RemoteException e) {
3063 }
3064 if (dumpUid < 0) {
3065 pw.println("Unknown package: " + dumpPackage);
3066 return;
3067 }
3068 dumpUid = UserHandle.getAppId(dumpUid);
3069 } else if ("--mode".equals(arg)) {
3070 i++;
3071 if (i >= args.length) {
3072 pw.println("No argument for --mode option");
3073 return;
3074 }
3075 dumpMode = Shell.strModeToMode(args[i], pw);
3076 if (dumpMode < 0) {
3077 return;
3078 }
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003079 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
3080 pw.println("Unknown option: " + arg);
3081 return;
3082 } else {
3083 pw.println("Unknown command: " + arg);
3084 return;
3085 }
3086 }
3087 }
3088
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003089 synchronized (this) {
3090 pw.println("Current AppOps Service state:");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003091 mConstants.dump(pw);
3092 pw.println();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003093 final long now = System.currentTimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003094 final long nowElapsed = SystemClock.elapsedRealtime();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003095 final long nowUptime = SystemClock.uptimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003096 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
3097 final Date date = new Date();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003098 boolean needSep = false;
Dianne Hackbornd5254412018-05-11 18:02:58 -07003099 if (dumpOp < 0 && dumpMode < 0 && dumpPackage == null && mProfileOwners != null) {
3100 pw.println(" Profile owners:");
3101 for (int poi = 0; poi < mProfileOwners.size(); poi++) {
3102 pw.print(" User #");
3103 pw.print(mProfileOwners.keyAt(poi));
3104 pw.print(": ");
3105 UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
3106 pw.println();
3107 }
3108 pw.println();
3109 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003110 if (mOpModeWatchers.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003111 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003112 for (int i=0; i<mOpModeWatchers.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003113 if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
3114 continue;
3115 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003116 boolean printedOpHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003117 ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003118 for (int j=0; j<callbacks.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003119 final ModeCallback cb = callbacks.valueAt(j);
3120 if (dumpPackage != null && cb.mWatchingUid >= 0
3121 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3122 continue;
3123 }
3124 needSep = true;
3125 if (!printedHeader) {
3126 pw.println(" Op mode watchers:");
3127 printedHeader = true;
3128 }
3129 if (!printedOpHeader) {
3130 pw.print(" Op ");
3131 pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
3132 pw.println(":");
3133 printedOpHeader = true;
3134 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003135 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003136 pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003137 }
3138 }
3139 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003140 if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
3141 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003142 for (int i=0; i<mPackageModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003143 if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
3144 continue;
3145 }
3146 needSep = true;
3147 if (!printedHeader) {
3148 pw.println(" Package mode watchers:");
3149 printedHeader = true;
3150 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003151 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
3152 pw.println(":");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003153 ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003154 for (int j=0; j<callbacks.size(); j++) {
3155 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn68d76552017-02-27 15:32:03 -08003156 pw.println(callbacks.valueAt(j));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003157 }
3158 }
3159 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003160 if (mModeWatchers.size() > 0 && dumpOp < 0) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003161 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003162 for (int i=0; i<mModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003163 final ModeCallback cb = mModeWatchers.valueAt(i);
3164 if (dumpPackage != null && cb.mWatchingUid >= 0
3165 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3166 continue;
3167 }
3168 needSep = true;
3169 if (!printedHeader) {
3170 pw.println(" All op mode watchers:");
3171 printedHeader = true;
3172 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003173 pw.print(" ");
3174 pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003175 pw.print(": "); pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003176 }
3177 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003178 if (mActiveWatchers.size() > 0 && dumpMode < 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003179 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003180 boolean printedHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003181 for (int i = 0; i < mActiveWatchers.size(); i++) {
3182 final SparseArray<ActiveCallback> activeWatchers = mActiveWatchers.valueAt(i);
3183 if (activeWatchers.size() <= 0) {
3184 continue;
3185 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003186 final ActiveCallback cb = activeWatchers.valueAt(0);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003187 if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
3188 continue;
3189 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003190 if (dumpPackage != null && cb.mWatchingUid >= 0
3191 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3192 continue;
3193 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003194 if (!printedHeader) {
3195 pw.println(" All op active watchers:");
3196 printedHeader = true;
3197 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003198 pw.print(" ");
3199 pw.print(Integer.toHexString(System.identityHashCode(
3200 mActiveWatchers.keyAt(i))));
3201 pw.println(" ->");
3202 pw.print(" [");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003203 final int opCount = activeWatchers.size();
3204 for (i = 0; i < opCount; i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003205 if (i > 0) {
3206 pw.print(' ');
3207 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003208 pw.print(AppOpsManager.opToName(activeWatchers.keyAt(i)));
3209 if (i < opCount - 1) {
3210 pw.print(',');
3211 }
3212 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003213 pw.println("]");
3214 pw.print(" ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003215 pw.println(cb);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003216 }
3217 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003218 if (mClients.size() > 0 && dumpMode < 0) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003219 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003220 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003221 for (int i=0; i<mClients.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003222 boolean printedClient = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003223 ClientState cs = mClients.valueAt(i);
Svet Ganovf7b47252018-02-26 11:11:27 -08003224 if (cs.mStartedOps.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003225 boolean printedStarted = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003226 for (int j=0; j<cs.mStartedOps.size(); j++) {
3227 Op op = cs.mStartedOps.get(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003228 if (dumpOp >= 0 && op.op != dumpOp) {
3229 continue;
3230 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003231 if (dumpPackage != null && !dumpPackage.equals(op.packageName)) {
3232 continue;
3233 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003234 if (!printedHeader) {
3235 pw.println(" Clients:");
3236 printedHeader = true;
3237 }
3238 if (!printedClient) {
3239 pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
3240 pw.print(" "); pw.println(cs);
3241 printedClient = true;
3242 }
3243 if (!printedStarted) {
3244 pw.println(" Started ops:");
3245 printedStarted = true;
3246 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003247 pw.print(" "); pw.print("uid="); pw.print(op.uid);
3248 pw.print(" pkg="); pw.print(op.packageName);
3249 pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
3250 }
3251 }
3252 }
3253 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003254 if (mAudioRestrictions.size() > 0 && dumpOp < 0 && dumpPackage != null
3255 && dumpMode < 0) {
John Spurlock1af30c72014-03-10 08:33:35 -04003256 boolean printedHeader = false;
3257 for (int o=0; o<mAudioRestrictions.size(); o++) {
3258 final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
3259 final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
3260 for (int i=0; i<restrictions.size(); i++) {
3261 if (!printedHeader){
3262 pw.println(" Audio Restrictions:");
3263 printedHeader = true;
3264 needSep = true;
3265 }
John Spurlock7b414672014-07-18 13:02:39 -04003266 final int usage = restrictions.keyAt(i);
John Spurlock1af30c72014-03-10 08:33:35 -04003267 pw.print(" "); pw.print(op);
John Spurlock7b414672014-07-18 13:02:39 -04003268 pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
John Spurlock1af30c72014-03-10 08:33:35 -04003269 Restriction r = restrictions.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003270 pw.print(": mode="); pw.println(AppOpsManager.modeToName(r.mode));
John Spurlock1af30c72014-03-10 08:33:35 -04003271 if (!r.exceptionPackages.isEmpty()) {
3272 pw.println(" Exceptions:");
3273 for (int j=0; j<r.exceptionPackages.size(); j++) {
3274 pw.print(" "); pw.println(r.exceptionPackages.valueAt(j));
3275 }
3276 }
3277 }
3278 }
3279 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003280 if (needSep) {
3281 pw.println();
3282 }
Svet Ganov2af57082015-07-30 08:44:20 -07003283 for (int i=0; i<mUidStates.size(); i++) {
3284 UidState uidState = mUidStates.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003285 final SparseIntArray opModes = uidState.opModes;
3286 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
3287
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003288 if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
3289 boolean hasOp = dumpOp < 0 || (uidState.opModes != null
3290 && uidState.opModes.indexOfKey(dumpOp) >= 0);
3291 boolean hasPackage = dumpPackage == null;
3292 boolean hasMode = dumpMode < 0;
3293 if (!hasMode && opModes != null) {
3294 for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
3295 if (opModes.valueAt(opi) == dumpMode) {
3296 hasMode = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003297 }
3298 }
3299 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003300 if (pkgOps != null) {
3301 for (int pkgi = 0;
3302 (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
3303 pkgi++) {
3304 Ops ops = pkgOps.valueAt(pkgi);
3305 if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
3306 hasOp = true;
3307 }
3308 if (!hasMode) {
3309 for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
3310 if (ops.valueAt(opi).mode == dumpMode) {
3311 hasMode = true;
3312 }
3313 }
3314 }
3315 if (!hasPackage && dumpPackage.equals(ops.packageName)) {
3316 hasPackage = true;
3317 }
3318 }
3319 }
3320 if (uidState.foregroundOps != null && !hasOp) {
3321 if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
3322 hasOp = true;
3323 }
3324 }
3325 if (!hasOp || !hasPackage || !hasMode) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003326 continue;
3327 }
3328 }
Svet Ganov2af57082015-07-30 08:44:20 -07003329
3330 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003331 pw.print(" state=");
3332 pw.println(UID_STATE_NAMES[uidState.state]);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003333 if (uidState.state != uidState.pendingState) {
3334 pw.print(" pendingState=");
3335 pw.println(UID_STATE_NAMES[uidState.pendingState]);
3336 }
3337 if (uidState.pendingStateCommitTime != 0) {
3338 pw.print(" pendingStateCommitTime=");
Dianne Hackborn9fb93502018-06-18 12:29:44 -07003339 TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003340 pw.println();
3341 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003342 if (uidState.startNesting != 0) {
3343 pw.print(" startNesting=");
3344 pw.println(uidState.startNesting);
3345 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003346 if (uidState.foregroundOps != null && (dumpMode < 0
3347 || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003348 pw.println(" foregroundOps:");
3349 for (int j = 0; j < uidState.foregroundOps.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003350 if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
3351 continue;
3352 }
3353 pw.print(" ");
3354 pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
3355 pw.print(": ");
3356 pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003357 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003358 pw.print(" hasForegroundWatchers=");
3359 pw.println(uidState.hasForegroundWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003360 }
Svet Ganovee438d42017-01-19 18:04:38 -08003361 needSep = true;
Svet Ganov2af57082015-07-30 08:44:20 -07003362
Svet Ganov2af57082015-07-30 08:44:20 -07003363 if (opModes != null) {
3364 final int opModeCount = opModes.size();
3365 for (int j = 0; j < opModeCount; j++) {
3366 final int code = opModes.keyAt(j);
3367 final int mode = opModes.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003368 if (dumpOp >= 0 && dumpOp != code) {
3369 continue;
3370 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003371 if (dumpMode >= 0 && dumpMode != mode) {
3372 continue;
3373 }
Svet Ganov2af57082015-07-30 08:44:20 -07003374 pw.print(" "); pw.print(AppOpsManager.opToName(code));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003375 pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
Svet Ganov2af57082015-07-30 08:44:20 -07003376 }
3377 }
3378
Svet Ganov2af57082015-07-30 08:44:20 -07003379 if (pkgOps == null) {
3380 continue;
3381 }
3382
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003383 for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003384 final Ops ops = pkgOps.valueAt(pkgi);
3385 if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
3386 continue;
3387 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003388 boolean printedPackage = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003389 for (int j=0; j<ops.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003390 final Op op = ops.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003391 if (dumpOp >= 0 && dumpOp != op.op) {
3392 continue;
3393 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003394 if (dumpMode >= 0 && dumpMode != op.mode) {
3395 continue;
3396 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003397 if (!printedPackage) {
3398 pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
3399 printedPackage = true;
3400 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003401 pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003402 pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003403 final int switchOp = AppOpsManager.opToSwitch(op.op);
3404 if (switchOp != op.op) {
3405 pw.print(" / switch ");
3406 pw.print(AppOpsManager.opToName(switchOp));
3407 final Op switchObj = ops.get(switchOp);
3408 int mode = switchObj != null
3409 ? switchObj.mode : AppOpsManager.opToDefaultMode(switchOp);
3410 pw.print("="); pw.print(AppOpsManager.modeToName(mode));
3411 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003412 pw.println("): ");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003413 dumpTimesLocked(pw,
3414 " Access: ",
3415 " ", op.time, now, sdf, date);
3416 dumpTimesLocked(pw,
3417 " Reject: ",
3418 " ", op.rejectTime, now, sdf, date);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003419 if (op.duration == -1) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003420 pw.print(" Running start at: ");
3421 TimeUtils.formatDuration(nowElapsed-op.startRealtime, pw);
3422 pw.println();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08003423 } else if (op.duration != 0) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003424 pw.print(" duration=");
3425 TimeUtils.formatDuration(op.duration, pw);
3426 pw.println();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003427 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003428 if (op.startNesting != 0) {
3429 pw.print(" startNesting=");
3430 pw.println(op.startNesting);
3431 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003432 }
3433 }
3434 }
Svet Ganovee438d42017-01-19 18:04:38 -08003435 if (needSep) {
3436 pw.println();
3437 }
3438
3439 final int userRestrictionCount = mOpUserRestrictions.size();
3440 for (int i = 0; i < userRestrictionCount; i++) {
3441 IBinder token = mOpUserRestrictions.keyAt(i);
3442 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
3443 pw.println(" User restrictions for token " + token + ":");
3444
3445 final int restrictionCount = restrictionState.perUserRestrictions != null
3446 ? restrictionState.perUserRestrictions.size() : 0;
3447 if (restrictionCount > 0) {
3448 pw.println(" Restricted ops:");
3449 for (int j = 0; j < restrictionCount; j++) {
3450 int userId = restrictionState.perUserRestrictions.keyAt(j);
3451 boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
3452 if (restrictedOps == null) {
3453 continue;
3454 }
3455 StringBuilder restrictedOpsValue = new StringBuilder();
3456 restrictedOpsValue.append("[");
3457 final int restrictedOpCount = restrictedOps.length;
3458 for (int k = 0; k < restrictedOpCount; k++) {
3459 if (restrictedOps[k]) {
3460 if (restrictedOpsValue.length() > 1) {
3461 restrictedOpsValue.append(", ");
3462 }
3463 restrictedOpsValue.append(AppOpsManager.opToName(k));
3464 }
3465 }
3466 restrictedOpsValue.append("]");
3467 pw.print(" "); pw.print("user: "); pw.print(userId);
3468 pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
3469 }
3470 }
3471
3472 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
3473 ? restrictionState.perUserExcludedPackages.size() : 0;
3474 if (excludedPackageCount > 0) {
3475 pw.println(" Excluded packages:");
3476 for (int j = 0; j < excludedPackageCount; j++) {
3477 int userId = restrictionState.perUserExcludedPackages.keyAt(j);
3478 String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
3479 pw.print(" "); pw.print("user: "); pw.print(userId);
3480 pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
3481 }
3482 }
3483 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003484 }
3485 }
John Spurlock1af30c72014-03-10 08:33:35 -04003486
3487 private static final class Restriction {
3488 private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
3489 int mode;
3490 ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
3491 }
Jason Monk62062992014-05-06 09:55:28 -04003492
3493 @Override
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003494 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
Jason Monk62062992014-05-06 09:55:28 -04003495 checkSystemUid("setUserRestrictions");
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003496 Preconditions.checkNotNull(restrictions);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003497 Preconditions.checkNotNull(token);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003498 for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
Jason Monk62062992014-05-06 09:55:28 -04003499 String restriction = AppOpsManager.opToRestriction(i);
Suprabh Shukla64e0dcb2016-05-24 16:23:11 -07003500 if (restriction != null) {
3501 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
3502 userHandle, null);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003503 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003504 }
3505 }
3506
3507 @Override
Ruben Brunk29931bc2016-03-11 00:24:26 -08003508 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
3509 String[] exceptionPackages) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003510 if (Binder.getCallingPid() != Process.myPid()) {
3511 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
3512 Binder.getCallingPid(), Binder.getCallingUid(), null);
3513 }
3514 if (userHandle != UserHandle.getCallingUserId()) {
3515 if (mContext.checkCallingOrSelfPermission(Manifest.permission
3516 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
3517 && mContext.checkCallingOrSelfPermission(Manifest.permission
3518 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
3519 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
3520 + " INTERACT_ACROSS_USERS to interact cross user ");
Jason Monk62062992014-05-06 09:55:28 -04003521 }
3522 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003523 verifyIncomingOp(code);
3524 Preconditions.checkNotNull(token);
Ruben Brunk29931bc2016-03-11 00:24:26 -08003525 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003526 }
3527
3528 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
Ruben Brunk29931bc2016-03-11 00:24:26 -08003529 int userHandle, String[] exceptionPackages) {
Svet Ganov442ed572016-08-17 17:29:43 -07003530 synchronized (AppOpsService.this) {
3531 ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
3532
3533 if (restrictionState == null) {
3534 try {
3535 restrictionState = new ClientRestrictionState(token);
3536 } catch (RemoteException e) {
3537 return;
3538 }
3539 mOpUserRestrictions.put(token, restrictionState);
Ruben Brunk29931bc2016-03-11 00:24:26 -08003540 }
Svet Ganov442ed572016-08-17 17:29:43 -07003541
3542 if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003543 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07003544 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
Svet Ganov442ed572016-08-17 17:29:43 -07003545 }
3546
3547 if (restrictionState.isDefault()) {
3548 mOpUserRestrictions.remove(token);
3549 restrictionState.destroy();
3550 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08003551 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -04003552 }
3553
Svet Ganov3a95f832018-03-23 17:44:30 -07003554 private void notifyWatchersOfChange(int code, int uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003555 final ArraySet<ModeCallback> clonedCallbacks;
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003556 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003557 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003558 if (callbacks == null) {
3559 return;
3560 }
Dianne Hackborn68d76552017-02-27 15:32:03 -08003561 clonedCallbacks = new ArraySet<>(callbacks);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003562 }
3563
Svet Ganov3a95f832018-03-23 17:44:30 -07003564 notifyOpChanged(clonedCallbacks, code, uid, null);
Jason Monk62062992014-05-06 09:55:28 -04003565 }
3566
3567 @Override
3568 public void removeUser(int userHandle) throws RemoteException {
3569 checkSystemUid("removeUser");
Svet Ganov442ed572016-08-17 17:29:43 -07003570 synchronized (AppOpsService.this) {
3571 final int tokenCount = mOpUserRestrictions.size();
3572 for (int i = tokenCount - 1; i >= 0; i--) {
3573 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
3574 opRestrictions.removeUser(userHandle);
3575 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003576 removeUidsForUserLocked(userHandle);
3577 }
3578 }
3579
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003580 @Override
3581 public boolean isOperationActive(int code, int uid, String packageName) {
Svet Ganovf7b47252018-02-26 11:11:27 -08003582 if (Binder.getCallingUid() != uid) {
3583 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
3584 != PackageManager.PERMISSION_GRANTED) {
3585 return false;
3586 }
3587 }
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003588 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003589 final String resolvedPackageName = resolvePackageName(uid, packageName);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003590 if (resolvedPackageName == null) {
3591 return false;
3592 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003593 synchronized (AppOpsService.this) {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003594 for (int i = mClients.size() - 1; i >= 0; i--) {
3595 final ClientState client = mClients.valueAt(i);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003596 for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
3597 final Op op = client.mStartedOps.get(j);
3598 if (op.op == code && op.uid == uid) return true;
3599 }
3600 }
3601 }
3602 return false;
3603 }
3604
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003605 private void removeUidsForUserLocked(int userHandle) {
3606 for (int i = mUidStates.size() - 1; i >= 0; --i) {
3607 final int uid = mUidStates.keyAt(i);
3608 if (UserHandle.getUserId(uid) == userHandle) {
3609 mUidStates.removeAt(i);
3610 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003611 }
3612 }
3613
Jason Monk62062992014-05-06 09:55:28 -04003614 private void checkSystemUid(String function) {
3615 int uid = Binder.getCallingUid();
3616 if (uid != Process.SYSTEM_UID) {
3617 throw new SecurityException(function + " must by called by the system");
3618 }
3619 }
3620
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003621 private static String resolvePackageName(int uid, String packageName) {
Svet Ganov82f09bc2018-01-12 22:08:40 -08003622 if (uid == Process.ROOT_UID) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003623 return "root";
3624 } else if (uid == Process.SHELL_UID) {
3625 return "com.android.shell";
Svet Ganov82f09bc2018-01-12 22:08:40 -08003626 } else if (uid == Process.MEDIA_UID) {
3627 return "media";
3628 } else if (uid == Process.AUDIOSERVER_UID) {
3629 return "audioserver";
3630 } else if (uid == Process.CAMERASERVER_UID) {
3631 return "cameraserver";
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003632 } else if (uid == Process.SYSTEM_UID && packageName == null) {
3633 return "android";
3634 }
3635 return packageName;
3636 }
3637
Svet Ganov82f09bc2018-01-12 22:08:40 -08003638 private static int resolveUid(String packageName) {
3639 if (packageName == null) {
3640 return -1;
3641 }
3642 switch (packageName) {
3643 case "root":
3644 return Process.ROOT_UID;
3645 case "shell":
3646 return Process.SHELL_UID;
3647 case "media":
3648 return Process.MEDIA_UID;
3649 case "audioserver":
3650 return Process.AUDIOSERVER_UID;
3651 case "cameraserver":
3652 return Process.CAMERASERVER_UID;
3653 }
3654 return -1;
3655 }
3656
Svet Ganov2af57082015-07-30 08:44:20 -07003657 private static String[] getPackagesForUid(int uid) {
Svet Ganovf3807aa2015-08-02 10:09:56 -07003658 String[] packageNames = null;
Svet Ganov2af57082015-07-30 08:44:20 -07003659 try {
riddle_hsu40b300f2015-11-23 13:22:03 +08003660 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
Svet Ganov2af57082015-07-30 08:44:20 -07003661 } catch (RemoteException e) {
3662 /* ignore - local call */
3663 }
Svet Ganovf3807aa2015-08-02 10:09:56 -07003664 if (packageNames == null) {
3665 return EmptyArray.STRING;
3666 }
3667 return packageNames;
Svet Ganov2af57082015-07-30 08:44:20 -07003668 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003669
3670 private final class ClientRestrictionState implements DeathRecipient {
3671 private final IBinder token;
3672 SparseArray<boolean[]> perUserRestrictions;
3673 SparseArray<String[]> perUserExcludedPackages;
3674
3675 public ClientRestrictionState(IBinder token)
3676 throws RemoteException {
3677 token.linkToDeath(this, 0);
3678 this.token = token;
3679 }
3680
3681 public boolean setRestriction(int code, boolean restricted,
3682 String[] excludedPackages, int userId) {
3683 boolean changed = false;
3684
3685 if (perUserRestrictions == null && restricted) {
3686 perUserRestrictions = new SparseArray<>();
3687 }
3688
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003689 int[] users;
3690 if (userId == UserHandle.USER_ALL) {
3691 List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003692
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003693 users = new int[liveUsers.size()];
3694 for (int i = 0; i < liveUsers.size(); i++) {
3695 users[i] = liveUsers.get(i).id;
3696 }
3697 } else {
3698 users = new int[]{userId};
3699 }
3700
3701 if (perUserRestrictions != null) {
3702 int numUsers = users.length;
3703
3704 for (int i = 0; i < numUsers; i++) {
3705 int thisUserId = users[i];
3706
3707 boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
3708 if (userRestrictions == null && restricted) {
3709 userRestrictions = new boolean[AppOpsManager._NUM_OP];
3710 perUserRestrictions.put(thisUserId, userRestrictions);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003711 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003712 if (userRestrictions != null && userRestrictions[code] != restricted) {
3713 userRestrictions[code] = restricted;
3714 if (!restricted && isDefault(userRestrictions)) {
3715 perUserRestrictions.remove(thisUserId);
3716 userRestrictions = null;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003717 }
3718 changed = true;
3719 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003720
3721 if (userRestrictions != null) {
3722 final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
3723 if (perUserExcludedPackages == null && !noExcludedPackages) {
3724 perUserExcludedPackages = new SparseArray<>();
3725 }
3726 if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
3727 perUserExcludedPackages.get(thisUserId))) {
3728 if (noExcludedPackages) {
3729 perUserExcludedPackages.remove(thisUserId);
3730 if (perUserExcludedPackages.size() <= 0) {
3731 perUserExcludedPackages = null;
3732 }
3733 } else {
3734 perUserExcludedPackages.put(thisUserId, excludedPackages);
3735 }
3736 changed = true;
3737 }
3738 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003739 }
3740 }
3741
3742 return changed;
3743 }
3744
3745 public boolean hasRestriction(int restriction, String packageName, int userId) {
3746 if (perUserRestrictions == null) {
3747 return false;
3748 }
3749 boolean[] restrictions = perUserRestrictions.get(userId);
3750 if (restrictions == null) {
3751 return false;
3752 }
3753 if (!restrictions[restriction]) {
3754 return false;
3755 }
3756 if (perUserExcludedPackages == null) {
3757 return true;
3758 }
3759 String[] perUserExclusions = perUserExcludedPackages.get(userId);
3760 if (perUserExclusions == null) {
3761 return true;
3762 }
3763 return !ArrayUtils.contains(perUserExclusions, packageName);
3764 }
3765
3766 public void removeUser(int userId) {
3767 if (perUserExcludedPackages != null) {
3768 perUserExcludedPackages.remove(userId);
3769 if (perUserExcludedPackages.size() <= 0) {
3770 perUserExcludedPackages = null;
3771 }
3772 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003773 if (perUserRestrictions != null) {
3774 perUserRestrictions.remove(userId);
3775 if (perUserRestrictions.size() <= 0) {
3776 perUserRestrictions = null;
3777 }
3778 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003779 }
3780
3781 public boolean isDefault() {
3782 return perUserRestrictions == null || perUserRestrictions.size() <= 0;
3783 }
3784
3785 @Override
3786 public void binderDied() {
3787 synchronized (AppOpsService.this) {
3788 mOpUserRestrictions.remove(token);
3789 if (perUserRestrictions == null) {
3790 return;
3791 }
3792 final int userCount = perUserRestrictions.size();
3793 for (int i = 0; i < userCount; i++) {
3794 final boolean[] restrictions = perUserRestrictions.valueAt(i);
3795 final int restrictionCount = restrictions.length;
3796 for (int j = 0; j < restrictionCount; j++) {
3797 if (restrictions[j]) {
3798 final int changedCode = j;
Svet Ganov3a95f832018-03-23 17:44:30 -07003799 mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003800 }
3801 }
3802 }
3803 destroy();
3804 }
3805 }
3806
3807 public void destroy() {
3808 token.unlinkToDeath(this, 0);
3809 }
3810
3811 private boolean isDefault(boolean[] array) {
3812 if (ArrayUtils.isEmpty(array)) {
3813 return true;
3814 }
3815 for (boolean value : array) {
3816 if (value) {
3817 return false;
3818 }
3819 }
3820 return true;
3821 }
3822 }
Dianne Hackbornd5254412018-05-11 18:02:58 -07003823
3824 private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
3825 @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
3826 synchronized (AppOpsService.this) {
3827 mProfileOwners = owners;
3828 }
3829 }
3830 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003831}