blob: f0ec69f488b13afe3da35265d482fdfc29bd1f11 [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
Suprabh Shukla3017fe42018-11-08 19:00:01 -080019import static android.app.AppOpsManager.OP_PLAY_AUDIO;
Hai Zhang2b98fb32018-09-21 15:18:46 -070020import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
21import static android.app.AppOpsManager.UID_STATE_CACHED;
22import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
23import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
24import static android.app.AppOpsManager.UID_STATE_LAST_NON_RESTRICTED;
25import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
26import static android.app.AppOpsManager.UID_STATE_TOP;
27import static android.app.AppOpsManager._NUM_UID_STATE;
Eugene Suslae4ee2c22018-11-05 12:23:30 -080028import static android.app.AppOpsManager.modeToName;
29import static android.app.AppOpsManager.opToName;
Hai Zhang2b98fb32018-09-21 15:18:46 -070030
Philip P. Moltmanne683f192017-06-23 14:05:04 -070031import android.Manifest;
Svet Ganovad0a49b2018-10-29 10:07:08 -070032import android.annotation.NonNull;
33import android.annotation.Nullable;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070034import android.app.ActivityManager;
35import android.app.ActivityThread;
36import android.app.AppGlobals;
37import android.app.AppOpsManager;
Svet Ganovad0a49b2018-10-29 10:07:08 -070038import android.app.AppOpsManager.HistoricalOpEntry;
39import android.app.AppOpsManager.HistoricalPackageOps;
Dianne Hackbornd5254412018-05-11 18:02:58 -070040import android.app.AppOpsManagerInternal;
Svet Ganovd873ae62018-06-25 16:39:23 -070041import android.app.AppOpsManagerInternal.CheckOpsDelegate;
Suprabh Shukla3017fe42018-11-08 19:00:01 -080042import android.content.BroadcastReceiver;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070043import android.content.ContentResolver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070044import android.content.Context;
Suprabh Shukla3017fe42018-11-08 19:00:01 -080045import android.content.Intent;
46import android.content.IntentFilter;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070047import android.content.pm.ApplicationInfo;
48import android.content.pm.IPackageManager;
49import android.content.pm.PackageManager;
50import android.content.pm.PackageManagerInternal;
Svet Ganovad0a49b2018-10-29 10:07:08 -070051import android.content.pm.ParceledListSlice;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070052import android.content.pm.UserInfo;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070053import android.database.ContentObserver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070054import android.media.AudioAttributes;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070055import android.net.Uri;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070056import android.os.AsyncTask;
57import android.os.Binder;
58import android.os.Bundle;
59import android.os.Handler;
60import android.os.IBinder;
61import android.os.Process;
62import android.os.RemoteException;
63import android.os.ResultReceiver;
64import android.os.ServiceManager;
65import android.os.ShellCallback;
66import android.os.ShellCommand;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070067import android.os.SystemClock;
Sudheer Shanka98cb3f02018-08-17 16:10:29 -070068import android.os.SystemProperties;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070069import android.os.UserHandle;
70import android.os.UserManager;
Sudheer Shanka98cb3f02018-08-17 16:10:29 -070071import android.os.storage.StorageManager;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070072import android.os.storage.StorageManagerInternal;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070073import android.provider.Settings;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070074import android.util.ArrayMap;
75import android.util.ArraySet;
76import android.util.AtomicFile;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070077import android.util.KeyValueListParser;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070078import android.util.Slog;
79import android.util.SparseArray;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -070080import android.util.SparseBooleanArray;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070081import android.util.SparseIntArray;
82import android.util.TimeUtils;
83import android.util.Xml;
84
Todd Kennedy556efba2018-11-15 07:43:55 -080085import com.android.internal.annotations.GuardedBy;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070086import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080087import com.android.internal.app.IAppOpsActiveCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070088import com.android.internal.app.IAppOpsCallback;
Svet Ganovb3d2ae22018-12-17 22:06:15 -080089import com.android.internal.app.IAppOpsNotedCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070090import com.android.internal.app.IAppOpsService;
91import com.android.internal.os.Zygote;
92import com.android.internal.util.ArrayUtils;
93import com.android.internal.util.DumpUtils;
94import com.android.internal.util.FastXmlSerializer;
95import com.android.internal.util.Preconditions;
96import com.android.internal.util.XmlUtils;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080097import com.android.internal.util.function.pooled.PooledLambda;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -050098
Philip P. Moltmanne683f192017-06-23 14:05:04 -070099import libcore.util.EmptyArray;
100
101import org.xmlpull.v1.XmlPullParser;
102import org.xmlpull.v1.XmlPullParserException;
103import org.xmlpull.v1.XmlSerializer;
104
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800105import java.io.File;
106import java.io.FileDescriptor;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800107import java.io.FileInputStream;
108import java.io.FileNotFoundException;
109import java.io.FileOutputStream;
110import java.io.IOException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800111import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100112import java.nio.charset.StandardCharsets;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700113import java.text.SimpleDateFormat;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800114import java.util.ArrayList;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700115import java.util.Arrays;
Svetoslav215b44a2015-08-04 19:03:40 -0700116import java.util.Collections;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700117import java.util.Date;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800118import java.util.HashMap;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800119import java.util.Iterator;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800120import java.util.List;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700121import java.util.Map;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800122
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800123public class AppOpsService extends IAppOpsService.Stub {
124 static final String TAG = "AppOps";
Dianne Hackborn35654b62013-01-14 17:38:02 -0800125 static final boolean DEBUG = false;
126
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700127 private static final int NO_VERSION = -1;
128 /** Increment by one every time and add the corresponding upgrade logic in
129 * {@link #upgradeLocked(int)} below. The first version was 1 */
130 private static final int CURRENT_VERSION = 1;
131
Dianne Hackborn35654b62013-01-14 17:38:02 -0800132 // Write at most every 30 minutes.
133 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800134
Svet Ganov3a95f832018-03-23 17:44:30 -0700135 // Constant meaning that any UID should be matched when dispatching callbacks
136 private static final int UID_ANY = -2;
137
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700138 // Map from process states to the uid states we track.
139 private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
140 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
141 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
142 UID_STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
143 UID_STATE_FOREGROUND_SERVICE, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
144 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
145 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
146 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
147 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
148 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_BACKUP
149 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_SERVICE
150 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_RECEIVER
151 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
152 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
153 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HOME
154 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
155 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
156 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
157 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_RECENT
158 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
159 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT
160 };
161
162 static final String[] UID_STATE_NAMES = new String[] {
163 "pers ", // UID_STATE_PERSISTENT
164 "top ", // UID_STATE_TOP
165 "fgsvc", // UID_STATE_FOREGROUND_SERVICE
166 "fg ", // UID_STATE_FOREGROUND
167 "bg ", // UID_STATE_BACKGROUND
168 "cch ", // UID_STATE_CACHED
169 };
170
171 static final String[] UID_STATE_TIME_ATTRS = new String[] {
172 "tp", // UID_STATE_PERSISTENT
173 "tt", // UID_STATE_TOP
174 "tfs", // UID_STATE_FOREGROUND_SERVICE
175 "tf", // UID_STATE_FOREGROUND
176 "tb", // UID_STATE_BACKGROUND
177 "tc", // UID_STATE_CACHED
178 };
179
180 static final String[] UID_STATE_REJECT_ATTRS = new String[] {
181 "rp", // UID_STATE_PERSISTENT
182 "rt", // UID_STATE_TOP
183 "rfs", // UID_STATE_FOREGROUND_SERVICE
184 "rf", // UID_STATE_FOREGROUND
185 "rb", // UID_STATE_BACKGROUND
186 "rc", // UID_STATE_CACHED
187 };
188
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800189 Context mContext;
190 final AtomicFile mFile;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800191 final Handler mHandler;
192
Dianne Hackbornd5254412018-05-11 18:02:58 -0700193 private final AppOpsManagerInternalImpl mAppOpsManagerInternal
194 = new AppOpsManagerInternalImpl();
195
Dianne Hackborn35654b62013-01-14 17:38:02 -0800196 boolean mWriteScheduled;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800197 boolean mFastWriteScheduled;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800198 final Runnable mWriteRunner = new Runnable() {
199 public void run() {
200 synchronized (AppOpsService.this) {
201 mWriteScheduled = false;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800202 mFastWriteScheduled = false;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800203 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
204 @Override protected Void doInBackground(Void... params) {
205 writeState();
206 return null;
207 }
208 };
209 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
210 }
211 }
212 };
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800213
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700214 @VisibleForTesting
215 final SparseArray<UidState> mUidStates = new SparseArray<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800216
Dianne Hackborn9fb93502018-06-18 12:29:44 -0700217 long mLastRealtime;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700218
Ruben Brunk29931bc2016-03-11 00:24:26 -0800219 /*
220 * These are app op restrictions imposed per user from various parties.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800221 */
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700222 private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
Jason Monk62062992014-05-06 09:55:28 -0400223
Dianne Hackbornd5254412018-05-11 18:02:58 -0700224 SparseIntArray mProfileOwners;
225
Todd Kennedy556efba2018-11-15 07:43:55 -0800226 @GuardedBy("this")
Svet Ganovd873ae62018-06-25 16:39:23 -0700227 private CheckOpsDelegate mCheckOpsDelegate;
228
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700229 /**
230 * All times are in milliseconds. These constants are kept synchronized with the system
231 * global Settings. Any access to this class or its fields should be done while
232 * holding the AppOpsService lock.
233 */
234 private final class Constants extends ContentObserver {
235 // Key names stored in the settings value.
Dianne Hackborne93ab412018-05-14 17:52:30 -0700236 private static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
237 private static final String KEY_FG_SERVICE_STATE_SETTLE_TIME
238 = "fg_service_state_settle_time";
239 private static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700240
241 /**
Dianne Hackborne93ab412018-05-14 17:52:30 -0700242 * How long we want for a drop in uid state from top to settle before applying it.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700243 * @see Settings.Global#APP_OPS_CONSTANTS
Dianne Hackborne93ab412018-05-14 17:52:30 -0700244 * @see #KEY_TOP_STATE_SETTLE_TIME
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700245 */
Dianne Hackborne93ab412018-05-14 17:52:30 -0700246 public long TOP_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700247
Dianne Hackborne93ab412018-05-14 17:52:30 -0700248 /**
249 * How long we want for a drop in uid state from foreground to settle before applying it.
250 * @see Settings.Global#APP_OPS_CONSTANTS
251 * @see #KEY_FG_SERVICE_STATE_SETTLE_TIME
252 */
253 public long FG_SERVICE_STATE_SETTLE_TIME;
254
255 /**
256 * How long we want for a drop in uid state from background to settle before applying it.
257 * @see Settings.Global#APP_OPS_CONSTANTS
258 * @see #KEY_BG_STATE_SETTLE_TIME
259 */
260 public long BG_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700261
262 private final KeyValueListParser mParser = new KeyValueListParser(',');
263 private ContentResolver mResolver;
264
265 public Constants(Handler handler) {
266 super(handler);
267 updateConstants();
268 }
269
270 public void startMonitoring(ContentResolver resolver) {
271 mResolver = resolver;
272 mResolver.registerContentObserver(
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700273 Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700274 false, this);
275 updateConstants();
276 }
277
278 @Override
279 public void onChange(boolean selfChange, Uri uri) {
280 updateConstants();
281 }
282
283 private void updateConstants() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700284 String value = mResolver != null ? Settings.Global.getString(mResolver,
285 Settings.Global.APP_OPS_CONSTANTS) : "";
286
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700287 synchronized (AppOpsService.this) {
288 try {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700289 mParser.setString(value);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700290 } catch (IllegalArgumentException e) {
291 // Failed to parse the settings string, log this and move on
292 // with defaults.
293 Slog.e(TAG, "Bad app ops settings", e);
294 }
Dianne Hackborne93ab412018-05-14 17:52:30 -0700295 TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
296 KEY_TOP_STATE_SETTLE_TIME, 30 * 1000L);
297 FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
298 KEY_FG_SERVICE_STATE_SETTLE_TIME, 10 * 1000L);
299 BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
300 KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700301 }
302 }
303
304 void dump(PrintWriter pw) {
305 pw.println(" Settings:");
306
Dianne Hackborne93ab412018-05-14 17:52:30 -0700307 pw.print(" "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("=");
308 TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700309 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700310 pw.print(" "); pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME); pw.print("=");
311 TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700312 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700313 pw.print(" "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("=");
314 TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700315 pw.println();
316 }
317 }
318
319 private final Constants mConstants;
320
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700321 @VisibleForTesting
322 static final class UidState {
Svet Ganov2af57082015-07-30 08:44:20 -0700323 public final int uid;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700324
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700325 public int state = UID_STATE_CACHED;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700326 public int pendingState = UID_STATE_CACHED;
327 public long pendingStateCommitTime;
328
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700329 public int startNesting;
Svet Ganov2af57082015-07-30 08:44:20 -0700330 public ArrayMap<String, Ops> pkgOps;
331 public SparseIntArray opModes;
332
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700333 // true indicates there is an interested observer, false there isn't but it has such an op
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700334 public SparseBooleanArray foregroundOps;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700335 public boolean hasForegroundWatchers;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700336
Svet Ganov2af57082015-07-30 08:44:20 -0700337 public UidState(int uid) {
338 this.uid = uid;
339 }
340
341 public void clear() {
342 pkgOps = null;
343 opModes = null;
344 }
345
346 public boolean isDefault() {
347 return (pkgOps == null || pkgOps.isEmpty())
348 && (opModes == null || opModes.size() <= 0);
349 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700350
351 int evalMode(int mode) {
352 if (mode == AppOpsManager.MODE_FOREGROUND) {
Dianne Hackborne93ab412018-05-14 17:52:30 -0700353 return state <= UID_STATE_LAST_NON_RESTRICTED
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700354 ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
355 }
356 return mode;
357 }
358
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700359 private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
360 SparseBooleanArray which) {
361 boolean curValue = which.get(op, false);
362 ArraySet<ModeCallback> callbacks = watchers.get(op);
363 if (callbacks != null) {
364 for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
365 if ((callbacks.valueAt(cbi).mFlags
366 & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
367 hasForegroundWatchers = true;
368 curValue = true;
369 }
370 }
371 }
372 which.put(op, curValue);
373 }
374
375 public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700376 SparseBooleanArray which = null;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700377 hasForegroundWatchers = false;
378 if (opModes != null) {
379 for (int i = opModes.size() - 1; i >= 0; i--) {
380 if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
381 if (which == null) {
382 which = new SparseBooleanArray();
383 }
384 evalForegroundWatchers(opModes.keyAt(i), watchers, which);
385 }
386 }
387 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700388 if (pkgOps != null) {
389 for (int i = pkgOps.size() - 1; i >= 0; i--) {
390 Ops ops = pkgOps.valueAt(i);
391 for (int j = ops.size() - 1; j >= 0; j--) {
392 if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
393 if (which == null) {
394 which = new SparseBooleanArray();
395 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700396 evalForegroundWatchers(ops.keyAt(j), watchers, which);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700397 }
398 }
399 }
400 }
401 foregroundOps = which;
402 }
Svet Ganov2af57082015-07-30 08:44:20 -0700403 }
404
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700405 final static class Ops extends SparseArray<Op> {
406 final String packageName;
407 final UidState uidState;
408 final boolean isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800409
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700410 Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800411 packageName = _packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700412 uidState = _uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400413 isPrivileged = _isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800414 }
415 }
416
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700417 final static class Op {
418 final UidState uidState;
419 final int uid;
420 final String packageName;
421 final int op;
422 int proxyUid = -1;
423 String proxyPackageName;
424 int mode;
425 int duration;
426 long time[] = new long[_NUM_UID_STATE];
427 long rejectTime[] = new long[_NUM_UID_STATE];
428 int startNesting;
429 long startRealtime;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800430
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700431 Op(UidState _uidState, String _packageName, int _op) {
432 uidState = _uidState;
433 uid = _uidState.uid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700434 packageName = _packageName;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800435 op = _op;
David Braunf5d83192013-09-16 13:43:51 -0700436 mode = AppOpsManager.opToDefaultMode(op);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800437 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700438
439 boolean hasAnyTime() {
440 for (int i = 0; i < AppOpsManager._NUM_UID_STATE; i++) {
441 if (time[i] != 0) {
442 return true;
443 }
444 if (rejectTime[i] != 0) {
445 return true;
446 }
447 }
448 return false;
449 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700450
451 int getMode() {
452 return uidState.evalMode(mode);
453 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800454 }
455
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800456 final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
457 final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
458 final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
459 final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800460 final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>();
Dianne Hackborn68d76552017-02-27 15:32:03 -0800461 final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800462
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700463 final class ModeCallback implements DeathRecipient {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800464 final IAppOpsCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700465 final int mWatchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700466 final int mFlags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700467 final int mCallingUid;
468 final int mCallingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800469
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700470 ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700471 int callingPid) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800472 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700473 mWatchingUid = watchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700474 mFlags = flags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700475 mCallingUid = callingUid;
476 mCallingPid = callingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800477 try {
478 mCallback.asBinder().linkToDeath(this, 0);
479 } catch (RemoteException e) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800480 /*ignored*/
Dianne Hackbornc2293022013-02-06 23:14:49 -0800481 }
482 }
483
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700484 public boolean isWatchingUid(int uid) {
485 return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
486 }
487
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700488 @Override
489 public String toString() {
490 StringBuilder sb = new StringBuilder(128);
491 sb.append("ModeCallback{");
492 sb.append(Integer.toHexString(System.identityHashCode(this)));
493 sb.append(" watchinguid=");
494 UserHandle.formatUid(sb, mWatchingUid);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700495 sb.append(" flags=0x");
496 sb.append(Integer.toHexString(mFlags));
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700497 sb.append(" from uid=");
498 UserHandle.formatUid(sb, mCallingUid);
499 sb.append(" pid=");
500 sb.append(mCallingPid);
501 sb.append('}');
502 return sb.toString();
503 }
504
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700505 void unlinkToDeath() {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800506 mCallback.asBinder().unlinkToDeath(this, 0);
507 }
508
509 @Override
510 public void binderDied() {
511 stopWatchingMode(mCallback);
512 }
513 }
514
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700515 final class ActiveCallback implements DeathRecipient {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800516 final IAppOpsActiveCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700517 final int mWatchingUid;
518 final int mCallingUid;
519 final int mCallingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800520
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700521 ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700522 int callingPid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800523 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700524 mWatchingUid = watchingUid;
525 mCallingUid = callingUid;
526 mCallingPid = callingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800527 try {
528 mCallback.asBinder().linkToDeath(this, 0);
529 } catch (RemoteException e) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800530 /*ignored*/
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800531 }
532 }
533
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700534 @Override
535 public String toString() {
536 StringBuilder sb = new StringBuilder(128);
537 sb.append("ActiveCallback{");
538 sb.append(Integer.toHexString(System.identityHashCode(this)));
539 sb.append(" watchinguid=");
540 UserHandle.formatUid(sb, mWatchingUid);
541 sb.append(" from uid=");
542 UserHandle.formatUid(sb, mCallingUid);
543 sb.append(" pid=");
544 sb.append(mCallingPid);
545 sb.append('}');
546 return sb.toString();
547 }
548
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700549 void destroy() {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800550 mCallback.asBinder().unlinkToDeath(this, 0);
551 }
552
553 @Override
554 public void binderDied() {
555 stopWatchingActive(mCallback);
556 }
557 }
558
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800559 final class NotedCallback implements DeathRecipient {
560 final IAppOpsNotedCallback mCallback;
561 final int mWatchingUid;
562 final int mCallingUid;
563 final int mCallingPid;
564
565 NotedCallback(IAppOpsNotedCallback callback, int watchingUid, int callingUid,
566 int callingPid) {
567 mCallback = callback;
568 mWatchingUid = watchingUid;
569 mCallingUid = callingUid;
570 mCallingPid = callingPid;
571 try {
572 mCallback.asBinder().linkToDeath(this, 0);
573 } catch (RemoteException e) {
574 /*ignored*/
575 }
576 }
577
578 @Override
579 public String toString() {
580 StringBuilder sb = new StringBuilder(128);
581 sb.append("NotedCallback{");
582 sb.append(Integer.toHexString(System.identityHashCode(this)));
583 sb.append(" watchinguid=");
584 UserHandle.formatUid(sb, mWatchingUid);
585 sb.append(" from uid=");
586 UserHandle.formatUid(sb, mCallingUid);
587 sb.append(" pid=");
588 sb.append(mCallingPid);
589 sb.append('}');
590 return sb.toString();
591 }
592
593 void destroy() {
594 mCallback.asBinder().unlinkToDeath(this, 0);
595 }
596
597 @Override
598 public void binderDied() {
599 stopWatchingNoted(mCallback);
600 }
601 }
602
Svet Ganova7a0db62018-02-27 20:08:01 -0800603 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700604
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700605 final class ClientState extends Binder implements DeathRecipient {
Svet Ganovf7b47252018-02-26 11:11:27 -0800606 final ArrayList<Op> mStartedOps = new ArrayList<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700607 final IBinder mAppToken;
608 final int mPid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700609
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700610 ClientState(IBinder appToken) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700611 mAppToken = appToken;
612 mPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -0800613 // Watch only for remote processes dying
614 if (!(appToken instanceof Binder)) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700615 try {
616 mAppToken.linkToDeath(this, 0);
617 } catch (RemoteException e) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800618 /* do nothing */
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700619 }
620 }
621 }
622
623 @Override
624 public String toString() {
625 return "ClientState{" +
626 "mAppToken=" + mAppToken +
Svet Ganovf7b47252018-02-26 11:11:27 -0800627 ", " + "pid=" + mPid +
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700628 '}';
629 }
630
631 @Override
632 public void binderDied() {
633 synchronized (AppOpsService.this) {
634 for (int i=mStartedOps.size()-1; i>=0; i--) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800635 finishOperationLocked(mStartedOps.get(i), /*finishNested*/ true);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700636 }
637 mClients.remove(mAppToken);
638 }
639 }
640 }
641
Jeff Brown6f357d32014-01-15 20:40:55 -0800642 public AppOpsService(File storagePath, Handler handler) {
Jeff Sharkey5f3e9342017-03-13 14:53:11 -0600643 LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
Dianne Hackborne17b4452018-01-10 13:15:40 -0800644 mFile = new AtomicFile(storagePath, "appops");
Jeff Brown6f357d32014-01-15 20:40:55 -0800645 mHandler = handler;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700646 mConstants = new Constants(mHandler);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800647 readState();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800648 }
David Braunf5d83192013-09-16 13:43:51 -0700649
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800650 public void publish(Context context) {
651 mContext = context;
652 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
Dianne Hackbornd5254412018-05-11 18:02:58 -0700653 LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800654 }
655
Dianne Hackborn514074f2013-02-11 10:52:46 -0800656 public void systemReady() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700657 mConstants.startMonitoring(mContext.getContentResolver());
658
Dianne Hackborn514074f2013-02-11 10:52:46 -0800659 synchronized (this) {
660 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700661 for (int i = mUidStates.size() - 1; i >= 0; i--) {
662 UidState uidState = mUidStates.valueAt(i);
663
664 String[] packageNames = getPackagesForUid(uidState.uid);
665 if (ArrayUtils.isEmpty(packageNames)) {
666 uidState.clear();
667 mUidStates.removeAt(i);
668 changed = true;
669 continue;
670 }
671
672 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
673 if (pkgs == null) {
674 continue;
675 }
676
Dianne Hackborn514074f2013-02-11 10:52:46 -0800677 Iterator<Ops> it = pkgs.values().iterator();
678 while (it.hasNext()) {
679 Ops ops = it.next();
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700680 int curUid = -1;
Dianne Hackborn514074f2013-02-11 10:52:46 -0800681 try {
Jeff Sharkeycd654482016-01-08 17:42:11 -0700682 curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
683 PackageManager.MATCH_UNINSTALLED_PACKAGES,
Svet Ganov2af57082015-07-30 08:44:20 -0700684 UserHandle.getUserId(ops.uidState.uid));
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700685 } catch (RemoteException ignored) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800686 }
Svet Ganov2af57082015-07-30 08:44:20 -0700687 if (curUid != ops.uidState.uid) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800688 Slog.i(TAG, "Pruning old package " + ops.packageName
Svet Ganov2af57082015-07-30 08:44:20 -0700689 + "/" + ops.uidState + ": new uid=" + curUid);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800690 it.remove();
691 changed = true;
692 }
693 }
Svet Ganov2af57082015-07-30 08:44:20 -0700694
695 if (uidState.isDefault()) {
696 mUidStates.removeAt(i);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800697 }
698 }
699 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800700 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800701 }
702 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700703
Suprabh Shukla3017fe42018-11-08 19:00:01 -0800704 final IntentFilter packageSuspendFilter = new IntentFilter();
705 packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
706 packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
707 mContext.registerReceiver(new BroadcastReceiver() {
708 @Override
709 public void onReceive(Context context, Intent intent) {
710 final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
711 final String[] changedPkgs = intent.getStringArrayExtra(
712 Intent.EXTRA_CHANGED_PACKAGE_LIST);
713 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(OP_PLAY_AUDIO);
714 for (int i = 0; i < changedUids.length; i++) {
715 final int changedUid = changedUids[i];
716 final String changedPkg = changedPkgs[i];
717 // We trust packagemanager to insert matching uid and packageNames in the extras
718 mHandler.sendMessage(PooledLambda.obtainMessage(AppOpsService::notifyOpChanged,
719 AppOpsService.this, callbacks, OP_PLAY_AUDIO, changedUid, changedPkg));
720 }
721 }
722 }, packageSuspendFilter);
723
Suprabh Shuklaaef25132017-01-23 18:09:03 -0800724 PackageManagerInternal packageManagerInternal = LocalServices.getService(
725 PackageManagerInternal.class);
726 packageManagerInternal.setExternalSourcesPolicy(
727 new PackageManagerInternal.ExternalSourcesPolicy() {
728 @Override
729 public int getPackageTrustedToInstallApps(String packageName, int uid) {
730 int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
731 uid, packageName);
732 switch (appOpMode) {
733 case AppOpsManager.MODE_ALLOWED:
734 return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
735 case AppOpsManager.MODE_ERRORED:
736 return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
737 default:
738 return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
739 }
740 }
741 });
742
Jeff Sharkey10ec9d82018-11-28 14:52:45 -0700743 if (!StorageManager.hasIsolatedStorage()) {
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700744 StorageManagerInternal storageManagerInternal = LocalServices.getService(
745 StorageManagerInternal.class);
746 storageManagerInternal.addExternalStoragePolicy(
747 new StorageManagerInternal.ExternalStorageMountPolicy() {
748 @Override
749 public int getMountMode(int uid, String packageName) {
750 if (Process.isIsolated(uid)) {
751 return Zygote.MOUNT_EXTERNAL_NONE;
752 }
753 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
754 packageName) != AppOpsManager.MODE_ALLOWED) {
755 return Zygote.MOUNT_EXTERNAL_NONE;
756 }
757 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
758 packageName) != AppOpsManager.MODE_ALLOWED) {
759 return Zygote.MOUNT_EXTERNAL_READ;
760 }
761 return Zygote.MOUNT_EXTERNAL_WRITE;
Svet Ganov6ee871e2015-07-10 14:29:33 -0700762 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700763
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700764 @Override
765 public boolean hasExternalStorage(int uid, String packageName) {
766 final int mountMode = getMountMode(uid, packageName);
767 return mountMode == Zygote.MOUNT_EXTERNAL_READ
768 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
769 }
770 });
771 }
Dianne Hackborn514074f2013-02-11 10:52:46 -0800772 }
773
774 public void packageRemoved(int uid, String packageName) {
775 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700776 UidState uidState = mUidStates.get(uid);
777 if (uidState == null) {
778 return;
779 }
780
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800781 Ops ops = null;
Svet Ganov2af57082015-07-30 08:44:20 -0700782
783 // Remove any package state if such.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800784 if (uidState.pkgOps != null) {
785 ops = uidState.pkgOps.remove(packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700786 }
787
788 // If we just nuked the last package state check if the UID is valid.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800789 if (ops != null && uidState.pkgOps.isEmpty()
Svet Ganov2af57082015-07-30 08:44:20 -0700790 && getPackagesForUid(uid).length <= 0) {
791 mUidStates.remove(uid);
792 }
793
Svet Ganova7a0db62018-02-27 20:08:01 -0800794 // Finish ops other packages started on behalf of the package.
795 final int clientCount = mClients.size();
796 for (int i = 0; i < clientCount; i++) {
797 final ClientState client = mClients.valueAt(i);
798 if (client.mStartedOps == null) {
799 continue;
800 }
801 final int opCount = client.mStartedOps.size();
802 for (int j = opCount - 1; j >= 0; j--) {
803 final Op op = client.mStartedOps.get(j);
804 if (uid == op.uid && packageName.equals(op.packageName)) {
805 finishOperationLocked(op, /*finishNested*/ true);
806 client.mStartedOps.remove(j);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700807 if (op.startNesting <= 0) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800808 scheduleOpActiveChangedIfNeededLocked(op.op,
809 uid, packageName, false);
810 }
811 }
812 }
813 }
814
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800815 if (ops != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700816 scheduleFastWriteLocked();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800817
818 final int opCount = ops.size();
819 for (int i = 0; i < opCount; i++) {
820 final Op op = ops.valueAt(i);
821 if (op.duration == -1) {
822 scheduleOpActiveChangedIfNeededLocked(
823 op.op, op.uid, op.packageName, false);
824 }
825 }
Dianne Hackborn514074f2013-02-11 10:52:46 -0800826 }
827 }
828 }
829
830 public void uidRemoved(int uid) {
831 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700832 if (mUidStates.indexOfKey(uid) >= 0) {
833 mUidStates.remove(uid);
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800834 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800835 }
836 }
837 }
838
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700839 public void updateUidProcState(int uid, int procState) {
840 synchronized (this) {
841 final UidState uidState = getUidStateLocked(uid, true);
842 final int newState = PROCESS_STATE_TO_UID_STATE[procState];
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700843 if (uidState != null && uidState.pendingState != newState) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700844 final int oldPendingState = uidState.pendingState;
845 uidState.pendingState = newState;
Dianne Hackborne93ab412018-05-14 17:52:30 -0700846 if (newState < uidState.state || newState <= UID_STATE_LAST_NON_RESTRICTED) {
847 // We are moving to a more important state, or the new state is in the
848 // foreground, then always do it immediately.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700849 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700850 } else if (uidState.pendingStateCommitTime == 0) {
851 // We are moving to a less important state for the first time,
852 // delay the application for a bit.
Dianne Hackborne93ab412018-05-14 17:52:30 -0700853 final long settleTime;
854 if (uidState.state <= UID_STATE_TOP) {
855 settleTime = mConstants.TOP_STATE_SETTLE_TIME;
856 } else if (uidState.state <= UID_STATE_FOREGROUND_SERVICE) {
857 settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
858 } else {
859 settleTime = mConstants.BG_STATE_SETTLE_TIME;
860 }
Dianne Hackborn9fb93502018-06-18 12:29:44 -0700861 uidState.pendingStateCommitTime = SystemClock.elapsedRealtime() + settleTime;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700862 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700863 if (uidState.startNesting != 0) {
864 // There is some actively running operation... need to find it
865 // and appropriately update its state.
866 final long now = System.currentTimeMillis();
867 for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
868 final Ops ops = uidState.pkgOps.valueAt(i);
869 for (int j = ops.size() - 1; j >= 0; j--) {
870 final Op op = ops.valueAt(j);
871 if (op.startNesting > 0) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700872 op.time[oldPendingState] = now;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700873 op.time[newState] = now;
874 }
875 }
876 }
877 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700878 }
879 }
880 }
881
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800882 public void shutdown() {
883 Slog.w(TAG, "Writing app ops before shutdown...");
Dianne Hackborn35654b62013-01-14 17:38:02 -0800884 boolean doWrite = false;
885 synchronized (this) {
886 if (mWriteScheduled) {
887 mWriteScheduled = false;
888 doWrite = true;
889 }
890 }
891 if (doWrite) {
892 writeState();
893 }
894 }
895
Dianne Hackborn72e39832013-01-18 18:36:09 -0800896 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
897 ArrayList<AppOpsManager.OpEntry> resOps = null;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700898 final long elapsedNow = SystemClock.elapsedRealtime();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800899 if (ops == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700900 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800901 for (int j=0; j<pkgOps.size(); j++) {
902 Op curOp = pkgOps.valueAt(j);
Amith Yamasania1ce9632018-05-28 20:50:48 -0700903 final boolean running = curOp.duration == -1;
904 long duration = running
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700905 ? (elapsedNow - curOp.startRealtime)
906 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800907 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Amith Yamasania1ce9632018-05-28 20:50:48 -0700908 curOp.rejectTime, (int) duration, running, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700909 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800910 }
911 } else {
912 for (int j=0; j<ops.length; j++) {
913 Op curOp = pkgOps.get(ops[j]);
914 if (curOp != null) {
915 if (resOps == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700916 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800917 }
Amith Yamasania1ce9632018-05-28 20:50:48 -0700918 final boolean running = curOp.duration == -1;
919 final long duration = running
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700920 ? (elapsedNow - curOp.startRealtime)
921 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800922 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Amith Yamasania1ce9632018-05-28 20:50:48 -0700923 curOp.rejectTime, (int) duration, running, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700924 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800925 }
926 }
927 }
928 return resOps;
929 }
930
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700931 private ArrayList<AppOpsManager.OpEntry> collectOps(SparseIntArray uidOps, int[] ops) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -0800932 if (uidOps == null) {
933 return null;
934 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700935 ArrayList<AppOpsManager.OpEntry> resOps = null;
936 if (ops == null) {
937 resOps = new ArrayList<>();
938 for (int j=0; j<uidOps.size(); j++) {
939 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(j), uidOps.valueAt(j),
940 0, 0, 0, -1, null));
941 }
942 } else {
943 for (int j=0; j<ops.length; j++) {
944 int index = uidOps.indexOfKey(ops[j]);
945 if (index >= 0) {
946 if (resOps == null) {
947 resOps = new ArrayList<>();
948 }
949 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(index), uidOps.valueAt(index),
950 0, 0, 0, -1, null));
951 }
952 }
953 }
954 return resOps;
955 }
956
Dianne Hackborn35654b62013-01-14 17:38:02 -0800957 @Override
958 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
959 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
960 Binder.getCallingPid(), Binder.getCallingUid(), null);
961 ArrayList<AppOpsManager.PackageOps> res = null;
962 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700963 final int uidStateCount = mUidStates.size();
964 for (int i = 0; i < uidStateCount; i++) {
965 UidState uidState = mUidStates.valueAt(i);
966 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
967 continue;
968 }
969 ArrayMap<String, Ops> packages = uidState.pkgOps;
970 final int packageCount = packages.size();
971 for (int j = 0; j < packageCount; j++) {
972 Ops pkgOps = packages.valueAt(j);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800973 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800974 if (resOps != null) {
975 if (res == null) {
976 res = new ArrayList<AppOpsManager.PackageOps>();
977 }
978 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700979 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800980 res.add(resPackage);
981 }
982 }
983 }
984 }
985 return res;
986 }
987
988 @Override
Dianne Hackborn72e39832013-01-18 18:36:09 -0800989 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
990 int[] ops) {
991 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
992 Binder.getCallingPid(), Binder.getCallingUid(), null);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000993 String resolvedPackageName = resolvePackageName(uid, packageName);
994 if (resolvedPackageName == null) {
995 return Collections.emptyList();
996 }
Dianne Hackborn72e39832013-01-18 18:36:09 -0800997 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -0700998 Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
999 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001000 if (pkgOps == null) {
1001 return null;
1002 }
1003 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
1004 if (resOps == null) {
1005 return null;
1006 }
1007 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
1008 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -07001009 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001010 res.add(resPackage);
1011 return res;
1012 }
1013 }
1014
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001015 @Override
Svet Ganovad0a49b2018-10-29 10:07:08 -07001016 public @Nullable ParceledListSlice getAllHistoricalPackagesOps(@Nullable String[] opNames,
1017 long beginTimeMillis, long endTimeMillis) {
1018 Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
1019 "beginTimeMillis must be non negative and lesser than endTimeMillis");
1020
1021 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1022 Binder.getCallingPid(), Binder.getCallingUid(), "getAllHistoricalPackagesOps");
1023
1024 ArrayList<HistoricalPackageOps> historicalPackageOpsList = null;
1025
1026 final int uidStateCount = mUidStates.size();
1027 for (int i = 0; i < uidStateCount; i++) {
1028 final UidState uidState = mUidStates.valueAt(i);
1029 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
1030 continue;
1031 }
1032 final ArrayMap<String, Ops> packages = uidState.pkgOps;
1033 final int packageCount = packages.size();
1034 for (int j = 0; j < packageCount; j++) {
1035 final Ops pkgOps = packages.valueAt(j);
1036 final AppOpsManager.HistoricalPackageOps historicalPackageOps =
1037 createHistoricalPackageOps(uidState.uid, pkgOps, opNames,
1038 beginTimeMillis, endTimeMillis);
1039 if (historicalPackageOps != null) {
1040 if (historicalPackageOpsList == null) {
1041 historicalPackageOpsList = new ArrayList<>();
1042 }
1043 historicalPackageOpsList.add(historicalPackageOps);
1044 }
1045 }
1046 }
1047
1048 if (historicalPackageOpsList == null) {
1049 return null;
1050 }
1051
1052 return new ParceledListSlice<>(historicalPackageOpsList);
1053 }
1054
1055 private static @Nullable HistoricalPackageOps createHistoricalPackageOps(int uid,
1056 @Nullable Ops pkgOps, @Nullable String[] opNames, long beginTimeMillis,
1057 long endTimeMillis) {
1058 // TODO: Implement historical data collection
1059 if (pkgOps == null) {
1060 return null;
1061 }
1062
1063 final HistoricalPackageOps historicalPackageOps = new HistoricalPackageOps(uid,
1064 pkgOps.packageName);
1065
1066 if (opNames == null) {
1067 opNames = AppOpsManager.getOpStrs();
1068 }
1069 for (String opName : opNames) {
1070 addHistoricOpEntry(AppOpsManager.strOpToOp(opName), pkgOps, historicalPackageOps);
1071 }
1072
1073 return historicalPackageOps;
1074 }
1075
1076 @Override
1077 public @Nullable HistoricalPackageOps getHistoricalPackagesOps(int uid,
1078 @NonNull String packageName, @Nullable String[] opNames,
1079 long beginTimeMillis, long endTimeMillis) {
1080 Preconditions.checkNotNull(packageName,
1081 "packageName cannot be null");
1082 Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
1083 "beginTimeMillis must be non negative and lesser than endTimeMillis");
1084
1085 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1086 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalPackagesOps");
1087
1088 final String resolvedPackageName = resolvePackageName(uid, packageName);
1089 if (resolvedPackageName == null) {
1090 return null;
1091 }
1092
1093 // TODO: Implement historical data collection
1094 final Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
1095 false /* uidMismatchExpected */);
1096 return createHistoricalPackageOps(uid, pkgOps, opNames, beginTimeMillis, endTimeMillis);
1097 }
1098
1099 private static void addHistoricOpEntry(int opCode, @NonNull Ops ops,
1100 @NonNull HistoricalPackageOps outHistoricalPackageOps) {
1101 final Op op = ops.get(opCode);
1102 if (op == null) {
1103 return;
1104 }
1105
1106 final HistoricalOpEntry historicalOpEntry = new HistoricalOpEntry(opCode);
1107
1108 // TODO: Keep per UID state duration
1109 for (int uidState = 0; uidState < AppOpsManager._NUM_UID_STATE; uidState++) {
1110 final int acceptCount;
1111 final int rejectCount;
1112 if (op.rejectTime[uidState] == 0) {
1113 acceptCount = 1;
1114 rejectCount = 0;
1115 } else {
1116 acceptCount = 0;
1117 rejectCount = 1;
1118 }
1119 historicalOpEntry.addEntry(uidState, acceptCount, rejectCount, 0);
1120 }
1121
1122 outHistoricalPackageOps.addEntry(historicalOpEntry);
1123 }
1124
1125 @Override
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001126 public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
1127 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1128 Binder.getCallingPid(), Binder.getCallingUid(), null);
1129 synchronized (this) {
1130 UidState uidState = getUidStateLocked(uid, false);
1131 if (uidState == null) {
1132 return null;
1133 }
1134 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState.opModes, ops);
1135 if (resOps == null) {
1136 return null;
1137 }
1138 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
1139 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
1140 null, uidState.uid, resOps);
1141 res.add(resPackage);
1142 return res;
1143 }
1144 }
1145
Dianne Hackborn607b4142013-08-02 18:10:10 -07001146 private void pruneOp(Op op, int uid, String packageName) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001147 if (!op.hasAnyTime()) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001148 Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
1149 false /* uidMismatchExpected */);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001150 if (ops != null) {
1151 ops.remove(op.op);
1152 if (ops.size() <= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -07001153 UidState uidState = ops.uidState;
1154 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001155 if (pkgOps != null) {
1156 pkgOps.remove(ops.packageName);
Svet Ganov2af57082015-07-30 08:44:20 -07001157 if (pkgOps.isEmpty()) {
1158 uidState.pkgOps = null;
1159 }
1160 if (uidState.isDefault()) {
1161 mUidStates.remove(uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001162 }
1163 }
1164 }
1165 }
1166 }
1167 }
1168
Dianne Hackbornd5254412018-05-11 18:02:58 -07001169 void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
1170 if (callingPid == Process.myPid()) {
1171 return;
1172 }
1173 final int callingUser = UserHandle.getUserId(callingUid);
1174 synchronized (this) {
1175 if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
1176 if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
1177 // Profile owners are allowed to change modes but only for apps
1178 // within their user.
1179 return;
1180 }
1181 }
1182 }
1183 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
1184 Binder.getCallingPid(), Binder.getCallingUid(), null);
1185 }
1186
Dianne Hackborn72e39832013-01-18 18:36:09 -08001187 @Override
Svet Ganov2af57082015-07-30 08:44:20 -07001188 public void setUidMode(int code, int uid, int mode) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08001189 if (DEBUG) {
1190 Slog.i(TAG, "uid " + uid + " OP_" + opToName(code) + " := " + modeToName(mode)
1191 + " by uid " + Binder.getCallingUid());
1192 }
1193
Dianne Hackbornd5254412018-05-11 18:02:58 -07001194 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Svet Ganov2af57082015-07-30 08:44:20 -07001195 verifyIncomingOp(code);
1196 code = AppOpsManager.opToSwitch(code);
1197
1198 synchronized (this) {
1199 final int defaultMode = AppOpsManager.opToDefaultMode(code);
1200
1201 UidState uidState = getUidStateLocked(uid, false);
1202 if (uidState == null) {
1203 if (mode == defaultMode) {
1204 return;
1205 }
1206 uidState = new UidState(uid);
1207 uidState.opModes = new SparseIntArray();
1208 uidState.opModes.put(code, mode);
1209 mUidStates.put(uid, uidState);
1210 scheduleWriteLocked();
1211 } else if (uidState.opModes == null) {
1212 if (mode != defaultMode) {
1213 uidState.opModes = new SparseIntArray();
1214 uidState.opModes.put(code, mode);
1215 scheduleWriteLocked();
1216 }
1217 } else {
Hai Zhang2b98fb32018-09-21 15:18:46 -07001218 if (uidState.opModes.indexOfKey(code) >= 0 && uidState.opModes.get(code) == mode) {
Svet Ganov2af57082015-07-30 08:44:20 -07001219 return;
1220 }
1221 if (mode == defaultMode) {
1222 uidState.opModes.delete(code);
1223 if (uidState.opModes.size() <= 0) {
1224 uidState.opModes = null;
1225 }
1226 } else {
1227 uidState.opModes.put(code, mode);
1228 }
1229 scheduleWriteLocked();
1230 }
1231 }
1232
Svetoslav215b44a2015-08-04 19:03:40 -07001233 String[] uidPackageNames = getPackagesForUid(uid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001234 ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
Svet Ganov2af57082015-07-30 08:44:20 -07001235
riddle_hsu40b300f2015-11-23 13:22:03 +08001236 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001237 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001238 if (callbacks != null) {
Svet Ganov2af57082015-07-30 08:44:20 -07001239 final int callbackCount = callbacks.size();
1240 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001241 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08001242 ArraySet<String> changedPackages = new ArraySet<>();
1243 Collections.addAll(changedPackages, uidPackageNames);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001244 if (callbackSpecs == null) {
1245 callbackSpecs = new ArrayMap<>();
1246 }
riddle_hsu40b300f2015-11-23 13:22:03 +08001247 callbackSpecs.put(callback, changedPackages);
1248 }
1249 }
1250
1251 for (String uidPackageName : uidPackageNames) {
1252 callbacks = mPackageModeWatchers.get(uidPackageName);
1253 if (callbacks != null) {
1254 if (callbackSpecs == null) {
1255 callbackSpecs = new ArrayMap<>();
Svet Ganov2af57082015-07-30 08:44:20 -07001256 }
riddle_hsu40b300f2015-11-23 13:22:03 +08001257 final int callbackCount = callbacks.size();
1258 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001259 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08001260 ArraySet<String> changedPackages = callbackSpecs.get(callback);
1261 if (changedPackages == null) {
1262 changedPackages = new ArraySet<>();
1263 callbackSpecs.put(callback, changedPackages);
1264 }
1265 changedPackages.add(uidPackageName);
1266 }
Svet Ganov2af57082015-07-30 08:44:20 -07001267 }
1268 }
1269 }
1270
1271 if (callbackSpecs == null) {
1272 return;
1273 }
1274
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001275 for (int i = 0; i < callbackSpecs.size(); i++) {
1276 final ModeCallback callback = callbackSpecs.keyAt(i);
1277 final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
1278 if (reportedPackageNames == null) {
1279 mHandler.sendMessage(PooledLambda.obtainMessage(
1280 AppOpsService::notifyOpChanged,
1281 this, callback, code, uid, (String) null));
1282
1283 } else {
1284 final int reportedPackageCount = reportedPackageNames.size();
1285 for (int j = 0; j < reportedPackageCount; j++) {
1286 final String reportedPackageName = reportedPackageNames.valueAt(j);
1287 mHandler.sendMessage(PooledLambda.obtainMessage(
1288 AppOpsService::notifyOpChanged,
1289 this, callback, code, uid, reportedPackageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001290 }
1291 }
Svet Ganov2af57082015-07-30 08:44:20 -07001292 }
1293 }
1294
1295 @Override
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001296 public void setMode(int code, int uid, String packageName, int mode) {
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07001297 setMode(code, uid, packageName, mode, true, false);
1298 }
1299
1300 /**
1301 * Sets the mode for a certain op and uid.
1302 *
1303 * @param code The op code to set
1304 * @param uid The UID for which to set
1305 * @param packageName The package for which to set
1306 * @param mode The new mode to set
1307 * @param verifyUid Iff {@code true}, check that the package name belongs to the uid
1308 * @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid ==
1309 * false})
1310 */
1311 private void setMode(int code, int uid, @NonNull String packageName, int mode,
1312 boolean verifyUid, boolean isPrivileged) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001313 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001314 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001315 ArraySet<ModeCallback> repCbs = null;
Dianne Hackbornc2293022013-02-06 23:14:49 -08001316 code = AppOpsManager.opToSwitch(code);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001317 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001318 UidState uidState = getUidStateLocked(uid, false);
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07001319 Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001320 if (op != null) {
1321 if (op.mode != mode) {
1322 op.mode = mode;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001323 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001324 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001325 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001326 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001327 if (cbs != null) {
1328 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001329 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001330 }
1331 repCbs.addAll(cbs);
1332 }
1333 cbs = mPackageModeWatchers.get(packageName);
1334 if (cbs != null) {
1335 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001336 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001337 }
1338 repCbs.addAll(cbs);
1339 }
David Braunf5d83192013-09-16 13:43:51 -07001340 if (mode == AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001341 // If going into the default mode, prune this op
1342 // if there is nothing else interesting in it.
Dianne Hackborn607b4142013-08-02 18:10:10 -07001343 pruneOp(op, uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001344 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001345 scheduleFastWriteLocked();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001346 }
1347 }
1348 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001349 if (repCbs != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001350 mHandler.sendMessage(PooledLambda.obtainMessage(
1351 AppOpsService::notifyOpChanged,
1352 this, repCbs, code, uid, packageName));
Dianne Hackbornc2293022013-02-06 23:14:49 -08001353 }
1354 }
1355
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001356 private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
1357 int uid, String packageName) {
1358 for (int i = 0; i < callbacks.size(); i++) {
1359 final ModeCallback callback = callbacks.valueAt(i);
1360 notifyOpChanged(callback, code, uid, packageName);
1361 }
1362 }
1363
1364 private void notifyOpChanged(ModeCallback callback, int code,
1365 int uid, String packageName) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001366 if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001367 return;
1368 }
1369 // There are components watching for mode changes such as window manager
1370 // and location manager which are in our process. The callbacks in these
1371 // components may require permissions our remote caller does not have.
1372 final long identity = Binder.clearCallingIdentity();
1373 try {
1374 callback.mCallback.opChanged(code, uid, packageName);
1375 } catch (RemoteException e) {
1376 /* ignore */
1377 } finally {
1378 Binder.restoreCallingIdentity(identity);
1379 }
1380 }
1381
1382 private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
1383 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
1384 int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001385 if (cbs == null) {
1386 return callbacks;
1387 }
1388 if (callbacks == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001389 callbacks = new HashMap<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001390 }
Svet Ganov2af57082015-07-30 08:44:20 -07001391 boolean duplicate = false;
Dianne Hackborn68d76552017-02-27 15:32:03 -08001392 final int N = cbs.size();
1393 for (int i=0; i<N; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001394 ModeCallback cb = cbs.valueAt(i);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001395 ArrayList<ChangeRec> reports = callbacks.get(cb);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001396 if (reports == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001397 reports = new ArrayList<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001398 callbacks.put(cb, reports);
Svet Ganov2af57082015-07-30 08:44:20 -07001399 } else {
1400 final int reportCount = reports.size();
1401 for (int j = 0; j < reportCount; j++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001402 ChangeRec report = reports.get(j);
1403 if (report.op == op && report.pkg.equals(packageName)) {
Svet Ganov2af57082015-07-30 08:44:20 -07001404 duplicate = true;
1405 break;
1406 }
1407 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001408 }
Svet Ganov2af57082015-07-30 08:44:20 -07001409 if (!duplicate) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001410 reports.add(new ChangeRec(op, uid, packageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001411 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001412 }
1413 return callbacks;
1414 }
1415
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001416 static final class ChangeRec {
1417 final int op;
1418 final int uid;
1419 final String pkg;
1420
1421 ChangeRec(int _op, int _uid, String _pkg) {
1422 op = _op;
1423 uid = _uid;
1424 pkg = _pkg;
1425 }
1426 }
1427
Dianne Hackborn607b4142013-08-02 18:10:10 -07001428 @Override
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001429 public void resetAllModes(int reqUserId, String reqPackageName) {
1430 final int callingPid = Binder.getCallingPid();
1431 final int callingUid = Binder.getCallingUid();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001432 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
1433 true, true, "resetAllModes", null);
Svet Ganov2af57082015-07-30 08:44:20 -07001434
1435 int reqUid = -1;
1436 if (reqPackageName != null) {
1437 try {
1438 reqUid = AppGlobals.getPackageManager().getPackageUid(
Jeff Sharkeycd654482016-01-08 17:42:11 -07001439 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
Svet Ganov2af57082015-07-30 08:44:20 -07001440 } catch (RemoteException e) {
1441 /* ignore - local call */
1442 }
1443 }
1444
Dianne Hackbornd5254412018-05-11 18:02:58 -07001445 enforceManageAppOpsModes(callingPid, callingUid, reqUid);
1446
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001447 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001448 synchronized (this) {
1449 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -07001450 for (int i = mUidStates.size() - 1; i >= 0; i--) {
1451 UidState uidState = mUidStates.valueAt(i);
1452
1453 SparseIntArray opModes = uidState.opModes;
1454 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
1455 final int uidOpCount = opModes.size();
1456 for (int j = uidOpCount - 1; j >= 0; j--) {
1457 final int code = opModes.keyAt(j);
1458 if (AppOpsManager.opAllowsReset(code)) {
1459 opModes.removeAt(j);
1460 if (opModes.size() <= 0) {
1461 uidState.opModes = null;
1462 }
1463 for (String packageName : getPackagesForUid(uidState.uid)) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001464 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001465 mOpModeWatchers.get(code));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001466 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001467 mPackageModeWatchers.get(packageName));
1468 }
1469 }
1470 }
1471 }
1472
1473 if (uidState.pkgOps == null) {
1474 continue;
1475 }
1476
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001477 if (reqUserId != UserHandle.USER_ALL
Svet Ganov2af57082015-07-30 08:44:20 -07001478 && reqUserId != UserHandle.getUserId(uidState.uid)) {
Alexandra Gherghinad6a98972014-08-04 17:05:34 +01001479 // Skip any ops for a different user
1480 continue;
1481 }
Svet Ganov2af57082015-07-30 08:44:20 -07001482
1483 Map<String, Ops> packages = uidState.pkgOps;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001484 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001485 boolean uidChanged = false;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001486 while (it.hasNext()) {
1487 Map.Entry<String, Ops> ent = it.next();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001488 String packageName = ent.getKey();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001489 if (reqPackageName != null && !reqPackageName.equals(packageName)) {
1490 // Skip any ops for a different package
1491 continue;
1492 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001493 Ops pkgOps = ent.getValue();
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001494 for (int j=pkgOps.size()-1; j>=0; j--) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001495 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn8828d3a2013-09-25 16:47:10 -07001496 if (AppOpsManager.opAllowsReset(curOp.op)
1497 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
David Braunf5d83192013-09-16 13:43:51 -07001498 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001499 changed = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001500 uidChanged = true;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001501 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001502 mOpModeWatchers.get(curOp.op));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001503 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001504 mPackageModeWatchers.get(packageName));
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001505 if (!curOp.hasAnyTime()) {
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001506 pkgOps.removeAt(j);
1507 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001508 }
1509 }
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001510 if (pkgOps.size() == 0) {
1511 it.remove();
1512 }
1513 }
Svet Ganov2af57082015-07-30 08:44:20 -07001514 if (uidState.isDefault()) {
1515 mUidStates.remove(uidState.uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001516 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001517 if (uidChanged) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001518 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001519 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001520 }
Svet Ganov2af57082015-07-30 08:44:20 -07001521
Dianne Hackborn607b4142013-08-02 18:10:10 -07001522 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001523 scheduleFastWriteLocked();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001524 }
1525 }
1526 if (callbacks != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001527 for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
1528 ModeCallback cb = ent.getKey();
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001529 ArrayList<ChangeRec> reports = ent.getValue();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001530 for (int i=0; i<reports.size(); i++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001531 ChangeRec rep = reports.get(i);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001532 mHandler.sendMessage(PooledLambda.obtainMessage(
1533 AppOpsService::notifyOpChanged,
1534 this, cb, rep.op, rep.uid, rep.pkg));
Dianne Hackborn607b4142013-08-02 18:10:10 -07001535 }
1536 }
1537 }
1538 }
1539
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001540 private void evalAllForegroundOpsLocked() {
1541 for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
1542 final UidState uidState = mUidStates.valueAt(uidi);
1543 if (uidState.foregroundOps != null) {
1544 uidState.evalForegroundOps(mOpModeWatchers);
1545 }
1546 }
1547 }
1548
Dianne Hackbornc2293022013-02-06 23:14:49 -08001549 @Override
1550 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001551 startWatchingModeWithFlags(op, packageName, 0, callback);
1552 }
1553
1554 @Override
1555 public void startWatchingModeWithFlags(int op, String packageName, int flags,
1556 IAppOpsCallback callback) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001557 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001558 final int callingUid = Binder.getCallingUid();
1559 final int callingPid = Binder.getCallingPid();
Dianne Hackborn5376edd2018-06-05 13:21:16 -07001560 // TODO: should have a privileged permission to protect this.
1561 // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require
1562 // the USAGE_STATS permission since this can provide information about when an
1563 // app is in the foreground?
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001564 Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
1565 AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001566 if (callback == null) {
1567 return;
1568 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001569 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001570 op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001571 ModeCallback cb = mModeWatchers.get(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001572 if (cb == null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001573 cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001574 mModeWatchers.put(callback.asBinder(), cb);
1575 }
1576 if (op != AppOpsManager.OP_NONE) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001577 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001578 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001579 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001580 mOpModeWatchers.put(op, cbs);
1581 }
1582 cbs.add(cb);
1583 }
1584 if (packageName != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001585 ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001586 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001587 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001588 mPackageModeWatchers.put(packageName, cbs);
1589 }
1590 cbs.add(cb);
1591 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001592 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001593 }
1594 }
1595
1596 @Override
1597 public void stopWatchingMode(IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001598 if (callback == null) {
1599 return;
1600 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001601 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001602 ModeCallback cb = mModeWatchers.remove(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001603 if (cb != null) {
1604 cb.unlinkToDeath();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001605 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001606 ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001607 cbs.remove(cb);
1608 if (cbs.size() <= 0) {
1609 mOpModeWatchers.removeAt(i);
1610 }
1611 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001612 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001613 ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001614 cbs.remove(cb);
1615 if (cbs.size() <= 0) {
1616 mPackageModeWatchers.removeAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001617 }
1618 }
1619 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001620 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001621 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001622 }
1623
1624 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001625 public IBinder getToken(IBinder clientToken) {
1626 synchronized (this) {
1627 ClientState cs = mClients.get(clientToken);
1628 if (cs == null) {
1629 cs = new ClientState(clientToken);
1630 mClients.put(clientToken, cs);
1631 }
1632 return cs;
1633 }
1634 }
1635
Svet Ganovd873ae62018-06-25 16:39:23 -07001636 public CheckOpsDelegate getAppOpsServiceDelegate() {
1637 synchronized (this) {
1638 return mCheckOpsDelegate;
1639 }
1640 }
1641
1642 public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) {
1643 synchronized (this) {
1644 mCheckOpsDelegate = delegate;
1645 }
1646 }
1647
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001648 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -08001649 public int checkOperation(int code, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001650 final CheckOpsDelegate delegate;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001651 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001652 delegate = mCheckOpsDelegate;
1653 }
Todd Kennedy556efba2018-11-15 07:43:55 -08001654 if (delegate == null) {
1655 return checkOperationImpl(code, uid, packageName);
1656 }
Svet Ganovd873ae62018-06-25 16:39:23 -07001657 return delegate.checkOperation(code, uid, packageName,
1658 AppOpsService.this::checkOperationImpl);
1659 }
1660
1661 private int checkOperationImpl(int code, int uid, String packageName) {
Todd Kennedy556efba2018-11-15 07:43:55 -08001662 verifyIncomingUid(uid);
1663 verifyIncomingOp(code);
1664 String resolvedPackageName = resolvePackageName(uid, packageName);
1665 if (resolvedPackageName == null) {
1666 return AppOpsManager.MODE_IGNORED;
1667 }
1668 return checkOperationUnchecked(code, uid, resolvedPackageName);
1669 }
1670
1671 private int checkOperationUnchecked(int code, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001672 synchronized (this) {
Todd Kennedy556efba2018-11-15 07:43:55 -08001673 if (isOpRestrictedLocked(uid, code, packageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001674 return AppOpsManager.MODE_IGNORED;
1675 }
Svet Ganov2af57082015-07-30 08:44:20 -07001676 code = AppOpsManager.opToSwitch(code);
1677 UidState uidState = getUidStateLocked(uid, false);
Svet Ganovee438d42017-01-19 18:04:38 -08001678 if (uidState != null && uidState.opModes != null
1679 && uidState.opModes.indexOfKey(code) >= 0) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001680 return uidState.evalMode(uidState.opModes.get(code));
Svet Ganov2af57082015-07-30 08:44:20 -07001681 }
Todd Kennedy556efba2018-11-15 07:43:55 -08001682 Op op = getOpLocked(code, uid, packageName, false, true, false);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001683 if (op == null) {
David Braunf5d83192013-09-16 13:43:51 -07001684 return AppOpsManager.opToDefaultMode(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001685 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001686 return op.mode;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001687 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001688 }
1689
1690 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001691 public int checkAudioOperation(int code, int usage, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001692 final CheckOpsDelegate delegate;
John Spurlock1af30c72014-03-10 08:33:35 -04001693 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001694 delegate = mCheckOpsDelegate;
1695 }
Todd Kennedy556efba2018-11-15 07:43:55 -08001696 if (delegate == null) {
1697 return checkAudioOperationImpl(code, usage, uid, packageName);
1698 }
Svet Ganovd873ae62018-06-25 16:39:23 -07001699 return delegate.checkAudioOperation(code, usage, uid, packageName,
1700 AppOpsService.this::checkAudioOperationImpl);
1701 }
1702
1703 private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
Todd Kennedy556efba2018-11-15 07:43:55 -08001704 boolean suspended;
1705 try {
1706 suspended = isPackageSuspendedForUser(packageName, uid);
1707 } catch (IllegalArgumentException ex) {
1708 // Package not found.
1709 suspended = false;
1710 }
1711
1712 if (suspended) {
1713 Slog.i(TAG, "Audio disabled for suspended package=" + packageName
1714 + " for uid=" + uid);
1715 return AppOpsManager.MODE_IGNORED;
1716 }
1717
Svet Ganovd873ae62018-06-25 16:39:23 -07001718 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001719 final int mode = checkRestrictionLocked(code, usage, uid, packageName);
John Spurlock1af30c72014-03-10 08:33:35 -04001720 if (mode != AppOpsManager.MODE_ALLOWED) {
1721 return mode;
1722 }
1723 }
1724 return checkOperation(code, uid, packageName);
1725 }
1726
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001727 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001728 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001729 return AppGlobals.getPackageManager().isPackageSuspendedForUser(
1730 pkg, UserHandle.getUserId(uid));
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001731 } catch (RemoteException re) {
1732 throw new SecurityException("Could not talk to package manager service");
1733 }
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001734 }
1735
John Spurlock7b414672014-07-18 13:02:39 -04001736 private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
1737 final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1738 if (usageRestrictions != null) {
1739 final Restriction r = usageRestrictions.get(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001740 if (r != null && !r.exceptionPackages.contains(packageName)) {
1741 return r.mode;
1742 }
1743 }
1744 return AppOpsManager.MODE_ALLOWED;
1745 }
1746
1747 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001748 public void setAudioRestriction(int code, int usage, int uid, int mode,
John Spurlock1af30c72014-03-10 08:33:35 -04001749 String[] exceptionPackages) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001750 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
John Spurlock1af30c72014-03-10 08:33:35 -04001751 verifyIncomingUid(uid);
1752 verifyIncomingOp(code);
1753 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001754 SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1755 if (usageRestrictions == null) {
1756 usageRestrictions = new SparseArray<Restriction>();
1757 mAudioRestrictions.put(code, usageRestrictions);
John Spurlock1af30c72014-03-10 08:33:35 -04001758 }
John Spurlock7b414672014-07-18 13:02:39 -04001759 usageRestrictions.remove(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001760 if (mode != AppOpsManager.MODE_ALLOWED) {
1761 final Restriction r = new Restriction();
1762 r.mode = mode;
1763 if (exceptionPackages != null) {
1764 final int N = exceptionPackages.length;
1765 r.exceptionPackages = new ArraySet<String>(N);
1766 for (int i = 0; i < N; i++) {
1767 final String pkg = exceptionPackages[i];
1768 if (pkg != null) {
1769 r.exceptionPackages.add(pkg.trim());
1770 }
1771 }
1772 }
John Spurlock7b414672014-07-18 13:02:39 -04001773 usageRestrictions.put(usage, r);
John Spurlock1af30c72014-03-10 08:33:35 -04001774 }
1775 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001776
1777 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07001778 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
John Spurlock1af30c72014-03-10 08:33:35 -04001779 }
1780
1781 @Override
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001782 public int checkPackage(int uid, String packageName) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001783 Preconditions.checkNotNull(packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001784 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001785 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
1786 true /* uidMismatchExpected */);
1787 if (ops != null) {
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001788 return AppOpsManager.MODE_ALLOWED;
1789 } else {
1790 return AppOpsManager.MODE_ERRORED;
1791 }
1792 }
1793 }
1794
1795 @Override
Svet Ganovd873ae62018-06-25 16:39:23 -07001796 public int noteProxyOperation(int code, int proxyUid,
1797 String proxyPackageName, int proxiedUid, String proxiedPackageName) {
1798 verifyIncomingUid(proxyUid);
Svet Ganov99b60432015-06-27 13:15:22 -07001799 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001800 String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
1801 if (resolveProxyPackageName == null) {
1802 return AppOpsManager.MODE_IGNORED;
1803 }
1804 final int proxyMode = noteOperationUnchecked(code, proxyUid,
1805 resolveProxyPackageName, -1, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001806 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
1807 return proxyMode;
1808 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001809 String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
1810 if (resolveProxiedPackageName == null) {
1811 return AppOpsManager.MODE_IGNORED;
1812 }
1813 return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
1814 proxyMode, resolveProxyPackageName);
Svet Ganov99b60432015-06-27 13:15:22 -07001815 }
1816
1817 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001818 public int noteOperation(int code, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001819 final CheckOpsDelegate delegate;
1820 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001821 delegate = mCheckOpsDelegate;
1822 }
Todd Kennedy556efba2018-11-15 07:43:55 -08001823 if (delegate == null) {
1824 return noteOperationImpl(code, uid, packageName);
1825 }
Svet Ganovd873ae62018-06-25 16:39:23 -07001826 return delegate.noteOperation(code, uid, packageName,
1827 AppOpsService.this::noteOperationImpl);
1828 }
1829
1830 private int noteOperationImpl(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001831 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001832 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001833 String resolvedPackageName = resolvePackageName(uid, packageName);
1834 if (resolvedPackageName == null) {
1835 return AppOpsManager.MODE_IGNORED;
1836 }
1837 return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001838 }
1839
1840 private int noteOperationUnchecked(int code, int uid, String packageName,
1841 int proxyUid, String proxyPackageName) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001842 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001843 final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001844 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001845 if (ops == null) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001846 scheduleOpNotedIfNeededLocked(code, uid, packageName,
1847 AppOpsManager.MODE_IGNORED);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001848 if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001849 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001850 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001851 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001852 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001853 if (isOpRestrictedLocked(uid, code, packageName)) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001854 scheduleOpNotedIfNeededLocked(code, uid, packageName,
1855 AppOpsManager.MODE_IGNORED);
Jason Monk62062992014-05-06 09:55:28 -04001856 return AppOpsManager.MODE_IGNORED;
1857 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001858 final UidState uidState = ops.uidState;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001859 if (op.duration == -1) {
1860 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001861 + " code " + code + " time=" + op.time[uidState.state]
1862 + " duration=" + op.duration);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001863 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001864 op.duration = 0;
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001865 final int switchCode = AppOpsManager.opToSwitch(code);
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001866 // If there is a non-default per UID policy (we set UID op mode only if
1867 // non-default) it takes over, otherwise use the per package policy.
1868 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001869 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganov2af57082015-07-30 08:44:20 -07001870 if (uidMode != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001871 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001872 + switchCode + " (" + code + ") uid " + uid + " package "
1873 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001874 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001875 scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode);
Svet Ganov2af57082015-07-30 08:44:20 -07001876 return uidMode;
1877 }
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001878 } else {
1879 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001880 final int mode = switchOp.getMode();
1881 if (mode != AppOpsManager.MODE_ALLOWED) {
1882 if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001883 + switchCode + " (" + code + ") uid " + uid + " package "
1884 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001885 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001886 scheduleOpNotedIfNeededLocked(op.op, uid, packageName, mode);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001887 return mode;
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001888 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001889 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001890 if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001891 + " package " + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001892 op.time[uidState.state] = System.currentTimeMillis();
1893 op.rejectTime[uidState.state] = 0;
Svet Ganov99b60432015-06-27 13:15:22 -07001894 op.proxyUid = proxyUid;
1895 op.proxyPackageName = proxyPackageName;
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001896 scheduleOpNotedIfNeededLocked(code, uid, packageName,
1897 AppOpsManager.MODE_ALLOWED);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001898 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001899 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001900 }
1901
1902 @Override
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001903 public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001904 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001905 final int callingUid = Binder.getCallingUid();
1906 final int callingPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -08001907 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1908 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001909 watchedUid = callingUid;
Svet Ganovf7b47252018-02-26 11:11:27 -08001910 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001911 if (ops != null) {
1912 Preconditions.checkArrayElementsInRange(ops, 0,
1913 AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
1914 }
1915 if (callback == null) {
1916 return;
1917 }
1918 synchronized (this) {
1919 SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
1920 if (callbacks == null) {
1921 callbacks = new SparseArray<>();
1922 mActiveWatchers.put(callback.asBinder(), callbacks);
1923 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001924 final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
1925 callingUid, callingPid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001926 for (int op : ops) {
1927 callbacks.put(op, activeCallback);
1928 }
1929 }
1930 }
1931
1932 @Override
1933 public void stopWatchingActive(IAppOpsActiveCallback callback) {
1934 if (callback == null) {
1935 return;
1936 }
1937 synchronized (this) {
1938 final SparseArray<ActiveCallback> activeCallbacks =
1939 mActiveWatchers.remove(callback.asBinder());
1940 if (activeCallbacks == null) {
1941 return;
1942 }
1943 final int callbackCount = activeCallbacks.size();
1944 for (int i = 0; i < callbackCount; i++) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001945 activeCallbacks.valueAt(i).destroy();
1946 }
1947 }
1948 }
1949
1950 @Override
1951 public void startWatchingNoted(@NonNull int[] ops, @NonNull IAppOpsNotedCallback callback) {
1952 int watchedUid = Process.INVALID_UID;
1953 final int callingUid = Binder.getCallingUid();
1954 final int callingPid = Binder.getCallingPid();
1955 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1956 != PackageManager.PERMISSION_GRANTED) {
1957 watchedUid = callingUid;
1958 }
1959 Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
1960 Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
1961 "Invalid op code in: " + Arrays.toString(ops));
1962 Preconditions.checkNotNull(callback, "Callback cannot be null");
1963 synchronized (this) {
1964 SparseArray<NotedCallback> callbacks = mNotedWatchers.get(callback.asBinder());
1965 if (callbacks == null) {
1966 callbacks = new SparseArray<>();
1967 mNotedWatchers.put(callback.asBinder(), callbacks);
1968 }
1969 final NotedCallback notedCallback = new NotedCallback(callback, watchedUid,
1970 callingUid, callingPid);
1971 for (int op : ops) {
1972 callbacks.put(op, notedCallback);
1973 }
1974 }
1975 }
1976
1977 @Override
1978 public void stopWatchingNoted(IAppOpsNotedCallback callback) {
1979 Preconditions.checkNotNull(callback, "Callback cannot be null");
1980 synchronized (this) {
1981 final SparseArray<NotedCallback> notedCallbacks =
1982 mNotedWatchers.remove(callback.asBinder());
1983 if (notedCallbacks == null) {
1984 return;
1985 }
1986 final int callbackCount = notedCallbacks.size();
1987 for (int i = 0; i < callbackCount; i++) {
1988 notedCallbacks.valueAt(i).destroy();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001989 }
1990 }
1991 }
1992
1993 @Override
Svet Ganovf7b47252018-02-26 11:11:27 -08001994 public int startOperation(IBinder token, int code, int uid, String packageName,
1995 boolean startIfModeDefault) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001996 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001997 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001998 String resolvedPackageName = resolvePackageName(uid, packageName);
1999 if (resolvedPackageName == null) {
2000 return AppOpsManager.MODE_IGNORED;
2001 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002002 ClientState client = (ClientState)token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002003 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002004 final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07002005 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002006 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002007 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002008 + " package " + resolvedPackageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07002009 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002010 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002011 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07002012 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04002013 return AppOpsManager.MODE_IGNORED;
2014 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002015 final int switchCode = AppOpsManager.opToSwitch(code);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002016 final UidState uidState = ops.uidState;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002017 // If there is a non-default per UID policy (we set UID op mode only if
2018 // non-default) it takes over, otherwise use the per package policy.
2019 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002020 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganovf7b47252018-02-26 11:11:27 -08002021 if (uidMode != AppOpsManager.MODE_ALLOWED
2022 && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002023 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07002024 + switchCode + " (" + code + ") uid " + uid + " package "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002025 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002026 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov2af57082015-07-30 08:44:20 -07002027 return uidMode;
2028 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002029 } else {
2030 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002031 final int mode = switchOp.getMode();
2032 if (mode != AppOpsManager.MODE_ALLOWED
2033 && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
2034 if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002035 + switchCode + " (" + code + ") uid " + uid + " package "
2036 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002037 op.rejectTime[uidState.state] = System.currentTimeMillis();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002038 return mode;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002039 }
Svet Ganov2af57082015-07-30 08:44:20 -07002040 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002041 if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002042 + " package " + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002043 if (op.startNesting == 0) {
2044 op.startRealtime = SystemClock.elapsedRealtime();
2045 op.time[uidState.state] = System.currentTimeMillis();
2046 op.rejectTime[uidState.state] = 0;
Dianne Hackborn35654b62013-01-14 17:38:02 -08002047 op.duration = -1;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002048 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002049 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002050 op.startNesting++;
2051 uidState.startNesting++;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002052 if (client.mStartedOps != null) {
2053 client.mStartedOps.add(op);
2054 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002055 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002056
2057 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002058 }
2059
2060 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002061 public void finishOperation(IBinder token, int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002062 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08002063 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002064 String resolvedPackageName = resolvePackageName(uid, packageName);
2065 if (resolvedPackageName == null) {
2066 return;
2067 }
2068 if (!(token instanceof ClientState)) {
2069 return;
2070 }
2071 ClientState client = (ClientState) token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002072 synchronized (this) {
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07002073 Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002074 if (op == null) {
2075 return;
2076 }
Svet Ganovf7b47252018-02-26 11:11:27 -08002077 if (!client.mStartedOps.remove(op)) {
Svet Ganovf5d5af12018-03-18 11:51:17 -07002078 // We finish ops when packages get removed to guarantee no dangling
2079 // started ops. However, some part of the system may asynchronously
2080 // finish ops for an already gone package. Hence, finishing an op
2081 // for a non existing package is fine and we don't log as a wtf.
2082 final long identity = Binder.clearCallingIdentity();
2083 try {
2084 if (LocalServices.getService(PackageManagerInternal.class).getPackageUid(
2085 resolvedPackageName, 0, UserHandle.getUserId(uid)) < 0) {
2086 Slog.i(TAG, "Finishing op=" + AppOpsManager.opToName(code)
2087 + " for non-existing package=" + resolvedPackageName
2088 + " in uid=" + uid);
2089 return;
2090 }
2091 } finally {
2092 Binder.restoreCallingIdentity(identity);
2093 }
2094 Slog.wtf(TAG, "Operation not started: uid=" + op.uid + " pkg="
2095 + op.packageName + " op=" + AppOpsManager.opToName(op.op));
Svet Ganov31d83ae2018-03-15 10:45:56 -07002096 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002097 }
Svet Ganova7a0db62018-02-27 20:08:01 -08002098 finishOperationLocked(op, /*finishNested*/ false);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002099 if (op.startNesting <= 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002100 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
2101 }
2102 }
2103 }
2104
2105 private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
2106 boolean active) {
2107 ArraySet<ActiveCallback> dispatchedCallbacks = null;
2108 final int callbackListCount = mActiveWatchers.size();
2109 for (int i = 0; i < callbackListCount; i++) {
2110 final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
2111 ActiveCallback callback = callbacks.get(code);
2112 if (callback != null) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002113 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svet Ganovf7b47252018-02-26 11:11:27 -08002114 continue;
2115 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002116 if (dispatchedCallbacks == null) {
2117 dispatchedCallbacks = new ArraySet<>();
2118 }
2119 dispatchedCallbacks.add(callback);
2120 }
2121 }
2122 if (dispatchedCallbacks == null) {
2123 return;
2124 }
2125 mHandler.sendMessage(PooledLambda.obtainMessage(
2126 AppOpsService::notifyOpActiveChanged,
2127 this, dispatchedCallbacks, code, uid, packageName, active));
2128 }
2129
2130 private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
2131 int code, int uid, String packageName, boolean active) {
2132 // There are components watching for mode changes such as window manager
2133 // and location manager which are in our process. The callbacks in these
2134 // components may require permissions our remote caller does not have.
2135 final long identity = Binder.clearCallingIdentity();
2136 try {
2137 final int callbackCount = callbacks.size();
2138 for (int i = 0; i < callbackCount; i++) {
2139 final ActiveCallback callback = callbacks.valueAt(i);
2140 try {
2141 callback.mCallback.opActiveChanged(code, uid, packageName, active);
2142 } catch (RemoteException e) {
2143 /* do nothing */
2144 }
2145 }
2146 } finally {
2147 Binder.restoreCallingIdentity(identity);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002148 }
2149 }
2150
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002151 private void scheduleOpNotedIfNeededLocked(int code, int uid, String packageName,
2152 int result) {
2153 ArraySet<NotedCallback> dispatchedCallbacks = null;
2154 final int callbackListCount = mNotedWatchers.size();
2155 for (int i = 0; i < callbackListCount; i++) {
2156 final SparseArray<NotedCallback> callbacks = mNotedWatchers.valueAt(i);
2157 final NotedCallback callback = callbacks.get(code);
2158 if (callback != null) {
2159 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
2160 continue;
2161 }
2162 if (dispatchedCallbacks == null) {
2163 dispatchedCallbacks = new ArraySet<>();
2164 }
2165 dispatchedCallbacks.add(callback);
2166 }
2167 }
2168 if (dispatchedCallbacks == null) {
2169 return;
2170 }
2171 mHandler.sendMessage(PooledLambda.obtainMessage(
2172 AppOpsService::notifyOpChecked,
2173 this, dispatchedCallbacks, code, uid, packageName, result));
2174 }
2175
2176 private void notifyOpChecked(ArraySet<NotedCallback> callbacks,
2177 int code, int uid, String packageName, int result) {
2178 // There are components watching for checks in our process. The callbacks in
2179 // these components may require permissions our remote caller does not have.
2180 final long identity = Binder.clearCallingIdentity();
2181 try {
2182 final int callbackCount = callbacks.size();
2183 for (int i = 0; i < callbackCount; i++) {
2184 final NotedCallback callback = callbacks.valueAt(i);
2185 try {
2186 callback.mCallback.opNoted(code, uid, packageName, result);
2187 } catch (RemoteException e) {
2188 /* do nothing */
2189 }
2190 }
2191 } finally {
2192 Binder.restoreCallingIdentity(identity);
2193 }
2194 }
2195
Svet Ganovb9d71a62015-04-30 10:38:13 -07002196 @Override
2197 public int permissionToOpCode(String permission) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002198 if (permission == null) {
2199 return AppOpsManager.OP_NONE;
2200 }
Svet Ganovb9d71a62015-04-30 10:38:13 -07002201 return AppOpsManager.permissionToOpCode(permission);
2202 }
2203
Svet Ganova7a0db62018-02-27 20:08:01 -08002204 void finishOperationLocked(Op op, boolean finishNested) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002205 if (op.startNesting <= 1 || finishNested) {
2206 if (op.startNesting == 1 || finishNested) {
2207 op.duration = (int)(SystemClock.elapsedRealtime() - op.startRealtime);
2208 op.time[op.uidState.state] = System.currentTimeMillis();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002209 } else {
2210 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
2211 + op.packageName + " code " + op.op + " time=" + op.time
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002212 + " duration=" + op.duration + " nesting=" + op.startNesting);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002213 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002214 if (op.startNesting >= 1) {
2215 op.uidState.startNesting -= op.startNesting;
2216 }
2217 op.startNesting = 0;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002218 } else {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002219 op.startNesting--;
2220 op.uidState.startNesting--;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002221 }
2222 }
2223
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002224 private void verifyIncomingUid(int uid) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002225 if (uid == Binder.getCallingUid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002226 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002227 }
2228 if (Binder.getCallingPid() == Process.myPid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002229 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002230 }
2231 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
2232 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002233 }
2234
Dianne Hackborn961321f2013-02-05 17:22:41 -08002235 private void verifyIncomingOp(int op) {
2236 if (op >= 0 && op < AppOpsManager._NUM_OP) {
2237 return;
2238 }
2239 throw new IllegalArgumentException("Bad operation #" + op);
2240 }
2241
Svet Ganov2af57082015-07-30 08:44:20 -07002242 private UidState getUidStateLocked(int uid, boolean edit) {
2243 UidState uidState = mUidStates.get(uid);
2244 if (uidState == null) {
2245 if (!edit) {
2246 return null;
2247 }
2248 uidState = new UidState(uid);
2249 mUidStates.put(uid, uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002250 } else {
2251 if (uidState.pendingStateCommitTime != 0) {
Dianne Hackborn9fb93502018-06-18 12:29:44 -07002252 if (uidState.pendingStateCommitTime < mLastRealtime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002253 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002254 } else {
Dianne Hackborn9fb93502018-06-18 12:29:44 -07002255 mLastRealtime = SystemClock.elapsedRealtime();
2256 if (uidState.pendingStateCommitTime < mLastRealtime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002257 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002258 }
2259 }
2260 }
Svet Ganov2af57082015-07-30 08:44:20 -07002261 }
2262 return uidState;
2263 }
2264
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002265 private void commitUidPendingStateLocked(UidState uidState) {
Dianne Hackborne93ab412018-05-14 17:52:30 -07002266 final boolean lastForeground = uidState.state <= UID_STATE_LAST_NON_RESTRICTED;
2267 final boolean nowForeground = uidState.pendingState <= UID_STATE_LAST_NON_RESTRICTED;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002268 uidState.state = uidState.pendingState;
2269 uidState.pendingStateCommitTime = 0;
Dianne Hackborne93ab412018-05-14 17:52:30 -07002270 if (uidState.hasForegroundWatchers && lastForeground != nowForeground) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002271 for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
2272 if (!uidState.foregroundOps.valueAt(fgi)) {
2273 continue;
2274 }
2275 final int code = uidState.foregroundOps.keyAt(fgi);
2276
2277 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
2278 if (callbacks != null) {
2279 for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
2280 final ModeCallback callback = callbacks.valueAt(cbi);
2281 if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
2282 || !callback.isWatchingUid(uidState.uid)) {
2283 continue;
2284 }
2285 boolean doAllPackages = uidState.opModes != null
Hai Zhang2b98fb32018-09-21 15:18:46 -07002286 && uidState.opModes.indexOfKey(code) >= 0
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002287 && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
2288 if (uidState.pkgOps != null) {
2289 for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
2290 final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
2291 if (doAllPackages || (op != null
2292 && op.mode == AppOpsManager.MODE_FOREGROUND)) {
2293 mHandler.sendMessage(PooledLambda.obtainMessage(
2294 AppOpsService::notifyOpChanged,
2295 this, callback, code, uidState.uid,
2296 uidState.pkgOps.keyAt(pkgi)));
2297 }
2298 }
2299 }
2300 }
2301 }
2302 }
2303 }
2304 }
2305
Yohei Yukawaa965d652017-10-12 15:02:26 -07002306 private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
2307 boolean uidMismatchExpected) {
Svet Ganov2af57082015-07-30 08:44:20 -07002308 UidState uidState = getUidStateLocked(uid, edit);
2309 if (uidState == null) {
2310 return null;
2311 }
2312
2313 if (uidState.pkgOps == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002314 if (!edit) {
2315 return null;
2316 }
Svet Ganov2af57082015-07-30 08:44:20 -07002317 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002318 }
Svet Ganov2af57082015-07-30 08:44:20 -07002319
2320 Ops ops = uidState.pkgOps.get(packageName);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002321 if (ops == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002322 if (!edit) {
2323 return null;
2324 }
Jason Monk1c7c3192014-06-26 12:52:18 -04002325 boolean isPrivileged = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002326 // This is the first time we have seen this package name under this uid,
2327 // so let's make sure it is valid.
Dianne Hackborn514074f2013-02-11 10:52:46 -08002328 if (uid != 0) {
2329 final long ident = Binder.clearCallingIdentity();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002330 try {
Dianne Hackborn514074f2013-02-11 10:52:46 -08002331 int pkgUid = -1;
2332 try {
Jason Monk1c7c3192014-06-26 12:52:18 -04002333 ApplicationInfo appInfo = ActivityThread.getPackageManager()
Jeff Sharkeycd654482016-01-08 17:42:11 -07002334 .getApplicationInfo(packageName,
Svet Ganovad0a49b2018-10-29 10:07:08 -07002335 PackageManager.MATCH_DIRECT_BOOT_AWARE
2336 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
Jeff Sharkeycd654482016-01-08 17:42:11 -07002337 UserHandle.getUserId(uid));
Jason Monk1c7c3192014-06-26 12:52:18 -04002338 if (appInfo != null) {
2339 pkgUid = appInfo.uid;
Alex Klyubinb9f8a522015-02-03 11:12:59 -08002340 isPrivileged = (appInfo.privateFlags
2341 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04002342 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08002343 pkgUid = resolveUid(packageName);
2344 if (pkgUid >= 0) {
Chien-Yu Chen75cade02016-01-11 10:56:21 -08002345 isPrivileged = false;
Jason Monk1c7c3192014-06-26 12:52:18 -04002346 }
Dianne Hackborn713df152013-05-17 11:27:57 -07002347 }
Jason Monk1c7c3192014-06-26 12:52:18 -04002348 } catch (RemoteException e) {
2349 Slog.w(TAG, "Could not contact PackageManager", e);
Dianne Hackborn514074f2013-02-11 10:52:46 -08002350 }
2351 if (pkgUid != uid) {
2352 // Oops! The package name is not valid for the uid they are calling
2353 // under. Abort.
Yohei Yukawaa965d652017-10-12 15:02:26 -07002354 if (!uidMismatchExpected) {
2355 RuntimeException ex = new RuntimeException("here");
2356 ex.fillInStackTrace();
2357 Slog.w(TAG, "Bad call: specified package " + packageName
2358 + " under uid " + uid + " but it is really " + pkgUid, ex);
2359 }
Dianne Hackborn514074f2013-02-11 10:52:46 -08002360 return null;
2361 }
2362 } finally {
2363 Binder.restoreCallingIdentity(ident);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002364 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002365 }
Svet Ganov2af57082015-07-30 08:44:20 -07002366 ops = new Ops(packageName, uidState, isPrivileged);
2367 uidState.pkgOps.put(packageName, ops);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002368 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08002369 return ops;
2370 }
2371
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07002372 /**
2373 * Get the state of all ops for a package, <b>don't verify that package belongs to uid</b>.
2374 *
2375 * <p>Usually callers should use {@link #getOpLocked} and not call this directly.
2376 *
2377 * @param uid The uid the of the package
2378 * @param packageName The package name for which to get the state for
2379 * @param edit Iff {@code true} create the {@link Ops} object if not yet created
2380 * @param isPrivileged Whether the package is privileged or not
2381 *
2382 * @return The {@link Ops state} of all ops for the package
2383 */
2384 private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
2385 boolean edit, boolean isPrivileged) {
2386 UidState uidState = getUidStateLocked(uid, edit);
2387 if (uidState == null) {
2388 return null;
2389 }
2390
2391 if (uidState.pkgOps == null) {
2392 if (!edit) {
2393 return null;
2394 }
2395 uidState.pkgOps = new ArrayMap<>();
2396 }
2397
2398 Ops ops = uidState.pkgOps.get(packageName);
2399 if (ops == null) {
2400 if (!edit) {
2401 return null;
2402 }
2403 ops = new Ops(packageName, uidState, isPrivileged);
2404 uidState.pkgOps.put(packageName, ops);
2405 }
2406 return ops;
2407 }
2408
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002409 private void scheduleWriteLocked() {
2410 if (!mWriteScheduled) {
2411 mWriteScheduled = true;
2412 mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
2413 }
2414 }
2415
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002416 private void scheduleFastWriteLocked() {
2417 if (!mFastWriteScheduled) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002418 mWriteScheduled = true;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002419 mFastWriteScheduled = true;
2420 mHandler.removeCallbacks(mWriteRunner);
2421 mHandler.postDelayed(mWriteRunner, 10*1000);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002422 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002423 }
2424
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07002425 /**
2426 * Get the state of an op for a uid.
2427 *
2428 * @param code The code of the op
2429 * @param uid The uid the of the package
2430 * @param packageName The package name for which to get the state for
2431 * @param edit Iff {@code true} create the {@link Op} object if not yet created
2432 * @param verifyUid Iff {@code true} check that the package belongs to the uid
2433 * @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid
2434 * == false})
2435 *
2436 * @return The {@link Op state} of the op
2437 */
2438 private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit,
2439 boolean verifyUid, boolean isPrivileged) {
2440 Ops ops;
2441
2442 if (verifyUid) {
2443 ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */);
2444 } else {
2445 ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
2446 }
2447
Dianne Hackborn72e39832013-01-18 18:36:09 -08002448 if (ops == null) {
2449 return null;
2450 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002451 return getOpLocked(ops, code, edit);
2452 }
2453
2454 private Op getOpLocked(Ops ops, int code, boolean edit) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002455 Op op = ops.get(code);
2456 if (op == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002457 if (!edit) {
2458 return null;
2459 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002460 op = new Op(ops.uidState, ops.packageName, code);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002461 ops.put(code, op);
2462 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002463 if (edit) {
2464 scheduleWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002465 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002466 return op;
2467 }
2468
Svet Ganov442ed572016-08-17 17:29:43 -07002469 private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
Jason Monk62062992014-05-06 09:55:28 -04002470 int userHandle = UserHandle.getUserId(uid);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002471 final int restrictionSetCount = mOpUserRestrictions.size();
Ruben Brunk29931bc2016-03-11 00:24:26 -08002472
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002473 for (int i = 0; i < restrictionSetCount; i++) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08002474 // For each client, check that the given op is not restricted, or that the given
2475 // package is exempt from the restriction.
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002476 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07002477 if (restrictionState.hasRestriction(code, packageName, userHandle)) {
2478 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
2479 // If we are the system, bypass user restrictions for certain codes
2480 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002481 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
2482 false /* uidMismatchExpected */);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07002483 if ((ops != null) && ops.isPrivileged) {
2484 return false;
2485 }
Ruben Brunk32f0fa42016-03-11 19:07:07 -08002486 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08002487 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002488 return true;
Jason Monk1c7c3192014-06-26 12:52:18 -04002489 }
Jason Monk62062992014-05-06 09:55:28 -04002490 }
2491 return false;
2492 }
2493
Dianne Hackborn35654b62013-01-14 17:38:02 -08002494 void readState() {
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002495 int oldVersion = NO_VERSION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08002496 synchronized (mFile) {
2497 synchronized (this) {
2498 FileInputStream stream;
2499 try {
2500 stream = mFile.openRead();
2501 } catch (FileNotFoundException e) {
2502 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
2503 return;
2504 }
2505 boolean success = false;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002506 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002507 try {
2508 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002509 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002510 int type;
2511 while ((type = parser.next()) != XmlPullParser.START_TAG
2512 && type != XmlPullParser.END_DOCUMENT) {
2513 ;
2514 }
2515
2516 if (type != XmlPullParser.START_TAG) {
2517 throw new IllegalStateException("no start tag found");
2518 }
2519
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002520 final String versionString = parser.getAttributeValue(null, "v");
2521 if (versionString != null) {
2522 oldVersion = Integer.parseInt(versionString);
2523 }
2524
Dianne Hackborn35654b62013-01-14 17:38:02 -08002525 int outerDepth = parser.getDepth();
2526 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2527 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2528 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2529 continue;
2530 }
2531
2532 String tagName = parser.getName();
2533 if (tagName.equals("pkg")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002534 readPackage(parser);
Svetoslav215b44a2015-08-04 19:03:40 -07002535 } else if (tagName.equals("uid")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002536 readUidOps(parser);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002537 } else {
2538 Slog.w(TAG, "Unknown element under <app-ops>: "
2539 + parser.getName());
2540 XmlUtils.skipCurrentTag(parser);
2541 }
2542 }
2543 success = true;
2544 } catch (IllegalStateException e) {
2545 Slog.w(TAG, "Failed parsing " + e);
2546 } catch (NullPointerException e) {
2547 Slog.w(TAG, "Failed parsing " + e);
2548 } catch (NumberFormatException e) {
2549 Slog.w(TAG, "Failed parsing " + e);
2550 } catch (XmlPullParserException e) {
2551 Slog.w(TAG, "Failed parsing " + e);
2552 } catch (IOException e) {
2553 Slog.w(TAG, "Failed parsing " + e);
2554 } catch (IndexOutOfBoundsException e) {
2555 Slog.w(TAG, "Failed parsing " + e);
2556 } finally {
2557 if (!success) {
Svet Ganov2af57082015-07-30 08:44:20 -07002558 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002559 }
2560 try {
2561 stream.close();
2562 } catch (IOException e) {
2563 }
2564 }
2565 }
2566 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002567 synchronized (this) {
2568 upgradeLocked(oldVersion);
2569 }
2570 }
2571
2572 private void upgradeRunAnyInBackgroundLocked() {
2573 for (int i = 0; i < mUidStates.size(); i++) {
2574 final UidState uidState = mUidStates.valueAt(i);
2575 if (uidState == null) {
2576 continue;
2577 }
2578 if (uidState.opModes != null) {
2579 final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
2580 if (idx >= 0) {
2581 uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
2582 uidState.opModes.valueAt(idx));
2583 }
2584 }
2585 if (uidState.pkgOps == null) {
2586 continue;
2587 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002588 boolean changed = false;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002589 for (int j = 0; j < uidState.pkgOps.size(); j++) {
2590 Ops ops = uidState.pkgOps.valueAt(j);
2591 if (ops != null) {
2592 final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
2593 if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002594 final Op copy = new Op(op.uidState, op.packageName,
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002595 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
2596 copy.mode = op.mode;
2597 ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002598 changed = true;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002599 }
2600 }
2601 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002602 if (changed) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002603 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002604 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002605 }
2606 }
2607
2608 private void upgradeLocked(int oldVersion) {
2609 if (oldVersion >= CURRENT_VERSION) {
2610 return;
2611 }
2612 Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
2613 switch (oldVersion) {
2614 case NO_VERSION:
2615 upgradeRunAnyInBackgroundLocked();
2616 // fall through
2617 case 1:
2618 // for future upgrades
2619 }
2620 scheduleFastWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002621 }
2622
Svet Ganov2af57082015-07-30 08:44:20 -07002623 void readUidOps(XmlPullParser parser) throws NumberFormatException,
2624 XmlPullParserException, IOException {
2625 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
2626 int outerDepth = parser.getDepth();
2627 int type;
2628 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2629 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2630 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2631 continue;
2632 }
2633
2634 String tagName = parser.getName();
2635 if (tagName.equals("op")) {
2636 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
2637 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
2638 UidState uidState = getUidStateLocked(uid, true);
2639 if (uidState.opModes == null) {
2640 uidState.opModes = new SparseIntArray();
2641 }
2642 uidState.opModes.put(code, mode);
2643 } else {
2644 Slog.w(TAG, "Unknown element under <uid-ops>: "
2645 + parser.getName());
2646 XmlUtils.skipCurrentTag(parser);
2647 }
2648 }
2649 }
2650
Dave Burke0997c5bd2013-08-02 20:25:02 +00002651 void readPackage(XmlPullParser parser) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002652 XmlPullParserException, IOException {
2653 String pkgName = parser.getAttributeValue(null, "n");
2654 int outerDepth = parser.getDepth();
2655 int type;
2656 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2657 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2658 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2659 continue;
2660 }
2661
2662 String tagName = parser.getName();
2663 if (tagName.equals("uid")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002664 readUid(parser, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002665 } else {
2666 Slog.w(TAG, "Unknown element under <pkg>: "
2667 + parser.getName());
2668 XmlUtils.skipCurrentTag(parser);
2669 }
2670 }
2671 }
2672
Dave Burke0997c5bd2013-08-02 20:25:02 +00002673 void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002674 XmlPullParserException, IOException {
2675 int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
Jason Monk1c7c3192014-06-26 12:52:18 -04002676 String isPrivilegedString = parser.getAttributeValue(null, "p");
2677 boolean isPrivileged = false;
2678 if (isPrivilegedString == null) {
2679 try {
2680 IPackageManager packageManager = ActivityThread.getPackageManager();
2681 if (packageManager != null) {
2682 ApplicationInfo appInfo = ActivityThread.getPackageManager()
2683 .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
2684 if (appInfo != null) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08002685 isPrivileged = (appInfo.privateFlags
2686 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04002687 }
2688 } else {
2689 // Could not load data, don't add to cache so it will be loaded later.
2690 return;
2691 }
2692 } catch (RemoteException e) {
2693 Slog.w(TAG, "Could not contact PackageManager", e);
2694 }
2695 } else {
2696 isPrivileged = Boolean.parseBoolean(isPrivilegedString);
2697 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002698 int outerDepth = parser.getDepth();
2699 int type;
2700 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2701 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2702 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2703 continue;
2704 }
2705
2706 String tagName = parser.getName();
2707 if (tagName.equals("op")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002708 UidState uidState = getUidStateLocked(uid, true);
2709 if (uidState.pkgOps == null) {
2710 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002711 }
Svet Ganov2af57082015-07-30 08:44:20 -07002712
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002713 Op op = new Op(uidState, pkgName,
2714 Integer.parseInt(parser.getAttributeValue(null, "n")));
2715
2716 for (int i = parser.getAttributeCount()-1; i >= 0; i--) {
2717 final String name = parser.getAttributeName(i);
2718 final String value = parser.getAttributeValue(i);
2719 switch (name) {
2720 case "m":
2721 op.mode = Integer.parseInt(value);
2722 break;
2723 case "d":
2724 op.duration = Integer.parseInt(value);
2725 break;
2726 case "pu":
2727 op.proxyUid = Integer.parseInt(value);
2728 break;
2729 case "pp":
2730 op.proxyPackageName = value;
2731 break;
2732 case "tp":
2733 op.time[AppOpsManager.UID_STATE_PERSISTENT] = Long.parseLong(value);
2734 break;
2735 case "tt":
2736 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2737 break;
2738 case "tfs":
2739 op.time[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2740 = Long.parseLong(value);
2741 break;
2742 case "tf":
2743 op.time[AppOpsManager.UID_STATE_FOREGROUND] = Long.parseLong(value);
2744 break;
2745 case "tb":
2746 op.time[AppOpsManager.UID_STATE_BACKGROUND] = Long.parseLong(value);
2747 break;
2748 case "tc":
2749 op.time[AppOpsManager.UID_STATE_CACHED] = Long.parseLong(value);
2750 break;
2751 case "rp":
2752 op.rejectTime[AppOpsManager.UID_STATE_PERSISTENT]
2753 = Long.parseLong(value);
2754 break;
2755 case "rt":
2756 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2757 break;
2758 case "rfs":
2759 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2760 = Long.parseLong(value);
2761 break;
2762 case "rf":
2763 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND]
2764 = Long.parseLong(value);
2765 break;
2766 case "rb":
2767 op.rejectTime[AppOpsManager.UID_STATE_BACKGROUND]
2768 = Long.parseLong(value);
2769 break;
2770 case "rc":
2771 op.rejectTime[AppOpsManager.UID_STATE_CACHED]
2772 = Long.parseLong(value);
2773 break;
2774 case "t":
2775 // Backwards compat.
2776 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2777 break;
2778 case "r":
2779 // Backwards compat.
2780 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2781 break;
2782 default:
2783 Slog.w(TAG, "Unknown attribute in 'op' tag: " + name);
2784 break;
2785 }
2786 }
2787
Svet Ganov2af57082015-07-30 08:44:20 -07002788 Ops ops = uidState.pkgOps.get(pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002789 if (ops == null) {
Svet Ganov2af57082015-07-30 08:44:20 -07002790 ops = new Ops(pkgName, uidState, isPrivileged);
2791 uidState.pkgOps.put(pkgName, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002792 }
2793 ops.put(op.op, op);
2794 } else {
2795 Slog.w(TAG, "Unknown element under <pkg>: "
2796 + parser.getName());
2797 XmlUtils.skipCurrentTag(parser);
2798 }
2799 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002800 UidState uidState = getUidStateLocked(uid, false);
2801 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002802 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002803 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002804 }
2805
2806 void writeState() {
2807 synchronized (mFile) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002808 FileOutputStream stream;
2809 try {
2810 stream = mFile.startWrite();
2811 } catch (IOException e) {
2812 Slog.w(TAG, "Failed to write state: " + e);
2813 return;
2814 }
2815
Dianne Hackborne17b4452018-01-10 13:15:40 -08002816 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
2817
Dianne Hackborn35654b62013-01-14 17:38:02 -08002818 try {
2819 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002820 out.setOutput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002821 out.startDocument(null, true);
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002822 out.startTag(null, "app-ops");
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002823 out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
Svet Ganov2af57082015-07-30 08:44:20 -07002824
2825 final int uidStateCount = mUidStates.size();
2826 for (int i = 0; i < uidStateCount; i++) {
2827 UidState uidState = mUidStates.valueAt(i);
2828 if (uidState.opModes != null && uidState.opModes.size() > 0) {
2829 out.startTag(null, "uid");
2830 out.attribute(null, "n", Integer.toString(uidState.uid));
2831 SparseIntArray uidOpModes = uidState.opModes;
2832 final int opCount = uidOpModes.size();
2833 for (int j = 0; j < opCount; j++) {
2834 final int op = uidOpModes.keyAt(j);
2835 final int mode = uidOpModes.valueAt(j);
2836 out.startTag(null, "op");
2837 out.attribute(null, "n", Integer.toString(op));
2838 out.attribute(null, "m", Integer.toString(mode));
2839 out.endTag(null, "op");
2840 }
2841 out.endTag(null, "uid");
2842 }
2843 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002844
2845 if (allOps != null) {
2846 String lastPkg = null;
2847 for (int i=0; i<allOps.size(); i++) {
2848 AppOpsManager.PackageOps pkg = allOps.get(i);
2849 if (!pkg.getPackageName().equals(lastPkg)) {
2850 if (lastPkg != null) {
2851 out.endTag(null, "pkg");
2852 }
2853 lastPkg = pkg.getPackageName();
2854 out.startTag(null, "pkg");
2855 out.attribute(null, "n", lastPkg);
2856 }
2857 out.startTag(null, "uid");
2858 out.attribute(null, "n", Integer.toString(pkg.getUid()));
Jason Monk1c7c3192014-06-26 12:52:18 -04002859 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002860 Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
2861 false /* edit */, false /* uidMismatchExpected */);
Jason Monk1c7c3192014-06-26 12:52:18 -04002862 // Should always be present as the list of PackageOps is generated
2863 // from Ops.
2864 if (ops != null) {
2865 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
2866 } else {
2867 out.attribute(null, "p", Boolean.toString(false));
2868 }
2869 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002870 List<AppOpsManager.OpEntry> ops = pkg.getOps();
2871 for (int j=0; j<ops.size(); j++) {
2872 AppOpsManager.OpEntry op = ops.get(j);
2873 out.startTag(null, "op");
2874 out.attribute(null, "n", Integer.toString(op.getOp()));
David Braunf5d83192013-09-16 13:43:51 -07002875 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002876 out.attribute(null, "m", Integer.toString(op.getMode()));
2877 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002878 for (int k = 0; k < _NUM_UID_STATE; k++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002879 final long time = op.getLastTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002880 if (time != 0) {
2881 out.attribute(null, UID_STATE_TIME_ATTRS[k],
2882 Long.toString(time));
2883 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002884 final long rejectTime = op.getLastRejectTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002885 if (rejectTime != 0) {
2886 out.attribute(null, UID_STATE_REJECT_ATTRS[k],
2887 Long.toString(rejectTime));
2888 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002889 }
2890 int dur = op.getDuration();
2891 if (dur != 0) {
2892 out.attribute(null, "d", Integer.toString(dur));
2893 }
Svet Ganov99b60432015-06-27 13:15:22 -07002894 int proxyUid = op.getProxyUid();
2895 if (proxyUid != -1) {
2896 out.attribute(null, "pu", Integer.toString(proxyUid));
2897 }
2898 String proxyPackageName = op.getProxyPackageName();
2899 if (proxyPackageName != null) {
2900 out.attribute(null, "pp", proxyPackageName);
2901 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002902 out.endTag(null, "op");
2903 }
2904 out.endTag(null, "uid");
2905 }
2906 if (lastPkg != null) {
2907 out.endTag(null, "pkg");
2908 }
2909 }
2910
2911 out.endTag(null, "app-ops");
2912 out.endDocument();
2913 mFile.finishWrite(stream);
2914 } catch (IOException e) {
2915 Slog.w(TAG, "Failed to write state, restoring backup.", e);
2916 mFile.failWrite(stream);
2917 }
2918 }
2919 }
2920
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002921 static class Shell extends ShellCommand {
2922 final IAppOpsService mInterface;
2923 final AppOpsService mInternal;
2924
2925 int userId = UserHandle.USER_SYSTEM;
2926 String packageName;
2927 String opStr;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002928 String modeStr;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002929 int op;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002930 int mode;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002931 int packageUid;
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002932 int nonpackageUid;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002933 final static Binder sBinder = new Binder();
2934 IBinder mToken;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002935
2936 Shell(IAppOpsService iface, AppOpsService internal) {
2937 mInterface = iface;
2938 mInternal = internal;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002939 try {
2940 mToken = mInterface.getToken(sBinder);
2941 } catch (RemoteException e) {
2942 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002943 }
2944
2945 @Override
2946 public int onCommand(String cmd) {
2947 return onShellCommand(this, cmd);
2948 }
2949
2950 @Override
2951 public void onHelp() {
2952 PrintWriter pw = getOutPrintWriter();
2953 dumpCommandHelp(pw);
2954 }
2955
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002956 static private int strOpToOp(String op, PrintWriter err) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002957 try {
2958 return AppOpsManager.strOpToOp(op);
2959 } catch (IllegalArgumentException e) {
2960 }
2961 try {
2962 return Integer.parseInt(op);
2963 } catch (NumberFormatException e) {
2964 }
2965 try {
2966 return AppOpsManager.strDebugOpToOp(op);
2967 } catch (IllegalArgumentException e) {
2968 err.println("Error: " + e.getMessage());
2969 return -1;
2970 }
2971 }
2972
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002973 static int strModeToMode(String modeStr, PrintWriter err) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002974 for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
2975 if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002976 return i;
2977 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002978 }
2979 try {
2980 return Integer.parseInt(modeStr);
2981 } catch (NumberFormatException e) {
2982 }
2983 err.println("Error: Mode " + modeStr + " is not valid");
2984 return -1;
2985 }
2986
2987 int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
2988 userId = UserHandle.USER_CURRENT;
2989 opStr = null;
2990 modeStr = null;
2991 for (String argument; (argument = getNextArg()) != null;) {
2992 if ("--user".equals(argument)) {
2993 userId = UserHandle.parseUserArg(getNextArgRequired());
2994 } else {
2995 if (opStr == null) {
2996 opStr = argument;
2997 } else if (modeStr == null) {
2998 modeStr = argument;
2999 break;
3000 }
3001 }
3002 }
3003 if (opStr == null) {
3004 err.println("Error: Operation not specified.");
3005 return -1;
3006 }
3007 op = strOpToOp(opStr, err);
3008 if (op < 0) {
3009 return -1;
3010 }
3011 if (modeStr != null) {
3012 if ((mode=strModeToMode(modeStr, err)) < 0) {
3013 return -1;
3014 }
3015 } else {
3016 mode = defMode;
3017 }
3018 return 0;
3019 }
3020
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003021 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
3022 userId = UserHandle.USER_CURRENT;
3023 packageName = null;
3024 opStr = null;
3025 for (String argument; (argument = getNextArg()) != null;) {
3026 if ("--user".equals(argument)) {
3027 userId = UserHandle.parseUserArg(getNextArgRequired());
3028 } else {
3029 if (packageName == null) {
3030 packageName = argument;
3031 } else if (opStr == null) {
3032 opStr = argument;
3033 break;
3034 }
3035 }
3036 }
3037 if (packageName == null) {
3038 err.println("Error: Package name not specified.");
3039 return -1;
3040 } else if (opStr == null && reqOp) {
3041 err.println("Error: Operation not specified.");
3042 return -1;
3043 }
3044 if (opStr != null) {
3045 op = strOpToOp(opStr, err);
3046 if (op < 0) {
3047 return -1;
3048 }
3049 } else {
3050 op = AppOpsManager.OP_NONE;
3051 }
3052 if (userId == UserHandle.USER_CURRENT) {
3053 userId = ActivityManager.getCurrentUser();
3054 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003055 nonpackageUid = -1;
3056 try {
3057 nonpackageUid = Integer.parseInt(packageName);
3058 } catch (NumberFormatException e) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003059 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003060 if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
3061 && packageName.indexOf('.') < 0) {
3062 int i = 1;
3063 while (i < packageName.length() && packageName.charAt(i) >= '0'
3064 && packageName.charAt(i) <= '9') {
3065 i++;
3066 }
3067 if (i > 1 && i < packageName.length()) {
3068 String userStr = packageName.substring(1, i);
3069 try {
3070 int user = Integer.parseInt(userStr);
3071 char type = packageName.charAt(i);
3072 i++;
3073 int startTypeVal = i;
3074 while (i < packageName.length() && packageName.charAt(i) >= '0'
3075 && packageName.charAt(i) <= '9') {
3076 i++;
3077 }
3078 if (i > startTypeVal) {
3079 String typeValStr = packageName.substring(startTypeVal, i);
3080 try {
3081 int typeVal = Integer.parseInt(typeValStr);
3082 if (type == 'a') {
3083 nonpackageUid = UserHandle.getUid(user,
3084 typeVal + Process.FIRST_APPLICATION_UID);
3085 } else if (type == 's') {
3086 nonpackageUid = UserHandle.getUid(user, typeVal);
3087 }
3088 } catch (NumberFormatException e) {
3089 }
3090 }
3091 } catch (NumberFormatException e) {
3092 }
3093 }
3094 }
3095 if (nonpackageUid != -1) {
3096 packageName = null;
3097 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08003098 packageUid = resolveUid(packageName);
3099 if (packageUid < 0) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003100 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
3101 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
3102 }
3103 if (packageUid < 0) {
3104 err.println("Error: No UID for " + packageName + " in user " + userId);
3105 return -1;
3106 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003107 }
3108 return 0;
3109 }
3110 }
3111
3112 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07003113 FileDescriptor err, String[] args, ShellCallback callback,
3114 ResultReceiver resultReceiver) {
3115 (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003116 }
3117
3118 static void dumpCommandHelp(PrintWriter pw) {
3119 pw.println("AppOps service (appops) commands:");
3120 pw.println(" help");
3121 pw.println(" Print this help text.");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05003122 pw.println(" start [--user <USER_ID>] <PACKAGE | UID> <OP> ");
3123 pw.println(" Starts a given operation for a particular application.");
3124 pw.println(" stop [--user <USER_ID>] <PACKAGE | UID> <OP> ");
3125 pw.println(" Stops a given operation for a particular application.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003126 pw.println(" set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003127 pw.println(" Set the mode for a particular application and operation.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003128 pw.println(" get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003129 pw.println(" Return the mode for a particular application and optional operation.");
Dianne Hackborne91f3e72016-03-25 18:48:15 -07003130 pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
3131 pw.println(" Print all packages that currently have the given op in the given mode.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003132 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
3133 pw.println(" Reset the given application or all applications to default modes.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003134 pw.println(" write-settings");
3135 pw.println(" Immediately write pending changes to storage.");
3136 pw.println(" read-settings");
3137 pw.println(" Read the last written settings, replacing current state in RAM.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003138 pw.println(" options:");
3139 pw.println(" <PACKAGE> an Android package name.");
3140 pw.println(" <OP> an AppOps operation.");
3141 pw.println(" <MODE> one of allow, ignore, deny, or default");
3142 pw.println(" <USER_ID> the user id under which the package is installed. If --user is not");
3143 pw.println(" specified, the current user is assumed.");
3144 }
3145
3146 static int onShellCommand(Shell shell, String cmd) {
3147 if (cmd == null) {
3148 return shell.handleDefaultCommands(cmd);
3149 }
3150 PrintWriter pw = shell.getOutPrintWriter();
3151 PrintWriter err = shell.getErrPrintWriter();
3152 try {
3153 switch (cmd) {
3154 case "set": {
3155 int res = shell.parseUserPackageOp(true, err);
3156 if (res < 0) {
3157 return res;
3158 }
3159 String modeStr = shell.getNextArg();
3160 if (modeStr == null) {
3161 err.println("Error: Mode not specified.");
3162 return -1;
3163 }
3164
Dianne Hackborne91f3e72016-03-25 18:48:15 -07003165 final int mode = shell.strModeToMode(modeStr, err);
3166 if (mode < 0) {
3167 return -1;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003168 }
3169
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003170 if (shell.packageName != null) {
3171 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
3172 mode);
3173 } else {
3174 shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
3175 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003176 return 0;
3177 }
3178 case "get": {
3179 int res = shell.parseUserPackageOp(false, err);
3180 if (res < 0) {
3181 return res;
3182 }
3183
Eugene Suslae4ee2c22018-11-05 12:23:30 -08003184 List<AppOpsManager.PackageOps> ops = new ArrayList<>();
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003185 if (shell.packageName != null) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08003186 // Uid mode overrides package mode, so make sure it's also reported
3187 List<AppOpsManager.PackageOps> r = shell.mInterface.getUidOps(
3188 shell.packageUid,
3189 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
3190 if (r != null) {
3191 ops.addAll(r);
3192 }
3193 r = shell.mInterface.getOpsForPackage(
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003194 shell.packageUid, shell.packageName,
3195 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
Eugene Suslae4ee2c22018-11-05 12:23:30 -08003196 if (r != null) {
3197 ops.addAll(r);
3198 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003199 } else {
3200 ops = shell.mInterface.getUidOps(
3201 shell.nonpackageUid,
3202 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
3203 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003204 if (ops == null || ops.size() <= 0) {
3205 pw.println("No operations.");
Svet Ganov82f09bc2018-01-12 22:08:40 -08003206 if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003207 pw.println("Default mode: " + AppOpsManager.modeToName(
Svet Ganov82f09bc2018-01-12 22:08:40 -08003208 AppOpsManager.opToDefaultMode(shell.op)));
3209 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003210 return 0;
3211 }
3212 final long now = System.currentTimeMillis();
3213 for (int i=0; i<ops.size(); i++) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08003214 AppOpsManager.PackageOps packageOps = ops.get(i);
3215 if (packageOps.getPackageName() == null) {
3216 pw.print("Uid mode: ");
3217 }
3218 List<AppOpsManager.OpEntry> entries = packageOps.getOps();
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003219 for (int j=0; j<entries.size(); j++) {
3220 AppOpsManager.OpEntry ent = entries.get(j);
3221 pw.print(AppOpsManager.opToName(ent.getOp()));
3222 pw.print(": ");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003223 pw.print(AppOpsManager.modeToName(ent.getMode()));
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003224 if (ent.getTime() != 0) {
3225 pw.print("; time=");
3226 TimeUtils.formatDuration(now - ent.getTime(), pw);
3227 pw.print(" ago");
3228 }
3229 if (ent.getRejectTime() != 0) {
3230 pw.print("; rejectTime=");
3231 TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
3232 pw.print(" ago");
3233 }
3234 if (ent.getDuration() == -1) {
3235 pw.print(" (running)");
3236 } else if (ent.getDuration() != 0) {
3237 pw.print("; duration=");
3238 TimeUtils.formatDuration(ent.getDuration(), pw);
3239 }
3240 pw.println();
3241 }
3242 }
3243 return 0;
3244 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07003245 case "query-op": {
3246 int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
3247 if (res < 0) {
3248 return res;
3249 }
3250 List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
3251 new int[] {shell.op});
3252 if (ops == null || ops.size() <= 0) {
3253 pw.println("No operations.");
3254 return 0;
3255 }
3256 for (int i=0; i<ops.size(); i++) {
3257 final AppOpsManager.PackageOps pkg = ops.get(i);
3258 boolean hasMatch = false;
3259 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
3260 for (int j=0; j<entries.size(); j++) {
3261 AppOpsManager.OpEntry ent = entries.get(j);
3262 if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
3263 hasMatch = true;
3264 break;
3265 }
3266 }
3267 if (hasMatch) {
3268 pw.println(pkg.getPackageName());
3269 }
3270 }
3271 return 0;
3272 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003273 case "reset": {
3274 String packageName = null;
3275 int userId = UserHandle.USER_CURRENT;
3276 for (String argument; (argument = shell.getNextArg()) != null;) {
3277 if ("--user".equals(argument)) {
3278 String userStr = shell.getNextArgRequired();
3279 userId = UserHandle.parseUserArg(userStr);
3280 } else {
3281 if (packageName == null) {
3282 packageName = argument;
3283 } else {
3284 err.println("Error: Unsupported argument: " + argument);
3285 return -1;
3286 }
3287 }
3288 }
3289
3290 if (userId == UserHandle.USER_CURRENT) {
3291 userId = ActivityManager.getCurrentUser();
3292 }
3293
3294 shell.mInterface.resetAllModes(userId, packageName);
3295 pw.print("Reset all modes for: ");
3296 if (userId == UserHandle.USER_ALL) {
3297 pw.print("all users");
3298 } else {
3299 pw.print("user "); pw.print(userId);
3300 }
3301 pw.print(", ");
3302 if (packageName == null) {
3303 pw.println("all packages");
3304 } else {
3305 pw.print("package "); pw.println(packageName);
3306 }
3307 return 0;
3308 }
3309 case "write-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07003310 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
3311 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003312 long token = Binder.clearCallingIdentity();
3313 try {
3314 synchronized (shell.mInternal) {
3315 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
3316 }
3317 shell.mInternal.writeState();
3318 pw.println("Current settings written.");
3319 } finally {
3320 Binder.restoreCallingIdentity(token);
3321 }
3322 return 0;
3323 }
3324 case "read-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07003325 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
3326 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003327 long token = Binder.clearCallingIdentity();
3328 try {
3329 shell.mInternal.readState();
3330 pw.println("Last settings read.");
3331 } finally {
3332 Binder.restoreCallingIdentity(token);
3333 }
3334 return 0;
3335 }
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05003336 case "start": {
3337 int res = shell.parseUserPackageOp(true, err);
3338 if (res < 0) {
3339 return res;
3340 }
3341
3342 if (shell.packageName != null) {
3343 shell.mInterface.startOperation(shell.mToken,
3344 shell.op, shell.packageUid, shell.packageName, true);
3345 } else {
3346 return -1;
3347 }
3348 return 0;
3349 }
3350 case "stop": {
3351 int res = shell.parseUserPackageOp(true, err);
3352 if (res < 0) {
3353 return res;
3354 }
3355
3356 if (shell.packageName != null) {
3357 shell.mInterface.finishOperation(shell.mToken,
3358 shell.op, shell.packageUid, shell.packageName);
3359 } else {
3360 return -1;
3361 }
3362 return 0;
3363 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003364 default:
3365 return shell.handleDefaultCommands(cmd);
3366 }
3367 } catch (RemoteException e) {
3368 pw.println("Remote exception: " + e);
3369 }
3370 return -1;
3371 }
3372
3373 private void dumpHelp(PrintWriter pw) {
3374 pw.println("AppOps service (appops) dump options:");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003375 pw.println(" -h");
3376 pw.println(" Print this help text.");
3377 pw.println(" --op [OP]");
3378 pw.println(" Limit output to data associated with the given app op code.");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003379 pw.println(" --mode [MODE]");
3380 pw.println(" Limit output to data associated with the given app op mode.");
3381 pw.println(" --package [PACKAGE]");
3382 pw.println(" Limit output to data associated with the given package name.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003383 }
3384
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003385 private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
3386 long now, SimpleDateFormat sdf, Date date) {
3387 boolean hasTime = false;
3388 for (int i = 0; i < _NUM_UID_STATE; i++) {
3389 if (times[i] != 0) {
3390 hasTime = true;
3391 break;
3392 }
3393 }
3394 if (!hasTime) {
3395 return;
3396 }
3397 boolean first = true;
3398 for (int i = 0; i < _NUM_UID_STATE; i++) {
3399 if (times[i] != 0) {
3400 pw.print(first ? firstPrefix : prefix);
3401 first = false;
3402 pw.print(UID_STATE_NAMES[i]);
3403 pw.print(" = ");
3404 date.setTime(times[i]);
3405 pw.print(sdf.format(date));
3406 pw.print(" (");
3407 TimeUtils.formatDuration(times[i]-now, pw);
3408 pw.println(")");
3409 }
3410 }
3411 }
3412
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003413 @Override
3414 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003415 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003416
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003417 int dumpOp = -1;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003418 String dumpPackage = null;
3419 int dumpUid = -1;
3420 int dumpMode = -1;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003421
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003422 if (args != null) {
3423 for (int i=0; i<args.length; i++) {
3424 String arg = args[i];
3425 if ("-h".equals(arg)) {
3426 dumpHelp(pw);
3427 return;
Tim Kilbourn8f1ea832015-08-26 15:07:37 -07003428 } else if ("-a".equals(arg)) {
3429 // dump all data
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003430 } else if ("--op".equals(arg)) {
3431 i++;
3432 if (i >= args.length) {
3433 pw.println("No argument for --op option");
3434 return;
3435 }
3436 dumpOp = Shell.strOpToOp(args[i], pw);
3437 if (dumpOp < 0) {
3438 return;
3439 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003440 } else if ("--package".equals(arg)) {
3441 i++;
3442 if (i >= args.length) {
3443 pw.println("No argument for --package option");
3444 return;
3445 }
3446 dumpPackage = args[i];
3447 try {
3448 dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
3449 PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
3450 0);
3451 } catch (RemoteException e) {
3452 }
3453 if (dumpUid < 0) {
3454 pw.println("Unknown package: " + dumpPackage);
3455 return;
3456 }
3457 dumpUid = UserHandle.getAppId(dumpUid);
3458 } else if ("--mode".equals(arg)) {
3459 i++;
3460 if (i >= args.length) {
3461 pw.println("No argument for --mode option");
3462 return;
3463 }
3464 dumpMode = Shell.strModeToMode(args[i], pw);
3465 if (dumpMode < 0) {
3466 return;
3467 }
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003468 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
3469 pw.println("Unknown option: " + arg);
3470 return;
3471 } else {
3472 pw.println("Unknown command: " + arg);
3473 return;
3474 }
3475 }
3476 }
3477
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003478 synchronized (this) {
3479 pw.println("Current AppOps Service state:");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003480 mConstants.dump(pw);
3481 pw.println();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003482 final long now = System.currentTimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003483 final long nowElapsed = SystemClock.elapsedRealtime();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003484 final long nowUptime = SystemClock.uptimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003485 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
3486 final Date date = new Date();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003487 boolean needSep = false;
Dianne Hackbornd5254412018-05-11 18:02:58 -07003488 if (dumpOp < 0 && dumpMode < 0 && dumpPackage == null && mProfileOwners != null) {
3489 pw.println(" Profile owners:");
3490 for (int poi = 0; poi < mProfileOwners.size(); poi++) {
3491 pw.print(" User #");
3492 pw.print(mProfileOwners.keyAt(poi));
3493 pw.print(": ");
3494 UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
3495 pw.println();
3496 }
3497 pw.println();
3498 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003499 if (mOpModeWatchers.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003500 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003501 for (int i=0; i<mOpModeWatchers.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003502 if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
3503 continue;
3504 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003505 boolean printedOpHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003506 ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003507 for (int j=0; j<callbacks.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003508 final ModeCallback cb = callbacks.valueAt(j);
3509 if (dumpPackage != null && cb.mWatchingUid >= 0
3510 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3511 continue;
3512 }
3513 needSep = true;
3514 if (!printedHeader) {
3515 pw.println(" Op mode watchers:");
3516 printedHeader = true;
3517 }
3518 if (!printedOpHeader) {
3519 pw.print(" Op ");
3520 pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
3521 pw.println(":");
3522 printedOpHeader = true;
3523 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003524 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003525 pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003526 }
3527 }
3528 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003529 if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
3530 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003531 for (int i=0; i<mPackageModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003532 if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
3533 continue;
3534 }
3535 needSep = true;
3536 if (!printedHeader) {
3537 pw.println(" Package mode watchers:");
3538 printedHeader = true;
3539 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003540 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
3541 pw.println(":");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003542 ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003543 for (int j=0; j<callbacks.size(); j++) {
3544 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn68d76552017-02-27 15:32:03 -08003545 pw.println(callbacks.valueAt(j));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003546 }
3547 }
3548 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003549 if (mModeWatchers.size() > 0 && dumpOp < 0) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003550 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003551 for (int i=0; i<mModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003552 final ModeCallback cb = mModeWatchers.valueAt(i);
3553 if (dumpPackage != null && cb.mWatchingUid >= 0
3554 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3555 continue;
3556 }
3557 needSep = true;
3558 if (!printedHeader) {
3559 pw.println(" All op mode watchers:");
3560 printedHeader = true;
3561 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003562 pw.print(" ");
3563 pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003564 pw.print(": "); pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003565 }
3566 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003567 if (mActiveWatchers.size() > 0 && dumpMode < 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003568 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003569 boolean printedHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003570 for (int i = 0; i < mActiveWatchers.size(); i++) {
3571 final SparseArray<ActiveCallback> activeWatchers = mActiveWatchers.valueAt(i);
3572 if (activeWatchers.size() <= 0) {
3573 continue;
3574 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003575 final ActiveCallback cb = activeWatchers.valueAt(0);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003576 if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
3577 continue;
3578 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003579 if (dumpPackage != null && cb.mWatchingUid >= 0
3580 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3581 continue;
3582 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003583 if (!printedHeader) {
3584 pw.println(" All op active watchers:");
3585 printedHeader = true;
3586 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003587 pw.print(" ");
3588 pw.print(Integer.toHexString(System.identityHashCode(
3589 mActiveWatchers.keyAt(i))));
3590 pw.println(" ->");
3591 pw.print(" [");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003592 final int opCount = activeWatchers.size();
3593 for (i = 0; i < opCount; i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003594 if (i > 0) {
3595 pw.print(' ');
3596 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003597 pw.print(AppOpsManager.opToName(activeWatchers.keyAt(i)));
3598 if (i < opCount - 1) {
3599 pw.print(',');
3600 }
3601 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003602 pw.println("]");
3603 pw.print(" ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003604 pw.println(cb);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003605 }
3606 }
Svet Ganovb3d2ae22018-12-17 22:06:15 -08003607 if (mNotedWatchers.size() > 0 && dumpMode < 0) {
3608 needSep = true;
3609 boolean printedHeader = false;
3610 for (int i = 0; i < mNotedWatchers.size(); i++) {
3611 final SparseArray<NotedCallback> notedWatchers = mNotedWatchers.valueAt(i);
3612 if (notedWatchers.size() <= 0) {
3613 continue;
3614 }
3615 final NotedCallback cb = notedWatchers.valueAt(0);
3616 if (dumpOp >= 0 && notedWatchers.indexOfKey(dumpOp) < 0) {
3617 continue;
3618 }
3619 if (dumpPackage != null && cb.mWatchingUid >= 0
3620 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3621 continue;
3622 }
3623 if (!printedHeader) {
3624 pw.println(" All op noted watchers:");
3625 printedHeader = true;
3626 }
3627 pw.print(" ");
3628 pw.print(Integer.toHexString(System.identityHashCode(
3629 mNotedWatchers.keyAt(i))));
3630 pw.println(" ->");
3631 pw.print(" [");
3632 final int opCount = notedWatchers.size();
3633 for (i = 0; i < opCount; i++) {
3634 if (i > 0) {
3635 pw.print(' ');
3636 }
3637 pw.print(AppOpsManager.opToName(notedWatchers.keyAt(i)));
3638 if (i < opCount - 1) {
3639 pw.print(',');
3640 }
3641 }
3642 pw.println("]");
3643 pw.print(" ");
3644 pw.println(cb);
3645 }
3646 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003647 if (mClients.size() > 0 && dumpMode < 0) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003648 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003649 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003650 for (int i=0; i<mClients.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003651 boolean printedClient = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003652 ClientState cs = mClients.valueAt(i);
Svet Ganovf7b47252018-02-26 11:11:27 -08003653 if (cs.mStartedOps.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003654 boolean printedStarted = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003655 for (int j=0; j<cs.mStartedOps.size(); j++) {
3656 Op op = cs.mStartedOps.get(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003657 if (dumpOp >= 0 && op.op != dumpOp) {
3658 continue;
3659 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003660 if (dumpPackage != null && !dumpPackage.equals(op.packageName)) {
3661 continue;
3662 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003663 if (!printedHeader) {
3664 pw.println(" Clients:");
3665 printedHeader = true;
3666 }
3667 if (!printedClient) {
3668 pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
3669 pw.print(" "); pw.println(cs);
3670 printedClient = true;
3671 }
3672 if (!printedStarted) {
3673 pw.println(" Started ops:");
3674 printedStarted = true;
3675 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003676 pw.print(" "); pw.print("uid="); pw.print(op.uid);
3677 pw.print(" pkg="); pw.print(op.packageName);
3678 pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
3679 }
3680 }
3681 }
3682 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003683 if (mAudioRestrictions.size() > 0 && dumpOp < 0 && dumpPackage != null
3684 && dumpMode < 0) {
John Spurlock1af30c72014-03-10 08:33:35 -04003685 boolean printedHeader = false;
3686 for (int o=0; o<mAudioRestrictions.size(); o++) {
3687 final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
3688 final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
3689 for (int i=0; i<restrictions.size(); i++) {
3690 if (!printedHeader){
3691 pw.println(" Audio Restrictions:");
3692 printedHeader = true;
3693 needSep = true;
3694 }
John Spurlock7b414672014-07-18 13:02:39 -04003695 final int usage = restrictions.keyAt(i);
John Spurlock1af30c72014-03-10 08:33:35 -04003696 pw.print(" "); pw.print(op);
John Spurlock7b414672014-07-18 13:02:39 -04003697 pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
John Spurlock1af30c72014-03-10 08:33:35 -04003698 Restriction r = restrictions.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003699 pw.print(": mode="); pw.println(AppOpsManager.modeToName(r.mode));
John Spurlock1af30c72014-03-10 08:33:35 -04003700 if (!r.exceptionPackages.isEmpty()) {
3701 pw.println(" Exceptions:");
3702 for (int j=0; j<r.exceptionPackages.size(); j++) {
3703 pw.print(" "); pw.println(r.exceptionPackages.valueAt(j));
3704 }
3705 }
3706 }
3707 }
3708 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003709 if (needSep) {
3710 pw.println();
3711 }
Svet Ganov2af57082015-07-30 08:44:20 -07003712 for (int i=0; i<mUidStates.size(); i++) {
3713 UidState uidState = mUidStates.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003714 final SparseIntArray opModes = uidState.opModes;
3715 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
3716
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003717 if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
3718 boolean hasOp = dumpOp < 0 || (uidState.opModes != null
3719 && uidState.opModes.indexOfKey(dumpOp) >= 0);
3720 boolean hasPackage = dumpPackage == null;
3721 boolean hasMode = dumpMode < 0;
3722 if (!hasMode && opModes != null) {
3723 for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
3724 if (opModes.valueAt(opi) == dumpMode) {
3725 hasMode = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003726 }
3727 }
3728 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003729 if (pkgOps != null) {
3730 for (int pkgi = 0;
3731 (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
3732 pkgi++) {
3733 Ops ops = pkgOps.valueAt(pkgi);
3734 if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
3735 hasOp = true;
3736 }
3737 if (!hasMode) {
3738 for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
3739 if (ops.valueAt(opi).mode == dumpMode) {
3740 hasMode = true;
3741 }
3742 }
3743 }
3744 if (!hasPackage && dumpPackage.equals(ops.packageName)) {
3745 hasPackage = true;
3746 }
3747 }
3748 }
3749 if (uidState.foregroundOps != null && !hasOp) {
3750 if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
3751 hasOp = true;
3752 }
3753 }
3754 if (!hasOp || !hasPackage || !hasMode) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003755 continue;
3756 }
3757 }
Svet Ganov2af57082015-07-30 08:44:20 -07003758
3759 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003760 pw.print(" state=");
3761 pw.println(UID_STATE_NAMES[uidState.state]);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003762 if (uidState.state != uidState.pendingState) {
3763 pw.print(" pendingState=");
3764 pw.println(UID_STATE_NAMES[uidState.pendingState]);
3765 }
3766 if (uidState.pendingStateCommitTime != 0) {
3767 pw.print(" pendingStateCommitTime=");
Dianne Hackborn9fb93502018-06-18 12:29:44 -07003768 TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003769 pw.println();
3770 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003771 if (uidState.startNesting != 0) {
3772 pw.print(" startNesting=");
3773 pw.println(uidState.startNesting);
3774 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003775 if (uidState.foregroundOps != null && (dumpMode < 0
3776 || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003777 pw.println(" foregroundOps:");
3778 for (int j = 0; j < uidState.foregroundOps.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003779 if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
3780 continue;
3781 }
3782 pw.print(" ");
3783 pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
3784 pw.print(": ");
3785 pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003786 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003787 pw.print(" hasForegroundWatchers=");
3788 pw.println(uidState.hasForegroundWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003789 }
Svet Ganovee438d42017-01-19 18:04:38 -08003790 needSep = true;
Svet Ganov2af57082015-07-30 08:44:20 -07003791
Svet Ganov2af57082015-07-30 08:44:20 -07003792 if (opModes != null) {
3793 final int opModeCount = opModes.size();
3794 for (int j = 0; j < opModeCount; j++) {
3795 final int code = opModes.keyAt(j);
3796 final int mode = opModes.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003797 if (dumpOp >= 0 && dumpOp != code) {
3798 continue;
3799 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003800 if (dumpMode >= 0 && dumpMode != mode) {
3801 continue;
3802 }
Svet Ganov2af57082015-07-30 08:44:20 -07003803 pw.print(" "); pw.print(AppOpsManager.opToName(code));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003804 pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
Svet Ganov2af57082015-07-30 08:44:20 -07003805 }
3806 }
3807
Svet Ganov2af57082015-07-30 08:44:20 -07003808 if (pkgOps == null) {
3809 continue;
3810 }
3811
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003812 for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003813 final Ops ops = pkgOps.valueAt(pkgi);
3814 if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
3815 continue;
3816 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003817 boolean printedPackage = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003818 for (int j=0; j<ops.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003819 final Op op = ops.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003820 if (dumpOp >= 0 && dumpOp != op.op) {
3821 continue;
3822 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003823 if (dumpMode >= 0 && dumpMode != op.mode) {
3824 continue;
3825 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003826 if (!printedPackage) {
3827 pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
3828 printedPackage = true;
3829 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003830 pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003831 pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003832 final int switchOp = AppOpsManager.opToSwitch(op.op);
3833 if (switchOp != op.op) {
3834 pw.print(" / switch ");
3835 pw.print(AppOpsManager.opToName(switchOp));
3836 final Op switchObj = ops.get(switchOp);
3837 int mode = switchObj != null
3838 ? switchObj.mode : AppOpsManager.opToDefaultMode(switchOp);
3839 pw.print("="); pw.print(AppOpsManager.modeToName(mode));
3840 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003841 pw.println("): ");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003842 dumpTimesLocked(pw,
3843 " Access: ",
3844 " ", op.time, now, sdf, date);
3845 dumpTimesLocked(pw,
3846 " Reject: ",
3847 " ", op.rejectTime, now, sdf, date);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003848 if (op.duration == -1) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003849 pw.print(" Running start at: ");
3850 TimeUtils.formatDuration(nowElapsed-op.startRealtime, pw);
3851 pw.println();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08003852 } else if (op.duration != 0) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003853 pw.print(" duration=");
3854 TimeUtils.formatDuration(op.duration, pw);
3855 pw.println();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003856 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003857 if (op.startNesting != 0) {
3858 pw.print(" startNesting=");
3859 pw.println(op.startNesting);
3860 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003861 }
3862 }
3863 }
Svet Ganovee438d42017-01-19 18:04:38 -08003864 if (needSep) {
3865 pw.println();
3866 }
3867
3868 final int userRestrictionCount = mOpUserRestrictions.size();
3869 for (int i = 0; i < userRestrictionCount; i++) {
3870 IBinder token = mOpUserRestrictions.keyAt(i);
3871 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
3872 pw.println(" User restrictions for token " + token + ":");
3873
3874 final int restrictionCount = restrictionState.perUserRestrictions != null
3875 ? restrictionState.perUserRestrictions.size() : 0;
3876 if (restrictionCount > 0) {
3877 pw.println(" Restricted ops:");
3878 for (int j = 0; j < restrictionCount; j++) {
3879 int userId = restrictionState.perUserRestrictions.keyAt(j);
3880 boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
3881 if (restrictedOps == null) {
3882 continue;
3883 }
3884 StringBuilder restrictedOpsValue = new StringBuilder();
3885 restrictedOpsValue.append("[");
3886 final int restrictedOpCount = restrictedOps.length;
3887 for (int k = 0; k < restrictedOpCount; k++) {
3888 if (restrictedOps[k]) {
3889 if (restrictedOpsValue.length() > 1) {
3890 restrictedOpsValue.append(", ");
3891 }
3892 restrictedOpsValue.append(AppOpsManager.opToName(k));
3893 }
3894 }
3895 restrictedOpsValue.append("]");
3896 pw.print(" "); pw.print("user: "); pw.print(userId);
3897 pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
3898 }
3899 }
3900
3901 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
3902 ? restrictionState.perUserExcludedPackages.size() : 0;
3903 if (excludedPackageCount > 0) {
3904 pw.println(" Excluded packages:");
3905 for (int j = 0; j < excludedPackageCount; j++) {
3906 int userId = restrictionState.perUserExcludedPackages.keyAt(j);
3907 String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
3908 pw.print(" "); pw.print("user: "); pw.print(userId);
3909 pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
3910 }
3911 }
3912 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003913 }
3914 }
John Spurlock1af30c72014-03-10 08:33:35 -04003915
3916 private static final class Restriction {
3917 private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
3918 int mode;
3919 ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
3920 }
Jason Monk62062992014-05-06 09:55:28 -04003921
3922 @Override
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003923 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
Jason Monk62062992014-05-06 09:55:28 -04003924 checkSystemUid("setUserRestrictions");
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003925 Preconditions.checkNotNull(restrictions);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003926 Preconditions.checkNotNull(token);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003927 for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
Jason Monk62062992014-05-06 09:55:28 -04003928 String restriction = AppOpsManager.opToRestriction(i);
Suprabh Shukla64e0dcb2016-05-24 16:23:11 -07003929 if (restriction != null) {
3930 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
3931 userHandle, null);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003932 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003933 }
3934 }
3935
3936 @Override
Ruben Brunk29931bc2016-03-11 00:24:26 -08003937 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
3938 String[] exceptionPackages) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003939 if (Binder.getCallingPid() != Process.myPid()) {
3940 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
3941 Binder.getCallingPid(), Binder.getCallingUid(), null);
3942 }
3943 if (userHandle != UserHandle.getCallingUserId()) {
3944 if (mContext.checkCallingOrSelfPermission(Manifest.permission
3945 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
3946 && mContext.checkCallingOrSelfPermission(Manifest.permission
3947 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
3948 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
3949 + " INTERACT_ACROSS_USERS to interact cross user ");
Jason Monk62062992014-05-06 09:55:28 -04003950 }
3951 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003952 verifyIncomingOp(code);
3953 Preconditions.checkNotNull(token);
Ruben Brunk29931bc2016-03-11 00:24:26 -08003954 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003955 }
3956
3957 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
Ruben Brunk29931bc2016-03-11 00:24:26 -08003958 int userHandle, String[] exceptionPackages) {
Svet Ganov442ed572016-08-17 17:29:43 -07003959 synchronized (AppOpsService.this) {
3960 ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
3961
3962 if (restrictionState == null) {
3963 try {
3964 restrictionState = new ClientRestrictionState(token);
3965 } catch (RemoteException e) {
3966 return;
3967 }
3968 mOpUserRestrictions.put(token, restrictionState);
Ruben Brunk29931bc2016-03-11 00:24:26 -08003969 }
Svet Ganov442ed572016-08-17 17:29:43 -07003970
3971 if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003972 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07003973 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
Svet Ganov442ed572016-08-17 17:29:43 -07003974 }
3975
3976 if (restrictionState.isDefault()) {
3977 mOpUserRestrictions.remove(token);
3978 restrictionState.destroy();
3979 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08003980 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -04003981 }
3982
Svet Ganov3a95f832018-03-23 17:44:30 -07003983 private void notifyWatchersOfChange(int code, int uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003984 final ArraySet<ModeCallback> clonedCallbacks;
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003985 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003986 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003987 if (callbacks == null) {
3988 return;
3989 }
Dianne Hackborn68d76552017-02-27 15:32:03 -08003990 clonedCallbacks = new ArraySet<>(callbacks);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003991 }
3992
Svet Ganov3a95f832018-03-23 17:44:30 -07003993 notifyOpChanged(clonedCallbacks, code, uid, null);
Jason Monk62062992014-05-06 09:55:28 -04003994 }
3995
3996 @Override
3997 public void removeUser(int userHandle) throws RemoteException {
3998 checkSystemUid("removeUser");
Svet Ganov442ed572016-08-17 17:29:43 -07003999 synchronized (AppOpsService.this) {
4000 final int tokenCount = mOpUserRestrictions.size();
4001 for (int i = tokenCount - 1; i >= 0; i--) {
4002 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
4003 opRestrictions.removeUser(userHandle);
4004 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07004005 removeUidsForUserLocked(userHandle);
4006 }
4007 }
4008
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004009 @Override
4010 public boolean isOperationActive(int code, int uid, String packageName) {
Svet Ganovf7b47252018-02-26 11:11:27 -08004011 if (Binder.getCallingUid() != uid) {
4012 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
4013 != PackageManager.PERMISSION_GRANTED) {
4014 return false;
4015 }
4016 }
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004017 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004018 final String resolvedPackageName = resolvePackageName(uid, packageName);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004019 if (resolvedPackageName == null) {
4020 return false;
4021 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004022 synchronized (AppOpsService.this) {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004023 for (int i = mClients.size() - 1; i >= 0; i--) {
4024 final ClientState client = mClients.valueAt(i);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004025 for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
4026 final Op op = client.mStartedOps.get(j);
4027 if (op.op == code && op.uid == uid) return true;
4028 }
4029 }
4030 }
4031 return false;
4032 }
4033
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07004034 private void removeUidsForUserLocked(int userHandle) {
4035 for (int i = mUidStates.size() - 1; i >= 0; --i) {
4036 final int uid = mUidStates.keyAt(i);
4037 if (UserHandle.getUserId(uid) == userHandle) {
4038 mUidStates.removeAt(i);
4039 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004040 }
4041 }
4042
Jason Monk62062992014-05-06 09:55:28 -04004043 private void checkSystemUid(String function) {
4044 int uid = Binder.getCallingUid();
4045 if (uid != Process.SYSTEM_UID) {
4046 throw new SecurityException(function + " must by called by the system");
4047 }
4048 }
4049
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00004050 private static String resolvePackageName(int uid, String packageName) {
Svet Ganov82f09bc2018-01-12 22:08:40 -08004051 if (uid == Process.ROOT_UID) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00004052 return "root";
4053 } else if (uid == Process.SHELL_UID) {
4054 return "com.android.shell";
Svet Ganov82f09bc2018-01-12 22:08:40 -08004055 } else if (uid == Process.MEDIA_UID) {
4056 return "media";
4057 } else if (uid == Process.AUDIOSERVER_UID) {
4058 return "audioserver";
4059 } else if (uid == Process.CAMERASERVER_UID) {
4060 return "cameraserver";
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00004061 } else if (uid == Process.SYSTEM_UID && packageName == null) {
4062 return "android";
4063 }
4064 return packageName;
4065 }
4066
Svet Ganov82f09bc2018-01-12 22:08:40 -08004067 private static int resolveUid(String packageName) {
4068 if (packageName == null) {
4069 return -1;
4070 }
4071 switch (packageName) {
4072 case "root":
4073 return Process.ROOT_UID;
4074 case "shell":
4075 return Process.SHELL_UID;
4076 case "media":
4077 return Process.MEDIA_UID;
4078 case "audioserver":
4079 return Process.AUDIOSERVER_UID;
4080 case "cameraserver":
4081 return Process.CAMERASERVER_UID;
4082 }
4083 return -1;
4084 }
4085
Svet Ganov2af57082015-07-30 08:44:20 -07004086 private static String[] getPackagesForUid(int uid) {
Svet Ganovf3807aa2015-08-02 10:09:56 -07004087 String[] packageNames = null;
Svet Ganov2af57082015-07-30 08:44:20 -07004088 try {
riddle_hsu40b300f2015-11-23 13:22:03 +08004089 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
Svet Ganov2af57082015-07-30 08:44:20 -07004090 } catch (RemoteException e) {
4091 /* ignore - local call */
4092 }
Svet Ganovf3807aa2015-08-02 10:09:56 -07004093 if (packageNames == null) {
4094 return EmptyArray.STRING;
4095 }
4096 return packageNames;
Svet Ganov2af57082015-07-30 08:44:20 -07004097 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004098
4099 private final class ClientRestrictionState implements DeathRecipient {
4100 private final IBinder token;
4101 SparseArray<boolean[]> perUserRestrictions;
4102 SparseArray<String[]> perUserExcludedPackages;
4103
4104 public ClientRestrictionState(IBinder token)
4105 throws RemoteException {
4106 token.linkToDeath(this, 0);
4107 this.token = token;
4108 }
4109
4110 public boolean setRestriction(int code, boolean restricted,
4111 String[] excludedPackages, int userId) {
4112 boolean changed = false;
4113
4114 if (perUserRestrictions == null && restricted) {
4115 perUserRestrictions = new SparseArray<>();
4116 }
4117
Philip P. Moltmanne683f192017-06-23 14:05:04 -07004118 int[] users;
4119 if (userId == UserHandle.USER_ALL) {
4120 List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004121
Philip P. Moltmanne683f192017-06-23 14:05:04 -07004122 users = new int[liveUsers.size()];
4123 for (int i = 0; i < liveUsers.size(); i++) {
4124 users[i] = liveUsers.get(i).id;
4125 }
4126 } else {
4127 users = new int[]{userId};
4128 }
4129
4130 if (perUserRestrictions != null) {
4131 int numUsers = users.length;
4132
4133 for (int i = 0; i < numUsers; i++) {
4134 int thisUserId = users[i];
4135
4136 boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
4137 if (userRestrictions == null && restricted) {
4138 userRestrictions = new boolean[AppOpsManager._NUM_OP];
4139 perUserRestrictions.put(thisUserId, userRestrictions);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004140 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07004141 if (userRestrictions != null && userRestrictions[code] != restricted) {
4142 userRestrictions[code] = restricted;
4143 if (!restricted && isDefault(userRestrictions)) {
4144 perUserRestrictions.remove(thisUserId);
4145 userRestrictions = null;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004146 }
4147 changed = true;
4148 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07004149
4150 if (userRestrictions != null) {
4151 final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
4152 if (perUserExcludedPackages == null && !noExcludedPackages) {
4153 perUserExcludedPackages = new SparseArray<>();
4154 }
4155 if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
4156 perUserExcludedPackages.get(thisUserId))) {
4157 if (noExcludedPackages) {
4158 perUserExcludedPackages.remove(thisUserId);
4159 if (perUserExcludedPackages.size() <= 0) {
4160 perUserExcludedPackages = null;
4161 }
4162 } else {
4163 perUserExcludedPackages.put(thisUserId, excludedPackages);
4164 }
4165 changed = true;
4166 }
4167 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004168 }
4169 }
4170
4171 return changed;
4172 }
4173
4174 public boolean hasRestriction(int restriction, String packageName, int userId) {
4175 if (perUserRestrictions == null) {
4176 return false;
4177 }
4178 boolean[] restrictions = perUserRestrictions.get(userId);
4179 if (restrictions == null) {
4180 return false;
4181 }
4182 if (!restrictions[restriction]) {
4183 return false;
4184 }
4185 if (perUserExcludedPackages == null) {
4186 return true;
4187 }
4188 String[] perUserExclusions = perUserExcludedPackages.get(userId);
4189 if (perUserExclusions == null) {
4190 return true;
4191 }
4192 return !ArrayUtils.contains(perUserExclusions, packageName);
4193 }
4194
4195 public void removeUser(int userId) {
4196 if (perUserExcludedPackages != null) {
4197 perUserExcludedPackages.remove(userId);
4198 if (perUserExcludedPackages.size() <= 0) {
4199 perUserExcludedPackages = null;
4200 }
4201 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07004202 if (perUserRestrictions != null) {
4203 perUserRestrictions.remove(userId);
4204 if (perUserRestrictions.size() <= 0) {
4205 perUserRestrictions = null;
4206 }
4207 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004208 }
4209
4210 public boolean isDefault() {
4211 return perUserRestrictions == null || perUserRestrictions.size() <= 0;
4212 }
4213
4214 @Override
4215 public void binderDied() {
4216 synchronized (AppOpsService.this) {
4217 mOpUserRestrictions.remove(token);
4218 if (perUserRestrictions == null) {
4219 return;
4220 }
4221 final int userCount = perUserRestrictions.size();
4222 for (int i = 0; i < userCount; i++) {
4223 final boolean[] restrictions = perUserRestrictions.valueAt(i);
4224 final int restrictionCount = restrictions.length;
4225 for (int j = 0; j < restrictionCount; j++) {
4226 if (restrictions[j]) {
4227 final int changedCode = j;
Svet Ganov3a95f832018-03-23 17:44:30 -07004228 mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004229 }
4230 }
4231 }
4232 destroy();
4233 }
4234 }
4235
4236 public void destroy() {
4237 token.unlinkToDeath(this, 0);
4238 }
4239
4240 private boolean isDefault(boolean[] array) {
4241 if (ArrayUtils.isEmpty(array)) {
4242 return true;
4243 }
4244 for (boolean value : array) {
4245 if (value) {
4246 return false;
4247 }
4248 }
4249 return true;
4250 }
4251 }
Dianne Hackbornd5254412018-05-11 18:02:58 -07004252
4253 private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
4254 @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
4255 synchronized (AppOpsService.this) {
4256 mProfileOwners = owners;
4257 }
4258 }
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07004259
4260 @Override
4261 public void setMode(int code, int uid, @NonNull String packageName, int mode,
4262 boolean isPrivileged) {
4263 AppOpsService.this.setMode(code, uid, packageName, mode, false, isPrivileged);
4264 }
Dianne Hackbornd5254412018-05-11 18:02:58 -07004265 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08004266}