blob: dedb237f004d6a544e22f6747150c63d1923a25e [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;
28
Philip P. Moltmanne683f192017-06-23 14:05:04 -070029import android.Manifest;
Svet Ganovad0a49b2018-10-29 10:07:08 -070030import android.annotation.NonNull;
31import android.annotation.Nullable;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070032import android.app.ActivityManager;
33import android.app.ActivityThread;
34import android.app.AppGlobals;
35import android.app.AppOpsManager;
Svet Ganovad0a49b2018-10-29 10:07:08 -070036import android.app.AppOpsManager.HistoricalOpEntry;
37import android.app.AppOpsManager.HistoricalPackageOps;
Dianne Hackbornd5254412018-05-11 18:02:58 -070038import android.app.AppOpsManagerInternal;
Svet Ganovd873ae62018-06-25 16:39:23 -070039import android.app.AppOpsManagerInternal.CheckOpsDelegate;
Suprabh Shukla3017fe42018-11-08 19:00:01 -080040import android.content.BroadcastReceiver;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070041import android.content.ContentResolver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070042import android.content.Context;
Suprabh Shukla3017fe42018-11-08 19:00:01 -080043import android.content.Intent;
44import android.content.IntentFilter;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070045import android.content.pm.ApplicationInfo;
46import android.content.pm.IPackageManager;
47import android.content.pm.PackageManager;
48import android.content.pm.PackageManagerInternal;
Svet Ganovad0a49b2018-10-29 10:07:08 -070049import android.content.pm.ParceledListSlice;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070050import android.content.pm.UserInfo;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070051import android.database.ContentObserver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070052import android.media.AudioAttributes;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070053import android.net.Uri;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070054import android.os.AsyncTask;
55import android.os.Binder;
56import android.os.Bundle;
57import android.os.Handler;
58import android.os.IBinder;
59import android.os.Process;
60import android.os.RemoteException;
61import android.os.ResultReceiver;
62import android.os.ServiceManager;
63import android.os.ShellCallback;
64import android.os.ShellCommand;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070065import android.os.SystemClock;
Sudheer Shanka98cb3f02018-08-17 16:10:29 -070066import android.os.SystemProperties;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070067import android.os.UserHandle;
68import android.os.UserManager;
Sudheer Shanka98cb3f02018-08-17 16:10:29 -070069import android.os.storage.StorageManager;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070070import android.os.storage.StorageManagerInternal;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070071import android.provider.Settings;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070072import android.util.ArrayMap;
73import android.util.ArraySet;
74import android.util.AtomicFile;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070075import android.util.KeyValueListParser;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070076import android.util.Slog;
77import android.util.SparseArray;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -070078import android.util.SparseBooleanArray;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070079import android.util.SparseIntArray;
80import android.util.TimeUtils;
81import android.util.Xml;
82
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070083import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080084import com.android.internal.app.IAppOpsActiveCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070085import com.android.internal.app.IAppOpsCallback;
86import com.android.internal.app.IAppOpsService;
87import com.android.internal.os.Zygote;
88import com.android.internal.util.ArrayUtils;
89import com.android.internal.util.DumpUtils;
90import com.android.internal.util.FastXmlSerializer;
91import com.android.internal.util.Preconditions;
92import com.android.internal.util.XmlUtils;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080093import com.android.internal.util.function.pooled.PooledLambda;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -050094
Philip P. Moltmanne683f192017-06-23 14:05:04 -070095import libcore.util.EmptyArray;
96
97import org.xmlpull.v1.XmlPullParser;
98import org.xmlpull.v1.XmlPullParserException;
99import org.xmlpull.v1.XmlSerializer;
100
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800101import java.io.File;
102import java.io.FileDescriptor;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800103import java.io.FileInputStream;
104import java.io.FileNotFoundException;
105import java.io.FileOutputStream;
106import java.io.IOException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800107import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100108import java.nio.charset.StandardCharsets;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700109import java.text.SimpleDateFormat;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800110import java.util.ArrayList;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700111import java.util.Arrays;
Svetoslav215b44a2015-08-04 19:03:40 -0700112import java.util.Collections;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700113import java.util.Date;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800114import java.util.HashMap;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800115import java.util.Iterator;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800116import java.util.List;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700117import java.util.Map;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800118
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800119public class AppOpsService extends IAppOpsService.Stub {
120 static final String TAG = "AppOps";
Dianne Hackborn35654b62013-01-14 17:38:02 -0800121 static final boolean DEBUG = false;
122
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700123 private static final int NO_VERSION = -1;
124 /** Increment by one every time and add the corresponding upgrade logic in
125 * {@link #upgradeLocked(int)} below. The first version was 1 */
126 private static final int CURRENT_VERSION = 1;
127
Dianne Hackborn35654b62013-01-14 17:38:02 -0800128 // Write at most every 30 minutes.
129 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800130
Svet Ganov3a95f832018-03-23 17:44:30 -0700131 // Constant meaning that any UID should be matched when dispatching callbacks
132 private static final int UID_ANY = -2;
133
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700134 // Map from process states to the uid states we track.
135 private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
136 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
137 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
138 UID_STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
139 UID_STATE_FOREGROUND_SERVICE, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
140 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
141 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
142 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
143 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
144 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_BACKUP
145 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_SERVICE
146 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_RECEIVER
147 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
148 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
149 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HOME
150 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
151 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
152 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
153 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_RECENT
154 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
155 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT
156 };
157
158 static final String[] UID_STATE_NAMES = new String[] {
159 "pers ", // UID_STATE_PERSISTENT
160 "top ", // UID_STATE_TOP
161 "fgsvc", // UID_STATE_FOREGROUND_SERVICE
162 "fg ", // UID_STATE_FOREGROUND
163 "bg ", // UID_STATE_BACKGROUND
164 "cch ", // UID_STATE_CACHED
165 };
166
167 static final String[] UID_STATE_TIME_ATTRS = new String[] {
168 "tp", // UID_STATE_PERSISTENT
169 "tt", // UID_STATE_TOP
170 "tfs", // UID_STATE_FOREGROUND_SERVICE
171 "tf", // UID_STATE_FOREGROUND
172 "tb", // UID_STATE_BACKGROUND
173 "tc", // UID_STATE_CACHED
174 };
175
176 static final String[] UID_STATE_REJECT_ATTRS = new String[] {
177 "rp", // UID_STATE_PERSISTENT
178 "rt", // UID_STATE_TOP
179 "rfs", // UID_STATE_FOREGROUND_SERVICE
180 "rf", // UID_STATE_FOREGROUND
181 "rb", // UID_STATE_BACKGROUND
182 "rc", // UID_STATE_CACHED
183 };
184
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800185 Context mContext;
186 final AtomicFile mFile;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800187 final Handler mHandler;
188
Dianne Hackbornd5254412018-05-11 18:02:58 -0700189 private final AppOpsManagerInternalImpl mAppOpsManagerInternal
190 = new AppOpsManagerInternalImpl();
191
Dianne Hackborn35654b62013-01-14 17:38:02 -0800192 boolean mWriteScheduled;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800193 boolean mFastWriteScheduled;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800194 final Runnable mWriteRunner = new Runnable() {
195 public void run() {
196 synchronized (AppOpsService.this) {
197 mWriteScheduled = false;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800198 mFastWriteScheduled = false;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800199 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
200 @Override protected Void doInBackground(Void... params) {
201 writeState();
202 return null;
203 }
204 };
205 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
206 }
207 }
208 };
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800209
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700210 @VisibleForTesting
211 final SparseArray<UidState> mUidStates = new SparseArray<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800212
Dianne Hackborn9fb93502018-06-18 12:29:44 -0700213 long mLastRealtime;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700214
Ruben Brunk29931bc2016-03-11 00:24:26 -0800215 /*
216 * These are app op restrictions imposed per user from various parties.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800217 */
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700218 private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
Jason Monk62062992014-05-06 09:55:28 -0400219
Dianne Hackbornd5254412018-05-11 18:02:58 -0700220 SparseIntArray mProfileOwners;
221
Svet Ganovd873ae62018-06-25 16:39:23 -0700222 private CheckOpsDelegate mCheckOpsDelegate;
223
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700224 /**
225 * All times are in milliseconds. These constants are kept synchronized with the system
226 * global Settings. Any access to this class or its fields should be done while
227 * holding the AppOpsService lock.
228 */
229 private final class Constants extends ContentObserver {
230 // Key names stored in the settings value.
Dianne Hackborne93ab412018-05-14 17:52:30 -0700231 private static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
232 private static final String KEY_FG_SERVICE_STATE_SETTLE_TIME
233 = "fg_service_state_settle_time";
234 private static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700235
236 /**
Dianne Hackborne93ab412018-05-14 17:52:30 -0700237 * How long we want for a drop in uid state from top to settle before applying it.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700238 * @see Settings.Global#APP_OPS_CONSTANTS
Dianne Hackborne93ab412018-05-14 17:52:30 -0700239 * @see #KEY_TOP_STATE_SETTLE_TIME
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700240 */
Dianne Hackborne93ab412018-05-14 17:52:30 -0700241 public long TOP_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700242
Dianne Hackborne93ab412018-05-14 17:52:30 -0700243 /**
244 * How long we want for a drop in uid state from foreground to settle before applying it.
245 * @see Settings.Global#APP_OPS_CONSTANTS
246 * @see #KEY_FG_SERVICE_STATE_SETTLE_TIME
247 */
248 public long FG_SERVICE_STATE_SETTLE_TIME;
249
250 /**
251 * How long we want for a drop in uid state from background to settle before applying it.
252 * @see Settings.Global#APP_OPS_CONSTANTS
253 * @see #KEY_BG_STATE_SETTLE_TIME
254 */
255 public long BG_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700256
257 private final KeyValueListParser mParser = new KeyValueListParser(',');
258 private ContentResolver mResolver;
259
260 public Constants(Handler handler) {
261 super(handler);
262 updateConstants();
263 }
264
265 public void startMonitoring(ContentResolver resolver) {
266 mResolver = resolver;
267 mResolver.registerContentObserver(
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700268 Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700269 false, this);
270 updateConstants();
271 }
272
273 @Override
274 public void onChange(boolean selfChange, Uri uri) {
275 updateConstants();
276 }
277
278 private void updateConstants() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700279 String value = mResolver != null ? Settings.Global.getString(mResolver,
280 Settings.Global.APP_OPS_CONSTANTS) : "";
281
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700282 synchronized (AppOpsService.this) {
283 try {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700284 mParser.setString(value);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700285 } catch (IllegalArgumentException e) {
286 // Failed to parse the settings string, log this and move on
287 // with defaults.
288 Slog.e(TAG, "Bad app ops settings", e);
289 }
Dianne Hackborne93ab412018-05-14 17:52:30 -0700290 TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
291 KEY_TOP_STATE_SETTLE_TIME, 30 * 1000L);
292 FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
293 KEY_FG_SERVICE_STATE_SETTLE_TIME, 10 * 1000L);
294 BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
295 KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700296 }
297 }
298
299 void dump(PrintWriter pw) {
300 pw.println(" Settings:");
301
Dianne Hackborne93ab412018-05-14 17:52:30 -0700302 pw.print(" "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("=");
303 TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700304 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700305 pw.print(" "); pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME); pw.print("=");
306 TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700307 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700308 pw.print(" "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("=");
309 TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700310 pw.println();
311 }
312 }
313
314 private final Constants mConstants;
315
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700316 @VisibleForTesting
317 static final class UidState {
Svet Ganov2af57082015-07-30 08:44:20 -0700318 public final int uid;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700319
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700320 public int state = UID_STATE_CACHED;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700321 public int pendingState = UID_STATE_CACHED;
322 public long pendingStateCommitTime;
323
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700324 public int startNesting;
Svet Ganov2af57082015-07-30 08:44:20 -0700325 public ArrayMap<String, Ops> pkgOps;
326 public SparseIntArray opModes;
327
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700328 // true indicates there is an interested observer, false there isn't but it has such an op
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700329 public SparseBooleanArray foregroundOps;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700330 public boolean hasForegroundWatchers;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700331
Svet Ganov2af57082015-07-30 08:44:20 -0700332 public UidState(int uid) {
333 this.uid = uid;
334 }
335
336 public void clear() {
337 pkgOps = null;
338 opModes = null;
339 }
340
341 public boolean isDefault() {
342 return (pkgOps == null || pkgOps.isEmpty())
343 && (opModes == null || opModes.size() <= 0);
344 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700345
346 int evalMode(int mode) {
347 if (mode == AppOpsManager.MODE_FOREGROUND) {
Dianne Hackborne93ab412018-05-14 17:52:30 -0700348 return state <= UID_STATE_LAST_NON_RESTRICTED
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700349 ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
350 }
351 return mode;
352 }
353
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700354 private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
355 SparseBooleanArray which) {
356 boolean curValue = which.get(op, false);
357 ArraySet<ModeCallback> callbacks = watchers.get(op);
358 if (callbacks != null) {
359 for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
360 if ((callbacks.valueAt(cbi).mFlags
361 & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
362 hasForegroundWatchers = true;
363 curValue = true;
364 }
365 }
366 }
367 which.put(op, curValue);
368 }
369
370 public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700371 SparseBooleanArray which = null;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700372 hasForegroundWatchers = false;
373 if (opModes != null) {
374 for (int i = opModes.size() - 1; i >= 0; i--) {
375 if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
376 if (which == null) {
377 which = new SparseBooleanArray();
378 }
379 evalForegroundWatchers(opModes.keyAt(i), watchers, which);
380 }
381 }
382 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700383 if (pkgOps != null) {
384 for (int i = pkgOps.size() - 1; i >= 0; i--) {
385 Ops ops = pkgOps.valueAt(i);
386 for (int j = ops.size() - 1; j >= 0; j--) {
387 if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
388 if (which == null) {
389 which = new SparseBooleanArray();
390 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700391 evalForegroundWatchers(ops.keyAt(j), watchers, which);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700392 }
393 }
394 }
395 }
396 foregroundOps = which;
397 }
Svet Ganov2af57082015-07-30 08:44:20 -0700398 }
399
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700400 final static class Ops extends SparseArray<Op> {
401 final String packageName;
402 final UidState uidState;
403 final boolean isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800404
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700405 Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800406 packageName = _packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700407 uidState = _uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400408 isPrivileged = _isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800409 }
410 }
411
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700412 final static class Op {
413 final UidState uidState;
414 final int uid;
415 final String packageName;
416 final int op;
417 int proxyUid = -1;
418 String proxyPackageName;
419 int mode;
420 int duration;
421 long time[] = new long[_NUM_UID_STATE];
422 long rejectTime[] = new long[_NUM_UID_STATE];
423 int startNesting;
424 long startRealtime;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800425
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700426 Op(UidState _uidState, String _packageName, int _op) {
427 uidState = _uidState;
428 uid = _uidState.uid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700429 packageName = _packageName;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800430 op = _op;
David Braunf5d83192013-09-16 13:43:51 -0700431 mode = AppOpsManager.opToDefaultMode(op);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800432 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700433
434 boolean hasAnyTime() {
435 for (int i = 0; i < AppOpsManager._NUM_UID_STATE; i++) {
436 if (time[i] != 0) {
437 return true;
438 }
439 if (rejectTime[i] != 0) {
440 return true;
441 }
442 }
443 return false;
444 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700445
446 int getMode() {
447 return uidState.evalMode(mode);
448 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800449 }
450
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800451 final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
452 final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
453 final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
454 final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
Dianne Hackborn68d76552017-02-27 15:32:03 -0800455 final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800456
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700457 final class ModeCallback implements DeathRecipient {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800458 final IAppOpsCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700459 final int mWatchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700460 final int mFlags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700461 final int mCallingUid;
462 final int mCallingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800463
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700464 ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700465 int callingPid) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800466 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700467 mWatchingUid = watchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700468 mFlags = flags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700469 mCallingUid = callingUid;
470 mCallingPid = callingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800471 try {
472 mCallback.asBinder().linkToDeath(this, 0);
473 } catch (RemoteException e) {
474 }
475 }
476
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700477 public boolean isWatchingUid(int uid) {
478 return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
479 }
480
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700481 @Override
482 public String toString() {
483 StringBuilder sb = new StringBuilder(128);
484 sb.append("ModeCallback{");
485 sb.append(Integer.toHexString(System.identityHashCode(this)));
486 sb.append(" watchinguid=");
487 UserHandle.formatUid(sb, mWatchingUid);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700488 sb.append(" flags=0x");
489 sb.append(Integer.toHexString(mFlags));
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700490 sb.append(" from uid=");
491 UserHandle.formatUid(sb, mCallingUid);
492 sb.append(" pid=");
493 sb.append(mCallingPid);
494 sb.append('}');
495 return sb.toString();
496 }
497
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700498 void unlinkToDeath() {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800499 mCallback.asBinder().unlinkToDeath(this, 0);
500 }
501
502 @Override
503 public void binderDied() {
504 stopWatchingMode(mCallback);
505 }
506 }
507
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700508 final class ActiveCallback implements DeathRecipient {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800509 final IAppOpsActiveCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700510 final int mWatchingUid;
511 final int mCallingUid;
512 final int mCallingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800513
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700514 ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700515 int callingPid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800516 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700517 mWatchingUid = watchingUid;
518 mCallingUid = callingUid;
519 mCallingPid = callingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800520 try {
521 mCallback.asBinder().linkToDeath(this, 0);
522 } catch (RemoteException e) {
523 }
524 }
525
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700526 @Override
527 public String toString() {
528 StringBuilder sb = new StringBuilder(128);
529 sb.append("ActiveCallback{");
530 sb.append(Integer.toHexString(System.identityHashCode(this)));
531 sb.append(" watchinguid=");
532 UserHandle.formatUid(sb, mWatchingUid);
533 sb.append(" from uid=");
534 UserHandle.formatUid(sb, mCallingUid);
535 sb.append(" pid=");
536 sb.append(mCallingPid);
537 sb.append('}');
538 return sb.toString();
539 }
540
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700541 void destroy() {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800542 mCallback.asBinder().unlinkToDeath(this, 0);
543 }
544
545 @Override
546 public void binderDied() {
547 stopWatchingActive(mCallback);
548 }
549 }
550
Svet Ganova7a0db62018-02-27 20:08:01 -0800551 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700552
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700553 final class ClientState extends Binder implements DeathRecipient {
Svet Ganovf7b47252018-02-26 11:11:27 -0800554 final ArrayList<Op> mStartedOps = new ArrayList<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700555 final IBinder mAppToken;
556 final int mPid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700557
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700558 ClientState(IBinder appToken) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700559 mAppToken = appToken;
560 mPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -0800561 // Watch only for remote processes dying
562 if (!(appToken instanceof Binder)) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700563 try {
564 mAppToken.linkToDeath(this, 0);
565 } catch (RemoteException e) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800566 /* do nothing */
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700567 }
568 }
569 }
570
571 @Override
572 public String toString() {
573 return "ClientState{" +
574 "mAppToken=" + mAppToken +
Svet Ganovf7b47252018-02-26 11:11:27 -0800575 ", " + "pid=" + mPid +
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700576 '}';
577 }
578
579 @Override
580 public void binderDied() {
581 synchronized (AppOpsService.this) {
582 for (int i=mStartedOps.size()-1; i>=0; i--) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800583 finishOperationLocked(mStartedOps.get(i), /*finishNested*/ true);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700584 }
585 mClients.remove(mAppToken);
586 }
587 }
588 }
589
Jeff Brown6f357d32014-01-15 20:40:55 -0800590 public AppOpsService(File storagePath, Handler handler) {
Jeff Sharkey5f3e9342017-03-13 14:53:11 -0600591 LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
Dianne Hackborne17b4452018-01-10 13:15:40 -0800592 mFile = new AtomicFile(storagePath, "appops");
Jeff Brown6f357d32014-01-15 20:40:55 -0800593 mHandler = handler;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700594 mConstants = new Constants(mHandler);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800595 readState();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800596 }
David Braunf5d83192013-09-16 13:43:51 -0700597
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800598 public void publish(Context context) {
599 mContext = context;
600 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
Dianne Hackbornd5254412018-05-11 18:02:58 -0700601 LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800602 }
603
Dianne Hackborn514074f2013-02-11 10:52:46 -0800604 public void systemReady() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700605 mConstants.startMonitoring(mContext.getContentResolver());
606
Dianne Hackborn514074f2013-02-11 10:52:46 -0800607 synchronized (this) {
608 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700609 for (int i = mUidStates.size() - 1; i >= 0; i--) {
610 UidState uidState = mUidStates.valueAt(i);
611
612 String[] packageNames = getPackagesForUid(uidState.uid);
613 if (ArrayUtils.isEmpty(packageNames)) {
614 uidState.clear();
615 mUidStates.removeAt(i);
616 changed = true;
617 continue;
618 }
619
620 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
621 if (pkgs == null) {
622 continue;
623 }
624
Dianne Hackborn514074f2013-02-11 10:52:46 -0800625 Iterator<Ops> it = pkgs.values().iterator();
626 while (it.hasNext()) {
627 Ops ops = it.next();
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700628 int curUid = -1;
Dianne Hackborn514074f2013-02-11 10:52:46 -0800629 try {
Jeff Sharkeycd654482016-01-08 17:42:11 -0700630 curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
631 PackageManager.MATCH_UNINSTALLED_PACKAGES,
Svet Ganov2af57082015-07-30 08:44:20 -0700632 UserHandle.getUserId(ops.uidState.uid));
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700633 } catch (RemoteException ignored) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800634 }
Svet Ganov2af57082015-07-30 08:44:20 -0700635 if (curUid != ops.uidState.uid) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800636 Slog.i(TAG, "Pruning old package " + ops.packageName
Svet Ganov2af57082015-07-30 08:44:20 -0700637 + "/" + ops.uidState + ": new uid=" + curUid);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800638 it.remove();
639 changed = true;
640 }
641 }
Svet Ganov2af57082015-07-30 08:44:20 -0700642
643 if (uidState.isDefault()) {
644 mUidStates.removeAt(i);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800645 }
646 }
647 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800648 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800649 }
650 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700651
Suprabh Shukla3017fe42018-11-08 19:00:01 -0800652 final IntentFilter packageSuspendFilter = new IntentFilter();
653 packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
654 packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
655 mContext.registerReceiver(new BroadcastReceiver() {
656 @Override
657 public void onReceive(Context context, Intent intent) {
658 final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
659 final String[] changedPkgs = intent.getStringArrayExtra(
660 Intent.EXTRA_CHANGED_PACKAGE_LIST);
661 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(OP_PLAY_AUDIO);
662 for (int i = 0; i < changedUids.length; i++) {
663 final int changedUid = changedUids[i];
664 final String changedPkg = changedPkgs[i];
665 // We trust packagemanager to insert matching uid and packageNames in the extras
666 mHandler.sendMessage(PooledLambda.obtainMessage(AppOpsService::notifyOpChanged,
667 AppOpsService.this, callbacks, OP_PLAY_AUDIO, changedUid, changedPkg));
668 }
669 }
670 }, packageSuspendFilter);
671
Suprabh Shuklaaef25132017-01-23 18:09:03 -0800672 PackageManagerInternal packageManagerInternal = LocalServices.getService(
673 PackageManagerInternal.class);
674 packageManagerInternal.setExternalSourcesPolicy(
675 new PackageManagerInternal.ExternalSourcesPolicy() {
676 @Override
677 public int getPackageTrustedToInstallApps(String packageName, int uid) {
678 int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
679 uid, packageName);
680 switch (appOpMode) {
681 case AppOpsManager.MODE_ALLOWED:
682 return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
683 case AppOpsManager.MODE_ERRORED:
684 return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
685 default:
686 return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
687 }
688 }
689 });
690
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700691 if (!SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, false)) {
692 StorageManagerInternal storageManagerInternal = LocalServices.getService(
693 StorageManagerInternal.class);
694 storageManagerInternal.addExternalStoragePolicy(
695 new StorageManagerInternal.ExternalStorageMountPolicy() {
696 @Override
697 public int getMountMode(int uid, String packageName) {
698 if (Process.isIsolated(uid)) {
699 return Zygote.MOUNT_EXTERNAL_NONE;
700 }
701 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
702 packageName) != AppOpsManager.MODE_ALLOWED) {
703 return Zygote.MOUNT_EXTERNAL_NONE;
704 }
705 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
706 packageName) != AppOpsManager.MODE_ALLOWED) {
707 return Zygote.MOUNT_EXTERNAL_READ;
708 }
709 return Zygote.MOUNT_EXTERNAL_WRITE;
Svet Ganov6ee871e2015-07-10 14:29:33 -0700710 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700711
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700712 @Override
713 public boolean hasExternalStorage(int uid, String packageName) {
714 final int mountMode = getMountMode(uid, packageName);
715 return mountMode == Zygote.MOUNT_EXTERNAL_READ
716 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
717 }
718 });
719 }
Dianne Hackborn514074f2013-02-11 10:52:46 -0800720 }
721
722 public void packageRemoved(int uid, String packageName) {
723 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700724 UidState uidState = mUidStates.get(uid);
725 if (uidState == null) {
726 return;
727 }
728
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800729 Ops ops = null;
Svet Ganov2af57082015-07-30 08:44:20 -0700730
731 // Remove any package state if such.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800732 if (uidState.pkgOps != null) {
733 ops = uidState.pkgOps.remove(packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700734 }
735
736 // If we just nuked the last package state check if the UID is valid.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800737 if (ops != null && uidState.pkgOps.isEmpty()
Svet Ganov2af57082015-07-30 08:44:20 -0700738 && getPackagesForUid(uid).length <= 0) {
739 mUidStates.remove(uid);
740 }
741
Svet Ganova7a0db62018-02-27 20:08:01 -0800742 // Finish ops other packages started on behalf of the package.
743 final int clientCount = mClients.size();
744 for (int i = 0; i < clientCount; i++) {
745 final ClientState client = mClients.valueAt(i);
746 if (client.mStartedOps == null) {
747 continue;
748 }
749 final int opCount = client.mStartedOps.size();
750 for (int j = opCount - 1; j >= 0; j--) {
751 final Op op = client.mStartedOps.get(j);
752 if (uid == op.uid && packageName.equals(op.packageName)) {
753 finishOperationLocked(op, /*finishNested*/ true);
754 client.mStartedOps.remove(j);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700755 if (op.startNesting <= 0) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800756 scheduleOpActiveChangedIfNeededLocked(op.op,
757 uid, packageName, false);
758 }
759 }
760 }
761 }
762
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800763 if (ops != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700764 scheduleFastWriteLocked();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800765
766 final int opCount = ops.size();
767 for (int i = 0; i < opCount; i++) {
768 final Op op = ops.valueAt(i);
769 if (op.duration == -1) {
770 scheduleOpActiveChangedIfNeededLocked(
771 op.op, op.uid, op.packageName, false);
772 }
773 }
Dianne Hackborn514074f2013-02-11 10:52:46 -0800774 }
775 }
776 }
777
778 public void uidRemoved(int uid) {
779 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700780 if (mUidStates.indexOfKey(uid) >= 0) {
781 mUidStates.remove(uid);
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800782 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800783 }
784 }
785 }
786
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700787 public void updateUidProcState(int uid, int procState) {
788 synchronized (this) {
789 final UidState uidState = getUidStateLocked(uid, true);
790 final int newState = PROCESS_STATE_TO_UID_STATE[procState];
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700791 if (uidState != null && uidState.pendingState != newState) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700792 final int oldPendingState = uidState.pendingState;
793 uidState.pendingState = newState;
Dianne Hackborne93ab412018-05-14 17:52:30 -0700794 if (newState < uidState.state || newState <= UID_STATE_LAST_NON_RESTRICTED) {
795 // We are moving to a more important state, or the new state is in the
796 // foreground, then always do it immediately.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700797 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700798 } else if (uidState.pendingStateCommitTime == 0) {
799 // We are moving to a less important state for the first time,
800 // delay the application for a bit.
Dianne Hackborne93ab412018-05-14 17:52:30 -0700801 final long settleTime;
802 if (uidState.state <= UID_STATE_TOP) {
803 settleTime = mConstants.TOP_STATE_SETTLE_TIME;
804 } else if (uidState.state <= UID_STATE_FOREGROUND_SERVICE) {
805 settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
806 } else {
807 settleTime = mConstants.BG_STATE_SETTLE_TIME;
808 }
Dianne Hackborn9fb93502018-06-18 12:29:44 -0700809 uidState.pendingStateCommitTime = SystemClock.elapsedRealtime() + settleTime;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700810 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700811 if (uidState.startNesting != 0) {
812 // There is some actively running operation... need to find it
813 // and appropriately update its state.
814 final long now = System.currentTimeMillis();
815 for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
816 final Ops ops = uidState.pkgOps.valueAt(i);
817 for (int j = ops.size() - 1; j >= 0; j--) {
818 final Op op = ops.valueAt(j);
819 if (op.startNesting > 0) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700820 op.time[oldPendingState] = now;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700821 op.time[newState] = now;
822 }
823 }
824 }
825 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700826 }
827 }
828 }
829
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800830 public void shutdown() {
831 Slog.w(TAG, "Writing app ops before shutdown...");
Dianne Hackborn35654b62013-01-14 17:38:02 -0800832 boolean doWrite = false;
833 synchronized (this) {
834 if (mWriteScheduled) {
835 mWriteScheduled = false;
836 doWrite = true;
837 }
838 }
839 if (doWrite) {
840 writeState();
841 }
842 }
843
Dianne Hackborn72e39832013-01-18 18:36:09 -0800844 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
845 ArrayList<AppOpsManager.OpEntry> resOps = null;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700846 final long elapsedNow = SystemClock.elapsedRealtime();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800847 if (ops == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700848 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800849 for (int j=0; j<pkgOps.size(); j++) {
850 Op curOp = pkgOps.valueAt(j);
Amith Yamasania1ce9632018-05-28 20:50:48 -0700851 final boolean running = curOp.duration == -1;
852 long duration = running
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700853 ? (elapsedNow - curOp.startRealtime)
854 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800855 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Amith Yamasania1ce9632018-05-28 20:50:48 -0700856 curOp.rejectTime, (int) duration, running, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700857 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800858 }
859 } else {
860 for (int j=0; j<ops.length; j++) {
861 Op curOp = pkgOps.get(ops[j]);
862 if (curOp != null) {
863 if (resOps == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700864 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800865 }
Amith Yamasania1ce9632018-05-28 20:50:48 -0700866 final boolean running = curOp.duration == -1;
867 final long duration = running
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700868 ? (elapsedNow - curOp.startRealtime)
869 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800870 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Amith Yamasania1ce9632018-05-28 20:50:48 -0700871 curOp.rejectTime, (int) duration, running, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700872 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800873 }
874 }
875 }
876 return resOps;
877 }
878
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700879 private ArrayList<AppOpsManager.OpEntry> collectOps(SparseIntArray uidOps, int[] ops) {
880 ArrayList<AppOpsManager.OpEntry> resOps = null;
881 if (ops == null) {
882 resOps = new ArrayList<>();
883 for (int j=0; j<uidOps.size(); j++) {
884 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(j), uidOps.valueAt(j),
885 0, 0, 0, -1, null));
886 }
887 } else {
888 for (int j=0; j<ops.length; j++) {
889 int index = uidOps.indexOfKey(ops[j]);
890 if (index >= 0) {
891 if (resOps == null) {
892 resOps = new ArrayList<>();
893 }
894 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(index), uidOps.valueAt(index),
895 0, 0, 0, -1, null));
896 }
897 }
898 }
899 return resOps;
900 }
901
Dianne Hackborn35654b62013-01-14 17:38:02 -0800902 @Override
903 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
904 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
905 Binder.getCallingPid(), Binder.getCallingUid(), null);
906 ArrayList<AppOpsManager.PackageOps> res = null;
907 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700908 final int uidStateCount = mUidStates.size();
909 for (int i = 0; i < uidStateCount; i++) {
910 UidState uidState = mUidStates.valueAt(i);
911 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
912 continue;
913 }
914 ArrayMap<String, Ops> packages = uidState.pkgOps;
915 final int packageCount = packages.size();
916 for (int j = 0; j < packageCount; j++) {
917 Ops pkgOps = packages.valueAt(j);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800918 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800919 if (resOps != null) {
920 if (res == null) {
921 res = new ArrayList<AppOpsManager.PackageOps>();
922 }
923 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700924 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800925 res.add(resPackage);
926 }
927 }
928 }
929 }
930 return res;
931 }
932
933 @Override
Dianne Hackborn72e39832013-01-18 18:36:09 -0800934 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
935 int[] ops) {
936 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
937 Binder.getCallingPid(), Binder.getCallingUid(), null);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000938 String resolvedPackageName = resolvePackageName(uid, packageName);
939 if (resolvedPackageName == null) {
940 return Collections.emptyList();
941 }
Dianne Hackborn72e39832013-01-18 18:36:09 -0800942 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -0700943 Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
944 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800945 if (pkgOps == null) {
946 return null;
947 }
948 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
949 if (resOps == null) {
950 return null;
951 }
952 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
953 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700954 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800955 res.add(resPackage);
956 return res;
957 }
958 }
959
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700960 @Override
Svet Ganovad0a49b2018-10-29 10:07:08 -0700961 public @Nullable ParceledListSlice getAllHistoricalPackagesOps(@Nullable String[] opNames,
962 long beginTimeMillis, long endTimeMillis) {
963 Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
964 "beginTimeMillis must be non negative and lesser than endTimeMillis");
965
966 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
967 Binder.getCallingPid(), Binder.getCallingUid(), "getAllHistoricalPackagesOps");
968
969 ArrayList<HistoricalPackageOps> historicalPackageOpsList = null;
970
971 final int uidStateCount = mUidStates.size();
972 for (int i = 0; i < uidStateCount; i++) {
973 final UidState uidState = mUidStates.valueAt(i);
974 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
975 continue;
976 }
977 final ArrayMap<String, Ops> packages = uidState.pkgOps;
978 final int packageCount = packages.size();
979 for (int j = 0; j < packageCount; j++) {
980 final Ops pkgOps = packages.valueAt(j);
981 final AppOpsManager.HistoricalPackageOps historicalPackageOps =
982 createHistoricalPackageOps(uidState.uid, pkgOps, opNames,
983 beginTimeMillis, endTimeMillis);
984 if (historicalPackageOps != null) {
985 if (historicalPackageOpsList == null) {
986 historicalPackageOpsList = new ArrayList<>();
987 }
988 historicalPackageOpsList.add(historicalPackageOps);
989 }
990 }
991 }
992
993 if (historicalPackageOpsList == null) {
994 return null;
995 }
996
997 return new ParceledListSlice<>(historicalPackageOpsList);
998 }
999
1000 private static @Nullable HistoricalPackageOps createHistoricalPackageOps(int uid,
1001 @Nullable Ops pkgOps, @Nullable String[] opNames, long beginTimeMillis,
1002 long endTimeMillis) {
1003 // TODO: Implement historical data collection
1004 if (pkgOps == null) {
1005 return null;
1006 }
1007
1008 final HistoricalPackageOps historicalPackageOps = new HistoricalPackageOps(uid,
1009 pkgOps.packageName);
1010
1011 if (opNames == null) {
1012 opNames = AppOpsManager.getOpStrs();
1013 }
1014 for (String opName : opNames) {
1015 addHistoricOpEntry(AppOpsManager.strOpToOp(opName), pkgOps, historicalPackageOps);
1016 }
1017
1018 return historicalPackageOps;
1019 }
1020
1021 @Override
1022 public @Nullable HistoricalPackageOps getHistoricalPackagesOps(int uid,
1023 @NonNull String packageName, @Nullable String[] opNames,
1024 long beginTimeMillis, long endTimeMillis) {
1025 Preconditions.checkNotNull(packageName,
1026 "packageName cannot be null");
1027 Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
1028 "beginTimeMillis must be non negative and lesser than endTimeMillis");
1029
1030 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1031 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalPackagesOps");
1032
1033 final String resolvedPackageName = resolvePackageName(uid, packageName);
1034 if (resolvedPackageName == null) {
1035 return null;
1036 }
1037
1038 // TODO: Implement historical data collection
1039 final Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
1040 false /* uidMismatchExpected */);
1041 return createHistoricalPackageOps(uid, pkgOps, opNames, beginTimeMillis, endTimeMillis);
1042 }
1043
1044 private static void addHistoricOpEntry(int opCode, @NonNull Ops ops,
1045 @NonNull HistoricalPackageOps outHistoricalPackageOps) {
1046 final Op op = ops.get(opCode);
1047 if (op == null) {
1048 return;
1049 }
1050
1051 final HistoricalOpEntry historicalOpEntry = new HistoricalOpEntry(opCode);
1052
1053 // TODO: Keep per UID state duration
1054 for (int uidState = 0; uidState < AppOpsManager._NUM_UID_STATE; uidState++) {
1055 final int acceptCount;
1056 final int rejectCount;
1057 if (op.rejectTime[uidState] == 0) {
1058 acceptCount = 1;
1059 rejectCount = 0;
1060 } else {
1061 acceptCount = 0;
1062 rejectCount = 1;
1063 }
1064 historicalOpEntry.addEntry(uidState, acceptCount, rejectCount, 0);
1065 }
1066
1067 outHistoricalPackageOps.addEntry(historicalOpEntry);
1068 }
1069
1070 @Override
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001071 public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
1072 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1073 Binder.getCallingPid(), Binder.getCallingUid(), null);
1074 synchronized (this) {
1075 UidState uidState = getUidStateLocked(uid, false);
1076 if (uidState == null) {
1077 return null;
1078 }
1079 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState.opModes, ops);
1080 if (resOps == null) {
1081 return null;
1082 }
1083 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
1084 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
1085 null, uidState.uid, resOps);
1086 res.add(resPackage);
1087 return res;
1088 }
1089 }
1090
Dianne Hackborn607b4142013-08-02 18:10:10 -07001091 private void pruneOp(Op op, int uid, String packageName) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001092 if (!op.hasAnyTime()) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001093 Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
1094 false /* uidMismatchExpected */);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001095 if (ops != null) {
1096 ops.remove(op.op);
1097 if (ops.size() <= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -07001098 UidState uidState = ops.uidState;
1099 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001100 if (pkgOps != null) {
1101 pkgOps.remove(ops.packageName);
Svet Ganov2af57082015-07-30 08:44:20 -07001102 if (pkgOps.isEmpty()) {
1103 uidState.pkgOps = null;
1104 }
1105 if (uidState.isDefault()) {
1106 mUidStates.remove(uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001107 }
1108 }
1109 }
1110 }
1111 }
1112 }
1113
Dianne Hackbornd5254412018-05-11 18:02:58 -07001114 void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
1115 if (callingPid == Process.myPid()) {
1116 return;
1117 }
1118 final int callingUser = UserHandle.getUserId(callingUid);
1119 synchronized (this) {
1120 if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
1121 if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
1122 // Profile owners are allowed to change modes but only for apps
1123 // within their user.
1124 return;
1125 }
1126 }
1127 }
1128 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
1129 Binder.getCallingPid(), Binder.getCallingUid(), null);
1130 }
1131
Dianne Hackborn72e39832013-01-18 18:36:09 -08001132 @Override
Svet Ganov2af57082015-07-30 08:44:20 -07001133 public void setUidMode(int code, int uid, int mode) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001134 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Svet Ganov2af57082015-07-30 08:44:20 -07001135 verifyIncomingOp(code);
1136 code = AppOpsManager.opToSwitch(code);
1137
1138 synchronized (this) {
1139 final int defaultMode = AppOpsManager.opToDefaultMode(code);
1140
1141 UidState uidState = getUidStateLocked(uid, false);
1142 if (uidState == null) {
1143 if (mode == defaultMode) {
1144 return;
1145 }
1146 uidState = new UidState(uid);
1147 uidState.opModes = new SparseIntArray();
1148 uidState.opModes.put(code, mode);
1149 mUidStates.put(uid, uidState);
1150 scheduleWriteLocked();
1151 } else if (uidState.opModes == null) {
1152 if (mode != defaultMode) {
1153 uidState.opModes = new SparseIntArray();
1154 uidState.opModes.put(code, mode);
1155 scheduleWriteLocked();
1156 }
1157 } else {
Hai Zhang2b98fb32018-09-21 15:18:46 -07001158 if (uidState.opModes.indexOfKey(code) >= 0 && uidState.opModes.get(code) == mode) {
Svet Ganov2af57082015-07-30 08:44:20 -07001159 return;
1160 }
1161 if (mode == defaultMode) {
1162 uidState.opModes.delete(code);
1163 if (uidState.opModes.size() <= 0) {
1164 uidState.opModes = null;
1165 }
1166 } else {
1167 uidState.opModes.put(code, mode);
1168 }
1169 scheduleWriteLocked();
1170 }
1171 }
1172
Svetoslav215b44a2015-08-04 19:03:40 -07001173 String[] uidPackageNames = getPackagesForUid(uid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001174 ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
Svet Ganov2af57082015-07-30 08:44:20 -07001175
riddle_hsu40b300f2015-11-23 13:22:03 +08001176 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001177 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001178 if (callbacks != null) {
Svet Ganov2af57082015-07-30 08:44:20 -07001179 final int callbackCount = callbacks.size();
1180 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001181 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08001182 ArraySet<String> changedPackages = new ArraySet<>();
1183 Collections.addAll(changedPackages, uidPackageNames);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001184 if (callbackSpecs == null) {
1185 callbackSpecs = new ArrayMap<>();
1186 }
riddle_hsu40b300f2015-11-23 13:22:03 +08001187 callbackSpecs.put(callback, changedPackages);
1188 }
1189 }
1190
1191 for (String uidPackageName : uidPackageNames) {
1192 callbacks = mPackageModeWatchers.get(uidPackageName);
1193 if (callbacks != null) {
1194 if (callbackSpecs == null) {
1195 callbackSpecs = new ArrayMap<>();
Svet Ganov2af57082015-07-30 08:44:20 -07001196 }
riddle_hsu40b300f2015-11-23 13:22:03 +08001197 final int callbackCount = callbacks.size();
1198 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001199 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08001200 ArraySet<String> changedPackages = callbackSpecs.get(callback);
1201 if (changedPackages == null) {
1202 changedPackages = new ArraySet<>();
1203 callbackSpecs.put(callback, changedPackages);
1204 }
1205 changedPackages.add(uidPackageName);
1206 }
Svet Ganov2af57082015-07-30 08:44:20 -07001207 }
1208 }
1209 }
1210
1211 if (callbackSpecs == null) {
1212 return;
1213 }
1214
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001215 for (int i = 0; i < callbackSpecs.size(); i++) {
1216 final ModeCallback callback = callbackSpecs.keyAt(i);
1217 final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
1218 if (reportedPackageNames == null) {
1219 mHandler.sendMessage(PooledLambda.obtainMessage(
1220 AppOpsService::notifyOpChanged,
1221 this, callback, code, uid, (String) null));
1222
1223 } else {
1224 final int reportedPackageCount = reportedPackageNames.size();
1225 for (int j = 0; j < reportedPackageCount; j++) {
1226 final String reportedPackageName = reportedPackageNames.valueAt(j);
1227 mHandler.sendMessage(PooledLambda.obtainMessage(
1228 AppOpsService::notifyOpChanged,
1229 this, callback, code, uid, reportedPackageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001230 }
1231 }
Svet Ganov2af57082015-07-30 08:44:20 -07001232 }
1233 }
1234
1235 @Override
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001236 public void setMode(int code, int uid, String packageName, int mode) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001237 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001238 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001239 ArraySet<ModeCallback> repCbs = null;
Dianne Hackbornc2293022013-02-06 23:14:49 -08001240 code = AppOpsManager.opToSwitch(code);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001241 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001242 UidState uidState = getUidStateLocked(uid, false);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001243 Op op = getOpLocked(code, uid, packageName, true);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001244 if (op != null) {
1245 if (op.mode != mode) {
1246 op.mode = mode;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001247 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001248 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001249 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001250 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001251 if (cbs != null) {
1252 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001253 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001254 }
1255 repCbs.addAll(cbs);
1256 }
1257 cbs = mPackageModeWatchers.get(packageName);
1258 if (cbs != null) {
1259 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001260 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001261 }
1262 repCbs.addAll(cbs);
1263 }
David Braunf5d83192013-09-16 13:43:51 -07001264 if (mode == AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001265 // If going into the default mode, prune this op
1266 // if there is nothing else interesting in it.
Dianne Hackborn607b4142013-08-02 18:10:10 -07001267 pruneOp(op, uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001268 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001269 scheduleFastWriteLocked();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001270 }
1271 }
1272 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001273 if (repCbs != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001274 mHandler.sendMessage(PooledLambda.obtainMessage(
1275 AppOpsService::notifyOpChanged,
1276 this, repCbs, code, uid, packageName));
Dianne Hackbornc2293022013-02-06 23:14:49 -08001277 }
1278 }
1279
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001280 private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
1281 int uid, String packageName) {
1282 for (int i = 0; i < callbacks.size(); i++) {
1283 final ModeCallback callback = callbacks.valueAt(i);
1284 notifyOpChanged(callback, code, uid, packageName);
1285 }
1286 }
1287
1288 private void notifyOpChanged(ModeCallback callback, int code,
1289 int uid, String packageName) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001290 if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001291 return;
1292 }
1293 // There are components watching for mode changes such as window manager
1294 // and location manager which are in our process. The callbacks in these
1295 // components may require permissions our remote caller does not have.
1296 final long identity = Binder.clearCallingIdentity();
1297 try {
1298 callback.mCallback.opChanged(code, uid, packageName);
1299 } catch (RemoteException e) {
1300 /* ignore */
1301 } finally {
1302 Binder.restoreCallingIdentity(identity);
1303 }
1304 }
1305
1306 private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
1307 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
1308 int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001309 if (cbs == null) {
1310 return callbacks;
1311 }
1312 if (callbacks == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001313 callbacks = new HashMap<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001314 }
Svet Ganov2af57082015-07-30 08:44:20 -07001315 boolean duplicate = false;
Dianne Hackborn68d76552017-02-27 15:32:03 -08001316 final int N = cbs.size();
1317 for (int i=0; i<N; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001318 ModeCallback cb = cbs.valueAt(i);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001319 ArrayList<ChangeRec> reports = callbacks.get(cb);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001320 if (reports == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001321 reports = new ArrayList<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001322 callbacks.put(cb, reports);
Svet Ganov2af57082015-07-30 08:44:20 -07001323 } else {
1324 final int reportCount = reports.size();
1325 for (int j = 0; j < reportCount; j++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001326 ChangeRec report = reports.get(j);
1327 if (report.op == op && report.pkg.equals(packageName)) {
Svet Ganov2af57082015-07-30 08:44:20 -07001328 duplicate = true;
1329 break;
1330 }
1331 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001332 }
Svet Ganov2af57082015-07-30 08:44:20 -07001333 if (!duplicate) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001334 reports.add(new ChangeRec(op, uid, packageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001335 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001336 }
1337 return callbacks;
1338 }
1339
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001340 static final class ChangeRec {
1341 final int op;
1342 final int uid;
1343 final String pkg;
1344
1345 ChangeRec(int _op, int _uid, String _pkg) {
1346 op = _op;
1347 uid = _uid;
1348 pkg = _pkg;
1349 }
1350 }
1351
Dianne Hackborn607b4142013-08-02 18:10:10 -07001352 @Override
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001353 public void resetAllModes(int reqUserId, String reqPackageName) {
1354 final int callingPid = Binder.getCallingPid();
1355 final int callingUid = Binder.getCallingUid();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001356 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
1357 true, true, "resetAllModes", null);
Svet Ganov2af57082015-07-30 08:44:20 -07001358
1359 int reqUid = -1;
1360 if (reqPackageName != null) {
1361 try {
1362 reqUid = AppGlobals.getPackageManager().getPackageUid(
Jeff Sharkeycd654482016-01-08 17:42:11 -07001363 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
Svet Ganov2af57082015-07-30 08:44:20 -07001364 } catch (RemoteException e) {
1365 /* ignore - local call */
1366 }
1367 }
1368
Dianne Hackbornd5254412018-05-11 18:02:58 -07001369 enforceManageAppOpsModes(callingPid, callingUid, reqUid);
1370
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001371 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001372 synchronized (this) {
1373 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -07001374 for (int i = mUidStates.size() - 1; i >= 0; i--) {
1375 UidState uidState = mUidStates.valueAt(i);
1376
1377 SparseIntArray opModes = uidState.opModes;
1378 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
1379 final int uidOpCount = opModes.size();
1380 for (int j = uidOpCount - 1; j >= 0; j--) {
1381 final int code = opModes.keyAt(j);
1382 if (AppOpsManager.opAllowsReset(code)) {
1383 opModes.removeAt(j);
1384 if (opModes.size() <= 0) {
1385 uidState.opModes = null;
1386 }
1387 for (String packageName : getPackagesForUid(uidState.uid)) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001388 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001389 mOpModeWatchers.get(code));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001390 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001391 mPackageModeWatchers.get(packageName));
1392 }
1393 }
1394 }
1395 }
1396
1397 if (uidState.pkgOps == null) {
1398 continue;
1399 }
1400
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001401 if (reqUserId != UserHandle.USER_ALL
Svet Ganov2af57082015-07-30 08:44:20 -07001402 && reqUserId != UserHandle.getUserId(uidState.uid)) {
Alexandra Gherghinad6a98972014-08-04 17:05:34 +01001403 // Skip any ops for a different user
1404 continue;
1405 }
Svet Ganov2af57082015-07-30 08:44:20 -07001406
1407 Map<String, Ops> packages = uidState.pkgOps;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001408 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001409 boolean uidChanged = false;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001410 while (it.hasNext()) {
1411 Map.Entry<String, Ops> ent = it.next();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001412 String packageName = ent.getKey();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001413 if (reqPackageName != null && !reqPackageName.equals(packageName)) {
1414 // Skip any ops for a different package
1415 continue;
1416 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001417 Ops pkgOps = ent.getValue();
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001418 for (int j=pkgOps.size()-1; j>=0; j--) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001419 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn8828d3a2013-09-25 16:47:10 -07001420 if (AppOpsManager.opAllowsReset(curOp.op)
1421 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
David Braunf5d83192013-09-16 13:43:51 -07001422 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001423 changed = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001424 uidChanged = true;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001425 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001426 mOpModeWatchers.get(curOp.op));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001427 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001428 mPackageModeWatchers.get(packageName));
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001429 if (!curOp.hasAnyTime()) {
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001430 pkgOps.removeAt(j);
1431 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001432 }
1433 }
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001434 if (pkgOps.size() == 0) {
1435 it.remove();
1436 }
1437 }
Svet Ganov2af57082015-07-30 08:44:20 -07001438 if (uidState.isDefault()) {
1439 mUidStates.remove(uidState.uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001440 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001441 if (uidChanged) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001442 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001443 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001444 }
Svet Ganov2af57082015-07-30 08:44:20 -07001445
Dianne Hackborn607b4142013-08-02 18:10:10 -07001446 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001447 scheduleFastWriteLocked();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001448 }
1449 }
1450 if (callbacks != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001451 for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
1452 ModeCallback cb = ent.getKey();
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001453 ArrayList<ChangeRec> reports = ent.getValue();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001454 for (int i=0; i<reports.size(); i++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001455 ChangeRec rep = reports.get(i);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001456 mHandler.sendMessage(PooledLambda.obtainMessage(
1457 AppOpsService::notifyOpChanged,
1458 this, cb, rep.op, rep.uid, rep.pkg));
Dianne Hackborn607b4142013-08-02 18:10:10 -07001459 }
1460 }
1461 }
1462 }
1463
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001464 private void evalAllForegroundOpsLocked() {
1465 for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
1466 final UidState uidState = mUidStates.valueAt(uidi);
1467 if (uidState.foregroundOps != null) {
1468 uidState.evalForegroundOps(mOpModeWatchers);
1469 }
1470 }
1471 }
1472
Dianne Hackbornc2293022013-02-06 23:14:49 -08001473 @Override
1474 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001475 startWatchingModeWithFlags(op, packageName, 0, callback);
1476 }
1477
1478 @Override
1479 public void startWatchingModeWithFlags(int op, String packageName, int flags,
1480 IAppOpsCallback callback) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001481 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001482 final int callingUid = Binder.getCallingUid();
1483 final int callingPid = Binder.getCallingPid();
Dianne Hackborn5376edd2018-06-05 13:21:16 -07001484 // TODO: should have a privileged permission to protect this.
1485 // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require
1486 // the USAGE_STATS permission since this can provide information about when an
1487 // app is in the foreground?
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001488 Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
1489 AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001490 if (callback == null) {
1491 return;
1492 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001493 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001494 op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001495 ModeCallback cb = mModeWatchers.get(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001496 if (cb == null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001497 cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001498 mModeWatchers.put(callback.asBinder(), cb);
1499 }
1500 if (op != AppOpsManager.OP_NONE) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001501 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001502 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001503 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001504 mOpModeWatchers.put(op, cbs);
1505 }
1506 cbs.add(cb);
1507 }
1508 if (packageName != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001509 ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001510 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001511 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001512 mPackageModeWatchers.put(packageName, cbs);
1513 }
1514 cbs.add(cb);
1515 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001516 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001517 }
1518 }
1519
1520 @Override
1521 public void stopWatchingMode(IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001522 if (callback == null) {
1523 return;
1524 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001525 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001526 ModeCallback cb = mModeWatchers.remove(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001527 if (cb != null) {
1528 cb.unlinkToDeath();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001529 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001530 ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001531 cbs.remove(cb);
1532 if (cbs.size() <= 0) {
1533 mOpModeWatchers.removeAt(i);
1534 }
1535 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001536 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001537 ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001538 cbs.remove(cb);
1539 if (cbs.size() <= 0) {
1540 mPackageModeWatchers.removeAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001541 }
1542 }
1543 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001544 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001545 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001546 }
1547
1548 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001549 public IBinder getToken(IBinder clientToken) {
1550 synchronized (this) {
1551 ClientState cs = mClients.get(clientToken);
1552 if (cs == null) {
1553 cs = new ClientState(clientToken);
1554 mClients.put(clientToken, cs);
1555 }
1556 return cs;
1557 }
1558 }
1559
Svet Ganovd873ae62018-06-25 16:39:23 -07001560 public CheckOpsDelegate getAppOpsServiceDelegate() {
1561 synchronized (this) {
1562 return mCheckOpsDelegate;
1563 }
1564 }
1565
1566 public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) {
1567 synchronized (this) {
1568 mCheckOpsDelegate = delegate;
1569 }
1570 }
1571
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001572 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -08001573 public int checkOperation(int code, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001574 final CheckOpsDelegate delegate;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001575 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001576 if (mCheckOpsDelegate == null) {
1577 return checkOperationImpl(code, uid, packageName);
1578 }
1579 delegate = mCheckOpsDelegate;
1580 }
1581 return delegate.checkOperation(code, uid, packageName,
1582 AppOpsService.this::checkOperationImpl);
1583 }
1584
1585 private int checkOperationImpl(int code, int uid, String packageName) {
1586 synchronized (this) {
1587 verifyIncomingUid(uid);
1588 verifyIncomingOp(code);
1589 String resolvedPackageName = resolvePackageName(uid, packageName);
1590 if (resolvedPackageName == null) {
1591 return AppOpsManager.MODE_IGNORED;
1592 }
Svet Ganov442ed572016-08-17 17:29:43 -07001593 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001594 return AppOpsManager.MODE_IGNORED;
1595 }
Svet Ganov2af57082015-07-30 08:44:20 -07001596 code = AppOpsManager.opToSwitch(code);
1597 UidState uidState = getUidStateLocked(uid, false);
Svet Ganovee438d42017-01-19 18:04:38 -08001598 if (uidState != null && uidState.opModes != null
1599 && uidState.opModes.indexOfKey(code) >= 0) {
1600 return uidState.opModes.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001601 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001602 Op op = getOpLocked(code, uid, resolvedPackageName, false);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001603 if (op == null) {
David Braunf5d83192013-09-16 13:43:51 -07001604 return AppOpsManager.opToDefaultMode(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001605 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001606 return op.mode;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001607 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001608 }
1609
1610 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001611 public int checkAudioOperation(int code, int usage, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001612 final CheckOpsDelegate delegate;
John Spurlock1af30c72014-03-10 08:33:35 -04001613 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001614 if (mCheckOpsDelegate == null) {
1615 return checkAudioOperationImpl(code, usage, uid, packageName);
1616 }
1617 delegate = mCheckOpsDelegate;
1618 }
1619 return delegate.checkAudioOperation(code, usage, uid, packageName,
1620 AppOpsService.this::checkAudioOperationImpl);
1621 }
1622
1623 private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
1624 synchronized (this) {
1625 boolean suspended;
1626 try {
1627 suspended = isPackageSuspendedForUser(packageName, uid);
1628 } catch (IllegalArgumentException ex) {
1629 // Package not found.
1630 suspended = false;
1631 }
1632
1633 if (suspended) {
1634 Slog.i(TAG, "Audio disabled for suspended package=" + packageName
1635 + " for uid=" + uid);
1636 return AppOpsManager.MODE_IGNORED;
1637 }
1638
John Spurlock7b414672014-07-18 13:02:39 -04001639 final int mode = checkRestrictionLocked(code, usage, uid, packageName);
John Spurlock1af30c72014-03-10 08:33:35 -04001640 if (mode != AppOpsManager.MODE_ALLOWED) {
1641 return mode;
1642 }
1643 }
1644 return checkOperation(code, uid, packageName);
1645 }
1646
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001647 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001648 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001649 return AppGlobals.getPackageManager().isPackageSuspendedForUser(
1650 pkg, UserHandle.getUserId(uid));
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001651 } catch (RemoteException re) {
1652 throw new SecurityException("Could not talk to package manager service");
1653 }
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001654 }
1655
John Spurlock7b414672014-07-18 13:02:39 -04001656 private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
1657 final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1658 if (usageRestrictions != null) {
1659 final Restriction r = usageRestrictions.get(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001660 if (r != null && !r.exceptionPackages.contains(packageName)) {
1661 return r.mode;
1662 }
1663 }
1664 return AppOpsManager.MODE_ALLOWED;
1665 }
1666
1667 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001668 public void setAudioRestriction(int code, int usage, int uid, int mode,
John Spurlock1af30c72014-03-10 08:33:35 -04001669 String[] exceptionPackages) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001670 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
John Spurlock1af30c72014-03-10 08:33:35 -04001671 verifyIncomingUid(uid);
1672 verifyIncomingOp(code);
1673 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001674 SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1675 if (usageRestrictions == null) {
1676 usageRestrictions = new SparseArray<Restriction>();
1677 mAudioRestrictions.put(code, usageRestrictions);
John Spurlock1af30c72014-03-10 08:33:35 -04001678 }
John Spurlock7b414672014-07-18 13:02:39 -04001679 usageRestrictions.remove(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001680 if (mode != AppOpsManager.MODE_ALLOWED) {
1681 final Restriction r = new Restriction();
1682 r.mode = mode;
1683 if (exceptionPackages != null) {
1684 final int N = exceptionPackages.length;
1685 r.exceptionPackages = new ArraySet<String>(N);
1686 for (int i = 0; i < N; i++) {
1687 final String pkg = exceptionPackages[i];
1688 if (pkg != null) {
1689 r.exceptionPackages.add(pkg.trim());
1690 }
1691 }
1692 }
John Spurlock7b414672014-07-18 13:02:39 -04001693 usageRestrictions.put(usage, r);
John Spurlock1af30c72014-03-10 08:33:35 -04001694 }
1695 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001696
1697 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07001698 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
John Spurlock1af30c72014-03-10 08:33:35 -04001699 }
1700
1701 @Override
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001702 public int checkPackage(int uid, String packageName) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001703 Preconditions.checkNotNull(packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001704 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001705 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
1706 true /* uidMismatchExpected */);
1707 if (ops != null) {
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001708 return AppOpsManager.MODE_ALLOWED;
1709 } else {
1710 return AppOpsManager.MODE_ERRORED;
1711 }
1712 }
1713 }
1714
1715 @Override
Svet Ganovd873ae62018-06-25 16:39:23 -07001716 public int noteProxyOperation(int code, int proxyUid,
1717 String proxyPackageName, int proxiedUid, String proxiedPackageName) {
1718 verifyIncomingUid(proxyUid);
Svet Ganov99b60432015-06-27 13:15:22 -07001719 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001720 String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
1721 if (resolveProxyPackageName == null) {
1722 return AppOpsManager.MODE_IGNORED;
1723 }
1724 final int proxyMode = noteOperationUnchecked(code, proxyUid,
1725 resolveProxyPackageName, -1, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001726 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
1727 return proxyMode;
1728 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001729 String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
1730 if (resolveProxiedPackageName == null) {
1731 return AppOpsManager.MODE_IGNORED;
1732 }
1733 return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
1734 proxyMode, resolveProxyPackageName);
Svet Ganov99b60432015-06-27 13:15:22 -07001735 }
1736
1737 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001738 public int noteOperation(int code, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001739 final CheckOpsDelegate delegate;
1740 synchronized (this) {
1741 if (mCheckOpsDelegate == null) {
1742 return noteOperationImpl(code, uid, packageName);
1743 }
1744 delegate = mCheckOpsDelegate;
1745 }
1746 return delegate.noteOperation(code, uid, packageName,
1747 AppOpsService.this::noteOperationImpl);
1748 }
1749
1750 private int noteOperationImpl(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001751 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001752 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001753 String resolvedPackageName = resolvePackageName(uid, packageName);
1754 if (resolvedPackageName == null) {
1755 return AppOpsManager.MODE_IGNORED;
1756 }
1757 return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001758 }
1759
1760 private int noteOperationUnchecked(int code, int uid, String packageName,
1761 int proxyUid, String proxyPackageName) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001762 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001763 final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001764 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001765 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001766 if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001767 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001768 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001769 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001770 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001771 if (isOpRestrictedLocked(uid, code, packageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001772 return AppOpsManager.MODE_IGNORED;
1773 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001774 final UidState uidState = ops.uidState;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001775 if (op.duration == -1) {
1776 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001777 + " code " + code + " time=" + op.time[uidState.state]
1778 + " duration=" + op.duration);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001779 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001780 op.duration = 0;
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001781 final int switchCode = AppOpsManager.opToSwitch(code);
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001782 // If there is a non-default per UID policy (we set UID op mode only if
1783 // non-default) it takes over, otherwise use the per package policy.
1784 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001785 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganov2af57082015-07-30 08:44:20 -07001786 if (uidMode != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001787 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001788 + switchCode + " (" + code + ") uid " + uid + " package "
1789 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001790 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov2af57082015-07-30 08:44:20 -07001791 return uidMode;
1792 }
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001793 } else {
1794 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001795 final int mode = switchOp.getMode();
1796 if (mode != AppOpsManager.MODE_ALLOWED) {
1797 if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001798 + switchCode + " (" + code + ") uid " + uid + " package "
1799 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001800 op.rejectTime[uidState.state] = System.currentTimeMillis();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001801 return mode;
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001802 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001803 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001804 if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001805 + " package " + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001806 op.time[uidState.state] = System.currentTimeMillis();
1807 op.rejectTime[uidState.state] = 0;
Svet Ganov99b60432015-06-27 13:15:22 -07001808 op.proxyUid = proxyUid;
1809 op.proxyPackageName = proxyPackageName;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001810 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001811 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001812 }
1813
1814 @Override
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001815 public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001816 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001817 final int callingUid = Binder.getCallingUid();
1818 final int callingPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -08001819 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1820 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001821 watchedUid = callingUid;
Svet Ganovf7b47252018-02-26 11:11:27 -08001822 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001823 if (ops != null) {
1824 Preconditions.checkArrayElementsInRange(ops, 0,
1825 AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
1826 }
1827 if (callback == null) {
1828 return;
1829 }
1830 synchronized (this) {
1831 SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
1832 if (callbacks == null) {
1833 callbacks = new SparseArray<>();
1834 mActiveWatchers.put(callback.asBinder(), callbacks);
1835 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001836 final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
1837 callingUid, callingPid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001838 for (int op : ops) {
1839 callbacks.put(op, activeCallback);
1840 }
1841 }
1842 }
1843
1844 @Override
1845 public void stopWatchingActive(IAppOpsActiveCallback callback) {
1846 if (callback == null) {
1847 return;
1848 }
1849 synchronized (this) {
1850 final SparseArray<ActiveCallback> activeCallbacks =
1851 mActiveWatchers.remove(callback.asBinder());
1852 if (activeCallbacks == null) {
1853 return;
1854 }
1855 final int callbackCount = activeCallbacks.size();
1856 for (int i = 0; i < callbackCount; i++) {
1857 // Apps ops are mapped to a singleton
1858 if (i == 0) {
1859 activeCallbacks.valueAt(i).destroy();
1860 }
1861 }
1862 }
1863 }
1864
1865 @Override
Svet Ganovf7b47252018-02-26 11:11:27 -08001866 public int startOperation(IBinder token, int code, int uid, String packageName,
1867 boolean startIfModeDefault) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001868 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001869 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001870 String resolvedPackageName = resolvePackageName(uid, packageName);
1871 if (resolvedPackageName == null) {
1872 return AppOpsManager.MODE_IGNORED;
1873 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001874 ClientState client = (ClientState)token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001875 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001876 final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001877 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001878 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001879 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001880 + " package " + resolvedPackageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001881 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001882 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001883 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001884 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001885 return AppOpsManager.MODE_IGNORED;
1886 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001887 final int switchCode = AppOpsManager.opToSwitch(code);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001888 final UidState uidState = ops.uidState;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001889 // If there is a non-default per UID policy (we set UID op mode only if
1890 // non-default) it takes over, otherwise use the per package policy.
1891 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001892 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganovf7b47252018-02-26 11:11:27 -08001893 if (uidMode != AppOpsManager.MODE_ALLOWED
1894 && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001895 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001896 + switchCode + " (" + code + ") uid " + uid + " package "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001897 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001898 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov2af57082015-07-30 08:44:20 -07001899 return uidMode;
1900 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001901 } else {
1902 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001903 final int mode = switchOp.getMode();
1904 if (mode != AppOpsManager.MODE_ALLOWED
1905 && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
1906 if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001907 + switchCode + " (" + code + ") uid " + uid + " package "
1908 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001909 op.rejectTime[uidState.state] = System.currentTimeMillis();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001910 return mode;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001911 }
Svet Ganov2af57082015-07-30 08:44:20 -07001912 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001913 if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001914 + " package " + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001915 if (op.startNesting == 0) {
1916 op.startRealtime = SystemClock.elapsedRealtime();
1917 op.time[uidState.state] = System.currentTimeMillis();
1918 op.rejectTime[uidState.state] = 0;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001919 op.duration = -1;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001920 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001921 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001922 op.startNesting++;
1923 uidState.startNesting++;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001924 if (client.mStartedOps != null) {
1925 client.mStartedOps.add(op);
1926 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001927 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001928
1929 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001930 }
1931
1932 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001933 public void finishOperation(IBinder token, int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001934 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001935 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001936 String resolvedPackageName = resolvePackageName(uid, packageName);
1937 if (resolvedPackageName == null) {
1938 return;
1939 }
1940 if (!(token instanceof ClientState)) {
1941 return;
1942 }
1943 ClientState client = (ClientState) token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001944 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001945 Op op = getOpLocked(code, uid, resolvedPackageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001946 if (op == null) {
1947 return;
1948 }
Svet Ganovf7b47252018-02-26 11:11:27 -08001949 if (!client.mStartedOps.remove(op)) {
Svet Ganovf5d5af12018-03-18 11:51:17 -07001950 // We finish ops when packages get removed to guarantee no dangling
1951 // started ops. However, some part of the system may asynchronously
1952 // finish ops for an already gone package. Hence, finishing an op
1953 // for a non existing package is fine and we don't log as a wtf.
1954 final long identity = Binder.clearCallingIdentity();
1955 try {
1956 if (LocalServices.getService(PackageManagerInternal.class).getPackageUid(
1957 resolvedPackageName, 0, UserHandle.getUserId(uid)) < 0) {
1958 Slog.i(TAG, "Finishing op=" + AppOpsManager.opToName(code)
1959 + " for non-existing package=" + resolvedPackageName
1960 + " in uid=" + uid);
1961 return;
1962 }
1963 } finally {
1964 Binder.restoreCallingIdentity(identity);
1965 }
1966 Slog.wtf(TAG, "Operation not started: uid=" + op.uid + " pkg="
1967 + op.packageName + " op=" + AppOpsManager.opToName(op.op));
Svet Ganov31d83ae2018-03-15 10:45:56 -07001968 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001969 }
Svet Ganova7a0db62018-02-27 20:08:01 -08001970 finishOperationLocked(op, /*finishNested*/ false);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001971 if (op.startNesting <= 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001972 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
1973 }
1974 }
1975 }
1976
1977 private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
1978 boolean active) {
1979 ArraySet<ActiveCallback> dispatchedCallbacks = null;
1980 final int callbackListCount = mActiveWatchers.size();
1981 for (int i = 0; i < callbackListCount; i++) {
1982 final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
1983 ActiveCallback callback = callbacks.get(code);
1984 if (callback != null) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001985 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001986 continue;
1987 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001988 if (dispatchedCallbacks == null) {
1989 dispatchedCallbacks = new ArraySet<>();
1990 }
1991 dispatchedCallbacks.add(callback);
1992 }
1993 }
1994 if (dispatchedCallbacks == null) {
1995 return;
1996 }
1997 mHandler.sendMessage(PooledLambda.obtainMessage(
1998 AppOpsService::notifyOpActiveChanged,
1999 this, dispatchedCallbacks, code, uid, packageName, active));
2000 }
2001
2002 private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
2003 int code, int uid, String packageName, boolean active) {
2004 // There are components watching for mode changes such as window manager
2005 // and location manager which are in our process. The callbacks in these
2006 // components may require permissions our remote caller does not have.
2007 final long identity = Binder.clearCallingIdentity();
2008 try {
2009 final int callbackCount = callbacks.size();
2010 for (int i = 0; i < callbackCount; i++) {
2011 final ActiveCallback callback = callbacks.valueAt(i);
2012 try {
2013 callback.mCallback.opActiveChanged(code, uid, packageName, active);
2014 } catch (RemoteException e) {
2015 /* do nothing */
2016 }
2017 }
2018 } finally {
2019 Binder.restoreCallingIdentity(identity);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002020 }
2021 }
2022
Svet Ganovb9d71a62015-04-30 10:38:13 -07002023 @Override
2024 public int permissionToOpCode(String permission) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002025 if (permission == null) {
2026 return AppOpsManager.OP_NONE;
2027 }
Svet Ganovb9d71a62015-04-30 10:38:13 -07002028 return AppOpsManager.permissionToOpCode(permission);
2029 }
2030
Svet Ganova7a0db62018-02-27 20:08:01 -08002031 void finishOperationLocked(Op op, boolean finishNested) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002032 if (op.startNesting <= 1 || finishNested) {
2033 if (op.startNesting == 1 || finishNested) {
2034 op.duration = (int)(SystemClock.elapsedRealtime() - op.startRealtime);
2035 op.time[op.uidState.state] = System.currentTimeMillis();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002036 } else {
2037 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
2038 + op.packageName + " code " + op.op + " time=" + op.time
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002039 + " duration=" + op.duration + " nesting=" + op.startNesting);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002040 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002041 if (op.startNesting >= 1) {
2042 op.uidState.startNesting -= op.startNesting;
2043 }
2044 op.startNesting = 0;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002045 } else {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002046 op.startNesting--;
2047 op.uidState.startNesting--;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002048 }
2049 }
2050
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002051 private void verifyIncomingUid(int uid) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002052 if (uid == Binder.getCallingUid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002053 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002054 }
2055 if (Binder.getCallingPid() == Process.myPid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002056 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002057 }
2058 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
2059 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002060 }
2061
Dianne Hackborn961321f2013-02-05 17:22:41 -08002062 private void verifyIncomingOp(int op) {
2063 if (op >= 0 && op < AppOpsManager._NUM_OP) {
2064 return;
2065 }
2066 throw new IllegalArgumentException("Bad operation #" + op);
2067 }
2068
Svet Ganov2af57082015-07-30 08:44:20 -07002069 private UidState getUidStateLocked(int uid, boolean edit) {
2070 UidState uidState = mUidStates.get(uid);
2071 if (uidState == null) {
2072 if (!edit) {
2073 return null;
2074 }
2075 uidState = new UidState(uid);
2076 mUidStates.put(uid, uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002077 } else {
2078 if (uidState.pendingStateCommitTime != 0) {
Dianne Hackborn9fb93502018-06-18 12:29:44 -07002079 if (uidState.pendingStateCommitTime < mLastRealtime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002080 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002081 } else {
Dianne Hackborn9fb93502018-06-18 12:29:44 -07002082 mLastRealtime = SystemClock.elapsedRealtime();
2083 if (uidState.pendingStateCommitTime < mLastRealtime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002084 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002085 }
2086 }
2087 }
Svet Ganov2af57082015-07-30 08:44:20 -07002088 }
2089 return uidState;
2090 }
2091
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002092 private void commitUidPendingStateLocked(UidState uidState) {
Dianne Hackborne93ab412018-05-14 17:52:30 -07002093 final boolean lastForeground = uidState.state <= UID_STATE_LAST_NON_RESTRICTED;
2094 final boolean nowForeground = uidState.pendingState <= UID_STATE_LAST_NON_RESTRICTED;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002095 uidState.state = uidState.pendingState;
2096 uidState.pendingStateCommitTime = 0;
Dianne Hackborne93ab412018-05-14 17:52:30 -07002097 if (uidState.hasForegroundWatchers && lastForeground != nowForeground) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002098 for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
2099 if (!uidState.foregroundOps.valueAt(fgi)) {
2100 continue;
2101 }
2102 final int code = uidState.foregroundOps.keyAt(fgi);
2103
2104 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
2105 if (callbacks != null) {
2106 for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
2107 final ModeCallback callback = callbacks.valueAt(cbi);
2108 if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
2109 || !callback.isWatchingUid(uidState.uid)) {
2110 continue;
2111 }
2112 boolean doAllPackages = uidState.opModes != null
Hai Zhang2b98fb32018-09-21 15:18:46 -07002113 && uidState.opModes.indexOfKey(code) >= 0
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002114 && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
2115 if (uidState.pkgOps != null) {
2116 for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
2117 final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
2118 if (doAllPackages || (op != null
2119 && op.mode == AppOpsManager.MODE_FOREGROUND)) {
2120 mHandler.sendMessage(PooledLambda.obtainMessage(
2121 AppOpsService::notifyOpChanged,
2122 this, callback, code, uidState.uid,
2123 uidState.pkgOps.keyAt(pkgi)));
2124 }
2125 }
2126 }
2127 }
2128 }
2129 }
2130 }
2131 }
2132
Yohei Yukawaa965d652017-10-12 15:02:26 -07002133 private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
2134 boolean uidMismatchExpected) {
Svet Ganov2af57082015-07-30 08:44:20 -07002135 UidState uidState = getUidStateLocked(uid, edit);
2136 if (uidState == null) {
2137 return null;
2138 }
2139
2140 if (uidState.pkgOps == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002141 if (!edit) {
2142 return null;
2143 }
Svet Ganov2af57082015-07-30 08:44:20 -07002144 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002145 }
Svet Ganov2af57082015-07-30 08:44:20 -07002146
2147 Ops ops = uidState.pkgOps.get(packageName);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002148 if (ops == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002149 if (!edit) {
2150 return null;
2151 }
Jason Monk1c7c3192014-06-26 12:52:18 -04002152 boolean isPrivileged = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002153 // This is the first time we have seen this package name under this uid,
2154 // so let's make sure it is valid.
Dianne Hackborn514074f2013-02-11 10:52:46 -08002155 if (uid != 0) {
2156 final long ident = Binder.clearCallingIdentity();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002157 try {
Dianne Hackborn514074f2013-02-11 10:52:46 -08002158 int pkgUid = -1;
2159 try {
Jason Monk1c7c3192014-06-26 12:52:18 -04002160 ApplicationInfo appInfo = ActivityThread.getPackageManager()
Jeff Sharkeycd654482016-01-08 17:42:11 -07002161 .getApplicationInfo(packageName,
Svet Ganovad0a49b2018-10-29 10:07:08 -07002162 PackageManager.MATCH_DIRECT_BOOT_AWARE
2163 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
Jeff Sharkeycd654482016-01-08 17:42:11 -07002164 UserHandle.getUserId(uid));
Jason Monk1c7c3192014-06-26 12:52:18 -04002165 if (appInfo != null) {
2166 pkgUid = appInfo.uid;
Alex Klyubinb9f8a522015-02-03 11:12:59 -08002167 isPrivileged = (appInfo.privateFlags
2168 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04002169 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08002170 pkgUid = resolveUid(packageName);
2171 if (pkgUid >= 0) {
Chien-Yu Chen75cade02016-01-11 10:56:21 -08002172 isPrivileged = false;
Jason Monk1c7c3192014-06-26 12:52:18 -04002173 }
Dianne Hackborn713df152013-05-17 11:27:57 -07002174 }
Jason Monk1c7c3192014-06-26 12:52:18 -04002175 } catch (RemoteException e) {
2176 Slog.w(TAG, "Could not contact PackageManager", e);
Dianne Hackborn514074f2013-02-11 10:52:46 -08002177 }
2178 if (pkgUid != uid) {
2179 // Oops! The package name is not valid for the uid they are calling
2180 // under. Abort.
Yohei Yukawaa965d652017-10-12 15:02:26 -07002181 if (!uidMismatchExpected) {
2182 RuntimeException ex = new RuntimeException("here");
2183 ex.fillInStackTrace();
2184 Slog.w(TAG, "Bad call: specified package " + packageName
2185 + " under uid " + uid + " but it is really " + pkgUid, ex);
2186 }
Dianne Hackborn514074f2013-02-11 10:52:46 -08002187 return null;
2188 }
2189 } finally {
2190 Binder.restoreCallingIdentity(ident);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002191 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002192 }
Svet Ganov2af57082015-07-30 08:44:20 -07002193 ops = new Ops(packageName, uidState, isPrivileged);
2194 uidState.pkgOps.put(packageName, ops);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002195 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08002196 return ops;
2197 }
2198
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002199 private void scheduleWriteLocked() {
2200 if (!mWriteScheduled) {
2201 mWriteScheduled = true;
2202 mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
2203 }
2204 }
2205
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002206 private void scheduleFastWriteLocked() {
2207 if (!mFastWriteScheduled) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002208 mWriteScheduled = true;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002209 mFastWriteScheduled = true;
2210 mHandler.removeCallbacks(mWriteRunner);
2211 mHandler.postDelayed(mWriteRunner, 10*1000);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002212 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002213 }
2214
Dianne Hackborn72e39832013-01-18 18:36:09 -08002215 private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002216 Ops ops = getOpsRawLocked(uid, packageName, edit,
2217 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -08002218 if (ops == null) {
2219 return null;
2220 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002221 return getOpLocked(ops, code, edit);
2222 }
2223
2224 private Op getOpLocked(Ops ops, int code, boolean edit) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002225 Op op = ops.get(code);
2226 if (op == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002227 if (!edit) {
2228 return null;
2229 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002230 op = new Op(ops.uidState, ops.packageName, code);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002231 ops.put(code, op);
2232 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002233 if (edit) {
2234 scheduleWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002235 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002236 return op;
2237 }
2238
Svet Ganov442ed572016-08-17 17:29:43 -07002239 private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
Jason Monk62062992014-05-06 09:55:28 -04002240 int userHandle = UserHandle.getUserId(uid);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002241 final int restrictionSetCount = mOpUserRestrictions.size();
Ruben Brunk29931bc2016-03-11 00:24:26 -08002242
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002243 for (int i = 0; i < restrictionSetCount; i++) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08002244 // For each client, check that the given op is not restricted, or that the given
2245 // package is exempt from the restriction.
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002246 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07002247 if (restrictionState.hasRestriction(code, packageName, userHandle)) {
2248 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
2249 // If we are the system, bypass user restrictions for certain codes
2250 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002251 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
2252 false /* uidMismatchExpected */);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07002253 if ((ops != null) && ops.isPrivileged) {
2254 return false;
2255 }
Ruben Brunk32f0fa42016-03-11 19:07:07 -08002256 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08002257 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002258 return true;
Jason Monk1c7c3192014-06-26 12:52:18 -04002259 }
Jason Monk62062992014-05-06 09:55:28 -04002260 }
2261 return false;
2262 }
2263
Dianne Hackborn35654b62013-01-14 17:38:02 -08002264 void readState() {
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002265 int oldVersion = NO_VERSION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08002266 synchronized (mFile) {
2267 synchronized (this) {
2268 FileInputStream stream;
2269 try {
2270 stream = mFile.openRead();
2271 } catch (FileNotFoundException e) {
2272 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
2273 return;
2274 }
2275 boolean success = false;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002276 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002277 try {
2278 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002279 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002280 int type;
2281 while ((type = parser.next()) != XmlPullParser.START_TAG
2282 && type != XmlPullParser.END_DOCUMENT) {
2283 ;
2284 }
2285
2286 if (type != XmlPullParser.START_TAG) {
2287 throw new IllegalStateException("no start tag found");
2288 }
2289
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002290 final String versionString = parser.getAttributeValue(null, "v");
2291 if (versionString != null) {
2292 oldVersion = Integer.parseInt(versionString);
2293 }
2294
Dianne Hackborn35654b62013-01-14 17:38:02 -08002295 int outerDepth = parser.getDepth();
2296 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2297 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2298 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2299 continue;
2300 }
2301
2302 String tagName = parser.getName();
2303 if (tagName.equals("pkg")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002304 readPackage(parser);
Svetoslav215b44a2015-08-04 19:03:40 -07002305 } else if (tagName.equals("uid")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002306 readUidOps(parser);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002307 } else {
2308 Slog.w(TAG, "Unknown element under <app-ops>: "
2309 + parser.getName());
2310 XmlUtils.skipCurrentTag(parser);
2311 }
2312 }
2313 success = true;
2314 } catch (IllegalStateException e) {
2315 Slog.w(TAG, "Failed parsing " + e);
2316 } catch (NullPointerException e) {
2317 Slog.w(TAG, "Failed parsing " + e);
2318 } catch (NumberFormatException e) {
2319 Slog.w(TAG, "Failed parsing " + e);
2320 } catch (XmlPullParserException e) {
2321 Slog.w(TAG, "Failed parsing " + e);
2322 } catch (IOException e) {
2323 Slog.w(TAG, "Failed parsing " + e);
2324 } catch (IndexOutOfBoundsException e) {
2325 Slog.w(TAG, "Failed parsing " + e);
2326 } finally {
2327 if (!success) {
Svet Ganov2af57082015-07-30 08:44:20 -07002328 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002329 }
2330 try {
2331 stream.close();
2332 } catch (IOException e) {
2333 }
2334 }
2335 }
2336 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002337 synchronized (this) {
2338 upgradeLocked(oldVersion);
2339 }
2340 }
2341
2342 private void upgradeRunAnyInBackgroundLocked() {
2343 for (int i = 0; i < mUidStates.size(); i++) {
2344 final UidState uidState = mUidStates.valueAt(i);
2345 if (uidState == null) {
2346 continue;
2347 }
2348 if (uidState.opModes != null) {
2349 final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
2350 if (idx >= 0) {
2351 uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
2352 uidState.opModes.valueAt(idx));
2353 }
2354 }
2355 if (uidState.pkgOps == null) {
2356 continue;
2357 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002358 boolean changed = false;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002359 for (int j = 0; j < uidState.pkgOps.size(); j++) {
2360 Ops ops = uidState.pkgOps.valueAt(j);
2361 if (ops != null) {
2362 final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
2363 if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002364 final Op copy = new Op(op.uidState, op.packageName,
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002365 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
2366 copy.mode = op.mode;
2367 ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002368 changed = true;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002369 }
2370 }
2371 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002372 if (changed) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002373 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002374 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002375 }
2376 }
2377
2378 private void upgradeLocked(int oldVersion) {
2379 if (oldVersion >= CURRENT_VERSION) {
2380 return;
2381 }
2382 Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
2383 switch (oldVersion) {
2384 case NO_VERSION:
2385 upgradeRunAnyInBackgroundLocked();
2386 // fall through
2387 case 1:
2388 // for future upgrades
2389 }
2390 scheduleFastWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002391 }
2392
Svet Ganov2af57082015-07-30 08:44:20 -07002393 void readUidOps(XmlPullParser parser) throws NumberFormatException,
2394 XmlPullParserException, IOException {
2395 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
2396 int outerDepth = parser.getDepth();
2397 int type;
2398 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2399 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2400 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2401 continue;
2402 }
2403
2404 String tagName = parser.getName();
2405 if (tagName.equals("op")) {
2406 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
2407 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
2408 UidState uidState = getUidStateLocked(uid, true);
2409 if (uidState.opModes == null) {
2410 uidState.opModes = new SparseIntArray();
2411 }
2412 uidState.opModes.put(code, mode);
2413 } else {
2414 Slog.w(TAG, "Unknown element under <uid-ops>: "
2415 + parser.getName());
2416 XmlUtils.skipCurrentTag(parser);
2417 }
2418 }
2419 }
2420
Dave Burke0997c5bd2013-08-02 20:25:02 +00002421 void readPackage(XmlPullParser parser) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002422 XmlPullParserException, IOException {
2423 String pkgName = parser.getAttributeValue(null, "n");
2424 int outerDepth = parser.getDepth();
2425 int type;
2426 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2427 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2428 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2429 continue;
2430 }
2431
2432 String tagName = parser.getName();
2433 if (tagName.equals("uid")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002434 readUid(parser, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002435 } else {
2436 Slog.w(TAG, "Unknown element under <pkg>: "
2437 + parser.getName());
2438 XmlUtils.skipCurrentTag(parser);
2439 }
2440 }
2441 }
2442
Dave Burke0997c5bd2013-08-02 20:25:02 +00002443 void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002444 XmlPullParserException, IOException {
2445 int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
Jason Monk1c7c3192014-06-26 12:52:18 -04002446 String isPrivilegedString = parser.getAttributeValue(null, "p");
2447 boolean isPrivileged = false;
2448 if (isPrivilegedString == null) {
2449 try {
2450 IPackageManager packageManager = ActivityThread.getPackageManager();
2451 if (packageManager != null) {
2452 ApplicationInfo appInfo = ActivityThread.getPackageManager()
2453 .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
2454 if (appInfo != null) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08002455 isPrivileged = (appInfo.privateFlags
2456 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04002457 }
2458 } else {
2459 // Could not load data, don't add to cache so it will be loaded later.
2460 return;
2461 }
2462 } catch (RemoteException e) {
2463 Slog.w(TAG, "Could not contact PackageManager", e);
2464 }
2465 } else {
2466 isPrivileged = Boolean.parseBoolean(isPrivilegedString);
2467 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002468 int outerDepth = parser.getDepth();
2469 int type;
2470 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2471 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2472 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2473 continue;
2474 }
2475
2476 String tagName = parser.getName();
2477 if (tagName.equals("op")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002478 UidState uidState = getUidStateLocked(uid, true);
2479 if (uidState.pkgOps == null) {
2480 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002481 }
Svet Ganov2af57082015-07-30 08:44:20 -07002482
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002483 Op op = new Op(uidState, pkgName,
2484 Integer.parseInt(parser.getAttributeValue(null, "n")));
2485
2486 for (int i = parser.getAttributeCount()-1; i >= 0; i--) {
2487 final String name = parser.getAttributeName(i);
2488 final String value = parser.getAttributeValue(i);
2489 switch (name) {
2490 case "m":
2491 op.mode = Integer.parseInt(value);
2492 break;
2493 case "d":
2494 op.duration = Integer.parseInt(value);
2495 break;
2496 case "pu":
2497 op.proxyUid = Integer.parseInt(value);
2498 break;
2499 case "pp":
2500 op.proxyPackageName = value;
2501 break;
2502 case "tp":
2503 op.time[AppOpsManager.UID_STATE_PERSISTENT] = Long.parseLong(value);
2504 break;
2505 case "tt":
2506 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2507 break;
2508 case "tfs":
2509 op.time[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2510 = Long.parseLong(value);
2511 break;
2512 case "tf":
2513 op.time[AppOpsManager.UID_STATE_FOREGROUND] = Long.parseLong(value);
2514 break;
2515 case "tb":
2516 op.time[AppOpsManager.UID_STATE_BACKGROUND] = Long.parseLong(value);
2517 break;
2518 case "tc":
2519 op.time[AppOpsManager.UID_STATE_CACHED] = Long.parseLong(value);
2520 break;
2521 case "rp":
2522 op.rejectTime[AppOpsManager.UID_STATE_PERSISTENT]
2523 = Long.parseLong(value);
2524 break;
2525 case "rt":
2526 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2527 break;
2528 case "rfs":
2529 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2530 = Long.parseLong(value);
2531 break;
2532 case "rf":
2533 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND]
2534 = Long.parseLong(value);
2535 break;
2536 case "rb":
2537 op.rejectTime[AppOpsManager.UID_STATE_BACKGROUND]
2538 = Long.parseLong(value);
2539 break;
2540 case "rc":
2541 op.rejectTime[AppOpsManager.UID_STATE_CACHED]
2542 = Long.parseLong(value);
2543 break;
2544 case "t":
2545 // Backwards compat.
2546 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2547 break;
2548 case "r":
2549 // Backwards compat.
2550 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2551 break;
2552 default:
2553 Slog.w(TAG, "Unknown attribute in 'op' tag: " + name);
2554 break;
2555 }
2556 }
2557
Svet Ganov2af57082015-07-30 08:44:20 -07002558 Ops ops = uidState.pkgOps.get(pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002559 if (ops == null) {
Svet Ganov2af57082015-07-30 08:44:20 -07002560 ops = new Ops(pkgName, uidState, isPrivileged);
2561 uidState.pkgOps.put(pkgName, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002562 }
2563 ops.put(op.op, op);
2564 } else {
2565 Slog.w(TAG, "Unknown element under <pkg>: "
2566 + parser.getName());
2567 XmlUtils.skipCurrentTag(parser);
2568 }
2569 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002570 UidState uidState = getUidStateLocked(uid, false);
2571 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002572 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002573 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002574 }
2575
2576 void writeState() {
2577 synchronized (mFile) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002578 FileOutputStream stream;
2579 try {
2580 stream = mFile.startWrite();
2581 } catch (IOException e) {
2582 Slog.w(TAG, "Failed to write state: " + e);
2583 return;
2584 }
2585
Dianne Hackborne17b4452018-01-10 13:15:40 -08002586 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
2587
Dianne Hackborn35654b62013-01-14 17:38:02 -08002588 try {
2589 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002590 out.setOutput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002591 out.startDocument(null, true);
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002592 out.startTag(null, "app-ops");
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002593 out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
Svet Ganov2af57082015-07-30 08:44:20 -07002594
2595 final int uidStateCount = mUidStates.size();
2596 for (int i = 0; i < uidStateCount; i++) {
2597 UidState uidState = mUidStates.valueAt(i);
2598 if (uidState.opModes != null && uidState.opModes.size() > 0) {
2599 out.startTag(null, "uid");
2600 out.attribute(null, "n", Integer.toString(uidState.uid));
2601 SparseIntArray uidOpModes = uidState.opModes;
2602 final int opCount = uidOpModes.size();
2603 for (int j = 0; j < opCount; j++) {
2604 final int op = uidOpModes.keyAt(j);
2605 final int mode = uidOpModes.valueAt(j);
2606 out.startTag(null, "op");
2607 out.attribute(null, "n", Integer.toString(op));
2608 out.attribute(null, "m", Integer.toString(mode));
2609 out.endTag(null, "op");
2610 }
2611 out.endTag(null, "uid");
2612 }
2613 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002614
2615 if (allOps != null) {
2616 String lastPkg = null;
2617 for (int i=0; i<allOps.size(); i++) {
2618 AppOpsManager.PackageOps pkg = allOps.get(i);
2619 if (!pkg.getPackageName().equals(lastPkg)) {
2620 if (lastPkg != null) {
2621 out.endTag(null, "pkg");
2622 }
2623 lastPkg = pkg.getPackageName();
2624 out.startTag(null, "pkg");
2625 out.attribute(null, "n", lastPkg);
2626 }
2627 out.startTag(null, "uid");
2628 out.attribute(null, "n", Integer.toString(pkg.getUid()));
Jason Monk1c7c3192014-06-26 12:52:18 -04002629 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002630 Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
2631 false /* edit */, false /* uidMismatchExpected */);
Jason Monk1c7c3192014-06-26 12:52:18 -04002632 // Should always be present as the list of PackageOps is generated
2633 // from Ops.
2634 if (ops != null) {
2635 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
2636 } else {
2637 out.attribute(null, "p", Boolean.toString(false));
2638 }
2639 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002640 List<AppOpsManager.OpEntry> ops = pkg.getOps();
2641 for (int j=0; j<ops.size(); j++) {
2642 AppOpsManager.OpEntry op = ops.get(j);
2643 out.startTag(null, "op");
2644 out.attribute(null, "n", Integer.toString(op.getOp()));
David Braunf5d83192013-09-16 13:43:51 -07002645 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002646 out.attribute(null, "m", Integer.toString(op.getMode()));
2647 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002648 for (int k = 0; k < _NUM_UID_STATE; k++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002649 final long time = op.getLastTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002650 if (time != 0) {
2651 out.attribute(null, UID_STATE_TIME_ATTRS[k],
2652 Long.toString(time));
2653 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002654 final long rejectTime = op.getLastRejectTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002655 if (rejectTime != 0) {
2656 out.attribute(null, UID_STATE_REJECT_ATTRS[k],
2657 Long.toString(rejectTime));
2658 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002659 }
2660 int dur = op.getDuration();
2661 if (dur != 0) {
2662 out.attribute(null, "d", Integer.toString(dur));
2663 }
Svet Ganov99b60432015-06-27 13:15:22 -07002664 int proxyUid = op.getProxyUid();
2665 if (proxyUid != -1) {
2666 out.attribute(null, "pu", Integer.toString(proxyUid));
2667 }
2668 String proxyPackageName = op.getProxyPackageName();
2669 if (proxyPackageName != null) {
2670 out.attribute(null, "pp", proxyPackageName);
2671 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002672 out.endTag(null, "op");
2673 }
2674 out.endTag(null, "uid");
2675 }
2676 if (lastPkg != null) {
2677 out.endTag(null, "pkg");
2678 }
2679 }
2680
2681 out.endTag(null, "app-ops");
2682 out.endDocument();
2683 mFile.finishWrite(stream);
2684 } catch (IOException e) {
2685 Slog.w(TAG, "Failed to write state, restoring backup.", e);
2686 mFile.failWrite(stream);
2687 }
2688 }
2689 }
2690
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002691 static class Shell extends ShellCommand {
2692 final IAppOpsService mInterface;
2693 final AppOpsService mInternal;
2694
2695 int userId = UserHandle.USER_SYSTEM;
2696 String packageName;
2697 String opStr;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002698 String modeStr;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002699 int op;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002700 int mode;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002701 int packageUid;
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002702 int nonpackageUid;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002703 final static Binder sBinder = new Binder();
2704 IBinder mToken;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002705
2706 Shell(IAppOpsService iface, AppOpsService internal) {
2707 mInterface = iface;
2708 mInternal = internal;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002709 try {
2710 mToken = mInterface.getToken(sBinder);
2711 } catch (RemoteException e) {
2712 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002713 }
2714
2715 @Override
2716 public int onCommand(String cmd) {
2717 return onShellCommand(this, cmd);
2718 }
2719
2720 @Override
2721 public void onHelp() {
2722 PrintWriter pw = getOutPrintWriter();
2723 dumpCommandHelp(pw);
2724 }
2725
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002726 static private int strOpToOp(String op, PrintWriter err) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002727 try {
2728 return AppOpsManager.strOpToOp(op);
2729 } catch (IllegalArgumentException e) {
2730 }
2731 try {
2732 return Integer.parseInt(op);
2733 } catch (NumberFormatException e) {
2734 }
2735 try {
2736 return AppOpsManager.strDebugOpToOp(op);
2737 } catch (IllegalArgumentException e) {
2738 err.println("Error: " + e.getMessage());
2739 return -1;
2740 }
2741 }
2742
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002743 static int strModeToMode(String modeStr, PrintWriter err) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002744 for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
2745 if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002746 return i;
2747 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002748 }
2749 try {
2750 return Integer.parseInt(modeStr);
2751 } catch (NumberFormatException e) {
2752 }
2753 err.println("Error: Mode " + modeStr + " is not valid");
2754 return -1;
2755 }
2756
2757 int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
2758 userId = UserHandle.USER_CURRENT;
2759 opStr = null;
2760 modeStr = null;
2761 for (String argument; (argument = getNextArg()) != null;) {
2762 if ("--user".equals(argument)) {
2763 userId = UserHandle.parseUserArg(getNextArgRequired());
2764 } else {
2765 if (opStr == null) {
2766 opStr = argument;
2767 } else if (modeStr == null) {
2768 modeStr = argument;
2769 break;
2770 }
2771 }
2772 }
2773 if (opStr == null) {
2774 err.println("Error: Operation not specified.");
2775 return -1;
2776 }
2777 op = strOpToOp(opStr, err);
2778 if (op < 0) {
2779 return -1;
2780 }
2781 if (modeStr != null) {
2782 if ((mode=strModeToMode(modeStr, err)) < 0) {
2783 return -1;
2784 }
2785 } else {
2786 mode = defMode;
2787 }
2788 return 0;
2789 }
2790
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002791 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
2792 userId = UserHandle.USER_CURRENT;
2793 packageName = null;
2794 opStr = null;
2795 for (String argument; (argument = getNextArg()) != null;) {
2796 if ("--user".equals(argument)) {
2797 userId = UserHandle.parseUserArg(getNextArgRequired());
2798 } else {
2799 if (packageName == null) {
2800 packageName = argument;
2801 } else if (opStr == null) {
2802 opStr = argument;
2803 break;
2804 }
2805 }
2806 }
2807 if (packageName == null) {
2808 err.println("Error: Package name not specified.");
2809 return -1;
2810 } else if (opStr == null && reqOp) {
2811 err.println("Error: Operation not specified.");
2812 return -1;
2813 }
2814 if (opStr != null) {
2815 op = strOpToOp(opStr, err);
2816 if (op < 0) {
2817 return -1;
2818 }
2819 } else {
2820 op = AppOpsManager.OP_NONE;
2821 }
2822 if (userId == UserHandle.USER_CURRENT) {
2823 userId = ActivityManager.getCurrentUser();
2824 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002825 nonpackageUid = -1;
2826 try {
2827 nonpackageUid = Integer.parseInt(packageName);
2828 } catch (NumberFormatException e) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002829 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002830 if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
2831 && packageName.indexOf('.') < 0) {
2832 int i = 1;
2833 while (i < packageName.length() && packageName.charAt(i) >= '0'
2834 && packageName.charAt(i) <= '9') {
2835 i++;
2836 }
2837 if (i > 1 && i < packageName.length()) {
2838 String userStr = packageName.substring(1, i);
2839 try {
2840 int user = Integer.parseInt(userStr);
2841 char type = packageName.charAt(i);
2842 i++;
2843 int startTypeVal = i;
2844 while (i < packageName.length() && packageName.charAt(i) >= '0'
2845 && packageName.charAt(i) <= '9') {
2846 i++;
2847 }
2848 if (i > startTypeVal) {
2849 String typeValStr = packageName.substring(startTypeVal, i);
2850 try {
2851 int typeVal = Integer.parseInt(typeValStr);
2852 if (type == 'a') {
2853 nonpackageUid = UserHandle.getUid(user,
2854 typeVal + Process.FIRST_APPLICATION_UID);
2855 } else if (type == 's') {
2856 nonpackageUid = UserHandle.getUid(user, typeVal);
2857 }
2858 } catch (NumberFormatException e) {
2859 }
2860 }
2861 } catch (NumberFormatException e) {
2862 }
2863 }
2864 }
2865 if (nonpackageUid != -1) {
2866 packageName = null;
2867 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08002868 packageUid = resolveUid(packageName);
2869 if (packageUid < 0) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002870 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
2871 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
2872 }
2873 if (packageUid < 0) {
2874 err.println("Error: No UID for " + packageName + " in user " + userId);
2875 return -1;
2876 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002877 }
2878 return 0;
2879 }
2880 }
2881
2882 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07002883 FileDescriptor err, String[] args, ShellCallback callback,
2884 ResultReceiver resultReceiver) {
2885 (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002886 }
2887
2888 static void dumpCommandHelp(PrintWriter pw) {
2889 pw.println("AppOps service (appops) commands:");
2890 pw.println(" help");
2891 pw.println(" Print this help text.");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002892 pw.println(" start [--user <USER_ID>] <PACKAGE | UID> <OP> ");
2893 pw.println(" Starts a given operation for a particular application.");
2894 pw.println(" stop [--user <USER_ID>] <PACKAGE | UID> <OP> ");
2895 pw.println(" Stops a given operation for a particular application.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002896 pw.println(" set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002897 pw.println(" Set the mode for a particular application and operation.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002898 pw.println(" get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002899 pw.println(" Return the mode for a particular application and optional operation.");
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002900 pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
2901 pw.println(" Print all packages that currently have the given op in the given mode.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002902 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
2903 pw.println(" Reset the given application or all applications to default modes.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002904 pw.println(" write-settings");
2905 pw.println(" Immediately write pending changes to storage.");
2906 pw.println(" read-settings");
2907 pw.println(" Read the last written settings, replacing current state in RAM.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002908 pw.println(" options:");
2909 pw.println(" <PACKAGE> an Android package name.");
2910 pw.println(" <OP> an AppOps operation.");
2911 pw.println(" <MODE> one of allow, ignore, deny, or default");
2912 pw.println(" <USER_ID> the user id under which the package is installed. If --user is not");
2913 pw.println(" specified, the current user is assumed.");
2914 }
2915
2916 static int onShellCommand(Shell shell, String cmd) {
2917 if (cmd == null) {
2918 return shell.handleDefaultCommands(cmd);
2919 }
2920 PrintWriter pw = shell.getOutPrintWriter();
2921 PrintWriter err = shell.getErrPrintWriter();
2922 try {
2923 switch (cmd) {
2924 case "set": {
2925 int res = shell.parseUserPackageOp(true, err);
2926 if (res < 0) {
2927 return res;
2928 }
2929 String modeStr = shell.getNextArg();
2930 if (modeStr == null) {
2931 err.println("Error: Mode not specified.");
2932 return -1;
2933 }
2934
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002935 final int mode = shell.strModeToMode(modeStr, err);
2936 if (mode < 0) {
2937 return -1;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002938 }
2939
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002940 if (shell.packageName != null) {
2941 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
2942 mode);
2943 } else {
2944 shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
2945 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002946 return 0;
2947 }
2948 case "get": {
2949 int res = shell.parseUserPackageOp(false, err);
2950 if (res < 0) {
2951 return res;
2952 }
2953
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002954 List<AppOpsManager.PackageOps> ops;
2955 if (shell.packageName != null) {
2956 ops = shell.mInterface.getOpsForPackage(
2957 shell.packageUid, shell.packageName,
2958 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
2959 } else {
2960 ops = shell.mInterface.getUidOps(
2961 shell.nonpackageUid,
2962 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
2963 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002964 if (ops == null || ops.size() <= 0) {
2965 pw.println("No operations.");
Svet Ganov82f09bc2018-01-12 22:08:40 -08002966 if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002967 pw.println("Default mode: " + AppOpsManager.modeToName(
Svet Ganov82f09bc2018-01-12 22:08:40 -08002968 AppOpsManager.opToDefaultMode(shell.op)));
2969 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002970 return 0;
2971 }
2972 final long now = System.currentTimeMillis();
2973 for (int i=0; i<ops.size(); i++) {
2974 List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
2975 for (int j=0; j<entries.size(); j++) {
2976 AppOpsManager.OpEntry ent = entries.get(j);
2977 pw.print(AppOpsManager.opToName(ent.getOp()));
2978 pw.print(": ");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002979 pw.print(AppOpsManager.modeToName(ent.getMode()));
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002980 if (ent.getTime() != 0) {
2981 pw.print("; time=");
2982 TimeUtils.formatDuration(now - ent.getTime(), pw);
2983 pw.print(" ago");
2984 }
2985 if (ent.getRejectTime() != 0) {
2986 pw.print("; rejectTime=");
2987 TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
2988 pw.print(" ago");
2989 }
2990 if (ent.getDuration() == -1) {
2991 pw.print(" (running)");
2992 } else if (ent.getDuration() != 0) {
2993 pw.print("; duration=");
2994 TimeUtils.formatDuration(ent.getDuration(), pw);
2995 }
2996 pw.println();
2997 }
2998 }
2999 return 0;
3000 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07003001 case "query-op": {
3002 int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
3003 if (res < 0) {
3004 return res;
3005 }
3006 List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
3007 new int[] {shell.op});
3008 if (ops == null || ops.size() <= 0) {
3009 pw.println("No operations.");
3010 return 0;
3011 }
3012 for (int i=0; i<ops.size(); i++) {
3013 final AppOpsManager.PackageOps pkg = ops.get(i);
3014 boolean hasMatch = false;
3015 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
3016 for (int j=0; j<entries.size(); j++) {
3017 AppOpsManager.OpEntry ent = entries.get(j);
3018 if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
3019 hasMatch = true;
3020 break;
3021 }
3022 }
3023 if (hasMatch) {
3024 pw.println(pkg.getPackageName());
3025 }
3026 }
3027 return 0;
3028 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003029 case "reset": {
3030 String packageName = null;
3031 int userId = UserHandle.USER_CURRENT;
3032 for (String argument; (argument = shell.getNextArg()) != null;) {
3033 if ("--user".equals(argument)) {
3034 String userStr = shell.getNextArgRequired();
3035 userId = UserHandle.parseUserArg(userStr);
3036 } else {
3037 if (packageName == null) {
3038 packageName = argument;
3039 } else {
3040 err.println("Error: Unsupported argument: " + argument);
3041 return -1;
3042 }
3043 }
3044 }
3045
3046 if (userId == UserHandle.USER_CURRENT) {
3047 userId = ActivityManager.getCurrentUser();
3048 }
3049
3050 shell.mInterface.resetAllModes(userId, packageName);
3051 pw.print("Reset all modes for: ");
3052 if (userId == UserHandle.USER_ALL) {
3053 pw.print("all users");
3054 } else {
3055 pw.print("user "); pw.print(userId);
3056 }
3057 pw.print(", ");
3058 if (packageName == null) {
3059 pw.println("all packages");
3060 } else {
3061 pw.print("package "); pw.println(packageName);
3062 }
3063 return 0;
3064 }
3065 case "write-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07003066 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
3067 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003068 long token = Binder.clearCallingIdentity();
3069 try {
3070 synchronized (shell.mInternal) {
3071 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
3072 }
3073 shell.mInternal.writeState();
3074 pw.println("Current settings written.");
3075 } finally {
3076 Binder.restoreCallingIdentity(token);
3077 }
3078 return 0;
3079 }
3080 case "read-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07003081 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
3082 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003083 long token = Binder.clearCallingIdentity();
3084 try {
3085 shell.mInternal.readState();
3086 pw.println("Last settings read.");
3087 } finally {
3088 Binder.restoreCallingIdentity(token);
3089 }
3090 return 0;
3091 }
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05003092 case "start": {
3093 int res = shell.parseUserPackageOp(true, err);
3094 if (res < 0) {
3095 return res;
3096 }
3097
3098 if (shell.packageName != null) {
3099 shell.mInterface.startOperation(shell.mToken,
3100 shell.op, shell.packageUid, shell.packageName, true);
3101 } else {
3102 return -1;
3103 }
3104 return 0;
3105 }
3106 case "stop": {
3107 int res = shell.parseUserPackageOp(true, err);
3108 if (res < 0) {
3109 return res;
3110 }
3111
3112 if (shell.packageName != null) {
3113 shell.mInterface.finishOperation(shell.mToken,
3114 shell.op, shell.packageUid, shell.packageName);
3115 } else {
3116 return -1;
3117 }
3118 return 0;
3119 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003120 default:
3121 return shell.handleDefaultCommands(cmd);
3122 }
3123 } catch (RemoteException e) {
3124 pw.println("Remote exception: " + e);
3125 }
3126 return -1;
3127 }
3128
3129 private void dumpHelp(PrintWriter pw) {
3130 pw.println("AppOps service (appops) dump options:");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003131 pw.println(" -h");
3132 pw.println(" Print this help text.");
3133 pw.println(" --op [OP]");
3134 pw.println(" Limit output to data associated with the given app op code.");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003135 pw.println(" --mode [MODE]");
3136 pw.println(" Limit output to data associated with the given app op mode.");
3137 pw.println(" --package [PACKAGE]");
3138 pw.println(" Limit output to data associated with the given package name.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003139 }
3140
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003141 private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
3142 long now, SimpleDateFormat sdf, Date date) {
3143 boolean hasTime = false;
3144 for (int i = 0; i < _NUM_UID_STATE; i++) {
3145 if (times[i] != 0) {
3146 hasTime = true;
3147 break;
3148 }
3149 }
3150 if (!hasTime) {
3151 return;
3152 }
3153 boolean first = true;
3154 for (int i = 0; i < _NUM_UID_STATE; i++) {
3155 if (times[i] != 0) {
3156 pw.print(first ? firstPrefix : prefix);
3157 first = false;
3158 pw.print(UID_STATE_NAMES[i]);
3159 pw.print(" = ");
3160 date.setTime(times[i]);
3161 pw.print(sdf.format(date));
3162 pw.print(" (");
3163 TimeUtils.formatDuration(times[i]-now, pw);
3164 pw.println(")");
3165 }
3166 }
3167 }
3168
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003169 @Override
3170 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003171 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003172
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003173 int dumpOp = -1;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003174 String dumpPackage = null;
3175 int dumpUid = -1;
3176 int dumpMode = -1;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003177
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003178 if (args != null) {
3179 for (int i=0; i<args.length; i++) {
3180 String arg = args[i];
3181 if ("-h".equals(arg)) {
3182 dumpHelp(pw);
3183 return;
Tim Kilbourn8f1ea832015-08-26 15:07:37 -07003184 } else if ("-a".equals(arg)) {
3185 // dump all data
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003186 } else if ("--op".equals(arg)) {
3187 i++;
3188 if (i >= args.length) {
3189 pw.println("No argument for --op option");
3190 return;
3191 }
3192 dumpOp = Shell.strOpToOp(args[i], pw);
3193 if (dumpOp < 0) {
3194 return;
3195 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003196 } else if ("--package".equals(arg)) {
3197 i++;
3198 if (i >= args.length) {
3199 pw.println("No argument for --package option");
3200 return;
3201 }
3202 dumpPackage = args[i];
3203 try {
3204 dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
3205 PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
3206 0);
3207 } catch (RemoteException e) {
3208 }
3209 if (dumpUid < 0) {
3210 pw.println("Unknown package: " + dumpPackage);
3211 return;
3212 }
3213 dumpUid = UserHandle.getAppId(dumpUid);
3214 } else if ("--mode".equals(arg)) {
3215 i++;
3216 if (i >= args.length) {
3217 pw.println("No argument for --mode option");
3218 return;
3219 }
3220 dumpMode = Shell.strModeToMode(args[i], pw);
3221 if (dumpMode < 0) {
3222 return;
3223 }
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003224 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
3225 pw.println("Unknown option: " + arg);
3226 return;
3227 } else {
3228 pw.println("Unknown command: " + arg);
3229 return;
3230 }
3231 }
3232 }
3233
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003234 synchronized (this) {
3235 pw.println("Current AppOps Service state:");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003236 mConstants.dump(pw);
3237 pw.println();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003238 final long now = System.currentTimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003239 final long nowElapsed = SystemClock.elapsedRealtime();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003240 final long nowUptime = SystemClock.uptimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003241 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
3242 final Date date = new Date();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003243 boolean needSep = false;
Dianne Hackbornd5254412018-05-11 18:02:58 -07003244 if (dumpOp < 0 && dumpMode < 0 && dumpPackage == null && mProfileOwners != null) {
3245 pw.println(" Profile owners:");
3246 for (int poi = 0; poi < mProfileOwners.size(); poi++) {
3247 pw.print(" User #");
3248 pw.print(mProfileOwners.keyAt(poi));
3249 pw.print(": ");
3250 UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
3251 pw.println();
3252 }
3253 pw.println();
3254 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003255 if (mOpModeWatchers.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003256 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003257 for (int i=0; i<mOpModeWatchers.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003258 if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
3259 continue;
3260 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003261 boolean printedOpHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003262 ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003263 for (int j=0; j<callbacks.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003264 final ModeCallback cb = callbacks.valueAt(j);
3265 if (dumpPackage != null && cb.mWatchingUid >= 0
3266 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3267 continue;
3268 }
3269 needSep = true;
3270 if (!printedHeader) {
3271 pw.println(" Op mode watchers:");
3272 printedHeader = true;
3273 }
3274 if (!printedOpHeader) {
3275 pw.print(" Op ");
3276 pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
3277 pw.println(":");
3278 printedOpHeader = true;
3279 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003280 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003281 pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003282 }
3283 }
3284 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003285 if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
3286 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003287 for (int i=0; i<mPackageModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003288 if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
3289 continue;
3290 }
3291 needSep = true;
3292 if (!printedHeader) {
3293 pw.println(" Package mode watchers:");
3294 printedHeader = true;
3295 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003296 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
3297 pw.println(":");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003298 ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003299 for (int j=0; j<callbacks.size(); j++) {
3300 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn68d76552017-02-27 15:32:03 -08003301 pw.println(callbacks.valueAt(j));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003302 }
3303 }
3304 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003305 if (mModeWatchers.size() > 0 && dumpOp < 0) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003306 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003307 for (int i=0; i<mModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003308 final ModeCallback cb = mModeWatchers.valueAt(i);
3309 if (dumpPackage != null && cb.mWatchingUid >= 0
3310 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3311 continue;
3312 }
3313 needSep = true;
3314 if (!printedHeader) {
3315 pw.println(" All op mode watchers:");
3316 printedHeader = true;
3317 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003318 pw.print(" ");
3319 pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003320 pw.print(": "); pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003321 }
3322 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003323 if (mActiveWatchers.size() > 0 && dumpMode < 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003324 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003325 boolean printedHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003326 for (int i = 0; i < mActiveWatchers.size(); i++) {
3327 final SparseArray<ActiveCallback> activeWatchers = mActiveWatchers.valueAt(i);
3328 if (activeWatchers.size() <= 0) {
3329 continue;
3330 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003331 final ActiveCallback cb = activeWatchers.valueAt(0);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003332 if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
3333 continue;
3334 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003335 if (dumpPackage != null && cb.mWatchingUid >= 0
3336 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3337 continue;
3338 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003339 if (!printedHeader) {
3340 pw.println(" All op active watchers:");
3341 printedHeader = true;
3342 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003343 pw.print(" ");
3344 pw.print(Integer.toHexString(System.identityHashCode(
3345 mActiveWatchers.keyAt(i))));
3346 pw.println(" ->");
3347 pw.print(" [");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003348 final int opCount = activeWatchers.size();
3349 for (i = 0; i < opCount; i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003350 if (i > 0) {
3351 pw.print(' ');
3352 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003353 pw.print(AppOpsManager.opToName(activeWatchers.keyAt(i)));
3354 if (i < opCount - 1) {
3355 pw.print(',');
3356 }
3357 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003358 pw.println("]");
3359 pw.print(" ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003360 pw.println(cb);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003361 }
3362 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003363 if (mClients.size() > 0 && dumpMode < 0) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003364 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003365 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003366 for (int i=0; i<mClients.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003367 boolean printedClient = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003368 ClientState cs = mClients.valueAt(i);
Svet Ganovf7b47252018-02-26 11:11:27 -08003369 if (cs.mStartedOps.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003370 boolean printedStarted = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003371 for (int j=0; j<cs.mStartedOps.size(); j++) {
3372 Op op = cs.mStartedOps.get(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003373 if (dumpOp >= 0 && op.op != dumpOp) {
3374 continue;
3375 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003376 if (dumpPackage != null && !dumpPackage.equals(op.packageName)) {
3377 continue;
3378 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003379 if (!printedHeader) {
3380 pw.println(" Clients:");
3381 printedHeader = true;
3382 }
3383 if (!printedClient) {
3384 pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
3385 pw.print(" "); pw.println(cs);
3386 printedClient = true;
3387 }
3388 if (!printedStarted) {
3389 pw.println(" Started ops:");
3390 printedStarted = true;
3391 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003392 pw.print(" "); pw.print("uid="); pw.print(op.uid);
3393 pw.print(" pkg="); pw.print(op.packageName);
3394 pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
3395 }
3396 }
3397 }
3398 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003399 if (mAudioRestrictions.size() > 0 && dumpOp < 0 && dumpPackage != null
3400 && dumpMode < 0) {
John Spurlock1af30c72014-03-10 08:33:35 -04003401 boolean printedHeader = false;
3402 for (int o=0; o<mAudioRestrictions.size(); o++) {
3403 final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
3404 final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
3405 for (int i=0; i<restrictions.size(); i++) {
3406 if (!printedHeader){
3407 pw.println(" Audio Restrictions:");
3408 printedHeader = true;
3409 needSep = true;
3410 }
John Spurlock7b414672014-07-18 13:02:39 -04003411 final int usage = restrictions.keyAt(i);
John Spurlock1af30c72014-03-10 08:33:35 -04003412 pw.print(" "); pw.print(op);
John Spurlock7b414672014-07-18 13:02:39 -04003413 pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
John Spurlock1af30c72014-03-10 08:33:35 -04003414 Restriction r = restrictions.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003415 pw.print(": mode="); pw.println(AppOpsManager.modeToName(r.mode));
John Spurlock1af30c72014-03-10 08:33:35 -04003416 if (!r.exceptionPackages.isEmpty()) {
3417 pw.println(" Exceptions:");
3418 for (int j=0; j<r.exceptionPackages.size(); j++) {
3419 pw.print(" "); pw.println(r.exceptionPackages.valueAt(j));
3420 }
3421 }
3422 }
3423 }
3424 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003425 if (needSep) {
3426 pw.println();
3427 }
Svet Ganov2af57082015-07-30 08:44:20 -07003428 for (int i=0; i<mUidStates.size(); i++) {
3429 UidState uidState = mUidStates.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003430 final SparseIntArray opModes = uidState.opModes;
3431 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
3432
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003433 if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
3434 boolean hasOp = dumpOp < 0 || (uidState.opModes != null
3435 && uidState.opModes.indexOfKey(dumpOp) >= 0);
3436 boolean hasPackage = dumpPackage == null;
3437 boolean hasMode = dumpMode < 0;
3438 if (!hasMode && opModes != null) {
3439 for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
3440 if (opModes.valueAt(opi) == dumpMode) {
3441 hasMode = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003442 }
3443 }
3444 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003445 if (pkgOps != null) {
3446 for (int pkgi = 0;
3447 (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
3448 pkgi++) {
3449 Ops ops = pkgOps.valueAt(pkgi);
3450 if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
3451 hasOp = true;
3452 }
3453 if (!hasMode) {
3454 for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
3455 if (ops.valueAt(opi).mode == dumpMode) {
3456 hasMode = true;
3457 }
3458 }
3459 }
3460 if (!hasPackage && dumpPackage.equals(ops.packageName)) {
3461 hasPackage = true;
3462 }
3463 }
3464 }
3465 if (uidState.foregroundOps != null && !hasOp) {
3466 if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
3467 hasOp = true;
3468 }
3469 }
3470 if (!hasOp || !hasPackage || !hasMode) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003471 continue;
3472 }
3473 }
Svet Ganov2af57082015-07-30 08:44:20 -07003474
3475 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003476 pw.print(" state=");
3477 pw.println(UID_STATE_NAMES[uidState.state]);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003478 if (uidState.state != uidState.pendingState) {
3479 pw.print(" pendingState=");
3480 pw.println(UID_STATE_NAMES[uidState.pendingState]);
3481 }
3482 if (uidState.pendingStateCommitTime != 0) {
3483 pw.print(" pendingStateCommitTime=");
Dianne Hackborn9fb93502018-06-18 12:29:44 -07003484 TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003485 pw.println();
3486 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003487 if (uidState.startNesting != 0) {
3488 pw.print(" startNesting=");
3489 pw.println(uidState.startNesting);
3490 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003491 if (uidState.foregroundOps != null && (dumpMode < 0
3492 || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003493 pw.println(" foregroundOps:");
3494 for (int j = 0; j < uidState.foregroundOps.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003495 if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
3496 continue;
3497 }
3498 pw.print(" ");
3499 pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
3500 pw.print(": ");
3501 pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003502 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003503 pw.print(" hasForegroundWatchers=");
3504 pw.println(uidState.hasForegroundWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003505 }
Svet Ganovee438d42017-01-19 18:04:38 -08003506 needSep = true;
Svet Ganov2af57082015-07-30 08:44:20 -07003507
Svet Ganov2af57082015-07-30 08:44:20 -07003508 if (opModes != null) {
3509 final int opModeCount = opModes.size();
3510 for (int j = 0; j < opModeCount; j++) {
3511 final int code = opModes.keyAt(j);
3512 final int mode = opModes.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003513 if (dumpOp >= 0 && dumpOp != code) {
3514 continue;
3515 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003516 if (dumpMode >= 0 && dumpMode != mode) {
3517 continue;
3518 }
Svet Ganov2af57082015-07-30 08:44:20 -07003519 pw.print(" "); pw.print(AppOpsManager.opToName(code));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003520 pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
Svet Ganov2af57082015-07-30 08:44:20 -07003521 }
3522 }
3523
Svet Ganov2af57082015-07-30 08:44:20 -07003524 if (pkgOps == null) {
3525 continue;
3526 }
3527
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003528 for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003529 final Ops ops = pkgOps.valueAt(pkgi);
3530 if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
3531 continue;
3532 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003533 boolean printedPackage = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003534 for (int j=0; j<ops.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003535 final Op op = ops.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003536 if (dumpOp >= 0 && dumpOp != op.op) {
3537 continue;
3538 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003539 if (dumpMode >= 0 && dumpMode != op.mode) {
3540 continue;
3541 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003542 if (!printedPackage) {
3543 pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
3544 printedPackage = true;
3545 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003546 pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003547 pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003548 final int switchOp = AppOpsManager.opToSwitch(op.op);
3549 if (switchOp != op.op) {
3550 pw.print(" / switch ");
3551 pw.print(AppOpsManager.opToName(switchOp));
3552 final Op switchObj = ops.get(switchOp);
3553 int mode = switchObj != null
3554 ? switchObj.mode : AppOpsManager.opToDefaultMode(switchOp);
3555 pw.print("="); pw.print(AppOpsManager.modeToName(mode));
3556 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003557 pw.println("): ");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003558 dumpTimesLocked(pw,
3559 " Access: ",
3560 " ", op.time, now, sdf, date);
3561 dumpTimesLocked(pw,
3562 " Reject: ",
3563 " ", op.rejectTime, now, sdf, date);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003564 if (op.duration == -1) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003565 pw.print(" Running start at: ");
3566 TimeUtils.formatDuration(nowElapsed-op.startRealtime, pw);
3567 pw.println();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08003568 } else if (op.duration != 0) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003569 pw.print(" duration=");
3570 TimeUtils.formatDuration(op.duration, pw);
3571 pw.println();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003572 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003573 if (op.startNesting != 0) {
3574 pw.print(" startNesting=");
3575 pw.println(op.startNesting);
3576 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003577 }
3578 }
3579 }
Svet Ganovee438d42017-01-19 18:04:38 -08003580 if (needSep) {
3581 pw.println();
3582 }
3583
3584 final int userRestrictionCount = mOpUserRestrictions.size();
3585 for (int i = 0; i < userRestrictionCount; i++) {
3586 IBinder token = mOpUserRestrictions.keyAt(i);
3587 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
3588 pw.println(" User restrictions for token " + token + ":");
3589
3590 final int restrictionCount = restrictionState.perUserRestrictions != null
3591 ? restrictionState.perUserRestrictions.size() : 0;
3592 if (restrictionCount > 0) {
3593 pw.println(" Restricted ops:");
3594 for (int j = 0; j < restrictionCount; j++) {
3595 int userId = restrictionState.perUserRestrictions.keyAt(j);
3596 boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
3597 if (restrictedOps == null) {
3598 continue;
3599 }
3600 StringBuilder restrictedOpsValue = new StringBuilder();
3601 restrictedOpsValue.append("[");
3602 final int restrictedOpCount = restrictedOps.length;
3603 for (int k = 0; k < restrictedOpCount; k++) {
3604 if (restrictedOps[k]) {
3605 if (restrictedOpsValue.length() > 1) {
3606 restrictedOpsValue.append(", ");
3607 }
3608 restrictedOpsValue.append(AppOpsManager.opToName(k));
3609 }
3610 }
3611 restrictedOpsValue.append("]");
3612 pw.print(" "); pw.print("user: "); pw.print(userId);
3613 pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
3614 }
3615 }
3616
3617 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
3618 ? restrictionState.perUserExcludedPackages.size() : 0;
3619 if (excludedPackageCount > 0) {
3620 pw.println(" Excluded packages:");
3621 for (int j = 0; j < excludedPackageCount; j++) {
3622 int userId = restrictionState.perUserExcludedPackages.keyAt(j);
3623 String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
3624 pw.print(" "); pw.print("user: "); pw.print(userId);
3625 pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
3626 }
3627 }
3628 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003629 }
3630 }
John Spurlock1af30c72014-03-10 08:33:35 -04003631
3632 private static final class Restriction {
3633 private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
3634 int mode;
3635 ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
3636 }
Jason Monk62062992014-05-06 09:55:28 -04003637
3638 @Override
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003639 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
Jason Monk62062992014-05-06 09:55:28 -04003640 checkSystemUid("setUserRestrictions");
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003641 Preconditions.checkNotNull(restrictions);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003642 Preconditions.checkNotNull(token);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003643 for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
Jason Monk62062992014-05-06 09:55:28 -04003644 String restriction = AppOpsManager.opToRestriction(i);
Suprabh Shukla64e0dcb2016-05-24 16:23:11 -07003645 if (restriction != null) {
3646 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
3647 userHandle, null);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003648 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003649 }
3650 }
3651
3652 @Override
Ruben Brunk29931bc2016-03-11 00:24:26 -08003653 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
3654 String[] exceptionPackages) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003655 if (Binder.getCallingPid() != Process.myPid()) {
3656 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
3657 Binder.getCallingPid(), Binder.getCallingUid(), null);
3658 }
3659 if (userHandle != UserHandle.getCallingUserId()) {
3660 if (mContext.checkCallingOrSelfPermission(Manifest.permission
3661 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
3662 && mContext.checkCallingOrSelfPermission(Manifest.permission
3663 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
3664 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
3665 + " INTERACT_ACROSS_USERS to interact cross user ");
Jason Monk62062992014-05-06 09:55:28 -04003666 }
3667 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003668 verifyIncomingOp(code);
3669 Preconditions.checkNotNull(token);
Ruben Brunk29931bc2016-03-11 00:24:26 -08003670 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003671 }
3672
3673 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
Ruben Brunk29931bc2016-03-11 00:24:26 -08003674 int userHandle, String[] exceptionPackages) {
Svet Ganov442ed572016-08-17 17:29:43 -07003675 synchronized (AppOpsService.this) {
3676 ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
3677
3678 if (restrictionState == null) {
3679 try {
3680 restrictionState = new ClientRestrictionState(token);
3681 } catch (RemoteException e) {
3682 return;
3683 }
3684 mOpUserRestrictions.put(token, restrictionState);
Ruben Brunk29931bc2016-03-11 00:24:26 -08003685 }
Svet Ganov442ed572016-08-17 17:29:43 -07003686
3687 if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003688 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07003689 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
Svet Ganov442ed572016-08-17 17:29:43 -07003690 }
3691
3692 if (restrictionState.isDefault()) {
3693 mOpUserRestrictions.remove(token);
3694 restrictionState.destroy();
3695 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08003696 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -04003697 }
3698
Svet Ganov3a95f832018-03-23 17:44:30 -07003699 private void notifyWatchersOfChange(int code, int uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003700 final ArraySet<ModeCallback> clonedCallbacks;
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003701 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003702 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003703 if (callbacks == null) {
3704 return;
3705 }
Dianne Hackborn68d76552017-02-27 15:32:03 -08003706 clonedCallbacks = new ArraySet<>(callbacks);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003707 }
3708
Svet Ganov3a95f832018-03-23 17:44:30 -07003709 notifyOpChanged(clonedCallbacks, code, uid, null);
Jason Monk62062992014-05-06 09:55:28 -04003710 }
3711
3712 @Override
3713 public void removeUser(int userHandle) throws RemoteException {
3714 checkSystemUid("removeUser");
Svet Ganov442ed572016-08-17 17:29:43 -07003715 synchronized (AppOpsService.this) {
3716 final int tokenCount = mOpUserRestrictions.size();
3717 for (int i = tokenCount - 1; i >= 0; i--) {
3718 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
3719 opRestrictions.removeUser(userHandle);
3720 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003721 removeUidsForUserLocked(userHandle);
3722 }
3723 }
3724
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003725 @Override
3726 public boolean isOperationActive(int code, int uid, String packageName) {
Svet Ganovf7b47252018-02-26 11:11:27 -08003727 if (Binder.getCallingUid() != uid) {
3728 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
3729 != PackageManager.PERMISSION_GRANTED) {
3730 return false;
3731 }
3732 }
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003733 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003734 final String resolvedPackageName = resolvePackageName(uid, packageName);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003735 if (resolvedPackageName == null) {
3736 return false;
3737 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003738 synchronized (AppOpsService.this) {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003739 for (int i = mClients.size() - 1; i >= 0; i--) {
3740 final ClientState client = mClients.valueAt(i);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003741 for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
3742 final Op op = client.mStartedOps.get(j);
3743 if (op.op == code && op.uid == uid) return true;
3744 }
3745 }
3746 }
3747 return false;
3748 }
3749
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003750 private void removeUidsForUserLocked(int userHandle) {
3751 for (int i = mUidStates.size() - 1; i >= 0; --i) {
3752 final int uid = mUidStates.keyAt(i);
3753 if (UserHandle.getUserId(uid) == userHandle) {
3754 mUidStates.removeAt(i);
3755 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003756 }
3757 }
3758
Jason Monk62062992014-05-06 09:55:28 -04003759 private void checkSystemUid(String function) {
3760 int uid = Binder.getCallingUid();
3761 if (uid != Process.SYSTEM_UID) {
3762 throw new SecurityException(function + " must by called by the system");
3763 }
3764 }
3765
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003766 private static String resolvePackageName(int uid, String packageName) {
Svet Ganov82f09bc2018-01-12 22:08:40 -08003767 if (uid == Process.ROOT_UID) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003768 return "root";
3769 } else if (uid == Process.SHELL_UID) {
3770 return "com.android.shell";
Svet Ganov82f09bc2018-01-12 22:08:40 -08003771 } else if (uid == Process.MEDIA_UID) {
3772 return "media";
3773 } else if (uid == Process.AUDIOSERVER_UID) {
3774 return "audioserver";
3775 } else if (uid == Process.CAMERASERVER_UID) {
3776 return "cameraserver";
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003777 } else if (uid == Process.SYSTEM_UID && packageName == null) {
3778 return "android";
3779 }
3780 return packageName;
3781 }
3782
Svet Ganov82f09bc2018-01-12 22:08:40 -08003783 private static int resolveUid(String packageName) {
3784 if (packageName == null) {
3785 return -1;
3786 }
3787 switch (packageName) {
3788 case "root":
3789 return Process.ROOT_UID;
3790 case "shell":
3791 return Process.SHELL_UID;
3792 case "media":
3793 return Process.MEDIA_UID;
3794 case "audioserver":
3795 return Process.AUDIOSERVER_UID;
3796 case "cameraserver":
3797 return Process.CAMERASERVER_UID;
3798 }
3799 return -1;
3800 }
3801
Svet Ganov2af57082015-07-30 08:44:20 -07003802 private static String[] getPackagesForUid(int uid) {
Svet Ganovf3807aa2015-08-02 10:09:56 -07003803 String[] packageNames = null;
Svet Ganov2af57082015-07-30 08:44:20 -07003804 try {
riddle_hsu40b300f2015-11-23 13:22:03 +08003805 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
Svet Ganov2af57082015-07-30 08:44:20 -07003806 } catch (RemoteException e) {
3807 /* ignore - local call */
3808 }
Svet Ganovf3807aa2015-08-02 10:09:56 -07003809 if (packageNames == null) {
3810 return EmptyArray.STRING;
3811 }
3812 return packageNames;
Svet Ganov2af57082015-07-30 08:44:20 -07003813 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003814
3815 private final class ClientRestrictionState implements DeathRecipient {
3816 private final IBinder token;
3817 SparseArray<boolean[]> perUserRestrictions;
3818 SparseArray<String[]> perUserExcludedPackages;
3819
3820 public ClientRestrictionState(IBinder token)
3821 throws RemoteException {
3822 token.linkToDeath(this, 0);
3823 this.token = token;
3824 }
3825
3826 public boolean setRestriction(int code, boolean restricted,
3827 String[] excludedPackages, int userId) {
3828 boolean changed = false;
3829
3830 if (perUserRestrictions == null && restricted) {
3831 perUserRestrictions = new SparseArray<>();
3832 }
3833
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003834 int[] users;
3835 if (userId == UserHandle.USER_ALL) {
3836 List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003837
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003838 users = new int[liveUsers.size()];
3839 for (int i = 0; i < liveUsers.size(); i++) {
3840 users[i] = liveUsers.get(i).id;
3841 }
3842 } else {
3843 users = new int[]{userId};
3844 }
3845
3846 if (perUserRestrictions != null) {
3847 int numUsers = users.length;
3848
3849 for (int i = 0; i < numUsers; i++) {
3850 int thisUserId = users[i];
3851
3852 boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
3853 if (userRestrictions == null && restricted) {
3854 userRestrictions = new boolean[AppOpsManager._NUM_OP];
3855 perUserRestrictions.put(thisUserId, userRestrictions);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003856 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003857 if (userRestrictions != null && userRestrictions[code] != restricted) {
3858 userRestrictions[code] = restricted;
3859 if (!restricted && isDefault(userRestrictions)) {
3860 perUserRestrictions.remove(thisUserId);
3861 userRestrictions = null;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003862 }
3863 changed = true;
3864 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003865
3866 if (userRestrictions != null) {
3867 final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
3868 if (perUserExcludedPackages == null && !noExcludedPackages) {
3869 perUserExcludedPackages = new SparseArray<>();
3870 }
3871 if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
3872 perUserExcludedPackages.get(thisUserId))) {
3873 if (noExcludedPackages) {
3874 perUserExcludedPackages.remove(thisUserId);
3875 if (perUserExcludedPackages.size() <= 0) {
3876 perUserExcludedPackages = null;
3877 }
3878 } else {
3879 perUserExcludedPackages.put(thisUserId, excludedPackages);
3880 }
3881 changed = true;
3882 }
3883 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003884 }
3885 }
3886
3887 return changed;
3888 }
3889
3890 public boolean hasRestriction(int restriction, String packageName, int userId) {
3891 if (perUserRestrictions == null) {
3892 return false;
3893 }
3894 boolean[] restrictions = perUserRestrictions.get(userId);
3895 if (restrictions == null) {
3896 return false;
3897 }
3898 if (!restrictions[restriction]) {
3899 return false;
3900 }
3901 if (perUserExcludedPackages == null) {
3902 return true;
3903 }
3904 String[] perUserExclusions = perUserExcludedPackages.get(userId);
3905 if (perUserExclusions == null) {
3906 return true;
3907 }
3908 return !ArrayUtils.contains(perUserExclusions, packageName);
3909 }
3910
3911 public void removeUser(int userId) {
3912 if (perUserExcludedPackages != null) {
3913 perUserExcludedPackages.remove(userId);
3914 if (perUserExcludedPackages.size() <= 0) {
3915 perUserExcludedPackages = null;
3916 }
3917 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003918 if (perUserRestrictions != null) {
3919 perUserRestrictions.remove(userId);
3920 if (perUserRestrictions.size() <= 0) {
3921 perUserRestrictions = null;
3922 }
3923 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003924 }
3925
3926 public boolean isDefault() {
3927 return perUserRestrictions == null || perUserRestrictions.size() <= 0;
3928 }
3929
3930 @Override
3931 public void binderDied() {
3932 synchronized (AppOpsService.this) {
3933 mOpUserRestrictions.remove(token);
3934 if (perUserRestrictions == null) {
3935 return;
3936 }
3937 final int userCount = perUserRestrictions.size();
3938 for (int i = 0; i < userCount; i++) {
3939 final boolean[] restrictions = perUserRestrictions.valueAt(i);
3940 final int restrictionCount = restrictions.length;
3941 for (int j = 0; j < restrictionCount; j++) {
3942 if (restrictions[j]) {
3943 final int changedCode = j;
Svet Ganov3a95f832018-03-23 17:44:30 -07003944 mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003945 }
3946 }
3947 }
3948 destroy();
3949 }
3950 }
3951
3952 public void destroy() {
3953 token.unlinkToDeath(this, 0);
3954 }
3955
3956 private boolean isDefault(boolean[] array) {
3957 if (ArrayUtils.isEmpty(array)) {
3958 return true;
3959 }
3960 for (boolean value : array) {
3961 if (value) {
3962 return false;
3963 }
3964 }
3965 return true;
3966 }
3967 }
Dianne Hackbornd5254412018-05-11 18:02:58 -07003968
3969 private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
3970 @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
3971 synchronized (AppOpsService.this) {
3972 mProfileOwners = owners;
3973 }
3974 }
3975 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003976}