blob: 366766e2e47bc663ab6eb73bb228acccae200646 [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
Hui Yu26969322019-08-21 14:56:35 -070019import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
Svet Ganovaf189e32019-02-15 18:45:29 -080020import static android.app.AppOpsManager.MAX_PRIORITY_UID_STATE;
21import static android.app.AppOpsManager.MIN_PRIORITY_UID_STATE;
Suprabh Shukla7e017922019-08-05 17:13:23 -070022import static android.app.AppOpsManager.OP_CAMERA;
Svet Ganovaf189e32019-02-15 18:45:29 -080023import static android.app.AppOpsManager.OP_FLAGS_ALL;
Svet Ganov8455ba22019-01-02 13:05:56 -080024import static android.app.AppOpsManager.OP_NONE;
Philip P. Moltmanndde07852019-01-25 16:42:36 -080025import static android.app.AppOpsManager.OP_PLAY_AUDIO;
Suprabh Shukla7e017922019-08-05 17:13:23 -070026import static android.app.AppOpsManager.OP_RECORD_AUDIO;
Hai Zhang2b98fb32018-09-21 15:18:46 -070027import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
28import static android.app.AppOpsManager.UID_STATE_CACHED;
29import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
30import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
Svet Ganovaf189e32019-02-15 18:45:29 -080031import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
Hai Zhang2b98fb32018-09-21 15:18:46 -070032import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
33import static android.app.AppOpsManager.UID_STATE_TOP;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -070034import static android.app.AppOpsManager._NUM_OP;
Eugene Suslae4ee2c22018-11-05 12:23:30 -080035import static android.app.AppOpsManager.modeToName;
36import static android.app.AppOpsManager.opToName;
Svet Ganovaf189e32019-02-15 18:45:29 -080037import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -070038import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
Hai Zhang2b98fb32018-09-21 15:18:46 -070039
Philip P. Moltmanne683f192017-06-23 14:05:04 -070040import android.Manifest;
Svet Ganovad0a49b2018-10-29 10:07:08 -070041import android.annotation.NonNull;
42import android.annotation.Nullable;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070043import android.app.ActivityManager;
44import android.app.ActivityThread;
45import android.app.AppGlobals;
46import android.app.AppOpsManager;
Svet Ganov8455ba22019-01-02 13:05:56 -080047import android.app.AppOpsManager.HistoricalOps;
Svet Ganov23c88db2019-01-22 20:38:11 -080048import android.app.AppOpsManager.HistoricalOpsRequest;
Svet Ganovaf189e32019-02-15 18:45:29 -080049import android.app.AppOpsManager.Mode;
50import android.app.AppOpsManager.OpEntry;
Philip P. Moltmann02cd91b2019-11-05 14:29:52 -080051import android.app.AppOpsManager.OpFeatureEntry;
Svet Ganovaf189e32019-02-15 18:45:29 -080052import android.app.AppOpsManager.OpFlags;
Dianne Hackbornd5254412018-05-11 18:02:58 -070053import android.app.AppOpsManagerInternal;
Svet Ganovd873ae62018-06-25 16:39:23 -070054import android.app.AppOpsManagerInternal.CheckOpsDelegate;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -070055import android.app.AsyncNotedAppOp;
Suprabh Shukla3017fe42018-11-08 19:00:01 -080056import android.content.BroadcastReceiver;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070057import android.content.ContentResolver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070058import android.content.Context;
Suprabh Shukla3017fe42018-11-08 19:00:01 -080059import android.content.Intent;
60import android.content.IntentFilter;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070061import android.content.pm.ApplicationInfo;
62import android.content.pm.IPackageManager;
63import android.content.pm.PackageManager;
64import android.content.pm.PackageManagerInternal;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -070065import android.content.pm.PermissionInfo;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070066import android.content.pm.UserInfo;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070067import android.database.ContentObserver;
Yin-Chia Yeh51d85162019-08-06 15:31:39 -070068import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070069import android.net.Uri;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070070import android.os.AsyncTask;
71import android.os.Binder;
Hai Zhang408ca762019-10-14 14:09:35 -070072import android.os.Build;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070073import android.os.Bundle;
74import android.os.Handler;
75import android.os.IBinder;
76import android.os.Process;
Svet Ganov8455ba22019-01-02 13:05:56 -080077import android.os.RemoteCallback;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -070078import android.os.RemoteCallbackList;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070079import android.os.RemoteException;
80import android.os.ResultReceiver;
81import android.os.ServiceManager;
82import android.os.ShellCallback;
83import android.os.ShellCommand;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070084import android.os.SystemClock;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070085import android.os.UserHandle;
86import android.os.UserManager;
Sudheer Shanka98cb3f02018-08-17 16:10:29 -070087import android.os.storage.StorageManager;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070088import android.os.storage.StorageManagerInternal;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070089import android.provider.Settings;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070090import android.util.ArrayMap;
91import android.util.ArraySet;
92import android.util.AtomicFile;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070093import android.util.KeyValueListParser;
Svet Ganovaf189e32019-02-15 18:45:29 -080094import android.util.LongSparseArray;
95import android.util.LongSparseLongArray;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -070096import android.util.Pair;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070097import android.util.Slog;
98import android.util.SparseArray;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -070099import android.util.SparseBooleanArray;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700100import android.util.SparseIntArray;
101import android.util.TimeUtils;
102import android.util.Xml;
103
Todd Kennedy556efba2018-11-15 07:43:55 -0800104import com.android.internal.annotations.GuardedBy;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700105import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800106import com.android.internal.app.IAppOpsActiveCallback;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700107import com.android.internal.app.IAppOpsAsyncNotedCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700108import com.android.internal.app.IAppOpsCallback;
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800109import com.android.internal.app.IAppOpsNotedCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700110import com.android.internal.app.IAppOpsService;
111import com.android.internal.os.Zygote;
112import com.android.internal.util.ArrayUtils;
Hai Zhange53e4c52019-10-08 18:57:01 -0700113import com.android.internal.util.CollectionUtils;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700114import com.android.internal.util.DumpUtils;
115import com.android.internal.util.FastXmlSerializer;
116import com.android.internal.util.Preconditions;
117import com.android.internal.util.XmlUtils;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800118import com.android.internal.util.function.pooled.PooledLambda;
Svet Ganov8455ba22019-01-02 13:05:56 -0800119import com.android.server.LocalServices;
120import com.android.server.LockGuard;
Philip P. Moltmanndde07852019-01-25 16:42:36 -0800121
Philip P. Moltmann02cd91b2019-11-05 14:29:52 -0800122import libcore.util.EmptyArray;
123
124import org.xmlpull.v1.XmlPullParser;
125import org.xmlpull.v1.XmlPullParserException;
126import org.xmlpull.v1.XmlSerializer;
127
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800128import java.io.File;
129import java.io.FileDescriptor;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800130import java.io.FileInputStream;
131import java.io.FileNotFoundException;
132import java.io.FileOutputStream;
133import java.io.IOException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800134import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100135import java.nio.charset.StandardCharsets;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700136import java.text.SimpleDateFormat;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800137import java.util.ArrayList;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700138import java.util.Arrays;
Svetoslav215b44a2015-08-04 19:03:40 -0700139import java.util.Collections;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700140import java.util.Date;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800141import java.util.HashMap;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800142import java.util.Iterator;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800143import java.util.List;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700144import java.util.Map;
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700145import java.util.Objects;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800146
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800147public class AppOpsService extends IAppOpsService.Stub {
148 static final String TAG = "AppOps";
Dianne Hackborn35654b62013-01-14 17:38:02 -0800149 static final boolean DEBUG = false;
150
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700151 private static final int NO_VERSION = -1;
152 /** Increment by one every time and add the corresponding upgrade logic in
153 * {@link #upgradeLocked(int)} below. The first version was 1 */
154 private static final int CURRENT_VERSION = 1;
155
Dianne Hackborn35654b62013-01-14 17:38:02 -0800156 // Write at most every 30 minutes.
157 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800158
Svet Ganov3a95f832018-03-23 17:44:30 -0700159 // Constant meaning that any UID should be matched when dispatching callbacks
160 private static final int UID_ANY = -2;
161
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700162 // Map from process states to the uid states we track.
163 private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
164 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
165 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
166 UID_STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
Amith Yamasanif235d0b2019-03-20 22:49:43 -0700167 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_TOP
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700168 UID_STATE_FOREGROUND_SERVICE, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
169 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
Hui Yu26969322019-08-21 14:56:35 -0700170 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700171 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
172 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
173 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_BACKUP
174 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_SERVICE
175 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_RECEIVER
176 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
177 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
178 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HOME
179 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
180 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
181 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
182 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_RECENT
183 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
184 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT
185 };
186
Suprabh Shukla7e017922019-08-05 17:13:23 -0700187 private static final int[] OPS_RESTRICTED_ON_SUSPEND = {
188 OP_PLAY_AUDIO,
189 OP_RECORD_AUDIO,
190 OP_CAMERA,
191 };
192
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700193 private static final int MAX_UNFORWARED_OPS = 10;
194
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800195 Context mContext;
196 final AtomicFile mFile;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800197 final Handler mHandler;
198
Dianne Hackbornd5254412018-05-11 18:02:58 -0700199 private final AppOpsManagerInternalImpl mAppOpsManagerInternal
200 = new AppOpsManagerInternalImpl();
201
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700202 /**
203 * Registered callbacks, called from {@link #noteAsyncOp}.
204 *
205 * <p>(package name, uid) -> callbacks
206 *
207 * @see #getAsyncNotedOpsKey(String, int)
208 */
209 @GuardedBy("this")
210 private final ArrayMap<Pair<String, Integer>, RemoteCallbackList<IAppOpsAsyncNotedCallback>>
211 mAsyncOpWatchers = new ArrayMap<>();
212
213 /**
214 * Async note-ops collected from {@link #noteAsyncOp} that have not been delivered to a
215 * callback yet.
216 *
217 * <p>(package name, uid) -> list&lt;ops&gt;
218 *
219 * @see #getAsyncNotedOpsKey(String, int)
220 */
221 @GuardedBy("this")
222 private final ArrayMap<Pair<String, Integer>, ArrayList<AsyncNotedAppOp>>
223 mUnforwardedAsyncNotedOps = new ArrayMap<>();
224
Dianne Hackborn35654b62013-01-14 17:38:02 -0800225 boolean mWriteScheduled;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800226 boolean mFastWriteScheduled;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800227 final Runnable mWriteRunner = new Runnable() {
228 public void run() {
229 synchronized (AppOpsService.this) {
230 mWriteScheduled = false;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800231 mFastWriteScheduled = false;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800232 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
233 @Override protected Void doInBackground(Void... params) {
234 writeState();
235 return null;
236 }
237 };
238 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
239 }
240 }
241 };
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800242
Eugene Susla463d5922019-07-17 18:14:15 -0700243 @GuardedBy("this")
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700244 @VisibleForTesting
245 final SparseArray<UidState> mUidStates = new SparseArray<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800246
Svet Ganov47641072019-06-06 12:57:12 -0700247 final HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this);
Svet Ganov8455ba22019-01-02 13:05:56 -0800248
Dianne Hackborn9fb93502018-06-18 12:29:44 -0700249 long mLastRealtime;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700250
Ruben Brunk29931bc2016-03-11 00:24:26 -0800251 /*
252 * These are app op restrictions imposed per user from various parties.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800253 */
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700254 private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
Jason Monk62062992014-05-06 09:55:28 -0400255
Dianne Hackbornd5254412018-05-11 18:02:58 -0700256 SparseIntArray mProfileOwners;
257
Todd Kennedy556efba2018-11-15 07:43:55 -0800258 @GuardedBy("this")
Svet Ganovd873ae62018-06-25 16:39:23 -0700259 private CheckOpsDelegate mCheckOpsDelegate;
260
Hai Zhange53e4c52019-10-08 18:57:01 -0700261 @GuardedBy("this")
262 private SparseArray<List<Integer>> mSwitchOpToOps;
263
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700264 /**
265 * All times are in milliseconds. These constants are kept synchronized with the system
266 * global Settings. Any access to this class or its fields should be done while
267 * holding the AppOpsService lock.
268 */
Amith Yamasani23d4cd72019-04-10 17:57:00 -0700269 @VisibleForTesting
270 final class Constants extends ContentObserver {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700271 // Key names stored in the settings value.
Dianne Hackborne93ab412018-05-14 17:52:30 -0700272 private static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
273 private static final String KEY_FG_SERVICE_STATE_SETTLE_TIME
274 = "fg_service_state_settle_time";
275 private static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700276
277 /**
Dianne Hackborne93ab412018-05-14 17:52:30 -0700278 * How long we want for a drop in uid state from top to settle before applying it.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700279 * @see Settings.Global#APP_OPS_CONSTANTS
Dianne Hackborne93ab412018-05-14 17:52:30 -0700280 * @see #KEY_TOP_STATE_SETTLE_TIME
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700281 */
Dianne Hackborne93ab412018-05-14 17:52:30 -0700282 public long TOP_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700283
Dianne Hackborne93ab412018-05-14 17:52:30 -0700284 /**
285 * How long we want for a drop in uid state from foreground to settle before applying it.
286 * @see Settings.Global#APP_OPS_CONSTANTS
287 * @see #KEY_FG_SERVICE_STATE_SETTLE_TIME
288 */
289 public long FG_SERVICE_STATE_SETTLE_TIME;
290
291 /**
292 * How long we want for a drop in uid state from background to settle before applying it.
293 * @see Settings.Global#APP_OPS_CONSTANTS
294 * @see #KEY_BG_STATE_SETTLE_TIME
295 */
296 public long BG_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700297
298 private final KeyValueListParser mParser = new KeyValueListParser(',');
299 private ContentResolver mResolver;
300
301 public Constants(Handler handler) {
302 super(handler);
303 updateConstants();
304 }
305
306 public void startMonitoring(ContentResolver resolver) {
307 mResolver = resolver;
308 mResolver.registerContentObserver(
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700309 Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700310 false, this);
311 updateConstants();
312 }
313
314 @Override
315 public void onChange(boolean selfChange, Uri uri) {
316 updateConstants();
317 }
318
319 private void updateConstants() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700320 String value = mResolver != null ? Settings.Global.getString(mResolver,
321 Settings.Global.APP_OPS_CONSTANTS) : "";
322
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700323 synchronized (AppOpsService.this) {
324 try {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700325 mParser.setString(value);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700326 } catch (IllegalArgumentException e) {
327 // Failed to parse the settings string, log this and move on
328 // with defaults.
329 Slog.e(TAG, "Bad app ops settings", e);
330 }
Dianne Hackborne93ab412018-05-14 17:52:30 -0700331 TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
332 KEY_TOP_STATE_SETTLE_TIME, 30 * 1000L);
333 FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
334 KEY_FG_SERVICE_STATE_SETTLE_TIME, 10 * 1000L);
335 BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
336 KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700337 }
338 }
339
340 void dump(PrintWriter pw) {
341 pw.println(" Settings:");
342
Dianne Hackborne93ab412018-05-14 17:52:30 -0700343 pw.print(" "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("=");
344 TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700345 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700346 pw.print(" "); pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME); pw.print("=");
347 TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700348 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700349 pw.print(" "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("=");
350 TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700351 pw.println();
352 }
353 }
354
Amith Yamasani23d4cd72019-04-10 17:57:00 -0700355 @VisibleForTesting
356 final Constants mConstants;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700357
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700358 @VisibleForTesting
359 static final class UidState {
Svet Ganov2af57082015-07-30 08:44:20 -0700360 public final int uid;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700361
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700362 public int state = UID_STATE_CACHED;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700363 public int pendingState = UID_STATE_CACHED;
364 public long pendingStateCommitTime;
Hui Yu26969322019-08-21 14:56:35 -0700365 public int capability;
366 public int pendingCapability;
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700367 // For all features combined
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700368 public int startNesting;
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700369
Svet Ganov2af57082015-07-30 08:44:20 -0700370 public ArrayMap<String, Ops> pkgOps;
Hai Zhang93540ca2019-09-28 00:04:18 +0000371 public SparseIntArray opModes;
Svet Ganov2af57082015-07-30 08:44:20 -0700372
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700373 // true indicates there is an interested observer, false there isn't but it has such an op
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700374 public SparseBooleanArray foregroundOps;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700375 public boolean hasForegroundWatchers;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700376
Svet Ganov2af57082015-07-30 08:44:20 -0700377 public UidState(int uid) {
378 this.uid = uid;
379 }
380
381 public void clear() {
382 pkgOps = null;
383 opModes = null;
384 }
385
386 public boolean isDefault() {
387 return (pkgOps == null || pkgOps.isEmpty())
Svet Ganovaf189e32019-02-15 18:45:29 -0800388 && (opModes == null || opModes.size() <= 0)
389 && (state == UID_STATE_CACHED
390 && (pendingState == UID_STATE_CACHED));
Svet Ganov2af57082015-07-30 08:44:20 -0700391 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700392
Svet Ganovaf189e32019-02-15 18:45:29 -0800393 int evalMode(int op, int mode) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700394 if (mode == AppOpsManager.MODE_FOREGROUND) {
Hui Yu26969322019-08-21 14:56:35 -0700395 if (state <= UID_STATE_TOP) {
396 // process is in foreground.
397 return AppOpsManager.MODE_ALLOWED;
398 } else if (state <= AppOpsManager.resolveFirstUnrestrictedUidState(op)) {
399 // process is in foreground, check its capability.
400 switch (op) {
401 case AppOpsManager.OP_FINE_LOCATION:
402 case AppOpsManager.OP_COARSE_LOCATION:
403 case AppOpsManager.OP_MONITOR_LOCATION:
404 case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
405 return ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0)
406 ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
407 default:
408 return AppOpsManager.MODE_ALLOWED;
409 }
410 } else {
411 // process is not in foreground.
412 return AppOpsManager.MODE_IGNORED;
413 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700414 }
415 return mode;
416 }
417
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700418 private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
419 SparseBooleanArray which) {
420 boolean curValue = which.get(op, false);
421 ArraySet<ModeCallback> callbacks = watchers.get(op);
422 if (callbacks != null) {
423 for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
424 if ((callbacks.valueAt(cbi).mFlags
425 & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
426 hasForegroundWatchers = true;
427 curValue = true;
428 }
429 }
430 }
431 which.put(op, curValue);
432 }
433
434 public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700435 SparseBooleanArray which = null;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700436 hasForegroundWatchers = false;
Hai Zhang93540ca2019-09-28 00:04:18 +0000437 if (opModes != null) {
438 for (int i = opModes.size() - 1; i >= 0; i--) {
439 if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
440 if (which == null) {
441 which = new SparseBooleanArray();
442 }
443 evalForegroundWatchers(opModes.keyAt(i), watchers, which);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700444 }
445 }
446 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700447 if (pkgOps != null) {
448 for (int i = pkgOps.size() - 1; i >= 0; i--) {
449 Ops ops = pkgOps.valueAt(i);
450 for (int j = ops.size() - 1; j >= 0; j--) {
451 if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
452 if (which == null) {
453 which = new SparseBooleanArray();
454 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700455 evalForegroundWatchers(ops.keyAt(j), watchers, which);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700456 }
457 }
458 }
459 }
460 foregroundOps = which;
461 }
Svet Ganov2af57082015-07-30 08:44:20 -0700462 }
463
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700464 final static class Ops extends SparseArray<Op> {
465 final String packageName;
466 final UidState uidState;
467 final boolean isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800468
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700469 Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800470 packageName = _packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700471 uidState = _uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400472 isPrivileged = _isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800473 }
474 }
475
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700476 private static final class FeatureOp {
477 public final @NonNull Op parent;
Svet Ganovaf189e32019-02-15 18:45:29 -0800478
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700479 public boolean running;
480
Svet Ganovaf189e32019-02-15 18:45:29 -0800481 private @Nullable LongSparseLongArray mAccessTimes;
482 private @Nullable LongSparseLongArray mRejectTimes;
483 private @Nullable LongSparseLongArray mDurations;
484 private @Nullable LongSparseLongArray mProxyUids;
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700485 private @Nullable LongSparseArray<String> mProxyFeatureIds;
Svet Ganovaf189e32019-02-15 18:45:29 -0800486 private @Nullable LongSparseArray<String> mProxyPackageNames;
487
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700488 public int startNesting;
489 public long startRealtime;
490
491 FeatureOp(@NonNull Op parent) {
492 this.parent = parent;
493 }
494
495 public void accessed(long time, int proxyUid, @Nullable String proxyPackageName,
496 @Nullable String proxyFeatureId, @AppOpsManager.UidState int uidState,
497 @OpFlags int flags) {
498 final long key = AppOpsManager.makeKey(uidState, flags);
499 if (mAccessTimes == null) {
500 mAccessTimes = new LongSparseLongArray();
501 }
502 mAccessTimes.put(key, time);
503 updateProxyState(key, proxyUid, proxyPackageName, proxyFeatureId);
504 if (mDurations != null) {
505 mDurations.delete(key);
506 }
507 }
508
509 public void rejected(long time, int proxyUid, @Nullable String proxyPackageName,
510 @Nullable String proxyFeatureId, @AppOpsManager.UidState int uidState,
511 @OpFlags int flags) {
512 final long key = AppOpsManager.makeKey(uidState, flags);
513 if (mRejectTimes == null) {
514 mRejectTimes = new LongSparseLongArray();
515 }
516 mRejectTimes.put(key, time);
517 updateProxyState(key, proxyUid, proxyPackageName, proxyFeatureId);
518 if (mDurations != null) {
519 mDurations.delete(key);
520 }
521 }
522
523 public void started(long time, @AppOpsManager.UidState int uidState, @OpFlags int flags) {
524 updateAccessTimeAndDuration(time, -1 /*duration*/, uidState, flags);
525 running = true;
526 }
527
528 public void finished(long time, long duration, @AppOpsManager.UidState int uidState,
529 @OpFlags int flags) {
530 updateAccessTimeAndDuration(time, duration, uidState, flags);
531 running = false;
532 }
533
534 public void running(long time, long duration, @AppOpsManager.UidState int uidState,
535 @OpFlags int flags) {
536 updateAccessTimeAndDuration(time, duration, uidState, flags);
537 }
538
539 public void continuing(long duration, @AppOpsManager.UidState int uidState,
540 @OpFlags int flags) {
541 final long key = AppOpsManager.makeKey(uidState, flags);
542 if (mDurations == null) {
543 mDurations = new LongSparseLongArray();
544 }
545 mDurations.put(key, duration);
546 }
547
548 private void updateAccessTimeAndDuration(long time, long duration,
549 @AppOpsManager.UidState int uidState, @OpFlags int flags) {
550 final long key = AppOpsManager.makeKey(uidState, flags);
551 if (mAccessTimes == null) {
552 mAccessTimes = new LongSparseLongArray();
553 }
554 mAccessTimes.put(key, time);
555 if (mDurations == null) {
556 mDurations = new LongSparseLongArray();
557 }
558 mDurations.put(key, duration);
559 }
560
561 private void updateProxyState(long key, int proxyUid,
562 @Nullable String proxyPackageName, @Nullable String featureId) {
563 if (proxyUid == Process.INVALID_UID) {
564 return;
565 }
566
567 if (mProxyUids == null) {
568 mProxyUids = new LongSparseLongArray();
569 }
570 mProxyUids.put(key, proxyUid);
571
572 if (mProxyPackageNames == null) {
573 mProxyPackageNames = new LongSparseArray<>();
574 }
575 mProxyPackageNames.put(key, proxyPackageName);
576
577 if (mProxyFeatureIds == null) {
578 mProxyFeatureIds = new LongSparseArray<>();
579 }
580 mProxyFeatureIds.put(key, featureId);
581 }
582
583 boolean hasAnyTime() {
584 return (mAccessTimes != null && mAccessTimes.size() > 0)
585 || (mRejectTimes != null && mRejectTimes.size() > 0);
586 }
587
588 @NonNull OpFeatureEntry.Builder createFeatureEntryBuilderLocked() {
589 return new OpFeatureEntry.Builder(running, mAccessTimes, mRejectTimes, mDurations,
590 mProxyUids, mProxyPackageNames, mProxyFeatureIds);
591 }
592 }
593
594 final static class Op {
595 int op;
596 final UidState uidState;
597 final @NonNull String packageName;
598
599 private @Mode int mode;
600
601 /** featureId -> FeatureOp */
602 final ArrayMap<String, FeatureOp> mFeatures = new ArrayMap<>(1);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800603
Svet Ganovaf189e32019-02-15 18:45:29 -0800604 Op(UidState uidState, String packageName, int op) {
605 this.op = op;
606 this.uidState = uidState;
607 this.packageName = packageName;
608 this.mode = AppOpsManager.opToDefaultMode(op);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700609 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700610
611 int getMode() {
Svet Ganovaf189e32019-02-15 18:45:29 -0800612 return mode;
613 }
614
615 int evalMode() {
616 return uidState.evalMode(op, mode);
617 }
618
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700619 void removeFeaturesWithNoTime() {
620 for (int i = mFeatures.size() - 1; i >= 0; i--) {
621 if (!mFeatures.valueAt(i).hasAnyTime()) {
622 mFeatures.removeAt(i);
623 }
Svet Ganovaf189e32019-02-15 18:45:29 -0800624 }
625 }
626
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700627 private @NonNull FeatureOp getOrCreateFeature(@NonNull Op parent,
628 @Nullable String featureId) {
629 FeatureOp featureOp;
630
631 featureOp = mFeatures.get(featureId);
632 if (featureOp == null) {
633 featureOp = new FeatureOp(parent);
634 mFeatures.put(featureId, featureOp);
Svet Ganovaf189e32019-02-15 18:45:29 -0800635 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700636
637 return featureOp;
Svet Ganovaf189e32019-02-15 18:45:29 -0800638 }
639
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700640 @NonNull OpEntry createEntryLocked() {
641 final int numFeatures = mFeatures.size();
Svet Ganovaf189e32019-02-15 18:45:29 -0800642
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700643 final Pair<String, OpFeatureEntry.Builder>[] featureEntries =
644 new Pair[numFeatures];
645 for (int i = 0; i < numFeatures; i++) {
646 featureEntries[i] = new Pair<>(mFeatures.keyAt(i),
647 mFeatures.valueAt(i).createFeatureEntryBuilderLocked());
Philip P. Moltmann4052d362019-09-19 14:52:38 -0700648 }
649
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700650 return new OpEntry(op, mode, featureEntries);
Svet Ganovaf189e32019-02-15 18:45:29 -0800651 }
652
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700653 @NonNull OpEntry createSingleFeatureEntryLocked(@Nullable String featureId) {
654 final int numFeatures = mFeatures.size();
655
656 final Pair<String, AppOpsManager.OpFeatureEntry.Builder>[] featureEntries =
657 new Pair[1];
658 for (int i = 0; i < numFeatures; i++) {
659 if (Objects.equals(mFeatures.keyAt(i), featureId)) {
660 featureEntries[0] = new Pair<>(mFeatures.keyAt(i),
661 mFeatures.valueAt(i).createFeatureEntryBuilderLocked());
662 break;
663 }
664 }
665
666 return new OpEntry(op, mode, featureEntries);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700667 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800668 }
669
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800670 final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
671 final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
672 final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
673 final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800674 final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>();
Yin-Chia Yeh51d85162019-08-06 15:31:39 -0700675 final AudioRestrictionManager mAudioRestrictionManager = new AudioRestrictionManager();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800676
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700677 final class ModeCallback implements DeathRecipient {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800678 final IAppOpsCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700679 final int mWatchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700680 final int mFlags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700681 final int mCallingUid;
682 final int mCallingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800683
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700684 ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700685 int callingPid) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800686 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700687 mWatchingUid = watchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700688 mFlags = flags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700689 mCallingUid = callingUid;
690 mCallingPid = callingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800691 try {
692 mCallback.asBinder().linkToDeath(this, 0);
693 } catch (RemoteException e) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800694 /*ignored*/
Dianne Hackbornc2293022013-02-06 23:14:49 -0800695 }
696 }
697
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700698 public boolean isWatchingUid(int uid) {
699 return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
700 }
701
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700702 @Override
703 public String toString() {
704 StringBuilder sb = new StringBuilder(128);
705 sb.append("ModeCallback{");
706 sb.append(Integer.toHexString(System.identityHashCode(this)));
707 sb.append(" watchinguid=");
708 UserHandle.formatUid(sb, mWatchingUid);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700709 sb.append(" flags=0x");
710 sb.append(Integer.toHexString(mFlags));
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700711 sb.append(" from uid=");
712 UserHandle.formatUid(sb, mCallingUid);
713 sb.append(" pid=");
714 sb.append(mCallingPid);
715 sb.append('}');
716 return sb.toString();
717 }
718
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700719 void unlinkToDeath() {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800720 mCallback.asBinder().unlinkToDeath(this, 0);
721 }
722
723 @Override
724 public void binderDied() {
725 stopWatchingMode(mCallback);
726 }
727 }
728
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700729 final class ActiveCallback implements DeathRecipient {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800730 final IAppOpsActiveCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700731 final int mWatchingUid;
732 final int mCallingUid;
733 final int mCallingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800734
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700735 ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700736 int callingPid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800737 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700738 mWatchingUid = watchingUid;
739 mCallingUid = callingUid;
740 mCallingPid = callingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800741 try {
742 mCallback.asBinder().linkToDeath(this, 0);
743 } catch (RemoteException e) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800744 /*ignored*/
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800745 }
746 }
747
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700748 @Override
749 public String toString() {
750 StringBuilder sb = new StringBuilder(128);
751 sb.append("ActiveCallback{");
752 sb.append(Integer.toHexString(System.identityHashCode(this)));
753 sb.append(" watchinguid=");
754 UserHandle.formatUid(sb, mWatchingUid);
755 sb.append(" from uid=");
756 UserHandle.formatUid(sb, mCallingUid);
757 sb.append(" pid=");
758 sb.append(mCallingPid);
759 sb.append('}');
760 return sb.toString();
761 }
762
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700763 void destroy() {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800764 mCallback.asBinder().unlinkToDeath(this, 0);
765 }
766
767 @Override
768 public void binderDied() {
769 stopWatchingActive(mCallback);
770 }
771 }
772
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800773 final class NotedCallback implements DeathRecipient {
774 final IAppOpsNotedCallback mCallback;
775 final int mWatchingUid;
776 final int mCallingUid;
777 final int mCallingPid;
778
779 NotedCallback(IAppOpsNotedCallback callback, int watchingUid, int callingUid,
780 int callingPid) {
781 mCallback = callback;
782 mWatchingUid = watchingUid;
783 mCallingUid = callingUid;
784 mCallingPid = callingPid;
785 try {
786 mCallback.asBinder().linkToDeath(this, 0);
787 } catch (RemoteException e) {
788 /*ignored*/
789 }
790 }
791
792 @Override
793 public String toString() {
794 StringBuilder sb = new StringBuilder(128);
795 sb.append("NotedCallback{");
796 sb.append(Integer.toHexString(System.identityHashCode(this)));
797 sb.append(" watchinguid=");
798 UserHandle.formatUid(sb, mWatchingUid);
799 sb.append(" from uid=");
800 UserHandle.formatUid(sb, mCallingUid);
801 sb.append(" pid=");
802 sb.append(mCallingPid);
803 sb.append('}');
804 return sb.toString();
805 }
806
807 void destroy() {
808 mCallback.asBinder().unlinkToDeath(this, 0);
809 }
810
811 @Override
812 public void binderDied() {
813 stopWatchingNoted(mCallback);
814 }
815 }
816
Svet Ganova7a0db62018-02-27 20:08:01 -0800817 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700818
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700819 final class ClientState extends Binder implements DeathRecipient {
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700820 final ArrayList<Pair<Op, String>> mStartedOps = new ArrayList<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700821 final IBinder mAppToken;
822 final int mPid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700823
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700824 ClientState(IBinder appToken) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700825 mAppToken = appToken;
826 mPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -0800827 // Watch only for remote processes dying
828 if (!(appToken instanceof Binder)) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700829 try {
830 mAppToken.linkToDeath(this, 0);
831 } catch (RemoteException e) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800832 /* do nothing */
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700833 }
834 }
835 }
836
837 @Override
838 public String toString() {
839 return "ClientState{" +
840 "mAppToken=" + mAppToken +
Svet Ganovf7b47252018-02-26 11:11:27 -0800841 ", " + "pid=" + mPid +
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700842 '}';
843 }
844
845 @Override
846 public void binderDied() {
847 synchronized (AppOpsService.this) {
848 for (int i=mStartedOps.size()-1; i>=0; i--) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700849 final Pair<Op, String> startedOp = mStartedOps.get(i);
850 final Op op = startedOp.first;
851 final String featureId = startedOp.second;
852
853 finishOperationLocked(op, featureId, /*finishNested*/ true);
854 if (op.mFeatures.get(featureId).startNesting <= 0) {
Bruno Martinsb420a642018-12-30 16:02:59 +0000855 scheduleOpActiveChangedIfNeededLocked(op.op, op.uidState.uid,
856 op.packageName, false);
857 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700858 }
859 mClients.remove(mAppToken);
860 }
861 }
862 }
863
Jeff Brown6f357d32014-01-15 20:40:55 -0800864 public AppOpsService(File storagePath, Handler handler) {
Jeff Sharkey5f3e9342017-03-13 14:53:11 -0600865 LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
Dianne Hackborne17b4452018-01-10 13:15:40 -0800866 mFile = new AtomicFile(storagePath, "appops");
Jeff Brown6f357d32014-01-15 20:40:55 -0800867 mHandler = handler;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700868 mConstants = new Constants(mHandler);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800869 readState();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800870 }
David Braunf5d83192013-09-16 13:43:51 -0700871
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800872 public void publish(Context context) {
873 mContext = context;
874 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
Dianne Hackbornd5254412018-05-11 18:02:58 -0700875 LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800876 }
877
Dianne Hackborn514074f2013-02-11 10:52:46 -0800878 public void systemReady() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700879 mConstants.startMonitoring(mContext.getContentResolver());
Svet Ganov8455ba22019-01-02 13:05:56 -0800880 mHistoricalRegistry.systemReady(mContext.getContentResolver());
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700881
Dianne Hackborn514074f2013-02-11 10:52:46 -0800882 synchronized (this) {
883 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700884 for (int i = mUidStates.size() - 1; i >= 0; i--) {
885 UidState uidState = mUidStates.valueAt(i);
886
887 String[] packageNames = getPackagesForUid(uidState.uid);
888 if (ArrayUtils.isEmpty(packageNames)) {
889 uidState.clear();
890 mUidStates.removeAt(i);
891 changed = true;
892 continue;
893 }
894
895 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
896 if (pkgs == null) {
897 continue;
898 }
899
Dianne Hackborn514074f2013-02-11 10:52:46 -0800900 Iterator<Ops> it = pkgs.values().iterator();
901 while (it.hasNext()) {
902 Ops ops = it.next();
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700903 int curUid = -1;
Dianne Hackborn514074f2013-02-11 10:52:46 -0800904 try {
Jeff Sharkeycd654482016-01-08 17:42:11 -0700905 curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
906 PackageManager.MATCH_UNINSTALLED_PACKAGES,
Svet Ganov2af57082015-07-30 08:44:20 -0700907 UserHandle.getUserId(ops.uidState.uid));
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700908 } catch (RemoteException ignored) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800909 }
Svet Ganov2af57082015-07-30 08:44:20 -0700910 if (curUid != ops.uidState.uid) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800911 Slog.i(TAG, "Pruning old package " + ops.packageName
Svet Ganov2af57082015-07-30 08:44:20 -0700912 + "/" + ops.uidState + ": new uid=" + curUid);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800913 it.remove();
914 changed = true;
915 }
916 }
Svet Ganov2af57082015-07-30 08:44:20 -0700917
918 if (uidState.isDefault()) {
919 mUidStates.removeAt(i);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800920 }
921 }
922 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800923 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800924 }
925 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700926
Suprabh Shukla3017fe42018-11-08 19:00:01 -0800927 final IntentFilter packageSuspendFilter = new IntentFilter();
928 packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
929 packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
930 mContext.registerReceiver(new BroadcastReceiver() {
931 @Override
932 public void onReceive(Context context, Intent intent) {
933 final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
934 final String[] changedPkgs = intent.getStringArrayExtra(
935 Intent.EXTRA_CHANGED_PACKAGE_LIST);
Suprabh Shuklab614a222019-09-12 14:42:46 -0700936 for (int code : OPS_RESTRICTED_ON_SUSPEND) {
937 ArraySet<ModeCallback> callbacks;
938 synchronized (AppOpsService.this) {
939 callbacks = mOpModeWatchers.get(code);
940 if (callbacks == null) {
941 continue;
942 }
943 callbacks = new ArraySet<>(callbacks);
Dianne Hackborn65e8de32019-04-04 11:01:41 -0700944 }
Suprabh Shuklab614a222019-09-12 14:42:46 -0700945 for (int i = 0; i < changedUids.length; i++) {
946 final int changedUid = changedUids[i];
947 final String changedPkg = changedPkgs[i];
948 // We trust packagemanager to insert matching uid and packageNames in the
949 // extras
Suprabh Shukla7e017922019-08-05 17:13:23 -0700950 notifyOpChanged(callbacks, code, changedUid, changedPkg);
951 }
Suprabh Shukla3017fe42018-11-08 19:00:01 -0800952 }
953 }
954 }, packageSuspendFilter);
955
Suprabh Shuklaaef25132017-01-23 18:09:03 -0800956 PackageManagerInternal packageManagerInternal = LocalServices.getService(
957 PackageManagerInternal.class);
958 packageManagerInternal.setExternalSourcesPolicy(
959 new PackageManagerInternal.ExternalSourcesPolicy() {
960 @Override
961 public int getPackageTrustedToInstallApps(String packageName, int uid) {
962 int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
963 uid, packageName);
964 switch (appOpMode) {
965 case AppOpsManager.MODE_ALLOWED:
966 return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
967 case AppOpsManager.MODE_ERRORED:
968 return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
969 default:
970 return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
971 }
972 }
973 });
974
Jeff Sharkey10ec9d82018-11-28 14:52:45 -0700975 if (!StorageManager.hasIsolatedStorage()) {
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700976 StorageManagerInternal storageManagerInternal = LocalServices.getService(
977 StorageManagerInternal.class);
978 storageManagerInternal.addExternalStoragePolicy(
979 new StorageManagerInternal.ExternalStorageMountPolicy() {
980 @Override
981 public int getMountMode(int uid, String packageName) {
982 if (Process.isIsolated(uid)) {
983 return Zygote.MOUNT_EXTERNAL_NONE;
984 }
985 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700986 packageName, null) != AppOpsManager.MODE_ALLOWED) {
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700987 return Zygote.MOUNT_EXTERNAL_NONE;
988 }
989 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700990 packageName, null) != AppOpsManager.MODE_ALLOWED) {
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700991 return Zygote.MOUNT_EXTERNAL_READ;
992 }
993 return Zygote.MOUNT_EXTERNAL_WRITE;
Svet Ganov6ee871e2015-07-10 14:29:33 -0700994 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700995
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700996 @Override
997 public boolean hasExternalStorage(int uid, String packageName) {
998 final int mountMode = getMountMode(uid, packageName);
999 return mountMode == Zygote.MOUNT_EXTERNAL_READ
1000 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
1001 }
1002 });
1003 }
Dianne Hackborn514074f2013-02-11 10:52:46 -08001004 }
1005
1006 public void packageRemoved(int uid, String packageName) {
1007 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001008 UidState uidState = mUidStates.get(uid);
1009 if (uidState == null) {
1010 return;
1011 }
1012
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001013 Ops ops = null;
Svet Ganov2af57082015-07-30 08:44:20 -07001014
1015 // Remove any package state if such.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001016 if (uidState.pkgOps != null) {
1017 ops = uidState.pkgOps.remove(packageName);
Svet Ganov2af57082015-07-30 08:44:20 -07001018 }
1019
1020 // If we just nuked the last package state check if the UID is valid.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001021 if (ops != null && uidState.pkgOps.isEmpty()
Svet Ganov2af57082015-07-30 08:44:20 -07001022 && getPackagesForUid(uid).length <= 0) {
1023 mUidStates.remove(uid);
1024 }
1025
Svet Ganova7a0db62018-02-27 20:08:01 -08001026 // Finish ops other packages started on behalf of the package.
1027 final int clientCount = mClients.size();
1028 for (int i = 0; i < clientCount; i++) {
1029 final ClientState client = mClients.valueAt(i);
1030 if (client.mStartedOps == null) {
1031 continue;
1032 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001033 final int startedOpCount = client.mStartedOps.size();
1034 for (int j = startedOpCount - 1; j >= 0; j--) {
1035 final Pair<Op, String> startedOp = client.mStartedOps.get(j);
1036 final Op op = startedOp.first;
1037 final String featureId = startedOp.second;
1038
Svet Ganovaf189e32019-02-15 18:45:29 -08001039 if (uid == op.uidState.uid && packageName.equals(op.packageName)) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001040 finishOperationLocked(op, featureId, /*finishNested*/ true);
Svet Ganova7a0db62018-02-27 20:08:01 -08001041 client.mStartedOps.remove(j);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001042 if (op.mFeatures.get(featureId).startNesting <= 0) {
Svet Ganova7a0db62018-02-27 20:08:01 -08001043 scheduleOpActiveChangedIfNeededLocked(op.op,
1044 uid, packageName, false);
1045 }
1046 }
1047 }
1048 }
1049
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001050 if (ops != null) {
Svet Ganov2af57082015-07-30 08:44:20 -07001051 scheduleFastWriteLocked();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001052
1053 final int opCount = ops.size();
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001054 for (int opNum = 0; opNum < opCount; opNum++) {
1055 final Op op = ops.valueAt(opNum);
1056
1057 final int numFeatures = op.mFeatures.size();
1058 for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
1059 if (op.mFeatures.valueAt(featureNum).running) {
1060 scheduleOpActiveChangedIfNeededLocked(
1061 op.op, op.uidState.uid, op.packageName, false);
1062 break;
1063 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001064 }
1065 }
Dianne Hackborn514074f2013-02-11 10:52:46 -08001066 }
Winson470b15b2019-05-07 16:29:59 -07001067
1068 mHistoricalRegistry.clearHistory(uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001069 }
1070 }
1071
1072 public void uidRemoved(int uid) {
1073 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001074 if (mUidStates.indexOfKey(uid) >= 0) {
1075 mUidStates.remove(uid);
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001076 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -08001077 }
1078 }
1079 }
1080
Hui Yu26969322019-08-21 14:56:35 -07001081 public void updateUidProcState(int uid, int procState,
1082 @ActivityManager.ProcessCapability int capability) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001083 synchronized (this) {
1084 final UidState uidState = getUidStateLocked(uid, true);
Hui Yu26969322019-08-21 14:56:35 -07001085 final int newState = PROCESS_STATE_TO_UID_STATE[procState];
1086 if (uidState != null && (uidState.pendingState != newState
1087 || uidState.pendingCapability != capability)) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001088 final int oldPendingState = uidState.pendingState;
1089 uidState.pendingState = newState;
Hui Yu26969322019-08-21 14:56:35 -07001090 uidState.pendingCapability = capability;
Wei Wang878d0b62019-03-28 18:12:18 -07001091 if (newState < uidState.state
1092 || (newState <= UID_STATE_MAX_LAST_NON_RESTRICTED
1093 && uidState.state > UID_STATE_MAX_LAST_NON_RESTRICTED)) {
1094 // We are moving to a more important state, or the new state may be in the
1095 // foreground and the old state is in the background, then always do it
1096 // immediately.
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001097 commitUidPendingStateLocked(uidState);
Hui Yu26969322019-08-21 14:56:35 -07001098 } else if (newState == uidState.state && capability != uidState.capability) {
1099 // No change on process state, but process capability has changed.
1100 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001101 } else if (uidState.pendingStateCommitTime == 0) {
1102 // We are moving to a less important state for the first time,
1103 // delay the application for a bit.
Dianne Hackborne93ab412018-05-14 17:52:30 -07001104 final long settleTime;
1105 if (uidState.state <= UID_STATE_TOP) {
1106 settleTime = mConstants.TOP_STATE_SETTLE_TIME;
1107 } else if (uidState.state <= UID_STATE_FOREGROUND_SERVICE) {
1108 settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
1109 } else {
1110 settleTime = mConstants.BG_STATE_SETTLE_TIME;
1111 }
Dianne Hackborn9fb93502018-06-18 12:29:44 -07001112 uidState.pendingStateCommitTime = SystemClock.elapsedRealtime() + settleTime;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001113 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001114 if (uidState.startNesting != 0) {
1115 // There is some actively running operation... need to find it
1116 // and appropriately update its state.
1117 final long now = System.currentTimeMillis();
Stanislav Zholnin5104a0f2019-12-02 18:22:19 +00001118 final long nowElapsed = SystemClock.elapsedRealtime();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001119 for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
1120 final Ops ops = uidState.pkgOps.valueAt(i);
1121 for (int j = ops.size() - 1; j >= 0; j--) {
1122 final Op op = ops.valueAt(j);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001123
1124 int numFeatures = op.mFeatures.size();
1125 for (int featureNum = 0; featureNum < numFeatures;
1126 featureNum++) {
1127 final FeatureOp featureOp = op.mFeatures.valueAt(
1128 featureNum);
1129 if (featureOp.startNesting > 0) {
1130 final long duration = SystemClock.elapsedRealtime()
1131 - featureOp.startRealtime;
1132 // We don't support proxy long running ops (start/stop)
1133 mHistoricalRegistry.increaseOpAccessDuration(op.op,
1134 op.uidState.uid, op.packageName, oldPendingState,
1135 AppOpsManager.OP_FLAG_SELF, duration);
1136 // Finish the op in the old state
1137 featureOp.finished(now, duration, oldPendingState,
1138 AppOpsManager.OP_FLAG_SELF);
1139 // Start the op in the new state
Stanislav Zholnin5104a0f2019-12-02 18:22:19 +00001140 featureOp.startRealtime = nowElapsed;
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001141 featureOp.started(now, newState, AppOpsManager.OP_FLAG_SELF);
1142 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001143 }
1144 }
1145 }
1146 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001147 }
1148 }
1149 }
1150
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001151 public void shutdown() {
1152 Slog.w(TAG, "Writing app ops before shutdown...");
Dianne Hackborn35654b62013-01-14 17:38:02 -08001153 boolean doWrite = false;
1154 synchronized (this) {
1155 if (mWriteScheduled) {
1156 mWriteScheduled = false;
1157 doWrite = true;
1158 }
1159 }
1160 if (doWrite) {
1161 writeState();
1162 }
1163 }
1164
Dianne Hackborn72e39832013-01-18 18:36:09 -08001165 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
1166 ArrayList<AppOpsManager.OpEntry> resOps = null;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001167 final long elapsedNow = SystemClock.elapsedRealtime();
Dianne Hackborn72e39832013-01-18 18:36:09 -08001168 if (ops == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001169 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -08001170 for (int j=0; j<pkgOps.size(); j++) {
1171 Op curOp = pkgOps.valueAt(j);
Svet Ganovaf189e32019-02-15 18:45:29 -08001172 resOps.add(getOpEntryForResult(curOp, elapsedNow));
Dianne Hackborn72e39832013-01-18 18:36:09 -08001173 }
1174 } else {
1175 for (int j=0; j<ops.length; j++) {
1176 Op curOp = pkgOps.get(ops[j]);
1177 if (curOp != null) {
1178 if (resOps == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001179 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -08001180 }
Svet Ganovaf189e32019-02-15 18:45:29 -08001181 resOps.add(getOpEntryForResult(curOp, elapsedNow));
Dianne Hackborn72e39832013-01-18 18:36:09 -08001182 }
1183 }
1184 }
1185 return resOps;
1186 }
1187
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001188 @Nullable
1189 private ArrayList<AppOpsManager.OpEntry> collectUidOps(@NonNull UidState uidState,
1190 @Nullable int[] ops) {
1191 if (uidState.opModes == null) {
1192 return null;
1193 }
1194
1195 int opModeCount = uidState.opModes.size();
1196 if (opModeCount == 0) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08001197 return null;
1198 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001199 ArrayList<AppOpsManager.OpEntry> resOps = null;
1200 if (ops == null) {
1201 resOps = new ArrayList<>();
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001202 for (int i = 0; i < opModeCount; i++) {
1203 int code = uidState.opModes.keyAt(i);
1204 resOps.add(new OpEntry(code, uidState.opModes.get(code), new Pair[0]));
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001205 }
1206 } else {
Hai Zhang93540ca2019-09-28 00:04:18 +00001207 for (int j=0; j<ops.length; j++) {
Philip P. Moltmannf56fe2c2019-10-30 08:42:47 -07001208 int code = ops[j];
1209 if (uidState.opModes.indexOfKey(code) >= 0) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001210 if (resOps == null) {
1211 resOps = new ArrayList<>();
1212 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001213 resOps.add(new OpEntry(code, uidState.opModes.get(code), new Pair[0]));
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001214 }
1215 }
1216 }
1217 return resOps;
1218 }
1219
Svet Ganovaf189e32019-02-15 18:45:29 -08001220 private static @NonNull OpEntry getOpEntryForResult(@NonNull Op op, long elapsedNow) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001221 final int numFeatures = op.mFeatures.size();
1222
1223 for (int i = 0; i < numFeatures; i++) {
1224 final FeatureOp featureOp = op.mFeatures.valueAt(i);
1225 if (featureOp.running) {
1226 featureOp.continuing(elapsedNow - featureOp.startRealtime,
1227 op.uidState.state, AppOpsManager.OP_FLAG_SELF);
1228 }
Svet Ganovaf189e32019-02-15 18:45:29 -08001229 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001230
1231 return op.createEntryLocked();
Svet Ganovaf189e32019-02-15 18:45:29 -08001232 }
1233
Dianne Hackborn35654b62013-01-14 17:38:02 -08001234 @Override
1235 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
1236 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1237 Binder.getCallingPid(), Binder.getCallingUid(), null);
1238 ArrayList<AppOpsManager.PackageOps> res = null;
1239 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001240 final int uidStateCount = mUidStates.size();
1241 for (int i = 0; i < uidStateCount; i++) {
1242 UidState uidState = mUidStates.valueAt(i);
1243 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
1244 continue;
1245 }
1246 ArrayMap<String, Ops> packages = uidState.pkgOps;
1247 final int packageCount = packages.size();
1248 for (int j = 0; j < packageCount; j++) {
1249 Ops pkgOps = packages.valueAt(j);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001250 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001251 if (resOps != null) {
1252 if (res == null) {
1253 res = new ArrayList<AppOpsManager.PackageOps>();
1254 }
1255 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -07001256 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001257 res.add(resPackage);
1258 }
1259 }
1260 }
1261 }
1262 return res;
1263 }
1264
1265 @Override
Dianne Hackborn72e39832013-01-18 18:36:09 -08001266 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
1267 int[] ops) {
1268 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1269 Binder.getCallingPid(), Binder.getCallingUid(), null);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001270 String resolvedPackageName = resolvePackageName(uid, packageName);
1271 if (resolvedPackageName == null) {
1272 return Collections.emptyList();
1273 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08001274 synchronized (this) {
Philip P. Moltmannec142a52019-04-09 13:38:07 -07001275 Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* isPrivileged */,
1276 false /* edit */);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001277 if (pkgOps == null) {
1278 return null;
1279 }
1280 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
1281 if (resOps == null) {
1282 return null;
1283 }
1284 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
1285 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -07001286 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001287 res.add(resPackage);
1288 return res;
1289 }
1290 }
1291
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001292 @Override
Svet Ganov8455ba22019-01-02 13:05:56 -08001293 public void getHistoricalOps(int uid, @NonNull String packageName,
Svet Ganov23c88db2019-01-22 20:38:11 -08001294 @Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis,
Svet Ganovaf189e32019-02-15 18:45:29 -08001295 @OpFlags int flags, @NonNull RemoteCallback callback) {
Svet Ganov23c88db2019-01-22 20:38:11 -08001296 // Use the builder to validate arguments.
Svet Ganovaf189e32019-02-15 18:45:29 -08001297 new HistoricalOpsRequest.Builder(
Svet Ganov23c88db2019-01-22 20:38:11 -08001298 beginTimeMillis, endTimeMillis)
1299 .setUid(uid)
1300 .setPackageName(packageName)
1301 .setOpNames(opNames)
Svet Ganovaf189e32019-02-15 18:45:29 -08001302 .setFlags(flags)
Svet Ganov23c88db2019-01-22 20:38:11 -08001303 .build();
Svet Ganov8455ba22019-01-02 13:05:56 -08001304 Preconditions.checkNotNull(callback, "callback cannot be null");
Svet Ganovad0a49b2018-10-29 10:07:08 -07001305
1306 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
Svet Ganov8455ba22019-01-02 13:05:56 -08001307 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
Svet Ganovad0a49b2018-10-29 10:07:08 -07001308
Svet Ganov23c88db2019-01-22 20:38:11 -08001309 final String[] opNamesArray = (opNames != null)
1310 ? opNames.toArray(new String[opNames.size()]) : null;
Svet Ganovad0a49b2018-10-29 10:07:08 -07001311
Svet Ganovaf189e32019-02-15 18:45:29 -08001312 // Must not hold the appops lock
1313 mHistoricalRegistry.getHistoricalOps(uid, packageName, opNamesArray,
1314 beginTimeMillis, endTimeMillis, flags, callback);
Svet Ganovad0a49b2018-10-29 10:07:08 -07001315 }
1316
1317 @Override
Svet Ganov8455ba22019-01-02 13:05:56 -08001318 public void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
Svet Ganov23c88db2019-01-22 20:38:11 -08001319 @Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis,
Svet Ganovaf189e32019-02-15 18:45:29 -08001320 @OpFlags int flags, @NonNull RemoteCallback callback) {
Svet Ganov23c88db2019-01-22 20:38:11 -08001321 // Use the builder to validate arguments.
Svet Ganovaf189e32019-02-15 18:45:29 -08001322 new HistoricalOpsRequest.Builder(
Svet Ganov23c88db2019-01-22 20:38:11 -08001323 beginTimeMillis, endTimeMillis)
1324 .setUid(uid)
1325 .setPackageName(packageName)
1326 .setOpNames(opNames)
Svet Ganovaf189e32019-02-15 18:45:29 -08001327 .setFlags(flags)
Svet Ganov23c88db2019-01-22 20:38:11 -08001328 .build();
Svet Ganov8455ba22019-01-02 13:05:56 -08001329 Preconditions.checkNotNull(callback, "callback cannot be null");
Svet Ganovad0a49b2018-10-29 10:07:08 -07001330
Svet Ganov8e5bf962019-03-19 23:59:03 -07001331 mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
Svet Ganov8455ba22019-01-02 13:05:56 -08001332 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
Svet Ganovad0a49b2018-10-29 10:07:08 -07001333
Svet Ganov23c88db2019-01-22 20:38:11 -08001334 final String[] opNamesArray = (opNames != null)
1335 ? opNames.toArray(new String[opNames.size()]) : null;
1336
Svet Ganov8455ba22019-01-02 13:05:56 -08001337 // Must not hold the appops lock
Svet Ganov23c88db2019-01-22 20:38:11 -08001338 mHistoricalRegistry.getHistoricalOpsFromDiskRaw(uid, packageName, opNamesArray,
Svet Ganovaf189e32019-02-15 18:45:29 -08001339 beginTimeMillis, endTimeMillis, flags, callback);
Svet Ganovad0a49b2018-10-29 10:07:08 -07001340 }
1341
1342 @Override
Svet Ganov8e5bf962019-03-19 23:59:03 -07001343 public void reloadNonHistoricalState() {
1344 mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
1345 Binder.getCallingPid(), Binder.getCallingUid(), "reloadNonHistoricalState");
1346 writeState();
1347 readState();
1348 }
1349
1350 @Override
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001351 public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
1352 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1353 Binder.getCallingPid(), Binder.getCallingUid(), null);
1354 synchronized (this) {
1355 UidState uidState = getUidStateLocked(uid, false);
1356 if (uidState == null) {
1357 return null;
1358 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001359 ArrayList<AppOpsManager.OpEntry> resOps = collectUidOps(uidState, ops);
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001360 if (resOps == null) {
1361 return null;
1362 }
Hai Zhang93540ca2019-09-28 00:04:18 +00001363 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001364 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
1365 null, uidState.uid, resOps);
1366 res.add(resPackage);
1367 return res;
1368 }
1369 }
1370
Eugene Susla463d5922019-07-17 18:14:15 -07001371 private void pruneOpLocked(Op op, int uid, String packageName) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001372 op.removeFeaturesWithNoTime();
1373
1374 if (op.mFeatures.size() == 0) {
1375 Ops ops = getOpsRawLocked(uid, packageName, false /* isPrivileged */,
1376 false /* edit */);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001377 if (ops != null) {
1378 ops.remove(op.op);
1379 if (ops.size() <= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -07001380 UidState uidState = ops.uidState;
1381 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001382 if (pkgOps != null) {
1383 pkgOps.remove(ops.packageName);
Svet Ganov2af57082015-07-30 08:44:20 -07001384 if (pkgOps.isEmpty()) {
1385 uidState.pkgOps = null;
1386 }
1387 if (uidState.isDefault()) {
1388 mUidStates.remove(uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001389 }
1390 }
1391 }
1392 }
1393 }
1394 }
1395
Svet Ganovaf189e32019-02-15 18:45:29 -08001396 private void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001397 if (callingPid == Process.myPid()) {
1398 return;
1399 }
1400 final int callingUser = UserHandle.getUserId(callingUid);
1401 synchronized (this) {
1402 if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
1403 if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
1404 // Profile owners are allowed to change modes but only for apps
1405 // within their user.
1406 return;
1407 }
1408 }
1409 }
1410 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
1411 Binder.getCallingPid(), Binder.getCallingUid(), null);
1412 }
1413
Dianne Hackborn72e39832013-01-18 18:36:09 -08001414 @Override
Svet Ganov2af57082015-07-30 08:44:20 -07001415 public void setUidMode(int code, int uid, int mode) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08001416 if (DEBUG) {
1417 Slog.i(TAG, "uid " + uid + " OP_" + opToName(code) + " := " + modeToName(mode)
1418 + " by uid " + Binder.getCallingUid());
1419 }
1420
Dianne Hackbornd5254412018-05-11 18:02:58 -07001421 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Svet Ganov2af57082015-07-30 08:44:20 -07001422 verifyIncomingOp(code);
1423 code = AppOpsManager.opToSwitch(code);
1424
Hai Zhange53e4c52019-10-08 18:57:01 -07001425 updatePermissionRevokedCompat(uid, code, mode);
1426
Svet Ganov2af57082015-07-30 08:44:20 -07001427 synchronized (this) {
1428 final int defaultMode = AppOpsManager.opToDefaultMode(code);
1429
1430 UidState uidState = getUidStateLocked(uid, false);
1431 if (uidState == null) {
1432 if (mode == defaultMode) {
1433 return;
1434 }
1435 uidState = new UidState(uid);
Hai Zhang93540ca2019-09-28 00:04:18 +00001436 uidState.opModes = new SparseIntArray();
1437 uidState.opModes.put(code, mode);
Svet Ganov2af57082015-07-30 08:44:20 -07001438 mUidStates.put(uid, uidState);
1439 scheduleWriteLocked();
Hai Zhang93540ca2019-09-28 00:04:18 +00001440 } else if (uidState.opModes == null) {
1441 if (mode != defaultMode) {
1442 uidState.opModes = new SparseIntArray();
1443 uidState.opModes.put(code, mode);
Svet Ganov2af57082015-07-30 08:44:20 -07001444 scheduleWriteLocked();
1445 }
Hai Zhang93540ca2019-09-28 00:04:18 +00001446 } else {
1447 if (uidState.opModes.indexOfKey(code) >= 0 && uidState.opModes.get(code) == mode) {
1448 return;
1449 }
1450 if (mode == defaultMode) {
1451 uidState.opModes.delete(code);
1452 if (uidState.opModes.size() <= 0) {
1453 uidState.opModes = null;
1454 }
1455 } else {
1456 uidState.opModes.put(code, mode);
1457 }
1458 scheduleWriteLocked();
Svet Ganov2af57082015-07-30 08:44:20 -07001459 }
Wei Wang711eb662019-03-21 18:24:17 -07001460 uidState.evalForegroundOps(mOpModeWatchers);
Svet Ganov2af57082015-07-30 08:44:20 -07001461 }
1462
Svetoslav215b44a2015-08-04 19:03:40 -07001463 String[] uidPackageNames = getPackagesForUid(uid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001464 ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
Svet Ganov2af57082015-07-30 08:44:20 -07001465
riddle_hsu40b300f2015-11-23 13:22:03 +08001466 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001467 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001468 if (callbacks != null) {
Svet Ganov2af57082015-07-30 08:44:20 -07001469 final int callbackCount = callbacks.size();
1470 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001471 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08001472 ArraySet<String> changedPackages = new ArraySet<>();
1473 Collections.addAll(changedPackages, uidPackageNames);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001474 if (callbackSpecs == null) {
1475 callbackSpecs = new ArrayMap<>();
1476 }
riddle_hsu40b300f2015-11-23 13:22:03 +08001477 callbackSpecs.put(callback, changedPackages);
1478 }
1479 }
1480
1481 for (String uidPackageName : uidPackageNames) {
1482 callbacks = mPackageModeWatchers.get(uidPackageName);
1483 if (callbacks != null) {
1484 if (callbackSpecs == null) {
1485 callbackSpecs = new ArrayMap<>();
Svet Ganov2af57082015-07-30 08:44:20 -07001486 }
riddle_hsu40b300f2015-11-23 13:22:03 +08001487 final int callbackCount = callbacks.size();
1488 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001489 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08001490 ArraySet<String> changedPackages = callbackSpecs.get(callback);
1491 if (changedPackages == null) {
1492 changedPackages = new ArraySet<>();
1493 callbackSpecs.put(callback, changedPackages);
1494 }
1495 changedPackages.add(uidPackageName);
1496 }
Svet Ganov2af57082015-07-30 08:44:20 -07001497 }
1498 }
1499 }
1500
1501 if (callbackSpecs == null) {
Sudheer Shankab1613982019-05-16 16:55:50 -07001502 notifyOpChangedSync(code, uid, null, mode);
Svet Ganov2af57082015-07-30 08:44:20 -07001503 return;
1504 }
1505
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001506 for (int i = 0; i < callbackSpecs.size(); i++) {
1507 final ModeCallback callback = callbackSpecs.keyAt(i);
1508 final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
1509 if (reportedPackageNames == null) {
1510 mHandler.sendMessage(PooledLambda.obtainMessage(
1511 AppOpsService::notifyOpChanged,
1512 this, callback, code, uid, (String) null));
1513
1514 } else {
1515 final int reportedPackageCount = reportedPackageNames.size();
1516 for (int j = 0; j < reportedPackageCount; j++) {
1517 final String reportedPackageName = reportedPackageNames.valueAt(j);
1518 mHandler.sendMessage(PooledLambda.obtainMessage(
1519 AppOpsService::notifyOpChanged,
1520 this, callback, code, uid, reportedPackageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001521 }
1522 }
Svet Ganov2af57082015-07-30 08:44:20 -07001523 }
Sudheer Shankab1613982019-05-16 16:55:50 -07001524
1525 notifyOpChangedSync(code, uid, null, mode);
1526 }
1527
Hai Zhange53e4c52019-10-08 18:57:01 -07001528 private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) {
Hai Zhang408ca762019-10-14 14:09:35 -07001529 PackageManagerInternal packageManagerInternal = LocalServices.getService(
1530 PackageManagerInternal.class);
1531 if (packageManagerInternal.getUidTargetSdkVersion(uid) >= Build.VERSION_CODES.M) {
1532 return;
1533 }
1534
Hai Zhange53e4c52019-10-08 18:57:01 -07001535 PackageManager packageManager = mContext.getPackageManager();
1536 String[] packageNames = packageManager.getPackagesForUid(uid);
1537 if (ArrayUtils.isEmpty(packageNames)) {
1538 return;
1539 }
1540 String packageName = packageNames[0];
1541
1542 List<Integer> ops = getSwitchOpToOps().get(switchCode);
1543 int opsSize = CollectionUtils.size(ops);
1544 for (int i = 0; i < opsSize; i++) {
1545 int code = ops.get(i);
1546
1547 String permissionName = AppOpsManager.opToPermission(code);
1548 if (permissionName == null) {
1549 continue;
1550 }
1551
1552 PermissionInfo permissionInfo;
1553 try {
1554 permissionInfo = packageManager.getPermissionInfo(permissionName, 0);
1555 } catch (PackageManager.NameNotFoundException e) {
1556 e.printStackTrace();
1557 continue;
1558 }
1559
1560 if (!permissionInfo.isRuntime()) {
1561 continue;
1562 }
1563
1564 UserHandle user = UserHandle.getUserHandleForUid(uid);
1565 boolean isRevokedCompat;
1566 if (permissionInfo.backgroundPermission != null) {
1567 boolean isBackgroundRevokedCompat = mode != AppOpsManager.MODE_ALLOWED;
1568 long identity = Binder.clearCallingIdentity();
1569 try {
1570 packageManager.updatePermissionFlags(permissionInfo.backgroundPermission,
1571 packageName, PackageManager.FLAG_PERMISSION_REVOKED_COMPAT,
1572 isBackgroundRevokedCompat
1573 ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user);
1574 } finally {
1575 Binder.restoreCallingIdentity(identity);
1576 }
1577
1578 isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED
1579 && mode != AppOpsManager.MODE_FOREGROUND;
1580 } else {
1581 isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED;
1582 }
1583
1584 long identity = Binder.clearCallingIdentity();
1585 try {
1586 packageManager.updatePermissionFlags(permissionName, packageName,
1587 PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, isRevokedCompat
1588 ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user);
1589 } finally {
1590 Binder.restoreCallingIdentity(identity);
1591 }
1592 }
1593 }
1594
1595 @NonNull
1596 private SparseArray<List<Integer>> getSwitchOpToOps() {
1597 synchronized (this) {
1598 if (mSwitchOpToOps == null) {
1599 mSwitchOpToOps = new SparseArray<>();
1600 for (int op = 0; op < _NUM_OP; op++) {
1601 int switchOp = AppOpsManager.opToSwitch(op);
1602 List<Integer> ops = mSwitchOpToOps.get(switchOp);
1603 if (ops == null) {
1604 ops = new ArrayList<>();
1605 mSwitchOpToOps.put(switchOp, ops);
1606 }
1607 ops.add(op);
1608 }
1609 }
1610 return mSwitchOpToOps;
1611 }
1612 }
1613
Sudheer Shankab1613982019-05-16 16:55:50 -07001614 private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode) {
1615 final StorageManagerInternal storageManagerInternal =
1616 LocalServices.getService(StorageManagerInternal.class);
1617 if (storageManagerInternal != null) {
1618 storageManagerInternal.onAppOpsChanged(code, uid, packageName, mode);
1619 }
Svet Ganov2af57082015-07-30 08:44:20 -07001620 }
1621
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07001622 /**
1623 * Sets the mode for a certain op and uid.
1624 *
1625 * @param code The op code to set
1626 * @param uid The UID for which to set
1627 * @param packageName The package for which to set
1628 * @param mode The new mode to set
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07001629 */
Philip P. Moltmannec142a52019-04-09 13:38:07 -07001630 @Override
1631 public void setMode(int code, int uid, @NonNull String packageName, int mode) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001632 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001633 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001634 ArraySet<ModeCallback> repCbs = null;
Dianne Hackbornc2293022013-02-06 23:14:49 -08001635 code = AppOpsManager.opToSwitch(code);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07001636
1637 boolean isPrivileged;
1638 try {
1639 isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
1640 } catch (SecurityException e) {
1641 Slog.e(TAG, "Cannot setMode", e);
1642 return;
1643 }
1644
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001645 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001646 UidState uidState = getUidStateLocked(uid, false);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07001647 Op op = getOpLocked(code, uid, packageName, isPrivileged, true);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001648 if (op != null) {
1649 if (op.mode != mode) {
1650 op.mode = mode;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001651 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001652 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001653 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001654 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001655 if (cbs != null) {
1656 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001657 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001658 }
1659 repCbs.addAll(cbs);
1660 }
1661 cbs = mPackageModeWatchers.get(packageName);
1662 if (cbs != null) {
1663 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001664 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001665 }
1666 repCbs.addAll(cbs);
1667 }
David Braunf5d83192013-09-16 13:43:51 -07001668 if (mode == AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001669 // If going into the default mode, prune this op
1670 // if there is nothing else interesting in it.
Eugene Susla463d5922019-07-17 18:14:15 -07001671 pruneOpLocked(op, uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001672 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001673 scheduleFastWriteLocked();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001674 }
1675 }
1676 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001677 if (repCbs != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001678 mHandler.sendMessage(PooledLambda.obtainMessage(
1679 AppOpsService::notifyOpChanged,
1680 this, repCbs, code, uid, packageName));
Dianne Hackbornc2293022013-02-06 23:14:49 -08001681 }
Sudheer Shankab1613982019-05-16 16:55:50 -07001682
1683 notifyOpChangedSync(code, uid, packageName, mode);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001684 }
1685
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001686 private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
1687 int uid, String packageName) {
1688 for (int i = 0; i < callbacks.size(); i++) {
1689 final ModeCallback callback = callbacks.valueAt(i);
1690 notifyOpChanged(callback, code, uid, packageName);
1691 }
1692 }
1693
1694 private void notifyOpChanged(ModeCallback callback, int code,
1695 int uid, String packageName) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001696 if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001697 return;
1698 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001699 // There are features watching for mode changes such as window manager
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001700 // and location manager which are in our process. The callbacks in these
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001701 // features may require permissions our remote caller does not have.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001702 final long identity = Binder.clearCallingIdentity();
1703 try {
1704 callback.mCallback.opChanged(code, uid, packageName);
1705 } catch (RemoteException e) {
1706 /* ignore */
1707 } finally {
1708 Binder.restoreCallingIdentity(identity);
1709 }
1710 }
1711
1712 private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
1713 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
1714 int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001715 if (cbs == null) {
1716 return callbacks;
1717 }
1718 if (callbacks == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001719 callbacks = new HashMap<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001720 }
Svet Ganov2af57082015-07-30 08:44:20 -07001721 boolean duplicate = false;
Dianne Hackborn68d76552017-02-27 15:32:03 -08001722 final int N = cbs.size();
1723 for (int i=0; i<N; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001724 ModeCallback cb = cbs.valueAt(i);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001725 ArrayList<ChangeRec> reports = callbacks.get(cb);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001726 if (reports == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001727 reports = new ArrayList<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001728 callbacks.put(cb, reports);
Svet Ganov2af57082015-07-30 08:44:20 -07001729 } else {
1730 final int reportCount = reports.size();
1731 for (int j = 0; j < reportCount; j++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001732 ChangeRec report = reports.get(j);
1733 if (report.op == op && report.pkg.equals(packageName)) {
Svet Ganov2af57082015-07-30 08:44:20 -07001734 duplicate = true;
1735 break;
1736 }
1737 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001738 }
Svet Ganov2af57082015-07-30 08:44:20 -07001739 if (!duplicate) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001740 reports.add(new ChangeRec(op, uid, packageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001741 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001742 }
1743 return callbacks;
1744 }
1745
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001746 static final class ChangeRec {
1747 final int op;
1748 final int uid;
1749 final String pkg;
1750
1751 ChangeRec(int _op, int _uid, String _pkg) {
1752 op = _op;
1753 uid = _uid;
1754 pkg = _pkg;
1755 }
1756 }
1757
Dianne Hackborn607b4142013-08-02 18:10:10 -07001758 @Override
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001759 public void resetAllModes(int reqUserId, String reqPackageName) {
1760 final int callingPid = Binder.getCallingPid();
1761 final int callingUid = Binder.getCallingUid();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001762 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
1763 true, true, "resetAllModes", null);
Svet Ganov2af57082015-07-30 08:44:20 -07001764
1765 int reqUid = -1;
1766 if (reqPackageName != null) {
1767 try {
1768 reqUid = AppGlobals.getPackageManager().getPackageUid(
Jeff Sharkeycd654482016-01-08 17:42:11 -07001769 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
Svet Ganov2af57082015-07-30 08:44:20 -07001770 } catch (RemoteException e) {
1771 /* ignore - local call */
1772 }
1773 }
1774
Dianne Hackbornd5254412018-05-11 18:02:58 -07001775 enforceManageAppOpsModes(callingPid, callingUid, reqUid);
1776
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001777 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001778 synchronized (this) {
1779 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -07001780 for (int i = mUidStates.size() - 1; i >= 0; i--) {
1781 UidState uidState = mUidStates.valueAt(i);
1782
Hai Zhang93540ca2019-09-28 00:04:18 +00001783 SparseIntArray opModes = uidState.opModes;
1784 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
1785 final int uidOpCount = opModes.size();
1786 for (int j = uidOpCount - 1; j >= 0; j--) {
1787 final int code = opModes.keyAt(j);
Svet Ganov2af57082015-07-30 08:44:20 -07001788 if (AppOpsManager.opAllowsReset(code)) {
Hai Zhang93540ca2019-09-28 00:04:18 +00001789 opModes.removeAt(j);
1790 if (opModes.size() <= 0) {
1791 uidState.opModes = null;
1792 }
Svet Ganov2af57082015-07-30 08:44:20 -07001793 for (String packageName : getPackagesForUid(uidState.uid)) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001794 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001795 mOpModeWatchers.get(code));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001796 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001797 mPackageModeWatchers.get(packageName));
1798 }
1799 }
1800 }
1801 }
1802
1803 if (uidState.pkgOps == null) {
1804 continue;
1805 }
1806
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001807 if (reqUserId != UserHandle.USER_ALL
Svet Ganov2af57082015-07-30 08:44:20 -07001808 && reqUserId != UserHandle.getUserId(uidState.uid)) {
Alexandra Gherghinad6a98972014-08-04 17:05:34 +01001809 // Skip any ops for a different user
1810 continue;
1811 }
Svet Ganov2af57082015-07-30 08:44:20 -07001812
1813 Map<String, Ops> packages = uidState.pkgOps;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001814 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001815 boolean uidChanged = false;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001816 while (it.hasNext()) {
1817 Map.Entry<String, Ops> ent = it.next();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001818 String packageName = ent.getKey();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001819 if (reqPackageName != null && !reqPackageName.equals(packageName)) {
1820 // Skip any ops for a different package
1821 continue;
1822 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001823 Ops pkgOps = ent.getValue();
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001824 for (int j=pkgOps.size()-1; j>=0; j--) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001825 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn8828d3a2013-09-25 16:47:10 -07001826 if (AppOpsManager.opAllowsReset(curOp.op)
1827 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
David Braunf5d83192013-09-16 13:43:51 -07001828 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001829 changed = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001830 uidChanged = true;
Svet Ganovaf189e32019-02-15 18:45:29 -08001831 final int uid = curOp.uidState.uid;
1832 callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001833 mOpModeWatchers.get(curOp.op));
Svet Ganovaf189e32019-02-15 18:45:29 -08001834 callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001835 mPackageModeWatchers.get(packageName));
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001836
1837 curOp.removeFeaturesWithNoTime();
1838 if (curOp.mFeatures.size() == 0) {
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001839 pkgOps.removeAt(j);
1840 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001841 }
1842 }
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001843 if (pkgOps.size() == 0) {
1844 it.remove();
1845 }
1846 }
Svet Ganov2af57082015-07-30 08:44:20 -07001847 if (uidState.isDefault()) {
1848 mUidStates.remove(uidState.uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001849 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001850 if (uidChanged) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001851 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001852 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001853 }
Svet Ganov2af57082015-07-30 08:44:20 -07001854
Dianne Hackborn607b4142013-08-02 18:10:10 -07001855 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001856 scheduleFastWriteLocked();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001857 }
1858 }
1859 if (callbacks != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001860 for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
1861 ModeCallback cb = ent.getKey();
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001862 ArrayList<ChangeRec> reports = ent.getValue();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001863 for (int i=0; i<reports.size(); i++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001864 ChangeRec rep = reports.get(i);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001865 mHandler.sendMessage(PooledLambda.obtainMessage(
1866 AppOpsService::notifyOpChanged,
1867 this, cb, rep.op, rep.uid, rep.pkg));
Dianne Hackborn607b4142013-08-02 18:10:10 -07001868 }
1869 }
1870 }
1871 }
1872
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001873 private void evalAllForegroundOpsLocked() {
1874 for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
1875 final UidState uidState = mUidStates.valueAt(uidi);
1876 if (uidState.foregroundOps != null) {
1877 uidState.evalForegroundOps(mOpModeWatchers);
1878 }
1879 }
1880 }
1881
Dianne Hackbornc2293022013-02-06 23:14:49 -08001882 @Override
1883 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001884 startWatchingModeWithFlags(op, packageName, 0, callback);
1885 }
1886
1887 @Override
1888 public void startWatchingModeWithFlags(int op, String packageName, int flags,
1889 IAppOpsCallback callback) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001890 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001891 final int callingUid = Binder.getCallingUid();
1892 final int callingPid = Binder.getCallingPid();
Dianne Hackborn5376edd2018-06-05 13:21:16 -07001893 // TODO: should have a privileged permission to protect this.
1894 // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require
1895 // the USAGE_STATS permission since this can provide information about when an
1896 // app is in the foreground?
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001897 Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
1898 AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001899 if (callback == null) {
1900 return;
1901 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001902 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001903 op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001904 ModeCallback cb = mModeWatchers.get(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001905 if (cb == null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001906 cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001907 mModeWatchers.put(callback.asBinder(), cb);
1908 }
1909 if (op != AppOpsManager.OP_NONE) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001910 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001911 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001912 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001913 mOpModeWatchers.put(op, cbs);
1914 }
1915 cbs.add(cb);
1916 }
1917 if (packageName != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001918 ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001919 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001920 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001921 mPackageModeWatchers.put(packageName, cbs);
1922 }
1923 cbs.add(cb);
1924 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001925 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001926 }
1927 }
1928
1929 @Override
1930 public void stopWatchingMode(IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001931 if (callback == null) {
1932 return;
1933 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001934 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001935 ModeCallback cb = mModeWatchers.remove(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001936 if (cb != null) {
1937 cb.unlinkToDeath();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001938 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001939 ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001940 cbs.remove(cb);
1941 if (cbs.size() <= 0) {
1942 mOpModeWatchers.removeAt(i);
1943 }
1944 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001945 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001946 ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001947 cbs.remove(cb);
1948 if (cbs.size() <= 0) {
1949 mPackageModeWatchers.removeAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001950 }
1951 }
1952 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001953 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001954 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001955 }
1956
1957 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001958 public IBinder getToken(IBinder clientToken) {
1959 synchronized (this) {
1960 ClientState cs = mClients.get(clientToken);
1961 if (cs == null) {
1962 cs = new ClientState(clientToken);
1963 mClients.put(clientToken, cs);
1964 }
1965 return cs;
1966 }
1967 }
1968
Svet Ganovd873ae62018-06-25 16:39:23 -07001969 public CheckOpsDelegate getAppOpsServiceDelegate() {
1970 synchronized (this) {
1971 return mCheckOpsDelegate;
1972 }
1973 }
1974
1975 public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) {
1976 synchronized (this) {
1977 mCheckOpsDelegate = delegate;
1978 }
1979 }
1980
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001981 @Override
Svet Ganov9d528a12018-12-19 17:23:11 -08001982 public int checkOperationRaw(int code, int uid, String packageName) {
1983 return checkOperationInternal(code, uid, packageName, true /*raw*/);
1984 }
1985
1986 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -08001987 public int checkOperation(int code, int uid, String packageName) {
Svet Ganov9d528a12018-12-19 17:23:11 -08001988 return checkOperationInternal(code, uid, packageName, false /*raw*/);
1989 }
1990
1991 private int checkOperationInternal(int code, int uid, String packageName, boolean raw) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001992 final CheckOpsDelegate delegate;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001993 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001994 delegate = mCheckOpsDelegate;
1995 }
Todd Kennedy556efba2018-11-15 07:43:55 -08001996 if (delegate == null) {
Svet Ganov9d528a12018-12-19 17:23:11 -08001997 return checkOperationImpl(code, uid, packageName, raw);
Todd Kennedy556efba2018-11-15 07:43:55 -08001998 }
Svet Ganov9d528a12018-12-19 17:23:11 -08001999 return delegate.checkOperation(code, uid, packageName, raw,
Svet Ganovd873ae62018-06-25 16:39:23 -07002000 AppOpsService.this::checkOperationImpl);
2001 }
2002
Svet Ganov9d528a12018-12-19 17:23:11 -08002003 private int checkOperationImpl(int code, int uid, String packageName,
2004 boolean raw) {
Todd Kennedy556efba2018-11-15 07:43:55 -08002005 verifyIncomingUid(uid);
2006 verifyIncomingOp(code);
2007 String resolvedPackageName = resolvePackageName(uid, packageName);
2008 if (resolvedPackageName == null) {
2009 return AppOpsManager.MODE_IGNORED;
2010 }
Svet Ganov9d528a12018-12-19 17:23:11 -08002011 return checkOperationUnchecked(code, uid, resolvedPackageName, raw);
Todd Kennedy556efba2018-11-15 07:43:55 -08002012 }
2013
Philip P. Moltmann724150d2019-03-11 17:01:05 -07002014 /**
Philip P. Moltmann724150d2019-03-11 17:01:05 -07002015 * Get the mode of an app-op.
2016 *
2017 * @param code The code of the op
2018 * @param uid The uid of the package the op belongs to
2019 * @param packageName The package the op belongs to
2020 * @param raw If the raw state of eval-ed state should be checked.
Philip P. Moltmann724150d2019-03-11 17:01:05 -07002021 *
2022 * @return The mode of the op
2023 */
2024 private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
Philip P. Moltmannd4ab19e2019-05-07 08:57:35 -07002025 boolean raw) {
Philip P. Moltmannc5f504a2019-06-12 16:31:29 -07002026 boolean isPrivileged;
2027
2028 try {
2029 isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
2030 } catch (SecurityException e) {
2031 Slog.e(TAG, "checkOperation", e);
2032 return AppOpsManager.opToDefaultMode(code);
2033 }
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002034
Suprabh Shukla7e017922019-08-05 17:13:23 -07002035 if (isOpRestrictedDueToSuspend(code, packageName, uid)) {
2036 return AppOpsManager.MODE_IGNORED;
2037 }
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002038 synchronized (this) {
2039 if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) {
Jason Monk62062992014-05-06 09:55:28 -04002040 return AppOpsManager.MODE_IGNORED;
2041 }
Svet Ganov2af57082015-07-30 08:44:20 -07002042 code = AppOpsManager.opToSwitch(code);
2043 UidState uidState = getUidStateLocked(uid, false);
Hai Zhang93540ca2019-09-28 00:04:18 +00002044 if (uidState != null && uidState.opModes != null
2045 && uidState.opModes.indexOfKey(code) >= 0) {
2046 final int rawMode = uidState.opModes.get(code);
Svet Ganovaf189e32019-02-15 18:45:29 -08002047 return raw ? rawMode : uidState.evalMode(code, rawMode);
Svet Ganov2af57082015-07-30 08:44:20 -07002048 }
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002049 Op op = getOpLocked(code, uid, packageName, false, false);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002050 if (op == null) {
David Braunf5d83192013-09-16 13:43:51 -07002051 return AppOpsManager.opToDefaultMode(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002052 }
Svet Ganovaf189e32019-02-15 18:45:29 -08002053 return raw ? op.mode : op.evalMode();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002054 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002055 }
2056
2057 @Override
John Spurlock7b414672014-07-18 13:02:39 -04002058 public int checkAudioOperation(int code, int usage, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002059 final CheckOpsDelegate delegate;
John Spurlock1af30c72014-03-10 08:33:35 -04002060 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002061 delegate = mCheckOpsDelegate;
2062 }
Todd Kennedy556efba2018-11-15 07:43:55 -08002063 if (delegate == null) {
2064 return checkAudioOperationImpl(code, usage, uid, packageName);
2065 }
Svet Ganovd873ae62018-06-25 16:39:23 -07002066 return delegate.checkAudioOperation(code, usage, uid, packageName,
2067 AppOpsService.this::checkAudioOperationImpl);
2068 }
2069
2070 private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
Yin-Chia Yeh51d85162019-08-06 15:31:39 -07002071 final int mode = mAudioRestrictionManager.checkAudioOperation(
2072 code, usage, uid, packageName);
2073 if (mode != AppOpsManager.MODE_ALLOWED) {
2074 return mode;
John Spurlock1af30c72014-03-10 08:33:35 -04002075 }
2076 return checkOperation(code, uid, packageName);
2077 }
2078
John Spurlock1af30c72014-03-10 08:33:35 -04002079 @Override
John Spurlock7b414672014-07-18 13:02:39 -04002080 public void setAudioRestriction(int code, int usage, int uid, int mode,
John Spurlock1af30c72014-03-10 08:33:35 -04002081 String[] exceptionPackages) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07002082 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
John Spurlock1af30c72014-03-10 08:33:35 -04002083 verifyIncomingUid(uid);
2084 verifyIncomingOp(code);
Yin-Chia Yeh51d85162019-08-06 15:31:39 -07002085
2086 mAudioRestrictionManager.setZenModeAudioRestriction(
2087 code, usage, uid, mode, exceptionPackages);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002088
2089 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07002090 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
John Spurlock1af30c72014-03-10 08:33:35 -04002091 }
2092
Yin-Chia Yeh51d85162019-08-06 15:31:39 -07002093
2094 @Override
2095 public void setCameraAudioRestriction(@CAMERA_AUDIO_RESTRICTION int mode) {
2096 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), -1);
2097
2098 mAudioRestrictionManager.setCameraAudioRestriction(mode);
2099
2100 mHandler.sendMessage(PooledLambda.obtainMessage(
2101 AppOpsService::notifyWatchersOfChange, this,
2102 AppOpsManager.OP_PLAY_AUDIO, UID_ANY));
2103 mHandler.sendMessage(PooledLambda.obtainMessage(
2104 AppOpsService::notifyWatchersOfChange, this,
2105 AppOpsManager.OP_VIBRATE, UID_ANY));
2106 }
2107
John Spurlock1af30c72014-03-10 08:33:35 -04002108 @Override
Jeff Sharkey911d7f42013-09-05 18:11:45 -07002109 public int checkPackage(int uid, String packageName) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002110 Preconditions.checkNotNull(packageName);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002111 try {
2112 verifyAndGetIsPrivileged(uid, packageName);
2113
2114 return AppOpsManager.MODE_ALLOWED;
2115 } catch (SecurityException ignored) {
2116 return AppOpsManager.MODE_ERRORED;
Jeff Sharkey911d7f42013-09-05 18:11:45 -07002117 }
2118 }
2119
2120 @Override
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002121 public int noteProxyOperation(int code, int proxiedUid, String proxiedPackageName,
2122 String proxiedFeatureId, int proxyUid, String proxyPackageName,
2123 String proxyFeatureId) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002124 verifyIncomingUid(proxyUid);
Svet Ganov99b60432015-06-27 13:15:22 -07002125 verifyIncomingOp(code);
Svet Ganovaf189e32019-02-15 18:45:29 -08002126
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002127 String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
2128 if (resolveProxyPackageName == null) {
2129 return AppOpsManager.MODE_IGNORED;
2130 }
Svet Ganovaf189e32019-02-15 18:45:29 -08002131
2132 final boolean isProxyTrusted = mContext.checkPermission(
2133 Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
2134 == PackageManager.PERMISSION_GRANTED;
2135
2136 final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
2137 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002138 final int proxyMode = noteOperationUnchecked(code, proxyUid, resolveProxyPackageName,
2139 proxyFeatureId, Process.INVALID_UID, null, null, proxyFlags);
Svet Ganov99b60432015-06-27 13:15:22 -07002140 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
2141 return proxyMode;
2142 }
Svet Ganovaf189e32019-02-15 18:45:29 -08002143
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002144 String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
2145 if (resolveProxiedPackageName == null) {
2146 return AppOpsManager.MODE_IGNORED;
2147 }
Svet Ganovaf189e32019-02-15 18:45:29 -08002148 final int proxiedFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXIED
2149 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED;
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002150 return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002151 proxiedFeatureId, proxyUid, resolveProxyPackageName, proxyFeatureId,
2152 proxiedFlags);
Svet Ganov99b60432015-06-27 13:15:22 -07002153 }
2154
2155 @Override
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002156 public int noteOperation(int code, int uid, String packageName, String featureId) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002157 final CheckOpsDelegate delegate;
2158 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002159 delegate = mCheckOpsDelegate;
2160 }
Todd Kennedy556efba2018-11-15 07:43:55 -08002161 if (delegate == null) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002162 return noteOperationImpl(code, uid, packageName, featureId);
Todd Kennedy556efba2018-11-15 07:43:55 -08002163 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002164 return delegate.noteOperation(code, uid, packageName, featureId,
Svet Ganovd873ae62018-06-25 16:39:23 -07002165 AppOpsService.this::noteOperationImpl);
2166 }
2167
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002168 private int noteOperationImpl(int code, int uid, String packageName, String featureId) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002169 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08002170 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002171 String resolvedPackageName = resolvePackageName(uid, packageName);
2172 if (resolvedPackageName == null) {
2173 return AppOpsManager.MODE_IGNORED;
2174 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002175 return noteOperationUnchecked(code, uid, resolvedPackageName, featureId,
2176 Process.INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF);
Svet Ganov99b60432015-06-27 13:15:22 -07002177 }
2178
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002179 private int noteOperationUnchecked(int code, int uid, String packageName, String featureId,
2180 int proxyUid, String proxyPackageName, @Nullable String proxyFeatureId,
2181 @OpFlags int flags) {
2182 // TODO moltmann: Verify that feature is declared in package
2183
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002184 boolean isPrivileged;
2185 try {
2186 isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
2187 } catch (SecurityException e) {
Philip P. Moltmannc5f504a2019-06-12 16:31:29 -07002188 Slog.e(TAG, "noteOperation", e);
2189 return AppOpsManager.MODE_ERRORED;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002190 }
2191
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002192 synchronized (this) {
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002193 final Ops ops = getOpsRawLocked(uid, packageName, isPrivileged, true /* edit */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002194 if (ops == null) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002195 scheduleOpNotedIfNeededLocked(code, uid, packageName,
2196 AppOpsManager.MODE_IGNORED);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002197 if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002198 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07002199 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002200 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002201 final Op op = getOpLocked(ops, code, true);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002202 final FeatureOp featureOp = op.getOrCreateFeature(op, featureId);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002203 if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002204 scheduleOpNotedIfNeededLocked(code, uid, packageName,
2205 AppOpsManager.MODE_IGNORED);
Jason Monk62062992014-05-06 09:55:28 -04002206 return AppOpsManager.MODE_IGNORED;
2207 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002208 final UidState uidState = ops.uidState;
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002209 if (featureOp.running) {
2210 final OpFeatureEntry entry = getOpLocked(ops, code,
2211 false).createSingleFeatureEntryLocked(featureId).getFeatures().get(
2212 featureId);
2213
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002214 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
Svet Ganovaf189e32019-02-15 18:45:29 -08002215 + " code " + code + " time=" + entry.getLastAccessTime(uidState.state,
2216 uidState.state, flags) + " duration=" + entry.getLastDuration(
2217 uidState.state, uidState.state, flags));
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002218 }
Svet Ganovaf189e32019-02-15 18:45:29 -08002219
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002220 final int switchCode = AppOpsManager.opToSwitch(code);
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07002221 // If there is a non-default per UID policy (we set UID op mode only if
2222 // non-default) it takes over, otherwise use the per package policy.
Hai Zhang93540ca2019-09-28 00:04:18 +00002223 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
2224 final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode));
Svet Ganov2af57082015-07-30 08:44:20 -07002225 if (uidMode != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002226 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07002227 + switchCode + " (" + code + ") uid " + uid + " package "
2228 + packageName);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002229 featureOp.rejected(System.currentTimeMillis(), proxyUid, proxyPackageName,
2230 proxyFeatureId, uidState.state, flags);
Svet Ganovaf189e32019-02-15 18:45:29 -08002231 mHistoricalRegistry.incrementOpRejected(code, uid, packageName,
2232 uidState.state, flags);
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002233 scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode);
Svet Ganov2af57082015-07-30 08:44:20 -07002234 return uidMode;
2235 }
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07002236 } else {
2237 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Svet Ganovaf189e32019-02-15 18:45:29 -08002238 final int mode = switchOp.evalMode();
2239 if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002240 if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07002241 + switchCode + " (" + code + ") uid " + uid + " package "
2242 + packageName);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002243 featureOp.rejected(System.currentTimeMillis(), proxyUid, proxyPackageName,
2244 proxyFeatureId, uidState.state, flags);
Svet Ganovaf189e32019-02-15 18:45:29 -08002245 mHistoricalRegistry.incrementOpRejected(code, uid, packageName,
2246 uidState.state, flags);
2247 scheduleOpNotedIfNeededLocked(code, uid, packageName, mode);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002248 return mode;
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07002249 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002250 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002251 if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002252 + " package " + packageName + (featureId == null ? "" : "." + featureId));
2253 featureOp.accessed(System.currentTimeMillis(), proxyUid, proxyPackageName,
2254 proxyFeatureId, uidState.state, flags);
2255 // TODO moltmann: Add features to historical app-ops
Svet Ganov8455ba22019-01-02 13:05:56 -08002256 mHistoricalRegistry.incrementOpAccessedCount(op.op, uid, packageName,
Svet Ganovaf189e32019-02-15 18:45:29 -08002257 uidState.state, flags);
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002258 scheduleOpNotedIfNeededLocked(code, uid, packageName,
2259 AppOpsManager.MODE_ALLOWED);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002260 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002261 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002262 }
2263
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002264 // TODO moltmann: Allow watching for feature ops
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002265 @Override
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002266 public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
Svet Ganovf7b47252018-02-26 11:11:27 -08002267 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002268 final int callingUid = Binder.getCallingUid();
2269 final int callingPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -08002270 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
2271 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002272 watchedUid = callingUid;
Svet Ganovf7b47252018-02-26 11:11:27 -08002273 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002274 if (ops != null) {
2275 Preconditions.checkArrayElementsInRange(ops, 0,
2276 AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
2277 }
2278 if (callback == null) {
2279 return;
2280 }
2281 synchronized (this) {
2282 SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
2283 if (callbacks == null) {
2284 callbacks = new SparseArray<>();
2285 mActiveWatchers.put(callback.asBinder(), callbacks);
2286 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002287 final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
2288 callingUid, callingPid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002289 for (int op : ops) {
2290 callbacks.put(op, activeCallback);
2291 }
2292 }
2293 }
2294
2295 @Override
2296 public void stopWatchingActive(IAppOpsActiveCallback callback) {
2297 if (callback == null) {
2298 return;
2299 }
2300 synchronized (this) {
2301 final SparseArray<ActiveCallback> activeCallbacks =
2302 mActiveWatchers.remove(callback.asBinder());
2303 if (activeCallbacks == null) {
2304 return;
2305 }
2306 final int callbackCount = activeCallbacks.size();
2307 for (int i = 0; i < callbackCount; i++) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002308 activeCallbacks.valueAt(i).destroy();
2309 }
2310 }
2311 }
2312
2313 @Override
2314 public void startWatchingNoted(@NonNull int[] ops, @NonNull IAppOpsNotedCallback callback) {
2315 int watchedUid = Process.INVALID_UID;
2316 final int callingUid = Binder.getCallingUid();
2317 final int callingPid = Binder.getCallingPid();
2318 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
2319 != PackageManager.PERMISSION_GRANTED) {
2320 watchedUid = callingUid;
2321 }
2322 Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
2323 Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
2324 "Invalid op code in: " + Arrays.toString(ops));
2325 Preconditions.checkNotNull(callback, "Callback cannot be null");
2326 synchronized (this) {
2327 SparseArray<NotedCallback> callbacks = mNotedWatchers.get(callback.asBinder());
2328 if (callbacks == null) {
2329 callbacks = new SparseArray<>();
2330 mNotedWatchers.put(callback.asBinder(), callbacks);
2331 }
2332 final NotedCallback notedCallback = new NotedCallback(callback, watchedUid,
2333 callingUid, callingPid);
2334 for (int op : ops) {
2335 callbacks.put(op, notedCallback);
2336 }
2337 }
2338 }
2339
2340 @Override
2341 public void stopWatchingNoted(IAppOpsNotedCallback callback) {
2342 Preconditions.checkNotNull(callback, "Callback cannot be null");
2343 synchronized (this) {
2344 final SparseArray<NotedCallback> notedCallbacks =
2345 mNotedWatchers.remove(callback.asBinder());
2346 if (notedCallbacks == null) {
2347 return;
2348 }
2349 final int callbackCount = notedCallbacks.size();
2350 for (int i = 0; i < callbackCount; i++) {
2351 notedCallbacks.valueAt(i).destroy();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002352 }
2353 }
2354 }
2355
2356 @Override
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07002357 public void noteAsyncOp(String callingPackageName, int uid, String packageName, int opCode,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002358 String featureId, String message) {
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07002359 Preconditions.checkNotNull(message);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07002360 verifyAndGetIsPrivileged(uid, packageName);
2361
2362 verifyIncomingUid(uid);
2363 verifyIncomingOp(opCode);
2364
2365 int callingUid = Binder.getCallingUid();
2366 long now = System.currentTimeMillis();
2367
2368 if (callingPackageName != null) {
2369 verifyAndGetIsPrivileged(callingUid, callingPackageName);
2370 }
2371
2372 long token = Binder.clearCallingIdentity();
2373 try {
2374 synchronized (this) {
2375 Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
2376
2377 RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
2378 AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002379 callingPackageName, featureId, message, now);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07002380 final boolean[] wasNoteForwarded = {false};
2381
2382 if (callbacks != null) {
2383 callbacks.broadcast((cb) -> {
2384 try {
2385 cb.opNoted(asyncNotedOp);
2386 wasNoteForwarded[0] = true;
2387 } catch (RemoteException e) {
2388 Slog.e(TAG,
2389 "Could not forward noteOp of " + opCode + " to " + packageName
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002390 + "/" + uid + "(" + featureId + ")", e);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07002391 }
2392 });
2393 }
2394
2395 if (!wasNoteForwarded[0]) {
2396 ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(key);
2397 if (unforwardedOps == null) {
2398 unforwardedOps = new ArrayList<>(1);
2399 mUnforwardedAsyncNotedOps.put(key, unforwardedOps);
2400 }
2401
2402 unforwardedOps.add(asyncNotedOp);
2403 if (unforwardedOps.size() > MAX_UNFORWARED_OPS) {
2404 unforwardedOps.remove(0);
2405 }
2406 }
2407 }
2408 } finally {
2409 Binder.restoreCallingIdentity(token);
2410 }
2411 }
2412
2413 /**
2414 * Compute a key to be used in {@link #mAsyncOpWatchers} and {@link #mUnforwardedAsyncNotedOps}
2415 *
2416 * @param packageName The package name of the app
2417 * @param uid The uid of the app
2418 *
2419 * @return They key uniquely identifying the app
2420 */
2421 private @NonNull Pair<String, Integer> getAsyncNotedOpsKey(@NonNull String packageName,
2422 int uid) {
2423 return new Pair<>(packageName, uid);
2424 }
2425
2426 @Override
2427 public void startWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) {
2428 Preconditions.checkNotNull(packageName);
2429 Preconditions.checkNotNull(callback);
2430
2431 int uid = Binder.getCallingUid();
2432 Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
2433
2434 verifyAndGetIsPrivileged(uid, packageName);
2435
2436 synchronized (this) {
2437 RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
2438 if (callbacks == null) {
2439 callbacks = new RemoteCallbackList<IAppOpsAsyncNotedCallback>() {
2440 @Override
2441 public void onCallbackDied(IAppOpsAsyncNotedCallback callback) {
2442 synchronized (AppOpsService.this) {
2443 if (getRegisteredCallbackCount() == 0) {
2444 mAsyncOpWatchers.remove(key);
2445 }
2446 }
2447 }
2448 };
2449 mAsyncOpWatchers.put(key, callbacks);
2450 }
2451
2452 callbacks.register(callback);
2453 }
2454 }
2455
2456 @Override
2457 public void stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) {
2458 Preconditions.checkNotNull(packageName);
2459 Preconditions.checkNotNull(callback);
2460
2461 int uid = Binder.getCallingUid();
2462 Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
2463
2464 verifyAndGetIsPrivileged(uid, packageName);
2465
2466 synchronized (this) {
2467 RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
2468 if (callbacks != null) {
2469 callbacks.unregister(callback);
2470 if (callbacks.getRegisteredCallbackCount() == 0) {
2471 mAsyncOpWatchers.remove(key);
2472 }
2473 }
2474 }
2475 }
2476
2477 @Override
2478 public List<AsyncNotedAppOp> extractAsyncOps(String packageName) {
2479 Preconditions.checkNotNull(packageName);
2480
2481 int uid = Binder.getCallingUid();
2482
2483 verifyAndGetIsPrivileged(uid, packageName);
2484
2485 synchronized (this) {
2486 return mUnforwardedAsyncNotedOps.remove(getAsyncNotedOpsKey(packageName, uid));
2487 }
2488 }
2489
2490 @Override
Svet Ganovf7b47252018-02-26 11:11:27 -08002491 public int startOperation(IBinder token, int code, int uid, String packageName,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002492 String featureId, boolean startIfModeDefault) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002493 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08002494 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002495 String resolvedPackageName = resolvePackageName(uid, packageName);
2496 if (resolvedPackageName == null) {
2497 return AppOpsManager.MODE_IGNORED;
2498 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002499 ClientState client = (ClientState)token;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002500
2501 boolean isPrivileged;
2502 try {
2503 isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
2504 } catch (SecurityException e) {
Philip P. Moltmannc5f504a2019-06-12 16:31:29 -07002505 Slog.e(TAG, "startOperation", e);
2506 return AppOpsManager.MODE_ERRORED;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002507 }
2508
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002509 synchronized (this) {
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002510 final Ops ops = getOpsRawLocked(uid, resolvedPackageName, isPrivileged,
2511 true /* edit */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002512 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002513 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002514 + " package " + resolvedPackageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07002515 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002516 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002517 final Op op = getOpLocked(ops, code, true);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002518 if (isOpRestrictedLocked(uid, code, resolvedPackageName, isPrivileged)) {
Jason Monk62062992014-05-06 09:55:28 -04002519 return AppOpsManager.MODE_IGNORED;
2520 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002521 final FeatureOp featureOp = op.getOrCreateFeature(op, featureId);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002522 final int switchCode = AppOpsManager.opToSwitch(code);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002523 final UidState uidState = ops.uidState;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002524 // If there is a non-default per UID policy (we set UID op mode only if
2525 // non-default) it takes over, otherwise use the per package policy.
Svet Ganovaf189e32019-02-15 18:45:29 -08002526 final int opCode = op.op;
Hai Zhang93540ca2019-09-28 00:04:18 +00002527 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
2528 final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode));
Svet Ganovf7b47252018-02-26 11:11:27 -08002529 if (uidMode != AppOpsManager.MODE_ALLOWED
2530 && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002531 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07002532 + switchCode + " (" + code + ") uid " + uid + " package "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002533 + resolvedPackageName);
Svet Ganovaf189e32019-02-15 18:45:29 -08002534 // We don't support proxy long running ops (start/stop)
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002535 featureOp.rejected(System.currentTimeMillis(), -1 /*proxyUid*/,
2536 null /*proxyPackage*/, null, uidState.state,
2537 AppOpsManager.OP_FLAG_SELF);
Svet Ganovaf189e32019-02-15 18:45:29 -08002538 mHistoricalRegistry.incrementOpRejected(opCode, uid, packageName,
2539 uidState.state, AppOpsManager.OP_FLAG_SELF);
Svet Ganov2af57082015-07-30 08:44:20 -07002540 return uidMode;
2541 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002542 } else {
2543 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Svet Ganovaf189e32019-02-15 18:45:29 -08002544 final int mode = switchOp.evalMode();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002545 if (mode != AppOpsManager.MODE_ALLOWED
2546 && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
2547 if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002548 + switchCode + " (" + code + ") uid " + uid + " package "
2549 + resolvedPackageName);
Svet Ganovaf189e32019-02-15 18:45:29 -08002550 // We don't support proxy long running ops (start/stop)
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002551 featureOp.rejected(System.currentTimeMillis(), -1 /*proxyUid*/,
2552 null /*proxyPackage*/, null, uidState.state,
2553 AppOpsManager.OP_FLAG_SELF);
Svet Ganovaf189e32019-02-15 18:45:29 -08002554 mHistoricalRegistry.incrementOpRejected(opCode, uid, packageName,
2555 uidState.state, AppOpsManager.OP_FLAG_SELF);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002556 return mode;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002557 }
Svet Ganov2af57082015-07-30 08:44:20 -07002558 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002559 if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002560 + " package " + resolvedPackageName);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002561 if (featureOp.startNesting == 0) {
2562 featureOp.startRealtime = SystemClock.elapsedRealtime();
Svet Ganovaf189e32019-02-15 18:45:29 -08002563 // We don't support proxy long running ops (start/stop)
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002564 featureOp.started(System.currentTimeMillis(), uidState.state,
Svet Ganovaf189e32019-02-15 18:45:29 -08002565 AppOpsManager.OP_FLAG_SELF);
2566 mHistoricalRegistry.incrementOpAccessedCount(opCode, uid, packageName,
2567 uidState.state, AppOpsManager.OP_FLAG_SELF);
2568
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002569 // TODO moltmann: call back when a feature became inactive
2570 if (uidState.startNesting == 0) {
2571 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
2572 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002573 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002574 featureOp.startNesting++;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002575 uidState.startNesting++;
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002576 client.mStartedOps.add(new Pair<>(op, featureId));
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002577 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002578
2579 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002580 }
2581
2582 @Override
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002583 public void finishOperation(IBinder token, int code, int uid, String packageName,
2584 String featureId) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002585 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08002586 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002587 String resolvedPackageName = resolvePackageName(uid, packageName);
2588 if (resolvedPackageName == null) {
2589 return;
2590 }
2591 if (!(token instanceof ClientState)) {
2592 return;
2593 }
2594 ClientState client = (ClientState) token;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002595
2596 boolean isPrivileged;
2597 try {
2598 isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
2599 } catch (SecurityException e) {
2600 Slog.e(TAG, "Cannot finishOperation", e);
2601 return;
2602 }
2603
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002604 synchronized (this) {
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002605 Op op = getOpLocked(code, uid, resolvedPackageName, isPrivileged, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002606 if (op == null) {
2607 return;
2608 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002609 final FeatureOp featureOp = op.mFeatures.get(featureId);
2610 if (featureOp == null) {
2611 return;
2612 }
2613
2614 if (client.mStartedOps.remove(new Pair<>(op, featureId))) {
2615 finishOperationLocked(op, featureId, /*finishNested*/ false);
2616
2617 // TODO moltmann: call back when a feature became inactive
2618 if (op.uidState.startNesting <= 0) {
Philip P. Moltmann8c50f822019-04-05 16:37:09 -07002619 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
Svet Ganovf5d5af12018-03-18 11:51:17 -07002620 }
Philip P. Moltmann8c50f822019-04-05 16:37:09 -07002621
Svet Ganov31d83ae2018-03-15 10:45:56 -07002622 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002623 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002624 }
Philip P. Moltmann8c50f822019-04-05 16:37:09 -07002625
2626 // We finish ops when packages get removed to guarantee no dangling
2627 // started ops. However, some part of the system may asynchronously
2628 // finish ops for an already gone package. Hence, finishing an op
2629 // for a non existing package is fine and we don't log as a wtf.
2630 final long identity = Binder.clearCallingIdentity();
2631 try {
2632 if (LocalServices.getService(PackageManagerInternal.class).getPackageUid(
2633 resolvedPackageName, 0, UserHandle.getUserId(uid)) < 0) {
2634 Slog.i(TAG, "Finishing op=" + AppOpsManager.opToName(code)
2635 + " for non-existing package=" + resolvedPackageName
2636 + " in uid=" + uid);
2637 return;
2638 }
2639 } finally {
2640 Binder.restoreCallingIdentity(identity);
2641 }
2642 Slog.wtf(TAG, "Operation not started: uid=" + uid + " pkg="
2643 + packageName + " op=" + AppOpsManager.opToName(code));
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002644 }
2645
2646 private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
2647 boolean active) {
2648 ArraySet<ActiveCallback> dispatchedCallbacks = null;
2649 final int callbackListCount = mActiveWatchers.size();
2650 for (int i = 0; i < callbackListCount; i++) {
2651 final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
2652 ActiveCallback callback = callbacks.get(code);
2653 if (callback != null) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002654 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svet Ganovf7b47252018-02-26 11:11:27 -08002655 continue;
2656 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002657 if (dispatchedCallbacks == null) {
2658 dispatchedCallbacks = new ArraySet<>();
2659 }
2660 dispatchedCallbacks.add(callback);
2661 }
2662 }
2663 if (dispatchedCallbacks == null) {
2664 return;
2665 }
2666 mHandler.sendMessage(PooledLambda.obtainMessage(
2667 AppOpsService::notifyOpActiveChanged,
2668 this, dispatchedCallbacks, code, uid, packageName, active));
2669 }
2670
2671 private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
2672 int code, int uid, String packageName, boolean active) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002673 // There are features watching for mode changes such as window manager
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002674 // and location manager which are in our process. The callbacks in these
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002675 // features may require permissions our remote caller does not have.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002676 final long identity = Binder.clearCallingIdentity();
2677 try {
2678 final int callbackCount = callbacks.size();
2679 for (int i = 0; i < callbackCount; i++) {
2680 final ActiveCallback callback = callbacks.valueAt(i);
2681 try {
2682 callback.mCallback.opActiveChanged(code, uid, packageName, active);
2683 } catch (RemoteException e) {
2684 /* do nothing */
2685 }
2686 }
2687 } finally {
2688 Binder.restoreCallingIdentity(identity);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002689 }
2690 }
2691
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002692 private void scheduleOpNotedIfNeededLocked(int code, int uid, String packageName,
2693 int result) {
2694 ArraySet<NotedCallback> dispatchedCallbacks = null;
2695 final int callbackListCount = mNotedWatchers.size();
2696 for (int i = 0; i < callbackListCount; i++) {
2697 final SparseArray<NotedCallback> callbacks = mNotedWatchers.valueAt(i);
2698 final NotedCallback callback = callbacks.get(code);
2699 if (callback != null) {
2700 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
2701 continue;
2702 }
2703 if (dispatchedCallbacks == null) {
2704 dispatchedCallbacks = new ArraySet<>();
2705 }
2706 dispatchedCallbacks.add(callback);
2707 }
2708 }
2709 if (dispatchedCallbacks == null) {
2710 return;
2711 }
2712 mHandler.sendMessage(PooledLambda.obtainMessage(
2713 AppOpsService::notifyOpChecked,
2714 this, dispatchedCallbacks, code, uid, packageName, result));
2715 }
2716
2717 private void notifyOpChecked(ArraySet<NotedCallback> callbacks,
2718 int code, int uid, String packageName, int result) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002719 // There are features watching for checks in our process. The callbacks in
2720 // these features may require permissions our remote caller does not have.
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002721 final long identity = Binder.clearCallingIdentity();
2722 try {
2723 final int callbackCount = callbacks.size();
2724 for (int i = 0; i < callbackCount; i++) {
2725 final NotedCallback callback = callbacks.valueAt(i);
2726 try {
2727 callback.mCallback.opNoted(code, uid, packageName, result);
2728 } catch (RemoteException e) {
2729 /* do nothing */
2730 }
2731 }
2732 } finally {
2733 Binder.restoreCallingIdentity(identity);
2734 }
2735 }
2736
Svet Ganovb9d71a62015-04-30 10:38:13 -07002737 @Override
2738 public int permissionToOpCode(String permission) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002739 if (permission == null) {
2740 return AppOpsManager.OP_NONE;
2741 }
Svet Ganovb9d71a62015-04-30 10:38:13 -07002742 return AppOpsManager.permissionToOpCode(permission);
2743 }
2744
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07002745 @Override
2746 public boolean shouldCollectNotes(int opCode) {
2747 Preconditions.checkArgumentInRange(opCode, 0, _NUM_OP - 1, "opCode");
2748
2749 String perm = AppOpsManager.opToPermission(opCode);
2750 if (perm == null) {
2751 return false;
2752 }
2753
2754 PermissionInfo permInfo;
2755 try {
2756 permInfo = mContext.getPackageManager().getPermissionInfo(perm, 0);
2757 } catch (PackageManager.NameNotFoundException e) {
2758 return false;
2759 }
2760
2761 return permInfo.getProtection() == PROTECTION_DANGEROUS;
2762 }
2763
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002764 void finishOperationLocked(@NonNull Op op, @Nullable String featureId, boolean finishNested) {
2765 final FeatureOp featureOp = op.mFeatures.get(featureId);
2766 final int opCode = featureOp.parent.op;
2767 final int uid = featureOp.parent.uidState.uid;
2768 if (featureOp.startNesting <= 1 || finishNested) {
2769 if (featureOp.startNesting == 1 || finishNested) {
Svet Ganovaf189e32019-02-15 18:45:29 -08002770 // We don't support proxy long running ops (start/stop)
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002771 final long duration = SystemClock.elapsedRealtime() - featureOp.startRealtime;
2772 featureOp.finished(System.currentTimeMillis(), duration, op.uidState.state,
Svet Ganovaf189e32019-02-15 18:45:29 -08002773 AppOpsManager.OP_FLAG_SELF);
2774 mHistoricalRegistry.increaseOpAccessDuration(opCode, uid, op.packageName,
2775 op.uidState.state, AppOpsManager.OP_FLAG_SELF, duration);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002776 } else {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002777 final OpFeatureEntry entry = op.createSingleFeatureEntryLocked(
2778 featureId).getFeatures().get(featureId);
Svet Ganovaf189e32019-02-15 18:45:29 -08002779 Slog.w(TAG, "Finishing op nesting under-run: uid " + uid + " pkg "
2780 + op.packageName + " code " + opCode + " time="
2781 + entry.getLastAccessTime(OP_FLAGS_ALL)
2782 + " duration=" + entry.getLastDuration(MAX_PRIORITY_UID_STATE,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002783 MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL) + " nesting="
2784 + featureOp.startNesting);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002785 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002786 if (featureOp.startNesting >= 1) {
2787 op.uidState.startNesting -= featureOp.startNesting;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002788 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002789 featureOp.startNesting = 0;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002790 } else {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002791 featureOp.startNesting--;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002792 op.uidState.startNesting--;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002793 }
2794 }
2795
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002796 private void verifyIncomingUid(int uid) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002797 if (uid == Binder.getCallingUid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002798 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002799 }
2800 if (Binder.getCallingPid() == Process.myPid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002801 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002802 }
2803 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
2804 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002805 }
2806
Dianne Hackborn961321f2013-02-05 17:22:41 -08002807 private void verifyIncomingOp(int op) {
2808 if (op >= 0 && op < AppOpsManager._NUM_OP) {
2809 return;
2810 }
2811 throw new IllegalArgumentException("Bad operation #" + op);
2812 }
2813
Philip P. Moltmann724150d2019-03-11 17:01:05 -07002814 private @Nullable UidState getUidStateLocked(int uid, boolean edit) {
Svet Ganov2af57082015-07-30 08:44:20 -07002815 UidState uidState = mUidStates.get(uid);
2816 if (uidState == null) {
2817 if (!edit) {
2818 return null;
2819 }
2820 uidState = new UidState(uid);
2821 mUidStates.put(uid, uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002822 } else {
2823 if (uidState.pendingStateCommitTime != 0) {
Dianne Hackborn9fb93502018-06-18 12:29:44 -07002824 if (uidState.pendingStateCommitTime < mLastRealtime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002825 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002826 } else {
Dianne Hackborn9fb93502018-06-18 12:29:44 -07002827 mLastRealtime = SystemClock.elapsedRealtime();
2828 if (uidState.pendingStateCommitTime < mLastRealtime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002829 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002830 }
2831 }
2832 }
Svet Ganov2af57082015-07-30 08:44:20 -07002833 }
2834 return uidState;
2835 }
2836
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002837 private void commitUidPendingStateLocked(UidState uidState) {
Wei Wang878d0b62019-03-28 18:12:18 -07002838 if (uidState.hasForegroundWatchers) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002839 for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
2840 if (!uidState.foregroundOps.valueAt(fgi)) {
2841 continue;
2842 }
2843 final int code = uidState.foregroundOps.keyAt(fgi);
Svet Ganovaf189e32019-02-15 18:45:29 -08002844 // For location ops we consider fg state only if the fg service
2845 // is of location type, for all other ops any fg service will do.
Wei Wang711eb662019-03-21 18:24:17 -07002846 final long firstUnrestrictedUidState = resolveFirstUnrestrictedUidState(code);
2847 final boolean resolvedLastFg = uidState.state <= firstUnrestrictedUidState;
2848 final boolean resolvedNowFg = uidState.pendingState <= firstUnrestrictedUidState;
2849 if (resolvedLastFg == resolvedNowFg) {
Svet Ganovaf189e32019-02-15 18:45:29 -08002850 continue;
2851 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002852 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
2853 if (callbacks != null) {
2854 for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
2855 final ModeCallback callback = callbacks.valueAt(cbi);
2856 if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
2857 || !callback.isWatchingUid(uidState.uid)) {
2858 continue;
2859 }
Hai Zhang93540ca2019-09-28 00:04:18 +00002860 boolean doAllPackages = uidState.opModes != null
2861 && uidState.opModes.indexOfKey(code) >= 0
2862 && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002863 if (uidState.pkgOps != null) {
2864 for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
2865 final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
Svet Ganovaf189e32019-02-15 18:45:29 -08002866 if (op == null) {
2867 continue;
2868 }
2869 if (doAllPackages || op.mode == AppOpsManager.MODE_FOREGROUND) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002870 mHandler.sendMessage(PooledLambda.obtainMessage(
2871 AppOpsService::notifyOpChanged,
2872 this, callback, code, uidState.uid,
2873 uidState.pkgOps.keyAt(pkgi)));
2874 }
2875 }
2876 }
2877 }
2878 }
2879 }
2880 }
Wei Wang711eb662019-03-21 18:24:17 -07002881 uidState.state = uidState.pendingState;
Hui Yu26969322019-08-21 14:56:35 -07002882 uidState.capability = uidState.pendingCapability;
Wei Wang711eb662019-03-21 18:24:17 -07002883 uidState.pendingStateCommitTime = 0;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002884 }
2885
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002886 /**
2887 * Verify that package belongs to uid and return whether the package is privileged.
2888 *
2889 * @param uid The uid the package belongs to
2890 * @param packageName The package the might belong to the uid
2891 *
2892 * @return {@code true} iff the package is privileged
2893 */
2894 private boolean verifyAndGetIsPrivileged(int uid, String packageName) {
2895 if (uid == Process.ROOT_UID) {
2896 // For backwards compatibility, don't check package name for root UID.
2897 return false;
2898 }
2899
2900 // Do not check if uid/packageName is already known
2901 synchronized (this) {
2902 UidState uidState = mUidStates.get(uid);
2903 if (uidState != null && uidState.pkgOps != null) {
2904 Ops ops = uidState.pkgOps.get(packageName);
2905
2906 if (ops != null) {
2907 return ops.isPrivileged;
2908 }
2909 }
2910 }
2911
2912 boolean isPrivileged = false;
2913 final long ident = Binder.clearCallingIdentity();
2914 try {
2915 int pkgUid;
2916
2917 ApplicationInfo appInfo = LocalServices.getService(PackageManagerInternal.class)
2918 .getApplicationInfo(packageName, PackageManager.MATCH_DIRECT_BOOT_AWARE
2919 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
2920 | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
2921 | PackageManager.MATCH_UNINSTALLED_PACKAGES
2922 | PackageManager.MATCH_INSTANT,
2923 Process.SYSTEM_UID, UserHandle.getUserId(uid));
2924 if (appInfo != null) {
2925 pkgUid = appInfo.uid;
2926 isPrivileged = (appInfo.privateFlags
2927 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
2928 } else {
2929 pkgUid = resolveUid(packageName);
2930 if (pkgUid >= 0) {
2931 isPrivileged = false;
2932 }
2933 }
2934 if (pkgUid != uid) {
2935 throw new SecurityException("Specified package " + packageName + " under uid " + uid
2936 + " but it is really " + pkgUid);
2937 }
2938 } finally {
2939 Binder.restoreCallingIdentity(ident);
2940 }
2941
2942 return isPrivileged;
2943 }
2944
2945 /**
2946 * Get (and potentially create) ops.
2947 *
2948 * @param uid The uid the package belongs to
2949 * @param packageName The name of the package
2950 * @param isPrivileged If the package is privilidged (ignored if {@code edit} is false)
2951 * @param edit If an ops does not exist, create the ops?
2952
2953 * @return
2954 */
2955 private Ops getOpsRawLocked(int uid, String packageName, boolean isPrivileged, boolean edit) {
Svet Ganov2af57082015-07-30 08:44:20 -07002956 UidState uidState = getUidStateLocked(uid, edit);
2957 if (uidState == null) {
2958 return null;
2959 }
2960
2961 if (uidState.pkgOps == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002962 if (!edit) {
2963 return null;
2964 }
Svet Ganov2af57082015-07-30 08:44:20 -07002965 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002966 }
Svet Ganov2af57082015-07-30 08:44:20 -07002967
2968 Ops ops = uidState.pkgOps.get(packageName);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002969 if (ops == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002970 if (!edit) {
2971 return null;
2972 }
Svet Ganov2af57082015-07-30 08:44:20 -07002973 ops = new Ops(packageName, uidState, isPrivileged);
2974 uidState.pkgOps.put(packageName, ops);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002975 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08002976 return ops;
2977 }
2978
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07002979 /**
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002980 * Get the state of all ops for a package.
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07002981 *
2982 * <p>Usually callers should use {@link #getOpLocked} and not call this directly.
2983 *
2984 * @param uid The uid the of the package
2985 * @param packageName The package name for which to get the state for
2986 * @param edit Iff {@code true} create the {@link Ops} object if not yet created
2987 * @param isPrivileged Whether the package is privileged or not
2988 *
2989 * @return The {@link Ops state} of all ops for the package
2990 */
2991 private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
2992 boolean edit, boolean isPrivileged) {
2993 UidState uidState = getUidStateLocked(uid, edit);
2994 if (uidState == null) {
2995 return null;
2996 }
2997
2998 if (uidState.pkgOps == null) {
2999 if (!edit) {
3000 return null;
3001 }
3002 uidState.pkgOps = new ArrayMap<>();
3003 }
3004
3005 Ops ops = uidState.pkgOps.get(packageName);
3006 if (ops == null) {
3007 if (!edit) {
3008 return null;
3009 }
3010 ops = new Ops(packageName, uidState, isPrivileged);
3011 uidState.pkgOps.put(packageName, ops);
3012 }
3013 return ops;
3014 }
3015
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003016 private void scheduleWriteLocked() {
3017 if (!mWriteScheduled) {
3018 mWriteScheduled = true;
3019 mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
3020 }
3021 }
3022
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08003023 private void scheduleFastWriteLocked() {
3024 if (!mFastWriteScheduled) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003025 mWriteScheduled = true;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08003026 mFastWriteScheduled = true;
3027 mHandler.removeCallbacks(mWriteRunner);
3028 mHandler.postDelayed(mWriteRunner, 10*1000);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003029 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003030 }
3031
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07003032 /**
3033 * Get the state of an op for a uid.
3034 *
3035 * @param code The code of the op
3036 * @param uid The uid the of the package
3037 * @param packageName The package name for which to get the state for
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003038 * @param isPrivileged Whether the package is privileged or not (only used if {@code edit
3039 * == true})
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07003040 * @param edit Iff {@code true} create the {@link Op} object if not yet created
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07003041 *
3042 * @return The {@link Op state} of the op
3043 */
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003044 private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
3045 boolean isPrivileged, boolean edit) {
3046 Ops ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
Dianne Hackborn72e39832013-01-18 18:36:09 -08003047 if (ops == null) {
3048 return null;
3049 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003050 return getOpLocked(ops, code, edit);
3051 }
3052
3053 private Op getOpLocked(Ops ops, int code, boolean edit) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003054 Op op = ops.get(code);
3055 if (op == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08003056 if (!edit) {
3057 return null;
3058 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003059 op = new Op(ops.uidState, ops.packageName, code);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003060 ops.put(code, op);
3061 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003062 if (edit) {
3063 scheduleWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08003064 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003065 return op;
3066 }
3067
Suprabh Shukla7e017922019-08-05 17:13:23 -07003068 private boolean isOpRestrictedDueToSuspend(int code, String packageName, int uid) {
Suprabh Shuklab614a222019-09-12 14:42:46 -07003069 if (!ArrayUtils.contains(OPS_RESTRICTED_ON_SUSPEND, code)) {
3070 return false;
3071 }
Suprabh Shukla7e017922019-08-05 17:13:23 -07003072 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Suprabh Shuklab614a222019-09-12 14:42:46 -07003073 return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid));
Suprabh Shukla7e017922019-08-05 17:13:23 -07003074 }
3075
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003076 private boolean isOpRestrictedLocked(int uid, int code, String packageName,
3077 boolean isPrivileged) {
Jason Monk62062992014-05-06 09:55:28 -04003078 int userHandle = UserHandle.getUserId(uid);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003079 final int restrictionSetCount = mOpUserRestrictions.size();
Ruben Brunk29931bc2016-03-11 00:24:26 -08003080
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003081 for (int i = 0; i < restrictionSetCount; i++) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08003082 // For each client, check that the given op is not restricted, or that the given
3083 // package is exempt from the restriction.
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003084 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07003085 if (restrictionState.hasRestriction(code, packageName, userHandle)) {
3086 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
3087 // If we are the system, bypass user restrictions for certain codes
3088 synchronized (this) {
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003089 Ops ops = getOpsRawLocked(uid, packageName, isPrivileged,
3090 true /* edit */);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07003091 if ((ops != null) && ops.isPrivileged) {
3092 return false;
3093 }
Ruben Brunk32f0fa42016-03-11 19:07:07 -08003094 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08003095 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003096 return true;
Jason Monk1c7c3192014-06-26 12:52:18 -04003097 }
Jason Monk62062992014-05-06 09:55:28 -04003098 }
3099 return false;
3100 }
3101
Dianne Hackborn35654b62013-01-14 17:38:02 -08003102 void readState() {
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003103 int oldVersion = NO_VERSION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08003104 synchronized (mFile) {
3105 synchronized (this) {
3106 FileInputStream stream;
3107 try {
3108 stream = mFile.openRead();
3109 } catch (FileNotFoundException e) {
3110 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
3111 return;
3112 }
3113 boolean success = false;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003114 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08003115 try {
3116 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01003117 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08003118 int type;
3119 while ((type = parser.next()) != XmlPullParser.START_TAG
3120 && type != XmlPullParser.END_DOCUMENT) {
3121 ;
3122 }
3123
3124 if (type != XmlPullParser.START_TAG) {
3125 throw new IllegalStateException("no start tag found");
3126 }
3127
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003128 final String versionString = parser.getAttributeValue(null, "v");
3129 if (versionString != null) {
3130 oldVersion = Integer.parseInt(versionString);
3131 }
3132
Dianne Hackborn35654b62013-01-14 17:38:02 -08003133 int outerDepth = parser.getDepth();
3134 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3135 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
3136 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3137 continue;
3138 }
3139
3140 String tagName = parser.getName();
3141 if (tagName.equals("pkg")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00003142 readPackage(parser);
Svetoslav215b44a2015-08-04 19:03:40 -07003143 } else if (tagName.equals("uid")) {
Svet Ganov2af57082015-07-30 08:44:20 -07003144 readUidOps(parser);
Dianne Hackborn35654b62013-01-14 17:38:02 -08003145 } else {
3146 Slog.w(TAG, "Unknown element under <app-ops>: "
3147 + parser.getName());
3148 XmlUtils.skipCurrentTag(parser);
3149 }
3150 }
3151 success = true;
3152 } catch (IllegalStateException e) {
3153 Slog.w(TAG, "Failed parsing " + e);
3154 } catch (NullPointerException e) {
3155 Slog.w(TAG, "Failed parsing " + e);
3156 } catch (NumberFormatException e) {
3157 Slog.w(TAG, "Failed parsing " + e);
3158 } catch (XmlPullParserException e) {
3159 Slog.w(TAG, "Failed parsing " + e);
3160 } catch (IOException e) {
3161 Slog.w(TAG, "Failed parsing " + e);
3162 } catch (IndexOutOfBoundsException e) {
3163 Slog.w(TAG, "Failed parsing " + e);
3164 } finally {
3165 if (!success) {
Svet Ganov2af57082015-07-30 08:44:20 -07003166 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08003167 }
3168 try {
3169 stream.close();
3170 } catch (IOException e) {
3171 }
3172 }
3173 }
3174 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003175 synchronized (this) {
3176 upgradeLocked(oldVersion);
3177 }
3178 }
3179
3180 private void upgradeRunAnyInBackgroundLocked() {
3181 for (int i = 0; i < mUidStates.size(); i++) {
3182 final UidState uidState = mUidStates.valueAt(i);
3183 if (uidState == null) {
3184 continue;
3185 }
Hai Zhang93540ca2019-09-28 00:04:18 +00003186 if (uidState.opModes != null) {
3187 final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
3188 if (idx >= 0) {
3189 uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
3190 uidState.opModes.valueAt(idx));
3191 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003192 }
3193 if (uidState.pkgOps == null) {
3194 continue;
3195 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003196 boolean changed = false;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003197 for (int j = 0; j < uidState.pkgOps.size(); j++) {
3198 Ops ops = uidState.pkgOps.valueAt(j);
3199 if (ops != null) {
3200 final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
3201 if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003202 final Op copy = new Op(op.uidState, op.packageName,
Svet Ganovaf189e32019-02-15 18:45:29 -08003203 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003204 copy.mode = op.mode;
3205 ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003206 changed = true;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003207 }
3208 }
3209 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003210 if (changed) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003211 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003212 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003213 }
3214 }
3215
3216 private void upgradeLocked(int oldVersion) {
3217 if (oldVersion >= CURRENT_VERSION) {
3218 return;
3219 }
3220 Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
3221 switch (oldVersion) {
3222 case NO_VERSION:
3223 upgradeRunAnyInBackgroundLocked();
3224 // fall through
3225 case 1:
3226 // for future upgrades
3227 }
3228 scheduleFastWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08003229 }
3230
Svet Ganovaf189e32019-02-15 18:45:29 -08003231 private void readUidOps(XmlPullParser parser) throws NumberFormatException,
Svet Ganov2af57082015-07-30 08:44:20 -07003232 XmlPullParserException, IOException {
3233 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
3234 int outerDepth = parser.getDepth();
3235 int type;
3236 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3237 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
3238 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3239 continue;
3240 }
3241
3242 String tagName = parser.getName();
3243 if (tagName.equals("op")) {
3244 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
3245 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
3246 UidState uidState = getUidStateLocked(uid, true);
Hai Zhang93540ca2019-09-28 00:04:18 +00003247 if (uidState.opModes == null) {
3248 uidState.opModes = new SparseIntArray();
3249 }
3250 uidState.opModes.put(code, mode);
Svet Ganov2af57082015-07-30 08:44:20 -07003251 } else {
3252 Slog.w(TAG, "Unknown element under <uid-ops>: "
3253 + parser.getName());
3254 XmlUtils.skipCurrentTag(parser);
3255 }
3256 }
3257 }
3258
Svet Ganovaf189e32019-02-15 18:45:29 -08003259 private void readPackage(XmlPullParser parser)
3260 throws NumberFormatException, XmlPullParserException, IOException {
Dianne Hackborn35654b62013-01-14 17:38:02 -08003261 String pkgName = parser.getAttributeValue(null, "n");
3262 int outerDepth = parser.getDepth();
3263 int type;
3264 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3265 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
3266 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3267 continue;
3268 }
3269
3270 String tagName = parser.getName();
3271 if (tagName.equals("uid")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00003272 readUid(parser, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08003273 } else {
3274 Slog.w(TAG, "Unknown element under <pkg>: "
3275 + parser.getName());
3276 XmlUtils.skipCurrentTag(parser);
3277 }
3278 }
3279 }
3280
Svet Ganovaf189e32019-02-15 18:45:29 -08003281 private void readUid(XmlPullParser parser, String pkgName)
3282 throws NumberFormatException, XmlPullParserException, IOException {
Dianne Hackborn35654b62013-01-14 17:38:02 -08003283 int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
Svet Ganovaf189e32019-02-15 18:45:29 -08003284 final UidState uidState = getUidStateLocked(uid, true);
Jason Monk1c7c3192014-06-26 12:52:18 -04003285 String isPrivilegedString = parser.getAttributeValue(null, "p");
3286 boolean isPrivileged = false;
3287 if (isPrivilegedString == null) {
3288 try {
3289 IPackageManager packageManager = ActivityThread.getPackageManager();
3290 if (packageManager != null) {
3291 ApplicationInfo appInfo = ActivityThread.getPackageManager()
3292 .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
3293 if (appInfo != null) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08003294 isPrivileged = (appInfo.privateFlags
3295 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04003296 }
3297 } else {
3298 // Could not load data, don't add to cache so it will be loaded later.
3299 return;
3300 }
3301 } catch (RemoteException e) {
3302 Slog.w(TAG, "Could not contact PackageManager", e);
3303 }
3304 } else {
3305 isPrivileged = Boolean.parseBoolean(isPrivilegedString);
3306 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08003307 int outerDepth = parser.getDepth();
3308 int type;
3309 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3310 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
3311 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3312 continue;
3313 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08003314 String tagName = parser.getName();
3315 if (tagName.equals("op")) {
Svet Ganovaf189e32019-02-15 18:45:29 -08003316 readOp(parser, uidState, pkgName, isPrivileged);
Dianne Hackborn35654b62013-01-14 17:38:02 -08003317 } else {
3318 Slog.w(TAG, "Unknown element under <pkg>: "
3319 + parser.getName());
3320 XmlUtils.skipCurrentTag(parser);
3321 }
3322 }
Svet Ganovaf189e32019-02-15 18:45:29 -08003323 uidState.evalForegroundOps(mOpModeWatchers);
3324 }
3325
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003326 private void readFeatureOp(XmlPullParser parser, @NonNull Op parent,
3327 @Nullable String feature) throws NumberFormatException, IOException {
3328 final FeatureOp featureOp = parent.getOrCreateFeature(parent, feature);
3329
3330 final long key = XmlUtils.readLongAttribute(parser, "n");
3331
3332 final int flags = AppOpsManager.extractFlagsFromKey(key);
3333 final int state = AppOpsManager.extractUidStateFromKey(key);
3334
3335 final long accessTime = XmlUtils.readLongAttribute(parser, "t", 0);
3336 final long rejectTime = XmlUtils.readLongAttribute(parser, "r", 0);
3337 final long accessDuration = XmlUtils.readLongAttribute(parser, "d", 0);
3338 final String proxyPkg = XmlUtils.readStringAttribute(parser, "pp");
3339 final int proxyUid = XmlUtils.readIntAttribute(parser, "pu", 0);
3340 final String proxyFeatureId = XmlUtils.readStringAttribute(parser, "pc");
3341
3342 if (accessTime > 0) {
3343 featureOp.accessed(accessTime, proxyUid, proxyPkg, proxyFeatureId, state, flags);
3344 }
3345 if (rejectTime > 0) {
3346 featureOp.rejected(rejectTime, proxyUid, proxyPkg, proxyFeatureId, state, flags);
3347 }
3348 if (accessDuration > 0) {
3349 featureOp.running(accessTime, accessDuration, state, flags);
3350 }
3351 }
3352
Svet Ganovaf189e32019-02-15 18:45:29 -08003353 private void readOp(XmlPullParser parser, @NonNull UidState uidState,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003354 @NonNull String pkgName, boolean isPrivileged) throws NumberFormatException,
3355 XmlPullParserException, IOException {
Svet Ganovaf189e32019-02-15 18:45:29 -08003356 Op op = new Op(uidState, pkgName,
3357 Integer.parseInt(parser.getAttributeValue(null, "n")));
3358
3359 final int mode = XmlUtils.readIntAttribute(parser, "m",
3360 AppOpsManager.opToDefaultMode(op.op));
3361 op.mode = mode;
3362
3363 int outerDepth = parser.getDepth();
3364 int type;
3365 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3366 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
3367 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3368 continue;
3369 }
3370 String tagName = parser.getName();
3371 if (tagName.equals("st")) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003372 readFeatureOp(parser, op, XmlUtils.readStringAttribute(parser, "id"));
Svet Ganovaf189e32019-02-15 18:45:29 -08003373 } else {
3374 Slog.w(TAG, "Unknown element under <op>: "
3375 + parser.getName());
3376 XmlUtils.skipCurrentTag(parser);
3377 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003378 }
Svet Ganovaf189e32019-02-15 18:45:29 -08003379
3380 if (uidState.pkgOps == null) {
3381 uidState.pkgOps = new ArrayMap<>();
3382 }
3383 Ops ops = uidState.pkgOps.get(pkgName);
3384 if (ops == null) {
3385 ops = new Ops(pkgName, uidState, isPrivileged);
3386 uidState.pkgOps.put(pkgName, ops);
3387 }
3388 ops.put(op.op, op);
Dianne Hackborn35654b62013-01-14 17:38:02 -08003389 }
3390
3391 void writeState() {
3392 synchronized (mFile) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08003393 FileOutputStream stream;
3394 try {
3395 stream = mFile.startWrite();
3396 } catch (IOException e) {
3397 Slog.w(TAG, "Failed to write state: " + e);
3398 return;
3399 }
3400
Dianne Hackborne17b4452018-01-10 13:15:40 -08003401 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
3402
Dianne Hackborn35654b62013-01-14 17:38:02 -08003403 try {
3404 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01003405 out.setOutput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08003406 out.startDocument(null, true);
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003407 out.startTag(null, "app-ops");
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003408 out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
Svet Ganov2af57082015-07-30 08:44:20 -07003409
Hai Zhang93540ca2019-09-28 00:04:18 +00003410 SparseArray<SparseIntArray> uidStatesClone;
Eugene Susla463d5922019-07-17 18:14:15 -07003411 synchronized (this) {
Hai Zhang93540ca2019-09-28 00:04:18 +00003412 uidStatesClone = new SparseArray<>(mUidStates.size());
3413
3414 final int uidStateCount = mUidStates.size();
3415 for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
3416 UidState uidState = mUidStates.valueAt(uidStateNum);
3417 int uid = mUidStates.keyAt(uidStateNum);
3418
3419 SparseIntArray opModes = uidState.opModes;
3420 if (opModes != null && opModes.size() > 0) {
3421 uidStatesClone.put(uid, new SparseIntArray(opModes.size()));
3422
3423 final int opCount = opModes.size();
3424 for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
3425 uidStatesClone.get(uid).put(
3426 opModes.keyAt(opCountNum),
3427 opModes.valueAt(opCountNum));
3428 }
Svet Ganov2af57082015-07-30 08:44:20 -07003429 }
Svet Ganov2af57082015-07-30 08:44:20 -07003430 }
3431 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08003432
Hai Zhang93540ca2019-09-28 00:04:18 +00003433 final int uidStateCount = uidStatesClone.size();
3434 for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
3435 SparseIntArray opModes = uidStatesClone.valueAt(uidStateNum);
3436 if (opModes != null && opModes.size() > 0) {
3437 out.startTag(null, "uid");
3438 out.attribute(null, "n",
3439 Integer.toString(uidStatesClone.keyAt(uidStateNum)));
3440 final int opCount = opModes.size();
3441 for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
3442 final int op = opModes.keyAt(opCountNum);
3443 final int mode = opModes.valueAt(opCountNum);
3444 out.startTag(null, "op");
3445 out.attribute(null, "n", Integer.toString(op));
3446 out.attribute(null, "m", Integer.toString(mode));
3447 out.endTag(null, "op");
3448 }
3449 out.endTag(null, "uid");
Eugene Susla11b706c2019-08-28 14:28:32 -07003450 }
3451 }
3452
Dianne Hackborn35654b62013-01-14 17:38:02 -08003453 if (allOps != null) {
3454 String lastPkg = null;
3455 for (int i=0; i<allOps.size(); i++) {
3456 AppOpsManager.PackageOps pkg = allOps.get(i);
3457 if (!pkg.getPackageName().equals(lastPkg)) {
3458 if (lastPkg != null) {
3459 out.endTag(null, "pkg");
3460 }
3461 lastPkg = pkg.getPackageName();
3462 out.startTag(null, "pkg");
3463 out.attribute(null, "n", lastPkg);
3464 }
3465 out.startTag(null, "uid");
3466 out.attribute(null, "n", Integer.toString(pkg.getUid()));
Jason Monk1c7c3192014-06-26 12:52:18 -04003467 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07003468 Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003469 false /* isPrivileged */, false /* edit */);
Jason Monk1c7c3192014-06-26 12:52:18 -04003470 // Should always be present as the list of PackageOps is generated
3471 // from Ops.
3472 if (ops != null) {
3473 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
3474 } else {
3475 out.attribute(null, "p", Boolean.toString(false));
3476 }
3477 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08003478 List<AppOpsManager.OpEntry> ops = pkg.getOps();
3479 for (int j=0; j<ops.size(); j++) {
3480 AppOpsManager.OpEntry op = ops.get(j);
3481 out.startTag(null, "op");
3482 out.attribute(null, "n", Integer.toString(op.getOp()));
David Braunf5d83192013-09-16 13:43:51 -07003483 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003484 out.attribute(null, "m", Integer.toString(op.getMode()));
3485 }
Svet Ganovaf189e32019-02-15 18:45:29 -08003486
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003487 for (String featureId : op.getFeatures().keySet()) {
3488 final OpFeatureEntry feature = op.getFeatures().get(
3489 featureId);
Svet Ganovaf189e32019-02-15 18:45:29 -08003490
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003491 final LongSparseArray keys = feature.collectKeys();
3492 if (keys == null || keys.size() <= 0) {
Svet Ganovaf189e32019-02-15 18:45:29 -08003493 continue;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003494 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003495 final int keyCount = keys.size();
Svet Ganovaf189e32019-02-15 18:45:29 -08003496
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003497 for (int k = 0; k < keyCount; k++) {
3498 final long key = keys.keyAt(k);
3499
3500 final int uidState = AppOpsManager.extractUidStateFromKey(key);
3501 final int flags = AppOpsManager.extractFlagsFromKey(key);
3502
3503 final long accessTime = feature.getLastAccessTime(
3504 uidState, uidState, flags);
3505 final long rejectTime = feature.getLastRejectTime(
3506 uidState, uidState, flags);
3507 final long accessDuration = feature.getLastDuration(
3508 uidState, uidState, flags);
3509 final String proxyPkg = feature.getProxyPackageName(uidState,
3510 flags);
3511 final String proxyFeatureId = feature.getProxyFeatureId(
3512 uidState, flags);
3513 final int proxyUid = feature.getProxyUid(uidState, flags);
3514
3515 if (accessTime <= 0 && rejectTime <= 0 && accessDuration <= 0
3516 && proxyPkg == null && proxyUid < 0) {
3517 continue;
3518 }
3519
3520 out.startTag(null, "st");
3521 if (featureId != null) {
3522 out.attribute(null, "id", featureId);
3523 }
3524 out.attribute(null, "n", Long.toString(key));
3525 if (accessTime > 0) {
3526 out.attribute(null, "t", Long.toString(accessTime));
3527 }
3528 if (rejectTime > 0) {
3529 out.attribute(null, "r", Long.toString(rejectTime));
3530 }
3531 if (accessDuration > 0) {
3532 out.attribute(null, "d", Long.toString(accessDuration));
3533 }
3534 if (proxyPkg != null) {
3535 out.attribute(null, "pp", proxyPkg);
3536 }
3537 if (proxyFeatureId != null) {
3538 out.attribute(null, "pc", proxyFeatureId);
3539 }
3540 if (proxyUid >= 0) {
3541 out.attribute(null, "pu", Integer.toString(proxyUid));
3542 }
3543 out.endTag(null, "st");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003544 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003545 }
Svet Ganovaf189e32019-02-15 18:45:29 -08003546
Dianne Hackborn35654b62013-01-14 17:38:02 -08003547 out.endTag(null, "op");
3548 }
3549 out.endTag(null, "uid");
3550 }
3551 if (lastPkg != null) {
3552 out.endTag(null, "pkg");
3553 }
3554 }
3555
3556 out.endTag(null, "app-ops");
3557 out.endDocument();
3558 mFile.finishWrite(stream);
3559 } catch (IOException e) {
3560 Slog.w(TAG, "Failed to write state, restoring backup.", e);
3561 mFile.failWrite(stream);
3562 }
3563 }
3564 }
3565
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003566 static class Shell extends ShellCommand {
3567 final IAppOpsService mInterface;
3568 final AppOpsService mInternal;
3569
3570 int userId = UserHandle.USER_SYSTEM;
3571 String packageName;
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003572 String featureId;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003573 String opStr;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07003574 String modeStr;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003575 int op;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07003576 int mode;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003577 int packageUid;
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003578 int nonpackageUid;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05003579 final static Binder sBinder = new Binder();
3580 IBinder mToken;
Svet Ganovd563e932019-04-14 13:07:41 -07003581 boolean targetsUid;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003582
3583 Shell(IAppOpsService iface, AppOpsService internal) {
3584 mInterface = iface;
3585 mInternal = internal;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05003586 try {
3587 mToken = mInterface.getToken(sBinder);
3588 } catch (RemoteException e) {
3589 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003590 }
3591
3592 @Override
3593 public int onCommand(String cmd) {
3594 return onShellCommand(this, cmd);
3595 }
3596
3597 @Override
3598 public void onHelp() {
3599 PrintWriter pw = getOutPrintWriter();
3600 dumpCommandHelp(pw);
3601 }
3602
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003603 static private int strOpToOp(String op, PrintWriter err) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003604 try {
3605 return AppOpsManager.strOpToOp(op);
3606 } catch (IllegalArgumentException e) {
3607 }
3608 try {
3609 return Integer.parseInt(op);
3610 } catch (NumberFormatException e) {
3611 }
3612 try {
3613 return AppOpsManager.strDebugOpToOp(op);
3614 } catch (IllegalArgumentException e) {
3615 err.println("Error: " + e.getMessage());
3616 return -1;
3617 }
3618 }
3619
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003620 static int strModeToMode(String modeStr, PrintWriter err) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003621 for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
3622 if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003623 return i;
3624 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07003625 }
3626 try {
3627 return Integer.parseInt(modeStr);
3628 } catch (NumberFormatException e) {
3629 }
3630 err.println("Error: Mode " + modeStr + " is not valid");
3631 return -1;
3632 }
3633
3634 int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
3635 userId = UserHandle.USER_CURRENT;
3636 opStr = null;
3637 modeStr = null;
3638 for (String argument; (argument = getNextArg()) != null;) {
3639 if ("--user".equals(argument)) {
3640 userId = UserHandle.parseUserArg(getNextArgRequired());
3641 } else {
3642 if (opStr == null) {
3643 opStr = argument;
3644 } else if (modeStr == null) {
3645 modeStr = argument;
3646 break;
3647 }
3648 }
3649 }
3650 if (opStr == null) {
3651 err.println("Error: Operation not specified.");
3652 return -1;
3653 }
3654 op = strOpToOp(opStr, err);
3655 if (op < 0) {
3656 return -1;
3657 }
3658 if (modeStr != null) {
3659 if ((mode=strModeToMode(modeStr, err)) < 0) {
3660 return -1;
3661 }
3662 } else {
3663 mode = defMode;
3664 }
3665 return 0;
3666 }
3667
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003668 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
3669 userId = UserHandle.USER_CURRENT;
3670 packageName = null;
3671 opStr = null;
3672 for (String argument; (argument = getNextArg()) != null;) {
3673 if ("--user".equals(argument)) {
3674 userId = UserHandle.parseUserArg(getNextArgRequired());
Svet Ganovd563e932019-04-14 13:07:41 -07003675 } else if ("--uid".equals(argument)) {
3676 targetsUid = true;
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003677 } else if ("--feature".equals(argument)) {
3678 featureId = getNextArgRequired();
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003679 } else {
3680 if (packageName == null) {
3681 packageName = argument;
3682 } else if (opStr == null) {
3683 opStr = argument;
3684 break;
3685 }
3686 }
3687 }
3688 if (packageName == null) {
3689 err.println("Error: Package name not specified.");
3690 return -1;
3691 } else if (opStr == null && reqOp) {
3692 err.println("Error: Operation not specified.");
3693 return -1;
3694 }
3695 if (opStr != null) {
3696 op = strOpToOp(opStr, err);
3697 if (op < 0) {
3698 return -1;
3699 }
3700 } else {
3701 op = AppOpsManager.OP_NONE;
3702 }
3703 if (userId == UserHandle.USER_CURRENT) {
3704 userId = ActivityManager.getCurrentUser();
3705 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003706 nonpackageUid = -1;
3707 try {
3708 nonpackageUid = Integer.parseInt(packageName);
3709 } catch (NumberFormatException e) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003710 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003711 if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
3712 && packageName.indexOf('.') < 0) {
3713 int i = 1;
3714 while (i < packageName.length() && packageName.charAt(i) >= '0'
3715 && packageName.charAt(i) <= '9') {
3716 i++;
3717 }
3718 if (i > 1 && i < packageName.length()) {
3719 String userStr = packageName.substring(1, i);
3720 try {
3721 int user = Integer.parseInt(userStr);
3722 char type = packageName.charAt(i);
3723 i++;
3724 int startTypeVal = i;
3725 while (i < packageName.length() && packageName.charAt(i) >= '0'
3726 && packageName.charAt(i) <= '9') {
3727 i++;
3728 }
3729 if (i > startTypeVal) {
3730 String typeValStr = packageName.substring(startTypeVal, i);
3731 try {
3732 int typeVal = Integer.parseInt(typeValStr);
3733 if (type == 'a') {
3734 nonpackageUid = UserHandle.getUid(user,
3735 typeVal + Process.FIRST_APPLICATION_UID);
3736 } else if (type == 's') {
3737 nonpackageUid = UserHandle.getUid(user, typeVal);
3738 }
3739 } catch (NumberFormatException e) {
3740 }
3741 }
3742 } catch (NumberFormatException e) {
3743 }
3744 }
3745 }
3746 if (nonpackageUid != -1) {
3747 packageName = null;
3748 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08003749 packageUid = resolveUid(packageName);
3750 if (packageUid < 0) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003751 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
3752 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
3753 }
3754 if (packageUid < 0) {
3755 err.println("Error: No UID for " + packageName + " in user " + userId);
3756 return -1;
3757 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003758 }
3759 return 0;
3760 }
3761 }
3762
3763 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07003764 FileDescriptor err, String[] args, ShellCallback callback,
3765 ResultReceiver resultReceiver) {
3766 (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003767 }
3768
3769 static void dumpCommandHelp(PrintWriter pw) {
3770 pw.println("AppOps service (appops) commands:");
3771 pw.println(" help");
3772 pw.println(" Print this help text.");
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003773 pw.println(" start [--user <USER_ID>] [--feature <FEATURE_ID>] <PACKAGE | UID> <OP> ");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05003774 pw.println(" Starts a given operation for a particular application.");
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003775 pw.println(" stop [--user <USER_ID>] [--feature <FEATURE_ID>] <PACKAGE | UID> <OP> ");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05003776 pw.println(" Stops a given operation for a particular application.");
Svet Ganovb687fad2019-04-30 17:32:44 -07003777 pw.println(" set [--user <USER_ID>] <[--uid] PACKAGE | UID> <OP> <MODE>");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003778 pw.println(" Set the mode for a particular application and operation.");
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003779 pw.println(" get [--user <USER_ID>] [--feature <FEATURE_ID>] <PACKAGE | UID> [<OP>]");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003780 pw.println(" Return the mode for a particular application and optional operation.");
Dianne Hackborne91f3e72016-03-25 18:48:15 -07003781 pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
3782 pw.println(" Print all packages that currently have the given op in the given mode.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003783 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
3784 pw.println(" Reset the given application or all applications to default modes.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003785 pw.println(" write-settings");
3786 pw.println(" Immediately write pending changes to storage.");
3787 pw.println(" read-settings");
3788 pw.println(" Read the last written settings, replacing current state in RAM.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003789 pw.println(" options:");
Svet Ganovb687fad2019-04-30 17:32:44 -07003790 pw.println(" <PACKAGE> an Android package name or its UID if prefixed by --uid");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003791 pw.println(" <OP> an AppOps operation.");
3792 pw.println(" <MODE> one of allow, ignore, deny, or default");
3793 pw.println(" <USER_ID> the user id under which the package is installed. If --user is not");
3794 pw.println(" specified, the current user is assumed.");
3795 }
3796
3797 static int onShellCommand(Shell shell, String cmd) {
3798 if (cmd == null) {
3799 return shell.handleDefaultCommands(cmd);
3800 }
3801 PrintWriter pw = shell.getOutPrintWriter();
3802 PrintWriter err = shell.getErrPrintWriter();
3803 try {
3804 switch (cmd) {
3805 case "set": {
3806 int res = shell.parseUserPackageOp(true, err);
3807 if (res < 0) {
3808 return res;
3809 }
3810 String modeStr = shell.getNextArg();
3811 if (modeStr == null) {
3812 err.println("Error: Mode not specified.");
3813 return -1;
3814 }
3815
Dianne Hackborne91f3e72016-03-25 18:48:15 -07003816 final int mode = shell.strModeToMode(modeStr, err);
3817 if (mode < 0) {
3818 return -1;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003819 }
3820
Svet Ganovd563e932019-04-14 13:07:41 -07003821 if (!shell.targetsUid && shell.packageName != null) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003822 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
3823 mode);
Svet Ganovd563e932019-04-14 13:07:41 -07003824 } else if (shell.targetsUid && shell.packageName != null) {
3825 try {
3826 final int uid = shell.mInternal.mContext.getPackageManager()
3827 .getPackageUid(shell.packageName, shell.userId);
3828 shell.mInterface.setUidMode(shell.op, uid, mode);
3829 } catch (PackageManager.NameNotFoundException e) {
3830 return -1;
3831 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003832 } else {
3833 shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
3834 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003835 return 0;
3836 }
3837 case "get": {
3838 int res = shell.parseUserPackageOp(false, err);
3839 if (res < 0) {
3840 return res;
3841 }
3842
Eugene Suslae4ee2c22018-11-05 12:23:30 -08003843 List<AppOpsManager.PackageOps> ops = new ArrayList<>();
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003844 if (shell.packageName != null) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08003845 // Uid mode overrides package mode, so make sure it's also reported
3846 List<AppOpsManager.PackageOps> r = shell.mInterface.getUidOps(
3847 shell.packageUid,
3848 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
3849 if (r != null) {
3850 ops.addAll(r);
3851 }
3852 r = shell.mInterface.getOpsForPackage(
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003853 shell.packageUid, shell.packageName,
3854 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
Eugene Suslae4ee2c22018-11-05 12:23:30 -08003855 if (r != null) {
3856 ops.addAll(r);
3857 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003858 } else {
3859 ops = shell.mInterface.getUidOps(
3860 shell.nonpackageUid,
3861 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
3862 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003863 if (ops == null || ops.size() <= 0) {
3864 pw.println("No operations.");
Svet Ganov82f09bc2018-01-12 22:08:40 -08003865 if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003866 pw.println("Default mode: " + AppOpsManager.modeToName(
Svet Ganov82f09bc2018-01-12 22:08:40 -08003867 AppOpsManager.opToDefaultMode(shell.op)));
3868 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003869 return 0;
3870 }
3871 final long now = System.currentTimeMillis();
3872 for (int i=0; i<ops.size(); i++) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08003873 AppOpsManager.PackageOps packageOps = ops.get(i);
3874 if (packageOps.getPackageName() == null) {
3875 pw.print("Uid mode: ");
3876 }
3877 List<AppOpsManager.OpEntry> entries = packageOps.getOps();
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003878 for (int j=0; j<entries.size(); j++) {
3879 AppOpsManager.OpEntry ent = entries.get(j);
3880 pw.print(AppOpsManager.opToName(ent.getOp()));
3881 pw.print(": ");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003882 pw.print(AppOpsManager.modeToName(ent.getMode()));
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003883 if (shell.featureId == null) {
3884 if (ent.getTime() != 0) {
3885 pw.print("; time=");
3886 TimeUtils.formatDuration(now - ent.getTime(), pw);
3887 pw.print(" ago");
3888 }
3889 if (ent.getRejectTime() != 0) {
3890 pw.print("; rejectTime=");
3891 TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
3892 pw.print(" ago");
3893 }
3894 if (ent.getDuration() == -1) {
3895 pw.print(" (running)");
3896 } else if (ent.getDuration() != 0) {
3897 pw.print("; duration=");
3898 TimeUtils.formatDuration(ent.getDuration(), pw);
3899 }
3900 } else {
3901 final OpFeatureEntry featureEnt = ent.getFeatures().get(
3902 shell.featureId);
3903 if (featureEnt != null) {
3904 if (featureEnt.getTime() != 0) {
3905 pw.print("; time=");
3906 TimeUtils.formatDuration(now - featureEnt.getTime(), pw);
3907 pw.print(" ago");
3908 }
3909 if (featureEnt.getRejectTime() != 0) {
3910 pw.print("; rejectTime=");
3911 TimeUtils.formatDuration(now - featureEnt.getRejectTime(),
3912 pw);
3913 pw.print(" ago");
3914 }
3915 if (featureEnt.getDuration() == -1) {
3916 pw.print(" (running)");
3917 } else if (featureEnt.getDuration() != 0) {
3918 pw.print("; duration=");
3919 TimeUtils.formatDuration(featureEnt.getDuration(), pw);
3920 }
3921 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003922 }
3923 pw.println();
3924 }
3925 }
3926 return 0;
3927 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07003928 case "query-op": {
3929 int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
3930 if (res < 0) {
3931 return res;
3932 }
3933 List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
3934 new int[] {shell.op});
3935 if (ops == null || ops.size() <= 0) {
3936 pw.println("No operations.");
3937 return 0;
3938 }
3939 for (int i=0; i<ops.size(); i++) {
3940 final AppOpsManager.PackageOps pkg = ops.get(i);
3941 boolean hasMatch = false;
3942 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
3943 for (int j=0; j<entries.size(); j++) {
3944 AppOpsManager.OpEntry ent = entries.get(j);
3945 if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
3946 hasMatch = true;
3947 break;
3948 }
3949 }
3950 if (hasMatch) {
3951 pw.println(pkg.getPackageName());
3952 }
3953 }
3954 return 0;
3955 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003956 case "reset": {
3957 String packageName = null;
3958 int userId = UserHandle.USER_CURRENT;
3959 for (String argument; (argument = shell.getNextArg()) != null;) {
3960 if ("--user".equals(argument)) {
3961 String userStr = shell.getNextArgRequired();
3962 userId = UserHandle.parseUserArg(userStr);
3963 } else {
3964 if (packageName == null) {
3965 packageName = argument;
3966 } else {
3967 err.println("Error: Unsupported argument: " + argument);
3968 return -1;
3969 }
3970 }
3971 }
3972
3973 if (userId == UserHandle.USER_CURRENT) {
3974 userId = ActivityManager.getCurrentUser();
3975 }
3976
3977 shell.mInterface.resetAllModes(userId, packageName);
3978 pw.print("Reset all modes for: ");
3979 if (userId == UserHandle.USER_ALL) {
3980 pw.print("all users");
3981 } else {
3982 pw.print("user "); pw.print(userId);
3983 }
3984 pw.print(", ");
3985 if (packageName == null) {
3986 pw.println("all packages");
3987 } else {
3988 pw.print("package "); pw.println(packageName);
3989 }
3990 return 0;
3991 }
3992 case "write-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07003993 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
3994 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003995 long token = Binder.clearCallingIdentity();
3996 try {
3997 synchronized (shell.mInternal) {
3998 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
3999 }
4000 shell.mInternal.writeState();
4001 pw.println("Current settings written.");
4002 } finally {
4003 Binder.restoreCallingIdentity(token);
4004 }
4005 return 0;
4006 }
4007 case "read-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07004008 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
4009 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004010 long token = Binder.clearCallingIdentity();
4011 try {
4012 shell.mInternal.readState();
4013 pw.println("Last settings read.");
4014 } finally {
4015 Binder.restoreCallingIdentity(token);
4016 }
4017 return 0;
4018 }
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05004019 case "start": {
4020 int res = shell.parseUserPackageOp(true, err);
4021 if (res < 0) {
4022 return res;
4023 }
4024
4025 if (shell.packageName != null) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004026 shell.mInterface.startOperation(shell.mToken, shell.op, shell.packageUid,
4027 shell.packageName, shell.featureId, true);
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05004028 } else {
4029 return -1;
4030 }
4031 return 0;
4032 }
4033 case "stop": {
4034 int res = shell.parseUserPackageOp(true, err);
4035 if (res < 0) {
4036 return res;
4037 }
4038
4039 if (shell.packageName != null) {
4040 shell.mInterface.finishOperation(shell.mToken,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004041 shell.op, shell.packageUid, shell.packageName, shell.featureId);
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05004042 } else {
4043 return -1;
4044 }
4045 return 0;
4046 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004047 default:
4048 return shell.handleDefaultCommands(cmd);
4049 }
4050 } catch (RemoteException e) {
4051 pw.println("Remote exception: " + e);
4052 }
4053 return -1;
4054 }
4055
4056 private void dumpHelp(PrintWriter pw) {
4057 pw.println("AppOps service (appops) dump options:");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004058 pw.println(" -h");
4059 pw.println(" Print this help text.");
4060 pw.println(" --op [OP]");
4061 pw.println(" Limit output to data associated with the given app op code.");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004062 pw.println(" --mode [MODE]");
4063 pw.println(" Limit output to data associated with the given app op mode.");
4064 pw.println(" --package [PACKAGE]");
4065 pw.println(" Limit output to data associated with the given package name.");
Dianne Hackborn125dc532019-01-09 13:31:48 -08004066 pw.println(" --watchers");
4067 pw.println(" Only output the watcher sections.");
Svet Ganovaf189e32019-02-15 18:45:29 -08004068 pw.println(" --history");
4069 pw.println(" Output the historical data.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07004070 }
4071
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004072 private void dumpStatesLocked(@NonNull PrintWriter pw, long nowElapsed, @NonNull Op op,
Svet Ganovaf189e32019-02-15 18:45:29 -08004073 long now, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004074 final int numFeatures = op.mFeatures.size();
4075 for (int i = 0; i < numFeatures; i++) {
4076 pw.print(prefix + op.mFeatures.keyAt(i) + "=[\n");
4077 dumpStatesLocked(pw, nowElapsed, op, op.mFeatures.keyAt(i), now, sdf, date,
4078 prefix + " ");
4079 pw.print(prefix + "]\n");
4080 }
4081 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004082
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004083 private void dumpStatesLocked(@NonNull PrintWriter pw, long nowElapsed, @NonNull Op op,
4084 @Nullable String featureId, long now, @NonNull SimpleDateFormat sdf,
4085 @NonNull Date date, @NonNull String prefix) {
4086
4087 final OpFeatureEntry entry = op.createSingleFeatureEntryLocked(
4088 featureId).getFeatures().get(featureId);
Svet Ganovaf189e32019-02-15 18:45:29 -08004089
4090 final LongSparseArray keys = entry.collectKeys();
4091 if (keys == null || keys.size() <= 0) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004092 return;
4093 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004094
4095 final int keyCount = keys.size();
4096 for (int k = 0; k < keyCount; k++) {
4097 final long key = keys.keyAt(k);
4098
4099 final int uidState = AppOpsManager.extractUidStateFromKey(key);
4100 final int flags = AppOpsManager.extractFlagsFromKey(key);
4101
4102 final long accessTime = entry.getLastAccessTime(
4103 uidState, uidState, flags);
4104 final long rejectTime = entry.getLastRejectTime(
4105 uidState, uidState, flags);
4106 final long accessDuration = entry.getLastDuration(
4107 uidState, uidState, flags);
4108 final String proxyPkg = entry.getProxyPackageName(uidState, flags);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004109 final String proxyFeatureId = entry.getProxyFeatureId(uidState, flags);
Svet Ganovaf189e32019-02-15 18:45:29 -08004110 final int proxyUid = entry.getProxyUid(uidState, flags);
4111
4112 if (accessTime > 0) {
4113 pw.print(prefix);
4114 pw.print("Access: ");
4115 pw.print(AppOpsManager.keyToString(key));
4116 pw.print(" ");
4117 date.setTime(accessTime);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004118 pw.print(sdf.format(date));
4119 pw.print(" (");
Svet Ganovaf189e32019-02-15 18:45:29 -08004120 TimeUtils.formatDuration(accessTime - now, pw);
4121 pw.print(")");
4122 if (accessDuration > 0) {
4123 pw.print(" duration=");
4124 TimeUtils.formatDuration(accessDuration, pw);
4125 }
4126 if (proxyUid >= 0) {
4127 pw.print(" proxy[");
4128 pw.print("uid=");
4129 pw.print(proxyUid);
4130 pw.print(", pkg=");
4131 pw.print(proxyPkg);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004132 pw.print(", feature=");
4133 pw.print(proxyFeatureId);
Svet Ganovaf189e32019-02-15 18:45:29 -08004134 pw.print("]");
4135 }
4136 pw.println();
4137 }
4138
4139 if (rejectTime > 0) {
4140 pw.print(prefix);
4141 pw.print("Reject: ");
4142 pw.print(AppOpsManager.keyToString(key));
4143 date.setTime(rejectTime);
4144 pw.print(sdf.format(date));
4145 pw.print(" (");
4146 TimeUtils.formatDuration(rejectTime - now, pw);
4147 pw.print(")");
4148 if (proxyUid >= 0) {
4149 pw.print(" proxy[");
4150 pw.print("uid=");
4151 pw.print(proxyUid);
4152 pw.print(", pkg=");
4153 pw.print(proxyPkg);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004154 pw.print(", feature=");
4155 pw.print(proxyFeatureId);
Svet Ganovaf189e32019-02-15 18:45:29 -08004156 pw.print("]");
4157 }
4158 pw.println();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004159 }
4160 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004161
4162 final FeatureOp featureOp = op.mFeatures.get(featureId);
4163 if (featureOp.running) {
4164 pw.print(prefix + "Running start at: ");
4165 TimeUtils.formatDuration(nowElapsed - featureOp.startRealtime, pw);
4166 pw.println();
4167 }
4168 if (featureOp.startNesting != 0) {
4169 pw.print(prefix + "startNesting=");
4170 pw.println(featureOp.startNesting);
4171 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004172 }
4173
Dianne Hackborna06de0f2012-12-11 16:34:47 -08004174 @Override
4175 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06004176 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08004177
Svet Ganov8455ba22019-01-02 13:05:56 -08004178 int dumpOp = OP_NONE;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004179 String dumpPackage = null;
Svet Ganov8455ba22019-01-02 13:05:56 -08004180 int dumpUid = Process.INVALID_UID;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004181 int dumpMode = -1;
Dianne Hackborn125dc532019-01-09 13:31:48 -08004182 boolean dumpWatchers = false;
Svet Ganovaf189e32019-02-15 18:45:29 -08004183 boolean dumpHistory = false;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004184
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07004185 if (args != null) {
4186 for (int i=0; i<args.length; i++) {
4187 String arg = args[i];
4188 if ("-h".equals(arg)) {
4189 dumpHelp(pw);
4190 return;
Tim Kilbourn8f1ea832015-08-26 15:07:37 -07004191 } else if ("-a".equals(arg)) {
4192 // dump all data
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004193 } else if ("--op".equals(arg)) {
4194 i++;
4195 if (i >= args.length) {
4196 pw.println("No argument for --op option");
4197 return;
4198 }
4199 dumpOp = Shell.strOpToOp(args[i], pw);
4200 if (dumpOp < 0) {
4201 return;
4202 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004203 } else if ("--package".equals(arg)) {
4204 i++;
4205 if (i >= args.length) {
4206 pw.println("No argument for --package option");
4207 return;
4208 }
4209 dumpPackage = args[i];
4210 try {
4211 dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
4212 PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
4213 0);
4214 } catch (RemoteException e) {
4215 }
4216 if (dumpUid < 0) {
4217 pw.println("Unknown package: " + dumpPackage);
4218 return;
4219 }
4220 dumpUid = UserHandle.getAppId(dumpUid);
4221 } else if ("--mode".equals(arg)) {
4222 i++;
4223 if (i >= args.length) {
4224 pw.println("No argument for --mode option");
4225 return;
4226 }
4227 dumpMode = Shell.strModeToMode(args[i], pw);
4228 if (dumpMode < 0) {
4229 return;
4230 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08004231 } else if ("--watchers".equals(arg)) {
4232 dumpWatchers = true;
Svet Ganovaf189e32019-02-15 18:45:29 -08004233 } else if ("--history".equals(arg)) {
4234 dumpHistory = true;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07004235 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
4236 pw.println("Unknown option: " + arg);
4237 return;
4238 } else {
4239 pw.println("Unknown command: " + arg);
4240 return;
4241 }
4242 }
4243 }
4244
Dianne Hackborna06de0f2012-12-11 16:34:47 -08004245 synchronized (this) {
4246 pw.println("Current AppOps Service state:");
Svet Ganovaf189e32019-02-15 18:45:29 -08004247 if (!dumpHistory && !dumpWatchers) {
4248 mConstants.dump(pw);
4249 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004250 pw.println();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08004251 final long now = System.currentTimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004252 final long nowElapsed = SystemClock.elapsedRealtime();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004253 final long nowUptime = SystemClock.uptimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004254 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
4255 final Date date = new Date();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004256 boolean needSep = false;
Dianne Hackborn125dc532019-01-09 13:31:48 -08004257 if (dumpOp < 0 && dumpMode < 0 && dumpPackage == null && mProfileOwners != null
Svet Ganovaf189e32019-02-15 18:45:29 -08004258 && !dumpWatchers && !dumpHistory) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07004259 pw.println(" Profile owners:");
4260 for (int poi = 0; poi < mProfileOwners.size(); poi++) {
4261 pw.print(" User #");
4262 pw.print(mProfileOwners.keyAt(poi));
4263 pw.print(": ");
4264 UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
4265 pw.println();
4266 }
4267 pw.println();
4268 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004269 if (mOpModeWatchers.size() > 0 && !dumpHistory) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004270 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004271 for (int i=0; i<mOpModeWatchers.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004272 if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
4273 continue;
4274 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004275 boolean printedOpHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004276 ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004277 for (int j=0; j<callbacks.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004278 final ModeCallback cb = callbacks.valueAt(j);
Dianne Hackborn125dc532019-01-09 13:31:48 -08004279 if (dumpPackage != null
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004280 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
4281 continue;
4282 }
4283 needSep = true;
4284 if (!printedHeader) {
4285 pw.println(" Op mode watchers:");
4286 printedHeader = true;
4287 }
4288 if (!printedOpHeader) {
4289 pw.print(" Op ");
4290 pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
4291 pw.println(":");
4292 printedOpHeader = true;
4293 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004294 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004295 pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004296 }
4297 }
4298 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004299 if (mPackageModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004300 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004301 for (int i=0; i<mPackageModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004302 if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
4303 continue;
4304 }
4305 needSep = true;
4306 if (!printedHeader) {
4307 pw.println(" Package mode watchers:");
4308 printedHeader = true;
4309 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004310 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
4311 pw.println(":");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004312 ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004313 for (int j=0; j<callbacks.size(); j++) {
4314 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn68d76552017-02-27 15:32:03 -08004315 pw.println(callbacks.valueAt(j));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004316 }
4317 }
4318 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004319 if (mModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004320 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004321 for (int i=0; i<mModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004322 final ModeCallback cb = mModeWatchers.valueAt(i);
Dianne Hackborn125dc532019-01-09 13:31:48 -08004323 if (dumpPackage != null
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004324 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
4325 continue;
4326 }
4327 needSep = true;
4328 if (!printedHeader) {
4329 pw.println(" All op mode watchers:");
4330 printedHeader = true;
4331 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07004332 pw.print(" ");
4333 pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004334 pw.print(": "); pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004335 }
4336 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004337 if (mActiveWatchers.size() > 0 && dumpMode < 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004338 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004339 boolean printedHeader = false;
Philip P. Moltmannba136462019-05-21 10:20:38 -07004340 for (int watcherNum = 0; watcherNum < mActiveWatchers.size(); watcherNum++) {
4341 final SparseArray<ActiveCallback> activeWatchers =
4342 mActiveWatchers.valueAt(watcherNum);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004343 if (activeWatchers.size() <= 0) {
4344 continue;
4345 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004346 final ActiveCallback cb = activeWatchers.valueAt(0);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004347 if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
4348 continue;
4349 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08004350 if (dumpPackage != null
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004351 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
4352 continue;
4353 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004354 if (!printedHeader) {
4355 pw.println(" All op active watchers:");
4356 printedHeader = true;
4357 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07004358 pw.print(" ");
4359 pw.print(Integer.toHexString(System.identityHashCode(
Philip P. Moltmannba136462019-05-21 10:20:38 -07004360 mActiveWatchers.keyAt(watcherNum))));
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07004361 pw.println(" ->");
4362 pw.print(" [");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004363 final int opCount = activeWatchers.size();
Philip P. Moltmannba136462019-05-21 10:20:38 -07004364 for (int opNum = 0; opNum < opCount; opNum++) {
4365 if (opNum > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004366 pw.print(' ');
4367 }
Philip P. Moltmannba136462019-05-21 10:20:38 -07004368 pw.print(AppOpsManager.opToName(activeWatchers.keyAt(opNum)));
4369 if (opNum < opCount - 1) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004370 pw.print(',');
4371 }
4372 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07004373 pw.println("]");
4374 pw.print(" ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004375 pw.println(cb);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004376 }
4377 }
Svet Ganovb3d2ae22018-12-17 22:06:15 -08004378 if (mNotedWatchers.size() > 0 && dumpMode < 0) {
4379 needSep = true;
4380 boolean printedHeader = false;
4381 for (int i = 0; i < mNotedWatchers.size(); i++) {
4382 final SparseArray<NotedCallback> notedWatchers = mNotedWatchers.valueAt(i);
4383 if (notedWatchers.size() <= 0) {
4384 continue;
4385 }
4386 final NotedCallback cb = notedWatchers.valueAt(0);
4387 if (dumpOp >= 0 && notedWatchers.indexOfKey(dumpOp) < 0) {
4388 continue;
4389 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08004390 if (dumpPackage != null
Svet Ganovb3d2ae22018-12-17 22:06:15 -08004391 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
4392 continue;
4393 }
4394 if (!printedHeader) {
4395 pw.println(" All op noted watchers:");
4396 printedHeader = true;
4397 }
4398 pw.print(" ");
4399 pw.print(Integer.toHexString(System.identityHashCode(
4400 mNotedWatchers.keyAt(i))));
4401 pw.println(" ->");
4402 pw.print(" [");
4403 final int opCount = notedWatchers.size();
4404 for (i = 0; i < opCount; i++) {
4405 if (i > 0) {
4406 pw.print(' ');
4407 }
4408 pw.print(AppOpsManager.opToName(notedWatchers.keyAt(i)));
4409 if (i < opCount - 1) {
4410 pw.print(',');
4411 }
4412 }
4413 pw.println("]");
4414 pw.print(" ");
4415 pw.println(cb);
4416 }
4417 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004418 if (mClients.size() > 0 && dumpMode < 0 && !dumpWatchers && !dumpHistory) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004419 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004420 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004421 for (int i=0; i<mClients.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004422 boolean printedClient = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004423 ClientState cs = mClients.valueAt(i);
Svet Ganovf7b47252018-02-26 11:11:27 -08004424 if (cs.mStartedOps.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004425 boolean printedStarted = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004426 for (int j=0; j<cs.mStartedOps.size(); j++) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004427 final Pair<Op, String> startedOp = cs.mStartedOps.get(j);
4428 final Op op = startedOp.first;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004429 if (dumpOp >= 0 && op.op != dumpOp) {
4430 continue;
4431 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004432 if (dumpPackage != null && !dumpPackage.equals(op.packageName)) {
4433 continue;
4434 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004435 if (!printedHeader) {
4436 pw.println(" Clients:");
4437 printedHeader = true;
4438 }
4439 if (!printedClient) {
4440 pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
4441 pw.print(" "); pw.println(cs);
4442 printedClient = true;
4443 }
4444 if (!printedStarted) {
4445 pw.println(" Started ops:");
4446 printedStarted = true;
4447 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004448 pw.print(" "); pw.print("uid="); pw.print(op.uidState.uid);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004449 pw.print(" pkg="); pw.print(op.packageName);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004450 pw.print(" featureId="); pw.print(startedOp.second);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004451 pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
4452 }
4453 }
4454 }
4455 }
Yin-Chia Yeh51d85162019-08-06 15:31:39 -07004456 if (mAudioRestrictionManager.hasActiveRestrictions() && dumpOp < 0
4457 && dumpPackage != null && dumpMode < 0 && !dumpWatchers && !dumpWatchers) {
4458 needSep = mAudioRestrictionManager.dump(pw) | needSep ;
John Spurlock1af30c72014-03-10 08:33:35 -04004459 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004460 if (needSep) {
4461 pw.println();
4462 }
Svet Ganov2af57082015-07-30 08:44:20 -07004463 for (int i=0; i<mUidStates.size(); i++) {
4464 UidState uidState = mUidStates.valueAt(i);
Hai Zhang93540ca2019-09-28 00:04:18 +00004465 final SparseIntArray opModes = uidState.opModes;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004466 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
4467
Svet Ganovaf189e32019-02-15 18:45:29 -08004468 if (dumpWatchers || dumpHistory) {
Dianne Hackborn125dc532019-01-09 13:31:48 -08004469 continue;
4470 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004471 if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
Hai Zhang93540ca2019-09-28 00:04:18 +00004472 boolean hasOp = dumpOp < 0 || (uidState.opModes != null
4473 && uidState.opModes.indexOfKey(dumpOp) >= 0);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004474 boolean hasPackage = dumpPackage == null;
4475 boolean hasMode = dumpMode < 0;
Hai Zhang93540ca2019-09-28 00:04:18 +00004476 if (!hasMode && opModes != null) {
4477 for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
4478 if (opModes.valueAt(opi) == dumpMode) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004479 hasMode = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004480 }
4481 }
4482 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004483 if (pkgOps != null) {
4484 for (int pkgi = 0;
Svet Ganov8455ba22019-01-02 13:05:56 -08004485 (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
4486 pkgi++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004487 Ops ops = pkgOps.valueAt(pkgi);
4488 if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
4489 hasOp = true;
4490 }
4491 if (!hasMode) {
4492 for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
4493 if (ops.valueAt(opi).mode == dumpMode) {
4494 hasMode = true;
4495 }
4496 }
4497 }
4498 if (!hasPackage && dumpPackage.equals(ops.packageName)) {
4499 hasPackage = true;
4500 }
4501 }
4502 }
4503 if (uidState.foregroundOps != null && !hasOp) {
4504 if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
4505 hasOp = true;
4506 }
4507 }
4508 if (!hasOp || !hasPackage || !hasMode) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004509 continue;
4510 }
4511 }
Svet Ganov2af57082015-07-30 08:44:20 -07004512
4513 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004514 pw.print(" state=");
Svet Ganovaf189e32019-02-15 18:45:29 -08004515 pw.println(AppOpsManager.getUidStateName(uidState.state));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004516 if (uidState.state != uidState.pendingState) {
4517 pw.print(" pendingState=");
Svet Ganovaf189e32019-02-15 18:45:29 -08004518 pw.println(AppOpsManager.getUidStateName(uidState.pendingState));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004519 }
Hui Yu26969322019-08-21 14:56:35 -07004520 pw.print(" capability=");
4521 pw.println(uidState.capability);
4522 if (uidState.capability != uidState.pendingCapability) {
4523 pw.print(" pendingCapability=");
4524 pw.println(uidState.pendingCapability);
4525 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004526 if (uidState.pendingStateCommitTime != 0) {
4527 pw.print(" pendingStateCommitTime=");
Dianne Hackborn9fb93502018-06-18 12:29:44 -07004528 TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004529 pw.println();
4530 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004531 if (uidState.startNesting != 0) {
4532 pw.print(" startNesting=");
4533 pw.println(uidState.startNesting);
4534 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004535 if (uidState.foregroundOps != null && (dumpMode < 0
4536 || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004537 pw.println(" foregroundOps:");
4538 for (int j = 0; j < uidState.foregroundOps.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004539 if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
4540 continue;
4541 }
4542 pw.print(" ");
4543 pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
4544 pw.print(": ");
4545 pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004546 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004547 pw.print(" hasForegroundWatchers=");
4548 pw.println(uidState.hasForegroundWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004549 }
Svet Ganovee438d42017-01-19 18:04:38 -08004550 needSep = true;
Svet Ganov2af57082015-07-30 08:44:20 -07004551
Hai Zhang93540ca2019-09-28 00:04:18 +00004552 if (opModes != null) {
4553 final int opModeCount = opModes.size();
4554 for (int j = 0; j < opModeCount; j++) {
4555 final int code = opModes.keyAt(j);
4556 final int mode = opModes.valueAt(j);
4557 if (dumpOp >= 0 && dumpOp != code) {
4558 continue;
4559 }
4560 if (dumpMode >= 0 && dumpMode != mode) {
4561 continue;
4562 }
4563 pw.print(" "); pw.print(AppOpsManager.opToName(code));
4564 pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
Svet Ganov2af57082015-07-30 08:44:20 -07004565 }
4566 }
4567
Svet Ganov2af57082015-07-30 08:44:20 -07004568 if (pkgOps == null) {
4569 continue;
4570 }
4571
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004572 for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004573 final Ops ops = pkgOps.valueAt(pkgi);
4574 if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
4575 continue;
4576 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004577 boolean printedPackage = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08004578 for (int j=0; j<ops.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004579 final Op op = ops.valueAt(j);
Svet Ganovaf189e32019-02-15 18:45:29 -08004580 final int opCode = op.op;
4581 if (dumpOp >= 0 && dumpOp != opCode) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004582 continue;
4583 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004584 if (dumpMode >= 0 && dumpMode != op.mode) {
4585 continue;
4586 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004587 if (!printedPackage) {
4588 pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
4589 printedPackage = true;
4590 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004591 pw.print(" "); pw.print(AppOpsManager.opToName(opCode));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004592 pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
Svet Ganovaf189e32019-02-15 18:45:29 -08004593 final int switchOp = AppOpsManager.opToSwitch(opCode);
4594 if (switchOp != opCode) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004595 pw.print(" / switch ");
4596 pw.print(AppOpsManager.opToName(switchOp));
4597 final Op switchObj = ops.get(switchOp);
Svet Ganovaf189e32019-02-15 18:45:29 -08004598 int mode = switchObj != null ? switchObj.mode
4599 : AppOpsManager.opToDefaultMode(switchOp);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004600 pw.print("="); pw.print(AppOpsManager.modeToName(mode));
4601 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004602 pw.println("): ");
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004603 dumpStatesLocked(pw, nowElapsed, op, now, sdf, date, " ");
Dianne Hackborna06de0f2012-12-11 16:34:47 -08004604 }
4605 }
4606 }
Svet Ganovee438d42017-01-19 18:04:38 -08004607 if (needSep) {
4608 pw.println();
4609 }
4610
4611 final int userRestrictionCount = mOpUserRestrictions.size();
4612 for (int i = 0; i < userRestrictionCount; i++) {
4613 IBinder token = mOpUserRestrictions.keyAt(i);
4614 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Dianne Hackborn125dc532019-01-09 13:31:48 -08004615 boolean printedTokenHeader = false;
4616
Svet Ganovaf189e32019-02-15 18:45:29 -08004617 if (dumpMode >= 0 || dumpWatchers || dumpHistory) {
Dianne Hackborn125dc532019-01-09 13:31:48 -08004618 continue;
4619 }
Svet Ganovee438d42017-01-19 18:04:38 -08004620
4621 final int restrictionCount = restrictionState.perUserRestrictions != null
4622 ? restrictionState.perUserRestrictions.size() : 0;
Dianne Hackborn125dc532019-01-09 13:31:48 -08004623 if (restrictionCount > 0 && dumpPackage == null) {
4624 boolean printedOpsHeader = false;
Svet Ganovee438d42017-01-19 18:04:38 -08004625 for (int j = 0; j < restrictionCount; j++) {
4626 int userId = restrictionState.perUserRestrictions.keyAt(j);
4627 boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
4628 if (restrictedOps == null) {
4629 continue;
4630 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08004631 if (dumpOp >= 0 && (dumpOp >= restrictedOps.length
4632 || !restrictedOps[dumpOp])) {
4633 continue;
4634 }
4635 if (!printedTokenHeader) {
4636 pw.println(" User restrictions for token " + token + ":");
4637 printedTokenHeader = true;
4638 }
4639 if (!printedOpsHeader) {
4640 pw.println(" Restricted ops:");
4641 printedOpsHeader = true;
4642 }
Svet Ganovee438d42017-01-19 18:04:38 -08004643 StringBuilder restrictedOpsValue = new StringBuilder();
4644 restrictedOpsValue.append("[");
4645 final int restrictedOpCount = restrictedOps.length;
4646 for (int k = 0; k < restrictedOpCount; k++) {
4647 if (restrictedOps[k]) {
4648 if (restrictedOpsValue.length() > 1) {
4649 restrictedOpsValue.append(", ");
4650 }
4651 restrictedOpsValue.append(AppOpsManager.opToName(k));
4652 }
4653 }
4654 restrictedOpsValue.append("]");
4655 pw.print(" "); pw.print("user: "); pw.print(userId);
4656 pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
4657 }
4658 }
4659
4660 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
4661 ? restrictionState.perUserExcludedPackages.size() : 0;
Dianne Hackborn125dc532019-01-09 13:31:48 -08004662 if (excludedPackageCount > 0 && dumpOp < 0) {
4663 boolean printedPackagesHeader = false;
Svet Ganovee438d42017-01-19 18:04:38 -08004664 for (int j = 0; j < excludedPackageCount; j++) {
4665 int userId = restrictionState.perUserExcludedPackages.keyAt(j);
4666 String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
Dianne Hackborn125dc532019-01-09 13:31:48 -08004667 if (packageNames == null) {
4668 continue;
4669 }
4670 boolean hasPackage;
4671 if (dumpPackage != null) {
4672 hasPackage = false;
4673 for (String pkg : packageNames) {
4674 if (dumpPackage.equals(pkg)) {
4675 hasPackage = true;
4676 break;
4677 }
4678 }
4679 } else {
4680 hasPackage = true;
4681 }
4682 if (!hasPackage) {
4683 continue;
4684 }
4685 if (!printedTokenHeader) {
4686 pw.println(" User restrictions for token " + token + ":");
4687 printedTokenHeader = true;
4688 }
4689 if (!printedPackagesHeader) {
4690 pw.println(" Excluded packages:");
4691 printedPackagesHeader = true;
4692 }
Svet Ganovee438d42017-01-19 18:04:38 -08004693 pw.print(" "); pw.print("user: "); pw.print(userId);
4694 pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
4695 }
4696 }
4697 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08004698 }
Svet Ganov8455ba22019-01-02 13:05:56 -08004699
4700 // Must not hold the appops lock
Svet Ganovaf189e32019-02-15 18:45:29 -08004701 if (dumpHistory && !dumpWatchers) {
4702 mHistoricalRegistry.dump(" ", pw, dumpUid, dumpPackage, dumpOp);
4703 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08004704 }
John Spurlock1af30c72014-03-10 08:33:35 -04004705
Jason Monk62062992014-05-06 09:55:28 -04004706 @Override
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004707 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
Jason Monk62062992014-05-06 09:55:28 -04004708 checkSystemUid("setUserRestrictions");
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00004709 Preconditions.checkNotNull(restrictions);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004710 Preconditions.checkNotNull(token);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004711 for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
Jason Monk62062992014-05-06 09:55:28 -04004712 String restriction = AppOpsManager.opToRestriction(i);
Suprabh Shukla64e0dcb2016-05-24 16:23:11 -07004713 if (restriction != null) {
4714 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
4715 userHandle, null);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004716 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004717 }
4718 }
4719
4720 @Override
Ruben Brunk29931bc2016-03-11 00:24:26 -08004721 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
4722 String[] exceptionPackages) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004723 if (Binder.getCallingPid() != Process.myPid()) {
4724 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
4725 Binder.getCallingPid(), Binder.getCallingUid(), null);
4726 }
4727 if (userHandle != UserHandle.getCallingUserId()) {
4728 if (mContext.checkCallingOrSelfPermission(Manifest.permission
4729 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
4730 && mContext.checkCallingOrSelfPermission(Manifest.permission
4731 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
4732 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
4733 + " INTERACT_ACROSS_USERS to interact cross user ");
Jason Monk62062992014-05-06 09:55:28 -04004734 }
4735 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004736 verifyIncomingOp(code);
4737 Preconditions.checkNotNull(token);
Ruben Brunk29931bc2016-03-11 00:24:26 -08004738 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004739 }
4740
4741 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
Ruben Brunk29931bc2016-03-11 00:24:26 -08004742 int userHandle, String[] exceptionPackages) {
Svet Ganov442ed572016-08-17 17:29:43 -07004743 synchronized (AppOpsService.this) {
4744 ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
4745
4746 if (restrictionState == null) {
4747 try {
4748 restrictionState = new ClientRestrictionState(token);
4749 } catch (RemoteException e) {
4750 return;
4751 }
4752 mOpUserRestrictions.put(token, restrictionState);
Ruben Brunk29931bc2016-03-11 00:24:26 -08004753 }
Svet Ganov442ed572016-08-17 17:29:43 -07004754
4755 if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004756 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07004757 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
Svet Ganov442ed572016-08-17 17:29:43 -07004758 }
4759
4760 if (restrictionState.isDefault()) {
4761 mOpUserRestrictions.remove(token);
4762 restrictionState.destroy();
4763 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08004764 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -04004765 }
4766
Svet Ganov3a95f832018-03-23 17:44:30 -07004767 private void notifyWatchersOfChange(int code, int uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004768 final ArraySet<ModeCallback> clonedCallbacks;
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004769 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004770 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004771 if (callbacks == null) {
4772 return;
4773 }
Dianne Hackborn68d76552017-02-27 15:32:03 -08004774 clonedCallbacks = new ArraySet<>(callbacks);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004775 }
4776
Svet Ganov3a95f832018-03-23 17:44:30 -07004777 notifyOpChanged(clonedCallbacks, code, uid, null);
Jason Monk62062992014-05-06 09:55:28 -04004778 }
4779
4780 @Override
4781 public void removeUser(int userHandle) throws RemoteException {
4782 checkSystemUid("removeUser");
Svet Ganov442ed572016-08-17 17:29:43 -07004783 synchronized (AppOpsService.this) {
4784 final int tokenCount = mOpUserRestrictions.size();
4785 for (int i = tokenCount - 1; i >= 0; i--) {
4786 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
4787 opRestrictions.removeUser(userHandle);
4788 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07004789 removeUidsForUserLocked(userHandle);
4790 }
4791 }
4792
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004793 @Override
4794 public boolean isOperationActive(int code, int uid, String packageName) {
Svet Ganovf7b47252018-02-26 11:11:27 -08004795 if (Binder.getCallingUid() != uid) {
4796 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
4797 != PackageManager.PERMISSION_GRANTED) {
4798 return false;
4799 }
4800 }
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004801 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004802 final String resolvedPackageName = resolvePackageName(uid, packageName);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004803 if (resolvedPackageName == null) {
4804 return false;
4805 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004806 // TODO moltmann: Allow to check for feature op activeness
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004807 synchronized (AppOpsService.this) {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004808 for (int i = mClients.size() - 1; i >= 0; i--) {
4809 final ClientState client = mClients.valueAt(i);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004810 for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004811 final Pair<Op, String> startedOp = client.mStartedOps.get(j);
4812 if (startedOp.first.op == code && startedOp.first.uidState.uid == uid) {
4813 return true;
4814 }
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004815 }
4816 }
4817 }
4818 return false;
4819 }
4820
Svet Ganov8455ba22019-01-02 13:05:56 -08004821 @Override
4822 public void setHistoryParameters(@AppOpsManager.HistoricalMode int mode,
4823 long baseSnapshotInterval, int compressionStep) {
4824 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
4825 "setHistoryParameters");
4826 // Must not hold the appops lock
4827 mHistoricalRegistry.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
4828 }
4829
4830 @Override
4831 public void offsetHistory(long offsetMillis) {
4832 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
4833 "offsetHistory");
4834 // Must not hold the appops lock
4835 mHistoricalRegistry.offsetHistory(offsetMillis);
4836 }
4837
4838 @Override
4839 public void addHistoricalOps(HistoricalOps ops) {
4840 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
4841 "addHistoricalOps");
4842 // Must not hold the appops lock
4843 mHistoricalRegistry.addHistoricalOps(ops);
4844 }
4845
4846 @Override
4847 public void resetHistoryParameters() {
4848 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
4849 "resetHistoryParameters");
4850 // Must not hold the appops lock
4851 mHistoricalRegistry.resetHistoryParameters();
4852 }
4853
4854 @Override
4855 public void clearHistory() {
4856 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
4857 "clearHistory");
4858 // Must not hold the appops lock
4859 mHistoricalRegistry.clearHistory();
4860 }
4861
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07004862 private void removeUidsForUserLocked(int userHandle) {
4863 for (int i = mUidStates.size() - 1; i >= 0; --i) {
4864 final int uid = mUidStates.keyAt(i);
4865 if (UserHandle.getUserId(uid) == userHandle) {
4866 mUidStates.removeAt(i);
4867 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004868 }
4869 }
4870
Jason Monk62062992014-05-06 09:55:28 -04004871 private void checkSystemUid(String function) {
4872 int uid = Binder.getCallingUid();
4873 if (uid != Process.SYSTEM_UID) {
4874 throw new SecurityException(function + " must by called by the system");
4875 }
4876 }
4877
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00004878 private static String resolvePackageName(int uid, String packageName) {
Svet Ganov82f09bc2018-01-12 22:08:40 -08004879 if (uid == Process.ROOT_UID) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00004880 return "root";
4881 } else if (uid == Process.SHELL_UID) {
4882 return "com.android.shell";
Svet Ganov82f09bc2018-01-12 22:08:40 -08004883 } else if (uid == Process.MEDIA_UID) {
4884 return "media";
4885 } else if (uid == Process.AUDIOSERVER_UID) {
4886 return "audioserver";
4887 } else if (uid == Process.CAMERASERVER_UID) {
4888 return "cameraserver";
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00004889 } else if (uid == Process.SYSTEM_UID && packageName == null) {
4890 return "android";
4891 }
4892 return packageName;
4893 }
4894
Svet Ganov82f09bc2018-01-12 22:08:40 -08004895 private static int resolveUid(String packageName) {
4896 if (packageName == null) {
4897 return -1;
4898 }
4899 switch (packageName) {
4900 case "root":
4901 return Process.ROOT_UID;
4902 case "shell":
4903 return Process.SHELL_UID;
4904 case "media":
4905 return Process.MEDIA_UID;
4906 case "audioserver":
4907 return Process.AUDIOSERVER_UID;
4908 case "cameraserver":
4909 return Process.CAMERASERVER_UID;
4910 }
4911 return -1;
4912 }
4913
Svet Ganov2af57082015-07-30 08:44:20 -07004914 private static String[] getPackagesForUid(int uid) {
Svet Ganovf3807aa2015-08-02 10:09:56 -07004915 String[] packageNames = null;
Philip P. Moltmann159d98b2018-12-20 08:30:53 -08004916
4917 // Very early during boot the package manager is not yet or not yet fully started. At this
4918 // time there are no packages yet.
4919 if (AppGlobals.getPackageManager() != null) {
4920 try {
4921 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
4922 } catch (RemoteException e) {
4923 /* ignore - local call */
4924 }
Svet Ganov2af57082015-07-30 08:44:20 -07004925 }
Svet Ganovf3807aa2015-08-02 10:09:56 -07004926 if (packageNames == null) {
4927 return EmptyArray.STRING;
4928 }
4929 return packageNames;
Svet Ganov2af57082015-07-30 08:44:20 -07004930 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004931
4932 private final class ClientRestrictionState implements DeathRecipient {
4933 private final IBinder token;
4934 SparseArray<boolean[]> perUserRestrictions;
4935 SparseArray<String[]> perUserExcludedPackages;
4936
4937 public ClientRestrictionState(IBinder token)
4938 throws RemoteException {
4939 token.linkToDeath(this, 0);
4940 this.token = token;
4941 }
4942
4943 public boolean setRestriction(int code, boolean restricted,
4944 String[] excludedPackages, int userId) {
4945 boolean changed = false;
4946
4947 if (perUserRestrictions == null && restricted) {
4948 perUserRestrictions = new SparseArray<>();
4949 }
4950
Philip P. Moltmanne683f192017-06-23 14:05:04 -07004951 int[] users;
4952 if (userId == UserHandle.USER_ALL) {
4953 List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004954
Philip P. Moltmanne683f192017-06-23 14:05:04 -07004955 users = new int[liveUsers.size()];
4956 for (int i = 0; i < liveUsers.size(); i++) {
4957 users[i] = liveUsers.get(i).id;
4958 }
4959 } else {
4960 users = new int[]{userId};
4961 }
4962
4963 if (perUserRestrictions != null) {
4964 int numUsers = users.length;
4965
4966 for (int i = 0; i < numUsers; i++) {
4967 int thisUserId = users[i];
4968
4969 boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
4970 if (userRestrictions == null && restricted) {
4971 userRestrictions = new boolean[AppOpsManager._NUM_OP];
4972 perUserRestrictions.put(thisUserId, userRestrictions);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004973 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07004974 if (userRestrictions != null && userRestrictions[code] != restricted) {
4975 userRestrictions[code] = restricted;
4976 if (!restricted && isDefault(userRestrictions)) {
4977 perUserRestrictions.remove(thisUserId);
4978 userRestrictions = null;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004979 }
4980 changed = true;
4981 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07004982
4983 if (userRestrictions != null) {
4984 final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
4985 if (perUserExcludedPackages == null && !noExcludedPackages) {
4986 perUserExcludedPackages = new SparseArray<>();
4987 }
4988 if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
4989 perUserExcludedPackages.get(thisUserId))) {
4990 if (noExcludedPackages) {
4991 perUserExcludedPackages.remove(thisUserId);
4992 if (perUserExcludedPackages.size() <= 0) {
4993 perUserExcludedPackages = null;
4994 }
4995 } else {
4996 perUserExcludedPackages.put(thisUserId, excludedPackages);
4997 }
4998 changed = true;
4999 }
5000 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07005001 }
5002 }
5003
5004 return changed;
5005 }
5006
5007 public boolean hasRestriction(int restriction, String packageName, int userId) {
5008 if (perUserRestrictions == null) {
5009 return false;
5010 }
5011 boolean[] restrictions = perUserRestrictions.get(userId);
5012 if (restrictions == null) {
5013 return false;
5014 }
5015 if (!restrictions[restriction]) {
5016 return false;
5017 }
5018 if (perUserExcludedPackages == null) {
5019 return true;
5020 }
5021 String[] perUserExclusions = perUserExcludedPackages.get(userId);
5022 if (perUserExclusions == null) {
5023 return true;
5024 }
5025 return !ArrayUtils.contains(perUserExclusions, packageName);
5026 }
5027
5028 public void removeUser(int userId) {
5029 if (perUserExcludedPackages != null) {
5030 perUserExcludedPackages.remove(userId);
5031 if (perUserExcludedPackages.size() <= 0) {
5032 perUserExcludedPackages = null;
5033 }
5034 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07005035 if (perUserRestrictions != null) {
5036 perUserRestrictions.remove(userId);
5037 if (perUserRestrictions.size() <= 0) {
5038 perUserRestrictions = null;
5039 }
5040 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07005041 }
5042
5043 public boolean isDefault() {
5044 return perUserRestrictions == null || perUserRestrictions.size() <= 0;
5045 }
5046
5047 @Override
5048 public void binderDied() {
5049 synchronized (AppOpsService.this) {
5050 mOpUserRestrictions.remove(token);
5051 if (perUserRestrictions == null) {
5052 return;
5053 }
5054 final int userCount = perUserRestrictions.size();
5055 for (int i = 0; i < userCount; i++) {
5056 final boolean[] restrictions = perUserRestrictions.valueAt(i);
5057 final int restrictionCount = restrictions.length;
5058 for (int j = 0; j < restrictionCount; j++) {
5059 if (restrictions[j]) {
5060 final int changedCode = j;
Svet Ganov3a95f832018-03-23 17:44:30 -07005061 mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07005062 }
5063 }
5064 }
5065 destroy();
5066 }
5067 }
5068
5069 public void destroy() {
5070 token.unlinkToDeath(this, 0);
5071 }
5072
5073 private boolean isDefault(boolean[] array) {
5074 if (ArrayUtils.isEmpty(array)) {
5075 return true;
5076 }
5077 for (boolean value : array) {
5078 if (value) {
5079 return false;
5080 }
5081 }
5082 return true;
5083 }
5084 }
Dianne Hackbornd5254412018-05-11 18:02:58 -07005085
5086 private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
5087 @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
5088 synchronized (AppOpsService.this) {
5089 mProfileOwners = owners;
5090 }
5091 }
5092 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08005093}