blob: 7ede6dcd41bd31a30e57faee43580a83d642a804 [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
Svet Ganov8455ba22019-01-02 13:05:56 -080017package com.android.server.appop;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080018
Suprabh Shukla3017fe42018-11-08 19:00:01 -080019import static android.app.AppOpsManager.OP_PLAY_AUDIO;
Svet Ganov8455ba22019-01-02 13:05:56 -080020import static android.app.AppOpsManager.OP_NONE;
Hai Zhang2b98fb32018-09-21 15:18:46 -070021import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
22import static android.app.AppOpsManager.UID_STATE_CACHED;
23import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
24import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
25import static android.app.AppOpsManager.UID_STATE_LAST_NON_RESTRICTED;
26import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
27import static android.app.AppOpsManager.UID_STATE_TOP;
28import static android.app.AppOpsManager._NUM_UID_STATE;
Eugene Suslae4ee2c22018-11-05 12:23:30 -080029import static android.app.AppOpsManager.modeToName;
30import static android.app.AppOpsManager.opToName;
Hai Zhang2b98fb32018-09-21 15:18:46 -070031
Philip P. Moltmanne683f192017-06-23 14:05:04 -070032import android.Manifest;
Svet Ganovad0a49b2018-10-29 10:07:08 -070033import android.annotation.NonNull;
34import android.annotation.Nullable;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070035import android.app.ActivityManager;
36import android.app.ActivityThread;
37import android.app.AppGlobals;
38import android.app.AppOpsManager;
Svet Ganov8455ba22019-01-02 13:05:56 -080039import android.app.AppOpsManager.HistoricalOps;
Dianne Hackbornd5254412018-05-11 18:02:58 -070040import android.app.AppOpsManagerInternal;
Svet Ganovd873ae62018-06-25 16:39:23 -070041import android.app.AppOpsManagerInternal.CheckOpsDelegate;
Suprabh Shukla3017fe42018-11-08 19:00:01 -080042import android.content.BroadcastReceiver;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070043import android.content.ContentResolver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070044import android.content.Context;
Suprabh Shukla3017fe42018-11-08 19:00:01 -080045import android.content.Intent;
46import android.content.IntentFilter;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070047import android.content.pm.ApplicationInfo;
48import android.content.pm.IPackageManager;
49import android.content.pm.PackageManager;
50import android.content.pm.PackageManagerInternal;
51import android.content.pm.UserInfo;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070052import android.database.ContentObserver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070053import android.media.AudioAttributes;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070054import android.net.Uri;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070055import android.os.AsyncTask;
56import android.os.Binder;
57import android.os.Bundle;
58import android.os.Handler;
59import android.os.IBinder;
60import android.os.Process;
Svet Ganov8455ba22019-01-02 13:05:56 -080061import android.os.RemoteCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070062import android.os.RemoteException;
63import android.os.ResultReceiver;
64import android.os.ServiceManager;
65import android.os.ShellCallback;
66import android.os.ShellCommand;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070067import android.os.SystemClock;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070068import android.os.UserHandle;
69import android.os.UserManager;
Sudheer Shanka98cb3f02018-08-17 16:10:29 -070070import android.os.storage.StorageManager;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070071import android.os.storage.StorageManagerInternal;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070072import android.provider.Settings;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070073import android.util.ArrayMap;
74import android.util.ArraySet;
75import android.util.AtomicFile;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070076import android.util.KeyValueListParser;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070077import android.util.Slog;
78import android.util.SparseArray;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -070079import android.util.SparseBooleanArray;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070080import android.util.SparseIntArray;
81import android.util.TimeUtils;
82import android.util.Xml;
83
Todd Kennedy556efba2018-11-15 07:43:55 -080084import com.android.internal.annotations.GuardedBy;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070085import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080086import com.android.internal.app.IAppOpsActiveCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070087import com.android.internal.app.IAppOpsCallback;
Svet Ganovb3d2ae22018-12-17 22:06:15 -080088import com.android.internal.app.IAppOpsNotedCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070089import com.android.internal.app.IAppOpsService;
90import com.android.internal.os.Zygote;
91import com.android.internal.util.ArrayUtils;
92import com.android.internal.util.DumpUtils;
93import com.android.internal.util.FastXmlSerializer;
94import com.android.internal.util.Preconditions;
95import com.android.internal.util.XmlUtils;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080096import com.android.internal.util.function.pooled.PooledLambda;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -050097
Svet Ganov8455ba22019-01-02 13:05:56 -080098import com.android.server.LocalServices;
99import com.android.server.LockGuard;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700100import libcore.util.EmptyArray;
101
102import org.xmlpull.v1.XmlPullParser;
103import org.xmlpull.v1.XmlPullParserException;
104import org.xmlpull.v1.XmlSerializer;
105
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800106import java.io.File;
107import java.io.FileDescriptor;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800108import java.io.FileInputStream;
109import java.io.FileNotFoundException;
110import java.io.FileOutputStream;
111import java.io.IOException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800112import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100113import java.nio.charset.StandardCharsets;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700114import java.text.SimpleDateFormat;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800115import java.util.ArrayList;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700116import java.util.Arrays;
Svetoslav215b44a2015-08-04 19:03:40 -0700117import java.util.Collections;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700118import java.util.Date;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800119import java.util.HashMap;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800120import java.util.Iterator;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800121import java.util.List;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700122import java.util.Map;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800123
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800124public class AppOpsService extends IAppOpsService.Stub {
125 static final String TAG = "AppOps";
Dianne Hackborn35654b62013-01-14 17:38:02 -0800126 static final boolean DEBUG = false;
127
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700128 private static final int NO_VERSION = -1;
129 /** Increment by one every time and add the corresponding upgrade logic in
130 * {@link #upgradeLocked(int)} below. The first version was 1 */
131 private static final int CURRENT_VERSION = 1;
132
Dianne Hackborn35654b62013-01-14 17:38:02 -0800133 // Write at most every 30 minutes.
134 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800135
Svet Ganov3a95f832018-03-23 17:44:30 -0700136 // Constant meaning that any UID should be matched when dispatching callbacks
137 private static final int UID_ANY = -2;
138
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700139 // Map from process states to the uid states we track.
140 private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
141 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
142 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
143 UID_STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
144 UID_STATE_FOREGROUND_SERVICE, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
145 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
146 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
147 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
148 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
149 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_BACKUP
150 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_SERVICE
151 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_RECEIVER
152 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
153 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
154 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HOME
155 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
156 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
157 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
158 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_RECENT
159 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
160 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT
161 };
162
163 static final String[] UID_STATE_NAMES = new String[] {
164 "pers ", // UID_STATE_PERSISTENT
165 "top ", // UID_STATE_TOP
166 "fgsvc", // UID_STATE_FOREGROUND_SERVICE
167 "fg ", // UID_STATE_FOREGROUND
168 "bg ", // UID_STATE_BACKGROUND
169 "cch ", // UID_STATE_CACHED
170 };
171
172 static final String[] UID_STATE_TIME_ATTRS = new String[] {
173 "tp", // UID_STATE_PERSISTENT
174 "tt", // UID_STATE_TOP
175 "tfs", // UID_STATE_FOREGROUND_SERVICE
176 "tf", // UID_STATE_FOREGROUND
177 "tb", // UID_STATE_BACKGROUND
178 "tc", // UID_STATE_CACHED
179 };
180
181 static final String[] UID_STATE_REJECT_ATTRS = new String[] {
182 "rp", // UID_STATE_PERSISTENT
183 "rt", // UID_STATE_TOP
184 "rfs", // UID_STATE_FOREGROUND_SERVICE
185 "rf", // UID_STATE_FOREGROUND
186 "rb", // UID_STATE_BACKGROUND
187 "rc", // UID_STATE_CACHED
188 };
189
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800190 Context mContext;
191 final AtomicFile mFile;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800192 final Handler mHandler;
193
Dianne Hackbornd5254412018-05-11 18:02:58 -0700194 private final AppOpsManagerInternalImpl mAppOpsManagerInternal
195 = new AppOpsManagerInternalImpl();
196
Dianne Hackborn35654b62013-01-14 17:38:02 -0800197 boolean mWriteScheduled;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800198 boolean mFastWriteScheduled;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800199 final Runnable mWriteRunner = new Runnable() {
200 public void run() {
201 synchronized (AppOpsService.this) {
202 mWriteScheduled = false;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800203 mFastWriteScheduled = false;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800204 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
205 @Override protected Void doInBackground(Void... params) {
206 writeState();
207 return null;
208 }
209 };
210 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
211 }
212 }
213 };
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800214
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700215 @VisibleForTesting
216 final SparseArray<UidState> mUidStates = new SparseArray<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800217
Svet Ganov8455ba22019-01-02 13:05:56 -0800218 private final HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this);
219
Dianne Hackborn9fb93502018-06-18 12:29:44 -0700220 long mLastRealtime;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700221
Ruben Brunk29931bc2016-03-11 00:24:26 -0800222 /*
223 * These are app op restrictions imposed per user from various parties.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800224 */
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700225 private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
Jason Monk62062992014-05-06 09:55:28 -0400226
Dianne Hackbornd5254412018-05-11 18:02:58 -0700227 SparseIntArray mProfileOwners;
228
Todd Kennedy556efba2018-11-15 07:43:55 -0800229 @GuardedBy("this")
Svet Ganovd873ae62018-06-25 16:39:23 -0700230 private CheckOpsDelegate mCheckOpsDelegate;
231
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700232 /**
233 * All times are in milliseconds. These constants are kept synchronized with the system
234 * global Settings. Any access to this class or its fields should be done while
235 * holding the AppOpsService lock.
236 */
237 private final class Constants extends ContentObserver {
238 // Key names stored in the settings value.
Dianne Hackborne93ab412018-05-14 17:52:30 -0700239 private static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
240 private static final String KEY_FG_SERVICE_STATE_SETTLE_TIME
241 = "fg_service_state_settle_time";
242 private static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700243
244 /**
Dianne Hackborne93ab412018-05-14 17:52:30 -0700245 * How long we want for a drop in uid state from top to settle before applying it.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700246 * @see Settings.Global#APP_OPS_CONSTANTS
Dianne Hackborne93ab412018-05-14 17:52:30 -0700247 * @see #KEY_TOP_STATE_SETTLE_TIME
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700248 */
Dianne Hackborne93ab412018-05-14 17:52:30 -0700249 public long TOP_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700250
Dianne Hackborne93ab412018-05-14 17:52:30 -0700251 /**
252 * How long we want for a drop in uid state from foreground to settle before applying it.
253 * @see Settings.Global#APP_OPS_CONSTANTS
254 * @see #KEY_FG_SERVICE_STATE_SETTLE_TIME
255 */
256 public long FG_SERVICE_STATE_SETTLE_TIME;
257
258 /**
259 * How long we want for a drop in uid state from background to settle before applying it.
260 * @see Settings.Global#APP_OPS_CONSTANTS
261 * @see #KEY_BG_STATE_SETTLE_TIME
262 */
263 public long BG_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700264
265 private final KeyValueListParser mParser = new KeyValueListParser(',');
266 private ContentResolver mResolver;
267
268 public Constants(Handler handler) {
269 super(handler);
270 updateConstants();
271 }
272
273 public void startMonitoring(ContentResolver resolver) {
274 mResolver = resolver;
275 mResolver.registerContentObserver(
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700276 Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700277 false, this);
278 updateConstants();
279 }
280
281 @Override
282 public void onChange(boolean selfChange, Uri uri) {
283 updateConstants();
284 }
285
286 private void updateConstants() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700287 String value = mResolver != null ? Settings.Global.getString(mResolver,
288 Settings.Global.APP_OPS_CONSTANTS) : "";
289
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700290 synchronized (AppOpsService.this) {
291 try {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700292 mParser.setString(value);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700293 } catch (IllegalArgumentException e) {
294 // Failed to parse the settings string, log this and move on
295 // with defaults.
296 Slog.e(TAG, "Bad app ops settings", e);
297 }
Dianne Hackborne93ab412018-05-14 17:52:30 -0700298 TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
299 KEY_TOP_STATE_SETTLE_TIME, 30 * 1000L);
300 FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
301 KEY_FG_SERVICE_STATE_SETTLE_TIME, 10 * 1000L);
302 BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
303 KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700304 }
305 }
306
307 void dump(PrintWriter pw) {
308 pw.println(" Settings:");
309
Dianne Hackborne93ab412018-05-14 17:52:30 -0700310 pw.print(" "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("=");
311 TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700312 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700313 pw.print(" "); pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME); pw.print("=");
314 TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700315 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700316 pw.print(" "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("=");
317 TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700318 pw.println();
319 }
320 }
321
322 private final Constants mConstants;
323
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700324 @VisibleForTesting
325 static final class UidState {
Svet Ganov2af57082015-07-30 08:44:20 -0700326 public final int uid;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700327
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700328 public int state = UID_STATE_CACHED;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700329 public int pendingState = UID_STATE_CACHED;
330 public long pendingStateCommitTime;
331
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700332 public int startNesting;
Svet Ganov2af57082015-07-30 08:44:20 -0700333 public ArrayMap<String, Ops> pkgOps;
334 public SparseIntArray opModes;
335
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700336 // true indicates there is an interested observer, false there isn't but it has such an op
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700337 public SparseBooleanArray foregroundOps;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700338 public boolean hasForegroundWatchers;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700339
Svet Ganov2af57082015-07-30 08:44:20 -0700340 public UidState(int uid) {
341 this.uid = uid;
342 }
343
344 public void clear() {
345 pkgOps = null;
346 opModes = null;
347 }
348
349 public boolean isDefault() {
350 return (pkgOps == null || pkgOps.isEmpty())
351 && (opModes == null || opModes.size() <= 0);
352 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700353
354 int evalMode(int mode) {
355 if (mode == AppOpsManager.MODE_FOREGROUND) {
Dianne Hackborne93ab412018-05-14 17:52:30 -0700356 return state <= UID_STATE_LAST_NON_RESTRICTED
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700357 ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
358 }
359 return mode;
360 }
361
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700362 private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
363 SparseBooleanArray which) {
364 boolean curValue = which.get(op, false);
365 ArraySet<ModeCallback> callbacks = watchers.get(op);
366 if (callbacks != null) {
367 for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
368 if ((callbacks.valueAt(cbi).mFlags
369 & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
370 hasForegroundWatchers = true;
371 curValue = true;
372 }
373 }
374 }
375 which.put(op, curValue);
376 }
377
378 public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700379 SparseBooleanArray which = null;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700380 hasForegroundWatchers = false;
381 if (opModes != null) {
382 for (int i = opModes.size() - 1; i >= 0; i--) {
383 if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
384 if (which == null) {
385 which = new SparseBooleanArray();
386 }
387 evalForegroundWatchers(opModes.keyAt(i), watchers, which);
388 }
389 }
390 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700391 if (pkgOps != null) {
392 for (int i = pkgOps.size() - 1; i >= 0; i--) {
393 Ops ops = pkgOps.valueAt(i);
394 for (int j = ops.size() - 1; j >= 0; j--) {
395 if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
396 if (which == null) {
397 which = new SparseBooleanArray();
398 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700399 evalForegroundWatchers(ops.keyAt(j), watchers, which);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700400 }
401 }
402 }
403 }
404 foregroundOps = which;
405 }
Svet Ganov2af57082015-07-30 08:44:20 -0700406 }
407
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700408 final static class Ops extends SparseArray<Op> {
409 final String packageName;
410 final UidState uidState;
411 final boolean isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800412
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700413 Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800414 packageName = _packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700415 uidState = _uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400416 isPrivileged = _isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800417 }
418 }
419
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700420 final static class Op {
421 final UidState uidState;
422 final int uid;
423 final String packageName;
424 final int op;
425 int proxyUid = -1;
426 String proxyPackageName;
427 int mode;
428 int duration;
429 long time[] = new long[_NUM_UID_STATE];
430 long rejectTime[] = new long[_NUM_UID_STATE];
431 int startNesting;
432 long startRealtime;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800433
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700434 Op(UidState _uidState, String _packageName, int _op) {
435 uidState = _uidState;
436 uid = _uidState.uid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700437 packageName = _packageName;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800438 op = _op;
David Braunf5d83192013-09-16 13:43:51 -0700439 mode = AppOpsManager.opToDefaultMode(op);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800440 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700441
442 boolean hasAnyTime() {
443 for (int i = 0; i < AppOpsManager._NUM_UID_STATE; i++) {
444 if (time[i] != 0) {
445 return true;
446 }
447 if (rejectTime[i] != 0) {
448 return true;
449 }
450 }
451 return false;
452 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700453
454 int getMode() {
455 return uidState.evalMode(mode);
456 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800457 }
458
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800459 final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
460 final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
461 final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
462 final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800463 final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>();
Dianne Hackborn68d76552017-02-27 15:32:03 -0800464 final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800465
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700466 final class ModeCallback implements DeathRecipient {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800467 final IAppOpsCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700468 final int mWatchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700469 final int mFlags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700470 final int mCallingUid;
471 final int mCallingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800472
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700473 ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700474 int callingPid) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800475 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700476 mWatchingUid = watchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700477 mFlags = flags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700478 mCallingUid = callingUid;
479 mCallingPid = callingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800480 try {
481 mCallback.asBinder().linkToDeath(this, 0);
482 } catch (RemoteException e) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800483 /*ignored*/
Dianne Hackbornc2293022013-02-06 23:14:49 -0800484 }
485 }
486
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700487 public boolean isWatchingUid(int uid) {
488 return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
489 }
490
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700491 @Override
492 public String toString() {
493 StringBuilder sb = new StringBuilder(128);
494 sb.append("ModeCallback{");
495 sb.append(Integer.toHexString(System.identityHashCode(this)));
496 sb.append(" watchinguid=");
497 UserHandle.formatUid(sb, mWatchingUid);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700498 sb.append(" flags=0x");
499 sb.append(Integer.toHexString(mFlags));
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700500 sb.append(" from uid=");
501 UserHandle.formatUid(sb, mCallingUid);
502 sb.append(" pid=");
503 sb.append(mCallingPid);
504 sb.append('}');
505 return sb.toString();
506 }
507
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700508 void unlinkToDeath() {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800509 mCallback.asBinder().unlinkToDeath(this, 0);
510 }
511
512 @Override
513 public void binderDied() {
514 stopWatchingMode(mCallback);
515 }
516 }
517
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700518 final class ActiveCallback implements DeathRecipient {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800519 final IAppOpsActiveCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700520 final int mWatchingUid;
521 final int mCallingUid;
522 final int mCallingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800523
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700524 ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700525 int callingPid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800526 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700527 mWatchingUid = watchingUid;
528 mCallingUid = callingUid;
529 mCallingPid = callingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800530 try {
531 mCallback.asBinder().linkToDeath(this, 0);
532 } catch (RemoteException e) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800533 /*ignored*/
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800534 }
535 }
536
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700537 @Override
538 public String toString() {
539 StringBuilder sb = new StringBuilder(128);
540 sb.append("ActiveCallback{");
541 sb.append(Integer.toHexString(System.identityHashCode(this)));
542 sb.append(" watchinguid=");
543 UserHandle.formatUid(sb, mWatchingUid);
544 sb.append(" from uid=");
545 UserHandle.formatUid(sb, mCallingUid);
546 sb.append(" pid=");
547 sb.append(mCallingPid);
548 sb.append('}');
549 return sb.toString();
550 }
551
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700552 void destroy() {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800553 mCallback.asBinder().unlinkToDeath(this, 0);
554 }
555
556 @Override
557 public void binderDied() {
558 stopWatchingActive(mCallback);
559 }
560 }
561
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800562 final class NotedCallback implements DeathRecipient {
563 final IAppOpsNotedCallback mCallback;
564 final int mWatchingUid;
565 final int mCallingUid;
566 final int mCallingPid;
567
568 NotedCallback(IAppOpsNotedCallback callback, int watchingUid, int callingUid,
569 int callingPid) {
570 mCallback = callback;
571 mWatchingUid = watchingUid;
572 mCallingUid = callingUid;
573 mCallingPid = callingPid;
574 try {
575 mCallback.asBinder().linkToDeath(this, 0);
576 } catch (RemoteException e) {
577 /*ignored*/
578 }
579 }
580
581 @Override
582 public String toString() {
583 StringBuilder sb = new StringBuilder(128);
584 sb.append("NotedCallback{");
585 sb.append(Integer.toHexString(System.identityHashCode(this)));
586 sb.append(" watchinguid=");
587 UserHandle.formatUid(sb, mWatchingUid);
588 sb.append(" from uid=");
589 UserHandle.formatUid(sb, mCallingUid);
590 sb.append(" pid=");
591 sb.append(mCallingPid);
592 sb.append('}');
593 return sb.toString();
594 }
595
596 void destroy() {
597 mCallback.asBinder().unlinkToDeath(this, 0);
598 }
599
600 @Override
601 public void binderDied() {
602 stopWatchingNoted(mCallback);
603 }
604 }
605
Svet Ganova7a0db62018-02-27 20:08:01 -0800606 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700607
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700608 final class ClientState extends Binder implements DeathRecipient {
Svet Ganovf7b47252018-02-26 11:11:27 -0800609 final ArrayList<Op> mStartedOps = new ArrayList<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700610 final IBinder mAppToken;
611 final int mPid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700612
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700613 ClientState(IBinder appToken) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700614 mAppToken = appToken;
615 mPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -0800616 // Watch only for remote processes dying
617 if (!(appToken instanceof Binder)) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700618 try {
619 mAppToken.linkToDeath(this, 0);
620 } catch (RemoteException e) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800621 /* do nothing */
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700622 }
623 }
624 }
625
626 @Override
627 public String toString() {
628 return "ClientState{" +
629 "mAppToken=" + mAppToken +
Svet Ganovf7b47252018-02-26 11:11:27 -0800630 ", " + "pid=" + mPid +
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700631 '}';
632 }
633
634 @Override
635 public void binderDied() {
636 synchronized (AppOpsService.this) {
637 for (int i=mStartedOps.size()-1; i>=0; i--) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800638 finishOperationLocked(mStartedOps.get(i), /*finishNested*/ true);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700639 }
640 mClients.remove(mAppToken);
641 }
642 }
643 }
644
Jeff Brown6f357d32014-01-15 20:40:55 -0800645 public AppOpsService(File storagePath, Handler handler) {
Jeff Sharkey5f3e9342017-03-13 14:53:11 -0600646 LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
Dianne Hackborne17b4452018-01-10 13:15:40 -0800647 mFile = new AtomicFile(storagePath, "appops");
Jeff Brown6f357d32014-01-15 20:40:55 -0800648 mHandler = handler;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700649 mConstants = new Constants(mHandler);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800650 readState();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800651 }
David Braunf5d83192013-09-16 13:43:51 -0700652
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800653 public void publish(Context context) {
654 mContext = context;
655 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
Dianne Hackbornd5254412018-05-11 18:02:58 -0700656 LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800657 }
658
Dianne Hackborn514074f2013-02-11 10:52:46 -0800659 public void systemReady() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700660 mConstants.startMonitoring(mContext.getContentResolver());
Svet Ganov8455ba22019-01-02 13:05:56 -0800661 mHistoricalRegistry.systemReady(mContext.getContentResolver());
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700662
Dianne Hackborn514074f2013-02-11 10:52:46 -0800663 synchronized (this) {
664 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700665 for (int i = mUidStates.size() - 1; i >= 0; i--) {
666 UidState uidState = mUidStates.valueAt(i);
667
668 String[] packageNames = getPackagesForUid(uidState.uid);
669 if (ArrayUtils.isEmpty(packageNames)) {
670 uidState.clear();
671 mUidStates.removeAt(i);
672 changed = true;
673 continue;
674 }
675
676 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
677 if (pkgs == null) {
678 continue;
679 }
680
Dianne Hackborn514074f2013-02-11 10:52:46 -0800681 Iterator<Ops> it = pkgs.values().iterator();
682 while (it.hasNext()) {
683 Ops ops = it.next();
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700684 int curUid = -1;
Dianne Hackborn514074f2013-02-11 10:52:46 -0800685 try {
Jeff Sharkeycd654482016-01-08 17:42:11 -0700686 curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
687 PackageManager.MATCH_UNINSTALLED_PACKAGES,
Svet Ganov2af57082015-07-30 08:44:20 -0700688 UserHandle.getUserId(ops.uidState.uid));
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700689 } catch (RemoteException ignored) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800690 }
Svet Ganov2af57082015-07-30 08:44:20 -0700691 if (curUid != ops.uidState.uid) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800692 Slog.i(TAG, "Pruning old package " + ops.packageName
Svet Ganov2af57082015-07-30 08:44:20 -0700693 + "/" + ops.uidState + ": new uid=" + curUid);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800694 it.remove();
695 changed = true;
696 }
697 }
Svet Ganov2af57082015-07-30 08:44:20 -0700698
699 if (uidState.isDefault()) {
700 mUidStates.removeAt(i);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800701 }
702 }
703 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800704 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800705 }
706 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700707
Suprabh Shukla3017fe42018-11-08 19:00:01 -0800708 final IntentFilter packageSuspendFilter = new IntentFilter();
709 packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
710 packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
711 mContext.registerReceiver(new BroadcastReceiver() {
712 @Override
713 public void onReceive(Context context, Intent intent) {
714 final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
715 final String[] changedPkgs = intent.getStringArrayExtra(
716 Intent.EXTRA_CHANGED_PACKAGE_LIST);
717 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(OP_PLAY_AUDIO);
718 for (int i = 0; i < changedUids.length; i++) {
719 final int changedUid = changedUids[i];
720 final String changedPkg = changedPkgs[i];
721 // We trust packagemanager to insert matching uid and packageNames in the extras
722 mHandler.sendMessage(PooledLambda.obtainMessage(AppOpsService::notifyOpChanged,
723 AppOpsService.this, callbacks, OP_PLAY_AUDIO, changedUid, changedPkg));
724 }
725 }
726 }, packageSuspendFilter);
727
Suprabh Shuklaaef25132017-01-23 18:09:03 -0800728 PackageManagerInternal packageManagerInternal = LocalServices.getService(
729 PackageManagerInternal.class);
730 packageManagerInternal.setExternalSourcesPolicy(
731 new PackageManagerInternal.ExternalSourcesPolicy() {
732 @Override
733 public int getPackageTrustedToInstallApps(String packageName, int uid) {
734 int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
735 uid, packageName);
736 switch (appOpMode) {
737 case AppOpsManager.MODE_ALLOWED:
738 return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
739 case AppOpsManager.MODE_ERRORED:
740 return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
741 default:
742 return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
743 }
744 }
745 });
746
Jeff Sharkey10ec9d82018-11-28 14:52:45 -0700747 if (!StorageManager.hasIsolatedStorage()) {
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700748 StorageManagerInternal storageManagerInternal = LocalServices.getService(
749 StorageManagerInternal.class);
750 storageManagerInternal.addExternalStoragePolicy(
751 new StorageManagerInternal.ExternalStorageMountPolicy() {
752 @Override
753 public int getMountMode(int uid, String packageName) {
754 if (Process.isIsolated(uid)) {
755 return Zygote.MOUNT_EXTERNAL_NONE;
756 }
757 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
758 packageName) != AppOpsManager.MODE_ALLOWED) {
759 return Zygote.MOUNT_EXTERNAL_NONE;
760 }
761 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
762 packageName) != AppOpsManager.MODE_ALLOWED) {
763 return Zygote.MOUNT_EXTERNAL_READ;
764 }
765 return Zygote.MOUNT_EXTERNAL_WRITE;
Svet Ganov6ee871e2015-07-10 14:29:33 -0700766 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700767
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700768 @Override
769 public boolean hasExternalStorage(int uid, String packageName) {
770 final int mountMode = getMountMode(uid, packageName);
771 return mountMode == Zygote.MOUNT_EXTERNAL_READ
772 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
773 }
774 });
775 }
Dianne Hackborn514074f2013-02-11 10:52:46 -0800776 }
777
778 public void packageRemoved(int uid, String packageName) {
779 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700780 UidState uidState = mUidStates.get(uid);
781 if (uidState == null) {
782 return;
783 }
784
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800785 Ops ops = null;
Svet Ganov2af57082015-07-30 08:44:20 -0700786
787 // Remove any package state if such.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800788 if (uidState.pkgOps != null) {
789 ops = uidState.pkgOps.remove(packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700790 }
791
792 // If we just nuked the last package state check if the UID is valid.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800793 if (ops != null && uidState.pkgOps.isEmpty()
Svet Ganov2af57082015-07-30 08:44:20 -0700794 && getPackagesForUid(uid).length <= 0) {
795 mUidStates.remove(uid);
796 }
797
Svet Ganova7a0db62018-02-27 20:08:01 -0800798 // Finish ops other packages started on behalf of the package.
799 final int clientCount = mClients.size();
800 for (int i = 0; i < clientCount; i++) {
801 final ClientState client = mClients.valueAt(i);
802 if (client.mStartedOps == null) {
803 continue;
804 }
805 final int opCount = client.mStartedOps.size();
806 for (int j = opCount - 1; j >= 0; j--) {
807 final Op op = client.mStartedOps.get(j);
808 if (uid == op.uid && packageName.equals(op.packageName)) {
809 finishOperationLocked(op, /*finishNested*/ true);
810 client.mStartedOps.remove(j);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700811 if (op.startNesting <= 0) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800812 scheduleOpActiveChangedIfNeededLocked(op.op,
813 uid, packageName, false);
814 }
815 }
816 }
817 }
818
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800819 if (ops != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700820 scheduleFastWriteLocked();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800821
822 final int opCount = ops.size();
823 for (int i = 0; i < opCount; i++) {
824 final Op op = ops.valueAt(i);
825 if (op.duration == -1) {
826 scheduleOpActiveChangedIfNeededLocked(
827 op.op, op.uid, op.packageName, false);
828 }
829 }
Dianne Hackborn514074f2013-02-11 10:52:46 -0800830 }
831 }
832 }
833
834 public void uidRemoved(int uid) {
835 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700836 if (mUidStates.indexOfKey(uid) >= 0) {
837 mUidStates.remove(uid);
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800838 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800839 }
840 }
841 }
842
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700843 public void updateUidProcState(int uid, int procState) {
844 synchronized (this) {
845 final UidState uidState = getUidStateLocked(uid, true);
846 final int newState = PROCESS_STATE_TO_UID_STATE[procState];
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700847 if (uidState != null && uidState.pendingState != newState) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700848 final int oldPendingState = uidState.pendingState;
849 uidState.pendingState = newState;
Dianne Hackborne93ab412018-05-14 17:52:30 -0700850 if (newState < uidState.state || newState <= UID_STATE_LAST_NON_RESTRICTED) {
851 // We are moving to a more important state, or the new state is in the
852 // foreground, then always do it immediately.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700853 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700854 } else if (uidState.pendingStateCommitTime == 0) {
855 // We are moving to a less important state for the first time,
856 // delay the application for a bit.
Dianne Hackborne93ab412018-05-14 17:52:30 -0700857 final long settleTime;
858 if (uidState.state <= UID_STATE_TOP) {
859 settleTime = mConstants.TOP_STATE_SETTLE_TIME;
860 } else if (uidState.state <= UID_STATE_FOREGROUND_SERVICE) {
861 settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
862 } else {
863 settleTime = mConstants.BG_STATE_SETTLE_TIME;
864 }
Dianne Hackborn9fb93502018-06-18 12:29:44 -0700865 uidState.pendingStateCommitTime = SystemClock.elapsedRealtime() + settleTime;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700866 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700867 if (uidState.startNesting != 0) {
868 // There is some actively running operation... need to find it
869 // and appropriately update its state.
870 final long now = System.currentTimeMillis();
871 for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
872 final Ops ops = uidState.pkgOps.valueAt(i);
873 for (int j = ops.size() - 1; j >= 0; j--) {
874 final Op op = ops.valueAt(j);
875 if (op.startNesting > 0) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700876 op.time[oldPendingState] = now;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700877 op.time[newState] = now;
878 }
879 }
880 }
881 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700882 }
883 }
884 }
885
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800886 public void shutdown() {
887 Slog.w(TAG, "Writing app ops before shutdown...");
Dianne Hackborn35654b62013-01-14 17:38:02 -0800888 boolean doWrite = false;
889 synchronized (this) {
890 if (mWriteScheduled) {
891 mWriteScheduled = false;
892 doWrite = true;
893 }
894 }
895 if (doWrite) {
896 writeState();
897 }
898 }
899
Dianne Hackborn72e39832013-01-18 18:36:09 -0800900 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
901 ArrayList<AppOpsManager.OpEntry> resOps = null;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700902 final long elapsedNow = SystemClock.elapsedRealtime();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800903 if (ops == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700904 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800905 for (int j=0; j<pkgOps.size(); j++) {
906 Op curOp = pkgOps.valueAt(j);
Amith Yamasania1ce9632018-05-28 20:50:48 -0700907 final boolean running = curOp.duration == -1;
908 long duration = running
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700909 ? (elapsedNow - curOp.startRealtime)
910 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800911 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Amith Yamasania1ce9632018-05-28 20:50:48 -0700912 curOp.rejectTime, (int) duration, running, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700913 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800914 }
915 } else {
916 for (int j=0; j<ops.length; j++) {
917 Op curOp = pkgOps.get(ops[j]);
918 if (curOp != null) {
919 if (resOps == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700920 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800921 }
Amith Yamasania1ce9632018-05-28 20:50:48 -0700922 final boolean running = curOp.duration == -1;
923 final long duration = running
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700924 ? (elapsedNow - curOp.startRealtime)
925 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800926 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Amith Yamasania1ce9632018-05-28 20:50:48 -0700927 curOp.rejectTime, (int) duration, running, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700928 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800929 }
930 }
931 }
932 return resOps;
933 }
934
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700935 private ArrayList<AppOpsManager.OpEntry> collectOps(SparseIntArray uidOps, int[] ops) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -0800936 if (uidOps == null) {
937 return null;
938 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700939 ArrayList<AppOpsManager.OpEntry> resOps = null;
940 if (ops == null) {
941 resOps = new ArrayList<>();
942 for (int j=0; j<uidOps.size(); j++) {
943 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(j), uidOps.valueAt(j),
944 0, 0, 0, -1, null));
945 }
946 } else {
947 for (int j=0; j<ops.length; j++) {
948 int index = uidOps.indexOfKey(ops[j]);
949 if (index >= 0) {
950 if (resOps == null) {
951 resOps = new ArrayList<>();
952 }
953 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(index), uidOps.valueAt(index),
954 0, 0, 0, -1, null));
955 }
956 }
957 }
958 return resOps;
959 }
960
Dianne Hackborn35654b62013-01-14 17:38:02 -0800961 @Override
962 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
963 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
964 Binder.getCallingPid(), Binder.getCallingUid(), null);
965 ArrayList<AppOpsManager.PackageOps> res = null;
966 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700967 final int uidStateCount = mUidStates.size();
968 for (int i = 0; i < uidStateCount; i++) {
969 UidState uidState = mUidStates.valueAt(i);
970 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
971 continue;
972 }
973 ArrayMap<String, Ops> packages = uidState.pkgOps;
974 final int packageCount = packages.size();
975 for (int j = 0; j < packageCount; j++) {
976 Ops pkgOps = packages.valueAt(j);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800977 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800978 if (resOps != null) {
979 if (res == null) {
980 res = new ArrayList<AppOpsManager.PackageOps>();
981 }
982 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700983 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800984 res.add(resPackage);
985 }
986 }
987 }
988 }
989 return res;
990 }
991
992 @Override
Dianne Hackborn72e39832013-01-18 18:36:09 -0800993 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
994 int[] ops) {
995 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
996 Binder.getCallingPid(), Binder.getCallingUid(), null);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000997 String resolvedPackageName = resolvePackageName(uid, packageName);
998 if (resolvedPackageName == null) {
999 return Collections.emptyList();
1000 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08001001 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001002 Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
1003 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001004 if (pkgOps == null) {
1005 return null;
1006 }
1007 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
1008 if (resOps == null) {
1009 return null;
1010 }
1011 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
1012 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -07001013 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001014 res.add(resPackage);
1015 return res;
1016 }
1017 }
1018
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001019 @Override
Svet Ganov8455ba22019-01-02 13:05:56 -08001020 public void getHistoricalOps(int uid, @NonNull String packageName,
1021 @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
1022 @NonNull RemoteCallback callback) {
1023 Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
1024 "uid must be " + Process.INVALID_UID + " or non negative");
Svet Ganovad0a49b2018-10-29 10:07:08 -07001025 Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
1026 "beginTimeMillis must be non negative and lesser than endTimeMillis");
Svet Ganov8455ba22019-01-02 13:05:56 -08001027 Preconditions.checkNotNull(callback, "callback cannot be null");
1028 checkValidOpsOrNull(opNames);
Svet Ganovad0a49b2018-10-29 10:07:08 -07001029
1030 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
Svet Ganov8455ba22019-01-02 13:05:56 -08001031 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
Svet Ganovad0a49b2018-10-29 10:07:08 -07001032
Svet Ganov8455ba22019-01-02 13:05:56 -08001033 if (mHistoricalRegistry.getMode() == AppOpsManager.HISTORICAL_MODE_DISABLED) {
1034 // TODO (bug:122218838): Remove once the feature fully enabled.
1035 getHistoricalPackagesOpsCompat(uid, packageName, opNames, beginTimeMillis,
1036 endTimeMillis, callback);
1037 } else {
1038 // Must not hold the appops lock
1039 mHistoricalRegistry.getHistoricalOps(uid, packageName, opNames,
1040 beginTimeMillis, endTimeMillis, callback);
Svet Ganovad0a49b2018-10-29 10:07:08 -07001041 }
Svet Ganovad0a49b2018-10-29 10:07:08 -07001042 }
1043
Svet Ganov8455ba22019-01-02 13:05:56 -08001044 private void getHistoricalPackagesOpsCompat(int uid, @NonNull String packageName,
1045 @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
1046 @NonNull RemoteCallback callback) {
1047 synchronized (AppOpsService.this) {
1048 final HistoricalOps ops = new HistoricalOps(beginTimeMillis, endTimeMillis);
1049 if (opNames == null) {
1050 opNames = AppOpsManager.getOpStrs();
1051 }
1052 final int uidStateCount = mUidStates.size();
1053 for (int uidIdx = 0; uidIdx < uidStateCount; uidIdx++) {
1054 final UidState uidState = mUidStates.valueAt(uidIdx);
1055 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()
1056 || (uid != Process.INVALID_UID && uid != uidState.uid)) {
1057 continue;
1058 }
1059 final ArrayMap<String, Ops> packages = uidState.pkgOps;
1060 final int packageCount = packages.size();
1061 for (int pkgIdx = 0; pkgIdx < packageCount; pkgIdx++) {
1062 final Ops pkgOps = packages.valueAt(pkgIdx);
1063 if (packageName != null && !packageName.equals(pkgOps.packageName)) {
1064 continue;
1065 }
1066 final int opCount = opNames.length;
1067 for (int opIdx = 0; opIdx < opCount; opIdx++) {
1068 final String opName = opNames[opIdx];
1069 if (!ArrayUtils.contains(opNames, opName)) {
1070 continue;
1071 }
1072 final int opCode = AppOpsManager.strOpToOp(opName);
1073 final Op op = pkgOps.get(opCode);
1074 if (op == null) {
1075 continue;
1076 }
1077 final int stateCount = AppOpsManager._NUM_UID_STATE;
1078 for (int stateIdx = 0; stateIdx < stateCount; stateIdx++) {
1079 if (op.rejectTime[stateIdx] != 0) {
1080 ops.increaseRejectCount(opCode, uidState.uid,
1081 pkgOps.packageName, stateIdx, 1);
1082 } else if (op.time[stateIdx] != 0) {
1083 ops.increaseAccessCount(opCode, uidState.uid,
1084 pkgOps.packageName, stateIdx, 1);
1085 }
1086 }
1087 }
1088 }
1089 }
1090 final Bundle payload = new Bundle();
1091 payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, ops);
1092 callback.sendResult(payload);
Svet Ganovad0a49b2018-10-29 10:07:08 -07001093 }
Svet Ganovad0a49b2018-10-29 10:07:08 -07001094 }
1095
1096 @Override
Svet Ganov8455ba22019-01-02 13:05:56 -08001097 public void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
1098 @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
1099 @NonNull RemoteCallback callback) {
1100 Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
1101 "uid must be " + Process.INVALID_UID + " or non negative");
Svet Ganovad0a49b2018-10-29 10:07:08 -07001102 Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
1103 "beginTimeMillis must be non negative and lesser than endTimeMillis");
Svet Ganov8455ba22019-01-02 13:05:56 -08001104 Preconditions.checkNotNull(callback, "callback cannot be null");
1105 checkValidOpsOrNull(opNames);
Svet Ganovad0a49b2018-10-29 10:07:08 -07001106
1107 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
Svet Ganov8455ba22019-01-02 13:05:56 -08001108 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
Svet Ganovad0a49b2018-10-29 10:07:08 -07001109
Svet Ganov8455ba22019-01-02 13:05:56 -08001110 // Must not hold the appops lock
1111 mHistoricalRegistry.getHistoricalOpsFromDiskRaw(uid, packageName, opNames,
1112 beginTimeMillis, endTimeMillis, callback);
Svet Ganovad0a49b2018-10-29 10:07:08 -07001113 }
1114
1115 @Override
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001116 public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
1117 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1118 Binder.getCallingPid(), Binder.getCallingUid(), null);
1119 synchronized (this) {
1120 UidState uidState = getUidStateLocked(uid, false);
1121 if (uidState == null) {
1122 return null;
1123 }
1124 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState.opModes, ops);
1125 if (resOps == null) {
1126 return null;
1127 }
1128 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
1129 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
1130 null, uidState.uid, resOps);
1131 res.add(resPackage);
1132 return res;
1133 }
1134 }
1135
Dianne Hackborn607b4142013-08-02 18:10:10 -07001136 private void pruneOp(Op op, int uid, String packageName) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001137 if (!op.hasAnyTime()) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001138 Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
1139 false /* uidMismatchExpected */);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001140 if (ops != null) {
1141 ops.remove(op.op);
1142 if (ops.size() <= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -07001143 UidState uidState = ops.uidState;
1144 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001145 if (pkgOps != null) {
1146 pkgOps.remove(ops.packageName);
Svet Ganov2af57082015-07-30 08:44:20 -07001147 if (pkgOps.isEmpty()) {
1148 uidState.pkgOps = null;
1149 }
1150 if (uidState.isDefault()) {
1151 mUidStates.remove(uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001152 }
1153 }
1154 }
1155 }
1156 }
1157 }
1158
Dianne Hackbornd5254412018-05-11 18:02:58 -07001159 void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
1160 if (callingPid == Process.myPid()) {
1161 return;
1162 }
1163 final int callingUser = UserHandle.getUserId(callingUid);
1164 synchronized (this) {
1165 if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
1166 if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
1167 // Profile owners are allowed to change modes but only for apps
1168 // within their user.
1169 return;
1170 }
1171 }
1172 }
1173 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
1174 Binder.getCallingPid(), Binder.getCallingUid(), null);
1175 }
1176
Dianne Hackborn72e39832013-01-18 18:36:09 -08001177 @Override
Svet Ganov2af57082015-07-30 08:44:20 -07001178 public void setUidMode(int code, int uid, int mode) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08001179 if (DEBUG) {
1180 Slog.i(TAG, "uid " + uid + " OP_" + opToName(code) + " := " + modeToName(mode)
1181 + " by uid " + Binder.getCallingUid());
1182 }
1183
Dianne Hackbornd5254412018-05-11 18:02:58 -07001184 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Svet Ganov2af57082015-07-30 08:44:20 -07001185 verifyIncomingOp(code);
1186 code = AppOpsManager.opToSwitch(code);
1187
1188 synchronized (this) {
1189 final int defaultMode = AppOpsManager.opToDefaultMode(code);
1190
1191 UidState uidState = getUidStateLocked(uid, false);
1192 if (uidState == null) {
1193 if (mode == defaultMode) {
1194 return;
1195 }
1196 uidState = new UidState(uid);
1197 uidState.opModes = new SparseIntArray();
1198 uidState.opModes.put(code, mode);
1199 mUidStates.put(uid, uidState);
1200 scheduleWriteLocked();
1201 } else if (uidState.opModes == null) {
1202 if (mode != defaultMode) {
1203 uidState.opModes = new SparseIntArray();
1204 uidState.opModes.put(code, mode);
1205 scheduleWriteLocked();
1206 }
1207 } else {
Hai Zhang2b98fb32018-09-21 15:18:46 -07001208 if (uidState.opModes.indexOfKey(code) >= 0 && uidState.opModes.get(code) == mode) {
Svet Ganov2af57082015-07-30 08:44:20 -07001209 return;
1210 }
1211 if (mode == defaultMode) {
1212 uidState.opModes.delete(code);
1213 if (uidState.opModes.size() <= 0) {
1214 uidState.opModes = null;
1215 }
1216 } else {
1217 uidState.opModes.put(code, mode);
1218 }
1219 scheduleWriteLocked();
1220 }
1221 }
1222
Svetoslav215b44a2015-08-04 19:03:40 -07001223 String[] uidPackageNames = getPackagesForUid(uid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001224 ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
Svet Ganov2af57082015-07-30 08:44:20 -07001225
riddle_hsu40b300f2015-11-23 13:22:03 +08001226 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001227 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001228 if (callbacks != null) {
Svet Ganov2af57082015-07-30 08:44:20 -07001229 final int callbackCount = callbacks.size();
1230 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001231 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08001232 ArraySet<String> changedPackages = new ArraySet<>();
1233 Collections.addAll(changedPackages, uidPackageNames);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001234 if (callbackSpecs == null) {
1235 callbackSpecs = new ArrayMap<>();
1236 }
riddle_hsu40b300f2015-11-23 13:22:03 +08001237 callbackSpecs.put(callback, changedPackages);
1238 }
1239 }
1240
1241 for (String uidPackageName : uidPackageNames) {
1242 callbacks = mPackageModeWatchers.get(uidPackageName);
1243 if (callbacks != null) {
1244 if (callbackSpecs == null) {
1245 callbackSpecs = new ArrayMap<>();
Svet Ganov2af57082015-07-30 08:44:20 -07001246 }
riddle_hsu40b300f2015-11-23 13:22:03 +08001247 final int callbackCount = callbacks.size();
1248 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001249 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08001250 ArraySet<String> changedPackages = callbackSpecs.get(callback);
1251 if (changedPackages == null) {
1252 changedPackages = new ArraySet<>();
1253 callbackSpecs.put(callback, changedPackages);
1254 }
1255 changedPackages.add(uidPackageName);
1256 }
Svet Ganov2af57082015-07-30 08:44:20 -07001257 }
1258 }
1259 }
1260
1261 if (callbackSpecs == null) {
1262 return;
1263 }
1264
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001265 for (int i = 0; i < callbackSpecs.size(); i++) {
1266 final ModeCallback callback = callbackSpecs.keyAt(i);
1267 final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
1268 if (reportedPackageNames == null) {
1269 mHandler.sendMessage(PooledLambda.obtainMessage(
1270 AppOpsService::notifyOpChanged,
1271 this, callback, code, uid, (String) null));
1272
1273 } else {
1274 final int reportedPackageCount = reportedPackageNames.size();
1275 for (int j = 0; j < reportedPackageCount; j++) {
1276 final String reportedPackageName = reportedPackageNames.valueAt(j);
1277 mHandler.sendMessage(PooledLambda.obtainMessage(
1278 AppOpsService::notifyOpChanged,
1279 this, callback, code, uid, reportedPackageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001280 }
1281 }
Svet Ganov2af57082015-07-30 08:44:20 -07001282 }
1283 }
1284
1285 @Override
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001286 public void setMode(int code, int uid, String packageName, int mode) {
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07001287 setMode(code, uid, packageName, mode, true, false);
1288 }
1289
1290 /**
1291 * Sets the mode for a certain op and uid.
1292 *
1293 * @param code The op code to set
1294 * @param uid The UID for which to set
1295 * @param packageName The package for which to set
1296 * @param mode The new mode to set
1297 * @param verifyUid Iff {@code true}, check that the package name belongs to the uid
1298 * @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid ==
1299 * false})
1300 */
1301 private void setMode(int code, int uid, @NonNull String packageName, int mode,
1302 boolean verifyUid, boolean isPrivileged) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001303 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001304 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001305 ArraySet<ModeCallback> repCbs = null;
Dianne Hackbornc2293022013-02-06 23:14:49 -08001306 code = AppOpsManager.opToSwitch(code);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001307 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001308 UidState uidState = getUidStateLocked(uid, false);
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07001309 Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001310 if (op != null) {
1311 if (op.mode != mode) {
1312 op.mode = mode;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001313 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001314 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001315 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001316 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001317 if (cbs != null) {
1318 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001319 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001320 }
1321 repCbs.addAll(cbs);
1322 }
1323 cbs = mPackageModeWatchers.get(packageName);
1324 if (cbs != null) {
1325 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001326 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001327 }
1328 repCbs.addAll(cbs);
1329 }
David Braunf5d83192013-09-16 13:43:51 -07001330 if (mode == AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001331 // If going into the default mode, prune this op
1332 // if there is nothing else interesting in it.
Dianne Hackborn607b4142013-08-02 18:10:10 -07001333 pruneOp(op, uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001334 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001335 scheduleFastWriteLocked();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001336 }
1337 }
1338 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001339 if (repCbs != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001340 mHandler.sendMessage(PooledLambda.obtainMessage(
1341 AppOpsService::notifyOpChanged,
1342 this, repCbs, code, uid, packageName));
Dianne Hackbornc2293022013-02-06 23:14:49 -08001343 }
1344 }
1345
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001346 private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
1347 int uid, String packageName) {
1348 for (int i = 0; i < callbacks.size(); i++) {
1349 final ModeCallback callback = callbacks.valueAt(i);
1350 notifyOpChanged(callback, code, uid, packageName);
1351 }
1352 }
1353
1354 private void notifyOpChanged(ModeCallback callback, int code,
1355 int uid, String packageName) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001356 if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001357 return;
1358 }
1359 // There are components watching for mode changes such as window manager
1360 // and location manager which are in our process. The callbacks in these
1361 // components may require permissions our remote caller does not have.
1362 final long identity = Binder.clearCallingIdentity();
1363 try {
1364 callback.mCallback.opChanged(code, uid, packageName);
1365 } catch (RemoteException e) {
1366 /* ignore */
1367 } finally {
1368 Binder.restoreCallingIdentity(identity);
1369 }
1370 }
1371
1372 private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
1373 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
1374 int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001375 if (cbs == null) {
1376 return callbacks;
1377 }
1378 if (callbacks == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001379 callbacks = new HashMap<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001380 }
Svet Ganov2af57082015-07-30 08:44:20 -07001381 boolean duplicate = false;
Dianne Hackborn68d76552017-02-27 15:32:03 -08001382 final int N = cbs.size();
1383 for (int i=0; i<N; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001384 ModeCallback cb = cbs.valueAt(i);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001385 ArrayList<ChangeRec> reports = callbacks.get(cb);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001386 if (reports == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001387 reports = new ArrayList<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001388 callbacks.put(cb, reports);
Svet Ganov2af57082015-07-30 08:44:20 -07001389 } else {
1390 final int reportCount = reports.size();
1391 for (int j = 0; j < reportCount; j++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001392 ChangeRec report = reports.get(j);
1393 if (report.op == op && report.pkg.equals(packageName)) {
Svet Ganov2af57082015-07-30 08:44:20 -07001394 duplicate = true;
1395 break;
1396 }
1397 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001398 }
Svet Ganov2af57082015-07-30 08:44:20 -07001399 if (!duplicate) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001400 reports.add(new ChangeRec(op, uid, packageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001401 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001402 }
1403 return callbacks;
1404 }
1405
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001406 static final class ChangeRec {
1407 final int op;
1408 final int uid;
1409 final String pkg;
1410
1411 ChangeRec(int _op, int _uid, String _pkg) {
1412 op = _op;
1413 uid = _uid;
1414 pkg = _pkg;
1415 }
1416 }
1417
Dianne Hackborn607b4142013-08-02 18:10:10 -07001418 @Override
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001419 public void resetAllModes(int reqUserId, String reqPackageName) {
1420 final int callingPid = Binder.getCallingPid();
1421 final int callingUid = Binder.getCallingUid();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001422 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
1423 true, true, "resetAllModes", null);
Svet Ganov2af57082015-07-30 08:44:20 -07001424
1425 int reqUid = -1;
1426 if (reqPackageName != null) {
1427 try {
1428 reqUid = AppGlobals.getPackageManager().getPackageUid(
Jeff Sharkeycd654482016-01-08 17:42:11 -07001429 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
Svet Ganov2af57082015-07-30 08:44:20 -07001430 } catch (RemoteException e) {
1431 /* ignore - local call */
1432 }
1433 }
1434
Dianne Hackbornd5254412018-05-11 18:02:58 -07001435 enforceManageAppOpsModes(callingPid, callingUid, reqUid);
1436
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001437 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001438 synchronized (this) {
1439 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -07001440 for (int i = mUidStates.size() - 1; i >= 0; i--) {
1441 UidState uidState = mUidStates.valueAt(i);
1442
1443 SparseIntArray opModes = uidState.opModes;
1444 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
1445 final int uidOpCount = opModes.size();
1446 for (int j = uidOpCount - 1; j >= 0; j--) {
1447 final int code = opModes.keyAt(j);
1448 if (AppOpsManager.opAllowsReset(code)) {
1449 opModes.removeAt(j);
1450 if (opModes.size() <= 0) {
1451 uidState.opModes = null;
1452 }
1453 for (String packageName : getPackagesForUid(uidState.uid)) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001454 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001455 mOpModeWatchers.get(code));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001456 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001457 mPackageModeWatchers.get(packageName));
1458 }
1459 }
1460 }
1461 }
1462
1463 if (uidState.pkgOps == null) {
1464 continue;
1465 }
1466
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001467 if (reqUserId != UserHandle.USER_ALL
Svet Ganov2af57082015-07-30 08:44:20 -07001468 && reqUserId != UserHandle.getUserId(uidState.uid)) {
Alexandra Gherghinad6a98972014-08-04 17:05:34 +01001469 // Skip any ops for a different user
1470 continue;
1471 }
Svet Ganov2af57082015-07-30 08:44:20 -07001472
1473 Map<String, Ops> packages = uidState.pkgOps;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001474 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001475 boolean uidChanged = false;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001476 while (it.hasNext()) {
1477 Map.Entry<String, Ops> ent = it.next();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001478 String packageName = ent.getKey();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001479 if (reqPackageName != null && !reqPackageName.equals(packageName)) {
1480 // Skip any ops for a different package
1481 continue;
1482 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001483 Ops pkgOps = ent.getValue();
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001484 for (int j=pkgOps.size()-1; j>=0; j--) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001485 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn8828d3a2013-09-25 16:47:10 -07001486 if (AppOpsManager.opAllowsReset(curOp.op)
1487 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
David Braunf5d83192013-09-16 13:43:51 -07001488 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001489 changed = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001490 uidChanged = true;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001491 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001492 mOpModeWatchers.get(curOp.op));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001493 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001494 mPackageModeWatchers.get(packageName));
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001495 if (!curOp.hasAnyTime()) {
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001496 pkgOps.removeAt(j);
1497 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001498 }
1499 }
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001500 if (pkgOps.size() == 0) {
1501 it.remove();
1502 }
1503 }
Svet Ganov2af57082015-07-30 08:44:20 -07001504 if (uidState.isDefault()) {
1505 mUidStates.remove(uidState.uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001506 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001507 if (uidChanged) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001508 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001509 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001510 }
Svet Ganov2af57082015-07-30 08:44:20 -07001511
Dianne Hackborn607b4142013-08-02 18:10:10 -07001512 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001513 scheduleFastWriteLocked();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001514 }
1515 }
1516 if (callbacks != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001517 for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
1518 ModeCallback cb = ent.getKey();
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001519 ArrayList<ChangeRec> reports = ent.getValue();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001520 for (int i=0; i<reports.size(); i++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001521 ChangeRec rep = reports.get(i);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001522 mHandler.sendMessage(PooledLambda.obtainMessage(
1523 AppOpsService::notifyOpChanged,
1524 this, cb, rep.op, rep.uid, rep.pkg));
Dianne Hackborn607b4142013-08-02 18:10:10 -07001525 }
1526 }
1527 }
1528 }
1529
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001530 private void evalAllForegroundOpsLocked() {
1531 for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
1532 final UidState uidState = mUidStates.valueAt(uidi);
1533 if (uidState.foregroundOps != null) {
1534 uidState.evalForegroundOps(mOpModeWatchers);
1535 }
1536 }
1537 }
1538
Dianne Hackbornc2293022013-02-06 23:14:49 -08001539 @Override
1540 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001541 startWatchingModeWithFlags(op, packageName, 0, callback);
1542 }
1543
1544 @Override
1545 public void startWatchingModeWithFlags(int op, String packageName, int flags,
1546 IAppOpsCallback callback) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001547 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001548 final int callingUid = Binder.getCallingUid();
1549 final int callingPid = Binder.getCallingPid();
Dianne Hackborn5376edd2018-06-05 13:21:16 -07001550 // TODO: should have a privileged permission to protect this.
1551 // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require
1552 // the USAGE_STATS permission since this can provide information about when an
1553 // app is in the foreground?
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001554 Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
1555 AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001556 if (callback == null) {
1557 return;
1558 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001559 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001560 op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001561 ModeCallback cb = mModeWatchers.get(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001562 if (cb == null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001563 cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001564 mModeWatchers.put(callback.asBinder(), cb);
1565 }
1566 if (op != AppOpsManager.OP_NONE) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001567 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001568 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001569 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001570 mOpModeWatchers.put(op, cbs);
1571 }
1572 cbs.add(cb);
1573 }
1574 if (packageName != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001575 ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001576 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001577 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001578 mPackageModeWatchers.put(packageName, cbs);
1579 }
1580 cbs.add(cb);
1581 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001582 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001583 }
1584 }
1585
1586 @Override
1587 public void stopWatchingMode(IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001588 if (callback == null) {
1589 return;
1590 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001591 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001592 ModeCallback cb = mModeWatchers.remove(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001593 if (cb != null) {
1594 cb.unlinkToDeath();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001595 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001596 ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001597 cbs.remove(cb);
1598 if (cbs.size() <= 0) {
1599 mOpModeWatchers.removeAt(i);
1600 }
1601 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001602 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001603 ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001604 cbs.remove(cb);
1605 if (cbs.size() <= 0) {
1606 mPackageModeWatchers.removeAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001607 }
1608 }
1609 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001610 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001611 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001612 }
1613
1614 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001615 public IBinder getToken(IBinder clientToken) {
1616 synchronized (this) {
1617 ClientState cs = mClients.get(clientToken);
1618 if (cs == null) {
1619 cs = new ClientState(clientToken);
1620 mClients.put(clientToken, cs);
1621 }
1622 return cs;
1623 }
1624 }
1625
Svet Ganovd873ae62018-06-25 16:39:23 -07001626 public CheckOpsDelegate getAppOpsServiceDelegate() {
1627 synchronized (this) {
1628 return mCheckOpsDelegate;
1629 }
1630 }
1631
1632 public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) {
1633 synchronized (this) {
1634 mCheckOpsDelegate = delegate;
1635 }
1636 }
1637
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001638 @Override
Svet Ganov9d528a12018-12-19 17:23:11 -08001639 public int checkOperationRaw(int code, int uid, String packageName) {
1640 return checkOperationInternal(code, uid, packageName, true /*raw*/);
1641 }
1642
1643 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -08001644 public int checkOperation(int code, int uid, String packageName) {
Svet Ganov9d528a12018-12-19 17:23:11 -08001645 return checkOperationInternal(code, uid, packageName, false /*raw*/);
1646 }
1647
1648 private int checkOperationInternal(int code, int uid, String packageName, boolean raw) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001649 final CheckOpsDelegate delegate;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001650 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001651 delegate = mCheckOpsDelegate;
1652 }
Todd Kennedy556efba2018-11-15 07:43:55 -08001653 if (delegate == null) {
Svet Ganov9d528a12018-12-19 17:23:11 -08001654 return checkOperationImpl(code, uid, packageName, raw);
Todd Kennedy556efba2018-11-15 07:43:55 -08001655 }
Svet Ganov9d528a12018-12-19 17:23:11 -08001656 return delegate.checkOperation(code, uid, packageName, raw,
Svet Ganovd873ae62018-06-25 16:39:23 -07001657 AppOpsService.this::checkOperationImpl);
1658 }
1659
Svet Ganov9d528a12018-12-19 17:23:11 -08001660 private int checkOperationImpl(int code, int uid, String packageName,
1661 boolean raw) {
Todd Kennedy556efba2018-11-15 07:43:55 -08001662 verifyIncomingUid(uid);
1663 verifyIncomingOp(code);
1664 String resolvedPackageName = resolvePackageName(uid, packageName);
1665 if (resolvedPackageName == null) {
1666 return AppOpsManager.MODE_IGNORED;
1667 }
Svet Ganov9d528a12018-12-19 17:23:11 -08001668 return checkOperationUnchecked(code, uid, resolvedPackageName, raw);
Todd Kennedy556efba2018-11-15 07:43:55 -08001669 }
1670
Svet Ganov9d528a12018-12-19 17:23:11 -08001671 private int checkOperationUnchecked(int code, int uid, String packageName,
1672 boolean raw) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001673 synchronized (this) {
Todd Kennedy556efba2018-11-15 07:43:55 -08001674 if (isOpRestrictedLocked(uid, code, packageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001675 return AppOpsManager.MODE_IGNORED;
1676 }
Svet Ganov2af57082015-07-30 08:44:20 -07001677 code = AppOpsManager.opToSwitch(code);
1678 UidState uidState = getUidStateLocked(uid, false);
Svet Ganovee438d42017-01-19 18:04:38 -08001679 if (uidState != null && uidState.opModes != null
1680 && uidState.opModes.indexOfKey(code) >= 0) {
Svet Ganov9d528a12018-12-19 17:23:11 -08001681 final int rawMode = uidState.opModes.get(code);
1682 return raw ? rawMode : uidState.evalMode(rawMode);
Svet Ganov2af57082015-07-30 08:44:20 -07001683 }
Todd Kennedy556efba2018-11-15 07:43:55 -08001684 Op op = getOpLocked(code, uid, packageName, false, true, false);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001685 if (op == null) {
David Braunf5d83192013-09-16 13:43:51 -07001686 return AppOpsManager.opToDefaultMode(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001687 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001688 return op.mode;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001689 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001690 }
1691
1692 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001693 public int checkAudioOperation(int code, int usage, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001694 final CheckOpsDelegate delegate;
John Spurlock1af30c72014-03-10 08:33:35 -04001695 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001696 delegate = mCheckOpsDelegate;
1697 }
Todd Kennedy556efba2018-11-15 07:43:55 -08001698 if (delegate == null) {
1699 return checkAudioOperationImpl(code, usage, uid, packageName);
1700 }
Svet Ganovd873ae62018-06-25 16:39:23 -07001701 return delegate.checkAudioOperation(code, usage, uid, packageName,
1702 AppOpsService.this::checkAudioOperationImpl);
1703 }
1704
1705 private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
Todd Kennedy556efba2018-11-15 07:43:55 -08001706 boolean suspended;
1707 try {
1708 suspended = isPackageSuspendedForUser(packageName, uid);
1709 } catch (IllegalArgumentException ex) {
1710 // Package not found.
1711 suspended = false;
1712 }
1713
1714 if (suspended) {
1715 Slog.i(TAG, "Audio disabled for suspended package=" + packageName
1716 + " for uid=" + uid);
1717 return AppOpsManager.MODE_IGNORED;
1718 }
1719
Svet Ganovd873ae62018-06-25 16:39:23 -07001720 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001721 final int mode = checkRestrictionLocked(code, usage, uid, packageName);
John Spurlock1af30c72014-03-10 08:33:35 -04001722 if (mode != AppOpsManager.MODE_ALLOWED) {
1723 return mode;
1724 }
1725 }
1726 return checkOperation(code, uid, packageName);
1727 }
1728
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001729 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001730 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001731 return AppGlobals.getPackageManager().isPackageSuspendedForUser(
1732 pkg, UserHandle.getUserId(uid));
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001733 } catch (RemoteException re) {
1734 throw new SecurityException("Could not talk to package manager service");
1735 }
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001736 }
1737
John Spurlock7b414672014-07-18 13:02:39 -04001738 private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
1739 final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1740 if (usageRestrictions != null) {
1741 final Restriction r = usageRestrictions.get(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001742 if (r != null && !r.exceptionPackages.contains(packageName)) {
1743 return r.mode;
1744 }
1745 }
1746 return AppOpsManager.MODE_ALLOWED;
1747 }
1748
1749 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001750 public void setAudioRestriction(int code, int usage, int uid, int mode,
John Spurlock1af30c72014-03-10 08:33:35 -04001751 String[] exceptionPackages) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001752 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
John Spurlock1af30c72014-03-10 08:33:35 -04001753 verifyIncomingUid(uid);
1754 verifyIncomingOp(code);
1755 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001756 SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1757 if (usageRestrictions == null) {
1758 usageRestrictions = new SparseArray<Restriction>();
1759 mAudioRestrictions.put(code, usageRestrictions);
John Spurlock1af30c72014-03-10 08:33:35 -04001760 }
John Spurlock7b414672014-07-18 13:02:39 -04001761 usageRestrictions.remove(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001762 if (mode != AppOpsManager.MODE_ALLOWED) {
1763 final Restriction r = new Restriction();
1764 r.mode = mode;
1765 if (exceptionPackages != null) {
1766 final int N = exceptionPackages.length;
1767 r.exceptionPackages = new ArraySet<String>(N);
1768 for (int i = 0; i < N; i++) {
1769 final String pkg = exceptionPackages[i];
1770 if (pkg != null) {
1771 r.exceptionPackages.add(pkg.trim());
1772 }
1773 }
1774 }
John Spurlock7b414672014-07-18 13:02:39 -04001775 usageRestrictions.put(usage, r);
John Spurlock1af30c72014-03-10 08:33:35 -04001776 }
1777 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001778
1779 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07001780 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
John Spurlock1af30c72014-03-10 08:33:35 -04001781 }
1782
1783 @Override
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001784 public int checkPackage(int uid, String packageName) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001785 Preconditions.checkNotNull(packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001786 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001787 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
1788 true /* uidMismatchExpected */);
1789 if (ops != null) {
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001790 return AppOpsManager.MODE_ALLOWED;
1791 } else {
1792 return AppOpsManager.MODE_ERRORED;
1793 }
1794 }
1795 }
1796
1797 @Override
Svet Ganovd873ae62018-06-25 16:39:23 -07001798 public int noteProxyOperation(int code, int proxyUid,
1799 String proxyPackageName, int proxiedUid, String proxiedPackageName) {
1800 verifyIncomingUid(proxyUid);
Svet Ganov99b60432015-06-27 13:15:22 -07001801 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001802 String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
1803 if (resolveProxyPackageName == null) {
1804 return AppOpsManager.MODE_IGNORED;
1805 }
1806 final int proxyMode = noteOperationUnchecked(code, proxyUid,
1807 resolveProxyPackageName, -1, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001808 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
1809 return proxyMode;
1810 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001811 String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
1812 if (resolveProxiedPackageName == null) {
1813 return AppOpsManager.MODE_IGNORED;
1814 }
1815 return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
1816 proxyMode, resolveProxyPackageName);
Svet Ganov99b60432015-06-27 13:15:22 -07001817 }
1818
1819 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001820 public int noteOperation(int code, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001821 final CheckOpsDelegate delegate;
1822 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001823 delegate = mCheckOpsDelegate;
1824 }
Todd Kennedy556efba2018-11-15 07:43:55 -08001825 if (delegate == null) {
1826 return noteOperationImpl(code, uid, packageName);
1827 }
Svet Ganovd873ae62018-06-25 16:39:23 -07001828 return delegate.noteOperation(code, uid, packageName,
1829 AppOpsService.this::noteOperationImpl);
1830 }
1831
1832 private int noteOperationImpl(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001833 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001834 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001835 String resolvedPackageName = resolvePackageName(uid, packageName);
1836 if (resolvedPackageName == null) {
1837 return AppOpsManager.MODE_IGNORED;
1838 }
1839 return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001840 }
1841
1842 private int noteOperationUnchecked(int code, int uid, String packageName,
1843 int proxyUid, String proxyPackageName) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001844 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001845 final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001846 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001847 if (ops == null) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001848 scheduleOpNotedIfNeededLocked(code, uid, packageName,
1849 AppOpsManager.MODE_IGNORED);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001850 if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001851 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001852 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001853 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001854 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001855 if (isOpRestrictedLocked(uid, code, packageName)) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001856 scheduleOpNotedIfNeededLocked(code, uid, packageName,
1857 AppOpsManager.MODE_IGNORED);
Jason Monk62062992014-05-06 09:55:28 -04001858 return AppOpsManager.MODE_IGNORED;
1859 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001860 final UidState uidState = ops.uidState;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001861 if (op.duration == -1) {
1862 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001863 + " code " + code + " time=" + op.time[uidState.state]
1864 + " duration=" + op.duration);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001865 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001866 op.duration = 0;
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001867 final int switchCode = AppOpsManager.opToSwitch(code);
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001868 // If there is a non-default per UID policy (we set UID op mode only if
1869 // non-default) it takes over, otherwise use the per package policy.
1870 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001871 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganov2af57082015-07-30 08:44:20 -07001872 if (uidMode != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001873 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001874 + switchCode + " (" + code + ") uid " + uid + " package "
1875 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001876 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001877 scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode);
Svet Ganov8455ba22019-01-02 13:05:56 -08001878 mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
1879 uidState.state);
Svet Ganov2af57082015-07-30 08:44:20 -07001880 return uidMode;
1881 }
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001882 } else {
1883 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001884 final int mode = switchOp.getMode();
1885 if (mode != AppOpsManager.MODE_ALLOWED) {
1886 if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001887 + switchCode + " (" + code + ") uid " + uid + " package "
1888 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001889 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001890 scheduleOpNotedIfNeededLocked(op.op, uid, packageName, mode);
Svet Ganov8455ba22019-01-02 13:05:56 -08001891 mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
1892 uidState.state);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001893 return mode;
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001894 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001895 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001896 if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001897 + " package " + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001898 op.time[uidState.state] = System.currentTimeMillis();
Svet Ganov8455ba22019-01-02 13:05:56 -08001899 mHistoricalRegistry.incrementOpAccessedCount(op.op, uid, packageName,
1900 uidState.state);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001901 op.rejectTime[uidState.state] = 0;
Svet Ganov99b60432015-06-27 13:15:22 -07001902 op.proxyUid = proxyUid;
1903 op.proxyPackageName = proxyPackageName;
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001904 scheduleOpNotedIfNeededLocked(code, uid, packageName,
1905 AppOpsManager.MODE_ALLOWED);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001906 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001907 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001908 }
1909
1910 @Override
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001911 public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001912 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001913 final int callingUid = Binder.getCallingUid();
1914 final int callingPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -08001915 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1916 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001917 watchedUid = callingUid;
Svet Ganovf7b47252018-02-26 11:11:27 -08001918 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001919 if (ops != null) {
1920 Preconditions.checkArrayElementsInRange(ops, 0,
1921 AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
1922 }
1923 if (callback == null) {
1924 return;
1925 }
1926 synchronized (this) {
1927 SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
1928 if (callbacks == null) {
1929 callbacks = new SparseArray<>();
1930 mActiveWatchers.put(callback.asBinder(), callbacks);
1931 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001932 final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
1933 callingUid, callingPid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001934 for (int op : ops) {
1935 callbacks.put(op, activeCallback);
1936 }
1937 }
1938 }
1939
1940 @Override
1941 public void stopWatchingActive(IAppOpsActiveCallback callback) {
1942 if (callback == null) {
1943 return;
1944 }
1945 synchronized (this) {
1946 final SparseArray<ActiveCallback> activeCallbacks =
1947 mActiveWatchers.remove(callback.asBinder());
1948 if (activeCallbacks == null) {
1949 return;
1950 }
1951 final int callbackCount = activeCallbacks.size();
1952 for (int i = 0; i < callbackCount; i++) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001953 activeCallbacks.valueAt(i).destroy();
1954 }
1955 }
1956 }
1957
1958 @Override
1959 public void startWatchingNoted(@NonNull int[] ops, @NonNull IAppOpsNotedCallback callback) {
1960 int watchedUid = Process.INVALID_UID;
1961 final int callingUid = Binder.getCallingUid();
1962 final int callingPid = Binder.getCallingPid();
1963 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1964 != PackageManager.PERMISSION_GRANTED) {
1965 watchedUid = callingUid;
1966 }
1967 Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
1968 Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
1969 "Invalid op code in: " + Arrays.toString(ops));
1970 Preconditions.checkNotNull(callback, "Callback cannot be null");
1971 synchronized (this) {
1972 SparseArray<NotedCallback> callbacks = mNotedWatchers.get(callback.asBinder());
1973 if (callbacks == null) {
1974 callbacks = new SparseArray<>();
1975 mNotedWatchers.put(callback.asBinder(), callbacks);
1976 }
1977 final NotedCallback notedCallback = new NotedCallback(callback, watchedUid,
1978 callingUid, callingPid);
1979 for (int op : ops) {
1980 callbacks.put(op, notedCallback);
1981 }
1982 }
1983 }
1984
1985 @Override
1986 public void stopWatchingNoted(IAppOpsNotedCallback callback) {
1987 Preconditions.checkNotNull(callback, "Callback cannot be null");
1988 synchronized (this) {
1989 final SparseArray<NotedCallback> notedCallbacks =
1990 mNotedWatchers.remove(callback.asBinder());
1991 if (notedCallbacks == null) {
1992 return;
1993 }
1994 final int callbackCount = notedCallbacks.size();
1995 for (int i = 0; i < callbackCount; i++) {
1996 notedCallbacks.valueAt(i).destroy();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001997 }
1998 }
1999 }
2000
2001 @Override
Svet Ganovf7b47252018-02-26 11:11:27 -08002002 public int startOperation(IBinder token, int code, int uid, String packageName,
2003 boolean startIfModeDefault) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002004 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08002005 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002006 String resolvedPackageName = resolvePackageName(uid, packageName);
2007 if (resolvedPackageName == null) {
2008 return AppOpsManager.MODE_IGNORED;
2009 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002010 ClientState client = (ClientState)token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002011 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002012 final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07002013 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002014 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002015 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002016 + " package " + resolvedPackageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07002017 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002018 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002019 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07002020 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04002021 return AppOpsManager.MODE_IGNORED;
2022 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002023 final int switchCode = AppOpsManager.opToSwitch(code);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002024 final UidState uidState = ops.uidState;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002025 // If there is a non-default per UID policy (we set UID op mode only if
2026 // non-default) it takes over, otherwise use the per package policy.
2027 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002028 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganovf7b47252018-02-26 11:11:27 -08002029 if (uidMode != AppOpsManager.MODE_ALLOWED
2030 && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002031 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07002032 + switchCode + " (" + code + ") uid " + uid + " package "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002033 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002034 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov8455ba22019-01-02 13:05:56 -08002035 mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
2036 uidState.state);
Svet Ganov2af57082015-07-30 08:44:20 -07002037 return uidMode;
2038 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002039 } else {
2040 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002041 final int mode = switchOp.getMode();
2042 if (mode != AppOpsManager.MODE_ALLOWED
2043 && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
2044 if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002045 + switchCode + " (" + code + ") uid " + uid + " package "
2046 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002047 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov8455ba22019-01-02 13:05:56 -08002048 mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
2049 uidState.state);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002050 return mode;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002051 }
Svet Ganov2af57082015-07-30 08:44:20 -07002052 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002053 if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002054 + " package " + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002055 if (op.startNesting == 0) {
2056 op.startRealtime = SystemClock.elapsedRealtime();
2057 op.time[uidState.state] = System.currentTimeMillis();
Svet Ganov8455ba22019-01-02 13:05:56 -08002058 mHistoricalRegistry.incrementOpAccessedCount(op.op, uid, packageName,
2059 uidState.state);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002060 op.rejectTime[uidState.state] = 0;
Dianne Hackborn35654b62013-01-14 17:38:02 -08002061 op.duration = -1;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002062 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002063 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002064 op.startNesting++;
2065 uidState.startNesting++;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002066 if (client.mStartedOps != null) {
2067 client.mStartedOps.add(op);
2068 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002069 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002070
2071 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002072 }
2073
2074 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002075 public void finishOperation(IBinder token, int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002076 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08002077 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002078 String resolvedPackageName = resolvePackageName(uid, packageName);
2079 if (resolvedPackageName == null) {
2080 return;
2081 }
2082 if (!(token instanceof ClientState)) {
2083 return;
2084 }
2085 ClientState client = (ClientState) token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002086 synchronized (this) {
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07002087 Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002088 if (op == null) {
2089 return;
2090 }
Svet Ganovf7b47252018-02-26 11:11:27 -08002091 if (!client.mStartedOps.remove(op)) {
Svet Ganovf5d5af12018-03-18 11:51:17 -07002092 // We finish ops when packages get removed to guarantee no dangling
2093 // started ops. However, some part of the system may asynchronously
2094 // finish ops for an already gone package. Hence, finishing an op
2095 // for a non existing package is fine and we don't log as a wtf.
2096 final long identity = Binder.clearCallingIdentity();
2097 try {
2098 if (LocalServices.getService(PackageManagerInternal.class).getPackageUid(
2099 resolvedPackageName, 0, UserHandle.getUserId(uid)) < 0) {
2100 Slog.i(TAG, "Finishing op=" + AppOpsManager.opToName(code)
2101 + " for non-existing package=" + resolvedPackageName
2102 + " in uid=" + uid);
2103 return;
2104 }
2105 } finally {
2106 Binder.restoreCallingIdentity(identity);
2107 }
2108 Slog.wtf(TAG, "Operation not started: uid=" + op.uid + " pkg="
2109 + op.packageName + " op=" + AppOpsManager.opToName(op.op));
Svet Ganov31d83ae2018-03-15 10:45:56 -07002110 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002111 }
Svet Ganova7a0db62018-02-27 20:08:01 -08002112 finishOperationLocked(op, /*finishNested*/ false);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002113 if (op.startNesting <= 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002114 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
2115 }
2116 }
2117 }
2118
2119 private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
2120 boolean active) {
2121 ArraySet<ActiveCallback> dispatchedCallbacks = null;
2122 final int callbackListCount = mActiveWatchers.size();
2123 for (int i = 0; i < callbackListCount; i++) {
2124 final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
2125 ActiveCallback callback = callbacks.get(code);
2126 if (callback != null) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002127 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svet Ganovf7b47252018-02-26 11:11:27 -08002128 continue;
2129 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002130 if (dispatchedCallbacks == null) {
2131 dispatchedCallbacks = new ArraySet<>();
2132 }
2133 dispatchedCallbacks.add(callback);
2134 }
2135 }
2136 if (dispatchedCallbacks == null) {
2137 return;
2138 }
2139 mHandler.sendMessage(PooledLambda.obtainMessage(
2140 AppOpsService::notifyOpActiveChanged,
2141 this, dispatchedCallbacks, code, uid, packageName, active));
2142 }
2143
2144 private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
2145 int code, int uid, String packageName, boolean active) {
2146 // There are components watching for mode changes such as window manager
2147 // and location manager which are in our process. The callbacks in these
2148 // components may require permissions our remote caller does not have.
2149 final long identity = Binder.clearCallingIdentity();
2150 try {
2151 final int callbackCount = callbacks.size();
2152 for (int i = 0; i < callbackCount; i++) {
2153 final ActiveCallback callback = callbacks.valueAt(i);
2154 try {
2155 callback.mCallback.opActiveChanged(code, uid, packageName, active);
2156 } catch (RemoteException e) {
2157 /* do nothing */
2158 }
2159 }
2160 } finally {
2161 Binder.restoreCallingIdentity(identity);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002162 }
2163 }
2164
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002165 private void scheduleOpNotedIfNeededLocked(int code, int uid, String packageName,
2166 int result) {
2167 ArraySet<NotedCallback> dispatchedCallbacks = null;
2168 final int callbackListCount = mNotedWatchers.size();
2169 for (int i = 0; i < callbackListCount; i++) {
2170 final SparseArray<NotedCallback> callbacks = mNotedWatchers.valueAt(i);
2171 final NotedCallback callback = callbacks.get(code);
2172 if (callback != null) {
2173 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
2174 continue;
2175 }
2176 if (dispatchedCallbacks == null) {
2177 dispatchedCallbacks = new ArraySet<>();
2178 }
2179 dispatchedCallbacks.add(callback);
2180 }
2181 }
2182 if (dispatchedCallbacks == null) {
2183 return;
2184 }
2185 mHandler.sendMessage(PooledLambda.obtainMessage(
2186 AppOpsService::notifyOpChecked,
2187 this, dispatchedCallbacks, code, uid, packageName, result));
2188 }
2189
2190 private void notifyOpChecked(ArraySet<NotedCallback> callbacks,
2191 int code, int uid, String packageName, int result) {
2192 // There are components watching for checks in our process. The callbacks in
2193 // these components may require permissions our remote caller does not have.
2194 final long identity = Binder.clearCallingIdentity();
2195 try {
2196 final int callbackCount = callbacks.size();
2197 for (int i = 0; i < callbackCount; i++) {
2198 final NotedCallback callback = callbacks.valueAt(i);
2199 try {
2200 callback.mCallback.opNoted(code, uid, packageName, result);
2201 } catch (RemoteException e) {
2202 /* do nothing */
2203 }
2204 }
2205 } finally {
2206 Binder.restoreCallingIdentity(identity);
2207 }
2208 }
2209
Svet Ganovb9d71a62015-04-30 10:38:13 -07002210 @Override
2211 public int permissionToOpCode(String permission) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002212 if (permission == null) {
2213 return AppOpsManager.OP_NONE;
2214 }
Svet Ganovb9d71a62015-04-30 10:38:13 -07002215 return AppOpsManager.permissionToOpCode(permission);
2216 }
2217
Svet Ganova7a0db62018-02-27 20:08:01 -08002218 void finishOperationLocked(Op op, boolean finishNested) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002219 if (op.startNesting <= 1 || finishNested) {
2220 if (op.startNesting == 1 || finishNested) {
2221 op.duration = (int)(SystemClock.elapsedRealtime() - op.startRealtime);
Svet Ganov8455ba22019-01-02 13:05:56 -08002222 mHistoricalRegistry.increaseOpAccessDuration(op.op, op.uid, op.packageName,
2223 op.uidState.state, op.duration);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002224 op.time[op.uidState.state] = System.currentTimeMillis();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002225 } else {
2226 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
2227 + op.packageName + " code " + op.op + " time=" + op.time
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002228 + " duration=" + op.duration + " nesting=" + op.startNesting);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002229 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002230 if (op.startNesting >= 1) {
2231 op.uidState.startNesting -= op.startNesting;
2232 }
2233 op.startNesting = 0;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002234 } else {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002235 op.startNesting--;
2236 op.uidState.startNesting--;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002237 }
2238 }
2239
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002240 private void verifyIncomingUid(int uid) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002241 if (uid == Binder.getCallingUid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002242 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002243 }
2244 if (Binder.getCallingPid() == Process.myPid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002245 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002246 }
2247 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
2248 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002249 }
2250
Dianne Hackborn961321f2013-02-05 17:22:41 -08002251 private void verifyIncomingOp(int op) {
2252 if (op >= 0 && op < AppOpsManager._NUM_OP) {
2253 return;
2254 }
2255 throw new IllegalArgumentException("Bad operation #" + op);
2256 }
2257
Svet Ganov2af57082015-07-30 08:44:20 -07002258 private UidState getUidStateLocked(int uid, boolean edit) {
2259 UidState uidState = mUidStates.get(uid);
2260 if (uidState == null) {
2261 if (!edit) {
2262 return null;
2263 }
2264 uidState = new UidState(uid);
2265 mUidStates.put(uid, uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002266 } else {
2267 if (uidState.pendingStateCommitTime != 0) {
Dianne Hackborn9fb93502018-06-18 12:29:44 -07002268 if (uidState.pendingStateCommitTime < mLastRealtime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002269 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002270 } else {
Dianne Hackborn9fb93502018-06-18 12:29:44 -07002271 mLastRealtime = SystemClock.elapsedRealtime();
2272 if (uidState.pendingStateCommitTime < mLastRealtime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002273 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002274 }
2275 }
2276 }
Svet Ganov2af57082015-07-30 08:44:20 -07002277 }
2278 return uidState;
2279 }
2280
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002281 private void commitUidPendingStateLocked(UidState uidState) {
Dianne Hackborne93ab412018-05-14 17:52:30 -07002282 final boolean lastForeground = uidState.state <= UID_STATE_LAST_NON_RESTRICTED;
2283 final boolean nowForeground = uidState.pendingState <= UID_STATE_LAST_NON_RESTRICTED;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002284 uidState.state = uidState.pendingState;
2285 uidState.pendingStateCommitTime = 0;
Dianne Hackborne93ab412018-05-14 17:52:30 -07002286 if (uidState.hasForegroundWatchers && lastForeground != nowForeground) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002287 for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
2288 if (!uidState.foregroundOps.valueAt(fgi)) {
2289 continue;
2290 }
2291 final int code = uidState.foregroundOps.keyAt(fgi);
2292
2293 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
2294 if (callbacks != null) {
2295 for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
2296 final ModeCallback callback = callbacks.valueAt(cbi);
2297 if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
2298 || !callback.isWatchingUid(uidState.uid)) {
2299 continue;
2300 }
2301 boolean doAllPackages = uidState.opModes != null
Hai Zhang2b98fb32018-09-21 15:18:46 -07002302 && uidState.opModes.indexOfKey(code) >= 0
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002303 && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
2304 if (uidState.pkgOps != null) {
2305 for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
2306 final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
2307 if (doAllPackages || (op != null
2308 && op.mode == AppOpsManager.MODE_FOREGROUND)) {
2309 mHandler.sendMessage(PooledLambda.obtainMessage(
2310 AppOpsService::notifyOpChanged,
2311 this, callback, code, uidState.uid,
2312 uidState.pkgOps.keyAt(pkgi)));
2313 }
2314 }
2315 }
2316 }
2317 }
2318 }
2319 }
2320 }
2321
Yohei Yukawaa965d652017-10-12 15:02:26 -07002322 private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
2323 boolean uidMismatchExpected) {
Svet Ganov2af57082015-07-30 08:44:20 -07002324 UidState uidState = getUidStateLocked(uid, edit);
2325 if (uidState == null) {
2326 return null;
2327 }
2328
2329 if (uidState.pkgOps == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002330 if (!edit) {
2331 return null;
2332 }
Svet Ganov2af57082015-07-30 08:44:20 -07002333 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002334 }
Svet Ganov2af57082015-07-30 08:44:20 -07002335
2336 Ops ops = uidState.pkgOps.get(packageName);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002337 if (ops == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002338 if (!edit) {
2339 return null;
2340 }
Jason Monk1c7c3192014-06-26 12:52:18 -04002341 boolean isPrivileged = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002342 // This is the first time we have seen this package name under this uid,
2343 // so let's make sure it is valid.
Dianne Hackborn514074f2013-02-11 10:52:46 -08002344 if (uid != 0) {
2345 final long ident = Binder.clearCallingIdentity();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002346 try {
Dianne Hackborn514074f2013-02-11 10:52:46 -08002347 int pkgUid = -1;
2348 try {
Jason Monk1c7c3192014-06-26 12:52:18 -04002349 ApplicationInfo appInfo = ActivityThread.getPackageManager()
Jeff Sharkeycd654482016-01-08 17:42:11 -07002350 .getApplicationInfo(packageName,
Svet Ganovad0a49b2018-10-29 10:07:08 -07002351 PackageManager.MATCH_DIRECT_BOOT_AWARE
Svet Ganov8455ba22019-01-02 13:05:56 -08002352 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
Jeff Sharkeycd654482016-01-08 17:42:11 -07002353 UserHandle.getUserId(uid));
Jason Monk1c7c3192014-06-26 12:52:18 -04002354 if (appInfo != null) {
2355 pkgUid = appInfo.uid;
Alex Klyubinb9f8a522015-02-03 11:12:59 -08002356 isPrivileged = (appInfo.privateFlags
2357 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04002358 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08002359 pkgUid = resolveUid(packageName);
2360 if (pkgUid >= 0) {
Chien-Yu Chen75cade02016-01-11 10:56:21 -08002361 isPrivileged = false;
Jason Monk1c7c3192014-06-26 12:52:18 -04002362 }
Dianne Hackborn713df152013-05-17 11:27:57 -07002363 }
Jason Monk1c7c3192014-06-26 12:52:18 -04002364 } catch (RemoteException e) {
2365 Slog.w(TAG, "Could not contact PackageManager", e);
Dianne Hackborn514074f2013-02-11 10:52:46 -08002366 }
2367 if (pkgUid != uid) {
2368 // Oops! The package name is not valid for the uid they are calling
2369 // under. Abort.
Yohei Yukawaa965d652017-10-12 15:02:26 -07002370 if (!uidMismatchExpected) {
2371 RuntimeException ex = new RuntimeException("here");
2372 ex.fillInStackTrace();
2373 Slog.w(TAG, "Bad call: specified package " + packageName
2374 + " under uid " + uid + " but it is really " + pkgUid, ex);
2375 }
Dianne Hackborn514074f2013-02-11 10:52:46 -08002376 return null;
2377 }
2378 } finally {
2379 Binder.restoreCallingIdentity(ident);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002380 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002381 }
Svet Ganov2af57082015-07-30 08:44:20 -07002382 ops = new Ops(packageName, uidState, isPrivileged);
2383 uidState.pkgOps.put(packageName, ops);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002384 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08002385 return ops;
2386 }
2387
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07002388 /**
2389 * Get the state of all ops for a package, <b>don't verify that package belongs to uid</b>.
2390 *
2391 * <p>Usually callers should use {@link #getOpLocked} and not call this directly.
2392 *
2393 * @param uid The uid the of the package
2394 * @param packageName The package name for which to get the state for
2395 * @param edit Iff {@code true} create the {@link Ops} object if not yet created
2396 * @param isPrivileged Whether the package is privileged or not
2397 *
2398 * @return The {@link Ops state} of all ops for the package
2399 */
2400 private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
2401 boolean edit, boolean isPrivileged) {
2402 UidState uidState = getUidStateLocked(uid, edit);
2403 if (uidState == null) {
2404 return null;
2405 }
2406
2407 if (uidState.pkgOps == null) {
2408 if (!edit) {
2409 return null;
2410 }
2411 uidState.pkgOps = new ArrayMap<>();
2412 }
2413
2414 Ops ops = uidState.pkgOps.get(packageName);
2415 if (ops == null) {
2416 if (!edit) {
2417 return null;
2418 }
2419 ops = new Ops(packageName, uidState, isPrivileged);
2420 uidState.pkgOps.put(packageName, ops);
2421 }
2422 return ops;
2423 }
2424
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002425 private void scheduleWriteLocked() {
2426 if (!mWriteScheduled) {
2427 mWriteScheduled = true;
2428 mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
2429 }
2430 }
2431
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002432 private void scheduleFastWriteLocked() {
2433 if (!mFastWriteScheduled) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002434 mWriteScheduled = true;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002435 mFastWriteScheduled = true;
2436 mHandler.removeCallbacks(mWriteRunner);
2437 mHandler.postDelayed(mWriteRunner, 10*1000);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002438 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002439 }
2440
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07002441 /**
2442 * Get the state of an op for a uid.
2443 *
2444 * @param code The code of the op
2445 * @param uid The uid the of the package
2446 * @param packageName The package name for which to get the state for
2447 * @param edit Iff {@code true} create the {@link Op} object if not yet created
2448 * @param verifyUid Iff {@code true} check that the package belongs to the uid
2449 * @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid
2450 * == false})
2451 *
2452 * @return The {@link Op state} of the op
2453 */
2454 private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit,
2455 boolean verifyUid, boolean isPrivileged) {
2456 Ops ops;
2457
2458 if (verifyUid) {
2459 ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */);
2460 } else {
2461 ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
2462 }
2463
Dianne Hackborn72e39832013-01-18 18:36:09 -08002464 if (ops == null) {
2465 return null;
2466 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002467 return getOpLocked(ops, code, edit);
2468 }
2469
2470 private Op getOpLocked(Ops ops, int code, boolean edit) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002471 Op op = ops.get(code);
2472 if (op == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002473 if (!edit) {
2474 return null;
2475 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002476 op = new Op(ops.uidState, ops.packageName, code);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002477 ops.put(code, op);
2478 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002479 if (edit) {
2480 scheduleWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002481 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002482 return op;
2483 }
2484
Svet Ganov442ed572016-08-17 17:29:43 -07002485 private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
Jason Monk62062992014-05-06 09:55:28 -04002486 int userHandle = UserHandle.getUserId(uid);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002487 final int restrictionSetCount = mOpUserRestrictions.size();
Ruben Brunk29931bc2016-03-11 00:24:26 -08002488
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002489 for (int i = 0; i < restrictionSetCount; i++) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08002490 // For each client, check that the given op is not restricted, or that the given
2491 // package is exempt from the restriction.
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002492 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07002493 if (restrictionState.hasRestriction(code, packageName, userHandle)) {
2494 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
2495 // If we are the system, bypass user restrictions for certain codes
2496 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002497 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
2498 false /* uidMismatchExpected */);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07002499 if ((ops != null) && ops.isPrivileged) {
2500 return false;
2501 }
Ruben Brunk32f0fa42016-03-11 19:07:07 -08002502 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08002503 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002504 return true;
Jason Monk1c7c3192014-06-26 12:52:18 -04002505 }
Jason Monk62062992014-05-06 09:55:28 -04002506 }
2507 return false;
2508 }
2509
Dianne Hackborn35654b62013-01-14 17:38:02 -08002510 void readState() {
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002511 int oldVersion = NO_VERSION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08002512 synchronized (mFile) {
2513 synchronized (this) {
2514 FileInputStream stream;
2515 try {
2516 stream = mFile.openRead();
2517 } catch (FileNotFoundException e) {
2518 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
2519 return;
2520 }
2521 boolean success = false;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002522 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002523 try {
2524 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002525 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002526 int type;
2527 while ((type = parser.next()) != XmlPullParser.START_TAG
2528 && type != XmlPullParser.END_DOCUMENT) {
2529 ;
2530 }
2531
2532 if (type != XmlPullParser.START_TAG) {
2533 throw new IllegalStateException("no start tag found");
2534 }
2535
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002536 final String versionString = parser.getAttributeValue(null, "v");
2537 if (versionString != null) {
2538 oldVersion = Integer.parseInt(versionString);
2539 }
2540
Dianne Hackborn35654b62013-01-14 17:38:02 -08002541 int outerDepth = parser.getDepth();
2542 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2543 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2544 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2545 continue;
2546 }
2547
2548 String tagName = parser.getName();
2549 if (tagName.equals("pkg")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002550 readPackage(parser);
Svetoslav215b44a2015-08-04 19:03:40 -07002551 } else if (tagName.equals("uid")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002552 readUidOps(parser);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002553 } else {
2554 Slog.w(TAG, "Unknown element under <app-ops>: "
2555 + parser.getName());
2556 XmlUtils.skipCurrentTag(parser);
2557 }
2558 }
2559 success = true;
2560 } catch (IllegalStateException e) {
2561 Slog.w(TAG, "Failed parsing " + e);
2562 } catch (NullPointerException e) {
2563 Slog.w(TAG, "Failed parsing " + e);
2564 } catch (NumberFormatException e) {
2565 Slog.w(TAG, "Failed parsing " + e);
2566 } catch (XmlPullParserException e) {
2567 Slog.w(TAG, "Failed parsing " + e);
2568 } catch (IOException e) {
2569 Slog.w(TAG, "Failed parsing " + e);
2570 } catch (IndexOutOfBoundsException e) {
2571 Slog.w(TAG, "Failed parsing " + e);
2572 } finally {
2573 if (!success) {
Svet Ganov2af57082015-07-30 08:44:20 -07002574 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002575 }
2576 try {
2577 stream.close();
2578 } catch (IOException e) {
2579 }
2580 }
2581 }
2582 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002583 synchronized (this) {
2584 upgradeLocked(oldVersion);
2585 }
2586 }
2587
2588 private void upgradeRunAnyInBackgroundLocked() {
2589 for (int i = 0; i < mUidStates.size(); i++) {
2590 final UidState uidState = mUidStates.valueAt(i);
2591 if (uidState == null) {
2592 continue;
2593 }
2594 if (uidState.opModes != null) {
2595 final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
2596 if (idx >= 0) {
2597 uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
2598 uidState.opModes.valueAt(idx));
2599 }
2600 }
2601 if (uidState.pkgOps == null) {
2602 continue;
2603 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002604 boolean changed = false;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002605 for (int j = 0; j < uidState.pkgOps.size(); j++) {
2606 Ops ops = uidState.pkgOps.valueAt(j);
2607 if (ops != null) {
2608 final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
2609 if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002610 final Op copy = new Op(op.uidState, op.packageName,
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002611 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
2612 copy.mode = op.mode;
2613 ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002614 changed = true;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002615 }
2616 }
2617 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002618 if (changed) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002619 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002620 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002621 }
2622 }
2623
2624 private void upgradeLocked(int oldVersion) {
2625 if (oldVersion >= CURRENT_VERSION) {
2626 return;
2627 }
2628 Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
2629 switch (oldVersion) {
2630 case NO_VERSION:
2631 upgradeRunAnyInBackgroundLocked();
2632 // fall through
2633 case 1:
2634 // for future upgrades
2635 }
2636 scheduleFastWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002637 }
2638
Svet Ganov2af57082015-07-30 08:44:20 -07002639 void readUidOps(XmlPullParser parser) throws NumberFormatException,
2640 XmlPullParserException, IOException {
2641 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
2642 int outerDepth = parser.getDepth();
2643 int type;
2644 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2645 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2646 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2647 continue;
2648 }
2649
2650 String tagName = parser.getName();
2651 if (tagName.equals("op")) {
2652 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
2653 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
2654 UidState uidState = getUidStateLocked(uid, true);
2655 if (uidState.opModes == null) {
2656 uidState.opModes = new SparseIntArray();
2657 }
2658 uidState.opModes.put(code, mode);
2659 } else {
2660 Slog.w(TAG, "Unknown element under <uid-ops>: "
2661 + parser.getName());
2662 XmlUtils.skipCurrentTag(parser);
2663 }
2664 }
2665 }
2666
Dave Burke0997c5bd2013-08-02 20:25:02 +00002667 void readPackage(XmlPullParser parser) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002668 XmlPullParserException, IOException {
2669 String pkgName = parser.getAttributeValue(null, "n");
2670 int outerDepth = parser.getDepth();
2671 int type;
2672 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2673 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2674 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2675 continue;
2676 }
2677
2678 String tagName = parser.getName();
2679 if (tagName.equals("uid")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002680 readUid(parser, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002681 } else {
2682 Slog.w(TAG, "Unknown element under <pkg>: "
2683 + parser.getName());
2684 XmlUtils.skipCurrentTag(parser);
2685 }
2686 }
2687 }
2688
Dave Burke0997c5bd2013-08-02 20:25:02 +00002689 void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002690 XmlPullParserException, IOException {
2691 int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
Jason Monk1c7c3192014-06-26 12:52:18 -04002692 String isPrivilegedString = parser.getAttributeValue(null, "p");
2693 boolean isPrivileged = false;
2694 if (isPrivilegedString == null) {
2695 try {
2696 IPackageManager packageManager = ActivityThread.getPackageManager();
2697 if (packageManager != null) {
2698 ApplicationInfo appInfo = ActivityThread.getPackageManager()
2699 .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
2700 if (appInfo != null) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08002701 isPrivileged = (appInfo.privateFlags
2702 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04002703 }
2704 } else {
2705 // Could not load data, don't add to cache so it will be loaded later.
2706 return;
2707 }
2708 } catch (RemoteException e) {
2709 Slog.w(TAG, "Could not contact PackageManager", e);
2710 }
2711 } else {
2712 isPrivileged = Boolean.parseBoolean(isPrivilegedString);
2713 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002714 int outerDepth = parser.getDepth();
2715 int type;
2716 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2717 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2718 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2719 continue;
2720 }
2721
2722 String tagName = parser.getName();
2723 if (tagName.equals("op")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002724 UidState uidState = getUidStateLocked(uid, true);
2725 if (uidState.pkgOps == null) {
2726 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002727 }
Svet Ganov2af57082015-07-30 08:44:20 -07002728
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002729 Op op = new Op(uidState, pkgName,
2730 Integer.parseInt(parser.getAttributeValue(null, "n")));
2731
2732 for (int i = parser.getAttributeCount()-1; i >= 0; i--) {
2733 final String name = parser.getAttributeName(i);
2734 final String value = parser.getAttributeValue(i);
2735 switch (name) {
2736 case "m":
2737 op.mode = Integer.parseInt(value);
2738 break;
2739 case "d":
2740 op.duration = Integer.parseInt(value);
2741 break;
2742 case "pu":
2743 op.proxyUid = Integer.parseInt(value);
2744 break;
2745 case "pp":
2746 op.proxyPackageName = value;
2747 break;
2748 case "tp":
2749 op.time[AppOpsManager.UID_STATE_PERSISTENT] = Long.parseLong(value);
2750 break;
2751 case "tt":
2752 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2753 break;
2754 case "tfs":
2755 op.time[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2756 = Long.parseLong(value);
2757 break;
2758 case "tf":
2759 op.time[AppOpsManager.UID_STATE_FOREGROUND] = Long.parseLong(value);
2760 break;
2761 case "tb":
2762 op.time[AppOpsManager.UID_STATE_BACKGROUND] = Long.parseLong(value);
2763 break;
2764 case "tc":
2765 op.time[AppOpsManager.UID_STATE_CACHED] = Long.parseLong(value);
2766 break;
2767 case "rp":
2768 op.rejectTime[AppOpsManager.UID_STATE_PERSISTENT]
2769 = Long.parseLong(value);
2770 break;
2771 case "rt":
2772 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2773 break;
2774 case "rfs":
2775 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2776 = Long.parseLong(value);
2777 break;
2778 case "rf":
2779 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND]
2780 = Long.parseLong(value);
2781 break;
2782 case "rb":
2783 op.rejectTime[AppOpsManager.UID_STATE_BACKGROUND]
2784 = Long.parseLong(value);
2785 break;
2786 case "rc":
2787 op.rejectTime[AppOpsManager.UID_STATE_CACHED]
2788 = Long.parseLong(value);
2789 break;
2790 case "t":
2791 // Backwards compat.
2792 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2793 break;
2794 case "r":
2795 // Backwards compat.
2796 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2797 break;
2798 default:
2799 Slog.w(TAG, "Unknown attribute in 'op' tag: " + name);
2800 break;
2801 }
2802 }
2803
Svet Ganov2af57082015-07-30 08:44:20 -07002804 Ops ops = uidState.pkgOps.get(pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002805 if (ops == null) {
Svet Ganov2af57082015-07-30 08:44:20 -07002806 ops = new Ops(pkgName, uidState, isPrivileged);
2807 uidState.pkgOps.put(pkgName, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002808 }
2809 ops.put(op.op, op);
2810 } else {
2811 Slog.w(TAG, "Unknown element under <pkg>: "
2812 + parser.getName());
2813 XmlUtils.skipCurrentTag(parser);
2814 }
2815 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002816 UidState uidState = getUidStateLocked(uid, false);
2817 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002818 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002819 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002820 }
2821
2822 void writeState() {
2823 synchronized (mFile) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002824 FileOutputStream stream;
2825 try {
2826 stream = mFile.startWrite();
2827 } catch (IOException e) {
2828 Slog.w(TAG, "Failed to write state: " + e);
2829 return;
2830 }
2831
Dianne Hackborne17b4452018-01-10 13:15:40 -08002832 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
2833
Dianne Hackborn35654b62013-01-14 17:38:02 -08002834 try {
2835 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002836 out.setOutput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002837 out.startDocument(null, true);
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002838 out.startTag(null, "app-ops");
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002839 out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
Svet Ganov2af57082015-07-30 08:44:20 -07002840
2841 final int uidStateCount = mUidStates.size();
2842 for (int i = 0; i < uidStateCount; i++) {
2843 UidState uidState = mUidStates.valueAt(i);
2844 if (uidState.opModes != null && uidState.opModes.size() > 0) {
2845 out.startTag(null, "uid");
2846 out.attribute(null, "n", Integer.toString(uidState.uid));
2847 SparseIntArray uidOpModes = uidState.opModes;
2848 final int opCount = uidOpModes.size();
2849 for (int j = 0; j < opCount; j++) {
2850 final int op = uidOpModes.keyAt(j);
2851 final int mode = uidOpModes.valueAt(j);
2852 out.startTag(null, "op");
2853 out.attribute(null, "n", Integer.toString(op));
2854 out.attribute(null, "m", Integer.toString(mode));
2855 out.endTag(null, "op");
2856 }
2857 out.endTag(null, "uid");
2858 }
2859 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002860
2861 if (allOps != null) {
2862 String lastPkg = null;
2863 for (int i=0; i<allOps.size(); i++) {
2864 AppOpsManager.PackageOps pkg = allOps.get(i);
2865 if (!pkg.getPackageName().equals(lastPkg)) {
2866 if (lastPkg != null) {
2867 out.endTag(null, "pkg");
2868 }
2869 lastPkg = pkg.getPackageName();
2870 out.startTag(null, "pkg");
2871 out.attribute(null, "n", lastPkg);
2872 }
2873 out.startTag(null, "uid");
2874 out.attribute(null, "n", Integer.toString(pkg.getUid()));
Jason Monk1c7c3192014-06-26 12:52:18 -04002875 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002876 Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
2877 false /* edit */, false /* uidMismatchExpected */);
Jason Monk1c7c3192014-06-26 12:52:18 -04002878 // Should always be present as the list of PackageOps is generated
2879 // from Ops.
2880 if (ops != null) {
2881 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
2882 } else {
2883 out.attribute(null, "p", Boolean.toString(false));
2884 }
2885 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002886 List<AppOpsManager.OpEntry> ops = pkg.getOps();
2887 for (int j=0; j<ops.size(); j++) {
2888 AppOpsManager.OpEntry op = ops.get(j);
2889 out.startTag(null, "op");
2890 out.attribute(null, "n", Integer.toString(op.getOp()));
David Braunf5d83192013-09-16 13:43:51 -07002891 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002892 out.attribute(null, "m", Integer.toString(op.getMode()));
2893 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002894 for (int k = 0; k < _NUM_UID_STATE; k++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002895 final long time = op.getLastTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002896 if (time != 0) {
2897 out.attribute(null, UID_STATE_TIME_ATTRS[k],
2898 Long.toString(time));
2899 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002900 final long rejectTime = op.getLastRejectTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002901 if (rejectTime != 0) {
2902 out.attribute(null, UID_STATE_REJECT_ATTRS[k],
2903 Long.toString(rejectTime));
2904 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002905 }
2906 int dur = op.getDuration();
2907 if (dur != 0) {
2908 out.attribute(null, "d", Integer.toString(dur));
2909 }
Svet Ganov99b60432015-06-27 13:15:22 -07002910 int proxyUid = op.getProxyUid();
2911 if (proxyUid != -1) {
2912 out.attribute(null, "pu", Integer.toString(proxyUid));
2913 }
2914 String proxyPackageName = op.getProxyPackageName();
2915 if (proxyPackageName != null) {
2916 out.attribute(null, "pp", proxyPackageName);
2917 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002918 out.endTag(null, "op");
2919 }
2920 out.endTag(null, "uid");
2921 }
2922 if (lastPkg != null) {
2923 out.endTag(null, "pkg");
2924 }
2925 }
2926
2927 out.endTag(null, "app-ops");
2928 out.endDocument();
2929 mFile.finishWrite(stream);
2930 } catch (IOException e) {
2931 Slog.w(TAG, "Failed to write state, restoring backup.", e);
2932 mFile.failWrite(stream);
2933 }
2934 }
2935 }
2936
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002937 static class Shell extends ShellCommand {
2938 final IAppOpsService mInterface;
2939 final AppOpsService mInternal;
2940
2941 int userId = UserHandle.USER_SYSTEM;
2942 String packageName;
2943 String opStr;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002944 String modeStr;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002945 int op;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002946 int mode;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002947 int packageUid;
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002948 int nonpackageUid;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002949 final static Binder sBinder = new Binder();
2950 IBinder mToken;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002951
2952 Shell(IAppOpsService iface, AppOpsService internal) {
2953 mInterface = iface;
2954 mInternal = internal;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002955 try {
2956 mToken = mInterface.getToken(sBinder);
2957 } catch (RemoteException e) {
2958 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002959 }
2960
2961 @Override
2962 public int onCommand(String cmd) {
2963 return onShellCommand(this, cmd);
2964 }
2965
2966 @Override
2967 public void onHelp() {
2968 PrintWriter pw = getOutPrintWriter();
2969 dumpCommandHelp(pw);
2970 }
2971
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002972 static private int strOpToOp(String op, PrintWriter err) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002973 try {
2974 return AppOpsManager.strOpToOp(op);
2975 } catch (IllegalArgumentException e) {
2976 }
2977 try {
2978 return Integer.parseInt(op);
2979 } catch (NumberFormatException e) {
2980 }
2981 try {
2982 return AppOpsManager.strDebugOpToOp(op);
2983 } catch (IllegalArgumentException e) {
2984 err.println("Error: " + e.getMessage());
2985 return -1;
2986 }
2987 }
2988
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002989 static int strModeToMode(String modeStr, PrintWriter err) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002990 for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
2991 if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002992 return i;
2993 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002994 }
2995 try {
2996 return Integer.parseInt(modeStr);
2997 } catch (NumberFormatException e) {
2998 }
2999 err.println("Error: Mode " + modeStr + " is not valid");
3000 return -1;
3001 }
3002
3003 int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
3004 userId = UserHandle.USER_CURRENT;
3005 opStr = null;
3006 modeStr = null;
3007 for (String argument; (argument = getNextArg()) != null;) {
3008 if ("--user".equals(argument)) {
3009 userId = UserHandle.parseUserArg(getNextArgRequired());
3010 } else {
3011 if (opStr == null) {
3012 opStr = argument;
3013 } else if (modeStr == null) {
3014 modeStr = argument;
3015 break;
3016 }
3017 }
3018 }
3019 if (opStr == null) {
3020 err.println("Error: Operation not specified.");
3021 return -1;
3022 }
3023 op = strOpToOp(opStr, err);
3024 if (op < 0) {
3025 return -1;
3026 }
3027 if (modeStr != null) {
3028 if ((mode=strModeToMode(modeStr, err)) < 0) {
3029 return -1;
3030 }
3031 } else {
3032 mode = defMode;
3033 }
3034 return 0;
3035 }
3036
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003037 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
3038 userId = UserHandle.USER_CURRENT;
3039 packageName = null;
3040 opStr = null;
3041 for (String argument; (argument = getNextArg()) != null;) {
3042 if ("--user".equals(argument)) {
3043 userId = UserHandle.parseUserArg(getNextArgRequired());
3044 } else {
3045 if (packageName == null) {
3046 packageName = argument;
3047 } else if (opStr == null) {
3048 opStr = argument;
3049 break;
3050 }
3051 }
3052 }
3053 if (packageName == null) {
3054 err.println("Error: Package name not specified.");
3055 return -1;
3056 } else if (opStr == null && reqOp) {
3057 err.println("Error: Operation not specified.");
3058 return -1;
3059 }
3060 if (opStr != null) {
3061 op = strOpToOp(opStr, err);
3062 if (op < 0) {
3063 return -1;
3064 }
3065 } else {
3066 op = AppOpsManager.OP_NONE;
3067 }
3068 if (userId == UserHandle.USER_CURRENT) {
3069 userId = ActivityManager.getCurrentUser();
3070 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003071 nonpackageUid = -1;
3072 try {
3073 nonpackageUid = Integer.parseInt(packageName);
3074 } catch (NumberFormatException e) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003075 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003076 if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
3077 && packageName.indexOf('.') < 0) {
3078 int i = 1;
3079 while (i < packageName.length() && packageName.charAt(i) >= '0'
3080 && packageName.charAt(i) <= '9') {
3081 i++;
3082 }
3083 if (i > 1 && i < packageName.length()) {
3084 String userStr = packageName.substring(1, i);
3085 try {
3086 int user = Integer.parseInt(userStr);
3087 char type = packageName.charAt(i);
3088 i++;
3089 int startTypeVal = i;
3090 while (i < packageName.length() && packageName.charAt(i) >= '0'
3091 && packageName.charAt(i) <= '9') {
3092 i++;
3093 }
3094 if (i > startTypeVal) {
3095 String typeValStr = packageName.substring(startTypeVal, i);
3096 try {
3097 int typeVal = Integer.parseInt(typeValStr);
3098 if (type == 'a') {
3099 nonpackageUid = UserHandle.getUid(user,
3100 typeVal + Process.FIRST_APPLICATION_UID);
3101 } else if (type == 's') {
3102 nonpackageUid = UserHandle.getUid(user, typeVal);
3103 }
3104 } catch (NumberFormatException e) {
3105 }
3106 }
3107 } catch (NumberFormatException e) {
3108 }
3109 }
3110 }
3111 if (nonpackageUid != -1) {
3112 packageName = null;
3113 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08003114 packageUid = resolveUid(packageName);
3115 if (packageUid < 0) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003116 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
3117 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
3118 }
3119 if (packageUid < 0) {
3120 err.println("Error: No UID for " + packageName + " in user " + userId);
3121 return -1;
3122 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003123 }
3124 return 0;
3125 }
3126 }
3127
3128 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07003129 FileDescriptor err, String[] args, ShellCallback callback,
3130 ResultReceiver resultReceiver) {
3131 (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003132 }
3133
3134 static void dumpCommandHelp(PrintWriter pw) {
3135 pw.println("AppOps service (appops) commands:");
3136 pw.println(" help");
3137 pw.println(" Print this help text.");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05003138 pw.println(" start [--user <USER_ID>] <PACKAGE | UID> <OP> ");
3139 pw.println(" Starts a given operation for a particular application.");
3140 pw.println(" stop [--user <USER_ID>] <PACKAGE | UID> <OP> ");
3141 pw.println(" Stops a given operation for a particular application.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003142 pw.println(" set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003143 pw.println(" Set the mode for a particular application and operation.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003144 pw.println(" get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003145 pw.println(" Return the mode for a particular application and optional operation.");
Dianne Hackborne91f3e72016-03-25 18:48:15 -07003146 pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
3147 pw.println(" Print all packages that currently have the given op in the given mode.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003148 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
3149 pw.println(" Reset the given application or all applications to default modes.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003150 pw.println(" write-settings");
3151 pw.println(" Immediately write pending changes to storage.");
3152 pw.println(" read-settings");
3153 pw.println(" Read the last written settings, replacing current state in RAM.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003154 pw.println(" options:");
3155 pw.println(" <PACKAGE> an Android package name.");
3156 pw.println(" <OP> an AppOps operation.");
3157 pw.println(" <MODE> one of allow, ignore, deny, or default");
3158 pw.println(" <USER_ID> the user id under which the package is installed. If --user is not");
3159 pw.println(" specified, the current user is assumed.");
3160 }
3161
3162 static int onShellCommand(Shell shell, String cmd) {
3163 if (cmd == null) {
3164 return shell.handleDefaultCommands(cmd);
3165 }
3166 PrintWriter pw = shell.getOutPrintWriter();
3167 PrintWriter err = shell.getErrPrintWriter();
3168 try {
3169 switch (cmd) {
3170 case "set": {
3171 int res = shell.parseUserPackageOp(true, err);
3172 if (res < 0) {
3173 return res;
3174 }
3175 String modeStr = shell.getNextArg();
3176 if (modeStr == null) {
3177 err.println("Error: Mode not specified.");
3178 return -1;
3179 }
3180
Dianne Hackborne91f3e72016-03-25 18:48:15 -07003181 final int mode = shell.strModeToMode(modeStr, err);
3182 if (mode < 0) {
3183 return -1;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003184 }
3185
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003186 if (shell.packageName != null) {
3187 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
3188 mode);
3189 } else {
3190 shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
3191 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003192 return 0;
3193 }
3194 case "get": {
3195 int res = shell.parseUserPackageOp(false, err);
3196 if (res < 0) {
3197 return res;
3198 }
3199
Eugene Suslae4ee2c22018-11-05 12:23:30 -08003200 List<AppOpsManager.PackageOps> ops = new ArrayList<>();
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003201 if (shell.packageName != null) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08003202 // Uid mode overrides package mode, so make sure it's also reported
3203 List<AppOpsManager.PackageOps> r = shell.mInterface.getUidOps(
3204 shell.packageUid,
3205 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
3206 if (r != null) {
3207 ops.addAll(r);
3208 }
3209 r = shell.mInterface.getOpsForPackage(
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003210 shell.packageUid, shell.packageName,
3211 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
Eugene Suslae4ee2c22018-11-05 12:23:30 -08003212 if (r != null) {
3213 ops.addAll(r);
3214 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003215 } else {
3216 ops = shell.mInterface.getUidOps(
3217 shell.nonpackageUid,
3218 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
3219 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003220 if (ops == null || ops.size() <= 0) {
3221 pw.println("No operations.");
Svet Ganov82f09bc2018-01-12 22:08:40 -08003222 if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003223 pw.println("Default mode: " + AppOpsManager.modeToName(
Svet Ganov82f09bc2018-01-12 22:08:40 -08003224 AppOpsManager.opToDefaultMode(shell.op)));
3225 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003226 return 0;
3227 }
3228 final long now = System.currentTimeMillis();
3229 for (int i=0; i<ops.size(); i++) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08003230 AppOpsManager.PackageOps packageOps = ops.get(i);
3231 if (packageOps.getPackageName() == null) {
3232 pw.print("Uid mode: ");
3233 }
3234 List<AppOpsManager.OpEntry> entries = packageOps.getOps();
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003235 for (int j=0; j<entries.size(); j++) {
3236 AppOpsManager.OpEntry ent = entries.get(j);
3237 pw.print(AppOpsManager.opToName(ent.getOp()));
3238 pw.print(": ");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003239 pw.print(AppOpsManager.modeToName(ent.getMode()));
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003240 if (ent.getTime() != 0) {
3241 pw.print("; time=");
3242 TimeUtils.formatDuration(now - ent.getTime(), pw);
3243 pw.print(" ago");
3244 }
3245 if (ent.getRejectTime() != 0) {
3246 pw.print("; rejectTime=");
3247 TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
3248 pw.print(" ago");
3249 }
3250 if (ent.getDuration() == -1) {
3251 pw.print(" (running)");
3252 } else if (ent.getDuration() != 0) {
3253 pw.print("; duration=");
3254 TimeUtils.formatDuration(ent.getDuration(), pw);
3255 }
3256 pw.println();
3257 }
3258 }
3259 return 0;
3260 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07003261 case "query-op": {
3262 int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
3263 if (res < 0) {
3264 return res;
3265 }
3266 List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
3267 new int[] {shell.op});
3268 if (ops == null || ops.size() <= 0) {
3269 pw.println("No operations.");
3270 return 0;
3271 }
3272 for (int i=0; i<ops.size(); i++) {
3273 final AppOpsManager.PackageOps pkg = ops.get(i);
3274 boolean hasMatch = false;
3275 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
3276 for (int j=0; j<entries.size(); j++) {
3277 AppOpsManager.OpEntry ent = entries.get(j);
3278 if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
3279 hasMatch = true;
3280 break;
3281 }
3282 }
3283 if (hasMatch) {
3284 pw.println(pkg.getPackageName());
3285 }
3286 }
3287 return 0;
3288 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003289 case "reset": {
3290 String packageName = null;
3291 int userId = UserHandle.USER_CURRENT;
3292 for (String argument; (argument = shell.getNextArg()) != null;) {
3293 if ("--user".equals(argument)) {
3294 String userStr = shell.getNextArgRequired();
3295 userId = UserHandle.parseUserArg(userStr);
3296 } else {
3297 if (packageName == null) {
3298 packageName = argument;
3299 } else {
3300 err.println("Error: Unsupported argument: " + argument);
3301 return -1;
3302 }
3303 }
3304 }
3305
3306 if (userId == UserHandle.USER_CURRENT) {
3307 userId = ActivityManager.getCurrentUser();
3308 }
3309
3310 shell.mInterface.resetAllModes(userId, packageName);
3311 pw.print("Reset all modes for: ");
3312 if (userId == UserHandle.USER_ALL) {
3313 pw.print("all users");
3314 } else {
3315 pw.print("user "); pw.print(userId);
3316 }
3317 pw.print(", ");
3318 if (packageName == null) {
3319 pw.println("all packages");
3320 } else {
3321 pw.print("package "); pw.println(packageName);
3322 }
3323 return 0;
3324 }
3325 case "write-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07003326 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
3327 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003328 long token = Binder.clearCallingIdentity();
3329 try {
3330 synchronized (shell.mInternal) {
3331 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
3332 }
3333 shell.mInternal.writeState();
3334 pw.println("Current settings written.");
3335 } finally {
3336 Binder.restoreCallingIdentity(token);
3337 }
3338 return 0;
3339 }
3340 case "read-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07003341 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
3342 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003343 long token = Binder.clearCallingIdentity();
3344 try {
3345 shell.mInternal.readState();
3346 pw.println("Last settings read.");
3347 } finally {
3348 Binder.restoreCallingIdentity(token);
3349 }
3350 return 0;
3351 }
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05003352 case "start": {
3353 int res = shell.parseUserPackageOp(true, err);
3354 if (res < 0) {
3355 return res;
3356 }
3357
3358 if (shell.packageName != null) {
3359 shell.mInterface.startOperation(shell.mToken,
3360 shell.op, shell.packageUid, shell.packageName, true);
3361 } else {
3362 return -1;
3363 }
3364 return 0;
3365 }
3366 case "stop": {
3367 int res = shell.parseUserPackageOp(true, err);
3368 if (res < 0) {
3369 return res;
3370 }
3371
3372 if (shell.packageName != null) {
3373 shell.mInterface.finishOperation(shell.mToken,
3374 shell.op, shell.packageUid, shell.packageName);
3375 } else {
3376 return -1;
3377 }
3378 return 0;
3379 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003380 default:
3381 return shell.handleDefaultCommands(cmd);
3382 }
3383 } catch (RemoteException e) {
3384 pw.println("Remote exception: " + e);
3385 }
3386 return -1;
3387 }
3388
3389 private void dumpHelp(PrintWriter pw) {
3390 pw.println("AppOps service (appops) dump options:");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003391 pw.println(" -h");
3392 pw.println(" Print this help text.");
3393 pw.println(" --op [OP]");
3394 pw.println(" Limit output to data associated with the given app op code.");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003395 pw.println(" --mode [MODE]");
3396 pw.println(" Limit output to data associated with the given app op mode.");
3397 pw.println(" --package [PACKAGE]");
3398 pw.println(" Limit output to data associated with the given package name.");
Dianne Hackborn125dc532019-01-09 13:31:48 -08003399 pw.println(" --watchers");
3400 pw.println(" Only output the watcher sections.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003401 }
3402
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003403 private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
3404 long now, SimpleDateFormat sdf, Date date) {
3405 boolean hasTime = false;
3406 for (int i = 0; i < _NUM_UID_STATE; i++) {
3407 if (times[i] != 0) {
3408 hasTime = true;
3409 break;
3410 }
3411 }
3412 if (!hasTime) {
3413 return;
3414 }
3415 boolean first = true;
3416 for (int i = 0; i < _NUM_UID_STATE; i++) {
3417 if (times[i] != 0) {
3418 pw.print(first ? firstPrefix : prefix);
3419 first = false;
3420 pw.print(UID_STATE_NAMES[i]);
3421 pw.print(" = ");
3422 date.setTime(times[i]);
3423 pw.print(sdf.format(date));
3424 pw.print(" (");
3425 TimeUtils.formatDuration(times[i]-now, pw);
3426 pw.println(")");
3427 }
3428 }
3429 }
3430
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003431 @Override
3432 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003433 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003434
Svet Ganov8455ba22019-01-02 13:05:56 -08003435 int dumpOp = OP_NONE;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003436 String dumpPackage = null;
Svet Ganov8455ba22019-01-02 13:05:56 -08003437 int dumpUid = Process.INVALID_UID;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003438 int dumpMode = -1;
Dianne Hackborn125dc532019-01-09 13:31:48 -08003439 boolean dumpWatchers = false;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003440
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003441 if (args != null) {
3442 for (int i=0; i<args.length; i++) {
3443 String arg = args[i];
3444 if ("-h".equals(arg)) {
3445 dumpHelp(pw);
3446 return;
Tim Kilbourn8f1ea832015-08-26 15:07:37 -07003447 } else if ("-a".equals(arg)) {
3448 // dump all data
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003449 } else if ("--op".equals(arg)) {
3450 i++;
3451 if (i >= args.length) {
3452 pw.println("No argument for --op option");
3453 return;
3454 }
3455 dumpOp = Shell.strOpToOp(args[i], pw);
3456 if (dumpOp < 0) {
3457 return;
3458 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003459 } else if ("--package".equals(arg)) {
3460 i++;
3461 if (i >= args.length) {
3462 pw.println("No argument for --package option");
3463 return;
3464 }
3465 dumpPackage = args[i];
3466 try {
3467 dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
3468 PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
3469 0);
3470 } catch (RemoteException e) {
3471 }
3472 if (dumpUid < 0) {
3473 pw.println("Unknown package: " + dumpPackage);
3474 return;
3475 }
3476 dumpUid = UserHandle.getAppId(dumpUid);
3477 } else if ("--mode".equals(arg)) {
3478 i++;
3479 if (i >= args.length) {
3480 pw.println("No argument for --mode option");
3481 return;
3482 }
3483 dumpMode = Shell.strModeToMode(args[i], pw);
3484 if (dumpMode < 0) {
3485 return;
3486 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08003487 } else if ("--watchers".equals(arg)) {
3488 dumpWatchers = true;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003489 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
3490 pw.println("Unknown option: " + arg);
3491 return;
3492 } else {
3493 pw.println("Unknown command: " + arg);
3494 return;
3495 }
3496 }
3497 }
3498
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003499 synchronized (this) {
3500 pw.println("Current AppOps Service state:");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003501 mConstants.dump(pw);
3502 pw.println();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003503 final long now = System.currentTimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003504 final long nowElapsed = SystemClock.elapsedRealtime();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003505 final long nowUptime = SystemClock.uptimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003506 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
3507 final Date date = new Date();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003508 boolean needSep = false;
Dianne Hackborn125dc532019-01-09 13:31:48 -08003509 if (dumpOp < 0 && dumpMode < 0 && dumpPackage == null && mProfileOwners != null
3510 && !dumpWatchers) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07003511 pw.println(" Profile owners:");
3512 for (int poi = 0; poi < mProfileOwners.size(); poi++) {
3513 pw.print(" User #");
3514 pw.print(mProfileOwners.keyAt(poi));
3515 pw.print(": ");
3516 UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
3517 pw.println();
3518 }
3519 pw.println();
3520 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003521 if (mOpModeWatchers.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003522 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003523 for (int i=0; i<mOpModeWatchers.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003524 if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
3525 continue;
3526 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003527 boolean printedOpHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003528 ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003529 for (int j=0; j<callbacks.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003530 final ModeCallback cb = callbacks.valueAt(j);
Dianne Hackborn125dc532019-01-09 13:31:48 -08003531 if (dumpPackage != null
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003532 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3533 continue;
3534 }
3535 needSep = true;
3536 if (!printedHeader) {
3537 pw.println(" Op mode watchers:");
3538 printedHeader = true;
3539 }
3540 if (!printedOpHeader) {
3541 pw.print(" Op ");
3542 pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
3543 pw.println(":");
3544 printedOpHeader = true;
3545 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003546 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003547 pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003548 }
3549 }
3550 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003551 if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
3552 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003553 for (int i=0; i<mPackageModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003554 if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
3555 continue;
3556 }
3557 needSep = true;
3558 if (!printedHeader) {
3559 pw.println(" Package mode watchers:");
3560 printedHeader = true;
3561 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003562 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
3563 pw.println(":");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003564 ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003565 for (int j=0; j<callbacks.size(); j++) {
3566 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn68d76552017-02-27 15:32:03 -08003567 pw.println(callbacks.valueAt(j));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003568 }
3569 }
3570 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003571 if (mModeWatchers.size() > 0 && dumpOp < 0) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003572 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003573 for (int i=0; i<mModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003574 final ModeCallback cb = mModeWatchers.valueAt(i);
Dianne Hackborn125dc532019-01-09 13:31:48 -08003575 if (dumpPackage != null
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003576 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3577 continue;
3578 }
3579 needSep = true;
3580 if (!printedHeader) {
3581 pw.println(" All op mode watchers:");
3582 printedHeader = true;
3583 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003584 pw.print(" ");
3585 pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003586 pw.print(": "); pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003587 }
3588 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003589 if (mActiveWatchers.size() > 0 && dumpMode < 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003590 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003591 boolean printedHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003592 for (int i = 0; i < mActiveWatchers.size(); i++) {
3593 final SparseArray<ActiveCallback> activeWatchers = mActiveWatchers.valueAt(i);
3594 if (activeWatchers.size() <= 0) {
3595 continue;
3596 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003597 final ActiveCallback cb = activeWatchers.valueAt(0);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003598 if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
3599 continue;
3600 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08003601 if (dumpPackage != null
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003602 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3603 continue;
3604 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003605 if (!printedHeader) {
3606 pw.println(" All op active watchers:");
3607 printedHeader = true;
3608 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003609 pw.print(" ");
3610 pw.print(Integer.toHexString(System.identityHashCode(
3611 mActiveWatchers.keyAt(i))));
3612 pw.println(" ->");
3613 pw.print(" [");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003614 final int opCount = activeWatchers.size();
3615 for (i = 0; i < opCount; i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003616 if (i > 0) {
3617 pw.print(' ');
3618 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003619 pw.print(AppOpsManager.opToName(activeWatchers.keyAt(i)));
3620 if (i < opCount - 1) {
3621 pw.print(',');
3622 }
3623 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003624 pw.println("]");
3625 pw.print(" ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003626 pw.println(cb);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003627 }
3628 }
Svet Ganovb3d2ae22018-12-17 22:06:15 -08003629 if (mNotedWatchers.size() > 0 && dumpMode < 0) {
3630 needSep = true;
3631 boolean printedHeader = false;
3632 for (int i = 0; i < mNotedWatchers.size(); i++) {
3633 final SparseArray<NotedCallback> notedWatchers = mNotedWatchers.valueAt(i);
3634 if (notedWatchers.size() <= 0) {
3635 continue;
3636 }
3637 final NotedCallback cb = notedWatchers.valueAt(0);
3638 if (dumpOp >= 0 && notedWatchers.indexOfKey(dumpOp) < 0) {
3639 continue;
3640 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08003641 if (dumpPackage != null
Svet Ganovb3d2ae22018-12-17 22:06:15 -08003642 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3643 continue;
3644 }
3645 if (!printedHeader) {
3646 pw.println(" All op noted watchers:");
3647 printedHeader = true;
3648 }
3649 pw.print(" ");
3650 pw.print(Integer.toHexString(System.identityHashCode(
3651 mNotedWatchers.keyAt(i))));
3652 pw.println(" ->");
3653 pw.print(" [");
3654 final int opCount = notedWatchers.size();
3655 for (i = 0; i < opCount; i++) {
3656 if (i > 0) {
3657 pw.print(' ');
3658 }
3659 pw.print(AppOpsManager.opToName(notedWatchers.keyAt(i)));
3660 if (i < opCount - 1) {
3661 pw.print(',');
3662 }
3663 }
3664 pw.println("]");
3665 pw.print(" ");
3666 pw.println(cb);
3667 }
3668 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08003669 if (mClients.size() > 0 && dumpMode < 0 && !dumpWatchers) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003670 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003671 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003672 for (int i=0; i<mClients.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003673 boolean printedClient = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003674 ClientState cs = mClients.valueAt(i);
Svet Ganovf7b47252018-02-26 11:11:27 -08003675 if (cs.mStartedOps.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003676 boolean printedStarted = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003677 for (int j=0; j<cs.mStartedOps.size(); j++) {
3678 Op op = cs.mStartedOps.get(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003679 if (dumpOp >= 0 && op.op != dumpOp) {
3680 continue;
3681 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003682 if (dumpPackage != null && !dumpPackage.equals(op.packageName)) {
3683 continue;
3684 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003685 if (!printedHeader) {
3686 pw.println(" Clients:");
3687 printedHeader = true;
3688 }
3689 if (!printedClient) {
3690 pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
3691 pw.print(" "); pw.println(cs);
3692 printedClient = true;
3693 }
3694 if (!printedStarted) {
3695 pw.println(" Started ops:");
3696 printedStarted = true;
3697 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003698 pw.print(" "); pw.print("uid="); pw.print(op.uid);
3699 pw.print(" pkg="); pw.print(op.packageName);
3700 pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
3701 }
3702 }
3703 }
3704 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003705 if (mAudioRestrictions.size() > 0 && dumpOp < 0 && dumpPackage != null
Dianne Hackborn125dc532019-01-09 13:31:48 -08003706 && dumpMode < 0 && !dumpWatchers) {
John Spurlock1af30c72014-03-10 08:33:35 -04003707 boolean printedHeader = false;
3708 for (int o=0; o<mAudioRestrictions.size(); o++) {
3709 final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
3710 final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
3711 for (int i=0; i<restrictions.size(); i++) {
3712 if (!printedHeader){
3713 pw.println(" Audio Restrictions:");
3714 printedHeader = true;
3715 needSep = true;
3716 }
John Spurlock7b414672014-07-18 13:02:39 -04003717 final int usage = restrictions.keyAt(i);
John Spurlock1af30c72014-03-10 08:33:35 -04003718 pw.print(" "); pw.print(op);
John Spurlock7b414672014-07-18 13:02:39 -04003719 pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
John Spurlock1af30c72014-03-10 08:33:35 -04003720 Restriction r = restrictions.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003721 pw.print(": mode="); pw.println(AppOpsManager.modeToName(r.mode));
John Spurlock1af30c72014-03-10 08:33:35 -04003722 if (!r.exceptionPackages.isEmpty()) {
3723 pw.println(" Exceptions:");
3724 for (int j=0; j<r.exceptionPackages.size(); j++) {
3725 pw.print(" "); pw.println(r.exceptionPackages.valueAt(j));
3726 }
3727 }
3728 }
3729 }
3730 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003731 if (needSep) {
3732 pw.println();
3733 }
Svet Ganov2af57082015-07-30 08:44:20 -07003734 for (int i=0; i<mUidStates.size(); i++) {
3735 UidState uidState = mUidStates.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003736 final SparseIntArray opModes = uidState.opModes;
3737 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
3738
Dianne Hackborn125dc532019-01-09 13:31:48 -08003739 if (dumpWatchers) {
3740 continue;
3741 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003742 if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
3743 boolean hasOp = dumpOp < 0 || (uidState.opModes != null
3744 && uidState.opModes.indexOfKey(dumpOp) >= 0);
3745 boolean hasPackage = dumpPackage == null;
3746 boolean hasMode = dumpMode < 0;
3747 if (!hasMode && opModes != null) {
3748 for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
3749 if (opModes.valueAt(opi) == dumpMode) {
3750 hasMode = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003751 }
3752 }
3753 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003754 if (pkgOps != null) {
3755 for (int pkgi = 0;
Svet Ganov8455ba22019-01-02 13:05:56 -08003756 (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
3757 pkgi++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003758 Ops ops = pkgOps.valueAt(pkgi);
3759 if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
3760 hasOp = true;
3761 }
3762 if (!hasMode) {
3763 for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
3764 if (ops.valueAt(opi).mode == dumpMode) {
3765 hasMode = true;
3766 }
3767 }
3768 }
3769 if (!hasPackage && dumpPackage.equals(ops.packageName)) {
3770 hasPackage = true;
3771 }
3772 }
3773 }
3774 if (uidState.foregroundOps != null && !hasOp) {
3775 if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
3776 hasOp = true;
3777 }
3778 }
3779 if (!hasOp || !hasPackage || !hasMode) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003780 continue;
3781 }
3782 }
Svet Ganov2af57082015-07-30 08:44:20 -07003783
3784 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003785 pw.print(" state=");
3786 pw.println(UID_STATE_NAMES[uidState.state]);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003787 if (uidState.state != uidState.pendingState) {
3788 pw.print(" pendingState=");
3789 pw.println(UID_STATE_NAMES[uidState.pendingState]);
3790 }
3791 if (uidState.pendingStateCommitTime != 0) {
3792 pw.print(" pendingStateCommitTime=");
Dianne Hackborn9fb93502018-06-18 12:29:44 -07003793 TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003794 pw.println();
3795 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003796 if (uidState.startNesting != 0) {
3797 pw.print(" startNesting=");
3798 pw.println(uidState.startNesting);
3799 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003800 if (uidState.foregroundOps != null && (dumpMode < 0
3801 || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003802 pw.println(" foregroundOps:");
3803 for (int j = 0; j < uidState.foregroundOps.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003804 if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
3805 continue;
3806 }
3807 pw.print(" ");
3808 pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
3809 pw.print(": ");
3810 pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003811 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003812 pw.print(" hasForegroundWatchers=");
3813 pw.println(uidState.hasForegroundWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003814 }
Svet Ganovee438d42017-01-19 18:04:38 -08003815 needSep = true;
Svet Ganov2af57082015-07-30 08:44:20 -07003816
Svet Ganov2af57082015-07-30 08:44:20 -07003817 if (opModes != null) {
3818 final int opModeCount = opModes.size();
3819 for (int j = 0; j < opModeCount; j++) {
3820 final int code = opModes.keyAt(j);
3821 final int mode = opModes.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003822 if (dumpOp >= 0 && dumpOp != code) {
3823 continue;
3824 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003825 if (dumpMode >= 0 && dumpMode != mode) {
3826 continue;
3827 }
Svet Ganov2af57082015-07-30 08:44:20 -07003828 pw.print(" "); pw.print(AppOpsManager.opToName(code));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003829 pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
Svet Ganov2af57082015-07-30 08:44:20 -07003830 }
3831 }
3832
Svet Ganov2af57082015-07-30 08:44:20 -07003833 if (pkgOps == null) {
3834 continue;
3835 }
3836
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003837 for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003838 final Ops ops = pkgOps.valueAt(pkgi);
3839 if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
3840 continue;
3841 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003842 boolean printedPackage = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003843 for (int j=0; j<ops.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003844 final Op op = ops.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003845 if (dumpOp >= 0 && dumpOp != op.op) {
3846 continue;
3847 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003848 if (dumpMode >= 0 && dumpMode != op.mode) {
3849 continue;
3850 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003851 if (!printedPackage) {
3852 pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
3853 printedPackage = true;
3854 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003855 pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003856 pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003857 final int switchOp = AppOpsManager.opToSwitch(op.op);
3858 if (switchOp != op.op) {
3859 pw.print(" / switch ");
3860 pw.print(AppOpsManager.opToName(switchOp));
3861 final Op switchObj = ops.get(switchOp);
3862 int mode = switchObj != null
3863 ? switchObj.mode : AppOpsManager.opToDefaultMode(switchOp);
3864 pw.print("="); pw.print(AppOpsManager.modeToName(mode));
3865 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003866 pw.println("): ");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003867 dumpTimesLocked(pw,
3868 " Access: ",
3869 " ", op.time, now, sdf, date);
3870 dumpTimesLocked(pw,
3871 " Reject: ",
3872 " ", op.rejectTime, now, sdf, date);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003873 if (op.duration == -1) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003874 pw.print(" Running start at: ");
3875 TimeUtils.formatDuration(nowElapsed-op.startRealtime, pw);
3876 pw.println();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08003877 } else if (op.duration != 0) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003878 pw.print(" duration=");
3879 TimeUtils.formatDuration(op.duration, pw);
3880 pw.println();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003881 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003882 if (op.startNesting != 0) {
3883 pw.print(" startNesting=");
3884 pw.println(op.startNesting);
3885 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003886 }
3887 }
3888 }
Svet Ganovee438d42017-01-19 18:04:38 -08003889 if (needSep) {
3890 pw.println();
3891 }
3892
3893 final int userRestrictionCount = mOpUserRestrictions.size();
3894 for (int i = 0; i < userRestrictionCount; i++) {
3895 IBinder token = mOpUserRestrictions.keyAt(i);
3896 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Dianne Hackborn125dc532019-01-09 13:31:48 -08003897 boolean printedTokenHeader = false;
3898
3899 if (dumpMode >= 0 || dumpWatchers) {
3900 continue;
3901 }
Svet Ganovee438d42017-01-19 18:04:38 -08003902
3903 final int restrictionCount = restrictionState.perUserRestrictions != null
3904 ? restrictionState.perUserRestrictions.size() : 0;
Dianne Hackborn125dc532019-01-09 13:31:48 -08003905 if (restrictionCount > 0 && dumpPackage == null) {
3906 boolean printedOpsHeader = false;
Svet Ganovee438d42017-01-19 18:04:38 -08003907 for (int j = 0; j < restrictionCount; j++) {
3908 int userId = restrictionState.perUserRestrictions.keyAt(j);
3909 boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
3910 if (restrictedOps == null) {
3911 continue;
3912 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08003913 if (dumpOp >= 0 && (dumpOp >= restrictedOps.length
3914 || !restrictedOps[dumpOp])) {
3915 continue;
3916 }
3917 if (!printedTokenHeader) {
3918 pw.println(" User restrictions for token " + token + ":");
3919 printedTokenHeader = true;
3920 }
3921 if (!printedOpsHeader) {
3922 pw.println(" Restricted ops:");
3923 printedOpsHeader = true;
3924 }
Svet Ganovee438d42017-01-19 18:04:38 -08003925 StringBuilder restrictedOpsValue = new StringBuilder();
3926 restrictedOpsValue.append("[");
3927 final int restrictedOpCount = restrictedOps.length;
3928 for (int k = 0; k < restrictedOpCount; k++) {
3929 if (restrictedOps[k]) {
3930 if (restrictedOpsValue.length() > 1) {
3931 restrictedOpsValue.append(", ");
3932 }
3933 restrictedOpsValue.append(AppOpsManager.opToName(k));
3934 }
3935 }
3936 restrictedOpsValue.append("]");
3937 pw.print(" "); pw.print("user: "); pw.print(userId);
3938 pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
3939 }
3940 }
3941
3942 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
3943 ? restrictionState.perUserExcludedPackages.size() : 0;
Dianne Hackborn125dc532019-01-09 13:31:48 -08003944 if (excludedPackageCount > 0 && dumpOp < 0) {
3945 boolean printedPackagesHeader = false;
Svet Ganovee438d42017-01-19 18:04:38 -08003946 for (int j = 0; j < excludedPackageCount; j++) {
3947 int userId = restrictionState.perUserExcludedPackages.keyAt(j);
3948 String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
Dianne Hackborn125dc532019-01-09 13:31:48 -08003949 if (packageNames == null) {
3950 continue;
3951 }
3952 boolean hasPackage;
3953 if (dumpPackage != null) {
3954 hasPackage = false;
3955 for (String pkg : packageNames) {
3956 if (dumpPackage.equals(pkg)) {
3957 hasPackage = true;
3958 break;
3959 }
3960 }
3961 } else {
3962 hasPackage = true;
3963 }
3964 if (!hasPackage) {
3965 continue;
3966 }
3967 if (!printedTokenHeader) {
3968 pw.println(" User restrictions for token " + token + ":");
3969 printedTokenHeader = true;
3970 }
3971 if (!printedPackagesHeader) {
3972 pw.println(" Excluded packages:");
3973 printedPackagesHeader = true;
3974 }
Svet Ganovee438d42017-01-19 18:04:38 -08003975 pw.print(" "); pw.print("user: "); pw.print(userId);
3976 pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
3977 }
3978 }
3979 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003980 }
Svet Ganov8455ba22019-01-02 13:05:56 -08003981
3982 // Must not hold the appops lock
3983 mHistoricalRegistry.dump(" ", pw, dumpUid, dumpPackage, dumpOp);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003984 }
John Spurlock1af30c72014-03-10 08:33:35 -04003985
3986 private static final class Restriction {
3987 private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
3988 int mode;
3989 ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
3990 }
Jason Monk62062992014-05-06 09:55:28 -04003991
3992 @Override
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003993 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
Jason Monk62062992014-05-06 09:55:28 -04003994 checkSystemUid("setUserRestrictions");
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003995 Preconditions.checkNotNull(restrictions);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003996 Preconditions.checkNotNull(token);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003997 for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
Jason Monk62062992014-05-06 09:55:28 -04003998 String restriction = AppOpsManager.opToRestriction(i);
Suprabh Shukla64e0dcb2016-05-24 16:23:11 -07003999 if (restriction != null) {
4000 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
4001 userHandle, null);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004002 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004003 }
4004 }
4005
4006 @Override
Ruben Brunk29931bc2016-03-11 00:24:26 -08004007 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
4008 String[] exceptionPackages) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004009 if (Binder.getCallingPid() != Process.myPid()) {
4010 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
4011 Binder.getCallingPid(), Binder.getCallingUid(), null);
4012 }
4013 if (userHandle != UserHandle.getCallingUserId()) {
4014 if (mContext.checkCallingOrSelfPermission(Manifest.permission
4015 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
4016 && mContext.checkCallingOrSelfPermission(Manifest.permission
4017 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
4018 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
4019 + " INTERACT_ACROSS_USERS to interact cross user ");
Jason Monk62062992014-05-06 09:55:28 -04004020 }
4021 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004022 verifyIncomingOp(code);
4023 Preconditions.checkNotNull(token);
Ruben Brunk29931bc2016-03-11 00:24:26 -08004024 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004025 }
4026
4027 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
Ruben Brunk29931bc2016-03-11 00:24:26 -08004028 int userHandle, String[] exceptionPackages) {
Svet Ganov442ed572016-08-17 17:29:43 -07004029 synchronized (AppOpsService.this) {
4030 ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
4031
4032 if (restrictionState == null) {
4033 try {
4034 restrictionState = new ClientRestrictionState(token);
4035 } catch (RemoteException e) {
4036 return;
4037 }
4038 mOpUserRestrictions.put(token, restrictionState);
Ruben Brunk29931bc2016-03-11 00:24:26 -08004039 }
Svet Ganov442ed572016-08-17 17:29:43 -07004040
4041 if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004042 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07004043 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
Svet Ganov442ed572016-08-17 17:29:43 -07004044 }
4045
4046 if (restrictionState.isDefault()) {
4047 mOpUserRestrictions.remove(token);
4048 restrictionState.destroy();
4049 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08004050 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -04004051 }
4052
Svet Ganov3a95f832018-03-23 17:44:30 -07004053 private void notifyWatchersOfChange(int code, int uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004054 final ArraySet<ModeCallback> clonedCallbacks;
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004055 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004056 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004057 if (callbacks == null) {
4058 return;
4059 }
Dianne Hackborn68d76552017-02-27 15:32:03 -08004060 clonedCallbacks = new ArraySet<>(callbacks);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004061 }
4062
Svet Ganov3a95f832018-03-23 17:44:30 -07004063 notifyOpChanged(clonedCallbacks, code, uid, null);
Jason Monk62062992014-05-06 09:55:28 -04004064 }
4065
4066 @Override
4067 public void removeUser(int userHandle) throws RemoteException {
4068 checkSystemUid("removeUser");
Svet Ganov442ed572016-08-17 17:29:43 -07004069 synchronized (AppOpsService.this) {
4070 final int tokenCount = mOpUserRestrictions.size();
4071 for (int i = tokenCount - 1; i >= 0; i--) {
4072 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
4073 opRestrictions.removeUser(userHandle);
4074 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07004075 removeUidsForUserLocked(userHandle);
4076 }
4077 }
4078
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004079 @Override
4080 public boolean isOperationActive(int code, int uid, String packageName) {
Svet Ganovf7b47252018-02-26 11:11:27 -08004081 if (Binder.getCallingUid() != uid) {
4082 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
4083 != PackageManager.PERMISSION_GRANTED) {
4084 return false;
4085 }
4086 }
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004087 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004088 final String resolvedPackageName = resolvePackageName(uid, packageName);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004089 if (resolvedPackageName == null) {
4090 return false;
4091 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004092 synchronized (AppOpsService.this) {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004093 for (int i = mClients.size() - 1; i >= 0; i--) {
4094 final ClientState client = mClients.valueAt(i);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004095 for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
4096 final Op op = client.mStartedOps.get(j);
4097 if (op.op == code && op.uid == uid) return true;
4098 }
4099 }
4100 }
4101 return false;
4102 }
4103
Svet Ganov8455ba22019-01-02 13:05:56 -08004104 @Override
4105 public void setHistoryParameters(@AppOpsManager.HistoricalMode int mode,
4106 long baseSnapshotInterval, int compressionStep) {
4107 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
4108 "setHistoryParameters");
4109 // Must not hold the appops lock
4110 mHistoricalRegistry.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
4111 }
4112
4113 @Override
4114 public void offsetHistory(long offsetMillis) {
4115 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
4116 "offsetHistory");
4117 // Must not hold the appops lock
4118 mHistoricalRegistry.offsetHistory(offsetMillis);
4119 }
4120
4121 @Override
4122 public void addHistoricalOps(HistoricalOps ops) {
4123 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
4124 "addHistoricalOps");
4125 // Must not hold the appops lock
4126 mHistoricalRegistry.addHistoricalOps(ops);
4127 }
4128
4129 @Override
4130 public void resetHistoryParameters() {
4131 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
4132 "resetHistoryParameters");
4133 // Must not hold the appops lock
4134 mHistoricalRegistry.resetHistoryParameters();
4135 }
4136
4137 @Override
4138 public void clearHistory() {
4139 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
4140 "clearHistory");
4141 // Must not hold the appops lock
4142 mHistoricalRegistry.clearHistory();
4143 }
4144
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07004145 private void removeUidsForUserLocked(int userHandle) {
4146 for (int i = mUidStates.size() - 1; i >= 0; --i) {
4147 final int uid = mUidStates.keyAt(i);
4148 if (UserHandle.getUserId(uid) == userHandle) {
4149 mUidStates.removeAt(i);
4150 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004151 }
4152 }
4153
Jason Monk62062992014-05-06 09:55:28 -04004154 private void checkSystemUid(String function) {
4155 int uid = Binder.getCallingUid();
4156 if (uid != Process.SYSTEM_UID) {
4157 throw new SecurityException(function + " must by called by the system");
4158 }
4159 }
4160
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00004161 private static String resolvePackageName(int uid, String packageName) {
Svet Ganov82f09bc2018-01-12 22:08:40 -08004162 if (uid == Process.ROOT_UID) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00004163 return "root";
4164 } else if (uid == Process.SHELL_UID) {
4165 return "com.android.shell";
Svet Ganov82f09bc2018-01-12 22:08:40 -08004166 } else if (uid == Process.MEDIA_UID) {
4167 return "media";
4168 } else if (uid == Process.AUDIOSERVER_UID) {
4169 return "audioserver";
4170 } else if (uid == Process.CAMERASERVER_UID) {
4171 return "cameraserver";
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00004172 } else if (uid == Process.SYSTEM_UID && packageName == null) {
4173 return "android";
4174 }
4175 return packageName;
4176 }
4177
Svet Ganov82f09bc2018-01-12 22:08:40 -08004178 private static int resolveUid(String packageName) {
4179 if (packageName == null) {
4180 return -1;
4181 }
4182 switch (packageName) {
4183 case "root":
4184 return Process.ROOT_UID;
4185 case "shell":
4186 return Process.SHELL_UID;
4187 case "media":
4188 return Process.MEDIA_UID;
4189 case "audioserver":
4190 return Process.AUDIOSERVER_UID;
4191 case "cameraserver":
4192 return Process.CAMERASERVER_UID;
4193 }
4194 return -1;
4195 }
4196
Svet Ganov2af57082015-07-30 08:44:20 -07004197 private static String[] getPackagesForUid(int uid) {
Svet Ganovf3807aa2015-08-02 10:09:56 -07004198 String[] packageNames = null;
Philip P. Moltmann159d98b2018-12-20 08:30:53 -08004199
4200 // Very early during boot the package manager is not yet or not yet fully started. At this
4201 // time there are no packages yet.
4202 if (AppGlobals.getPackageManager() != null) {
4203 try {
4204 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
4205 } catch (RemoteException e) {
4206 /* ignore - local call */
4207 }
Svet Ganov2af57082015-07-30 08:44:20 -07004208 }
Svet Ganovf3807aa2015-08-02 10:09:56 -07004209 if (packageNames == null) {
4210 return EmptyArray.STRING;
4211 }
4212 return packageNames;
Svet Ganov2af57082015-07-30 08:44:20 -07004213 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004214
Svet Ganov8455ba22019-01-02 13:05:56 -08004215 private static void checkValidOpsOrNull(String[] opNames) {
4216 if (opNames != null) {
4217 for (String opName : opNames) {
4218 if (AppOpsManager.strOpToOp(opName) == AppOpsManager.OP_NONE) {
4219 throw new IllegalArgumentException("Unknown op: " + opName);
4220 }
4221 }
4222 }
4223 }
4224
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004225 private final class ClientRestrictionState implements DeathRecipient {
4226 private final IBinder token;
4227 SparseArray<boolean[]> perUserRestrictions;
4228 SparseArray<String[]> perUserExcludedPackages;
4229
4230 public ClientRestrictionState(IBinder token)
4231 throws RemoteException {
4232 token.linkToDeath(this, 0);
4233 this.token = token;
4234 }
4235
4236 public boolean setRestriction(int code, boolean restricted,
4237 String[] excludedPackages, int userId) {
4238 boolean changed = false;
4239
4240 if (perUserRestrictions == null && restricted) {
4241 perUserRestrictions = new SparseArray<>();
4242 }
4243
Philip P. Moltmanne683f192017-06-23 14:05:04 -07004244 int[] users;
4245 if (userId == UserHandle.USER_ALL) {
4246 List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004247
Philip P. Moltmanne683f192017-06-23 14:05:04 -07004248 users = new int[liveUsers.size()];
4249 for (int i = 0; i < liveUsers.size(); i++) {
4250 users[i] = liveUsers.get(i).id;
4251 }
4252 } else {
4253 users = new int[]{userId};
4254 }
4255
4256 if (perUserRestrictions != null) {
4257 int numUsers = users.length;
4258
4259 for (int i = 0; i < numUsers; i++) {
4260 int thisUserId = users[i];
4261
4262 boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
4263 if (userRestrictions == null && restricted) {
4264 userRestrictions = new boolean[AppOpsManager._NUM_OP];
4265 perUserRestrictions.put(thisUserId, userRestrictions);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004266 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07004267 if (userRestrictions != null && userRestrictions[code] != restricted) {
4268 userRestrictions[code] = restricted;
4269 if (!restricted && isDefault(userRestrictions)) {
4270 perUserRestrictions.remove(thisUserId);
4271 userRestrictions = null;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004272 }
4273 changed = true;
4274 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07004275
4276 if (userRestrictions != null) {
4277 final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
4278 if (perUserExcludedPackages == null && !noExcludedPackages) {
4279 perUserExcludedPackages = new SparseArray<>();
4280 }
4281 if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
4282 perUserExcludedPackages.get(thisUserId))) {
4283 if (noExcludedPackages) {
4284 perUserExcludedPackages.remove(thisUserId);
4285 if (perUserExcludedPackages.size() <= 0) {
4286 perUserExcludedPackages = null;
4287 }
4288 } else {
4289 perUserExcludedPackages.put(thisUserId, excludedPackages);
4290 }
4291 changed = true;
4292 }
4293 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004294 }
4295 }
4296
4297 return changed;
4298 }
4299
4300 public boolean hasRestriction(int restriction, String packageName, int userId) {
4301 if (perUserRestrictions == null) {
4302 return false;
4303 }
4304 boolean[] restrictions = perUserRestrictions.get(userId);
4305 if (restrictions == null) {
4306 return false;
4307 }
4308 if (!restrictions[restriction]) {
4309 return false;
4310 }
4311 if (perUserExcludedPackages == null) {
4312 return true;
4313 }
4314 String[] perUserExclusions = perUserExcludedPackages.get(userId);
4315 if (perUserExclusions == null) {
4316 return true;
4317 }
4318 return !ArrayUtils.contains(perUserExclusions, packageName);
4319 }
4320
4321 public void removeUser(int userId) {
4322 if (perUserExcludedPackages != null) {
4323 perUserExcludedPackages.remove(userId);
4324 if (perUserExcludedPackages.size() <= 0) {
4325 perUserExcludedPackages = null;
4326 }
4327 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07004328 if (perUserRestrictions != null) {
4329 perUserRestrictions.remove(userId);
4330 if (perUserRestrictions.size() <= 0) {
4331 perUserRestrictions = null;
4332 }
4333 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004334 }
4335
4336 public boolean isDefault() {
4337 return perUserRestrictions == null || perUserRestrictions.size() <= 0;
4338 }
4339
4340 @Override
4341 public void binderDied() {
4342 synchronized (AppOpsService.this) {
4343 mOpUserRestrictions.remove(token);
4344 if (perUserRestrictions == null) {
4345 return;
4346 }
4347 final int userCount = perUserRestrictions.size();
4348 for (int i = 0; i < userCount; i++) {
4349 final boolean[] restrictions = perUserRestrictions.valueAt(i);
4350 final int restrictionCount = restrictions.length;
4351 for (int j = 0; j < restrictionCount; j++) {
4352 if (restrictions[j]) {
4353 final int changedCode = j;
Svet Ganov3a95f832018-03-23 17:44:30 -07004354 mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004355 }
4356 }
4357 }
4358 destroy();
4359 }
4360 }
4361
4362 public void destroy() {
4363 token.unlinkToDeath(this, 0);
4364 }
4365
4366 private boolean isDefault(boolean[] array) {
4367 if (ArrayUtils.isEmpty(array)) {
4368 return true;
4369 }
4370 for (boolean value : array) {
4371 if (value) {
4372 return false;
4373 }
4374 }
4375 return true;
4376 }
4377 }
Dianne Hackbornd5254412018-05-11 18:02:58 -07004378
4379 private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
4380 @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
4381 synchronized (AppOpsService.this) {
4382 mProfileOwners = owners;
4383 }
4384 }
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07004385
4386 @Override
Philip P. Moltmann159d98b2018-12-20 08:30:53 -08004387 public void setUidMode(int code, int uid, int mode) {
4388 AppOpsService.this.setUidMode(code, uid, mode);
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07004389 }
Dianne Hackbornd5254412018-05-11 18:02:58 -07004390 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08004391}