1 /*
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 
17 package com.android.server.appop;
18 
19 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
20 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
21 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
22 import static android.app.AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
23 import static android.app.AppOpsManager.ATTRIBUTION_FLAG_TRUSTED;
24 import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
25 import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
26 import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
27 import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
28 import static android.app.AppOpsManager.FILTER_BY_UID;
29 import static android.app.AppOpsManager.HISTORY_FLAG_GET_ATTRIBUTION_CHAINS;
30 import static android.app.AppOpsManager.HistoricalOpsRequestFilter;
31 import static android.app.AppOpsManager.KEY_BG_STATE_SETTLE_TIME;
32 import static android.app.AppOpsManager.KEY_FG_SERVICE_STATE_SETTLE_TIME;
33 import static android.app.AppOpsManager.KEY_TOP_STATE_SETTLE_TIME;
34 import static android.app.AppOpsManager.MODE_ALLOWED;
35 import static android.app.AppOpsManager.MODE_DEFAULT;
36 import static android.app.AppOpsManager.MODE_ERRORED;
37 import static android.app.AppOpsManager.MODE_FOREGROUND;
38 import static android.app.AppOpsManager.MODE_IGNORED;
39 import static android.app.AppOpsManager.NoteOpEvent;
40 import static android.app.AppOpsManager.OP_CAMERA;
41 import static android.app.AppOpsManager.OP_FLAGS_ALL;
42 import static android.app.AppOpsManager.OP_FLAG_SELF;
43 import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
44 import static android.app.AppOpsManager.OP_NONE;
45 import static android.app.AppOpsManager.OP_PLAY_AUDIO;
46 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
47 import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD;
48 import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_FAILED;
49 import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_RESUMED;
50 import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_STARTED;
51 import static android.app.AppOpsManager.OpEventProxyInfo;
52 import static android.app.AppOpsManager.RestrictionBypass;
53 import static android.app.AppOpsManager.SAMPLING_STRATEGY_BOOT_TIME_SAMPLING;
54 import static android.app.AppOpsManager.SAMPLING_STRATEGY_RARELY_USED;
55 import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM;
56 import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM_OPS;
57 import static android.app.AppOpsManager.SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE;
58 import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
59 import static android.app.AppOpsManager.UID_STATE_CACHED;
60 import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
61 import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
62 import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
63 import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
64 import static android.app.AppOpsManager.UID_STATE_TOP;
65 import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES;
66 import static android.app.AppOpsManager._NUM_OP;
67 import static android.app.AppOpsManager.extractFlagsFromKey;
68 import static android.app.AppOpsManager.extractUidStateFromKey;
69 import static android.app.AppOpsManager.makeKey;
70 import static android.app.AppOpsManager.modeToName;
71 import static android.app.AppOpsManager.opAllowSystemBypassRestriction;
72 import static android.app.AppOpsManager.opToName;
73 import static android.app.AppOpsManager.opToPublicName;
74 import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState;
75 import static android.content.Intent.ACTION_PACKAGE_REMOVED;
76 import static android.content.Intent.EXTRA_REPLACING;
77 import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
78 import static android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP;
79 
80 import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS;
81 
82 import static java.lang.Long.max;
83 
84 import android.Manifest;
85 import android.annotation.IntRange;
86 import android.annotation.NonNull;
87 import android.annotation.Nullable;
88 import android.annotation.UserIdInt;
89 import android.app.ActivityManager;
90 import android.app.ActivityManagerInternal;
91 import android.app.AppGlobals;
92 import android.app.AppOpsManager;
93 import android.app.AppOpsManager.AttributedOpEntry;
94 import android.app.AppOpsManager.AttributionFlags;
95 import android.app.AppOpsManager.HistoricalOps;
96 import android.app.AppOpsManager.Mode;
97 import android.app.AppOpsManager.OpEntry;
98 import android.app.AppOpsManager.OpFlags;
99 import android.app.AppOpsManagerInternal;
100 import android.app.AppOpsManagerInternal.CheckOpsDelegate;
101 import android.app.AsyncNotedAppOp;
102 import android.app.RuntimeAppOpAccessMessage;
103 import android.app.SyncNotedAppOp;
104 import android.app.admin.DevicePolicyManagerInternal;
105 import android.content.AttributionSource;
106 import android.content.BroadcastReceiver;
107 import android.content.ContentResolver;
108 import android.content.Context;
109 import android.content.Intent;
110 import android.content.IntentFilter;
111 import android.content.pm.PackageInfo;
112 import android.content.pm.PackageManager;
113 import android.content.pm.PackageManagerInternal;
114 import android.content.pm.PermissionInfo;
115 import android.content.pm.UserInfo;
116 import android.content.pm.parsing.component.ParsedAttribution;
117 import android.database.ContentObserver;
118 import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION;
119 import android.net.Uri;
120 import android.os.AsyncTask;
121 import android.os.Binder;
122 import android.os.Build;
123 import android.os.Bundle;
124 import android.os.Handler;
125 import android.os.IBinder;
126 import android.os.PackageTagsList;
127 import android.os.Process;
128 import android.os.RemoteCallback;
129 import android.os.RemoteCallbackList;
130 import android.os.RemoteException;
131 import android.os.ResultReceiver;
132 import android.os.ServiceManager;
133 import android.os.ShellCallback;
134 import android.os.ShellCommand;
135 import android.os.SystemClock;
136 import android.os.UserHandle;
137 import android.os.UserManager;
138 import android.os.storage.StorageManagerInternal;
139 import android.permission.PermissionManager;
140 import android.provider.Settings;
141 import android.util.ArrayMap;
142 import android.util.ArraySet;
143 import android.util.AtomicFile;
144 import android.util.IndentingPrintWriter;
145 import android.util.KeyValueListParser;
146 import android.util.LongSparseArray;
147 import android.util.Pair;
148 import android.util.Pools;
149 import android.util.Pools.SimplePool;
150 import android.util.Slog;
151 import android.util.SparseArray;
152 import android.util.SparseBooleanArray;
153 import android.util.SparseIntArray;
154 import android.util.TimeUtils;
155 import android.util.TypedXmlPullParser;
156 import android.util.TypedXmlSerializer;
157 import android.util.Xml;
158 
159 import com.android.internal.annotations.GuardedBy;
160 import com.android.internal.annotations.Immutable;
161 import com.android.internal.annotations.VisibleForTesting;
162 import com.android.internal.app.IAppOpsActiveCallback;
163 import com.android.internal.app.IAppOpsAsyncNotedCallback;
164 import com.android.internal.app.IAppOpsCallback;
165 import com.android.internal.app.IAppOpsNotedCallback;
166 import com.android.internal.app.IAppOpsService;
167 import com.android.internal.app.IAppOpsStartedCallback;
168 import com.android.internal.app.MessageSamplingConfig;
169 import com.android.internal.compat.IPlatformCompat;
170 import com.android.internal.util.ArrayUtils;
171 import com.android.internal.util.DumpUtils;
172 import com.android.internal.util.Preconditions;
173 import com.android.internal.util.XmlUtils;
174 import com.android.internal.util.function.pooled.PooledLambda;
175 import com.android.server.LocalServices;
176 import com.android.server.LockGuard;
177 import com.android.server.SystemServerInitThreadPool;
178 import com.android.server.SystemServiceManager;
179 import com.android.server.pm.PackageList;
180 import com.android.server.pm.parsing.pkg.AndroidPackage;
181 
182 import libcore.util.EmptyArray;
183 
184 import org.json.JSONException;
185 import org.json.JSONObject;
186 import org.xmlpull.v1.XmlPullParser;
187 import org.xmlpull.v1.XmlPullParserException;
188 
189 import java.io.File;
190 import java.io.FileDescriptor;
191 import java.io.FileInputStream;
192 import java.io.FileNotFoundException;
193 import java.io.FileOutputStream;
194 import java.io.FileWriter;
195 import java.io.IOException;
196 import java.io.PrintWriter;
197 import java.text.SimpleDateFormat;
198 import java.time.Instant;
199 import java.time.temporal.ChronoUnit;
200 import java.util.ArrayList;
201 import java.util.Arrays;
202 import java.util.Collections;
203 import java.util.Date;
204 import java.util.HashMap;
205 import java.util.Iterator;
206 import java.util.List;
207 import java.util.Map;
208 import java.util.NoSuchElementException;
209 import java.util.Objects;
210 import java.util.Scanner;
211 import java.util.Set;
212 import java.util.concurrent.ThreadLocalRandom;
213 import java.util.function.Consumer;
214 
215 public class AppOpsService extends IAppOpsService.Stub {
216     static final String TAG = "AppOps";
217     static final boolean DEBUG = false;
218 
219     /**
220      * Used for data access validation collection, we wish to only log a specific access once
221      */
222     private final ArraySet<NoteOpTrace> mNoteOpCallerStacktraces = new ArraySet<>();
223 
224     private static final int NO_VERSION = -1;
225     /** Increment by one every time and add the corresponding upgrade logic in
226      *  {@link #upgradeLocked(int)} below. The first version was 1 */
227     private static final int CURRENT_VERSION = 1;
228 
229     // Write at most every 30 minutes.
230     static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
231 
232     // Constant meaning that any UID should be matched when dispatching callbacks
233     private static final int UID_ANY = -2;
234 
235     // Map from process states to the uid states we track.
236     private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
237         UID_STATE_PERSISTENT,           // ActivityManager.PROCESS_STATE_PERSISTENT
238         UID_STATE_PERSISTENT,           // ActivityManager.PROCESS_STATE_PERSISTENT_UI
239         UID_STATE_TOP,                  // ActivityManager.PROCESS_STATE_TOP
240         UID_STATE_FOREGROUND,           // ActivityManager.PROCESS_STATE_BOUND_TOP
241         UID_STATE_FOREGROUND_SERVICE,   // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
242         UID_STATE_FOREGROUND,           // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
243         UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
244         UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
245         UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
246         UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_BACKUP
247         UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_SERVICE
248         UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_RECEIVER
249         UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_TOP_SLEEPING
250         UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
251         UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_HOME
252         UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
253         UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
254         UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
255         UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_RECENT
256         UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_EMPTY
257         UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_NONEXISTENT
258     };
259 
260     private static final int[] OPS_RESTRICTED_ON_SUSPEND = {
261             OP_PLAY_AUDIO,
262             OP_RECORD_AUDIO,
263             OP_CAMERA,
264     };
265 
266     private static final int MAX_UNFORWARDED_OPS = 10;
267     private static final int MAX_UNUSED_POOLED_OBJECTS = 3;
268     private static final int RARELY_USED_PACKAGES_INITIALIZATION_DELAY_MILLIS = 300000;
269 
270     final Context mContext;
271     final AtomicFile mFile;
272     private final @Nullable File mNoteOpCallerStacktracesFile;
273     final Handler mHandler;
274 
275     /** Pool for {@link OpEventProxyInfoPool} to avoid to constantly reallocate new objects */
276     @GuardedBy("this")
277     private final OpEventProxyInfoPool mOpEventProxyInfoPool = new OpEventProxyInfoPool();
278 
279     /** Pool for {@link InProgressStartOpEventPool} to avoid to constantly reallocate new objects */
280     @GuardedBy("this")
281     private final InProgressStartOpEventPool mInProgressStartOpEventPool =
282             new InProgressStartOpEventPool();
283 
284     private final AppOpsManagerInternalImpl mAppOpsManagerInternal
285             = new AppOpsManagerInternalImpl();
286     @Nullable private final DevicePolicyManagerInternal dpmi =
287             LocalServices.getService(DevicePolicyManagerInternal.class);
288 
289     private final IPlatformCompat mPlatformCompat = IPlatformCompat.Stub.asInterface(
290             ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
291 
292     /**
293      * Registered callbacks, called from {@link #collectAsyncNotedOp}.
294      *
295      * <p>(package name, uid) -> callbacks
296      *
297      * @see #getAsyncNotedOpsKey(String, int)
298      */
299     @GuardedBy("this")
300     private final ArrayMap<Pair<String, Integer>, RemoteCallbackList<IAppOpsAsyncNotedCallback>>
301             mAsyncOpWatchers = new ArrayMap<>();
302 
303     /**
304      * Async note-ops collected from {@link #collectAsyncNotedOp} that have not been delivered to a
305      * callback yet.
306      *
307      * <p>(package name, uid) -> list&lt;ops&gt;
308      *
309      * @see #getAsyncNotedOpsKey(String, int)
310      */
311     @GuardedBy("this")
312     private final ArrayMap<Pair<String, Integer>, ArrayList<AsyncNotedAppOp>>
313             mUnforwardedAsyncNotedOps = new ArrayMap<>();
314 
315     boolean mWriteNoteOpsScheduled;
316 
317     boolean mWriteScheduled;
318     boolean mFastWriteScheduled;
319     final Runnable mWriteRunner = new Runnable() {
320         public void run() {
321             synchronized (AppOpsService.this) {
322                 mWriteScheduled = false;
323                 mFastWriteScheduled = false;
324                 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
325                     @Override protected Void doInBackground(Void... params) {
326                         writeState();
327                         return null;
328                     }
329                 };
330                 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
331             }
332         }
333     };
334 
335     @GuardedBy("this")
336     @VisibleForTesting
337     final SparseArray<UidState> mUidStates = new SparseArray<>();
338 
339     volatile @NonNull HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this);
340 
341     long mLastRealtime;
342 
343     /*
344      * These are app op restrictions imposed per user from various parties.
345      */
346     private final ArrayMap<IBinder, ClientUserRestrictionState> mOpUserRestrictions =
347             new ArrayMap<>();
348 
349     /*
350      * These are app op restrictions imposed globally from various parties within the system.
351      */
352     private final ArrayMap<IBinder, ClientGlobalRestrictionState> mOpGlobalRestrictions =
353             new ArrayMap<>();
354 
355     SparseIntArray mProfileOwners;
356 
357     private volatile CheckOpsDelegateDispatcher mCheckOpsDelegateDispatcher =
358             new CheckOpsDelegateDispatcher(/*policy*/ null, /*delegate*/ null);
359 
360     /**
361       * Reverse lookup for {@link AppOpsManager#opToSwitch(int)}. Initialized once and never
362       * changed
363       */
364     private final SparseArray<int[]> mSwitchedOps = new SparseArray<>();
365 
366     private ActivityManagerInternal mActivityManagerInternal;
367 
368     /** Package sampled for message collection in the current session */
369     @GuardedBy("this")
370     private String mSampledPackage = null;
371 
372     /** Appop sampled for message collection in the current session */
373     @GuardedBy("this")
374     private int mSampledAppOpCode = OP_NONE;
375 
376     /** Maximum distance for appop to be considered for message collection in the current session */
377     @GuardedBy("this")
378     private int mAcceptableLeftDistance = 0;
379 
380     /** Number of messages collected for sampled package and appop in the current session */
381     @GuardedBy("this")
382     private float mMessagesCollectedCount;
383 
384     /** List of rarely used packages priorities for message collection */
385     @GuardedBy("this")
386     private ArraySet<String> mRarelyUsedPackages = new ArraySet<>();
387 
388     /** Sampling strategy used for current session */
389     @GuardedBy("this")
390     @AppOpsManager.SamplingStrategy
391     private int mSamplingStrategy;
392 
393     /** Last runtime permission access message collected and ready for reporting */
394     @GuardedBy("this")
395     private RuntimeAppOpAccessMessage mCollectedRuntimePermissionMessage;
396 
397     /** Package Manager internal. Access via {@link #getPackageManagerInternal()} */
398     private @Nullable PackageManagerInternal mPackageManagerInternal;
399 
400     /**
401      * An unsynchronized pool of {@link OpEventProxyInfo} objects.
402      */
403     private class OpEventProxyInfoPool extends SimplePool<OpEventProxyInfo> {
OpEventProxyInfoPool()404         OpEventProxyInfoPool() {
405             super(MAX_UNUSED_POOLED_OBJECTS);
406         }
407 
acquire(@ntRangefrom = 0) int uid, @Nullable String packageName, @Nullable String attributionTag)408         OpEventProxyInfo acquire(@IntRange(from = 0) int uid, @Nullable String packageName,
409                 @Nullable String attributionTag) {
410             OpEventProxyInfo recycled = acquire();
411             if (recycled != null) {
412                 recycled.reinit(uid, packageName, attributionTag);
413                 return recycled;
414             }
415 
416             return new OpEventProxyInfo(uid, packageName, attributionTag);
417         }
418     }
419 
420     /**
421      * An unsynchronized pool of {@link InProgressStartOpEvent} objects.
422      */
423     private class InProgressStartOpEventPool extends SimplePool<InProgressStartOpEvent> {
InProgressStartOpEventPool()424         InProgressStartOpEventPool() {
425             super(MAX_UNUSED_POOLED_OBJECTS);
426         }
427 
acquire(long startTime, long elapsedTime, @NonNull IBinder clientId, @Nullable String attributionTag, @NonNull Runnable onDeath, int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState, @OpFlags int flags, @AttributionFlags int attributionFlags, int attributionChainId)428         InProgressStartOpEvent acquire(long startTime, long elapsedTime, @NonNull IBinder clientId,
429                 @Nullable String attributionTag, @NonNull Runnable onDeath, int proxyUid,
430                 @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
431                 @AppOpsManager.UidState int uidState, @OpFlags int flags, @AttributionFlags
432                 int attributionFlags, int attributionChainId) throws RemoteException {
433 
434             InProgressStartOpEvent recycled = acquire();
435 
436             OpEventProxyInfo proxyInfo = null;
437             if (proxyUid != Process.INVALID_UID) {
438                 proxyInfo = mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName,
439                         proxyAttributionTag);
440             }
441 
442             if (recycled != null) {
443                 recycled.reinit(startTime, elapsedTime, clientId, attributionTag, onDeath,
444                         uidState, flags, proxyInfo,  attributionFlags, attributionChainId,
445                         mOpEventProxyInfoPool);
446                 return recycled;
447             }
448 
449             return new InProgressStartOpEvent(startTime, elapsedTime, clientId, attributionTag,
450                     onDeath, uidState, proxyInfo, flags, attributionFlags, attributionChainId);
451         }
452     }
453 
454     /**
455      * All times are in milliseconds. These constants are kept synchronized with the system
456      * global Settings. Any access to this class or its fields should be done while
457      * holding the AppOpsService lock.
458      */
459     @VisibleForTesting
460     final class Constants extends ContentObserver {
461 
462         /**
463          * How long we want for a drop in uid state from top to settle before applying it.
464          * @see Settings.Global#APP_OPS_CONSTANTS
465          * @see AppOpsManager#KEY_TOP_STATE_SETTLE_TIME
466          */
467         public long TOP_STATE_SETTLE_TIME;
468 
469         /**
470          * How long we want for a drop in uid state from foreground to settle before applying it.
471          * @see Settings.Global#APP_OPS_CONSTANTS
472          * @see AppOpsManager#KEY_FG_SERVICE_STATE_SETTLE_TIME
473          */
474         public long FG_SERVICE_STATE_SETTLE_TIME;
475 
476         /**
477          * How long we want for a drop in uid state from background to settle before applying it.
478          * @see Settings.Global#APP_OPS_CONSTANTS
479          * @see AppOpsManager#KEY_BG_STATE_SETTLE_TIME
480          */
481         public long BG_STATE_SETTLE_TIME;
482 
483         private final KeyValueListParser mParser = new KeyValueListParser(',');
484         private ContentResolver mResolver;
485 
Constants(Handler handler)486         public Constants(Handler handler) {
487             super(handler);
488             updateConstants();
489         }
490 
startMonitoring(ContentResolver resolver)491         public void startMonitoring(ContentResolver resolver) {
492             mResolver = resolver;
493             mResolver.registerContentObserver(
494                     Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
495                     false, this);
496             updateConstants();
497         }
498 
499         @Override
onChange(boolean selfChange, Uri uri)500         public void onChange(boolean selfChange, Uri uri) {
501             updateConstants();
502         }
503 
updateConstants()504         private void updateConstants() {
505             String value = mResolver != null ? Settings.Global.getString(mResolver,
506                     Settings.Global.APP_OPS_CONSTANTS) : "";
507 
508             synchronized (AppOpsService.this) {
509                 try {
510                     mParser.setString(value);
511                 } catch (IllegalArgumentException e) {
512                     // Failed to parse the settings string, log this and move on
513                     // with defaults.
514                     Slog.e(TAG, "Bad app ops settings", e);
515                 }
516                 TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
517                         KEY_TOP_STATE_SETTLE_TIME, 5 * 1000L);
518                 FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
519                         KEY_FG_SERVICE_STATE_SETTLE_TIME, 5 * 1000L);
520                 BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
521                         KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
522             }
523         }
524 
dump(PrintWriter pw)525         void dump(PrintWriter pw) {
526             pw.println("  Settings:");
527 
528             pw.print("    "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("=");
529             TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw);
530             pw.println();
531             pw.print("    "); pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME); pw.print("=");
532             TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
533             pw.println();
534             pw.print("    "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("=");
535             TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
536             pw.println();
537         }
538     }
539 
540     @VisibleForTesting
541     final Constants mConstants;
542 
543     @VisibleForTesting
544     final class UidState {
545         public final int uid;
546 
547         public int state = UID_STATE_CACHED;
548         public int pendingState = UID_STATE_CACHED;
549         public long pendingStateCommitTime;
550         public int capability;
551         public int pendingCapability;
552         public boolean appWidgetVisible;
553         public boolean pendingAppWidgetVisible;
554 
555         public ArrayMap<String, Ops> pkgOps;
556         public SparseIntArray opModes;
557 
558         // true indicates there is an interested observer, false there isn't but it has such an op
559         public SparseBooleanArray foregroundOps;
560         public boolean hasForegroundWatchers;
561 
UidState(int uid)562         public UidState(int uid) {
563             this.uid = uid;
564         }
565 
clear()566         public void clear() {
567             pkgOps = null;
568             opModes = null;
569         }
570 
isDefault()571         public boolean isDefault() {
572             return (pkgOps == null || pkgOps.isEmpty())
573                     && (opModes == null || opModes.size() <= 0)
574                     && (state == UID_STATE_CACHED
575                     && (pendingState == UID_STATE_CACHED));
576         }
577 
evalMode(int op, int mode)578         int evalMode(int op, int mode) {
579             if (mode == MODE_FOREGROUND) {
580                 if (appWidgetVisible) {
581                     return MODE_ALLOWED;
582                 } else if (mActivityManagerInternal != null
583                         && mActivityManagerInternal.isPendingTopUid(uid)) {
584                     return MODE_ALLOWED;
585                 } else if (mActivityManagerInternal != null
586                         && mActivityManagerInternal.isTempAllowlistedForFgsWhileInUse(uid)) {
587                     return MODE_ALLOWED;
588                 } else if (state <= UID_STATE_TOP) {
589                     // process is in TOP.
590                     return MODE_ALLOWED;
591                 } else if (state <= AppOpsManager.resolveFirstUnrestrictedUidState(op)) {
592                     // process is in foreground, check its capability.
593                     switch (op) {
594                         case AppOpsManager.OP_FINE_LOCATION:
595                         case AppOpsManager.OP_COARSE_LOCATION:
596                         case AppOpsManager.OP_MONITOR_LOCATION:
597                         case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
598                             if ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) {
599                                 return MODE_ALLOWED;
600                             } else {
601                                 return MODE_IGNORED;
602                             }
603                         case OP_CAMERA:
604                             if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
605                                 return MODE_ALLOWED;
606                             } else {
607                                 return MODE_IGNORED;
608                             }
609                         case OP_RECORD_AUDIO:
610                             if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
611                                 return MODE_ALLOWED;
612                             } else {
613                                 return MODE_IGNORED;
614                             }
615                         default:
616                             return MODE_ALLOWED;
617                     }
618                 } else {
619                     // process is not in foreground.
620                     return MODE_IGNORED;
621                 }
622             }
623             return mode;
624         }
625 
evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers, SparseBooleanArray which)626         private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
627                 SparseBooleanArray which) {
628             boolean curValue = which.get(op, false);
629             ArraySet<ModeCallback> callbacks = watchers.get(op);
630             if (callbacks != null) {
631                 for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
632                     if ((callbacks.valueAt(cbi).mFlags
633                             & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
634                         hasForegroundWatchers = true;
635                         curValue = true;
636                     }
637                 }
638             }
639             which.put(op, curValue);
640         }
641 
evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers)642         public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
643             SparseBooleanArray which = null;
644             hasForegroundWatchers = false;
645             if (opModes != null) {
646                 for (int i = opModes.size() - 1; i >= 0; i--) {
647                     if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
648                         if (which == null) {
649                             which = new SparseBooleanArray();
650                         }
651                         evalForegroundWatchers(opModes.keyAt(i), watchers, which);
652                     }
653                 }
654             }
655             if (pkgOps != null) {
656                 for (int i = pkgOps.size() - 1; i >= 0; i--) {
657                     Ops ops = pkgOps.valueAt(i);
658                     for (int j = ops.size() - 1; j >= 0; j--) {
659                         if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
660                             if (which == null) {
661                                 which = new SparseBooleanArray();
662                             }
663                             evalForegroundWatchers(ops.keyAt(j), watchers, which);
664                         }
665                     }
666                 }
667             }
668             foregroundOps = which;
669         }
670     }
671 
672     final static class Ops extends SparseArray<Op> {
673         final String packageName;
674         final UidState uidState;
675 
676         /**
677          * The restriction properties of the package. If {@code null} it could not have been read
678          * yet and has to be refreshed.
679          */
680         @Nullable RestrictionBypass bypass;
681 
682         /** Lazily populated cache of attributionTags of this package */
683         final @NonNull ArraySet<String> knownAttributionTags = new ArraySet<>();
684 
685         /**
686          * Lazily populated cache of <b>valid</b> attributionTags of this package, a set smaller
687          * than or equal to {@link #knownAttributionTags}.
688          */
689         final @NonNull ArraySet<String> validAttributionTags = new ArraySet<>();
690 
Ops(String _packageName, UidState _uidState)691         Ops(String _packageName, UidState _uidState) {
692             packageName = _packageName;
693             uidState = _uidState;
694         }
695     }
696 
697     /** Returned from {@link #verifyAndGetBypass(int, String, String, String, boolean)}. */
698     private static final class PackageVerificationResult {
699 
700         final RestrictionBypass bypass;
701         final boolean isAttributionTagValid;
702 
PackageVerificationResult(RestrictionBypass bypass, boolean isAttributionTagValid)703         PackageVerificationResult(RestrictionBypass bypass, boolean isAttributionTagValid) {
704             this.bypass = bypass;
705             this.isAttributionTagValid = isAttributionTagValid;
706         }
707     }
708 
709     /** A in progress startOp->finishOp event */
710     private static final class InProgressStartOpEvent implements IBinder.DeathRecipient {
711         /** Wall clock time of startOp event (not monotonic) */
712         private long mStartTime;
713 
714         /** Elapsed time since boot of startOp event */
715         private long mStartElapsedTime;
716 
717         /** Id of the client that started the event */
718         private @NonNull IBinder mClientId;
719 
720         /** The attribution tag for this operation */
721         private @Nullable String mAttributionTag;
722 
723         /** To call when client dies */
724         private @NonNull Runnable mOnDeath;
725 
726         /** uidstate used when calling startOp */
727         private @AppOpsManager.UidState int mUidState;
728 
729         /** Proxy information of the startOp event */
730         private @Nullable OpEventProxyInfo mProxy;
731 
732         /** Proxy flag information */
733         private @OpFlags int mFlags;
734 
735         /** How many times the op was started but not finished yet */
736         int numUnfinishedStarts;
737 
738         /** The attribution flags related to this event */
739         private @AttributionFlags int mAttributionFlags;
740 
741         /** The id of the attribution chain this even is a part of */
742         private int mAttributionChainId;
743 
744         /**
745          * Create a new {@link InProgressStartOpEvent}.
746          *
747          * @param startTime The time {@link #startOperation} was called
748          * @param startElapsedTime The elapsed time when {@link #startOperation} was called
749          * @param clientId The client id of the caller of {@link #startOperation}
750          * @param attributionTag The attribution tag for the operation.
751          * @param onDeath The code to execute on client death
752          * @param uidState The uidstate of the app {@link #startOperation} was called for
753          * @param attributionFlags the attribution flags for this operation.
754          * @param attributionChainId the unique id of the attribution chain this op is a part of.
755          * @param proxy The proxy information, if {@link #startProxyOperation} was called
756          * @param flags The trusted/nontrusted/self flags.
757          *
758          * @throws RemoteException If the client is dying
759          */
InProgressStartOpEvent(long startTime, long startElapsedTime, @NonNull IBinder clientId, @Nullable String attributionTag, @NonNull Runnable onDeath, @AppOpsManager.UidState int uidState, @Nullable OpEventProxyInfo proxy, @OpFlags int flags, @AttributionFlags int attributionFlags, int attributionChainId)760         private InProgressStartOpEvent(long startTime, long startElapsedTime,
761                 @NonNull IBinder clientId, @Nullable String attributionTag,
762                 @NonNull Runnable onDeath, @AppOpsManager.UidState int uidState,
763                 @Nullable OpEventProxyInfo proxy, @OpFlags int flags,
764                 @AttributionFlags int attributionFlags, int attributionChainId)
765                 throws RemoteException {
766             mStartTime = startTime;
767             mStartElapsedTime = startElapsedTime;
768             mClientId = clientId;
769             mAttributionTag = attributionTag;
770             mOnDeath = onDeath;
771             mUidState = uidState;
772             mProxy = proxy;
773             mFlags = flags;
774             mAttributionFlags = attributionFlags;
775             mAttributionChainId = attributionChainId;
776 
777             clientId.linkToDeath(this, 0);
778         }
779 
780         /** Clean up event */
finish()781         public void finish() {
782             try {
783                 mClientId.unlinkToDeath(this, 0);
784             } catch (NoSuchElementException e) {
785                 // Either not linked, or already unlinked. Either way, nothing to do.
786             }
787         }
788 
789         @Override
binderDied()790         public void binderDied() {
791             mOnDeath.run();
792         }
793 
794         /**
795          * Reinit existing object with new state.
796          *
797          * @param startTime The time {@link #startOperation} was called
798          * @param startElapsedTime The elapsed time when {@link #startOperation} was called
799          * @param clientId The client id of the caller of {@link #startOperation}
800          * @param attributionTag The attribution tag for this operation.
801          * @param onDeath The code to execute on client death
802          * @param uidState The uidstate of the app {@link #startOperation} was called for
803          * @param flags The flags relating to the proxy
804          * @param proxy The proxy information, if {@link #startProxyOperation} was called
805          * @param attributionFlags the attribution flags for this operation.
806          * @param attributionChainId the unique id of the attribution chain this op is a part of.
807          * @param proxyPool The pool to release previous {@link OpEventProxyInfo} to
808          *
809          * @throws RemoteException If the client is dying
810          */
reinit(long startTime, long startElapsedTime, @NonNull IBinder clientId, @Nullable String attributionTag, @NonNull Runnable onDeath, @AppOpsManager.UidState int uidState, @OpFlags int flags, @Nullable OpEventProxyInfo proxy, @AttributionFlags int attributionFlags, int attributionChainId, @NonNull Pools.Pool<OpEventProxyInfo> proxyPool )811         public void reinit(long startTime, long startElapsedTime, @NonNull IBinder clientId,
812                 @Nullable String attributionTag, @NonNull Runnable onDeath,
813                 @AppOpsManager.UidState int uidState, @OpFlags int flags,
814                 @Nullable OpEventProxyInfo proxy, @AttributionFlags int attributionFlags,
815                 int attributionChainId, @NonNull Pools.Pool<OpEventProxyInfo> proxyPool
816         ) throws RemoteException {
817             mStartTime = startTime;
818             mStartElapsedTime = startElapsedTime;
819             mClientId = clientId;
820             mAttributionTag = attributionTag;
821             mOnDeath = onDeath;
822             mUidState = uidState;
823             mFlags = flags;
824 
825             if (mProxy != null) {
826                 proxyPool.release(mProxy);
827             }
828             mProxy = proxy;
829             mAttributionFlags = attributionFlags;
830             mAttributionChainId = attributionChainId;
831 
832             clientId.linkToDeath(this, 0);
833         }
834 
835         /** @return Wall clock time of startOp event */
getStartTime()836         public long getStartTime() {
837             return mStartTime;
838         }
839 
840         /** @return Elapsed time since boot of startOp event */
getStartElapsedTime()841         public long getStartElapsedTime() {
842             return mStartElapsedTime;
843         }
844 
845         /** @return Id of the client that started the event */
getClientId()846         public @NonNull IBinder getClientId() {
847             return mClientId;
848         }
849 
850         /** @return uidstate used when calling startOp */
getUidState()851         public @AppOpsManager.UidState int getUidState() {
852             return mUidState;
853         }
854 
855         /** @return proxy tag for the access */
getProxy()856         public @Nullable OpEventProxyInfo getProxy() {
857             return mProxy;
858         }
859 
860         /** @return flags used for the access */
getFlags()861         public @OpFlags int getFlags() {
862             return mFlags;
863         }
864 
865         /** @return attributoin flags used for the access */
getAttributionFlags()866         public @AttributionFlags int getAttributionFlags() {
867             return mAttributionFlags;
868         }
869 
870         /** @return attribution chain id for the access */
getAttributionChainId()871         public int getAttributionChainId() {
872             return mAttributionChainId;
873         }
874     }
875 
876     private final class AttributedOp {
877         public final @Nullable String tag;
878         public final @NonNull Op parent;
879 
880         /**
881          * Last successful accesses (noteOp + finished startOp) for each uidState/opFlag combination
882          *
883          * <p>Key is {@link AppOpsManager#makeKey}
884          */
885         @GuardedBy("AppOpsService.this")
886         private @Nullable LongSparseArray<NoteOpEvent> mAccessEvents;
887 
888         /**
889          * Last rejected accesses for each uidState/opFlag combination
890          *
891          * <p>Key is {@link AppOpsManager#makeKey}
892          */
893         @GuardedBy("AppOpsService.this")
894         private @Nullable LongSparseArray<NoteOpEvent> mRejectEvents;
895 
896         /**
897          * Currently in progress startOp events
898          *
899          * <p>Key is clientId
900          */
901         @GuardedBy("AppOpsService.this")
902         private @Nullable ArrayMap<IBinder, InProgressStartOpEvent> mInProgressEvents;
903 
904         /**
905          * Currently paused startOp events
906          *
907          * <p>Key is clientId
908          */
909         @GuardedBy("AppOpsService.this")
910         private @Nullable ArrayMap<IBinder, InProgressStartOpEvent> mPausedInProgressEvents;
911 
AttributedOp(@ullable String tag, @NonNull Op parent)912         AttributedOp(@Nullable String tag, @NonNull Op parent) {
913             this.tag = tag;
914             this.parent = parent;
915         }
916 
917         /**
918          * Update state when noteOp was rejected or startOp->finishOp event finished
919          *
920          * @param proxyUid The uid of the proxy
921          * @param proxyPackageName The package name of the proxy
922          * @param proxyAttributionTag the attributionTag in the proxies package
923          * @param uidState UID state of the app noteOp/startOp was called for
924          * @param flags OpFlags of the call
925          */
accessed(int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState, @OpFlags int flags)926         public void accessed(int proxyUid, @Nullable String proxyPackageName,
927                 @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState,
928                 @OpFlags int flags) {
929             long accessTime = System.currentTimeMillis();
930             accessed(accessTime, -1, proxyUid, proxyPackageName,
931                     proxyAttributionTag, uidState, flags);
932 
933             mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName,
934                     tag, uidState, flags, accessTime, AppOpsManager.ATTRIBUTION_FLAGS_NONE,
935                     AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE);
936         }
937 
938         /**
939          * Add an access that was previously collected.
940          *
941          * @param noteTime The time of the event
942          * @param duration The duration of the event
943          * @param proxyUid The uid of the proxy
944          * @param proxyPackageName The package name of the proxy
945          * @param proxyAttributionTag the attributionTag in the proxies package
946          * @param uidState UID state of the app noteOp/startOp was called for
947          * @param flags OpFlags of the call
948          */
accessed(long noteTime, long duration, int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState, @OpFlags int flags)949         public void accessed(long noteTime, long duration, int proxyUid,
950                 @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
951                 @AppOpsManager.UidState int uidState, @OpFlags int flags) {
952             long key = makeKey(uidState, flags);
953 
954             if (mAccessEvents == null) {
955                 mAccessEvents = new LongSparseArray<>(1);
956             }
957 
958             OpEventProxyInfo proxyInfo = null;
959             if (proxyUid != Process.INVALID_UID) {
960                 proxyInfo = mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName,
961                         proxyAttributionTag);
962             }
963 
964             NoteOpEvent existingEvent = mAccessEvents.get(key);
965             if (existingEvent != null) {
966                 existingEvent.reinit(noteTime, duration, proxyInfo, mOpEventProxyInfoPool);
967             } else {
968                 mAccessEvents.put(key, new NoteOpEvent(noteTime, duration, proxyInfo));
969             }
970         }
971 
972         /**
973          * Update state when noteOp/startOp was rejected.
974          *
975          * @param uidState UID state of the app noteOp is called for
976          * @param flags OpFlags of the call
977          */
rejected(@ppOpsManager.UidState int uidState, @OpFlags int flags)978         public void rejected(@AppOpsManager.UidState int uidState, @OpFlags int flags) {
979             rejected(System.currentTimeMillis(), uidState, flags);
980 
981             mHistoricalRegistry.incrementOpRejected(parent.op, parent.uid, parent.packageName,
982                     tag, uidState, flags);
983         }
984 
985         /**
986          * Add an rejection that was previously collected
987          *
988          * @param noteTime The time of the event
989          * @param uidState UID state of the app noteOp/startOp was called for
990          * @param flags OpFlags of the call
991          */
rejected(long noteTime, @AppOpsManager.UidState int uidState, @OpFlags int flags)992         public void rejected(long noteTime, @AppOpsManager.UidState int uidState,
993                 @OpFlags int flags) {
994             long key = makeKey(uidState, flags);
995 
996             if (mRejectEvents == null) {
997                 mRejectEvents = new LongSparseArray<>(1);
998             }
999 
1000             // We do not collect proxy information for rejections yet
1001             NoteOpEvent existingEvent = mRejectEvents.get(key);
1002             if (existingEvent != null) {
1003                 existingEvent.reinit(noteTime, -1, null, mOpEventProxyInfoPool);
1004             } else {
1005                 mRejectEvents.put(key, new NoteOpEvent(noteTime, -1, null));
1006             }
1007         }
1008 
1009         /**
1010          * Update state when start was called
1011          *
1012          * @param clientId Id of the startOp caller
1013          * @param proxyUid The UID of the proxy app
1014          * @param proxyPackageName The package name of the proxy app
1015          * @param proxyAttributionTag The attribution tag of the proxy app
1016          * @param uidState UID state of the app startOp is called for
1017          * @param flags The proxy flags
1018          * @param attributionFlags The attribution flags associated with this operation.
1019          * @param attributionChainId The if of the attribution chain this operations is a part of.
1020          */
started(@onNull IBinder clientId, int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState, @OpFlags int flags, @AttributionFlags int attributionFlags, int attributionChainId)1021         public void started(@NonNull IBinder clientId, int proxyUid,
1022                 @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
1023                 @AppOpsManager.UidState int uidState, @OpFlags int flags, @AttributionFlags
1024                 int attributionFlags, int attributionChainId) throws RemoteException {
1025             started(clientId, proxyUid, proxyPackageName, proxyAttributionTag,
1026                     uidState, flags,/*triggerCallbackIfNeeded*/ true, attributionFlags,
1027                     attributionChainId);
1028         }
1029 
started(@onNull IBinder clientId, int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState, @OpFlags int flags, boolean triggerCallbackIfNeeded, @AttributionFlags int attributionFlags, int attributionChainId)1030         private void started(@NonNull IBinder clientId, int proxyUid,
1031                 @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
1032                 @AppOpsManager.UidState int uidState, @OpFlags int flags,
1033                 boolean triggerCallbackIfNeeded, @AttributionFlags int attributionFlags,
1034                 int attributionChainId) throws RemoteException {
1035             startedOrPaused(clientId, proxyUid, proxyPackageName,
1036                     proxyAttributionTag, uidState, flags, triggerCallbackIfNeeded,
1037                     /*triggerCallbackIfNeeded*/ true, attributionFlags, attributionChainId);
1038         }
1039 
startedOrPaused(@onNull IBinder clientId, int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState, @OpFlags int flags, boolean triggerCallbackIfNeeded, boolean isStarted, @AttributionFlags int attributionFlags, int attributionChainId)1040         private void startedOrPaused(@NonNull IBinder clientId, int proxyUid,
1041                 @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
1042                 @AppOpsManager.UidState int uidState, @OpFlags int flags,
1043                 boolean triggerCallbackIfNeeded, boolean isStarted, @AttributionFlags
1044                 int attributionFlags, int attributionChainId) throws RemoteException {
1045             if (triggerCallbackIfNeeded && !parent.isRunning() && isStarted) {
1046                 scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, parent.packageName,
1047                         tag, true, attributionFlags, attributionChainId);
1048             }
1049 
1050             if (isStarted && mInProgressEvents == null) {
1051                 mInProgressEvents = new ArrayMap<>(1);
1052             } else if (!isStarted && mPausedInProgressEvents == null) {
1053                 mPausedInProgressEvents = new ArrayMap<>(1);
1054             }
1055             ArrayMap<IBinder, InProgressStartOpEvent> events = isStarted
1056                     ? mInProgressEvents : mPausedInProgressEvents;
1057 
1058             long startTime = System.currentTimeMillis();
1059             InProgressStartOpEvent event = events.get(clientId);
1060             if (event == null) {
1061                 event = mInProgressStartOpEventPool.acquire(startTime,
1062                         SystemClock.elapsedRealtime(), clientId, tag,
1063                         PooledLambda.obtainRunnable(AppOpsService::onClientDeath, this, clientId),
1064                         proxyUid, proxyPackageName, proxyAttributionTag, uidState, flags,
1065                         attributionFlags, attributionChainId);
1066                 events.put(clientId, event);
1067             } else {
1068                 if (uidState != event.mUidState) {
1069                     onUidStateChanged(uidState);
1070                 }
1071             }
1072 
1073             event.numUnfinishedStarts++;
1074 
1075             if (isStarted) {
1076                 mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
1077                         parent.packageName, tag, uidState, flags, startTime, attributionFlags,
1078                         attributionChainId);
1079             }
1080         }
1081 
1082         /**
1083          * Update state when finishOp was called. Will finish started ops, and delete paused ops.
1084          *
1085          * @param clientId Id of the finishOp caller
1086          */
finished(@onNull IBinder clientId)1087         public void finished(@NonNull IBinder clientId) {
1088             finished(clientId, true);
1089         }
1090 
finished(@onNull IBinder clientId, boolean triggerCallbackIfNeeded)1091         private void finished(@NonNull IBinder clientId, boolean triggerCallbackIfNeeded) {
1092             finishOrPause(clientId, triggerCallbackIfNeeded, false);
1093         }
1094 
1095         /**
1096          * Update state when paused or finished is called. If pausing, it records the op as
1097          * stopping in the HistoricalRegistry, but does not delete it.
1098          */
finishOrPause(@onNull IBinder clientId, boolean triggerCallbackIfNeeded, boolean isPausing)1099         private void finishOrPause(@NonNull IBinder clientId, boolean triggerCallbackIfNeeded,
1100                 boolean isPausing) {
1101             int indexOfToken = isRunning() ? mInProgressEvents.indexOfKey(clientId) : -1;
1102             if (indexOfToken < 0) {
1103                 finishPossiblyPaused(clientId, isPausing);
1104                 return;
1105             }
1106 
1107             InProgressStartOpEvent event = mInProgressEvents.valueAt(indexOfToken);
1108             if (!isPausing) {
1109                 event.numUnfinishedStarts--;
1110             }
1111             // If we are pausing, create a NoteOpEvent, but don't change the InProgress event
1112             if (event.numUnfinishedStarts == 0 || isPausing) {
1113                 if (!isPausing) {
1114                     event.finish();
1115                     mInProgressEvents.removeAt(indexOfToken);
1116                 }
1117 
1118                 if (mAccessEvents == null) {
1119                     mAccessEvents = new LongSparseArray<>(1);
1120                 }
1121 
1122                 OpEventProxyInfo proxyCopy = event.getProxy() != null
1123                         ? new OpEventProxyInfo(event.getProxy()) : null;
1124 
1125                 long accessDurationMillis =
1126                         SystemClock.elapsedRealtime() - event.getStartElapsedTime();
1127                 NoteOpEvent finishedEvent = new NoteOpEvent(event.getStartTime(),
1128                         accessDurationMillis, proxyCopy);
1129                 mAccessEvents.put(makeKey(event.getUidState(), event.getFlags()),
1130                         finishedEvent);
1131 
1132                 mHistoricalRegistry.increaseOpAccessDuration(parent.op, parent.uid,
1133                         parent.packageName, tag, event.getUidState(),
1134                         event.getFlags(), finishedEvent.getNoteTime(), finishedEvent.getDuration(),
1135                         event.getAttributionFlags(), event.getAttributionChainId());
1136 
1137                 if (!isPausing) {
1138                     mInProgressStartOpEventPool.release(event);
1139                     if (mInProgressEvents.isEmpty()) {
1140                         mInProgressEvents = null;
1141 
1142                         // TODO ntmyren: Also callback for single attribution tag activity changes
1143                         if (triggerCallbackIfNeeded && !parent.isRunning()) {
1144                             scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
1145                                     parent.packageName, tag, false, event.getAttributionFlags(),
1146                                     event.getAttributionChainId());
1147                         }
1148                     }
1149                 }
1150             }
1151         }
1152 
1153         // Finish or pause (no-op) an already paused op
finishPossiblyPaused(@onNull IBinder clientId, boolean isPausing)1154         private void finishPossiblyPaused(@NonNull IBinder clientId, boolean isPausing) {
1155             if (!isPaused()) {
1156                 Slog.wtf(TAG, "No ops running or paused");
1157                 return;
1158             }
1159 
1160             int indexOfToken = mPausedInProgressEvents.indexOfKey(clientId);
1161             if (indexOfToken < 0) {
1162                 Slog.wtf(TAG, "No op running or paused for the client");
1163                 return;
1164             } else if (isPausing) {
1165                 // already paused
1166                 return;
1167             }
1168 
1169             // no need to record a paused event finishing.
1170             InProgressStartOpEvent event = mPausedInProgressEvents.valueAt(indexOfToken);
1171             event.numUnfinishedStarts--;
1172             if (event.numUnfinishedStarts == 0) {
1173                 mPausedInProgressEvents.removeAt(indexOfToken);
1174                 mInProgressStartOpEventPool.release(event);
1175                 if (mPausedInProgressEvents.isEmpty()) {
1176                     mPausedInProgressEvents = null;
1177                 }
1178             }
1179         }
1180 
1181         /**
1182          * Create an event that will be started, if the op is unpaused.
1183          */
createPaused(@onNull IBinder clientId, int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState, @OpFlags int flags, @AttributionFlags int attributionFlags, int attributionChainId)1184         public void createPaused(@NonNull IBinder clientId, int proxyUid,
1185                 @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
1186                 @AppOpsManager.UidState int uidState, @OpFlags int flags, @AttributionFlags
1187                 int attributionFlags, int attributionChainId) throws RemoteException {
1188             startedOrPaused(clientId, proxyUid, proxyPackageName, proxyAttributionTag,
1189                     uidState, flags, true, false, attributionFlags, attributionChainId);
1190         }
1191 
1192         /**
1193          * Pause all currently started ops. This will create a HistoricalRegistry
1194          */
pause()1195         public void pause() {
1196             if (!isRunning()) {
1197                 return;
1198             }
1199 
1200             if (mPausedInProgressEvents == null) {
1201                 mPausedInProgressEvents = new ArrayMap<>(1);
1202             }
1203 
1204             for (int i = 0; i < mInProgressEvents.size(); i++) {
1205                 InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
1206                 mPausedInProgressEvents.put(event.mClientId, event);
1207                 finishOrPause(event.mClientId, true, true);
1208 
1209                 scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
1210                         parent.packageName, tag, false,
1211                         event.getAttributionFlags(), event.getAttributionChainId());
1212             }
1213             mInProgressEvents = null;
1214         }
1215 
1216         /**
1217          * Unpause all currently paused ops. This will reinitialize their start and duration
1218          * times, but keep all other values the same
1219          */
resume()1220         public void resume() {
1221             if (!isPaused()) {
1222                 return;
1223             }
1224 
1225             if (mInProgressEvents == null) {
1226                 mInProgressEvents = new ArrayMap<>(mPausedInProgressEvents.size());
1227             }
1228             boolean shouldSendActive = !mPausedInProgressEvents.isEmpty()
1229                     && mInProgressEvents.isEmpty();
1230 
1231             long startTime = System.currentTimeMillis();
1232             for (int i = 0; i < mPausedInProgressEvents.size(); i++) {
1233                 InProgressStartOpEvent event = mPausedInProgressEvents.valueAt(i);
1234                 mInProgressEvents.put(event.mClientId, event);
1235                 event.mStartElapsedTime = SystemClock.elapsedRealtime();
1236                 event.mStartTime = startTime;
1237                 mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
1238                         parent.packageName, tag, event.mUidState, event.mFlags, startTime,
1239                         event.getAttributionFlags(), event.getAttributionChainId());
1240                 if (shouldSendActive) {
1241                     scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, parent.packageName,
1242                             tag, true, event.getAttributionFlags(), event.getAttributionChainId());
1243                 }
1244                 // Note: this always sends MODE_ALLOWED, even if the mode is FOREGROUND
1245                 // TODO ntmyren: figure out how to get the real mode.
1246                 scheduleOpStartedIfNeededLocked(parent.op, parent.uid, parent.packageName,
1247                         tag, event.getFlags(), MODE_ALLOWED, START_TYPE_RESUMED,
1248                         event.getAttributionFlags(), event.getAttributionChainId());
1249             }
1250             mPausedInProgressEvents = null;
1251         }
1252 
1253         /**
1254          * Called in the case the client dies without calling finish first
1255          *
1256          * @param clientId The client that died
1257          */
onClientDeath(@onNull IBinder clientId)1258         void onClientDeath(@NonNull IBinder clientId) {
1259             synchronized (AppOpsService.this) {
1260                 if (!isPaused() && !isRunning()) {
1261                     return;
1262                 }
1263 
1264                 ArrayMap<IBinder, InProgressStartOpEvent> events = isPaused()
1265                         ? mPausedInProgressEvents : mInProgressEvents;
1266                 InProgressStartOpEvent deadEvent = events.get(clientId);
1267                 if (deadEvent != null) {
1268                     deadEvent.numUnfinishedStarts = 1;
1269                 }
1270 
1271                 finished(clientId);
1272             }
1273         }
1274 
1275         /**
1276          * Notify that the state of the uid changed
1277          *
1278          * @param newState The new state
1279          */
onUidStateChanged(@ppOpsManager.UidState int newState)1280         public void onUidStateChanged(@AppOpsManager.UidState int newState) {
1281             if (!isPaused() && !isRunning()) {
1282                 return;
1283             }
1284 
1285             boolean isRunning = isRunning();
1286             ArrayMap<IBinder, AppOpsService.InProgressStartOpEvent> events =
1287                     isRunning ? mInProgressEvents : mPausedInProgressEvents;
1288 
1289             int numInProgressEvents = events.size();
1290             List<IBinder> binders = new ArrayList<>(events.keySet());
1291             for (int i = 0; i < numInProgressEvents; i++) {
1292                 InProgressStartOpEvent event = events.get(binders.get(i));
1293 
1294                 if (event != null && event.getUidState() != newState) {
1295                     try {
1296                         // Remove all but one unfinished start count and then call finished() to
1297                         // remove start event object
1298                         int numPreviousUnfinishedStarts = event.numUnfinishedStarts;
1299                         event.numUnfinishedStarts = 1;
1300                         OpEventProxyInfo proxy = event.getProxy();
1301 
1302                         finished(event.getClientId(), false);
1303 
1304                         // Call started() to add a new start event object and then add the
1305                         // previously removed unfinished start counts back
1306                         if (proxy != null) {
1307                             startedOrPaused(event.getClientId(), proxy.getUid(),
1308                                     proxy.getPackageName(), proxy.getAttributionTag(), newState,
1309                                     event.getFlags(), false, isRunning,
1310                                     event.getAttributionFlags(), event.getAttributionChainId());
1311                         } else {
1312                             startedOrPaused(event.getClientId(), Process.INVALID_UID, null, null,
1313                                     newState, event.getFlags(), false, isRunning,
1314                                     event.getAttributionFlags(), event.getAttributionChainId());
1315                         }
1316 
1317                         events = isRunning ? mInProgressEvents : mPausedInProgressEvents;
1318                         InProgressStartOpEvent newEvent = events.get(binders.get(i));
1319                         if (newEvent != null) {
1320                             newEvent.numUnfinishedStarts += numPreviousUnfinishedStarts - 1;
1321                         }
1322                     } catch (RemoteException e) {
1323                         if (DEBUG) Slog.e(TAG, "Cannot switch to new uidState " + newState);
1324                     }
1325                 }
1326             }
1327         }
1328 
1329         /**
1330          * Combine {@code a} and {@code b} and return the result. The result might be {@code a}
1331          * or {@code b}. If there is an event for the same key in both the later event is retained.
1332          */
add(@ullable LongSparseArray<NoteOpEvent> a, @Nullable LongSparseArray<NoteOpEvent> b)1333         private @Nullable LongSparseArray<NoteOpEvent> add(@Nullable LongSparseArray<NoteOpEvent> a,
1334                 @Nullable LongSparseArray<NoteOpEvent> b) {
1335             if (a == null) {
1336                 return b;
1337             }
1338 
1339             if (b == null) {
1340                 return a;
1341             }
1342 
1343             int numEventsToAdd = b.size();
1344             for (int i = 0; i < numEventsToAdd; i++) {
1345                 long keyOfEventToAdd = b.keyAt(i);
1346                 NoteOpEvent bEvent = b.valueAt(i);
1347                 NoteOpEvent aEvent = a.get(keyOfEventToAdd);
1348 
1349                 if (aEvent == null || bEvent.getNoteTime() > aEvent.getNoteTime()) {
1350                     a.put(keyOfEventToAdd, bEvent);
1351                 }
1352             }
1353 
1354             return a;
1355         }
1356 
1357         /**
1358          * Add all data from the {@code opToAdd} to this op.
1359          *
1360          * <p>If there is an event for the same key in both the later event is retained.
1361          * <p>{@code opToAdd} should not be used after this method is called.
1362          *
1363          * @param opToAdd The op to add
1364          */
add(@onNull AttributedOp opToAdd)1365         public void add(@NonNull AttributedOp opToAdd) {
1366             if (opToAdd.isRunning() || opToAdd.isPaused()) {
1367                 ArrayMap<IBinder, InProgressStartOpEvent> ignoredEvents = opToAdd.isRunning()
1368                         ? opToAdd.mInProgressEvents : opToAdd.mPausedInProgressEvents;
1369                 Slog.w(TAG, "Ignoring " + ignoredEvents.size() + " app-ops, running: "
1370                         + opToAdd.isRunning());
1371 
1372                 int numInProgressEvents = ignoredEvents.size();
1373                 for (int i = 0; i < numInProgressEvents; i++) {
1374                     InProgressStartOpEvent event = ignoredEvents.valueAt(i);
1375 
1376                     event.finish();
1377                     mInProgressStartOpEventPool.release(event);
1378                 }
1379             }
1380 
1381             mAccessEvents = add(mAccessEvents, opToAdd.mAccessEvents);
1382             mRejectEvents = add(mRejectEvents, opToAdd.mRejectEvents);
1383         }
1384 
isRunning()1385         public boolean isRunning() {
1386             return mInProgressEvents != null && !mInProgressEvents.isEmpty();
1387         }
1388 
isPaused()1389         public boolean isPaused() {
1390             return mPausedInProgressEvents != null && !mPausedInProgressEvents.isEmpty();
1391         }
1392 
hasAnyTime()1393         boolean hasAnyTime() {
1394             return (mAccessEvents != null && mAccessEvents.size() > 0)
1395                     || (mRejectEvents != null && mRejectEvents.size() > 0);
1396         }
1397 
1398         /**
1399          * Clone a {@link LongSparseArray} and clone all values.
1400          */
deepClone( @ullable LongSparseArray<NoteOpEvent> original)1401         private @Nullable LongSparseArray<NoteOpEvent> deepClone(
1402                 @Nullable LongSparseArray<NoteOpEvent> original) {
1403             if (original == null) {
1404                 return original;
1405             }
1406 
1407             int size = original.size();
1408             LongSparseArray<NoteOpEvent> clone = new LongSparseArray<>(size);
1409             for (int i = 0; i < size; i++) {
1410                 clone.put(original.keyAt(i), new NoteOpEvent(original.valueAt(i)));
1411             }
1412 
1413             return clone;
1414         }
1415 
createAttributedOpEntryLocked()1416         @NonNull AttributedOpEntry createAttributedOpEntryLocked() {
1417             LongSparseArray<NoteOpEvent> accessEvents = deepClone(mAccessEvents);
1418 
1419             // Add in progress events as access events
1420             if (isRunning()) {
1421                 long now = SystemClock.elapsedRealtime();
1422                 int numInProgressEvents = mInProgressEvents.size();
1423 
1424                 if (accessEvents == null) {
1425                     accessEvents = new LongSparseArray<>(numInProgressEvents);
1426                 }
1427 
1428                 for (int i = 0; i < numInProgressEvents; i++) {
1429                     InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
1430 
1431                     accessEvents.append(makeKey(event.getUidState(), event.getFlags()),
1432                             new NoteOpEvent(event.getStartTime(), now - event.getStartElapsedTime(),
1433                                     event.getProxy()));
1434                 }
1435             }
1436 
1437             LongSparseArray<NoteOpEvent> rejectEvents = deepClone(mRejectEvents);
1438 
1439             return new AttributedOpEntry(parent.op, isRunning(), accessEvents, rejectEvents);
1440         }
1441     }
1442 
1443     final class Op {
1444         int op;
1445         int uid;
1446         final UidState uidState;
1447         final @NonNull String packageName;
1448 
1449         private @Mode int mode;
1450 
1451         /** attributionTag -> AttributedOp */
1452         final ArrayMap<String, AttributedOp> mAttributions = new ArrayMap<>(1);
1453 
Op(UidState uidState, String packageName, int op, int uid)1454         Op(UidState uidState, String packageName, int op, int uid) {
1455             this.op = op;
1456             this.uid = uid;
1457             this.uidState = uidState;
1458             this.packageName = packageName;
1459             this.mode = AppOpsManager.opToDefaultMode(op);
1460         }
1461 
getMode()1462         int getMode() {
1463             return mode;
1464         }
1465 
evalMode()1466         int evalMode() {
1467             return uidState.evalMode(op, mode);
1468         }
1469 
removeAttributionsWithNoTime()1470         void removeAttributionsWithNoTime() {
1471             for (int i = mAttributions.size() - 1; i >= 0; i--) {
1472                 if (!mAttributions.valueAt(i).hasAnyTime()) {
1473                     mAttributions.removeAt(i);
1474                 }
1475             }
1476         }
1477 
getOrCreateAttribution(@onNull Op parent, @Nullable String attributionTag)1478         private @NonNull AttributedOp getOrCreateAttribution(@NonNull Op parent,
1479                 @Nullable String attributionTag) {
1480             AttributedOp attributedOp;
1481 
1482             attributedOp = mAttributions.get(attributionTag);
1483             if (attributedOp == null) {
1484                 attributedOp = new AttributedOp(attributionTag, parent);
1485                 mAttributions.put(attributionTag, attributedOp);
1486             }
1487 
1488             return attributedOp;
1489         }
1490 
createEntryLocked()1491         @NonNull OpEntry createEntryLocked() {
1492             final int numAttributions = mAttributions.size();
1493 
1494             final ArrayMap<String, AppOpsManager.AttributedOpEntry> attributionEntries =
1495                     new ArrayMap<>(numAttributions);
1496             for (int i = 0; i < numAttributions; i++) {
1497                 attributionEntries.put(mAttributions.keyAt(i),
1498                         mAttributions.valueAt(i).createAttributedOpEntryLocked());
1499             }
1500 
1501             return new OpEntry(op, mode, attributionEntries);
1502         }
1503 
createSingleAttributionEntryLocked(@ullable String attributionTag)1504         @NonNull OpEntry createSingleAttributionEntryLocked(@Nullable String attributionTag) {
1505             final int numAttributions = mAttributions.size();
1506 
1507             final ArrayMap<String, AttributedOpEntry> attributionEntries = new ArrayMap<>(1);
1508             for (int i = 0; i < numAttributions; i++) {
1509                 if (Objects.equals(mAttributions.keyAt(i), attributionTag)) {
1510                     attributionEntries.put(mAttributions.keyAt(i),
1511                             mAttributions.valueAt(i).createAttributedOpEntryLocked());
1512                     break;
1513                 }
1514             }
1515 
1516             return new OpEntry(op, mode, attributionEntries);
1517         }
1518 
isRunning()1519         boolean isRunning() {
1520             final int numAttributions = mAttributions.size();
1521             for (int i = 0; i < numAttributions; i++) {
1522                 if (mAttributions.valueAt(i).isRunning()) {
1523                     return true;
1524                 }
1525             }
1526 
1527             return false;
1528         }
1529     }
1530 
1531     final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
1532     final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
1533     final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
1534     final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
1535     final ArrayMap<IBinder, SparseArray<StartedCallback>> mStartedWatchers = new ArrayMap<>();
1536     final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>();
1537     final AudioRestrictionManager mAudioRestrictionManager = new AudioRestrictionManager();
1538 
1539     final class ModeCallback implements DeathRecipient {
1540         /** If mWatchedOpCode==ALL_OPS notify for ops affected by the switch-op */
1541         public static final int ALL_OPS = -2;
1542 
1543         final IAppOpsCallback mCallback;
1544         final int mWatchingUid;
1545         final int mFlags;
1546         final int mWatchedOpCode;
1547         final int mCallingUid;
1548         final int mCallingPid;
1549 
ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int watchedOp, int callingUid, int callingPid)1550         ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int watchedOp,
1551                 int callingUid, int callingPid) {
1552             mCallback = callback;
1553             mWatchingUid = watchingUid;
1554             mFlags = flags;
1555             mWatchedOpCode = watchedOp;
1556             mCallingUid = callingUid;
1557             mCallingPid = callingPid;
1558             try {
1559                 mCallback.asBinder().linkToDeath(this, 0);
1560             } catch (RemoteException e) {
1561                 /*ignored*/
1562             }
1563         }
1564 
isWatchingUid(int uid)1565         public boolean isWatchingUid(int uid) {
1566             return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
1567         }
1568 
1569         @Override
toString()1570         public String toString() {
1571             StringBuilder sb = new StringBuilder(128);
1572             sb.append("ModeCallback{");
1573             sb.append(Integer.toHexString(System.identityHashCode(this)));
1574             sb.append(" watchinguid=");
1575             UserHandle.formatUid(sb, mWatchingUid);
1576             sb.append(" flags=0x");
1577             sb.append(Integer.toHexString(mFlags));
1578             switch (mWatchedOpCode) {
1579                 case OP_NONE:
1580                     break;
1581                 case ALL_OPS:
1582                     sb.append(" op=(all)");
1583                     break;
1584                 default:
1585                     sb.append(" op=");
1586                     sb.append(opToName(mWatchedOpCode));
1587                     break;
1588             }
1589             sb.append(" from uid=");
1590             UserHandle.formatUid(sb, mCallingUid);
1591             sb.append(" pid=");
1592             sb.append(mCallingPid);
1593             sb.append('}');
1594             return sb.toString();
1595         }
1596 
unlinkToDeath()1597         void unlinkToDeath() {
1598             mCallback.asBinder().unlinkToDeath(this, 0);
1599         }
1600 
1601         @Override
binderDied()1602         public void binderDied() {
1603             stopWatchingMode(mCallback);
1604         }
1605     }
1606 
1607     final class ActiveCallback implements DeathRecipient {
1608         final IAppOpsActiveCallback mCallback;
1609         final int mWatchingUid;
1610         final int mCallingUid;
1611         final int mCallingPid;
1612 
ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid, int callingPid)1613         ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
1614                 int callingPid) {
1615             mCallback = callback;
1616             mWatchingUid = watchingUid;
1617             mCallingUid = callingUid;
1618             mCallingPid = callingPid;
1619             try {
1620                 mCallback.asBinder().linkToDeath(this, 0);
1621             } catch (RemoteException e) {
1622                 /*ignored*/
1623             }
1624         }
1625 
1626         @Override
toString()1627         public String toString() {
1628             StringBuilder sb = new StringBuilder(128);
1629             sb.append("ActiveCallback{");
1630             sb.append(Integer.toHexString(System.identityHashCode(this)));
1631             sb.append(" watchinguid=");
1632             UserHandle.formatUid(sb, mWatchingUid);
1633             sb.append(" from uid=");
1634             UserHandle.formatUid(sb, mCallingUid);
1635             sb.append(" pid=");
1636             sb.append(mCallingPid);
1637             sb.append('}');
1638             return sb.toString();
1639         }
1640 
destroy()1641         void destroy() {
1642             mCallback.asBinder().unlinkToDeath(this, 0);
1643         }
1644 
1645         @Override
binderDied()1646         public void binderDied() {
1647             stopWatchingActive(mCallback);
1648         }
1649     }
1650 
1651     final class StartedCallback implements DeathRecipient {
1652         final IAppOpsStartedCallback mCallback;
1653         final int mWatchingUid;
1654         final int mCallingUid;
1655         final int mCallingPid;
1656 
StartedCallback(IAppOpsStartedCallback callback, int watchingUid, int callingUid, int callingPid)1657         StartedCallback(IAppOpsStartedCallback callback, int watchingUid, int callingUid,
1658                 int callingPid) {
1659             mCallback = callback;
1660             mWatchingUid = watchingUid;
1661             mCallingUid = callingUid;
1662             mCallingPid = callingPid;
1663             try {
1664                 mCallback.asBinder().linkToDeath(this, 0);
1665             } catch (RemoteException e) {
1666                 /*ignored*/
1667             }
1668         }
1669 
1670         @Override
toString()1671         public String toString() {
1672             StringBuilder sb = new StringBuilder(128);
1673             sb.append("StartedCallback{");
1674             sb.append(Integer.toHexString(System.identityHashCode(this)));
1675             sb.append(" watchinguid=");
1676             UserHandle.formatUid(sb, mWatchingUid);
1677             sb.append(" from uid=");
1678             UserHandle.formatUid(sb, mCallingUid);
1679             sb.append(" pid=");
1680             sb.append(mCallingPid);
1681             sb.append('}');
1682             return sb.toString();
1683         }
1684 
destroy()1685         void destroy() {
1686             mCallback.asBinder().unlinkToDeath(this, 0);
1687         }
1688 
1689         @Override
binderDied()1690         public void binderDied() {
1691             stopWatchingStarted(mCallback);
1692         }
1693     }
1694 
1695     final class NotedCallback implements DeathRecipient {
1696         final IAppOpsNotedCallback mCallback;
1697         final int mWatchingUid;
1698         final int mCallingUid;
1699         final int mCallingPid;
1700 
NotedCallback(IAppOpsNotedCallback callback, int watchingUid, int callingUid, int callingPid)1701         NotedCallback(IAppOpsNotedCallback callback, int watchingUid, int callingUid,
1702                 int callingPid) {
1703             mCallback = callback;
1704             mWatchingUid = watchingUid;
1705             mCallingUid = callingUid;
1706             mCallingPid = callingPid;
1707             try {
1708                 mCallback.asBinder().linkToDeath(this, 0);
1709             } catch (RemoteException e) {
1710                 /*ignored*/
1711             }
1712         }
1713 
1714         @Override
toString()1715         public String toString() {
1716             StringBuilder sb = new StringBuilder(128);
1717             sb.append("NotedCallback{");
1718             sb.append(Integer.toHexString(System.identityHashCode(this)));
1719             sb.append(" watchinguid=");
1720             UserHandle.formatUid(sb, mWatchingUid);
1721             sb.append(" from uid=");
1722             UserHandle.formatUid(sb, mCallingUid);
1723             sb.append(" pid=");
1724             sb.append(mCallingPid);
1725             sb.append('}');
1726             return sb.toString();
1727         }
1728 
destroy()1729         void destroy() {
1730             mCallback.asBinder().unlinkToDeath(this, 0);
1731         }
1732 
1733         @Override
binderDied()1734         public void binderDied() {
1735             stopWatchingNoted(mCallback);
1736         }
1737     }
1738 
1739     /**
1740      * Call {@link AttributedOp#onClientDeath attributedOp.onClientDeath(clientId)}.
1741      */
onClientDeath(@onNull AttributedOp attributedOp, @NonNull IBinder clientId)1742     private static void onClientDeath(@NonNull AttributedOp attributedOp,
1743             @NonNull IBinder clientId) {
1744         attributedOp.onClientDeath(clientId);
1745     }
1746 
1747 
1748     /**
1749      * Loads the OpsValidation file results into a hashmap {@link #mNoteOpCallerStacktraces}
1750      * so that we do not log the same operation twice between instances
1751      */
readNoteOpCallerStackTraces()1752     private void readNoteOpCallerStackTraces() {
1753         try {
1754             if (!mNoteOpCallerStacktracesFile.exists()) {
1755                 mNoteOpCallerStacktracesFile.createNewFile();
1756                 return;
1757             }
1758 
1759             try (Scanner read = new Scanner(mNoteOpCallerStacktracesFile)) {
1760                 read.useDelimiter("\\},");
1761                 while (read.hasNext()) {
1762                     String jsonOps = read.next();
1763                     mNoteOpCallerStacktraces.add(NoteOpTrace.fromJson(jsonOps));
1764                 }
1765             }
1766         } catch (Exception e) {
1767             Slog.e(TAG, "Cannot parse traces noteOps", e);
1768         }
1769     }
1770 
AppOpsService(File storagePath, Handler handler, Context context)1771     public AppOpsService(File storagePath, Handler handler, Context context) {
1772         mContext = context;
1773 
1774         LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
1775         mFile = new AtomicFile(storagePath, "appops");
1776         if (AppOpsManager.NOTE_OP_COLLECTION_ENABLED) {
1777             mNoteOpCallerStacktracesFile = new File(SystemServiceManager.ensureSystemDir(),
1778                     "noteOpStackTraces.json");
1779             readNoteOpCallerStackTraces();
1780         } else {
1781             mNoteOpCallerStacktracesFile = null;
1782         }
1783         mHandler = handler;
1784         mConstants = new Constants(mHandler);
1785         readState();
1786 
1787         for (int switchedCode = 0; switchedCode < _NUM_OP; switchedCode++) {
1788             int switchCode = AppOpsManager.opToSwitch(switchedCode);
1789             mSwitchedOps.put(switchCode,
1790                     ArrayUtils.appendInt(mSwitchedOps.get(switchCode), switchedCode));
1791         }
1792     }
1793 
publish()1794     public void publish() {
1795         ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
1796         LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
1797     }
1798 
1799     /** Handler for work when packages are removed or updated */
1800     private BroadcastReceiver mOnPackageUpdatedReceiver = new BroadcastReceiver() {
1801         @Override
1802         public void onReceive(Context context, Intent intent) {
1803             String action = intent.getAction();
1804             String pkgName = intent.getData().getEncodedSchemeSpecificPart();
1805             int uid = intent.getIntExtra(Intent.EXTRA_UID, Process.INVALID_UID);
1806 
1807             if (action.equals(ACTION_PACKAGE_REMOVED) && !intent.hasExtra(EXTRA_REPLACING)) {
1808                 synchronized (AppOpsService.this) {
1809                     UidState uidState = mUidStates.get(uid);
1810                     if (uidState == null || uidState.pkgOps == null) {
1811                         return;
1812                     }
1813 
1814                     Ops removedOps = uidState.pkgOps.remove(pkgName);
1815                     if (removedOps != null) {
1816                         scheduleFastWriteLocked();
1817                     }
1818                 }
1819             } else if (action.equals(Intent.ACTION_PACKAGE_REPLACED)) {
1820                 AndroidPackage pkg = getPackageManagerInternal().getPackage(pkgName);
1821                 if (pkg == null) {
1822                     return;
1823                 }
1824 
1825                 ArrayMap<String, String> dstAttributionTags = new ArrayMap<>();
1826                 ArraySet<String> attributionTags = new ArraySet<>();
1827                 attributionTags.add(null);
1828                 if (pkg.getAttributions() != null) {
1829                     int numAttributions = pkg.getAttributions().size();
1830                     for (int attributionNum = 0; attributionNum < numAttributions;
1831                             attributionNum++) {
1832                         ParsedAttribution attribution = pkg.getAttributions().get(attributionNum);
1833                         attributionTags.add(attribution.tag);
1834 
1835                         int numInheritFrom = attribution.inheritFrom.size();
1836                         for (int inheritFromNum = 0; inheritFromNum < numInheritFrom;
1837                                 inheritFromNum++) {
1838                             dstAttributionTags.put(attribution.inheritFrom.get(inheritFromNum),
1839                                     attribution.tag);
1840                         }
1841                     }
1842                 }
1843 
1844                 synchronized (AppOpsService.this) {
1845                     UidState uidState = mUidStates.get(uid);
1846                     if (uidState == null || uidState.pkgOps == null) {
1847                         return;
1848                     }
1849 
1850                     Ops ops = uidState.pkgOps.get(pkgName);
1851                     if (ops == null) {
1852                         return;
1853                     }
1854 
1855                     // Reset cached package properties to re-initialize when needed
1856                     ops.bypass = null;
1857                     ops.knownAttributionTags.clear();
1858 
1859                     // Merge data collected for removed attributions into their successor
1860                     // attributions
1861                     int numOps = ops.size();
1862                     for (int opNum = 0; opNum < numOps; opNum++) {
1863                         Op op = ops.valueAt(opNum);
1864 
1865                         int numAttributions = op.mAttributions.size();
1866                         for (int attributionNum = numAttributions - 1; attributionNum >= 0;
1867                                 attributionNum--) {
1868                             String attributionTag = op.mAttributions.keyAt(attributionNum);
1869 
1870                             if (attributionTags.contains(attributionTag)) {
1871                                 // attribution still exist after upgrade
1872                                 continue;
1873                             }
1874 
1875                             String newAttributionTag = dstAttributionTags.get(attributionTag);
1876 
1877                             AttributedOp newAttributedOp = op.getOrCreateAttribution(op,
1878                                     newAttributionTag);
1879                             newAttributedOp.add(op.mAttributions.valueAt(attributionNum));
1880                             op.mAttributions.removeAt(attributionNum);
1881 
1882                             scheduleFastWriteLocked();
1883                         }
1884                     }
1885                 }
1886             }
1887         }
1888     };
1889 
systemReady()1890     public void systemReady() {
1891         mConstants.startMonitoring(mContext.getContentResolver());
1892         mHistoricalRegistry.systemReady(mContext.getContentResolver());
1893 
1894         IntentFilter packageUpdateFilter = new IntentFilter();
1895         packageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1896         packageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
1897         packageUpdateFilter.addDataScheme("package");
1898 
1899         mContext.registerReceiverAsUser(mOnPackageUpdatedReceiver, UserHandle.ALL,
1900                 packageUpdateFilter, null, null);
1901 
1902         synchronized (this) {
1903             for (int uidNum = mUidStates.size() - 1; uidNum >= 0; uidNum--) {
1904                 int uid = mUidStates.keyAt(uidNum);
1905                 UidState uidState = mUidStates.valueAt(uidNum);
1906 
1907                 String[] pkgsInUid = getPackagesForUid(uidState.uid);
1908                 if (ArrayUtils.isEmpty(pkgsInUid)) {
1909                     uidState.clear();
1910                     mUidStates.removeAt(uidNum);
1911                     scheduleFastWriteLocked();
1912                     continue;
1913                 }
1914 
1915                 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
1916                 if (pkgs == null) {
1917                     continue;
1918                 }
1919 
1920                 int numPkgs = pkgs.size();
1921                 for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
1922                     String pkg = pkgs.keyAt(pkgNum);
1923 
1924                     String action;
1925                     if (!ArrayUtils.contains(pkgsInUid, pkg)) {
1926                         action = Intent.ACTION_PACKAGE_REMOVED;
1927                     } else {
1928                         action = Intent.ACTION_PACKAGE_REPLACED;
1929                     }
1930 
1931                     SystemServerInitThreadPool.submit(
1932                             () -> mOnPackageUpdatedReceiver.onReceive(mContext, new Intent(action)
1933                                     .setData(Uri.fromParts("package", pkg, null))
1934                                     .putExtra(Intent.EXTRA_UID, uid)),
1935                             "Update app-ops uidState in case package " + pkg + " changed");
1936                 }
1937             }
1938         }
1939 
1940         final IntentFilter packageSuspendFilter = new IntentFilter();
1941         packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
1942         packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1943         mContext.registerReceiverAsUser(new BroadcastReceiver() {
1944             @Override
1945             public void onReceive(Context context, Intent intent) {
1946                 final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1947                 final String[] changedPkgs = intent.getStringArrayExtra(
1948                         Intent.EXTRA_CHANGED_PACKAGE_LIST);
1949                 for (int code : OPS_RESTRICTED_ON_SUSPEND) {
1950                     ArraySet<ModeCallback> callbacks;
1951                     synchronized (AppOpsService.this) {
1952                         callbacks = mOpModeWatchers.get(code);
1953                         if (callbacks == null) {
1954                             continue;
1955                         }
1956                         callbacks = new ArraySet<>(callbacks);
1957                     }
1958                     for (int i = 0; i < changedUids.length; i++) {
1959                         final int changedUid = changedUids[i];
1960                         final String changedPkg = changedPkgs[i];
1961                         // We trust packagemanager to insert matching uid and packageNames in the
1962                         // extras
1963                         notifyOpChanged(callbacks, code, changedUid, changedPkg);
1964                     }
1965                 }
1966             }
1967         }, UserHandle.ALL, packageSuspendFilter, null, null);
1968 
1969         final IntentFilter packageAddedFilter = new IntentFilter();
1970         packageAddedFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1971         packageAddedFilter.addDataScheme("package");
1972         mContext.registerReceiver(new BroadcastReceiver() {
1973             @Override
1974             public void onReceive(Context context, Intent intent) {
1975                 final Uri data = intent.getData();
1976 
1977                 final String packageName = data.getSchemeSpecificPart();
1978                 PackageInfo pi = getPackageManagerInternal().getPackageInfo(packageName,
1979                         PackageManager.GET_PERMISSIONS, Process.myUid(), mContext.getUserId());
1980                 if (isSamplingTarget(pi)) {
1981                     synchronized (this) {
1982                         mRarelyUsedPackages.add(packageName);
1983                     }
1984                 }
1985             }
1986         }, packageAddedFilter);
1987 
1988         mHandler.postDelayed(new Runnable() {
1989             @Override
1990             public void run() {
1991                 List<String> packageNames = getPackageListAndResample();
1992                 initializeRarelyUsedPackagesList(new ArraySet<>(packageNames));
1993             }
1994         }, RARELY_USED_PACKAGES_INITIALIZATION_DELAY_MILLIS);
1995 
1996         getPackageManagerInternal().setExternalSourcesPolicy(
1997                 new PackageManagerInternal.ExternalSourcesPolicy() {
1998                     @Override
1999                     public int getPackageTrustedToInstallApps(String packageName, int uid) {
2000                         int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
2001                                 uid, packageName);
2002                         switch (appOpMode) {
2003                             case AppOpsManager.MODE_ALLOWED:
2004                                 return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
2005                             case AppOpsManager.MODE_ERRORED:
2006                                 return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
2007                             default:
2008                                 return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
2009                         }
2010                     }
2011                 });
2012 
2013         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
2014     }
2015 
2016     /**
2017      * Sets a policy for handling app ops.
2018      *
2019      * @param policy The policy.
2020      */
setAppOpsPolicy(@ullable CheckOpsDelegate policy)2021     public void setAppOpsPolicy(@Nullable CheckOpsDelegate policy) {
2022         final CheckOpsDelegateDispatcher oldDispatcher = mCheckOpsDelegateDispatcher;
2023         final CheckOpsDelegate delegate = (oldDispatcher != null)
2024                 ? oldDispatcher.mCheckOpsDelegate : null;
2025         mCheckOpsDelegateDispatcher = new CheckOpsDelegateDispatcher(policy, delegate);
2026     }
2027 
packageRemoved(int uid, String packageName)2028     public void packageRemoved(int uid, String packageName) {
2029         synchronized (this) {
2030             UidState uidState = mUidStates.get(uid);
2031             if (uidState == null) {
2032                 return;
2033             }
2034 
2035             Ops ops = null;
2036 
2037             // Remove any package state if such.
2038             if (uidState.pkgOps != null) {
2039                 ops = uidState.pkgOps.remove(packageName);
2040             }
2041 
2042             // If we just nuked the last package state check if the UID is valid.
2043             if (ops != null && uidState.pkgOps.isEmpty()
2044                     && getPackagesForUid(uid).length <= 0) {
2045                 mUidStates.remove(uid);
2046             }
2047 
2048             if (ops != null) {
2049                 scheduleFastWriteLocked();
2050 
2051                 final int numOps = ops.size();
2052                 for (int opNum = 0; opNum < numOps; opNum++) {
2053                     final Op op = ops.valueAt(opNum);
2054 
2055                     final int numAttributions = op.mAttributions.size();
2056                     for (int attributionNum = 0; attributionNum < numAttributions;
2057                             attributionNum++) {
2058                         AttributedOp attributedOp = op.mAttributions.valueAt(attributionNum);
2059 
2060                         while (attributedOp.isRunning()) {
2061                             attributedOp.finished(attributedOp.mInProgressEvents.keyAt(0));
2062                         }
2063                         while (attributedOp.isPaused()) {
2064                             attributedOp.finished(attributedOp.mPausedInProgressEvents.keyAt(0));
2065                         }
2066                     }
2067                 }
2068             }
2069         }
2070 
2071         mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::clearHistory,
2072                     mHistoricalRegistry, uid, packageName));
2073     }
2074 
uidRemoved(int uid)2075     public void uidRemoved(int uid) {
2076         synchronized (this) {
2077             if (mUidStates.indexOfKey(uid) >= 0) {
2078                 mUidStates.remove(uid);
2079                 scheduleFastWriteLocked();
2080             }
2081         }
2082     }
2083 
2084     /**
2085      * Update the pending state for the uid
2086      *
2087      * @param currentTime The current elapsed real time
2088      * @param uid The uid that has a pending state
2089      */
updatePendingState(long currentTime, int uid)2090     private void updatePendingState(long currentTime, int uid) {
2091         synchronized (this) {
2092             mLastRealtime = max(currentTime, mLastRealtime);
2093             updatePendingStateIfNeededLocked(mUidStates.get(uid));
2094         }
2095     }
2096 
updateUidProcState(int uid, int procState, @ActivityManager.ProcessCapability int capability)2097     public void updateUidProcState(int uid, int procState,
2098             @ActivityManager.ProcessCapability int capability) {
2099         synchronized (this) {
2100             final UidState uidState = getUidStateLocked(uid, true);
2101             final int newState = PROCESS_STATE_TO_UID_STATE[procState];
2102             if (uidState != null && (uidState.pendingState != newState
2103                     || uidState.pendingCapability != capability)) {
2104                 final int oldPendingState = uidState.pendingState;
2105                 uidState.pendingState = newState;
2106                 uidState.pendingCapability = capability;
2107                 if (newState < uidState.state
2108                         || (newState <= UID_STATE_MAX_LAST_NON_RESTRICTED
2109                                 && uidState.state > UID_STATE_MAX_LAST_NON_RESTRICTED)) {
2110                     // We are moving to a more important state, or the new state may be in the
2111                     // foreground and the old state is in the background, then always do it
2112                     // immediately.
2113                     commitUidPendingStateLocked(uidState);
2114                 } else if (newState == uidState.state && capability != uidState.capability) {
2115                     // No change on process state, but process capability has changed.
2116                     commitUidPendingStateLocked(uidState);
2117                 } else if (uidState.pendingStateCommitTime == 0) {
2118                     // We are moving to a less important state for the first time,
2119                     // delay the application for a bit.
2120                     final long settleTime;
2121                     if (uidState.state <= UID_STATE_TOP) {
2122                         settleTime = mConstants.TOP_STATE_SETTLE_TIME;
2123                     } else if (uidState.state <= UID_STATE_FOREGROUND_SERVICE) {
2124                         settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
2125                     } else {
2126                         settleTime = mConstants.BG_STATE_SETTLE_TIME;
2127                     }
2128                     final long commitTime = SystemClock.elapsedRealtime() + settleTime;
2129                     uidState.pendingStateCommitTime = commitTime;
2130 
2131                     mHandler.sendMessageDelayed(
2132                             PooledLambda.obtainMessage(AppOpsService::updatePendingState, this,
2133                                     commitTime + 1, uid), settleTime + 1);
2134                 }
2135 
2136                 if (uidState.pkgOps != null) {
2137                     int numPkgs = uidState.pkgOps.size();
2138                     for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
2139                         Ops ops = uidState.pkgOps.valueAt(pkgNum);
2140 
2141                         int numOps = ops.size();
2142                         for (int opNum = 0; opNum < numOps; opNum++) {
2143                             Op op = ops.valueAt(opNum);
2144 
2145                             int numAttributions = op.mAttributions.size();
2146                             for (int attributionNum = 0; attributionNum < numAttributions;
2147                                     attributionNum++) {
2148                                 AttributedOp attributedOp = op.mAttributions.valueAt(
2149                                         attributionNum);
2150 
2151                                 attributedOp.onUidStateChanged(newState);
2152                             }
2153                         }
2154                     }
2155                 }
2156             }
2157         }
2158     }
2159 
shutdown()2160     public void shutdown() {
2161         Slog.w(TAG, "Writing app ops before shutdown...");
2162         boolean doWrite = false;
2163         synchronized (this) {
2164             if (mWriteScheduled) {
2165                 mWriteScheduled = false;
2166                 mFastWriteScheduled = false;
2167                 mHandler.removeCallbacks(mWriteRunner);
2168                 doWrite = true;
2169             }
2170         }
2171         if (doWrite) {
2172             writeState();
2173         }
2174         if (AppOpsManager.NOTE_OP_COLLECTION_ENABLED && mWriteNoteOpsScheduled) {
2175             writeNoteOps();
2176         }
2177 
2178         mHistoricalRegistry.shutdown();
2179     }
2180 
collectOps(Ops pkgOps, int[] ops)2181     private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
2182         ArrayList<AppOpsManager.OpEntry> resOps = null;
2183         final long elapsedNow = SystemClock.elapsedRealtime();
2184         if (ops == null) {
2185             resOps = new ArrayList<>();
2186             for (int j=0; j<pkgOps.size(); j++) {
2187                 Op curOp = pkgOps.valueAt(j);
2188                 resOps.add(getOpEntryForResult(curOp, elapsedNow));
2189             }
2190         } else {
2191             for (int j=0; j<ops.length; j++) {
2192                 Op curOp = pkgOps.get(ops[j]);
2193                 if (curOp != null) {
2194                     if (resOps == null) {
2195                         resOps = new ArrayList<>();
2196                     }
2197                     resOps.add(getOpEntryForResult(curOp, elapsedNow));
2198                 }
2199             }
2200         }
2201         return resOps;
2202     }
2203 
2204     @Nullable
collectUidOps(@onNull UidState uidState, @Nullable int[] ops)2205     private ArrayList<AppOpsManager.OpEntry> collectUidOps(@NonNull UidState uidState,
2206             @Nullable int[] ops) {
2207         if (uidState.opModes == null) {
2208             return null;
2209         }
2210 
2211         int opModeCount = uidState.opModes.size();
2212         if (opModeCount == 0) {
2213             return null;
2214         }
2215         ArrayList<AppOpsManager.OpEntry> resOps = null;
2216         if (ops == null) {
2217             resOps = new ArrayList<>();
2218             for (int i = 0; i < opModeCount; i++) {
2219                 int code = uidState.opModes.keyAt(i);
2220                 resOps.add(new OpEntry(code, uidState.opModes.get(code), Collections.emptyMap()));
2221             }
2222         } else {
2223             for (int j=0; j<ops.length; j++) {
2224                 int code = ops[j];
2225                 if (uidState.opModes.indexOfKey(code) >= 0) {
2226                     if (resOps == null) {
2227                         resOps = new ArrayList<>();
2228                     }
2229                     resOps.add(new OpEntry(code, uidState.opModes.get(code),
2230                             Collections.emptyMap()));
2231                 }
2232             }
2233         }
2234         return resOps;
2235     }
2236 
getOpEntryForResult(@onNull Op op, long elapsedNow)2237     private static @NonNull OpEntry getOpEntryForResult(@NonNull Op op, long elapsedNow) {
2238         return op.createEntryLocked();
2239     }
2240 
2241     @Override
getPackagesForOps(int[] ops)2242     public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
2243         final int callingUid = Binder.getCallingUid();
2244         final boolean hasAllPackageAccess = mContext.checkPermission(
2245                 Manifest.permission.GET_APP_OPS_STATS, Binder.getCallingPid(),
2246                 Binder.getCallingUid(), null) == PackageManager.PERMISSION_GRANTED;
2247         ArrayList<AppOpsManager.PackageOps> res = null;
2248         synchronized (this) {
2249             final int uidStateCount = mUidStates.size();
2250             for (int i = 0; i < uidStateCount; i++) {
2251                 UidState uidState = mUidStates.valueAt(i);
2252                 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
2253                     continue;
2254                 }
2255                 ArrayMap<String, Ops> packages = uidState.pkgOps;
2256                 final int packageCount = packages.size();
2257                 for (int j = 0; j < packageCount; j++) {
2258                     Ops pkgOps = packages.valueAt(j);
2259                     ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
2260                     if (resOps != null) {
2261                         if (res == null) {
2262                             res = new ArrayList<>();
2263                         }
2264                         AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
2265                                 pkgOps.packageName, pkgOps.uidState.uid, resOps);
2266                         // Caller can always see their packages and with a permission all.
2267                         if (hasAllPackageAccess || callingUid == pkgOps.uidState.uid) {
2268                             res.add(resPackage);
2269                         }
2270                     }
2271                 }
2272             }
2273         }
2274         return res;
2275     }
2276 
2277     @Override
getOpsForPackage(int uid, String packageName, int[] ops)2278     public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
2279             int[] ops) {
2280         enforceGetAppOpsStatsPermissionIfNeeded(uid,packageName);
2281         String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
2282         if (resolvedPackageName == null) {
2283             return Collections.emptyList();
2284         }
2285         synchronized (this) {
2286             Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, false, null,
2287                     /* edit */ false);
2288             if (pkgOps == null) {
2289                 return null;
2290             }
2291             ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
2292             if (resOps == null) {
2293                 return null;
2294             }
2295             ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
2296             AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
2297                     pkgOps.packageName, pkgOps.uidState.uid, resOps);
2298             res.add(resPackage);
2299             return res;
2300         }
2301     }
2302 
enforceGetAppOpsStatsPermissionIfNeeded(int uid, String packageName)2303     private void enforceGetAppOpsStatsPermissionIfNeeded(int uid, String packageName) {
2304         final int callingUid = Binder.getCallingUid();
2305         // We get to access everything
2306         if (callingUid == Process.myPid()) {
2307             return;
2308         }
2309         // Apps can access their own data
2310         if (uid == callingUid && packageName != null
2311                 && checkPackage(uid, packageName) == MODE_ALLOWED) {
2312             return;
2313         }
2314         // Otherwise, you need a permission...
2315         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
2316                 Binder.getCallingPid(), callingUid, null);
2317     }
2318 
2319     /**
2320      * Verify that historical appop request arguments are valid.
2321      */
ensureHistoricalOpRequestIsValid(int uid, String packageName, String attributionTag, List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis, int flags)2322     private void ensureHistoricalOpRequestIsValid(int uid, String packageName,
2323             String attributionTag, List<String> opNames, int filter, long beginTimeMillis,
2324             long endTimeMillis, int flags) {
2325         if ((filter & FILTER_BY_UID) != 0) {
2326             Preconditions.checkArgument(uid != Process.INVALID_UID);
2327         } else {
2328             Preconditions.checkArgument(uid == Process.INVALID_UID);
2329         }
2330 
2331         if ((filter & FILTER_BY_PACKAGE_NAME) != 0) {
2332             Objects.requireNonNull(packageName);
2333         } else {
2334             Preconditions.checkArgument(packageName == null);
2335         }
2336 
2337         if ((filter & FILTER_BY_ATTRIBUTION_TAG) == 0) {
2338             Preconditions.checkArgument(attributionTag == null);
2339         }
2340 
2341         if ((filter & FILTER_BY_OP_NAMES) != 0) {
2342             Objects.requireNonNull(opNames);
2343         } else {
2344             Preconditions.checkArgument(opNames == null);
2345         }
2346 
2347         Preconditions.checkFlagsArgument(filter,
2348                 FILTER_BY_UID | FILTER_BY_PACKAGE_NAME | FILTER_BY_ATTRIBUTION_TAG
2349                         | FILTER_BY_OP_NAMES);
2350         Preconditions.checkArgumentNonnegative(beginTimeMillis);
2351         Preconditions.checkArgument(endTimeMillis > beginTimeMillis);
2352         Preconditions.checkFlagsArgument(flags, OP_FLAGS_ALL);
2353     }
2354 
2355     @Override
getHistoricalOps(int uid, String packageName, String attributionTag, List<String> opNames, int dataType, int filter, long beginTimeMillis, long endTimeMillis, int flags, RemoteCallback callback)2356     public void getHistoricalOps(int uid, String packageName, String attributionTag,
2357             List<String> opNames, int dataType, int filter, long beginTimeMillis,
2358             long endTimeMillis, int flags, RemoteCallback callback) {
2359         PackageManager pm = mContext.getPackageManager();
2360 
2361         ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
2362                 beginTimeMillis, endTimeMillis, flags);
2363         Objects.requireNonNull(callback, "callback cannot be null");
2364         ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class);
2365         boolean isSelfRequest = (filter & FILTER_BY_UID) != 0 && uid == Binder.getCallingUid();
2366         if (!isSelfRequest) {
2367             boolean isCallerInstrumented = ami.isUidCurrentlyInstrumented(Binder.getCallingUid());
2368             boolean isCallerSystem = Binder.getCallingPid() == Process.myPid();
2369             boolean isCallerPermissionController;
2370             try {
2371                 isCallerPermissionController = pm.getPackageUidAsUser(
2372                         mContext.getPackageManager().getPermissionControllerPackageName(), 0,
2373                         UserHandle.getUserId(Binder.getCallingUid()))
2374                         == Binder.getCallingUid();
2375             } catch (PackageManager.NameNotFoundException doesNotHappen) {
2376                 return;
2377             }
2378 
2379             if (!isCallerSystem && !isCallerInstrumented && !isCallerPermissionController) {
2380                 mHandler.post(() -> callback.sendResult(new Bundle()));
2381                 return;
2382             }
2383 
2384             mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
2385                     Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
2386         }
2387 
2388         final String[] opNamesArray = (opNames != null)
2389                 ? opNames.toArray(new String[opNames.size()]) : null;
2390 
2391         Set<String> attributionChainExemptPackages = null;
2392         if ((dataType & HISTORY_FLAG_GET_ATTRIBUTION_CHAINS) != 0) {
2393             attributionChainExemptPackages =
2394                     PermissionManager.getIndicatorExemptedPackages(mContext);
2395         }
2396 
2397         final String[] chainExemptPkgArray = attributionChainExemptPackages != null
2398                 ? attributionChainExemptPackages.toArray(
2399                         new String[attributionChainExemptPackages.size()]) : null;
2400 
2401         // Must not hold the appops lock
2402         mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOps,
2403                 mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType,
2404                 filter, beginTimeMillis, endTimeMillis, flags, chainExemptPkgArray,
2405                 callback).recycleOnUse());
2406     }
2407 
2408     @Override
getHistoricalOpsFromDiskRaw(int uid, String packageName, String attributionTag, List<String> opNames, int dataType, int filter, long beginTimeMillis, long endTimeMillis, int flags, RemoteCallback callback)2409     public void getHistoricalOpsFromDiskRaw(int uid, String packageName, String attributionTag,
2410             List<String> opNames, int dataType, int filter, long beginTimeMillis,
2411             long endTimeMillis, int flags, RemoteCallback callback) {
2412         ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
2413                 beginTimeMillis, endTimeMillis, flags);
2414         Objects.requireNonNull(callback, "callback cannot be null");
2415 
2416         mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
2417                 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
2418 
2419         final String[] opNamesArray = (opNames != null)
2420                 ? opNames.toArray(new String[opNames.size()]) : null;
2421 
2422         Set<String> attributionChainExemptPackages = null;
2423         if ((dataType & HISTORY_FLAG_GET_ATTRIBUTION_CHAINS) != 0) {
2424             attributionChainExemptPackages =
2425                     PermissionManager.getIndicatorExemptedPackages(mContext);
2426         }
2427 
2428         final String[] chainExemptPkgArray = attributionChainExemptPackages != null
2429                 ? attributionChainExemptPackages.toArray(
2430                 new String[attributionChainExemptPackages.size()]) : null;
2431 
2432         // Must not hold the appops lock
2433         mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOpsFromDiskRaw,
2434                 mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType,
2435                 filter, beginTimeMillis, endTimeMillis, flags, chainExemptPkgArray,
2436                 callback).recycleOnUse());
2437     }
2438 
2439     @Override
reloadNonHistoricalState()2440     public void reloadNonHistoricalState() {
2441         mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
2442                 Binder.getCallingPid(), Binder.getCallingUid(), "reloadNonHistoricalState");
2443         writeState();
2444         readState();
2445     }
2446 
2447     @Override
getUidOps(int uid, int[] ops)2448     public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
2449         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
2450                 Binder.getCallingPid(), Binder.getCallingUid(), null);
2451         synchronized (this) {
2452             UidState uidState = getUidStateLocked(uid, false);
2453             if (uidState == null) {
2454                 return null;
2455             }
2456             ArrayList<AppOpsManager.OpEntry> resOps = collectUidOps(uidState, ops);
2457             if (resOps == null) {
2458                 return null;
2459             }
2460             ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
2461             AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
2462                     null, uidState.uid, resOps);
2463             res.add(resPackage);
2464             return res;
2465         }
2466     }
2467 
pruneOpLocked(Op op, int uid, String packageName)2468     private void pruneOpLocked(Op op, int uid, String packageName) {
2469         op.removeAttributionsWithNoTime();
2470 
2471         if (op.mAttributions.isEmpty()) {
2472             Ops ops = getOpsLocked(uid, packageName, null, false, null, /* edit */ false);
2473             if (ops != null) {
2474                 ops.remove(op.op);
2475                 if (ops.size() <= 0) {
2476                     UidState uidState = ops.uidState;
2477                     ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
2478                     if (pkgOps != null) {
2479                         pkgOps.remove(ops.packageName);
2480                         if (pkgOps.isEmpty()) {
2481                             uidState.pkgOps = null;
2482                         }
2483                         if (uidState.isDefault()) {
2484                             mUidStates.remove(uid);
2485                         }
2486                     }
2487                 }
2488             }
2489         }
2490     }
2491 
enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid)2492     private void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
2493         if (callingPid == Process.myPid()) {
2494             return;
2495         }
2496         final int callingUser = UserHandle.getUserId(callingUid);
2497         synchronized (this) {
2498             if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
2499                 if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
2500                     // Profile owners are allowed to change modes but only for apps
2501                     // within their user.
2502                     return;
2503                 }
2504             }
2505         }
2506         mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
2507                 Binder.getCallingPid(), Binder.getCallingUid(), null);
2508     }
2509 
2510     @Override
setUidMode(int code, int uid, int mode)2511     public void setUidMode(int code, int uid, int mode) {
2512         setUidMode(code, uid, mode, null);
2513     }
2514 
setUidMode(int code, int uid, int mode, @Nullable IAppOpsCallback permissionPolicyCallback)2515     private void setUidMode(int code, int uid, int mode,
2516             @Nullable IAppOpsCallback permissionPolicyCallback) {
2517         if (DEBUG) {
2518             Slog.i(TAG, "uid " + uid + " OP_" + opToName(code) + " := " + modeToName(mode)
2519                     + " by uid " + Binder.getCallingUid());
2520         }
2521 
2522         enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
2523         verifyIncomingOp(code);
2524         code = AppOpsManager.opToSwitch(code);
2525 
2526         if (permissionPolicyCallback == null) {
2527             updatePermissionRevokedCompat(uid, code, mode);
2528         }
2529 
2530         int previousMode;
2531         synchronized (this) {
2532             final int defaultMode = AppOpsManager.opToDefaultMode(code);
2533 
2534             UidState uidState = getUidStateLocked(uid, false);
2535             if (uidState == null) {
2536                 if (mode == defaultMode) {
2537                     return;
2538                 }
2539                 previousMode = MODE_DEFAULT;
2540                 uidState = new UidState(uid);
2541                 uidState.opModes = new SparseIntArray();
2542                 uidState.opModes.put(code, mode);
2543                 mUidStates.put(uid, uidState);
2544                 scheduleWriteLocked();
2545             } else if (uidState.opModes == null) {
2546                 previousMode = MODE_DEFAULT;
2547                 if (mode != defaultMode) {
2548                     uidState.opModes = new SparseIntArray();
2549                     uidState.opModes.put(code, mode);
2550                     scheduleWriteLocked();
2551                 }
2552             } else {
2553                 if (uidState.opModes.indexOfKey(code) >= 0 && uidState.opModes.get(code) == mode) {
2554                     return;
2555                 }
2556                 previousMode = uidState.opModes.get(code);
2557                 if (mode == defaultMode) {
2558                     uidState.opModes.delete(code);
2559                     if (uidState.opModes.size() <= 0) {
2560                         uidState.opModes = null;
2561                     }
2562                 } else {
2563                     uidState.opModes.put(code, mode);
2564                 }
2565                 scheduleWriteLocked();
2566             }
2567             uidState.evalForegroundOps(mOpModeWatchers);
2568             if (mode != MODE_ERRORED && mode != previousMode) {
2569                 updateStartedOpModeForUidLocked(code, mode == MODE_IGNORED, uid);
2570             }
2571         }
2572 
2573         notifyOpChangedForAllPkgsInUid(code, uid, false, permissionPolicyCallback);
2574         notifyOpChangedSync(code, uid, null, mode, previousMode);
2575     }
2576 
2577     /**
2578      * Notify that an op changed for all packages in an uid.
2579      *
2580      * @param code The op that changed
2581      * @param uid The uid the op was changed for
2582      * @param onlyForeground Only notify watchers that watch for foreground changes
2583      */
notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground, @Nullable IAppOpsCallback callbackToIgnore)2584     private void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground,
2585             @Nullable IAppOpsCallback callbackToIgnore) {
2586         String[] uidPackageNames = getPackagesForUid(uid);
2587         ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
2588 
2589         synchronized (this) {
2590             ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
2591             if (callbacks != null) {
2592                 final int callbackCount = callbacks.size();
2593                 for (int i = 0; i < callbackCount; i++) {
2594                     ModeCallback callback = callbacks.valueAt(i);
2595                     if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) {
2596                         continue;
2597                     }
2598 
2599                     ArraySet<String> changedPackages = new ArraySet<>();
2600                     Collections.addAll(changedPackages, uidPackageNames);
2601                     if (callbackSpecs == null) {
2602                         callbackSpecs = new ArrayMap<>();
2603                     }
2604                     callbackSpecs.put(callback, changedPackages);
2605                 }
2606             }
2607 
2608             for (String uidPackageName : uidPackageNames) {
2609                 callbacks = mPackageModeWatchers.get(uidPackageName);
2610                 if (callbacks != null) {
2611                     if (callbackSpecs == null) {
2612                         callbackSpecs = new ArrayMap<>();
2613                     }
2614                     final int callbackCount = callbacks.size();
2615                     for (int i = 0; i < callbackCount; i++) {
2616                         ModeCallback callback = callbacks.valueAt(i);
2617                         if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) {
2618                             continue;
2619                         }
2620 
2621                         ArraySet<String> changedPackages = callbackSpecs.get(callback);
2622                         if (changedPackages == null) {
2623                             changedPackages = new ArraySet<>();
2624                             callbackSpecs.put(callback, changedPackages);
2625                         }
2626                         changedPackages.add(uidPackageName);
2627                     }
2628                 }
2629             }
2630 
2631             if (callbackSpecs != null && callbackToIgnore != null) {
2632                 callbackSpecs.remove(mModeWatchers.get(callbackToIgnore.asBinder()));
2633             }
2634         }
2635 
2636         if (callbackSpecs == null) {
2637             return;
2638         }
2639 
2640         for (int i = 0; i < callbackSpecs.size(); i++) {
2641             final ModeCallback callback = callbackSpecs.keyAt(i);
2642             final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
2643             if (reportedPackageNames == null) {
2644                 mHandler.sendMessage(PooledLambda.obtainMessage(
2645                         AppOpsService::notifyOpChanged,
2646                         this, callback, code, uid, (String) null));
2647 
2648             } else {
2649                 final int reportedPackageCount = reportedPackageNames.size();
2650                 for (int j = 0; j < reportedPackageCount; j++) {
2651                     final String reportedPackageName = reportedPackageNames.valueAt(j);
2652                     mHandler.sendMessage(PooledLambda.obtainMessage(
2653                             AppOpsService::notifyOpChanged,
2654                             this, callback, code, uid, reportedPackageName));
2655                 }
2656             }
2657         }
2658     }
2659 
updatePermissionRevokedCompat(int uid, int switchCode, int mode)2660     private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) {
2661         PackageManager packageManager = mContext.getPackageManager();
2662         if (packageManager == null) {
2663             // This can only happen during early boot. At this time the permission state and appop
2664             // state are in sync
2665             return;
2666         }
2667 
2668         String[] packageNames = packageManager.getPackagesForUid(uid);
2669         if (ArrayUtils.isEmpty(packageNames)) {
2670             return;
2671         }
2672         String packageName = packageNames[0];
2673 
2674         int[] ops = mSwitchedOps.get(switchCode);
2675         for (int code : ops) {
2676             String permissionName = AppOpsManager.opToPermission(code);
2677             if (permissionName == null) {
2678                 continue;
2679             }
2680 
2681             if (packageManager.checkPermission(permissionName, packageName)
2682                     != PackageManager.PERMISSION_GRANTED) {
2683                 continue;
2684             }
2685 
2686             PermissionInfo permissionInfo;
2687             try {
2688                 permissionInfo = packageManager.getPermissionInfo(permissionName, 0);
2689             } catch (PackageManager.NameNotFoundException e) {
2690                 e.printStackTrace();
2691                 continue;
2692             }
2693 
2694             if (!permissionInfo.isRuntime()) {
2695                 continue;
2696             }
2697 
2698             boolean supportsRuntimePermissions = getPackageManagerInternal()
2699                     .getUidTargetSdkVersion(uid) >= Build.VERSION_CODES.M;
2700 
2701             UserHandle user = UserHandle.getUserHandleForUid(uid);
2702             boolean isRevokedCompat;
2703             if (permissionInfo.backgroundPermission != null) {
2704                 if (packageManager.checkPermission(permissionInfo.backgroundPermission, packageName)
2705                         == PackageManager.PERMISSION_GRANTED) {
2706                     boolean isBackgroundRevokedCompat = mode != AppOpsManager.MODE_ALLOWED;
2707 
2708                     if (isBackgroundRevokedCompat && supportsRuntimePermissions) {
2709                         Slog.w(TAG, "setUidMode() called with a mode inconsistent with runtime"
2710                                 + " permission state, this is discouraged and you should revoke the"
2711                                 + " runtime permission instead: uid=" + uid + ", switchCode="
2712                                 + switchCode + ", mode=" + mode + ", permission="
2713                                 + permissionInfo.backgroundPermission);
2714                     }
2715 
2716                     final long identity = Binder.clearCallingIdentity();
2717                     try {
2718                         packageManager.updatePermissionFlags(permissionInfo.backgroundPermission,
2719                                 packageName, PackageManager.FLAG_PERMISSION_REVOKED_COMPAT,
2720                                 isBackgroundRevokedCompat
2721                                         ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user);
2722                     } finally {
2723                         Binder.restoreCallingIdentity(identity);
2724                     }
2725                 }
2726 
2727                 isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED
2728                         && mode != AppOpsManager.MODE_FOREGROUND;
2729             } else {
2730                 isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED;
2731             }
2732 
2733             if (isRevokedCompat && supportsRuntimePermissions) {
2734                 Slog.w(TAG, "setUidMode() called with a mode inconsistent with runtime"
2735                         + " permission state, this is discouraged and you should revoke the"
2736                         + " runtime permission instead: uid=" + uid + ", switchCode="
2737                         + switchCode + ", mode=" + mode + ", permission=" + permissionName);
2738             }
2739 
2740             final long identity = Binder.clearCallingIdentity();
2741             try {
2742                 packageManager.updatePermissionFlags(permissionName, packageName,
2743                         PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, isRevokedCompat
2744                                 ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user);
2745             } finally {
2746                 Binder.restoreCallingIdentity(identity);
2747             }
2748         }
2749     }
2750 
notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode, int previousMode)2751     private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode,
2752             int previousMode) {
2753         final StorageManagerInternal storageManagerInternal =
2754                 LocalServices.getService(StorageManagerInternal.class);
2755         if (storageManagerInternal != null) {
2756             storageManagerInternal.onAppOpsChanged(code, uid, packageName, mode, previousMode);
2757         }
2758     }
2759 
2760     /**
2761      * Sets the mode for a certain op and uid.
2762      *
2763      * @param code The op code to set
2764      * @param uid The UID for which to set
2765      * @param packageName The package for which to set
2766      * @param mode The new mode to set
2767      */
2768     @Override
setMode(int code, int uid, @NonNull String packageName, int mode)2769     public void setMode(int code, int uid, @NonNull String packageName, int mode) {
2770         setMode(code, uid, packageName, mode, null);
2771     }
2772 
setMode(int code, int uid, @NonNull String packageName, int mode, @Nullable IAppOpsCallback permissionPolicyCallback)2773     private void setMode(int code, int uid, @NonNull String packageName, int mode,
2774             @Nullable IAppOpsCallback permissionPolicyCallback) {
2775         enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
2776         verifyIncomingOp(code);
2777         verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
2778 
2779         ArraySet<ModeCallback> repCbs = null;
2780         code = AppOpsManager.opToSwitch(code);
2781 
2782         PackageVerificationResult pvr;
2783         try {
2784             pvr = verifyAndGetBypass(uid, packageName, null);
2785         } catch (SecurityException e) {
2786             Slog.e(TAG, "Cannot setMode", e);
2787             return;
2788         }
2789 
2790         int previousMode = MODE_DEFAULT;
2791         synchronized (this) {
2792             UidState uidState = getUidStateLocked(uid, false);
2793             Op op = getOpLocked(code, uid, packageName, null, false, pvr.bypass, /* edit */ true);
2794             if (op != null) {
2795                 if (op.mode != mode) {
2796                     previousMode = op.mode;
2797                     op.mode = mode;
2798                     if (uidState != null) {
2799                         uidState.evalForegroundOps(mOpModeWatchers);
2800                     }
2801                     ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
2802                     if (cbs != null) {
2803                         if (repCbs == null) {
2804                             repCbs = new ArraySet<>();
2805                         }
2806                         repCbs.addAll(cbs);
2807                     }
2808                     cbs = mPackageModeWatchers.get(packageName);
2809                     if (cbs != null) {
2810                         if (repCbs == null) {
2811                             repCbs = new ArraySet<>();
2812                         }
2813                         repCbs.addAll(cbs);
2814                     }
2815                     if (repCbs != null && permissionPolicyCallback != null) {
2816                         repCbs.remove(mModeWatchers.get(permissionPolicyCallback.asBinder()));
2817                     }
2818                     if (mode == AppOpsManager.opToDefaultMode(op.op)) {
2819                         // If going into the default mode, prune this op
2820                         // if there is nothing else interesting in it.
2821                         pruneOpLocked(op, uid, packageName);
2822                     }
2823                     scheduleFastWriteLocked();
2824                     if (mode != MODE_ERRORED) {
2825                         updateStartedOpModeForUidLocked(code, mode == MODE_IGNORED, uid);
2826                     }
2827                 }
2828             }
2829         }
2830         if (repCbs != null) {
2831             mHandler.sendMessage(PooledLambda.obtainMessage(
2832                     AppOpsService::notifyOpChanged,
2833                     this, repCbs, code, uid, packageName));
2834         }
2835 
2836         notifyOpChangedSync(code, uid, packageName, mode, previousMode);
2837     }
2838 
notifyOpChanged(ArraySet<ModeCallback> callbacks, int code, int uid, String packageName)2839     private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
2840             int uid, String packageName) {
2841         for (int i = 0; i < callbacks.size(); i++) {
2842             final ModeCallback callback = callbacks.valueAt(i);
2843             notifyOpChanged(callback, code, uid, packageName);
2844         }
2845     }
2846 
notifyOpChanged(ModeCallback callback, int code, int uid, String packageName)2847     private void notifyOpChanged(ModeCallback callback, int code,
2848             int uid, String packageName) {
2849         if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
2850             return;
2851         }
2852 
2853         // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE
2854         int[] switchedCodes;
2855         if (callback.mWatchedOpCode == ALL_OPS) {
2856             switchedCodes = mSwitchedOps.get(code);
2857         } else if (callback.mWatchedOpCode == OP_NONE) {
2858             switchedCodes = new int[]{code};
2859         } else {
2860             switchedCodes = new int[]{callback.mWatchedOpCode};
2861         }
2862 
2863         for (int switchedCode : switchedCodes) {
2864             // There are features watching for mode changes such as window manager
2865             // and location manager which are in our process. The callbacks in these
2866             // features may require permissions our remote caller does not have.
2867             final long identity = Binder.clearCallingIdentity();
2868             try {
2869                 callback.mCallback.opChanged(switchedCode, uid, packageName);
2870             } catch (RemoteException e) {
2871                 /* ignore */
2872             } finally {
2873                 Binder.restoreCallingIdentity(identity);
2874             }
2875         }
2876     }
2877 
addChange(ArrayList<ChangeRec> reports, int op, int uid, String packageName, int previousMode)2878     private static ArrayList<ChangeRec> addChange(ArrayList<ChangeRec> reports,
2879             int op, int uid, String packageName, int previousMode) {
2880         boolean duplicate = false;
2881         if (reports == null) {
2882             reports = new ArrayList<>();
2883         } else {
2884             final int reportCount = reports.size();
2885             for (int j = 0; j < reportCount; j++) {
2886                 ChangeRec report = reports.get(j);
2887                 if (report.op == op && report.pkg.equals(packageName)) {
2888                     duplicate = true;
2889                     break;
2890                 }
2891             }
2892         }
2893         if (!duplicate) {
2894             reports.add(new ChangeRec(op, uid, packageName, previousMode));
2895         }
2896 
2897         return reports;
2898     }
2899 
addCallbacks( HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks, int op, int uid, String packageName, int previousMode, ArraySet<ModeCallback> cbs)2900     private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
2901             HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
2902             int op, int uid, String packageName, int previousMode, ArraySet<ModeCallback> cbs) {
2903         if (cbs == null) {
2904             return callbacks;
2905         }
2906         if (callbacks == null) {
2907             callbacks = new HashMap<>();
2908         }
2909         final int N = cbs.size();
2910         for (int i=0; i<N; i++) {
2911             ModeCallback cb = cbs.valueAt(i);
2912             ArrayList<ChangeRec> reports = callbacks.get(cb);
2913             ArrayList<ChangeRec> changed = addChange(reports, op, uid, packageName, previousMode);
2914             if (changed != reports) {
2915                 callbacks.put(cb, changed);
2916             }
2917         }
2918         return callbacks;
2919     }
2920 
2921     static final class ChangeRec {
2922         final int op;
2923         final int uid;
2924         final String pkg;
2925         final int previous_mode;
2926 
ChangeRec(int _op, int _uid, String _pkg, int _previous_mode)2927         ChangeRec(int _op, int _uid, String _pkg, int _previous_mode) {
2928             op = _op;
2929             uid = _uid;
2930             pkg = _pkg;
2931             previous_mode = _previous_mode;
2932         }
2933     }
2934 
2935     @Override
resetAllModes(int reqUserId, String reqPackageName)2936     public void resetAllModes(int reqUserId, String reqPackageName) {
2937         final int callingPid = Binder.getCallingPid();
2938         final int callingUid = Binder.getCallingUid();
2939         reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
2940                 true, true, "resetAllModes", null);
2941 
2942         int reqUid = -1;
2943         if (reqPackageName != null) {
2944             try {
2945                 reqUid = AppGlobals.getPackageManager().getPackageUid(
2946                         reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
2947             } catch (RemoteException e) {
2948                 /* ignore - local call */
2949             }
2950         }
2951 
2952         enforceManageAppOpsModes(callingPid, callingUid, reqUid);
2953 
2954         HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
2955         ArrayList<ChangeRec> allChanges = new ArrayList<>();
2956         synchronized (this) {
2957             boolean changed = false;
2958             for (int i = mUidStates.size() - 1; i >= 0; i--) {
2959                 UidState uidState = mUidStates.valueAt(i);
2960 
2961                 SparseIntArray opModes = uidState.opModes;
2962                 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
2963                     final int uidOpCount = opModes.size();
2964                     for (int j = uidOpCount - 1; j >= 0; j--) {
2965                         final int code = opModes.keyAt(j);
2966                         if (AppOpsManager.opAllowsReset(code)) {
2967                             int previousMode = opModes.valueAt(j);
2968                             opModes.removeAt(j);
2969                             if (opModes.size() <= 0) {
2970                                 uidState.opModes = null;
2971                             }
2972                             for (String packageName : getPackagesForUid(uidState.uid)) {
2973                                 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
2974                                         previousMode, mOpModeWatchers.get(code));
2975                                 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
2976                                         previousMode, mPackageModeWatchers.get(packageName));
2977 
2978                                 allChanges = addChange(allChanges, code, uidState.uid,
2979                                         packageName, previousMode);
2980                             }
2981                         }
2982                     }
2983                 }
2984 
2985                 if (uidState.pkgOps == null) {
2986                     continue;
2987                 }
2988 
2989                 if (reqUserId != UserHandle.USER_ALL
2990                         && reqUserId != UserHandle.getUserId(uidState.uid)) {
2991                     // Skip any ops for a different user
2992                     continue;
2993                 }
2994 
2995                 Map<String, Ops> packages = uidState.pkgOps;
2996                 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
2997                 boolean uidChanged = false;
2998                 while (it.hasNext()) {
2999                     Map.Entry<String, Ops> ent = it.next();
3000                     String packageName = ent.getKey();
3001                     if (reqPackageName != null && !reqPackageName.equals(packageName)) {
3002                         // Skip any ops for a different package
3003                         continue;
3004                     }
3005                     Ops pkgOps = ent.getValue();
3006                     for (int j=pkgOps.size()-1; j>=0; j--) {
3007                         Op curOp = pkgOps.valueAt(j);
3008                         if (shouldDeferResetOpToDpm(curOp.op)) {
3009                             deferResetOpToDpm(curOp.op, reqPackageName, reqUserId);
3010                             continue;
3011                         }
3012                         if (AppOpsManager.opAllowsReset(curOp.op)
3013                                 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
3014                             int previousMode = curOp.mode;
3015                             curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
3016                             changed = true;
3017                             uidChanged = true;
3018                             final int uid = curOp.uidState.uid;
3019                             callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
3020                                     previousMode, mOpModeWatchers.get(curOp.op));
3021                             callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
3022                                     previousMode, mPackageModeWatchers.get(packageName));
3023 
3024                             allChanges = addChange(allChanges, curOp.op, uid, packageName,
3025                                     previousMode);
3026                             curOp.removeAttributionsWithNoTime();
3027                             if (curOp.mAttributions.isEmpty()) {
3028                                 pkgOps.removeAt(j);
3029                             }
3030                         }
3031                     }
3032                     if (pkgOps.size() == 0) {
3033                         it.remove();
3034                     }
3035                 }
3036                 if (uidState.isDefault()) {
3037                     mUidStates.remove(uidState.uid);
3038                 }
3039                 if (uidChanged) {
3040                     uidState.evalForegroundOps(mOpModeWatchers);
3041                 }
3042             }
3043 
3044             if (changed) {
3045                 scheduleFastWriteLocked();
3046             }
3047         }
3048         if (callbacks != null) {
3049             for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
3050                 ModeCallback cb = ent.getKey();
3051                 ArrayList<ChangeRec> reports = ent.getValue();
3052                 for (int i=0; i<reports.size(); i++) {
3053                     ChangeRec rep = reports.get(i);
3054                     mHandler.sendMessage(PooledLambda.obtainMessage(
3055                             AppOpsService::notifyOpChanged,
3056                             this, cb, rep.op, rep.uid, rep.pkg));
3057                 }
3058             }
3059         }
3060 
3061         int numChanges = allChanges.size();
3062         for (int i = 0; i < numChanges; i++) {
3063             ChangeRec change = allChanges.get(i);
3064             notifyOpChangedSync(change.op, change.uid, change.pkg,
3065                     AppOpsManager.opToDefaultMode(change.op), change.previous_mode);
3066         }
3067     }
3068 
shouldDeferResetOpToDpm(int op)3069     private boolean shouldDeferResetOpToDpm(int op) {
3070         // TODO(b/174582385): avoid special-casing app-op resets by migrating app-op permission
3071         //  pre-grants to a role-based mechanism or another general-purpose mechanism.
3072         return dpmi != null && dpmi.supportsResetOp(op);
3073     }
3074 
3075     /** Assumes {@link #shouldDeferResetOpToDpm(int)} is true. */
deferResetOpToDpm(int op, String packageName, @UserIdInt int userId)3076     private void deferResetOpToDpm(int op, String packageName, @UserIdInt int userId) {
3077         // TODO(b/174582385): avoid special-casing app-op resets by migrating app-op permission
3078         //  pre-grants to a role-based mechanism or another general-purpose mechanism.
3079         dpmi.resetOp(op, packageName, userId);
3080     }
3081 
evalAllForegroundOpsLocked()3082     private void evalAllForegroundOpsLocked() {
3083         for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
3084             final UidState uidState = mUidStates.valueAt(uidi);
3085             if (uidState.foregroundOps != null) {
3086                 uidState.evalForegroundOps(mOpModeWatchers);
3087             }
3088         }
3089     }
3090 
3091     @Override
startWatchingMode(int op, String packageName, IAppOpsCallback callback)3092     public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
3093         startWatchingModeWithFlags(op, packageName, 0, callback);
3094     }
3095 
3096     @Override
startWatchingModeWithFlags(int op, String packageName, int flags, IAppOpsCallback callback)3097     public void startWatchingModeWithFlags(int op, String packageName, int flags,
3098             IAppOpsCallback callback) {
3099         int watchedUid = -1;
3100         final int callingUid = Binder.getCallingUid();
3101         final int callingPid = Binder.getCallingPid();
3102         // TODO: should have a privileged permission to protect this.
3103         // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require
3104         // the USAGE_STATS permission since this can provide information about when an
3105         // app is in the foreground?
3106         Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
3107                 AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
3108         if (callback == null) {
3109             return;
3110         }
3111         final boolean mayWatchPackageName =
3112                 packageName != null && !filterAppAccessUnlocked(packageName);
3113         synchronized (this) {
3114             int switchOp = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
3115 
3116             int notifiedOps;
3117             if ((flags & CALL_BACK_ON_SWITCHED_OP) == 0) {
3118                 if (op == OP_NONE) {
3119                     notifiedOps = ALL_OPS;
3120                 } else {
3121                     notifiedOps = op;
3122                 }
3123             } else {
3124                 notifiedOps = switchOp;
3125             }
3126 
3127             ModeCallback cb = mModeWatchers.get(callback.asBinder());
3128             if (cb == null) {
3129                 cb = new ModeCallback(callback, watchedUid, flags, notifiedOps, callingUid,
3130                         callingPid);
3131                 mModeWatchers.put(callback.asBinder(), cb);
3132             }
3133             if (switchOp != AppOpsManager.OP_NONE) {
3134                 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(switchOp);
3135                 if (cbs == null) {
3136                     cbs = new ArraySet<>();
3137                     mOpModeWatchers.put(switchOp, cbs);
3138                 }
3139                 cbs.add(cb);
3140             }
3141             if (mayWatchPackageName) {
3142                 ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
3143                 if (cbs == null) {
3144                     cbs = new ArraySet<>();
3145                     mPackageModeWatchers.put(packageName, cbs);
3146                 }
3147                 cbs.add(cb);
3148             }
3149             evalAllForegroundOpsLocked();
3150         }
3151     }
3152 
3153     @Override
stopWatchingMode(IAppOpsCallback callback)3154     public void stopWatchingMode(IAppOpsCallback callback) {
3155         if (callback == null) {
3156             return;
3157         }
3158         synchronized (this) {
3159             ModeCallback cb = mModeWatchers.remove(callback.asBinder());
3160             if (cb != null) {
3161                 cb.unlinkToDeath();
3162                 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
3163                     ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
3164                     cbs.remove(cb);
3165                     if (cbs.size() <= 0) {
3166                         mOpModeWatchers.removeAt(i);
3167                     }
3168                 }
3169                 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
3170                     ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
3171                     cbs.remove(cb);
3172                     if (cbs.size() <= 0) {
3173                         mPackageModeWatchers.removeAt(i);
3174                     }
3175                 }
3176             }
3177             evalAllForegroundOpsLocked();
3178         }
3179     }
3180 
getAppOpsServiceDelegate()3181     public CheckOpsDelegate getAppOpsServiceDelegate() {
3182         synchronized (AppOpsService.this) {
3183             final CheckOpsDelegateDispatcher dispatcher = mCheckOpsDelegateDispatcher;
3184             return (dispatcher != null) ? dispatcher.getCheckOpsDelegate() : null;
3185         }
3186     }
3187 
setAppOpsServiceDelegate(CheckOpsDelegate delegate)3188     public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) {
3189         synchronized (AppOpsService.this) {
3190             final CheckOpsDelegateDispatcher oldDispatcher = mCheckOpsDelegateDispatcher;
3191             final CheckOpsDelegate policy = (oldDispatcher != null) ? oldDispatcher.mPolicy : null;
3192             mCheckOpsDelegateDispatcher = new CheckOpsDelegateDispatcher(policy, delegate);
3193         }
3194     }
3195 
3196     @Override
checkOperationRaw(int code, int uid, String packageName, @Nullable String attributionTag)3197     public int checkOperationRaw(int code, int uid, String packageName,
3198             @Nullable String attributionTag) {
3199         return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, attributionTag,
3200                 true /*raw*/);
3201     }
3202 
3203     @Override
checkOperation(int code, int uid, String packageName)3204     public int checkOperation(int code, int uid, String packageName) {
3205         return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, null,
3206                 false /*raw*/);
3207     }
3208 
checkOperationImpl(int code, int uid, String packageName, @Nullable String attributionTag, boolean raw)3209     private int checkOperationImpl(int code, int uid, String packageName,
3210             @Nullable String attributionTag, boolean raw) {
3211         verifyIncomingOp(code);
3212         verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
3213 
3214         String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
3215         if (resolvedPackageName == null) {
3216             return AppOpsManager.MODE_IGNORED;
3217         }
3218         return checkOperationUnchecked(code, uid, resolvedPackageName, attributionTag, raw);
3219     }
3220 
3221     /**
3222      * Get the mode of an app-op.
3223      *
3224      * @param code The code of the op
3225      * @param uid The uid of the package the op belongs to
3226      * @param packageName The package the op belongs to
3227      * @param raw If the raw state of eval-ed state should be checked.
3228      *
3229      * @return The mode of the op
3230      */
checkOperationUnchecked(int code, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean raw)3231     private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
3232             @Nullable String attributionTag, boolean raw) {
3233         PackageVerificationResult pvr;
3234         try {
3235             pvr = verifyAndGetBypass(uid, packageName, null);
3236         } catch (SecurityException e) {
3237             Slog.e(TAG, "checkOperation", e);
3238             return AppOpsManager.opToDefaultMode(code);
3239         }
3240 
3241         if (isOpRestrictedDueToSuspend(code, packageName, uid)) {
3242             return AppOpsManager.MODE_IGNORED;
3243         }
3244         synchronized (this) {
3245             if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass)) {
3246                 return AppOpsManager.MODE_IGNORED;
3247             }
3248             code = AppOpsManager.opToSwitch(code);
3249             UidState uidState = getUidStateLocked(uid, false);
3250             if (uidState != null && uidState.opModes != null
3251                     && uidState.opModes.indexOfKey(code) >= 0) {
3252                 final int rawMode = uidState.opModes.get(code);
3253                 return raw ? rawMode : uidState.evalMode(code, rawMode);
3254             }
3255             Op op = getOpLocked(code, uid, packageName, null, false, pvr.bypass, /* edit */ false);
3256             if (op == null) {
3257                 return AppOpsManager.opToDefaultMode(code);
3258             }
3259             return raw ? op.mode : op.evalMode();
3260         }
3261     }
3262 
3263     @Override
checkAudioOperation(int code, int usage, int uid, String packageName)3264     public int checkAudioOperation(int code, int usage, int uid, String packageName) {
3265         return mCheckOpsDelegateDispatcher.checkAudioOperation(code, usage, uid, packageName);
3266     }
3267 
checkAudioOperationImpl(int code, int usage, int uid, String packageName)3268     private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
3269         final int mode = mAudioRestrictionManager.checkAudioOperation(
3270                 code, usage, uid, packageName);
3271         if (mode != AppOpsManager.MODE_ALLOWED) {
3272             return mode;
3273         }
3274         return checkOperation(code, uid, packageName);
3275     }
3276 
3277     @Override
setAudioRestriction(int code, int usage, int uid, int mode, String[] exceptionPackages)3278     public void setAudioRestriction(int code, int usage, int uid, int mode,
3279             String[] exceptionPackages) {
3280         enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
3281         verifyIncomingUid(uid);
3282         verifyIncomingOp(code);
3283 
3284         mAudioRestrictionManager.setZenModeAudioRestriction(
3285                 code, usage, uid, mode, exceptionPackages);
3286 
3287         mHandler.sendMessage(PooledLambda.obtainMessage(
3288                 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
3289     }
3290 
3291 
3292     @Override
setCameraAudioRestriction(@AMERA_AUDIO_RESTRICTION int mode)3293     public void setCameraAudioRestriction(@CAMERA_AUDIO_RESTRICTION int mode) {
3294         enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), -1);
3295 
3296         mAudioRestrictionManager.setCameraAudioRestriction(mode);
3297 
3298         mHandler.sendMessage(PooledLambda.obtainMessage(
3299                 AppOpsService::notifyWatchersOfChange, this,
3300                 AppOpsManager.OP_PLAY_AUDIO, UID_ANY));
3301         mHandler.sendMessage(PooledLambda.obtainMessage(
3302                 AppOpsService::notifyWatchersOfChange, this,
3303                 AppOpsManager.OP_VIBRATE, UID_ANY));
3304     }
3305 
3306     @Override
checkPackage(int uid, String packageName)3307     public int checkPackage(int uid, String packageName) {
3308         Objects.requireNonNull(packageName);
3309         try {
3310             verifyAndGetBypass(uid, packageName, null);
3311             if (filterAppAccessUnlocked(packageName)) {
3312                 return AppOpsManager.MODE_ERRORED;
3313             }
3314             return AppOpsManager.MODE_ALLOWED;
3315         } catch (SecurityException ignored) {
3316             return AppOpsManager.MODE_ERRORED;
3317         }
3318     }
3319 
3320     /**
3321      * This method will check with PackageManager to determine if the package provided should
3322      * be visible to the {@link Binder#getCallingUid()}.
3323      *
3324      * NOTE: This must not be called while synchronized on {@code this} to avoid dead locks
3325      */
filterAppAccessUnlocked(String packageName)3326     private boolean filterAppAccessUnlocked(String packageName) {
3327         final int callingUid = Binder.getCallingUid();
3328         return LocalServices.getService(PackageManagerInternal.class)
3329                 .filterAppAccess(packageName, callingUid, UserHandle.getUserId(callingUid));
3330     }
3331 
3332     @Override
noteProxyOperation(int code, AttributionSource attributionSource, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, boolean skipProxyOperation)3333     public SyncNotedAppOp noteProxyOperation(int code, AttributionSource attributionSource,
3334             boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
3335             boolean skipProxyOperation) {
3336         return mCheckOpsDelegateDispatcher.noteProxyOperation(code, attributionSource,
3337                 shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation);
3338     }
3339 
noteProxyOperationImpl(int code, AttributionSource attributionSource, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, boolean skipProxyOperation)3340     private SyncNotedAppOp noteProxyOperationImpl(int code, AttributionSource attributionSource,
3341             boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
3342             boolean skipProxyOperation) {
3343         final int proxyUid = attributionSource.getUid();
3344         final String proxyPackageName = attributionSource.getPackageName();
3345         final String proxyAttributionTag = attributionSource.getAttributionTag();
3346         final int proxiedUid = attributionSource.getNextUid();
3347         final String proxiedPackageName = attributionSource.getNextPackageName();
3348         final String proxiedAttributionTag = attributionSource.getNextAttributionTag();
3349 
3350         verifyIncomingProxyUid(attributionSource);
3351         verifyIncomingOp(code);
3352         verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid));
3353         verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid));
3354 
3355         skipProxyOperation = skipProxyOperation
3356                 && isCallerAndAttributionTrusted(attributionSource);
3357 
3358         String resolveProxyPackageName = AppOpsManager.resolvePackageName(proxyUid,
3359                 proxyPackageName);
3360         if (resolveProxyPackageName == null) {
3361             return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code,
3362                     proxiedAttributionTag, proxiedPackageName);
3363         }
3364 
3365         final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid;
3366         final boolean isProxyTrusted = mContext.checkPermission(
3367                 Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
3368                 == PackageManager.PERMISSION_GRANTED || isSelfBlame;
3369 
3370         if (!skipProxyOperation) {
3371             final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
3372                     : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
3373 
3374             final SyncNotedAppOp proxyReturn = noteOperationUnchecked(code, proxyUid,
3375                     resolveProxyPackageName, proxyAttributionTag, Process.INVALID_UID, null, null,
3376                     proxyFlags, !isProxyTrusted, "proxy " + message, shouldCollectMessage);
3377             if (proxyReturn.getOpMode() != AppOpsManager.MODE_ALLOWED) {
3378                 return new SyncNotedAppOp(proxyReturn.getOpMode(), code, proxiedAttributionTag,
3379                         proxiedPackageName);
3380             }
3381         }
3382 
3383         String resolveProxiedPackageName = AppOpsManager.resolvePackageName(proxiedUid,
3384                 proxiedPackageName);
3385         if (resolveProxiedPackageName == null) {
3386             return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, proxiedAttributionTag,
3387                     proxiedPackageName);
3388         }
3389 
3390         final int proxiedFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXIED
3391                 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED;
3392         return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
3393                 proxiedAttributionTag, proxyUid, resolveProxyPackageName, proxyAttributionTag,
3394                 proxiedFlags, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
3395     }
3396 
3397     @Override
noteOperation(int code, int uid, String packageName, String attributionTag, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage)3398     public SyncNotedAppOp noteOperation(int code, int uid, String packageName,
3399             String attributionTag, boolean shouldCollectAsyncNotedOp, String message,
3400             boolean shouldCollectMessage) {
3401         return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName,
3402                 attributionTag, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
3403     }
3404 
noteOperationImpl(int code, int uid, @Nullable String packageName, @Nullable String attributionTag, boolean shouldCollectAsyncNotedOp, @Nullable String message, boolean shouldCollectMessage)3405     private SyncNotedAppOp noteOperationImpl(int code, int uid, @Nullable String packageName,
3406             @Nullable String attributionTag, boolean shouldCollectAsyncNotedOp,
3407             @Nullable String message, boolean shouldCollectMessage) {
3408         verifyIncomingUid(uid);
3409         verifyIncomingOp(code);
3410         verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
3411 
3412         String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
3413         if (resolvedPackageName == null) {
3414             return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
3415                     packageName);
3416         }
3417         return noteOperationUnchecked(code, uid, resolvedPackageName, attributionTag,
3418                 Process.INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF,
3419                 shouldCollectAsyncNotedOp, message, shouldCollectMessage);
3420     }
3421 
noteOperationUnchecked(int code, int uid, @NonNull String packageName, @Nullable String attributionTag, int proxyUid, String proxyPackageName, @Nullable String proxyAttributionTag, @OpFlags int flags, boolean shouldCollectAsyncNotedOp, @Nullable String message, boolean shouldCollectMessage)3422     private SyncNotedAppOp noteOperationUnchecked(int code, int uid, @NonNull String packageName,
3423             @Nullable String attributionTag, int proxyUid, String proxyPackageName,
3424             @Nullable String proxyAttributionTag, @OpFlags int flags,
3425             boolean shouldCollectAsyncNotedOp, @Nullable String message,
3426             boolean shouldCollectMessage) {
3427         PackageVerificationResult pvr;
3428         try {
3429             pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName);
3430             boolean wasNull = attributionTag == null;
3431             if (!pvr.isAttributionTagValid) {
3432                 attributionTag = null;
3433             }
3434         } catch (SecurityException e) {
3435             Slog.e(TAG, "noteOperation", e);
3436             return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
3437                     packageName);
3438         }
3439 
3440         synchronized (this) {
3441             final Ops ops = getOpsLocked(uid, packageName, attributionTag,
3442                     pvr.isAttributionTagValid, pvr.bypass, /* edit */ true);
3443             if (ops == null) {
3444                 scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
3445                         AppOpsManager.MODE_IGNORED);
3446                 if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
3447                         + " package " + packageName + "flags: " +
3448                         AppOpsManager.flagsToString(flags));
3449                 return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
3450                         packageName);
3451             }
3452             final Op op = getOpLocked(ops, code, uid, true);
3453             final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
3454             if (attributedOp.isRunning()) {
3455                 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code "
3456                         + code + " startTime of in progress event="
3457                         + attributedOp.mInProgressEvents.valueAt(0).getStartTime());
3458             }
3459 
3460             final int switchCode = AppOpsManager.opToSwitch(code);
3461             final UidState uidState = ops.uidState;
3462             if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass)) {
3463                 attributedOp.rejected(uidState.state, flags);
3464                 scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
3465                         AppOpsManager.MODE_IGNORED);
3466                 return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
3467                         packageName);
3468             }
3469             // If there is a non-default per UID policy (we set UID op mode only if
3470             // non-default) it takes over, otherwise use the per package policy.
3471             if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
3472                 final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode));
3473                 if (uidMode != AppOpsManager.MODE_ALLOWED) {
3474                     if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
3475                             + switchCode + " (" + code + ") uid " + uid + " package "
3476                             + packageName + " flags: " + AppOpsManager.flagsToString(flags));
3477                     attributedOp.rejected(uidState.state, flags);
3478                     scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
3479                             uidMode);
3480                     return new SyncNotedAppOp(uidMode, code, attributionTag, packageName);
3481                 }
3482             } else {
3483                 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
3484                         : op;
3485                 final int mode = switchOp.evalMode();
3486                 if (mode != AppOpsManager.MODE_ALLOWED) {
3487                     if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
3488                             + switchCode + " (" + code + ") uid " + uid + " package "
3489                             + packageName + " flags: " + AppOpsManager.flagsToString(flags));
3490                     attributedOp.rejected(uidState.state, flags);
3491                     scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
3492                             mode);
3493                     return new SyncNotedAppOp(mode, code, attributionTag, packageName);
3494                 }
3495             }
3496             if (DEBUG) {
3497                 Slog.d(TAG,
3498                         "noteOperation: allowing code " + code + " uid " + uid + " package "
3499                                 + packageName + (attributionTag == null ? ""
3500                                 : "." + attributionTag) + " flags: "
3501                                 + AppOpsManager.flagsToString(flags));
3502             }
3503             scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
3504                     AppOpsManager.MODE_ALLOWED);
3505             attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag, uidState.state,
3506                     flags);
3507 
3508             if (shouldCollectAsyncNotedOp) {
3509                 collectAsyncNotedOp(uid, packageName, code, attributionTag, flags, message,
3510                         shouldCollectMessage);
3511             }
3512 
3513             return new SyncNotedAppOp(AppOpsManager.MODE_ALLOWED, code, attributionTag,
3514                     packageName);
3515         }
3516     }
3517 
3518     // TODO moltmann: Allow watching for attribution ops
3519     @Override
startWatchingActive(int[] ops, IAppOpsActiveCallback callback)3520     public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
3521         int watchedUid = Process.INVALID_UID;
3522         final int callingUid = Binder.getCallingUid();
3523         final int callingPid = Binder.getCallingPid();
3524         if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
3525                 != PackageManager.PERMISSION_GRANTED) {
3526             watchedUid = callingUid;
3527         }
3528         if (ops != null) {
3529             Preconditions.checkArrayElementsInRange(ops, 0,
3530                     AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
3531         }
3532         if (callback == null) {
3533             return;
3534         }
3535         synchronized (this) {
3536             SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
3537             if (callbacks == null) {
3538                 callbacks = new SparseArray<>();
3539                 mActiveWatchers.put(callback.asBinder(), callbacks);
3540             }
3541             final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
3542                     callingUid, callingPid);
3543             for (int op : ops) {
3544                 callbacks.put(op, activeCallback);
3545             }
3546         }
3547     }
3548 
3549     @Override
stopWatchingActive(IAppOpsActiveCallback callback)3550     public void stopWatchingActive(IAppOpsActiveCallback callback) {
3551         if (callback == null) {
3552             return;
3553         }
3554         synchronized (this) {
3555             final SparseArray<ActiveCallback> activeCallbacks =
3556                     mActiveWatchers.remove(callback.asBinder());
3557             if (activeCallbacks == null) {
3558                 return;
3559             }
3560             final int callbackCount = activeCallbacks.size();
3561             for (int i = 0; i < callbackCount; i++) {
3562                 activeCallbacks.valueAt(i).destroy();
3563             }
3564         }
3565     }
3566 
3567     @Override
startWatchingStarted(int[] ops, @NonNull IAppOpsStartedCallback callback)3568     public void startWatchingStarted(int[] ops, @NonNull IAppOpsStartedCallback callback) {
3569         int watchedUid = Process.INVALID_UID;
3570         final int callingUid = Binder.getCallingUid();
3571         final int callingPid = Binder.getCallingPid();
3572         if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
3573                 != PackageManager.PERMISSION_GRANTED) {
3574             watchedUid = callingUid;
3575         }
3576 
3577         Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
3578         Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
3579                 "Invalid op code in: " + Arrays.toString(ops));
3580         Objects.requireNonNull(callback, "Callback cannot be null");
3581 
3582         synchronized (this) {
3583             SparseArray<StartedCallback> callbacks = mStartedWatchers.get(callback.asBinder());
3584             if (callbacks == null) {
3585                 callbacks = new SparseArray<>();
3586                 mStartedWatchers.put(callback.asBinder(), callbacks);
3587             }
3588 
3589             final StartedCallback startedCallback = new StartedCallback(callback, watchedUid,
3590                     callingUid, callingPid);
3591             for (int op : ops) {
3592                 callbacks.put(op, startedCallback);
3593             }
3594         }
3595     }
3596 
3597     @Override
stopWatchingStarted(IAppOpsStartedCallback callback)3598     public void stopWatchingStarted(IAppOpsStartedCallback callback) {
3599         Objects.requireNonNull(callback, "Callback cannot be null");
3600 
3601         synchronized (this) {
3602             final SparseArray<StartedCallback> startedCallbacks =
3603                     mStartedWatchers.remove(callback.asBinder());
3604             if (startedCallbacks == null) {
3605                 return;
3606             }
3607 
3608             final int callbackCount = startedCallbacks.size();
3609             for (int i = 0; i < callbackCount; i++) {
3610                 startedCallbacks.valueAt(i).destroy();
3611             }
3612         }
3613     }
3614 
3615     @Override
startWatchingNoted(@onNull int[] ops, @NonNull IAppOpsNotedCallback callback)3616     public void startWatchingNoted(@NonNull int[] ops, @NonNull IAppOpsNotedCallback callback) {
3617         int watchedUid = Process.INVALID_UID;
3618         final int callingUid = Binder.getCallingUid();
3619         final int callingPid = Binder.getCallingPid();
3620         if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
3621                 != PackageManager.PERMISSION_GRANTED) {
3622             watchedUid = callingUid;
3623         }
3624         Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
3625         Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
3626                 "Invalid op code in: " + Arrays.toString(ops));
3627         Objects.requireNonNull(callback, "Callback cannot be null");
3628         synchronized (this) {
3629             SparseArray<NotedCallback> callbacks = mNotedWatchers.get(callback.asBinder());
3630             if (callbacks == null) {
3631                 callbacks = new SparseArray<>();
3632                 mNotedWatchers.put(callback.asBinder(), callbacks);
3633             }
3634             final NotedCallback notedCallback = new NotedCallback(callback, watchedUid,
3635                     callingUid, callingPid);
3636             for (int op : ops) {
3637                 callbacks.put(op, notedCallback);
3638             }
3639         }
3640     }
3641 
3642     @Override
stopWatchingNoted(IAppOpsNotedCallback callback)3643     public void stopWatchingNoted(IAppOpsNotedCallback callback) {
3644         Objects.requireNonNull(callback, "Callback cannot be null");
3645         synchronized (this) {
3646             final SparseArray<NotedCallback> notedCallbacks =
3647                     mNotedWatchers.remove(callback.asBinder());
3648             if (notedCallbacks == null) {
3649                 return;
3650             }
3651             final int callbackCount = notedCallbacks.size();
3652             for (int i = 0; i < callbackCount; i++) {
3653                 notedCallbacks.valueAt(i).destroy();
3654             }
3655         }
3656     }
3657 
3658     /**
3659      * Collect an {@link AsyncNotedAppOp}.
3660      *
3661      * @param uid The uid the op was noted for
3662      * @param packageName The package the op was noted for
3663      * @param opCode The code of the op noted
3664      * @param attributionTag attribution tag the op was noted for
3665      * @param message The message for the op noting
3666      */
collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode, @Nullable String attributionTag, @OpFlags int flags, @NonNull String message, boolean shouldCollectMessage)3667     private void collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode,
3668             @Nullable String attributionTag, @OpFlags int flags, @NonNull String message,
3669             boolean shouldCollectMessage) {
3670         Objects.requireNonNull(message);
3671 
3672         int callingUid = Binder.getCallingUid();
3673 
3674         final long token = Binder.clearCallingIdentity();
3675         try {
3676             synchronized (this) {
3677                 Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
3678 
3679                 RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
3680                 AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
3681                         attributionTag, message, System.currentTimeMillis());
3682                 final boolean[] wasNoteForwarded = {false};
3683 
3684                 if ((flags & (OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED)) != 0
3685                         && shouldCollectMessage) {
3686                     reportRuntimeAppOpAccessMessageAsyncLocked(uid, packageName, opCode,
3687                             attributionTag, message);
3688                 }
3689 
3690                 if (callbacks != null) {
3691                     callbacks.broadcast((cb) -> {
3692                         try {
3693                             cb.opNoted(asyncNotedOp);
3694                             wasNoteForwarded[0] = true;
3695                         } catch (RemoteException e) {
3696                             Slog.e(TAG,
3697                                     "Could not forward noteOp of " + opCode + " to " + packageName
3698                                             + "/" + uid + "(" + attributionTag + ")", e);
3699                         }
3700                     });
3701                 }
3702 
3703                 if (!wasNoteForwarded[0]) {
3704                     ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(key);
3705                     if (unforwardedOps == null) {
3706                         unforwardedOps = new ArrayList<>(1);
3707                         mUnforwardedAsyncNotedOps.put(key, unforwardedOps);
3708                     }
3709 
3710                     unforwardedOps.add(asyncNotedOp);
3711                     if (unforwardedOps.size() > MAX_UNFORWARDED_OPS) {
3712                         unforwardedOps.remove(0);
3713                     }
3714                 }
3715             }
3716         } finally {
3717             Binder.restoreCallingIdentity(token);
3718         }
3719     }
3720 
3721     /**
3722      * Compute a key to be used in {@link #mAsyncOpWatchers} and {@link #mUnforwardedAsyncNotedOps}
3723      *
3724      * @param packageName The package name of the app
3725      * @param uid The uid of the app
3726      *
3727      * @return They key uniquely identifying the app
3728      */
getAsyncNotedOpsKey(@onNull String packageName, int uid)3729     private @NonNull Pair<String, Integer> getAsyncNotedOpsKey(@NonNull String packageName,
3730             int uid) {
3731         return new Pair<>(packageName, uid);
3732     }
3733 
3734     @Override
startWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback)3735     public void startWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) {
3736         Objects.requireNonNull(packageName);
3737         Objects.requireNonNull(callback);
3738 
3739         int uid = Binder.getCallingUid();
3740         Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
3741 
3742         verifyAndGetBypass(uid, packageName, null);
3743 
3744         synchronized (this) {
3745             RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
3746             if (callbacks == null) {
3747                 callbacks = new RemoteCallbackList<IAppOpsAsyncNotedCallback>() {
3748                     @Override
3749                     public void onCallbackDied(IAppOpsAsyncNotedCallback callback) {
3750                         synchronized (AppOpsService.this) {
3751                             if (getRegisteredCallbackCount() == 0) {
3752                                 mAsyncOpWatchers.remove(key);
3753                             }
3754                         }
3755                     }
3756                 };
3757                 mAsyncOpWatchers.put(key, callbacks);
3758             }
3759 
3760             callbacks.register(callback);
3761         }
3762     }
3763 
3764     @Override
stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback)3765     public void stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) {
3766         Objects.requireNonNull(packageName);
3767         Objects.requireNonNull(callback);
3768 
3769         int uid = Binder.getCallingUid();
3770         Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
3771 
3772         verifyAndGetBypass(uid, packageName, null);
3773 
3774         synchronized (this) {
3775             RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
3776             if (callbacks != null) {
3777                 callbacks.unregister(callback);
3778                 if (callbacks.getRegisteredCallbackCount() == 0) {
3779                     mAsyncOpWatchers.remove(key);
3780                 }
3781             }
3782         }
3783     }
3784 
3785     @Override
extractAsyncOps(String packageName)3786     public List<AsyncNotedAppOp> extractAsyncOps(String packageName) {
3787         Objects.requireNonNull(packageName);
3788 
3789         int uid = Binder.getCallingUid();
3790 
3791         verifyAndGetBypass(uid, packageName, null);
3792 
3793         synchronized (this) {
3794             return mUnforwardedAsyncNotedOps.remove(getAsyncNotedOpsKey(packageName, uid));
3795         }
3796     }
3797 
3798     @Override
startOperation(IBinder token, int code, int uid, @Nullable String packageName, @Nullable String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, @AttributionFlags int attributionFlags, int attributionChainId)3799     public SyncNotedAppOp startOperation(IBinder token, int code, int uid,
3800             @Nullable String packageName, @Nullable String attributionTag,
3801             boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
3802             String message, boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
3803             int attributionChainId) {
3804         return mCheckOpsDelegateDispatcher.startOperation(token, code, uid, packageName,
3805                 attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message,
3806                 shouldCollectMessage, attributionFlags, attributionChainId);
3807     }
3808 
startOperationImpl(@onNull IBinder clientId, int code, int uid, @Nullable String packageName, @Nullable String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @NonNull String message, boolean shouldCollectMessage, @AttributionFlags int attributionFlags, int attributionChainId)3809     private SyncNotedAppOp startOperationImpl(@NonNull IBinder clientId, int code, int uid,
3810             @Nullable String packageName, @Nullable String attributionTag,
3811             boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @NonNull String message,
3812             boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
3813             int attributionChainId) {
3814         verifyIncomingUid(uid);
3815         verifyIncomingOp(code);
3816         verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
3817 
3818         String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
3819         if (resolvedPackageName == null) {
3820             return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
3821                     packageName);
3822         }
3823 
3824         // As a special case for OP_RECORD_AUDIO_HOTWORD, which we use only for attribution
3825         // purposes and not as a check, also make sure that the caller is allowed to access
3826         // the data gated by OP_RECORD_AUDIO.
3827         //
3828         // TODO: Revert this change before Android 12.
3829         if (code == OP_RECORD_AUDIO_HOTWORD) {
3830             int result = checkOperation(OP_RECORD_AUDIO, uid, packageName);
3831             if (result != AppOpsManager.MODE_ALLOWED) {
3832                 return new SyncNotedAppOp(result, code, attributionTag, packageName);
3833             }
3834         }
3835         return startOperationUnchecked(clientId, code, uid, packageName, attributionTag,
3836                 Process.INVALID_UID, null, null, OP_FLAG_SELF, startIfModeDefault,
3837                 shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags,
3838                 attributionChainId, /*dryRun*/ false);
3839     }
3840 
3841     @Override
startProxyOperation(int code, @NonNull AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags, @AttributionFlags int proxiedAttributionFlags, int attributionChainId)3842     public SyncNotedAppOp startProxyOperation(int code,
3843             @NonNull AttributionSource attributionSource, boolean startIfModeDefault,
3844             boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
3845             boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags,
3846             @AttributionFlags int proxiedAttributionFlags, int attributionChainId) {
3847         return mCheckOpsDelegateDispatcher.startProxyOperation(code, attributionSource,
3848                 startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
3849                 skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlags,
3850                 attributionChainId);
3851     }
3852 
startProxyOperationImpl(int code, @NonNull AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags, @AttributionFlags int proxiedAttributionFlags, int attributionChainId)3853     private SyncNotedAppOp startProxyOperationImpl(int code,
3854             @NonNull AttributionSource attributionSource,
3855             boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message,
3856             boolean shouldCollectMessage, boolean skipProxyOperation, @AttributionFlags
3857             int proxyAttributionFlags, @AttributionFlags int proxiedAttributionFlags,
3858             int attributionChainId) {
3859         final int proxyUid = attributionSource.getUid();
3860         final String proxyPackageName = attributionSource.getPackageName();
3861         final String proxyAttributionTag = attributionSource.getAttributionTag();
3862         final IBinder proxyToken = attributionSource.getToken();
3863         final int proxiedUid = attributionSource.getNextUid();
3864         final String proxiedPackageName = attributionSource.getNextPackageName();
3865         final String proxiedAttributionTag = attributionSource.getNextAttributionTag();
3866         final IBinder proxiedToken = attributionSource.getNextToken();
3867 
3868         verifyIncomingProxyUid(attributionSource);
3869         verifyIncomingOp(code);
3870         verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid));
3871         verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid));
3872 
3873         boolean isCallerTrusted = isCallerAndAttributionTrusted(attributionSource);
3874         skipProxyOperation = isCallerTrusted && skipProxyOperation;
3875 
3876         String resolvedProxyPackageName = AppOpsManager.resolvePackageName(proxyUid,
3877                 proxyPackageName);
3878         if (resolvedProxyPackageName == null) {
3879             return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, proxiedAttributionTag,
3880                     proxiedPackageName);
3881         }
3882 
3883         final boolean isChainTrusted = isCallerTrusted
3884                 && attributionChainId != ATTRIBUTION_CHAIN_ID_NONE
3885                 && ((proxyAttributionFlags & ATTRIBUTION_FLAG_TRUSTED) != 0
3886                 || (proxiedAttributionFlags & ATTRIBUTION_FLAG_TRUSTED) != 0);
3887         final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid;
3888         final boolean isProxyTrusted = mContext.checkPermission(
3889                 Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
3890                 == PackageManager.PERMISSION_GRANTED || isSelfBlame
3891                 || isChainTrusted;
3892 
3893         String resolvedProxiedPackageName = AppOpsManager.resolvePackageName(proxiedUid,
3894                 proxiedPackageName);
3895         if (resolvedProxiedPackageName == null) {
3896             return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, proxiedAttributionTag,
3897                     proxiedPackageName);
3898         }
3899 
3900         final int proxiedFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXIED
3901                 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED;
3902 
3903         if (!skipProxyOperation) {
3904             // Test if the proxied operation will succeed before starting the proxy operation
3905             final SyncNotedAppOp testProxiedOp = startOperationUnchecked(proxiedToken, code,
3906                     proxiedUid, resolvedProxiedPackageName, proxiedAttributionTag, proxyUid,
3907                     resolvedProxyPackageName, proxyAttributionTag, proxiedFlags, startIfModeDefault,
3908                     shouldCollectAsyncNotedOp, message, shouldCollectMessage,
3909                     proxiedAttributionFlags, attributionChainId, /*dryRun*/ true);
3910             if (!shouldStartForMode(testProxiedOp.getOpMode(), startIfModeDefault)) {
3911                 return testProxiedOp;
3912             }
3913 
3914             final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
3915                     : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
3916 
3917             final SyncNotedAppOp proxyAppOp = startOperationUnchecked(proxyToken, code, proxyUid,
3918                     resolvedProxyPackageName, proxyAttributionTag, Process.INVALID_UID, null, null,
3919                     proxyFlags, startIfModeDefault, !isProxyTrusted, "proxy " + message,
3920                     shouldCollectMessage, proxyAttributionFlags, attributionChainId,
3921                     /*dryRun*/ false);
3922             if (!shouldStartForMode(proxyAppOp.getOpMode(), startIfModeDefault)) {
3923                 return proxyAppOp;
3924             }
3925         }
3926 
3927         return startOperationUnchecked(proxiedToken, code, proxiedUid, resolvedProxiedPackageName,
3928                 proxiedAttributionTag, proxyUid, resolvedProxyPackageName, proxyAttributionTag,
3929                 proxiedFlags, startIfModeDefault, shouldCollectAsyncNotedOp, message,
3930                 shouldCollectMessage, proxiedAttributionFlags, attributionChainId,
3931                 /*dryRun*/ false);
3932     }
3933 
shouldStartForMode(int mode, boolean startIfModeDefault)3934     private boolean shouldStartForMode(int mode, boolean startIfModeDefault) {
3935         return (mode == MODE_ALLOWED || (mode == MODE_DEFAULT && startIfModeDefault));
3936     }
3937 
startOperationUnchecked(IBinder clientId, int code, int uid, @NonNull String packageName, @Nullable String attributionTag, int proxyUid, String proxyPackageName, @Nullable String proxyAttributionTag, @OpFlags int flags, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @Nullable String message, boolean shouldCollectMessage, @AttributionFlags int attributionFlags, int attributionChainId, boolean dryRun)3938     private SyncNotedAppOp startOperationUnchecked(IBinder clientId, int code, int uid,
3939             @NonNull String packageName, @Nullable String attributionTag, int proxyUid,
3940             String proxyPackageName, @Nullable String proxyAttributionTag, @OpFlags int flags,
3941             boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @Nullable String message,
3942             boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
3943             int attributionChainId, boolean dryRun) {
3944         PackageVerificationResult pvr;
3945         try {
3946             pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName);
3947             if (!pvr.isAttributionTagValid) {
3948                 attributionTag = null;
3949             }
3950         } catch (SecurityException e) {
3951             Slog.e(TAG, "startOperation", e);
3952             return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
3953                     packageName);
3954         }
3955 
3956         boolean isRestricted = false;
3957         int startType = START_TYPE_FAILED;
3958         synchronized (this) {
3959             final Ops ops = getOpsLocked(uid, packageName, attributionTag,
3960                     pvr.isAttributionTagValid, pvr.bypass, /* edit */ true);
3961             if (ops == null) {
3962                 if (!dryRun) {
3963                     scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
3964                             flags, AppOpsManager.MODE_IGNORED, startType, attributionFlags,
3965                             attributionChainId);
3966                 }
3967                 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
3968                         + " package " + packageName + " flags: "
3969                         + AppOpsManager.flagsToString(flags));
3970                 return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
3971                         packageName);
3972             }
3973             final Op op = getOpLocked(ops, code, uid, true);
3974             final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
3975             final UidState uidState = ops.uidState;
3976             isRestricted = isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass);
3977             final int switchCode = AppOpsManager.opToSwitch(code);
3978             // If there is a non-default per UID policy (we set UID op mode only if
3979             // non-default) it takes over, otherwise use the per package policy.
3980             if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
3981                 final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode));
3982                 if (!shouldStartForMode(uidMode, startIfModeDefault)) {
3983                     if (DEBUG) {
3984                         Slog.d(TAG, "startOperation: uid reject #" + uidMode + " for code "
3985                                 + switchCode + " (" + code + ") uid " + uid + " package "
3986                                 + packageName + " flags: " + AppOpsManager.flagsToString(flags));
3987                     }
3988                     if (!dryRun) {
3989                         attributedOp.rejected(uidState.state, flags);
3990                         scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
3991                                 flags, uidMode, startType, attributionFlags, attributionChainId);
3992                     }
3993                     return new SyncNotedAppOp(uidMode, code, attributionTag, packageName);
3994                 }
3995             } else {
3996                 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
3997                         : op;
3998                 final int mode = switchOp.evalMode();
3999                 if (mode != AppOpsManager.MODE_ALLOWED
4000                         && (!startIfModeDefault || mode != MODE_DEFAULT)) {
4001                     if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
4002                             + switchCode + " (" + code + ") uid " + uid + " package "
4003                             + packageName + " flags: " + AppOpsManager.flagsToString(flags));
4004                     if (!dryRun) {
4005                         attributedOp.rejected(uidState.state, flags);
4006                         scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
4007                                 flags, mode, startType, attributionFlags, attributionChainId);
4008                     }
4009                     return new SyncNotedAppOp(mode, code, attributionTag, packageName);
4010                 }
4011             }
4012             if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
4013                     + " package " + packageName + " restricted: " + isRestricted
4014                     + " flags: " + AppOpsManager.flagsToString(flags));
4015             if (!dryRun) {
4016                 try {
4017                     if (isRestricted) {
4018                         attributedOp.createPaused(clientId, proxyUid, proxyPackageName,
4019                                 proxyAttributionTag, uidState.state, flags, attributionFlags,
4020                                 attributionChainId);
4021                     } else {
4022                         attributedOp.started(clientId, proxyUid, proxyPackageName,
4023                                 proxyAttributionTag, uidState.state, flags, attributionFlags,
4024                                 attributionChainId);
4025                         startType = START_TYPE_STARTED;
4026                     }
4027                 } catch (RemoteException e) {
4028                     throw new RuntimeException(e);
4029                 }
4030                 scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag, flags,
4031                         isRestricted ? MODE_IGNORED : MODE_ALLOWED, startType, attributionFlags,
4032                         attributionChainId);
4033             }
4034         }
4035 
4036         if (shouldCollectAsyncNotedOp && !dryRun && !isRestricted) {
4037             collectAsyncNotedOp(uid, packageName, code, attributionTag, AppOpsManager.OP_FLAG_SELF,
4038                     message, shouldCollectMessage);
4039         }
4040 
4041         return new SyncNotedAppOp(isRestricted ? MODE_IGNORED : MODE_ALLOWED, code, attributionTag,
4042                 packageName);
4043     }
4044 
4045     @Override
finishOperation(IBinder clientId, int code, int uid, String packageName, String attributionTag)4046     public void finishOperation(IBinder clientId, int code, int uid, String packageName,
4047             String attributionTag) {
4048         mCheckOpsDelegateDispatcher.finishOperation(clientId, code, uid, packageName,
4049                 attributionTag);
4050     }
4051 
finishOperationImpl(IBinder clientId, int code, int uid, String packageName, String attributionTag)4052     private void finishOperationImpl(IBinder clientId, int code, int uid, String packageName,
4053             String attributionTag) {
4054         verifyIncomingUid(uid);
4055         verifyIncomingOp(code);
4056         verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
4057 
4058         String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
4059         if (resolvedPackageName == null) {
4060             return;
4061         }
4062 
4063         finishOperationUnchecked(clientId, code, uid, resolvedPackageName, attributionTag);
4064     }
4065 
4066     @Override
finishProxyOperation(int code, @NonNull AttributionSource attributionSource, boolean skipProxyOperation)4067     public void finishProxyOperation(int code, @NonNull AttributionSource attributionSource,
4068             boolean skipProxyOperation) {
4069         mCheckOpsDelegateDispatcher.finishProxyOperation(code, attributionSource,
4070                 skipProxyOperation);
4071     }
4072 
finishProxyOperationImpl(int code, @NonNull AttributionSource attributionSource, boolean skipProxyOperation)4073     private Void finishProxyOperationImpl(int code, @NonNull AttributionSource attributionSource,
4074             boolean skipProxyOperation) {
4075         final int proxyUid = attributionSource.getUid();
4076         final String proxyPackageName = attributionSource.getPackageName();
4077         final String proxyAttributionTag = attributionSource.getAttributionTag();
4078         final IBinder proxyToken = attributionSource.getToken();
4079         final int proxiedUid = attributionSource.getNextUid();
4080         final String proxiedPackageName = attributionSource.getNextPackageName();
4081         final String proxiedAttributionTag = attributionSource.getNextAttributionTag();
4082         final IBinder proxiedToken = attributionSource.getNextToken();
4083 
4084         skipProxyOperation = skipProxyOperation
4085                 && isCallerAndAttributionTrusted(attributionSource);
4086 
4087         verifyIncomingProxyUid(attributionSource);
4088         verifyIncomingOp(code);
4089         verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid));
4090         verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid));
4091 
4092         String resolvedProxyPackageName = AppOpsManager.resolvePackageName(proxyUid,
4093                 proxyPackageName);
4094         if (resolvedProxyPackageName == null) {
4095             return null;
4096         }
4097 
4098         if (!skipProxyOperation) {
4099             finishOperationUnchecked(proxyToken, code, proxyUid, resolvedProxyPackageName,
4100                     proxyAttributionTag);
4101         }
4102 
4103         String resolvedProxiedPackageName = AppOpsManager.resolvePackageName(proxiedUid,
4104                 proxiedPackageName);
4105         if (resolvedProxiedPackageName == null) {
4106             return null;
4107         }
4108 
4109         finishOperationUnchecked(proxiedToken, code, proxiedUid, resolvedProxiedPackageName,
4110                 proxiedAttributionTag);
4111 
4112         return null;
4113     }
4114 
finishOperationUnchecked(IBinder clientId, int code, int uid, String packageName, String attributionTag)4115     private void finishOperationUnchecked(IBinder clientId, int code, int uid, String packageName,
4116             String attributionTag) {
4117         PackageVerificationResult pvr;
4118         try {
4119             pvr = verifyAndGetBypass(uid, packageName, attributionTag);
4120             if (!pvr.isAttributionTagValid) {
4121                 attributionTag = null;
4122             }
4123         } catch (SecurityException e) {
4124             Slog.e(TAG, "Cannot finishOperation", e);
4125             return;
4126         }
4127 
4128         synchronized (this) {
4129             Op op = getOpLocked(code, uid, packageName, attributionTag, pvr.isAttributionTagValid,
4130                     pvr.bypass, /* edit */ true);
4131             if (op == null) {
4132                 Slog.e(TAG, "Operation not found: uid=" + uid + " pkg=" + packageName + "("
4133                         + attributionTag + ") op=" + AppOpsManager.opToName(code));
4134                 return;
4135             }
4136             final AttributedOp attributedOp = op.mAttributions.get(attributionTag);
4137             if (attributedOp == null) {
4138                 Slog.e(TAG, "Attribution not found: uid=" + uid + " pkg=" + packageName + "("
4139                         + attributionTag + ") op=" + AppOpsManager.opToName(code));
4140                 return;
4141             }
4142 
4143             if (attributedOp.isRunning() || attributedOp.isPaused()) {
4144                 attributedOp.finished(clientId);
4145             } else {
4146                 Slog.e(TAG, "Operation not started: uid=" + uid + " pkg=" + packageName + "("
4147                         + attributionTag + ") op=" + AppOpsManager.opToName(code));
4148             }
4149         }
4150     }
4151 
scheduleOpActiveChangedIfNeededLocked(int code, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean active, @AttributionFlags int attributionFlags, int attributionChainId)4152     private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, @NonNull
4153             String packageName, @Nullable String attributionTag, boolean active, @AttributionFlags
4154             int attributionFlags, int attributionChainId) {
4155         ArraySet<ActiveCallback> dispatchedCallbacks = null;
4156         final int callbackListCount = mActiveWatchers.size();
4157         for (int i = 0; i < callbackListCount; i++) {
4158             final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
4159             ActiveCallback callback = callbacks.get(code);
4160             if (callback != null) {
4161                 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
4162                     continue;
4163                 }
4164                 if (dispatchedCallbacks == null) {
4165                     dispatchedCallbacks = new ArraySet<>();
4166                 }
4167                 dispatchedCallbacks.add(callback);
4168             }
4169         }
4170         if (dispatchedCallbacks == null) {
4171             return;
4172         }
4173         mHandler.sendMessage(PooledLambda.obtainMessage(
4174                 AppOpsService::notifyOpActiveChanged,
4175                 this, dispatchedCallbacks, code, uid, packageName, attributionTag, active,
4176                 attributionFlags, attributionChainId));
4177     }
4178 
notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks, int code, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean active, @AttributionFlags int attributionFlags, int attributionChainId)4179     private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
4180             int code, int uid, @NonNull String packageName, @Nullable String attributionTag,
4181             boolean active, @AttributionFlags int attributionFlags, int attributionChainId) {
4182         // There are features watching for mode changes such as window manager
4183         // and location manager which are in our process. The callbacks in these
4184         // features may require permissions our remote caller does not have.
4185         final long identity = Binder.clearCallingIdentity();
4186         try {
4187             final int callbackCount = callbacks.size();
4188             for (int i = 0; i < callbackCount; i++) {
4189                 final ActiveCallback callback = callbacks.valueAt(i);
4190                 try {
4191                     callback.mCallback.opActiveChanged(code, uid, packageName, attributionTag,
4192                             active, attributionFlags, attributionChainId);
4193                 } catch (RemoteException e) {
4194                     /* do nothing */
4195                 }
4196             }
4197         } finally {
4198             Binder.restoreCallingIdentity(identity);
4199         }
4200     }
4201 
scheduleOpStartedIfNeededLocked(int code, int uid, String pkgName, String attributionTag, @OpFlags int flags, @Mode int result, @AppOpsManager.OnOpStartedListener.StartedType int startedType, @AttributionFlags int attributionFlags, int attributionChainId)4202     private void scheduleOpStartedIfNeededLocked(int code, int uid, String pkgName,
4203             String attributionTag, @OpFlags int flags, @Mode int result,
4204             @AppOpsManager.OnOpStartedListener.StartedType int startedType,
4205             @AttributionFlags int attributionFlags, int attributionChainId) {
4206         ArraySet<StartedCallback> dispatchedCallbacks = null;
4207         final int callbackListCount = mStartedWatchers.size();
4208         for (int i = 0; i < callbackListCount; i++) {
4209             final SparseArray<StartedCallback> callbacks = mStartedWatchers.valueAt(i);
4210 
4211             StartedCallback callback = callbacks.get(code);
4212             if (callback != null) {
4213                 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
4214                     continue;
4215                 }
4216 
4217                 if (dispatchedCallbacks == null) {
4218                     dispatchedCallbacks = new ArraySet<>();
4219                 }
4220                 dispatchedCallbacks.add(callback);
4221             }
4222         }
4223 
4224         if (dispatchedCallbacks == null) {
4225             return;
4226         }
4227 
4228         mHandler.sendMessage(PooledLambda.obtainMessage(
4229                 AppOpsService::notifyOpStarted,
4230                 this, dispatchedCallbacks, code, uid, pkgName, attributionTag, flags,
4231                 result, startedType, attributionFlags, attributionChainId));
4232     }
4233 
notifyOpStarted(ArraySet<StartedCallback> callbacks, int code, int uid, String packageName, String attributionTag, @OpFlags int flags, @Mode int result, @AppOpsManager.OnOpStartedListener.StartedType int startedType, @AttributionFlags int attributionFlags, int attributionChainId)4234     private void notifyOpStarted(ArraySet<StartedCallback> callbacks,
4235             int code, int uid, String packageName, String attributionTag, @OpFlags int flags,
4236             @Mode int result, @AppOpsManager.OnOpStartedListener.StartedType int startedType,
4237             @AttributionFlags int attributionFlags, int attributionChainId) {
4238         final long identity = Binder.clearCallingIdentity();
4239         try {
4240             final int callbackCount = callbacks.size();
4241             for (int i = 0; i < callbackCount; i++) {
4242                 final StartedCallback callback = callbacks.valueAt(i);
4243                 try {
4244                     callback.mCallback.opStarted(code, uid, packageName, attributionTag, flags,
4245                             result, startedType, attributionFlags, attributionChainId);
4246                 } catch (RemoteException e) {
4247                     /* do nothing */
4248                 }
4249             }
4250         } finally {
4251             Binder.restoreCallingIdentity(identity);
4252         }
4253     }
4254 
scheduleOpNotedIfNeededLocked(int code, int uid, String packageName, String attributionTag, @OpFlags int flags, @Mode int result)4255     private void scheduleOpNotedIfNeededLocked(int code, int uid, String packageName,
4256             String attributionTag, @OpFlags int flags, @Mode int result) {
4257         ArraySet<NotedCallback> dispatchedCallbacks = null;
4258         final int callbackListCount = mNotedWatchers.size();
4259         for (int i = 0; i < callbackListCount; i++) {
4260             final SparseArray<NotedCallback> callbacks = mNotedWatchers.valueAt(i);
4261             final NotedCallback callback = callbacks.get(code);
4262             if (callback != null) {
4263                 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
4264                     continue;
4265                 }
4266                 if (dispatchedCallbacks == null) {
4267                     dispatchedCallbacks = new ArraySet<>();
4268                 }
4269                 dispatchedCallbacks.add(callback);
4270             }
4271         }
4272         if (dispatchedCallbacks == null) {
4273             return;
4274         }
4275         mHandler.sendMessage(PooledLambda.obtainMessage(
4276                 AppOpsService::notifyOpChecked,
4277                 this, dispatchedCallbacks, code, uid, packageName, attributionTag, flags,
4278                 result));
4279     }
4280 
notifyOpChecked(ArraySet<NotedCallback> callbacks, int code, int uid, String packageName, String attributionTag, @OpFlags int flags, @Mode int result)4281     private void notifyOpChecked(ArraySet<NotedCallback> callbacks,
4282             int code, int uid, String packageName, String attributionTag, @OpFlags int flags,
4283             @Mode int result) {
4284         // There are features watching for checks in our process. The callbacks in
4285         // these features may require permissions our remote caller does not have.
4286         final long identity = Binder.clearCallingIdentity();
4287         try {
4288             final int callbackCount = callbacks.size();
4289             for (int i = 0; i < callbackCount; i++) {
4290                 final NotedCallback callback = callbacks.valueAt(i);
4291                 try {
4292                     callback.mCallback.opNoted(code, uid, packageName, attributionTag, flags,
4293                             result);
4294                 } catch (RemoteException e) {
4295                     /* do nothing */
4296                 }
4297             }
4298         } finally {
4299             Binder.restoreCallingIdentity(identity);
4300         }
4301     }
4302 
4303     @Override
permissionToOpCode(String permission)4304     public int permissionToOpCode(String permission) {
4305         if (permission == null) {
4306             return AppOpsManager.OP_NONE;
4307         }
4308         return AppOpsManager.permissionToOpCode(permission);
4309     }
4310 
4311     @Override
shouldCollectNotes(int opCode)4312     public boolean shouldCollectNotes(int opCode) {
4313         Preconditions.checkArgumentInRange(opCode, 0, _NUM_OP - 1, "opCode");
4314 
4315         String perm = AppOpsManager.opToPermission(opCode);
4316         if (perm == null) {
4317             return false;
4318         }
4319 
4320         PermissionInfo permInfo;
4321         try {
4322             permInfo = mContext.getPackageManager().getPermissionInfo(perm, 0);
4323         } catch (PackageManager.NameNotFoundException e) {
4324             return false;
4325         }
4326 
4327         return permInfo.getProtection() == PROTECTION_DANGEROUS
4328                 || (permInfo.getProtectionFlags() & PROTECTION_FLAG_APPOP) != 0;
4329     }
4330 
verifyIncomingProxyUid(@onNull AttributionSource attributionSource)4331     private void verifyIncomingProxyUid(@NonNull AttributionSource attributionSource) {
4332         if (attributionSource.getUid() == Binder.getCallingUid()) {
4333             return;
4334         }
4335         if (Binder.getCallingPid() == Process.myPid()) {
4336             return;
4337         }
4338         if (attributionSource.isTrusted(mContext)) {
4339             return;
4340         }
4341         mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
4342                 Binder.getCallingPid(), Binder.getCallingUid(), null);
4343     }
4344 
verifyIncomingUid(int uid)4345     private void verifyIncomingUid(int uid) {
4346         if (uid == Binder.getCallingUid()) {
4347             return;
4348         }
4349         if (Binder.getCallingPid() == Process.myPid()) {
4350             return;
4351         }
4352         mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
4353                 Binder.getCallingPid(), Binder.getCallingUid(), null);
4354     }
4355 
verifyIncomingOp(int op)4356     private void verifyIncomingOp(int op) {
4357         if (op >= 0 && op < AppOpsManager._NUM_OP) {
4358             return;
4359         }
4360         throw new IllegalArgumentException("Bad operation #" + op);
4361     }
4362 
verifyIncomingPackage(@ullable String packageName, @UserIdInt int userId)4363     private void verifyIncomingPackage(@Nullable String packageName, @UserIdInt int userId) {
4364         if (packageName != null && getPackageManagerInternal().filterAppAccess(packageName,
4365                 Binder.getCallingUid(), userId)) {
4366             throw new IllegalArgumentException(
4367                     packageName + " not found from " + Binder.getCallingUid());
4368         }
4369     }
4370 
isCallerAndAttributionTrusted(@onNull AttributionSource attributionSource)4371     private boolean isCallerAndAttributionTrusted(@NonNull AttributionSource attributionSource) {
4372         if (attributionSource.getUid() != Binder.getCallingUid()
4373                 && attributionSource.isTrusted(mContext)) {
4374             return true;
4375         }
4376         return mContext.checkPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
4377                 Binder.getCallingPid(), Binder.getCallingUid(), null)
4378                 == PackageManager.PERMISSION_GRANTED;
4379     }
4380 
getUidStateLocked(int uid, boolean edit)4381     private @Nullable UidState getUidStateLocked(int uid, boolean edit) {
4382         UidState uidState = mUidStates.get(uid);
4383         if (uidState == null) {
4384             if (!edit) {
4385                 return null;
4386             }
4387             uidState = new UidState(uid);
4388             mUidStates.put(uid, uidState);
4389         } else {
4390             updatePendingStateIfNeededLocked(uidState);
4391         }
4392         return uidState;
4393     }
4394 
4395     /**
4396      * Check if the pending state should be updated and do so if needed
4397      *
4398      * @param uidState The uidState that might have a pending state
4399      */
updatePendingStateIfNeededLocked(@onNull UidState uidState)4400     private void updatePendingStateIfNeededLocked(@NonNull UidState uidState) {
4401         if (uidState != null) {
4402             if (uidState.pendingStateCommitTime != 0) {
4403                 if (uidState.pendingStateCommitTime < mLastRealtime) {
4404                     commitUidPendingStateLocked(uidState);
4405                 } else {
4406                     mLastRealtime = SystemClock.elapsedRealtime();
4407                     if (uidState.pendingStateCommitTime < mLastRealtime) {
4408                         commitUidPendingStateLocked(uidState);
4409                     }
4410                 }
4411             }
4412         }
4413     }
4414 
commitUidPendingStateLocked(UidState uidState)4415     private void commitUidPendingStateLocked(UidState uidState) {
4416         if (uidState.hasForegroundWatchers) {
4417             for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
4418                 if (!uidState.foregroundOps.valueAt(fgi)) {
4419                     continue;
4420                 }
4421                 final int code = uidState.foregroundOps.keyAt(fgi);
4422                 // For location ops we consider fg state only if the fg service
4423                 // is of location type, for all other ops any fg service will do.
4424                 final long firstUnrestrictedUidState = resolveFirstUnrestrictedUidState(code);
4425                 final boolean resolvedLastFg = uidState.state <= firstUnrestrictedUidState;
4426                 final boolean resolvedNowFg = uidState.pendingState <= firstUnrestrictedUidState;
4427                 if (resolvedLastFg == resolvedNowFg
4428                         && uidState.capability == uidState.pendingCapability
4429                         && uidState.appWidgetVisible == uidState.pendingAppWidgetVisible) {
4430                     continue;
4431                 }
4432 
4433                 if (uidState.opModes != null
4434                         && uidState.opModes.indexOfKey(code) >= 0
4435                         && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND) {
4436                     mHandler.sendMessage(PooledLambda.obtainMessage(
4437                             AppOpsService::notifyOpChangedForAllPkgsInUid,
4438                             this, code, uidState.uid, true, null));
4439                 } else if (uidState.pkgOps != null) {
4440                     final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
4441                     if (callbacks != null) {
4442                         for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
4443                             final ModeCallback callback = callbacks.valueAt(cbi);
4444                             if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
4445                                     || !callback.isWatchingUid(uidState.uid)) {
4446                                 continue;
4447                             }
4448                             for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
4449                                 final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
4450                                 if (op == null) {
4451                                     continue;
4452                                 }
4453                                 if (op.mode == AppOpsManager.MODE_FOREGROUND) {
4454                                     mHandler.sendMessage(PooledLambda.obtainMessage(
4455                                             AppOpsService::notifyOpChanged,
4456                                             this, callback, code, uidState.uid,
4457                                             uidState.pkgOps.keyAt(pkgi)));
4458                                 }
4459                             }
4460                         }
4461                     }
4462                 }
4463             }
4464         }
4465         uidState.state = uidState.pendingState;
4466         uidState.capability = uidState.pendingCapability;
4467         uidState.appWidgetVisible = uidState.pendingAppWidgetVisible;
4468         uidState.pendingStateCommitTime = 0;
4469     }
4470 
updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible)4471     private void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible) {
4472         synchronized (this) {
4473             for (int i = uidPackageNames.size() - 1; i >= 0; i--) {
4474                 final int uid = uidPackageNames.keyAt(i);
4475                 final UidState uidState = getUidStateLocked(uid, true);
4476                 if (uidState != null && (uidState.pendingAppWidgetVisible != visible)) {
4477                     uidState.pendingAppWidgetVisible = visible;
4478                     if (uidState.pendingAppWidgetVisible != uidState.appWidgetVisible) {
4479                         commitUidPendingStateLocked(uidState);
4480                     }
4481                 }
4482             }
4483         }
4484     }
4485 
4486     /**
4487      * @return {@link PackageManagerInternal}
4488      */
getPackageManagerInternal()4489     private @NonNull PackageManagerInternal getPackageManagerInternal() {
4490         if (mPackageManagerInternal == null) {
4491             mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
4492         }
4493 
4494         return mPackageManagerInternal;
4495     }
4496 
4497     /**
4498      * Create a restriction description matching the properties of the package.
4499      *
4500      * @param pkg The package to create the restriction description for
4501      *
4502      * @return The restriction matching the package
4503      */
getBypassforPackage(@onNull AndroidPackage pkg)4504     private RestrictionBypass getBypassforPackage(@NonNull AndroidPackage pkg) {
4505         return new RestrictionBypass(pkg.isPrivileged(), mContext.checkPermission(
4506                 android.Manifest.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS, -1, pkg.getUid())
4507                 == PackageManager.PERMISSION_GRANTED);
4508     }
4509 
4510     /**
4511      * @see #verifyAndGetBypass(int, String, String, String)
4512      */
verifyAndGetBypass(int uid, String packageName, @Nullable String attributionTag)4513     private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName,
4514             @Nullable String attributionTag) {
4515         return verifyAndGetBypass(uid, packageName, attributionTag, null);
4516     }
4517 
4518     /**
4519      * Verify that package belongs to uid and return the {@link RestrictionBypass bypass
4520      * description} for the package, along with a boolean indicating whether the attribution tag is
4521      * valid.
4522      *
4523      * @param uid The uid the package belongs to
4524      * @param packageName The package the might belong to the uid
4525      * @param attributionTag attribution tag or {@code null} if no need to verify
4526      * @param proxyPackageName The proxy package, from which the attribution tag is to be pulled
4527      *
4528      * @return PackageVerificationResult containing {@link RestrictionBypass} and whether the
4529      *         attribution tag is valid
4530      */
verifyAndGetBypass(int uid, String packageName, @Nullable String attributionTag, @Nullable String proxyPackageName)4531     private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName,
4532             @Nullable String attributionTag, @Nullable String proxyPackageName) {
4533         if (uid == Process.ROOT_UID) {
4534             // For backwards compatibility, don't check package name for root UID.
4535             return new PackageVerificationResult(null,
4536                     /* isAttributionTagValid */ true);
4537         }
4538 
4539         // Do not check if uid/packageName/attributionTag is already known.
4540         synchronized (this) {
4541             UidState uidState = mUidStates.get(uid);
4542             if (uidState != null && uidState.pkgOps != null) {
4543                 Ops ops = uidState.pkgOps.get(packageName);
4544 
4545                 if (ops != null && (attributionTag == null || ops.knownAttributionTags.contains(
4546                         attributionTag)) && ops.bypass != null) {
4547                     return new PackageVerificationResult(ops.bypass,
4548                             ops.validAttributionTags.contains(attributionTag));
4549                 }
4550             }
4551         }
4552 
4553         int callingUid = Binder.getCallingUid();
4554 
4555         // Allow any attribution tag for resolvable uids
4556         int pkgUid;
4557         if (Objects.equals(packageName, "com.android.shell")) {
4558             // Special case for the shell which is a package but should be able
4559             // to bypass app attribution tag restrictions.
4560             pkgUid = Process.SHELL_UID;
4561         } else {
4562             pkgUid = resolveUid(packageName);
4563         }
4564         if (pkgUid != Process.INVALID_UID) {
4565             if (pkgUid != UserHandle.getAppId(uid)) {
4566                 String otherUidMessage = DEBUG ? " but it is really " + pkgUid : " but it is not";
4567                 throw new SecurityException("Specified package " + packageName + " under uid "
4568                         +  UserHandle.getAppId(uid) + otherUidMessage);
4569             }
4570             return new PackageVerificationResult(RestrictionBypass.UNRESTRICTED,
4571                     /* isAttributionTagValid */ true);
4572         }
4573 
4574         int userId = UserHandle.getUserId(uid);
4575         RestrictionBypass bypass = null;
4576         boolean isAttributionTagValid = false;
4577 
4578         final long ident = Binder.clearCallingIdentity();
4579         try {
4580             PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
4581             AndroidPackage pkg = pmInt.getPackage(packageName);
4582             if (pkg != null) {
4583                 isAttributionTagValid = isAttributionInPackage(pkg, attributionTag);
4584                 pkgUid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid()));
4585                 bypass = getBypassforPackage(pkg);
4586             }
4587             if (!isAttributionTagValid) {
4588                 AndroidPackage proxyPkg = proxyPackageName != null
4589                         ? pmInt.getPackage(proxyPackageName) : null;
4590                 // Re-check in proxy.
4591                 isAttributionTagValid = isAttributionInPackage(proxyPkg, attributionTag);
4592                 String msg;
4593                 if (pkg != null && isAttributionTagValid) {
4594                     msg = "attributionTag " + attributionTag + " declared in manifest of the proxy"
4595                             + " package " + proxyPackageName + ", this is not advised";
4596                 } else if (pkg != null) {
4597                     msg = "attributionTag " + attributionTag + " not declared in manifest of "
4598                             + packageName;
4599                 } else {
4600                     msg = "package " + packageName + " not found, can't check for "
4601                             + "attributionTag " + attributionTag;
4602                 }
4603 
4604                 try {
4605                     if (!mPlatformCompat.isChangeEnabledByPackageName(
4606                             SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE, packageName,
4607                             userId) || !mPlatformCompat.isChangeEnabledByUid(
4608                                     SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE,
4609                             callingUid)) {
4610                         // Do not override tags if overriding is not enabled for this package
4611                         isAttributionTagValid = true;
4612                     }
4613                     Slog.e(TAG, msg);
4614                 } catch (RemoteException neverHappens) {
4615                 }
4616             }
4617         } finally {
4618             Binder.restoreCallingIdentity(ident);
4619         }
4620 
4621         if (pkgUid != uid) {
4622             String otherUidMessage = DEBUG ? " but it is really " + pkgUid : " but it is not";
4623             throw new SecurityException("Specified package " + packageName + " under uid " + uid
4624                     + otherUidMessage);
4625         }
4626 
4627         return new PackageVerificationResult(bypass, isAttributionTagValid);
4628     }
4629 
isAttributionInPackage(@ullable AndroidPackage pkg, @Nullable String attributionTag)4630     private boolean isAttributionInPackage(@Nullable AndroidPackage pkg,
4631             @Nullable String attributionTag) {
4632         if (pkg == null) {
4633             return false;
4634         } else if (attributionTag == null) {
4635             return true;
4636         }
4637         if (pkg.getAttributions() != null) {
4638             int numAttributions = pkg.getAttributions().size();
4639             for (int i = 0; i < numAttributions; i++) {
4640                 if (pkg.getAttributions().get(i).tag.equals(attributionTag)) {
4641                     return true;
4642                 }
4643             }
4644         }
4645 
4646         return false;
4647     }
4648 
4649     /**
4650      * Get (and potentially create) ops.
4651      *
4652      * @param uid The uid the package belongs to
4653      * @param packageName The name of the package
4654      * @param attributionTag attribution tag
4655      * @param isAttributionTagValid whether the given attribution tag is valid
4656      * @param bypass When to bypass certain op restrictions (can be null if edit == false)
4657      * @param edit If an ops does not exist, create the ops?
4658 
4659      * @return The ops
4660      */
getOpsLocked(int uid, String packageName, @Nullable String attributionTag, boolean isAttributionTagValid, @Nullable RestrictionBypass bypass, boolean edit)4661     private Ops getOpsLocked(int uid, String packageName, @Nullable String attributionTag,
4662             boolean isAttributionTagValid, @Nullable RestrictionBypass bypass, boolean edit) {
4663         UidState uidState = getUidStateLocked(uid, edit);
4664         if (uidState == null) {
4665             return null;
4666         }
4667 
4668         if (uidState.pkgOps == null) {
4669             if (!edit) {
4670                 return null;
4671             }
4672             uidState.pkgOps = new ArrayMap<>();
4673         }
4674 
4675         Ops ops = uidState.pkgOps.get(packageName);
4676         if (ops == null) {
4677             if (!edit) {
4678                 return null;
4679             }
4680             ops = new Ops(packageName, uidState);
4681             uidState.pkgOps.put(packageName, ops);
4682         }
4683 
4684         if (edit) {
4685             if (bypass != null) {
4686                 ops.bypass = bypass;
4687             }
4688 
4689             if (attributionTag != null) {
4690                 ops.knownAttributionTags.add(attributionTag);
4691                 if (isAttributionTagValid) {
4692                     ops.validAttributionTags.add(attributionTag);
4693                 } else {
4694                     ops.validAttributionTags.remove(attributionTag);
4695                 }
4696             }
4697         }
4698 
4699         return ops;
4700     }
4701 
scheduleWriteLocked()4702     private void scheduleWriteLocked() {
4703         if (!mWriteScheduled) {
4704             mWriteScheduled = true;
4705             mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
4706         }
4707     }
4708 
scheduleFastWriteLocked()4709     private void scheduleFastWriteLocked() {
4710         if (!mFastWriteScheduled) {
4711             mWriteScheduled = true;
4712             mFastWriteScheduled = true;
4713             mHandler.removeCallbacks(mWriteRunner);
4714             mHandler.postDelayed(mWriteRunner, 10*1000);
4715         }
4716     }
4717 
4718     /**
4719      * Get the state of an op for a uid.
4720      *
4721      * @param code The code of the op
4722      * @param uid The uid the of the package
4723      * @param packageName The package name for which to get the state for
4724      * @param attributionTag The attribution tag
4725      * @param isAttributionTagValid Whether the given attribution tag is valid
4726      * @param bypass When to bypass certain op restrictions (can be null if edit == false)
4727      * @param edit Iff {@code true} create the {@link Op} object if not yet created
4728      *
4729      * @return The {@link Op state} of the op
4730      */
getOpLocked(int code, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean isAttributionTagValid, @Nullable RestrictionBypass bypass, boolean edit)4731     private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
4732             @Nullable String attributionTag, boolean isAttributionTagValid,
4733             @Nullable RestrictionBypass bypass, boolean edit) {
4734         Ops ops = getOpsLocked(uid, packageName, attributionTag, isAttributionTagValid, bypass,
4735                 edit);
4736         if (ops == null) {
4737             return null;
4738         }
4739         return getOpLocked(ops, code, uid, edit);
4740     }
4741 
getOpLocked(Ops ops, int code, int uid, boolean edit)4742     private Op getOpLocked(Ops ops, int code, int uid, boolean edit) {
4743         Op op = ops.get(code);
4744         if (op == null) {
4745             if (!edit) {
4746                 return null;
4747             }
4748             op = new Op(ops.uidState, ops.packageName, code, uid);
4749             ops.put(code, op);
4750         }
4751         if (edit) {
4752             scheduleWriteLocked();
4753         }
4754         return op;
4755     }
4756 
isOpRestrictedDueToSuspend(int code, String packageName, int uid)4757     private boolean isOpRestrictedDueToSuspend(int code, String packageName, int uid) {
4758         if (!ArrayUtils.contains(OPS_RESTRICTED_ON_SUSPEND, code)) {
4759             return false;
4760         }
4761         final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
4762         return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid));
4763     }
4764 
isOpRestrictedLocked(int uid, int code, String packageName, String attributionTag, @Nullable RestrictionBypass appBypass)4765     private boolean isOpRestrictedLocked(int uid, int code, String packageName,
4766             String attributionTag, @Nullable RestrictionBypass appBypass) {
4767         int restrictionSetCount = mOpGlobalRestrictions.size();
4768 
4769         for (int i = 0; i < restrictionSetCount; i++) {
4770             ClientGlobalRestrictionState restrictionState = mOpGlobalRestrictions.valueAt(i);
4771             if (restrictionState.hasRestriction(code)) {
4772                 return true;
4773             }
4774         }
4775 
4776         int userHandle = UserHandle.getUserId(uid);
4777         restrictionSetCount = mOpUserRestrictions.size();
4778 
4779         for (int i = 0; i < restrictionSetCount; i++) {
4780             // For each client, check that the given op is not restricted, or that the given
4781             // package is exempt from the restriction.
4782             ClientUserRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
4783             if (restrictionState.hasRestriction(code, packageName, attributionTag, userHandle)) {
4784                 RestrictionBypass opBypass = opAllowSystemBypassRestriction(code);
4785                 if (opBypass != null) {
4786                     // If we are the system, bypass user restrictions for certain codes
4787                     synchronized (this) {
4788                         if (opBypass.isPrivileged && appBypass != null && appBypass.isPrivileged) {
4789                             return false;
4790                         }
4791                         if (opBypass.isRecordAudioRestrictionExcept && appBypass != null
4792                                 && appBypass.isRecordAudioRestrictionExcept) {
4793                             return false;
4794                         }
4795                     }
4796                 }
4797                 return true;
4798             }
4799         }
4800         return false;
4801     }
4802 
readState()4803     void readState() {
4804         int oldVersion = NO_VERSION;
4805         synchronized (mFile) {
4806             synchronized (this) {
4807                 FileInputStream stream;
4808                 try {
4809                     stream = mFile.openRead();
4810                 } catch (FileNotFoundException e) {
4811                     Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
4812                     return;
4813                 }
4814                 boolean success = false;
4815                 mUidStates.clear();
4816                 try {
4817                     TypedXmlPullParser parser = Xml.resolvePullParser(stream);
4818                     int type;
4819                     while ((type = parser.next()) != XmlPullParser.START_TAG
4820                             && type != XmlPullParser.END_DOCUMENT) {
4821                         ;
4822                     }
4823 
4824                     if (type != XmlPullParser.START_TAG) {
4825                         throw new IllegalStateException("no start tag found");
4826                     }
4827 
4828                     oldVersion = parser.getAttributeInt(null, "v", NO_VERSION);
4829 
4830                     int outerDepth = parser.getDepth();
4831                     while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4832                             && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4833                         if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4834                             continue;
4835                         }
4836 
4837                         String tagName = parser.getName();
4838                         if (tagName.equals("pkg")) {
4839                             readPackage(parser);
4840                         } else if (tagName.equals("uid")) {
4841                             readUidOps(parser);
4842                         } else {
4843                             Slog.w(TAG, "Unknown element under <app-ops>: "
4844                                     + parser.getName());
4845                             XmlUtils.skipCurrentTag(parser);
4846                         }
4847                     }
4848                     success = true;
4849                 } catch (IllegalStateException e) {
4850                     Slog.w(TAG, "Failed parsing " + e);
4851                 } catch (NullPointerException e) {
4852                     Slog.w(TAG, "Failed parsing " + e);
4853                 } catch (NumberFormatException e) {
4854                     Slog.w(TAG, "Failed parsing " + e);
4855                 } catch (XmlPullParserException e) {
4856                     Slog.w(TAG, "Failed parsing " + e);
4857                 } catch (IOException e) {
4858                     Slog.w(TAG, "Failed parsing " + e);
4859                 } catch (IndexOutOfBoundsException e) {
4860                     Slog.w(TAG, "Failed parsing " + e);
4861                 } finally {
4862                     if (!success) {
4863                         mUidStates.clear();
4864                     }
4865                     try {
4866                         stream.close();
4867                     } catch (IOException e) {
4868                     }
4869                 }
4870             }
4871         }
4872         synchronized (this) {
4873             upgradeLocked(oldVersion);
4874         }
4875     }
4876 
upgradeRunAnyInBackgroundLocked()4877     private void upgradeRunAnyInBackgroundLocked() {
4878         for (int i = 0; i < mUidStates.size(); i++) {
4879             final UidState uidState = mUidStates.valueAt(i);
4880             if (uidState == null) {
4881                 continue;
4882             }
4883             if (uidState.opModes != null) {
4884                 final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
4885                 if (idx >= 0) {
4886                     uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
4887                         uidState.opModes.valueAt(idx));
4888                 }
4889             }
4890             if (uidState.pkgOps == null) {
4891                 continue;
4892             }
4893             boolean changed = false;
4894             for (int j = 0; j < uidState.pkgOps.size(); j++) {
4895                 Ops ops = uidState.pkgOps.valueAt(j);
4896                 if (ops != null) {
4897                     final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
4898                     if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
4899                         final Op copy = new Op(op.uidState, op.packageName,
4900                                 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uidState.uid);
4901                         copy.mode = op.mode;
4902                         ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
4903                         changed = true;
4904                     }
4905                 }
4906             }
4907             if (changed) {
4908                 uidState.evalForegroundOps(mOpModeWatchers);
4909             }
4910         }
4911     }
4912 
upgradeLocked(int oldVersion)4913     private void upgradeLocked(int oldVersion) {
4914         if (oldVersion >= CURRENT_VERSION) {
4915             return;
4916         }
4917         Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
4918         switch (oldVersion) {
4919             case NO_VERSION:
4920                 upgradeRunAnyInBackgroundLocked();
4921                 // fall through
4922             case 1:
4923                 // for future upgrades
4924         }
4925         scheduleFastWriteLocked();
4926     }
4927 
readUidOps(TypedXmlPullParser parser)4928     private void readUidOps(TypedXmlPullParser parser) throws NumberFormatException,
4929             XmlPullParserException, IOException {
4930         final int uid = parser.getAttributeInt(null, "n");
4931         int outerDepth = parser.getDepth();
4932         int type;
4933         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4934                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4935             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4936                 continue;
4937             }
4938 
4939             String tagName = parser.getName();
4940             if (tagName.equals("op")) {
4941                 final int code = parser.getAttributeInt(null, "n");
4942                 final int mode = parser.getAttributeInt(null, "m");
4943                 setUidMode(code, uid, mode);
4944             } else {
4945                 Slog.w(TAG, "Unknown element under <uid-ops>: "
4946                         + parser.getName());
4947                 XmlUtils.skipCurrentTag(parser);
4948             }
4949         }
4950     }
4951 
readPackage(TypedXmlPullParser parser)4952     private void readPackage(TypedXmlPullParser parser)
4953             throws NumberFormatException, XmlPullParserException, IOException {
4954         String pkgName = parser.getAttributeValue(null, "n");
4955         int outerDepth = parser.getDepth();
4956         int type;
4957         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4958                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4959             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4960                 continue;
4961             }
4962 
4963             String tagName = parser.getName();
4964             if (tagName.equals("uid")) {
4965                 readUid(parser, pkgName);
4966             } else {
4967                 Slog.w(TAG, "Unknown element under <pkg>: "
4968                         + parser.getName());
4969                 XmlUtils.skipCurrentTag(parser);
4970             }
4971         }
4972     }
4973 
readUid(TypedXmlPullParser parser, String pkgName)4974     private void readUid(TypedXmlPullParser parser, String pkgName)
4975             throws NumberFormatException, XmlPullParserException, IOException {
4976         int uid = parser.getAttributeInt(null, "n");
4977         final UidState uidState = getUidStateLocked(uid, true);
4978         int outerDepth = parser.getDepth();
4979         int type;
4980         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4981                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4982             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4983                 continue;
4984             }
4985             String tagName = parser.getName();
4986             if (tagName.equals("op")) {
4987                 readOp(parser, uidState, pkgName);
4988             } else {
4989                 Slog.w(TAG, "Unknown element under <pkg>: "
4990                         + parser.getName());
4991                 XmlUtils.skipCurrentTag(parser);
4992             }
4993         }
4994         uidState.evalForegroundOps(mOpModeWatchers);
4995     }
4996 
readAttributionOp(TypedXmlPullParser parser, @NonNull Op parent, @Nullable String attribution)4997     private void readAttributionOp(TypedXmlPullParser parser, @NonNull Op parent,
4998             @Nullable String attribution)
4999             throws NumberFormatException, IOException, XmlPullParserException {
5000         final AttributedOp attributedOp = parent.getOrCreateAttribution(parent, attribution);
5001 
5002         final long key = parser.getAttributeLong(null, "n");
5003         final int uidState = extractUidStateFromKey(key);
5004         final int opFlags = extractFlagsFromKey(key);
5005 
5006         final long accessTime = parser.getAttributeLong(null, "t", 0);
5007         final long rejectTime = parser.getAttributeLong(null, "r", 0);
5008         final long accessDuration = parser.getAttributeLong(null, "d", -1);
5009         final String proxyPkg = XmlUtils.readStringAttribute(parser, "pp");
5010         final int proxyUid = parser.getAttributeInt(null, "pu", Process.INVALID_UID);
5011         final String proxyAttributionTag = XmlUtils.readStringAttribute(parser, "pc");
5012 
5013         if (accessTime > 0) {
5014             attributedOp.accessed(accessTime, accessDuration, proxyUid, proxyPkg,
5015                     proxyAttributionTag, uidState, opFlags);
5016         }
5017         if (rejectTime > 0) {
5018             attributedOp.rejected(rejectTime, uidState, opFlags);
5019         }
5020     }
5021 
readOp(TypedXmlPullParser parser, @NonNull UidState uidState, @NonNull String pkgName)5022     private void readOp(TypedXmlPullParser parser,
5023             @NonNull UidState uidState, @NonNull String pkgName)
5024             throws NumberFormatException, XmlPullParserException, IOException {
5025         int opCode = parser.getAttributeInt(null, "n");
5026         Op op = new Op(uidState, pkgName, opCode, uidState.uid);
5027 
5028         final int mode = parser.getAttributeInt(null, "m", AppOpsManager.opToDefaultMode(op.op));
5029         op.mode = mode;
5030 
5031         int outerDepth = parser.getDepth();
5032         int type;
5033         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
5034                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
5035             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
5036                 continue;
5037             }
5038             String tagName = parser.getName();
5039             if (tagName.equals("st")) {
5040                 readAttributionOp(parser, op, XmlUtils.readStringAttribute(parser, "id"));
5041             } else {
5042                 Slog.w(TAG, "Unknown element under <op>: "
5043                         + parser.getName());
5044                 XmlUtils.skipCurrentTag(parser);
5045             }
5046         }
5047 
5048         if (uidState.pkgOps == null) {
5049             uidState.pkgOps = new ArrayMap<>();
5050         }
5051         Ops ops = uidState.pkgOps.get(pkgName);
5052         if (ops == null) {
5053             ops = new Ops(pkgName, uidState);
5054             uidState.pkgOps.put(pkgName, ops);
5055         }
5056         ops.put(op.op, op);
5057     }
5058 
writeState()5059     void writeState() {
5060         synchronized (mFile) {
5061             FileOutputStream stream;
5062             try {
5063                 stream = mFile.startWrite();
5064             } catch (IOException e) {
5065                 Slog.w(TAG, "Failed to write state: " + e);
5066                 return;
5067             }
5068 
5069             List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
5070 
5071             try {
5072                 TypedXmlSerializer out = Xml.resolveSerializer(stream);
5073                 out.startDocument(null, true);
5074                 out.startTag(null, "app-ops");
5075                 out.attributeInt(null, "v", CURRENT_VERSION);
5076 
5077                 SparseArray<SparseIntArray> uidStatesClone;
5078                 synchronized (this) {
5079                     uidStatesClone = new SparseArray<>(mUidStates.size());
5080 
5081                     final int uidStateCount = mUidStates.size();
5082                     for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
5083                         UidState uidState = mUidStates.valueAt(uidStateNum);
5084                         int uid = mUidStates.keyAt(uidStateNum);
5085 
5086                         SparseIntArray opModes = uidState.opModes;
5087                         if (opModes != null && opModes.size() > 0) {
5088                             uidStatesClone.put(uid, new SparseIntArray(opModes.size()));
5089 
5090                             final int opCount = opModes.size();
5091                             for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
5092                                 uidStatesClone.get(uid).put(
5093                                         opModes.keyAt(opCountNum),
5094                                         opModes.valueAt(opCountNum));
5095                             }
5096                         }
5097                     }
5098                 }
5099 
5100                 final int uidStateCount = uidStatesClone.size();
5101                 for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
5102                     SparseIntArray opModes = uidStatesClone.valueAt(uidStateNum);
5103                     if (opModes != null && opModes.size() > 0) {
5104                         out.startTag(null, "uid");
5105                         out.attributeInt(null, "n", uidStatesClone.keyAt(uidStateNum));
5106                         final int opCount = opModes.size();
5107                         for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
5108                             final int op = opModes.keyAt(opCountNum);
5109                             final int mode = opModes.valueAt(opCountNum);
5110                             out.startTag(null, "op");
5111                             out.attributeInt(null, "n", op);
5112                             out.attributeInt(null, "m", mode);
5113                             out.endTag(null, "op");
5114                         }
5115                         out.endTag(null, "uid");
5116                     }
5117                 }
5118 
5119                 if (allOps != null) {
5120                     String lastPkg = null;
5121                     for (int i=0; i<allOps.size(); i++) {
5122                         AppOpsManager.PackageOps pkg = allOps.get(i);
5123                         if (!Objects.equals(pkg.getPackageName(), lastPkg)) {
5124                             if (lastPkg != null) {
5125                                 out.endTag(null, "pkg");
5126                             }
5127                             lastPkg = pkg.getPackageName();
5128                             if (lastPkg != null) {
5129                                 out.startTag(null, "pkg");
5130                                 out.attribute(null, "n", lastPkg);
5131                             }
5132                         }
5133                         out.startTag(null, "uid");
5134                         out.attributeInt(null, "n", pkg.getUid());
5135                         List<AppOpsManager.OpEntry> ops = pkg.getOps();
5136                         for (int j=0; j<ops.size(); j++) {
5137                             AppOpsManager.OpEntry op = ops.get(j);
5138                             out.startTag(null, "op");
5139                             out.attributeInt(null, "n", op.getOp());
5140                             if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
5141                                 out.attributeInt(null, "m", op.getMode());
5142                             }
5143 
5144                             for (String attributionTag : op.getAttributedOpEntries().keySet()) {
5145                                 final AttributedOpEntry attribution =
5146                                         op.getAttributedOpEntries().get(attributionTag);
5147 
5148                                 final ArraySet<Long> keys = attribution.collectKeys();
5149 
5150                                 final int keyCount = keys.size();
5151                                 for (int k = 0; k < keyCount; k++) {
5152                                     final long key = keys.valueAt(k);
5153 
5154                                     final int uidState = AppOpsManager.extractUidStateFromKey(key);
5155                                     final int flags = AppOpsManager.extractFlagsFromKey(key);
5156 
5157                                     final long accessTime = attribution.getLastAccessTime(uidState,
5158                                             uidState, flags);
5159                                     final long rejectTime = attribution.getLastRejectTime(uidState,
5160                                             uidState, flags);
5161                                     final long accessDuration = attribution.getLastDuration(
5162                                             uidState, uidState, flags);
5163                                     // Proxy information for rejections is not backed up
5164                                     final OpEventProxyInfo proxy = attribution.getLastProxyInfo(
5165                                             uidState, uidState, flags);
5166 
5167                                     if (accessTime <= 0 && rejectTime <= 0 && accessDuration <= 0
5168                                             && proxy == null) {
5169                                         continue;
5170                                     }
5171 
5172                                     String proxyPkg = null;
5173                                     String proxyAttributionTag = null;
5174                                     int proxyUid = Process.INVALID_UID;
5175                                     if (proxy != null) {
5176                                         proxyPkg = proxy.getPackageName();
5177                                         proxyAttributionTag = proxy.getAttributionTag();
5178                                         proxyUid = proxy.getUid();
5179                                     }
5180 
5181                                     out.startTag(null, "st");
5182                                     if (attributionTag != null) {
5183                                         out.attribute(null, "id", attributionTag);
5184                                     }
5185                                     out.attributeLong(null, "n", key);
5186                                     if (accessTime > 0) {
5187                                         out.attributeLong(null, "t", accessTime);
5188                                     }
5189                                     if (rejectTime > 0) {
5190                                         out.attributeLong(null, "r", rejectTime);
5191                                     }
5192                                     if (accessDuration > 0) {
5193                                         out.attributeLong(null, "d", accessDuration);
5194                                     }
5195                                     if (proxyPkg != null) {
5196                                         out.attribute(null, "pp", proxyPkg);
5197                                     }
5198                                     if (proxyAttributionTag != null) {
5199                                         out.attribute(null, "pc", proxyAttributionTag);
5200                                     }
5201                                     if (proxyUid >= 0) {
5202                                         out.attributeInt(null, "pu", proxyUid);
5203                                     }
5204                                     out.endTag(null, "st");
5205                                 }
5206                             }
5207 
5208                             out.endTag(null, "op");
5209                         }
5210                         out.endTag(null, "uid");
5211                     }
5212                     if (lastPkg != null) {
5213                         out.endTag(null, "pkg");
5214                     }
5215                 }
5216 
5217                 out.endTag(null, "app-ops");
5218                 out.endDocument();
5219                 mFile.finishWrite(stream);
5220             } catch (IOException e) {
5221                 Slog.w(TAG, "Failed to write state, restoring backup.", e);
5222                 mFile.failWrite(stream);
5223             }
5224         }
5225         mHistoricalRegistry.writeAndClearDiscreteHistory();
5226     }
5227 
5228     static class Shell extends ShellCommand {
5229         final IAppOpsService mInterface;
5230         final AppOpsService mInternal;
5231 
5232         int userId = UserHandle.USER_SYSTEM;
5233         String packageName;
5234         String attributionTag;
5235         String opStr;
5236         String modeStr;
5237         int op;
5238         int mode;
5239         int packageUid;
5240         int nonpackageUid;
5241         final static Binder sBinder = new Binder();
5242         IBinder mToken;
5243         boolean targetsUid;
5244 
Shell(IAppOpsService iface, AppOpsService internal)5245         Shell(IAppOpsService iface, AppOpsService internal) {
5246             mInterface = iface;
5247             mInternal = internal;
5248             mToken = AppOpsManager.getClientId();
5249         }
5250 
5251         @Override
onCommand(String cmd)5252         public int onCommand(String cmd) {
5253             return onShellCommand(this, cmd);
5254         }
5255 
5256         @Override
onHelp()5257         public void onHelp() {
5258             PrintWriter pw = getOutPrintWriter();
5259             dumpCommandHelp(pw);
5260         }
5261 
strOpToOp(String op, PrintWriter err)5262         static private int strOpToOp(String op, PrintWriter err) {
5263             try {
5264                 return AppOpsManager.strOpToOp(op);
5265             } catch (IllegalArgumentException e) {
5266             }
5267             try {
5268                 return Integer.parseInt(op);
5269             } catch (NumberFormatException e) {
5270             }
5271             try {
5272                 return AppOpsManager.strDebugOpToOp(op);
5273             } catch (IllegalArgumentException e) {
5274                 err.println("Error: " + e.getMessage());
5275                 return -1;
5276             }
5277         }
5278 
strModeToMode(String modeStr, PrintWriter err)5279         static int strModeToMode(String modeStr, PrintWriter err) {
5280             for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
5281                 if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
5282                     return i;
5283                 }
5284             }
5285             try {
5286                 return Integer.parseInt(modeStr);
5287             } catch (NumberFormatException e) {
5288             }
5289             err.println("Error: Mode " + modeStr + " is not valid");
5290             return -1;
5291         }
5292 
parseUserOpMode(int defMode, PrintWriter err)5293         int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
5294             userId = UserHandle.USER_CURRENT;
5295             opStr = null;
5296             modeStr = null;
5297             for (String argument; (argument = getNextArg()) != null;) {
5298                 if ("--user".equals(argument)) {
5299                     userId = UserHandle.parseUserArg(getNextArgRequired());
5300                 } else {
5301                     if (opStr == null) {
5302                         opStr = argument;
5303                     } else if (modeStr == null) {
5304                         modeStr = argument;
5305                         break;
5306                     }
5307                 }
5308             }
5309             if (opStr == null) {
5310                 err.println("Error: Operation not specified.");
5311                 return -1;
5312             }
5313             op = strOpToOp(opStr, err);
5314             if (op < 0) {
5315                 return -1;
5316             }
5317             if (modeStr != null) {
5318                 if ((mode=strModeToMode(modeStr, err)) < 0) {
5319                     return -1;
5320                 }
5321             } else {
5322                 mode = defMode;
5323             }
5324             return 0;
5325         }
5326 
parseUserPackageOp(boolean reqOp, PrintWriter err)5327         int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
5328             userId = UserHandle.USER_CURRENT;
5329             packageName = null;
5330             opStr = null;
5331             for (String argument; (argument = getNextArg()) != null;) {
5332                 if ("--user".equals(argument)) {
5333                     userId = UserHandle.parseUserArg(getNextArgRequired());
5334                 } else if ("--uid".equals(argument)) {
5335                     targetsUid = true;
5336                 } else if ("--attribution".equals(argument)) {
5337                     attributionTag = getNextArgRequired();
5338                 } else {
5339                     if (packageName == null) {
5340                         packageName = argument;
5341                     } else if (opStr == null) {
5342                         opStr = argument;
5343                         break;
5344                     }
5345                 }
5346             }
5347             if (packageName == null) {
5348                 err.println("Error: Package name not specified.");
5349                 return -1;
5350             } else if (opStr == null && reqOp) {
5351                 err.println("Error: Operation not specified.");
5352                 return -1;
5353             }
5354             if (opStr != null) {
5355                 op = strOpToOp(opStr, err);
5356                 if (op < 0) {
5357                     return -1;
5358                 }
5359             } else {
5360                 op = AppOpsManager.OP_NONE;
5361             }
5362             if (userId == UserHandle.USER_CURRENT) {
5363                 userId = ActivityManager.getCurrentUser();
5364             }
5365             nonpackageUid = -1;
5366             try {
5367                 nonpackageUid = Integer.parseInt(packageName);
5368             } catch (NumberFormatException e) {
5369             }
5370             if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
5371                     && packageName.indexOf('.') < 0) {
5372                 int i = 1;
5373                 while (i < packageName.length() && packageName.charAt(i) >= '0'
5374                         && packageName.charAt(i) <= '9') {
5375                     i++;
5376                 }
5377                 if (i > 1 && i < packageName.length()) {
5378                     String userStr = packageName.substring(1, i);
5379                     try {
5380                         int user = Integer.parseInt(userStr);
5381                         char type = packageName.charAt(i);
5382                         i++;
5383                         int startTypeVal = i;
5384                         while (i < packageName.length() && packageName.charAt(i) >= '0'
5385                                 && packageName.charAt(i) <= '9') {
5386                             i++;
5387                         }
5388                         if (i > startTypeVal) {
5389                             String typeValStr = packageName.substring(startTypeVal, i);
5390                             try {
5391                                 int typeVal = Integer.parseInt(typeValStr);
5392                                 if (type == 'a') {
5393                                     nonpackageUid = UserHandle.getUid(user,
5394                                             typeVal + Process.FIRST_APPLICATION_UID);
5395                                 } else if (type == 's') {
5396                                     nonpackageUid = UserHandle.getUid(user, typeVal);
5397                                 }
5398                             } catch (NumberFormatException e) {
5399                             }
5400                         }
5401                     } catch (NumberFormatException e) {
5402                     }
5403                 }
5404             }
5405             if (nonpackageUid != -1) {
5406                 packageName = null;
5407             } else {
5408                 packageUid = resolveUid(packageName);
5409                 if (packageUid < 0) {
5410                     packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
5411                             PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
5412                 }
5413                 if (packageUid < 0) {
5414                     err.println("Error: No UID for " + packageName + " in user " + userId);
5415                     return -1;
5416                 }
5417             }
5418             return 0;
5419         }
5420     }
5421 
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)5422     @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
5423             FileDescriptor err, String[] args, ShellCallback callback,
5424             ResultReceiver resultReceiver) {
5425         (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
5426     }
5427 
dumpCommandHelp(PrintWriter pw)5428     static void dumpCommandHelp(PrintWriter pw) {
5429         pw.println("AppOps service (appops) commands:");
5430         pw.println("  help");
5431         pw.println("    Print this help text.");
5432         pw.println("  start [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> "
5433                 + "<OP> ");
5434         pw.println("    Starts a given operation for a particular application.");
5435         pw.println("  stop [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> "
5436                 + "<OP> ");
5437         pw.println("    Stops a given operation for a particular application.");
5438         pw.println("  set [--user <USER_ID>] <[--uid] PACKAGE | UID> <OP> <MODE>");
5439         pw.println("    Set the mode for a particular application and operation.");
5440         pw.println("  get [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> "
5441                 + "[<OP>]");
5442         pw.println("    Return the mode for a particular application and optional operation.");
5443         pw.println("  query-op [--user <USER_ID>] <OP> [<MODE>]");
5444         pw.println("    Print all packages that currently have the given op in the given mode.");
5445         pw.println("  reset [--user <USER_ID>] [<PACKAGE>]");
5446         pw.println("    Reset the given application or all applications to default modes.");
5447         pw.println("  write-settings");
5448         pw.println("    Immediately write pending changes to storage.");
5449         pw.println("  read-settings");
5450         pw.println("    Read the last written settings, replacing current state in RAM.");
5451         pw.println("  options:");
5452         pw.println("    <PACKAGE> an Android package name or its UID if prefixed by --uid");
5453         pw.println("    <OP>      an AppOps operation.");
5454         pw.println("    <MODE>    one of allow, ignore, deny, or default");
5455         pw.println("    <USER_ID> the user id under which the package is installed. If --user is");
5456         pw.println("              not specified, the current user is assumed.");
5457     }
5458 
onShellCommand(Shell shell, String cmd)5459     static int onShellCommand(Shell shell, String cmd) {
5460         if (cmd == null) {
5461             return shell.handleDefaultCommands(cmd);
5462         }
5463         PrintWriter pw = shell.getOutPrintWriter();
5464         PrintWriter err = shell.getErrPrintWriter();
5465         try {
5466             switch (cmd) {
5467                 case "set": {
5468                     int res = shell.parseUserPackageOp(true, err);
5469                     if (res < 0) {
5470                         return res;
5471                     }
5472                     String modeStr = shell.getNextArg();
5473                     if (modeStr == null) {
5474                         err.println("Error: Mode not specified.");
5475                         return -1;
5476                     }
5477 
5478                     final int mode = shell.strModeToMode(modeStr, err);
5479                     if (mode < 0) {
5480                         return -1;
5481                     }
5482 
5483                     if (!shell.targetsUid && shell.packageName != null) {
5484                         shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
5485                                 mode);
5486                     } else if (shell.targetsUid && shell.packageName != null) {
5487                         try {
5488                             final int uid = shell.mInternal.mContext.getPackageManager()
5489                                     .getPackageUidAsUser(shell.packageName, shell.userId);
5490                             shell.mInterface.setUidMode(shell.op, uid, mode);
5491                         } catch (PackageManager.NameNotFoundException e) {
5492                             return -1;
5493                         }
5494                     } else {
5495                         shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
5496                     }
5497                     return 0;
5498                 }
5499                 case "get": {
5500                     int res = shell.parseUserPackageOp(false, err);
5501                     if (res < 0) {
5502                         return res;
5503                     }
5504 
5505                     List<AppOpsManager.PackageOps> ops = new ArrayList<>();
5506                     if (shell.packageName != null) {
5507                         // Uid mode overrides package mode, so make sure it's also reported
5508                         List<AppOpsManager.PackageOps> r = shell.mInterface.getUidOps(
5509                                 shell.packageUid,
5510                                 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
5511                         if (r != null) {
5512                             ops.addAll(r);
5513                         }
5514                         r = shell.mInterface.getOpsForPackage(
5515                                 shell.packageUid, shell.packageName,
5516                                 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
5517                         if (r != null) {
5518                             ops.addAll(r);
5519                         }
5520                     } else {
5521                         ops = shell.mInterface.getUidOps(
5522                                 shell.nonpackageUid,
5523                                 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
5524                     }
5525                     if (ops == null || ops.size() <= 0) {
5526                         pw.println("No operations.");
5527                         if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
5528                             pw.println("Default mode: " + AppOpsManager.modeToName(
5529                                     AppOpsManager.opToDefaultMode(shell.op)));
5530                         }
5531                         return 0;
5532                     }
5533                     final long now = System.currentTimeMillis();
5534                     for (int i=0; i<ops.size(); i++) {
5535                         AppOpsManager.PackageOps packageOps = ops.get(i);
5536                         if (packageOps.getPackageName() == null) {
5537                             pw.print("Uid mode: ");
5538                         }
5539                         List<AppOpsManager.OpEntry> entries = packageOps.getOps();
5540                         for (int j=0; j<entries.size(); j++) {
5541                             AppOpsManager.OpEntry ent = entries.get(j);
5542                             pw.print(AppOpsManager.opToName(ent.getOp()));
5543                             pw.print(": ");
5544                             pw.print(AppOpsManager.modeToName(ent.getMode()));
5545                             if (shell.attributionTag == null) {
5546                                 if (ent.getLastAccessTime(OP_FLAGS_ALL) != -1) {
5547                                     pw.print("; time=");
5548                                     TimeUtils.formatDuration(
5549                                             now - ent.getLastAccessTime(OP_FLAGS_ALL), pw);
5550                                     pw.print(" ago");
5551                                 }
5552                                 if (ent.getLastRejectTime(OP_FLAGS_ALL) != -1) {
5553                                     pw.print("; rejectTime=");
5554                                     TimeUtils.formatDuration(
5555                                             now - ent.getLastRejectTime(OP_FLAGS_ALL), pw);
5556                                     pw.print(" ago");
5557                                 }
5558                                 if (ent.isRunning()) {
5559                                     pw.print(" (running)");
5560                                 } else if (ent.getLastDuration(OP_FLAGS_ALL) != -1) {
5561                                     pw.print("; duration=");
5562                                     TimeUtils.formatDuration(ent.getLastDuration(OP_FLAGS_ALL), pw);
5563                                 }
5564                             } else {
5565                                 final AppOpsManager.AttributedOpEntry attributionEnt =
5566                                         ent.getAttributedOpEntries().get(shell.attributionTag);
5567                                 if (attributionEnt != null) {
5568                                     if (attributionEnt.getLastAccessTime(OP_FLAGS_ALL) != -1) {
5569                                         pw.print("; time=");
5570                                         TimeUtils.formatDuration(
5571                                                 now - attributionEnt.getLastAccessTime(
5572                                                         OP_FLAGS_ALL), pw);
5573                                         pw.print(" ago");
5574                                     }
5575                                     if (attributionEnt.getLastRejectTime(OP_FLAGS_ALL) != -1) {
5576                                         pw.print("; rejectTime=");
5577                                         TimeUtils.formatDuration(
5578                                                 now - attributionEnt.getLastRejectTime(
5579                                                         OP_FLAGS_ALL), pw);
5580                                         pw.print(" ago");
5581                                     }
5582                                     if (attributionEnt.isRunning()) {
5583                                         pw.print(" (running)");
5584                                     } else if (attributionEnt.getLastDuration(OP_FLAGS_ALL)
5585                                             != -1) {
5586                                         pw.print("; duration=");
5587                                         TimeUtils.formatDuration(
5588                                                 attributionEnt.getLastDuration(OP_FLAGS_ALL), pw);
5589                                     }
5590                                 }
5591                             }
5592                             pw.println();
5593                         }
5594                     }
5595                     return 0;
5596                 }
5597                 case "query-op": {
5598                     int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
5599                     if (res < 0) {
5600                         return res;
5601                     }
5602                     List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
5603                             new int[] {shell.op});
5604                     if (ops == null || ops.size() <= 0) {
5605                         pw.println("No operations.");
5606                         return 0;
5607                     }
5608                     for (int i=0; i<ops.size(); i++) {
5609                         final AppOpsManager.PackageOps pkg = ops.get(i);
5610                         boolean hasMatch = false;
5611                         final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
5612                         for (int j=0; j<entries.size(); j++) {
5613                             AppOpsManager.OpEntry ent = entries.get(j);
5614                             if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
5615                                 hasMatch = true;
5616                                 break;
5617                             }
5618                         }
5619                         if (hasMatch) {
5620                             pw.println(pkg.getPackageName());
5621                         }
5622                     }
5623                     return 0;
5624                 }
5625                 case "reset": {
5626                     String packageName = null;
5627                     int userId = UserHandle.USER_CURRENT;
5628                     for (String argument; (argument = shell.getNextArg()) != null;) {
5629                         if ("--user".equals(argument)) {
5630                             String userStr = shell.getNextArgRequired();
5631                             userId = UserHandle.parseUserArg(userStr);
5632                         } else {
5633                             if (packageName == null) {
5634                                 packageName = argument;
5635                             } else {
5636                                 err.println("Error: Unsupported argument: " + argument);
5637                                 return -1;
5638                             }
5639                         }
5640                     }
5641 
5642                     if (userId == UserHandle.USER_CURRENT) {
5643                         userId = ActivityManager.getCurrentUser();
5644                     }
5645 
5646                     shell.mInterface.resetAllModes(userId, packageName);
5647                     pw.print("Reset all modes for: ");
5648                     if (userId == UserHandle.USER_ALL) {
5649                         pw.print("all users");
5650                     } else {
5651                         pw.print("user "); pw.print(userId);
5652                     }
5653                     pw.print(", ");
5654                     if (packageName == null) {
5655                         pw.println("all packages");
5656                     } else {
5657                         pw.print("package "); pw.println(packageName);
5658                     }
5659                     return 0;
5660                 }
5661                 case "write-settings": {
5662                     shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
5663                             Binder.getCallingUid(), -1);
5664                     final long token = Binder.clearCallingIdentity();
5665                     try {
5666                         synchronized (shell.mInternal) {
5667                             shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
5668                         }
5669                         shell.mInternal.writeState();
5670                         pw.println("Current settings written.");
5671                     } finally {
5672                         Binder.restoreCallingIdentity(token);
5673                     }
5674                     return 0;
5675                 }
5676                 case "read-settings": {
5677                     shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
5678                             Binder.getCallingUid(), -1);
5679                     final long token = Binder.clearCallingIdentity();
5680                     try {
5681                         shell.mInternal.readState();
5682                         pw.println("Last settings read.");
5683                     } finally {
5684                         Binder.restoreCallingIdentity(token);
5685                     }
5686                     return 0;
5687                 }
5688                 case "start": {
5689                     int res = shell.parseUserPackageOp(true, err);
5690                     if (res < 0) {
5691                         return res;
5692                     }
5693 
5694                     if (shell.packageName != null) {
5695                         shell.mInterface.startOperation(shell.mToken, shell.op, shell.packageUid,
5696                                 shell.packageName, shell.attributionTag, true, true,
5697                                 "appops start shell command", true,
5698                                 AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR, ATTRIBUTION_CHAIN_ID_NONE);
5699                     } else {
5700                         return -1;
5701                     }
5702                     return 0;
5703                 }
5704                 case "stop": {
5705                     int res = shell.parseUserPackageOp(true, err);
5706                     if (res < 0) {
5707                         return res;
5708                     }
5709 
5710                     if (shell.packageName != null) {
5711                         shell.mInterface.finishOperation(shell.mToken, shell.op, shell.packageUid,
5712                                 shell.packageName, shell.attributionTag);
5713                     } else {
5714                         return -1;
5715                     }
5716                     return 0;
5717                 }
5718                 default:
5719                     return shell.handleDefaultCommands(cmd);
5720             }
5721         } catch (RemoteException e) {
5722             pw.println("Remote exception: " + e);
5723         }
5724         return -1;
5725     }
5726 
dumpHelp(PrintWriter pw)5727     private void dumpHelp(PrintWriter pw) {
5728         pw.println("AppOps service (appops) dump options:");
5729         pw.println("  -h");
5730         pw.println("    Print this help text.");
5731         pw.println("  --op [OP]");
5732         pw.println("    Limit output to data associated with the given app op code.");
5733         pw.println("  --mode [MODE]");
5734         pw.println("    Limit output to data associated with the given app op mode.");
5735         pw.println("  --package [PACKAGE]");
5736         pw.println("    Limit output to data associated with the given package name.");
5737         pw.println("  --attributionTag [attributionTag]");
5738         pw.println("    Limit output to data associated with the given attribution tag.");
5739         pw.println("  --include-discrete [n]");
5740         pw.println("    Include discrete ops limited to n per dimension. Use zero for no limit.");
5741         pw.println("  --watchers");
5742         pw.println("    Only output the watcher sections.");
5743         pw.println("  --history");
5744         pw.println("    Only output history.");
5745     }
5746 
dumpStatesLocked(@onNull PrintWriter pw, @Nullable String filterAttributionTag, @HistoricalOpsRequestFilter int filter, long nowElapsed, @NonNull Op op, long now, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix)5747     private void dumpStatesLocked(@NonNull PrintWriter pw, @Nullable String filterAttributionTag,
5748             @HistoricalOpsRequestFilter int filter, long nowElapsed, @NonNull Op op, long now,
5749             @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix) {
5750         final int numAttributions = op.mAttributions.size();
5751         for (int i = 0; i < numAttributions; i++) {
5752             if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !Objects.equals(
5753                     op.mAttributions.keyAt(i), filterAttributionTag)) {
5754                 continue;
5755             }
5756 
5757             pw.print(prefix + op.mAttributions.keyAt(i) + "=[\n");
5758             dumpStatesLocked(pw, nowElapsed, op, op.mAttributions.keyAt(i), now, sdf, date,
5759                     prefix + "  ");
5760             pw.print(prefix + "]\n");
5761         }
5762     }
5763 
dumpStatesLocked(@onNull PrintWriter pw, long nowElapsed, @NonNull Op op, @Nullable String attributionTag, long now, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix)5764     private void dumpStatesLocked(@NonNull PrintWriter pw, long nowElapsed, @NonNull Op op,
5765             @Nullable String attributionTag, long now, @NonNull SimpleDateFormat sdf,
5766             @NonNull Date date, @NonNull String prefix) {
5767 
5768         final AttributedOpEntry entry = op.createSingleAttributionEntryLocked(
5769                 attributionTag).getAttributedOpEntries().get(attributionTag);
5770 
5771         final ArraySet<Long> keys = entry.collectKeys();
5772 
5773         final int keyCount = keys.size();
5774         for (int k = 0; k < keyCount; k++) {
5775             final long key = keys.valueAt(k);
5776 
5777             final int uidState = AppOpsManager.extractUidStateFromKey(key);
5778             final int flags = AppOpsManager.extractFlagsFromKey(key);
5779 
5780             final long accessTime = entry.getLastAccessTime(uidState, uidState, flags);
5781             final long rejectTime = entry.getLastRejectTime(uidState, uidState, flags);
5782             final long accessDuration = entry.getLastDuration(uidState, uidState, flags);
5783             final OpEventProxyInfo proxy = entry.getLastProxyInfo(uidState, uidState, flags);
5784 
5785             String proxyPkg = null;
5786             String proxyAttributionTag = null;
5787             int proxyUid = Process.INVALID_UID;
5788             if (proxy != null) {
5789                 proxyPkg = proxy.getPackageName();
5790                 proxyAttributionTag = proxy.getAttributionTag();
5791                 proxyUid = proxy.getUid();
5792             }
5793 
5794             if (accessTime > 0) {
5795                 pw.print(prefix);
5796                 pw.print("Access: ");
5797                 pw.print(AppOpsManager.keyToString(key));
5798                 pw.print(" ");
5799                 date.setTime(accessTime);
5800                 pw.print(sdf.format(date));
5801                 pw.print(" (");
5802                 TimeUtils.formatDuration(accessTime - now, pw);
5803                 pw.print(")");
5804                 if (accessDuration > 0) {
5805                     pw.print(" duration=");
5806                     TimeUtils.formatDuration(accessDuration, pw);
5807                 }
5808                 if (proxyUid >= 0) {
5809                     pw.print(" proxy[");
5810                     pw.print("uid=");
5811                     pw.print(proxyUid);
5812                     pw.print(", pkg=");
5813                     pw.print(proxyPkg);
5814                     pw.print(", attributionTag=");
5815                     pw.print(proxyAttributionTag);
5816                     pw.print("]");
5817                 }
5818                 pw.println();
5819             }
5820 
5821             if (rejectTime > 0) {
5822                 pw.print(prefix);
5823                 pw.print("Reject: ");
5824                 pw.print(AppOpsManager.keyToString(key));
5825                 date.setTime(rejectTime);
5826                 pw.print(sdf.format(date));
5827                 pw.print(" (");
5828                 TimeUtils.formatDuration(rejectTime - now, pw);
5829                 pw.print(")");
5830                 if (proxyUid >= 0) {
5831                     pw.print(" proxy[");
5832                     pw.print("uid=");
5833                     pw.print(proxyUid);
5834                     pw.print(", pkg=");
5835                     pw.print(proxyPkg);
5836                     pw.print(", attributionTag=");
5837                     pw.print(proxyAttributionTag);
5838                     pw.print("]");
5839                 }
5840                 pw.println();
5841             }
5842         }
5843 
5844         final AttributedOp attributedOp = op.mAttributions.get(attributionTag);
5845         if (attributedOp.isRunning()) {
5846             long earliestElapsedTime = Long.MAX_VALUE;
5847             long maxNumStarts = 0;
5848             int numInProgressEvents = attributedOp.mInProgressEvents.size();
5849             for (int i = 0; i < numInProgressEvents; i++) {
5850                 InProgressStartOpEvent event = attributedOp.mInProgressEvents.valueAt(i);
5851 
5852                 earliestElapsedTime = Math.min(earliestElapsedTime, event.getStartElapsedTime());
5853                 maxNumStarts = Math.max(maxNumStarts, event.numUnfinishedStarts);
5854             }
5855 
5856             pw.print(prefix + "Running start at: ");
5857             TimeUtils.formatDuration(nowElapsed - earliestElapsedTime, pw);
5858             pw.println();
5859 
5860             if (maxNumStarts > 1) {
5861                 pw.print(prefix + "startNesting=");
5862                 pw.println(maxNumStarts);
5863             }
5864         }
5865     }
5866 
5867     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)5868     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
5869         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
5870 
5871         int dumpOp = OP_NONE;
5872         String dumpPackage = null;
5873         String dumpAttributionTag = null;
5874         int dumpUid = Process.INVALID_UID;
5875         int dumpMode = -1;
5876         boolean dumpWatchers = false;
5877         // TODO ntmyren: Remove the dumpHistory and dumpFilter
5878         boolean dumpHistory = false;
5879         boolean includeDiscreteOps = false;
5880         int nDiscreteOps = 10;
5881         @HistoricalOpsRequestFilter int dumpFilter = 0;
5882 
5883         if (args != null) {
5884             for (int i = 0; i < args.length; i++) {
5885                 String arg = args[i];
5886                 if ("-h".equals(arg)) {
5887                     dumpHelp(pw);
5888                     return;
5889                 } else if ("-a".equals(arg)) {
5890                     // dump all data
5891                 } else if ("--op".equals(arg)) {
5892                     i++;
5893                     if (i >= args.length) {
5894                         pw.println("No argument for --op option");
5895                         return;
5896                     }
5897                     dumpOp = Shell.strOpToOp(args[i], pw);
5898                     dumpFilter |= FILTER_BY_OP_NAMES;
5899                     if (dumpOp < 0) {
5900                         return;
5901                     }
5902                 } else if ("--package".equals(arg)) {
5903                     i++;
5904                     if (i >= args.length) {
5905                         pw.println("No argument for --package option");
5906                         return;
5907                     }
5908                     dumpPackage = args[i];
5909                     dumpFilter |= FILTER_BY_PACKAGE_NAME;
5910                     try {
5911                         dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
5912                                 PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
5913                                 0);
5914                     } catch (RemoteException e) {
5915                     }
5916                     if (dumpUid < 0) {
5917                         pw.println("Unknown package: " + dumpPackage);
5918                         return;
5919                     }
5920                     dumpUid = UserHandle.getAppId(dumpUid);
5921                     dumpFilter |= FILTER_BY_UID;
5922                 } else if ("--attributionTag".equals(arg)) {
5923                     i++;
5924                     if (i >= args.length) {
5925                         pw.println("No argument for --attributionTag option");
5926                         return;
5927                     }
5928                     dumpAttributionTag = args[i];
5929                     dumpFilter |= FILTER_BY_ATTRIBUTION_TAG;
5930                 } else if ("--mode".equals(arg)) {
5931                     i++;
5932                     if (i >= args.length) {
5933                         pw.println("No argument for --mode option");
5934                         return;
5935                     }
5936                     dumpMode = Shell.strModeToMode(args[i], pw);
5937                     if (dumpMode < 0) {
5938                         return;
5939                     }
5940                 } else if ("--watchers".equals(arg)) {
5941                     dumpWatchers = true;
5942                 } else if ("--include-discrete".equals(arg)) {
5943                     i++;
5944                     if (i >= args.length) {
5945                         pw.println("No argument for --include-discrete option");
5946                         return;
5947                     }
5948                     try {
5949                         nDiscreteOps = Integer.valueOf(args[i]);
5950                     } catch (NumberFormatException e) {
5951                         pw.println("Wrong parameter: " + args[i]);
5952                         return;
5953                     }
5954                     includeDiscreteOps = true;
5955                 } else if ("--history".equals(arg)) {
5956                     dumpHistory = true;
5957                 } else if (arg.length() > 0 && arg.charAt(0) == '-') {
5958                     pw.println("Unknown option: " + arg);
5959                     return;
5960                 } else {
5961                     pw.println("Unknown command: " + arg);
5962                     return;
5963                 }
5964             }
5965         }
5966 
5967         final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
5968         final Date date = new Date();
5969         synchronized (this) {
5970             pw.println("Current AppOps Service state:");
5971             if (!dumpHistory && !dumpWatchers) {
5972                 mConstants.dump(pw);
5973             }
5974             pw.println();
5975             final long now = System.currentTimeMillis();
5976             final long nowElapsed = SystemClock.elapsedRealtime();
5977             final long nowUptime = SystemClock.uptimeMillis();
5978             boolean needSep = false;
5979             if (dumpFilter == 0 && dumpMode < 0 && mProfileOwners != null && !dumpWatchers
5980                     && !dumpHistory) {
5981                 pw.println("  Profile owners:");
5982                 for (int poi = 0; poi < mProfileOwners.size(); poi++) {
5983                     pw.print("    User #");
5984                     pw.print(mProfileOwners.keyAt(poi));
5985                     pw.print(": ");
5986                     UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
5987                     pw.println();
5988                 }
5989                 pw.println();
5990             }
5991             if (mOpModeWatchers.size() > 0 && !dumpHistory) {
5992                 boolean printedHeader = false;
5993                 for (int i=0; i<mOpModeWatchers.size(); i++) {
5994                     if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
5995                         continue;
5996                     }
5997                     boolean printedOpHeader = false;
5998                     ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
5999                     for (int j=0; j<callbacks.size(); j++) {
6000                         final ModeCallback cb = callbacks.valueAt(j);
6001                         if (dumpPackage != null
6002                                 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
6003                             continue;
6004                         }
6005                         needSep = true;
6006                         if (!printedHeader) {
6007                             pw.println("  Op mode watchers:");
6008                             printedHeader = true;
6009                         }
6010                         if (!printedOpHeader) {
6011                             pw.print("    Op ");
6012                             pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
6013                             pw.println(":");
6014                             printedOpHeader = true;
6015                         }
6016                         pw.print("      #"); pw.print(j); pw.print(": ");
6017                         pw.println(cb);
6018                     }
6019                 }
6020             }
6021             if (mPackageModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
6022                 boolean printedHeader = false;
6023                 for (int i=0; i<mPackageModeWatchers.size(); i++) {
6024                     if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
6025                         continue;
6026                     }
6027                     needSep = true;
6028                     if (!printedHeader) {
6029                         pw.println("  Package mode watchers:");
6030                         printedHeader = true;
6031                     }
6032                     pw.print("    Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
6033                     pw.println(":");
6034                     ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
6035                     for (int j=0; j<callbacks.size(); j++) {
6036                         pw.print("      #"); pw.print(j); pw.print(": ");
6037                         pw.println(callbacks.valueAt(j));
6038                     }
6039                 }
6040             }
6041             if (mModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
6042                 boolean printedHeader = false;
6043                 for (int i=0; i<mModeWatchers.size(); i++) {
6044                     final ModeCallback cb = mModeWatchers.valueAt(i);
6045                     if (dumpPackage != null
6046                             && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
6047                         continue;
6048                     }
6049                     needSep = true;
6050                     if (!printedHeader) {
6051                         pw.println("  All op mode watchers:");
6052                         printedHeader = true;
6053                     }
6054                     pw.print("    ");
6055                     pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
6056                     pw.print(": "); pw.println(cb);
6057                 }
6058             }
6059             if (mActiveWatchers.size() > 0 && dumpMode < 0) {
6060                 needSep = true;
6061                 boolean printedHeader = false;
6062                 for (int watcherNum = 0; watcherNum < mActiveWatchers.size(); watcherNum++) {
6063                     final SparseArray<ActiveCallback> activeWatchers =
6064                             mActiveWatchers.valueAt(watcherNum);
6065                     if (activeWatchers.size() <= 0) {
6066                         continue;
6067                     }
6068                     final ActiveCallback cb = activeWatchers.valueAt(0);
6069                     if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
6070                         continue;
6071                     }
6072                     if (dumpPackage != null
6073                             && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
6074                         continue;
6075                     }
6076                     if (!printedHeader) {
6077                         pw.println("  All op active watchers:");
6078                         printedHeader = true;
6079                     }
6080                     pw.print("    ");
6081                     pw.print(Integer.toHexString(System.identityHashCode(
6082                             mActiveWatchers.keyAt(watcherNum))));
6083                     pw.println(" ->");
6084                     pw.print("        [");
6085                     final int opCount = activeWatchers.size();
6086                     for (int opNum = 0; opNum < opCount; opNum++) {
6087                         if (opNum > 0) {
6088                             pw.print(' ');
6089                         }
6090                         pw.print(AppOpsManager.opToName(activeWatchers.keyAt(opNum)));
6091                         if (opNum < opCount - 1) {
6092                             pw.print(',');
6093                         }
6094                     }
6095                     pw.println("]");
6096                     pw.print("        ");
6097                     pw.println(cb);
6098                 }
6099             }
6100             if (mStartedWatchers.size() > 0 && dumpMode < 0) {
6101                 needSep = true;
6102                 boolean printedHeader = false;
6103 
6104                 final int watchersSize = mStartedWatchers.size();
6105                 for (int watcherNum = 0; watcherNum < watchersSize; watcherNum++) {
6106                     final SparseArray<StartedCallback> startedWatchers =
6107                             mStartedWatchers.valueAt(watcherNum);
6108                     if (startedWatchers.size() <= 0) {
6109                         continue;
6110                     }
6111 
6112                     final StartedCallback cb = startedWatchers.valueAt(0);
6113                     if (dumpOp >= 0 && startedWatchers.indexOfKey(dumpOp) < 0) {
6114                         continue;
6115                     }
6116 
6117                     if (dumpPackage != null
6118                             && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
6119                         continue;
6120                     }
6121 
6122                     if (!printedHeader) {
6123                         pw.println("  All op started watchers:");
6124                         printedHeader = true;
6125                     }
6126 
6127                     pw.print("    ");
6128                     pw.print(Integer.toHexString(System.identityHashCode(
6129                             mStartedWatchers.keyAt(watcherNum))));
6130                     pw.println(" ->");
6131 
6132                     pw.print("        [");
6133                     final int opCount = startedWatchers.size();
6134                     for (int opNum = 0; opNum < opCount; opNum++) {
6135                         if (opNum > 0) {
6136                             pw.print(' ');
6137                         }
6138 
6139                         pw.print(AppOpsManager.opToName(startedWatchers.keyAt(opNum)));
6140                         if (opNum < opCount - 1) {
6141                             pw.print(',');
6142                         }
6143                     }
6144                     pw.println("]");
6145 
6146                     pw.print("        ");
6147                     pw.println(cb);
6148                 }
6149             }
6150             if (mNotedWatchers.size() > 0 && dumpMode < 0) {
6151                 needSep = true;
6152                 boolean printedHeader = false;
6153                 for (int watcherNum = 0; watcherNum < mNotedWatchers.size(); watcherNum++) {
6154                     final SparseArray<NotedCallback> notedWatchers =
6155                             mNotedWatchers.valueAt(watcherNum);
6156                     if (notedWatchers.size() <= 0) {
6157                         continue;
6158                     }
6159                     final NotedCallback cb = notedWatchers.valueAt(0);
6160                     if (dumpOp >= 0 && notedWatchers.indexOfKey(dumpOp) < 0) {
6161                         continue;
6162                     }
6163                     if (dumpPackage != null
6164                             && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
6165                         continue;
6166                     }
6167                     if (!printedHeader) {
6168                         pw.println("  All op noted watchers:");
6169                         printedHeader = true;
6170                     }
6171                     pw.print("    ");
6172                     pw.print(Integer.toHexString(System.identityHashCode(
6173                             mNotedWatchers.keyAt(watcherNum))));
6174                     pw.println(" ->");
6175                     pw.print("        [");
6176                     final int opCount = notedWatchers.size();
6177                     for (int opNum = 0; opNum < opCount; opNum++) {
6178                         if (opNum > 0) {
6179                             pw.print(' ');
6180                         }
6181                         pw.print(AppOpsManager.opToName(notedWatchers.keyAt(opNum)));
6182                         if (opNum < opCount - 1) {
6183                             pw.print(',');
6184                         }
6185                     }
6186                     pw.println("]");
6187                     pw.print("        ");
6188                     pw.println(cb);
6189                 }
6190             }
6191             if (mAudioRestrictionManager.hasActiveRestrictions() && dumpOp < 0
6192                     && dumpPackage != null && dumpMode < 0 && !dumpWatchers && !dumpWatchers) {
6193                 needSep = mAudioRestrictionManager.dump(pw) | needSep ;
6194             }
6195             if (needSep) {
6196                 pw.println();
6197             }
6198             for (int i=0; i<mUidStates.size(); i++) {
6199                 UidState uidState = mUidStates.valueAt(i);
6200                 final SparseIntArray opModes = uidState.opModes;
6201                 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
6202 
6203                 if (dumpWatchers || dumpHistory) {
6204                     continue;
6205                 }
6206                 if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
6207                     boolean hasOp = dumpOp < 0 || (uidState.opModes != null
6208                             && uidState.opModes.indexOfKey(dumpOp) >= 0);
6209                     boolean hasPackage = dumpPackage == null || dumpUid == mUidStates.keyAt(i);
6210                     boolean hasMode = dumpMode < 0;
6211                     if (!hasMode && opModes != null) {
6212                         for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
6213                             if (opModes.valueAt(opi) == dumpMode) {
6214                                 hasMode = true;
6215                             }
6216                         }
6217                     }
6218                     if (pkgOps != null) {
6219                         for (int pkgi = 0;
6220                                  (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
6221                                  pkgi++) {
6222                             Ops ops = pkgOps.valueAt(pkgi);
6223                             if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
6224                                 hasOp = true;
6225                             }
6226                             if (!hasMode) {
6227                                 for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
6228                                     if (ops.valueAt(opi).mode == dumpMode) {
6229                                         hasMode = true;
6230                                     }
6231                                 }
6232                             }
6233                             if (!hasPackage && dumpPackage.equals(ops.packageName)) {
6234                                 hasPackage = true;
6235                             }
6236                         }
6237                     }
6238                     if (uidState.foregroundOps != null && !hasOp) {
6239                         if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
6240                             hasOp = true;
6241                         }
6242                     }
6243                     if (!hasOp || !hasPackage || !hasMode) {
6244                         continue;
6245                     }
6246                 }
6247 
6248                 pw.print("  Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
6249                 pw.print("    state=");
6250                 pw.println(AppOpsManager.getUidStateName(uidState.state));
6251                 if (uidState.state != uidState.pendingState) {
6252                     pw.print("    pendingState=");
6253                     pw.println(AppOpsManager.getUidStateName(uidState.pendingState));
6254                 }
6255                 pw.print("    capability=");
6256                 ActivityManager.printCapabilitiesFull(pw, uidState.capability);
6257                 pw.println();
6258                 if (uidState.capability != uidState.pendingCapability) {
6259                     pw.print("    pendingCapability=");
6260                     ActivityManager.printCapabilitiesFull(pw, uidState.pendingCapability);
6261                     pw.println();
6262                 }
6263                 pw.print("    appWidgetVisible=");
6264                 pw.println(uidState.appWidgetVisible);
6265                 if (uidState.appWidgetVisible != uidState.pendingAppWidgetVisible) {
6266                     pw.print("    pendingAppWidgetVisible=");
6267                     pw.println(uidState.pendingAppWidgetVisible);
6268                 }
6269                 if (uidState.pendingStateCommitTime != 0) {
6270                     pw.print("    pendingStateCommitTime=");
6271                     TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw);
6272                     pw.println();
6273                 }
6274                 if (uidState.foregroundOps != null && (dumpMode < 0
6275                         || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
6276                     pw.println("    foregroundOps:");
6277                     for (int j = 0; j < uidState.foregroundOps.size(); j++) {
6278                         if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
6279                             continue;
6280                         }
6281                         pw.print("      ");
6282                         pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
6283                         pw.print(": ");
6284                         pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
6285                     }
6286                     pw.print("    hasForegroundWatchers=");
6287                     pw.println(uidState.hasForegroundWatchers);
6288                 }
6289                 needSep = true;
6290 
6291                 if (opModes != null) {
6292                     final int opModeCount = opModes.size();
6293                     for (int j = 0; j < opModeCount; j++) {
6294                         final int code = opModes.keyAt(j);
6295                         final int mode = opModes.valueAt(j);
6296                         if (dumpOp >= 0 && dumpOp != code) {
6297                             continue;
6298                         }
6299                         if (dumpMode >= 0 && dumpMode != mode) {
6300                             continue;
6301                         }
6302                         pw.print("      "); pw.print(AppOpsManager.opToName(code));
6303                         pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
6304                     }
6305                 }
6306 
6307                 if (pkgOps == null) {
6308                     continue;
6309                 }
6310 
6311                 for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
6312                     final Ops ops = pkgOps.valueAt(pkgi);
6313                     if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
6314                         continue;
6315                     }
6316                     boolean printedPackage = false;
6317                     for (int j=0; j<ops.size(); j++) {
6318                         final Op op = ops.valueAt(j);
6319                         final int opCode = op.op;
6320                         if (dumpOp >= 0 && dumpOp != opCode) {
6321                             continue;
6322                         }
6323                         if (dumpMode >= 0 && dumpMode != op.mode) {
6324                             continue;
6325                         }
6326                         if (!printedPackage) {
6327                             pw.print("    Package "); pw.print(ops.packageName); pw.println(":");
6328                             printedPackage = true;
6329                         }
6330                         pw.print("      "); pw.print(AppOpsManager.opToName(opCode));
6331                         pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
6332                         final int switchOp = AppOpsManager.opToSwitch(opCode);
6333                         if (switchOp != opCode) {
6334                             pw.print(" / switch ");
6335                             pw.print(AppOpsManager.opToName(switchOp));
6336                             final Op switchObj = ops.get(switchOp);
6337                             int mode = switchObj != null ? switchObj.mode
6338                                     : AppOpsManager.opToDefaultMode(switchOp);
6339                             pw.print("="); pw.print(AppOpsManager.modeToName(mode));
6340                         }
6341                         pw.println("): ");
6342                         dumpStatesLocked(pw, dumpAttributionTag, dumpFilter, nowElapsed, op, now,
6343                                 sdf, date, "        ");
6344                     }
6345                 }
6346             }
6347             if (needSep) {
6348                 pw.println();
6349             }
6350 
6351             final int globalRestrictionCount = mOpGlobalRestrictions.size();
6352             for (int i = 0; i < globalRestrictionCount; i++) {
6353                 IBinder token = mOpGlobalRestrictions.keyAt(i);
6354                 ClientGlobalRestrictionState restrictionState = mOpGlobalRestrictions.valueAt(i);
6355                 ArraySet<Integer> restrictedOps = restrictionState.mRestrictedOps;
6356 
6357                 pw.println("  Global restrictions for token " + token + ":");
6358                 StringBuilder restrictedOpsValue = new StringBuilder();
6359                 restrictedOpsValue.append("[");
6360                 final int restrictedOpCount = restrictedOps.size();
6361                 for (int j = 0; j < restrictedOpCount; j++) {
6362                     if (restrictedOpsValue.length() > 1) {
6363                         restrictedOpsValue.append(", ");
6364                     }
6365                     restrictedOpsValue.append(AppOpsManager.opToName(restrictedOps.valueAt(j)));
6366                 }
6367                 restrictedOpsValue.append("]");
6368                 pw.println("      Restricted ops: " + restrictedOpsValue);
6369 
6370             }
6371 
6372             final int userRestrictionCount = mOpUserRestrictions.size();
6373             for (int i = 0; i < userRestrictionCount; i++) {
6374                 IBinder token = mOpUserRestrictions.keyAt(i);
6375                 ClientUserRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
6376                 boolean printedTokenHeader = false;
6377 
6378                 if (dumpMode >= 0 || dumpWatchers || dumpHistory) {
6379                     continue;
6380                 }
6381 
6382                 final int restrictionCount = restrictionState.perUserRestrictions != null
6383                         ? restrictionState.perUserRestrictions.size() : 0;
6384                 if (restrictionCount > 0 && dumpPackage == null) {
6385                     boolean printedOpsHeader = false;
6386                     for (int j = 0; j < restrictionCount; j++) {
6387                         int userId = restrictionState.perUserRestrictions.keyAt(j);
6388                         boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
6389                         if (restrictedOps == null) {
6390                             continue;
6391                         }
6392                         if (dumpOp >= 0 && (dumpOp >= restrictedOps.length
6393                                 || !restrictedOps[dumpOp])) {
6394                             continue;
6395                         }
6396                         if (!printedTokenHeader) {
6397                             pw.println("  User restrictions for token " + token + ":");
6398                             printedTokenHeader = true;
6399                         }
6400                         if (!printedOpsHeader) {
6401                             pw.println("      Restricted ops:");
6402                             printedOpsHeader = true;
6403                         }
6404                         StringBuilder restrictedOpsValue = new StringBuilder();
6405                         restrictedOpsValue.append("[");
6406                         final int restrictedOpCount = restrictedOps.length;
6407                         for (int k = 0; k < restrictedOpCount; k++) {
6408                             if (restrictedOps[k]) {
6409                                 if (restrictedOpsValue.length() > 1) {
6410                                     restrictedOpsValue.append(", ");
6411                                 }
6412                                 restrictedOpsValue.append(AppOpsManager.opToName(k));
6413                             }
6414                         }
6415                         restrictedOpsValue.append("]");
6416                         pw.print("        "); pw.print("user: "); pw.print(userId);
6417                                 pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
6418                     }
6419                 }
6420 
6421                 final int excludedPackageCount = restrictionState.perUserExcludedPackageTags != null
6422                         ? restrictionState.perUserExcludedPackageTags.size() : 0;
6423                 if (excludedPackageCount > 0 && dumpOp < 0) {
6424                     IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
6425                     ipw.increaseIndent();
6426                     boolean printedPackagesHeader = false;
6427                     for (int j = 0; j < excludedPackageCount; j++) {
6428                         int userId = restrictionState.perUserExcludedPackageTags.keyAt(j);
6429                         PackageTagsList packageNames =
6430                                 restrictionState.perUserExcludedPackageTags.valueAt(j);
6431                         if (packageNames == null) {
6432                             continue;
6433                         }
6434                         boolean hasPackage;
6435                         if (dumpPackage != null) {
6436                             hasPackage = packageNames.includes(dumpPackage);
6437                         } else {
6438                             hasPackage = true;
6439                         }
6440                         if (!hasPackage) {
6441                             continue;
6442                         }
6443                         if (!printedTokenHeader) {
6444                             ipw.println("User restrictions for token " + token + ":");
6445                             printedTokenHeader = true;
6446                         }
6447 
6448                         ipw.increaseIndent();
6449                         if (!printedPackagesHeader) {
6450                             ipw.println("Excluded packages:");
6451                             printedPackagesHeader = true;
6452                         }
6453 
6454                         ipw.increaseIndent();
6455                         ipw.print("user: ");
6456                         ipw.print(userId);
6457                         ipw.println(" packages: ");
6458 
6459                         ipw.increaseIndent();
6460                         packageNames.dump(ipw);
6461 
6462                         ipw.decreaseIndent();
6463                         ipw.decreaseIndent();
6464                         ipw.decreaseIndent();
6465                     }
6466                     ipw.decreaseIndent();
6467                 }
6468             }
6469         }
6470 
6471         // Must not hold the appops lock
6472         if (dumpHistory && !dumpWatchers) {
6473             mHistoricalRegistry.dump("  ", pw, dumpUid, dumpPackage, dumpAttributionTag, dumpOp,
6474                     dumpFilter);
6475         }
6476         if (includeDiscreteOps) {
6477             pw.println("Discrete accesses: ");
6478             mHistoricalRegistry.dumpDiscreteData(pw, dumpUid, dumpPackage, dumpAttributionTag,
6479                     dumpFilter, dumpOp, sdf, date, "  ", nDiscreteOps);
6480         }
6481     }
6482 
6483     @Override
6484     public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
6485         checkSystemUid("setUserRestrictions");
6486         Objects.requireNonNull(restrictions);
6487         Objects.requireNonNull(token);
6488         for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
6489             String restriction = AppOpsManager.opToRestriction(i);
6490             if (restriction != null) {
6491                 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
6492                         userHandle, null);
6493             }
6494         }
6495     }
6496 
6497     @Override
6498     public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
6499             PackageTagsList excludedPackageTags) {
6500         if (Binder.getCallingPid() != Process.myPid()) {
6501             mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
6502                     Binder.getCallingPid(), Binder.getCallingUid(), null);
6503         }
6504         if (userHandle != UserHandle.getCallingUserId()) {
6505             if (mContext.checkCallingOrSelfPermission(Manifest.permission
6506                     .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
6507                 && mContext.checkCallingOrSelfPermission(Manifest.permission
6508                     .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
6509                 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
6510                         + " INTERACT_ACROSS_USERS to interact cross user ");
6511             }
6512         }
6513         verifyIncomingOp(code);
6514         Objects.requireNonNull(token);
6515         setUserRestrictionNoCheck(code, restricted, token, userHandle, excludedPackageTags);
6516     }
6517 
6518     private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
6519             int userHandle, PackageTagsList excludedPackageTags) {
6520         synchronized (AppOpsService.this) {
6521             ClientUserRestrictionState restrictionState = mOpUserRestrictions.get(token);
6522 
6523             if (restrictionState == null) {
6524                 try {
6525                     restrictionState = new ClientUserRestrictionState(token);
6526                 } catch (RemoteException e) {
6527                     return;
6528                 }
6529                 mOpUserRestrictions.put(token, restrictionState);
6530             }
6531 
6532             if (restrictionState.setRestriction(code, restricted, excludedPackageTags,
6533                     userHandle)) {
6534                 mHandler.sendMessage(PooledLambda.obtainMessage(
6535                         AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
6536                 mHandler.sendMessage(PooledLambda.obtainMessage(
6537                         AppOpsService::updateStartedOpModeForUser, this, code, restricted,
6538                         userHandle));
6539             }
6540 
6541             if (restrictionState.isDefault()) {
6542                 mOpUserRestrictions.remove(token);
6543                 restrictionState.destroy();
6544             }
6545         }
6546     }
6547 
6548     private void updateStartedOpModeForUser(int code, boolean restricted, int userId) {
6549         synchronized (AppOpsService.this) {
6550             int numUids = mUidStates.size();
6551             for (int uidNum = 0; uidNum < numUids; uidNum++) {
6552                 int uid = mUidStates.keyAt(uidNum);
6553                 if (userId != UserHandle.USER_ALL && UserHandle.getUserId(uid) != userId) {
6554                     continue;
6555                 }
6556                 updateStartedOpModeForUidLocked(code, restricted, uid);
6557             }
6558         }
6559     }
6560 
6561     private void updateStartedOpModeForUidLocked(int code, boolean restricted, int uid) {
6562         UidState uidState = mUidStates.get(uid);
6563         if (uidState == null || uidState.pkgOps == null) {
6564             return;
6565         }
6566 
6567         int numPkgOps = uidState.pkgOps.size();
6568         for (int pkgNum = 0; pkgNum < numPkgOps; pkgNum++) {
6569             Ops ops = uidState.pkgOps.valueAt(pkgNum);
6570             Op op = ops != null ? ops.get(code) : null;
6571             if (op == null || (op.mode != MODE_ALLOWED && op.mode != MODE_FOREGROUND)) {
6572                 continue;
6573             }
6574             int numAttrTags = op.mAttributions.size();
6575             for (int attrNum = 0; attrNum < numAttrTags; attrNum++) {
6576                 AttributedOp attrOp = op.mAttributions.valueAt(attrNum);
6577                 if (restricted && attrOp.isRunning()) {
6578                     attrOp.pause();
6579                 } else if (attrOp.isPaused()) {
6580                     attrOp.resume();
6581                 }
6582             }
6583         }
6584     }
6585 
6586     private void notifyWatchersOfChange(int code, int uid) {
6587         final ArraySet<ModeCallback> clonedCallbacks;
6588         synchronized (this) {
6589             ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
6590             if (callbacks == null) {
6591                 return;
6592             }
6593             clonedCallbacks = new ArraySet<>(callbacks);
6594         }
6595 
6596         notifyOpChanged(clonedCallbacks,  code, uid, null);
6597     }
6598 
6599     @Override
6600     public void removeUser(int userHandle) throws RemoteException {
6601         checkSystemUid("removeUser");
6602         synchronized (AppOpsService.this) {
6603             final int tokenCount = mOpUserRestrictions.size();
6604             for (int i = tokenCount - 1; i >= 0; i--) {
6605                 ClientUserRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
6606                 opRestrictions.removeUser(userHandle);
6607             }
6608             removeUidsForUserLocked(userHandle);
6609         }
6610     }
6611 
6612     @Override
6613     public boolean isOperationActive(int code, int uid, String packageName) {
6614         if (Binder.getCallingUid() != uid) {
6615             if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
6616                     != PackageManager.PERMISSION_GRANTED) {
6617                 return false;
6618             }
6619         }
6620         verifyIncomingOp(code);
6621         verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
6622 
6623         final String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
6624         if (resolvedPackageName == null) {
6625             return false;
6626         }
6627         // TODO moltmann: Allow to check for attribution op activeness
6628         synchronized (AppOpsService.this) {
6629             Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, false, null, false);
6630             if (pkgOps == null) {
6631                 return false;
6632             }
6633 
6634             Op op = pkgOps.get(code);
6635             if (op == null) {
6636                 return false;
6637             }
6638 
6639             return op.isRunning();
6640         }
6641     }
6642 
6643     @Override
6644     public boolean isProxying(int op, @NonNull String proxyPackageName,
6645             @NonNull String proxyAttributionTag, int proxiedUid,
6646             @NonNull String proxiedPackageName) {
6647         Objects.requireNonNull(proxyPackageName);
6648         Objects.requireNonNull(proxiedPackageName);
6649         final long callingUid = Binder.getCallingUid();
6650         final long identity = Binder.clearCallingIdentity();
6651         try {
6652             final List<AppOpsManager.PackageOps> packageOps = getOpsForPackage(proxiedUid,
6653                     proxiedPackageName, new int[] {op});
6654             if (packageOps == null || packageOps.isEmpty()) {
6655                 return false;
6656             }
6657             final List<OpEntry> opEntries = packageOps.get(0).getOps();
6658             if (opEntries.isEmpty()) {
6659                 return false;
6660             }
6661             final OpEntry opEntry = opEntries.get(0);
6662             if (!opEntry.isRunning()) {
6663                 return false;
6664             }
6665             final OpEventProxyInfo proxyInfo = opEntry.getLastProxyInfo(
6666                     OP_FLAG_TRUSTED_PROXIED | AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED);
6667             return proxyInfo != null && callingUid == proxyInfo.getUid()
6668                     && proxyPackageName.equals(proxyInfo.getPackageName())
6669                     && Objects.equals(proxyAttributionTag, proxyInfo.getAttributionTag());
6670         } finally {
6671             Binder.restoreCallingIdentity(identity);
6672         }
6673     }
6674 
6675     @Override
6676     public void resetPackageOpsNoHistory(@NonNull String packageName) {
6677         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
6678                 "resetPackageOpsNoHistory");
6679         synchronized (AppOpsService.this) {
6680             final int uid = mPackageManagerInternal.getPackageUid(packageName, 0,
6681                     UserHandle.getCallingUserId());
6682             if (uid == Process.INVALID_UID) {
6683                 return;
6684             }
6685             UidState uidState = mUidStates.get(uid);
6686             if (uidState == null || uidState.pkgOps == null) {
6687                 return;
6688             }
6689             Ops removedOps = uidState.pkgOps.remove(packageName);
6690             if (removedOps != null) {
6691                 scheduleFastWriteLocked();
6692             }
6693         }
6694     }
6695 
6696     @Override
6697     public void setHistoryParameters(@AppOpsManager.HistoricalMode int mode,
6698             long baseSnapshotInterval, int compressionStep) {
6699         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
6700                 "setHistoryParameters");
6701         // Must not hold the appops lock
6702         mHistoricalRegistry.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
6703     }
6704 
6705     @Override
6706     public void offsetHistory(long offsetMillis) {
6707         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
6708                 "offsetHistory");
6709         // Must not hold the appops lock
6710         mHistoricalRegistry.offsetHistory(offsetMillis);
6711         mHistoricalRegistry.offsetDiscreteHistory(offsetMillis);
6712     }
6713 
6714     @Override
6715     public void addHistoricalOps(HistoricalOps ops) {
6716         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
6717                 "addHistoricalOps");
6718         // Must not hold the appops lock
6719         mHistoricalRegistry.addHistoricalOps(ops);
6720     }
6721 
6722     @Override
6723     public void resetHistoryParameters() {
6724         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
6725                 "resetHistoryParameters");
6726         // Must not hold the appops lock
6727         mHistoricalRegistry.resetHistoryParameters();
6728     }
6729 
6730     @Override
6731     public void clearHistory() {
6732         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
6733                 "clearHistory");
6734         // Must not hold the appops lock
6735         mHistoricalRegistry.clearAllHistory();
6736     }
6737 
6738     @Override
6739     public void rebootHistory(long offlineDurationMillis) {
6740         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
6741                 "rebootHistory");
6742 
6743         Preconditions.checkArgument(offlineDurationMillis >= 0);
6744 
6745         // Must not hold the appops lock
6746         mHistoricalRegistry.shutdown();
6747 
6748         if (offlineDurationMillis > 0) {
6749             SystemClock.sleep(offlineDurationMillis);
6750         }
6751 
6752         mHistoricalRegistry = new HistoricalRegistry(mHistoricalRegistry);
6753         mHistoricalRegistry.systemReady(mContext.getContentResolver());
6754         mHistoricalRegistry.persistPendingHistory();
6755     }
6756 
6757     /**
6758      * Report runtime access to AppOp together with message (including stack trace)
6759      *
6760      * @param packageName The package which reported the op
6761      * @param notedAppOp contains code of op and attributionTag provided by developer
6762      * @param message Message describing AppOp access (can be stack trace)
6763      *
6764      * @return Config for future sampling to reduce amount of reporting
6765      */
6766     @Override
6767     public MessageSamplingConfig reportRuntimeAppOpAccessMessageAndGetConfig(
6768             String packageName, SyncNotedAppOp notedAppOp, String message) {
6769         int uid = Binder.getCallingUid();
6770         Objects.requireNonNull(packageName);
6771         synchronized (this) {
6772             switchPackageIfBootTimeOrRarelyUsedLocked(packageName);
6773             if (!packageName.equals(mSampledPackage)) {
6774                 return new MessageSamplingConfig(OP_NONE, 0,
6775                         Instant.now().plus(1, ChronoUnit.HOURS).toEpochMilli());
6776             }
6777 
6778             Objects.requireNonNull(notedAppOp);
6779             Objects.requireNonNull(message);
6780 
6781             reportRuntimeAppOpAccessMessageInternalLocked(uid, packageName,
6782                     AppOpsManager.strOpToOp(notedAppOp.getOp()),
6783                     notedAppOp.getAttributionTag(), message);
6784 
6785             return new MessageSamplingConfig(mSampledAppOpCode, mAcceptableLeftDistance,
6786                     Instant.now().plus(1, ChronoUnit.HOURS).toEpochMilli());
6787         }
6788     }
6789 
6790     /**
6791      * Report runtime access to AppOp together with message (entry point for reporting
6792      * asynchronous access)
6793      * @param uid Uid of the package which reported the op
6794      * @param packageName The package which reported the op
6795      * @param opCode Code of AppOp
6796      * @param attributionTag FeautreId of AppOp reported
6797      * @param message Message describing AppOp access (can be stack trace)
6798      */
6799     private void reportRuntimeAppOpAccessMessageAsyncLocked(int uid,
6800             @NonNull String packageName, int opCode, @Nullable String attributionTag,
6801             @NonNull String message) {
6802         switchPackageIfBootTimeOrRarelyUsedLocked(packageName);
6803         if (!Objects.equals(mSampledPackage, packageName)) {
6804             return;
6805         }
6806         reportRuntimeAppOpAccessMessageInternalLocked(uid, packageName, opCode, attributionTag,
6807                 message);
6808     }
6809 
6810     /**
6811      * Decides whether reported message is within the range of watched AppOps and picks it for
6812      * reporting uniformly at random across all received messages.
6813      */
6814     private void reportRuntimeAppOpAccessMessageInternalLocked(int uid,
6815             @NonNull String packageName, int opCode, @Nullable String attributionTag,
6816             @NonNull String message) {
6817         int newLeftDistance = AppOpsManager.leftCircularDistance(opCode,
6818                 mSampledAppOpCode, _NUM_OP);
6819 
6820         if (mAcceptableLeftDistance < newLeftDistance
6821                 && mSamplingStrategy != SAMPLING_STRATEGY_UNIFORM_OPS) {
6822             return;
6823         }
6824 
6825         if (mAcceptableLeftDistance > newLeftDistance
6826                 && mSamplingStrategy != SAMPLING_STRATEGY_UNIFORM_OPS) {
6827             mAcceptableLeftDistance = newLeftDistance;
6828             mMessagesCollectedCount = 0.0f;
6829         }
6830 
6831         mMessagesCollectedCount += 1.0f;
6832         if (ThreadLocalRandom.current().nextFloat() <= 1.0f / mMessagesCollectedCount) {
6833             mCollectedRuntimePermissionMessage = new RuntimeAppOpAccessMessage(uid, opCode,
6834                     packageName, attributionTag, message, mSamplingStrategy);
6835         }
6836         return;
6837     }
6838 
6839     /** Pulls current AppOps access report and resamples package and app op to watch */
6840     @Override
6841     public @Nullable RuntimeAppOpAccessMessage collectRuntimeAppOpAccessMessage() {
6842         ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class);
6843         boolean isCallerInstrumented = ami.isUidCurrentlyInstrumented(Binder.getCallingUid());
6844         boolean isCallerSystem = Binder.getCallingPid() == Process.myPid();
6845         if (!isCallerSystem && !isCallerInstrumented) {
6846             return null;
6847         }
6848         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
6849                 Binder.getCallingPid(), Binder.getCallingUid(), null);
6850         RuntimeAppOpAccessMessage result;
6851         synchronized (this) {
6852             result = mCollectedRuntimePermissionMessage;
6853             mCollectedRuntimePermissionMessage = null;
6854         }
6855         mHandler.sendMessage(PooledLambda.obtainMessage(
6856                 AppOpsService::getPackageListAndResample,
6857                 this));
6858         return result;
6859     }
6860 
6861     /**
6862      * Checks if package is in the list of rarely used package and starts watching the new package
6863      * to collect incoming message or if collection is happening in first minutes since boot.
6864      * @param packageName
6865      */
6866     private void switchPackageIfBootTimeOrRarelyUsedLocked(@NonNull String packageName) {
6867         if (mSampledPackage == null) {
6868             if (ThreadLocalRandom.current().nextFloat() < 0.5f) {
6869                 mSamplingStrategy = SAMPLING_STRATEGY_BOOT_TIME_SAMPLING;
6870                 resampleAppOpForPackageLocked(packageName, true);
6871             }
6872         } else if (mRarelyUsedPackages.contains(packageName)) {
6873             mRarelyUsedPackages.remove(packageName);
6874             if (ThreadLocalRandom.current().nextFloat() < 0.5f) {
6875                 mSamplingStrategy = SAMPLING_STRATEGY_RARELY_USED;
6876                 resampleAppOpForPackageLocked(packageName, true);
6877             }
6878         }
6879     }
6880 
6881     /** Obtains package list and resamples package and appop to watch. */
6882     private List<String> getPackageListAndResample() {
6883         List<String> packageNames = getPackageNamesForSampling();
6884         synchronized (this) {
6885             resamplePackageAndAppOpLocked(packageNames);
6886         }
6887         return packageNames;
6888     }
6889 
6890     /** Resamples package and appop to watch from the list provided. */
6891     private void resamplePackageAndAppOpLocked(@NonNull List<String> packageNames) {
6892         if (!packageNames.isEmpty()) {
6893             if (ThreadLocalRandom.current().nextFloat() < 0.5f) {
6894                 mSamplingStrategy = SAMPLING_STRATEGY_UNIFORM;
6895                 resampleAppOpForPackageLocked(packageNames.get(
6896                         ThreadLocalRandom.current().nextInt(packageNames.size())), true);
6897             } else {
6898                 mSamplingStrategy = SAMPLING_STRATEGY_UNIFORM_OPS;
6899                 resampleAppOpForPackageLocked(packageNames.get(
6900                         ThreadLocalRandom.current().nextInt(packageNames.size())), false);
6901             }
6902         }
6903     }
6904 
6905     /** Resamples appop for the chosen package and initializes sampling state */
6906     private void resampleAppOpForPackageLocked(@NonNull String packageName, boolean pickOp) {
6907         mMessagesCollectedCount = 0.0f;
6908         mSampledAppOpCode = pickOp ? ThreadLocalRandom.current().nextInt(_NUM_OP) : OP_NONE;
6909         mAcceptableLeftDistance = _NUM_OP - 1;
6910         mSampledPackage = packageName;
6911     }
6912 
6913     /**
6914      * Creates list of rarely used packages - packages which were not used over last week or
6915      * which declared but did not use permissions over last week.
6916      *  */
6917     private void initializeRarelyUsedPackagesList(@NonNull ArraySet<String> candidates) {
6918         AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
6919         List<String> runtimeAppOpsList = getRuntimeAppOpsList();
6920         AppOpsManager.HistoricalOpsRequest histOpsRequest =
6921                 new AppOpsManager.HistoricalOpsRequest.Builder(
6922                         Math.max(Instant.now().minus(7, ChronoUnit.DAYS).toEpochMilli(), 0),
6923                         Long.MAX_VALUE).setOpNames(runtimeAppOpsList).setFlags(
6924                         OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED).build();
6925         appOps.getHistoricalOps(histOpsRequest, AsyncTask.THREAD_POOL_EXECUTOR,
6926                 new Consumer<HistoricalOps>() {
6927                     @Override
6928                     public void accept(HistoricalOps histOps) {
6929                         int uidCount = histOps.getUidCount();
6930                         for (int uidIdx = 0; uidIdx < uidCount; uidIdx++) {
6931                             final AppOpsManager.HistoricalUidOps uidOps = histOps.getUidOpsAt(
6932                                     uidIdx);
6933                             int pkgCount = uidOps.getPackageCount();
6934                             for (int pkgIdx = 0; pkgIdx < pkgCount; pkgIdx++) {
6935                                 String packageName = uidOps.getPackageOpsAt(
6936                                         pkgIdx).getPackageName();
6937                                 if (!candidates.contains(packageName)) {
6938                                     continue;
6939                                 }
6940                                 AppOpsManager.HistoricalPackageOps packageOps =
6941                                         uidOps.getPackageOpsAt(pkgIdx);
6942                                 if (packageOps.getOpCount() != 0) {
6943                                     candidates.remove(packageName);
6944                                 }
6945                             }
6946                         }
6947                         synchronized (this) {
6948                             int numPkgs = mRarelyUsedPackages.size();
6949                             for (int i = 0; i < numPkgs; i++) {
6950                                 candidates.add(mRarelyUsedPackages.valueAt(i));
6951                             }
6952                             mRarelyUsedPackages = candidates;
6953                         }
6954                     }
6955                 });
6956     }
6957 
6958     /** List of app ops related to runtime permissions */
6959     private List<String> getRuntimeAppOpsList() {
6960         ArrayList<String> result = new ArrayList();
6961         for (int i = 0; i < _NUM_OP; i++) {
6962             if (shouldCollectNotes(i)) {
6963                 result.add(opToPublicName(i));
6964             }
6965         }
6966         return result;
6967     }
6968 
6969     /** Returns list of packages to be used for package sampling */
6970     private @NonNull List<String> getPackageNamesForSampling() {
6971         List<String> packageNames = new ArrayList<>();
6972         PackageManagerInternal packageManagerInternal = LocalServices.getService(
6973                 PackageManagerInternal.class);
6974         PackageList packages = packageManagerInternal.getPackageList();
6975         for (String packageName : packages.getPackageNames()) {
6976             PackageInfo pkg = packageManagerInternal.getPackageInfo(packageName,
6977                     PackageManager.GET_PERMISSIONS, Process.myUid(), mContext.getUserId());
6978             if (isSamplingTarget(pkg)) {
6979                 packageNames.add(pkg.packageName);
6980             }
6981         }
6982         return packageNames;
6983     }
6984 
6985     /** Checks whether package should be included in sampling pool */
6986     private boolean isSamplingTarget(@Nullable PackageInfo pkg) {
6987         if (pkg == null) {
6988             return false;
6989         }
6990         String[] requestedPermissions = pkg.requestedPermissions;
6991         if (requestedPermissions == null) {
6992             return false;
6993         }
6994         for (String permission : requestedPermissions) {
6995             PermissionInfo permissionInfo;
6996             try {
6997                 permissionInfo = mContext.getPackageManager().getPermissionInfo(permission, 0);
6998             } catch (PackageManager.NameNotFoundException ignored) {
6999                 continue;
7000             }
7001             if (permissionInfo.getProtection() == PROTECTION_DANGEROUS) {
7002                 return true;
7003             }
7004         }
7005         return false;
7006     }
7007 
7008     private void removeUidsForUserLocked(int userHandle) {
7009         for (int i = mUidStates.size() - 1; i >= 0; --i) {
7010             final int uid = mUidStates.keyAt(i);
7011             if (UserHandle.getUserId(uid) == userHandle) {
7012                 mUidStates.removeAt(i);
7013             }
7014         }
7015     }
7016 
7017     private void checkSystemUid(String function) {
7018         int uid = Binder.getCallingUid();
7019         if (uid != Process.SYSTEM_UID) {
7020             throw new SecurityException(function + " must by called by the system");
7021         }
7022     }
7023 
7024     private static int resolveUid(String packageName)  {
7025         if (packageName == null) {
7026             return -1;
7027         }
7028         switch (packageName) {
7029             case "root":
7030                 return Process.ROOT_UID;
7031             case "shell":
7032             case "dumpstate":
7033                 return Process.SHELL_UID;
7034             case "media":
7035                 return Process.MEDIA_UID;
7036             case "audioserver":
7037                 return Process.AUDIOSERVER_UID;
7038             case "cameraserver":
7039                 return Process.CAMERASERVER_UID;
7040         }
7041         return -1;
7042     }
7043 
7044     private static String[] getPackagesForUid(int uid) {
7045         String[] packageNames = null;
7046 
7047         // Very early during boot the package manager is not yet or not yet fully started. At this
7048         // time there are no packages yet.
7049         if (AppGlobals.getPackageManager() != null) {
7050             try {
7051                 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
7052             } catch (RemoteException e) {
7053                 /* ignore - local call */
7054             }
7055         }
7056         if (packageNames == null) {
7057             return EmptyArray.STRING;
7058         }
7059         return packageNames;
7060     }
7061 
7062     private final class ClientUserRestrictionState implements DeathRecipient {
7063         private final IBinder token;
7064         SparseArray<boolean[]> perUserRestrictions;
7065         SparseArray<PackageTagsList> perUserExcludedPackageTags;
7066 
7067         ClientUserRestrictionState(IBinder token)
7068                 throws RemoteException {
7069             token.linkToDeath(this, 0);
7070             this.token = token;
7071         }
7072 
7073         public boolean setRestriction(int code, boolean restricted,
7074                 PackageTagsList excludedPackageTags, int userId) {
7075             boolean changed = false;
7076 
7077             if (perUserRestrictions == null && restricted) {
7078                 perUserRestrictions = new SparseArray<>();
7079             }
7080 
7081             int[] users;
7082             if (userId == UserHandle.USER_ALL) {
7083                 // TODO(b/162888972): this call is returning all users, not just live ones - we
7084                 // need to either fix the method called, or rename the variable
7085                 List<UserInfo> liveUsers = UserManager.get(mContext).getUsers();
7086 
7087                 users = new int[liveUsers.size()];
7088                 for (int i = 0; i < liveUsers.size(); i++) {
7089                     users[i] = liveUsers.get(i).id;
7090                 }
7091             } else {
7092                 users = new int[]{userId};
7093             }
7094 
7095             if (perUserRestrictions != null) {
7096                 int numUsers = users.length;
7097 
7098                 for (int i = 0; i < numUsers; i++) {
7099                     int thisUserId = users[i];
7100 
7101                     boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
7102                     if (userRestrictions == null && restricted) {
7103                         userRestrictions = new boolean[AppOpsManager._NUM_OP];
7104                         perUserRestrictions.put(thisUserId, userRestrictions);
7105                     }
7106                     if (userRestrictions != null && userRestrictions[code] != restricted) {
7107                         userRestrictions[code] = restricted;
7108                         if (!restricted && isDefault(userRestrictions)) {
7109                             perUserRestrictions.remove(thisUserId);
7110                             userRestrictions = null;
7111                         }
7112                         changed = true;
7113                     }
7114 
7115                     if (userRestrictions != null) {
7116                         final boolean noExcludedPackages =
7117                                 excludedPackageTags == null || excludedPackageTags.isEmpty();
7118                         if (perUserExcludedPackageTags == null && !noExcludedPackages) {
7119                             perUserExcludedPackageTags = new SparseArray<>();
7120                         }
7121                         if (perUserExcludedPackageTags != null) {
7122                             if (noExcludedPackages) {
7123                                 perUserExcludedPackageTags.remove(thisUserId);
7124                                 if (perUserExcludedPackageTags.size() <= 0) {
7125                                     perUserExcludedPackageTags = null;
7126                                 }
7127                             } else {
7128                                 perUserExcludedPackageTags.put(thisUserId, excludedPackageTags);
7129                             }
7130                             changed = true;
7131                         }
7132                     }
7133                 }
7134             }
7135 
7136             return changed;
7137         }
7138 
7139         public boolean hasRestriction(int restriction, String packageName, String attributionTag,
7140                 int userId) {
7141             if (perUserRestrictions == null) {
7142                 return false;
7143             }
7144             boolean[] restrictions = perUserRestrictions.get(userId);
7145             if (restrictions == null) {
7146                 return false;
7147             }
7148             if (!restrictions[restriction]) {
7149                 return false;
7150             }
7151             if (perUserExcludedPackageTags == null) {
7152                 return true;
7153             }
7154             PackageTagsList perUserExclusions = perUserExcludedPackageTags.get(userId);
7155             if (perUserExclusions == null) {
7156                 return true;
7157             }
7158 
7159             return !perUserExclusions.contains(packageName, attributionTag);
7160         }
7161 
7162         public void removeUser(int userId) {
7163             if (perUserExcludedPackageTags != null) {
7164                 perUserExcludedPackageTags.remove(userId);
7165                 if (perUserExcludedPackageTags.size() <= 0) {
7166                     perUserExcludedPackageTags = null;
7167                 }
7168             }
7169             if (perUserRestrictions != null) {
7170                 perUserRestrictions.remove(userId);
7171                 if (perUserRestrictions.size() <= 0) {
7172                     perUserRestrictions = null;
7173                 }
7174             }
7175         }
7176 
7177         public boolean isDefault() {
7178             return perUserRestrictions == null || perUserRestrictions.size() <= 0;
7179         }
7180 
7181         @Override
7182         public void binderDied() {
7183             synchronized (AppOpsService.this) {
7184                 mOpUserRestrictions.remove(token);
7185                 if (perUserRestrictions == null) {
7186                     return;
7187                 }
7188                 final int userCount = perUserRestrictions.size();
7189                 for (int i = 0; i < userCount; i++) {
7190                     final boolean[] restrictions = perUserRestrictions.valueAt(i);
7191                     final int restrictionCount = restrictions.length;
7192                     for (int j = 0; j < restrictionCount; j++) {
7193                         if (restrictions[j]) {
7194                             final int changedCode = j;
7195                             mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
7196                         }
7197                     }
7198                 }
7199                 destroy();
7200             }
7201         }
7202 
7203         public void destroy() {
7204             token.unlinkToDeath(this, 0);
7205         }
7206 
7207         private boolean isDefault(boolean[] array) {
7208             if (ArrayUtils.isEmpty(array)) {
7209                 return true;
7210             }
7211             for (boolean value : array) {
7212                 if (value) {
7213                     return false;
7214                 }
7215             }
7216             return true;
7217         }
7218     }
7219 
7220     private final class ClientGlobalRestrictionState implements DeathRecipient {
7221         final IBinder mToken;
7222         final ArraySet<Integer> mRestrictedOps = new ArraySet<>();
7223 
7224         ClientGlobalRestrictionState(IBinder token)
7225                 throws RemoteException {
7226             token.linkToDeath(this, 0);
7227             this.mToken = token;
7228         }
7229 
7230         boolean setRestriction(int code, boolean restricted) {
7231             if (restricted) {
7232                 return mRestrictedOps.add(code);
7233             } else {
7234                 return mRestrictedOps.remove(code);
7235             }
7236         }
7237 
7238         boolean hasRestriction(int code) {
7239             return mRestrictedOps.contains(code);
7240         }
7241 
7242         boolean isDefault() {
7243             return mRestrictedOps.isEmpty();
7244         }
7245 
7246         @Override
7247         public void binderDied() {
7248             destroy();
7249         }
7250 
7251         void destroy() {
7252             mToken.unlinkToDeath(this, 0);
7253         }
7254     }
7255 
7256     private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
7257         @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
7258             synchronized (AppOpsService.this) {
7259                 mProfileOwners = owners;
7260             }
7261         }
7262 
7263         @Override
7264         public void updateAppWidgetVisibility(SparseArray<String> uidPackageNames,
7265                 boolean visible) {
7266             AppOpsService.this.updateAppWidgetVisibility(uidPackageNames, visible);
7267         }
7268 
7269         @Override
7270         public void setUidModeFromPermissionPolicy(int code, int uid, int mode,
7271                 @Nullable IAppOpsCallback callback) {
7272             setUidMode(code, uid, mode, callback);
7273         }
7274 
7275         @Override
7276         public void setModeFromPermissionPolicy(int code, int uid, @NonNull String packageName,
7277                 int mode, @Nullable IAppOpsCallback callback) {
7278             setMode(code, uid, packageName, mode, callback);
7279         }
7280 
7281 
7282         @Override
7283         public void setGlobalRestriction(int code, boolean restricted, IBinder token) {
7284             if (Binder.getCallingPid() != Process.myPid()) {
7285                 // TODO instead of this enforcement put in AppOpsManagerInternal
7286                 throw new SecurityException("Only the system can set global restrictions");
7287             }
7288 
7289             synchronized (AppOpsService.this) {
7290                 ClientGlobalRestrictionState restrictionState = mOpGlobalRestrictions.get(token);
7291 
7292                 if (restrictionState == null) {
7293                     try {
7294                         restrictionState = new ClientGlobalRestrictionState(token);
7295                     } catch (RemoteException  e) {
7296                         return;
7297                     }
7298                     mOpGlobalRestrictions.put(token, restrictionState);
7299                 }
7300 
7301                 if (restrictionState.setRestriction(code, restricted)) {
7302                     mHandler.sendMessage(PooledLambda.obtainMessage(
7303                             AppOpsService::notifyWatchersOfChange, AppOpsService.this, code,
7304                             UID_ANY));
7305                     mHandler.sendMessage(PooledLambda.obtainMessage(
7306                             AppOpsService::updateStartedOpModeForUser, AppOpsService.this,
7307                             code, restricted, UserHandle.USER_ALL));
7308                 }
7309 
7310                 if (restrictionState.isDefault()) {
7311                     mOpGlobalRestrictions.remove(token);
7312                     restrictionState.destroy();
7313                 }
7314             }
7315         }
7316 
7317         @Override
7318         public int getOpRestrictionCount(int code, UserHandle user, String pkg,
7319                 String attributionTag) {
7320             int number = 0;
7321             synchronized (AppOpsService.this) {
7322                 int numRestrictions = mOpUserRestrictions.size();
7323                 for (int i = 0; i < numRestrictions; i++) {
7324                     if (mOpUserRestrictions.valueAt(i)
7325                             .hasRestriction(code, pkg, attributionTag, user.getIdentifier())) {
7326                         number++;
7327                     }
7328                 }
7329 
7330                 numRestrictions = mOpGlobalRestrictions.size();
7331                 for (int i = 0; i < numRestrictions; i++) {
7332                     if (mOpGlobalRestrictions.valueAt(i).hasRestriction(code)) {
7333                         number++;
7334                     }
7335                 }
7336             }
7337 
7338             return number;
7339         }
7340     }
7341 
7342     /**
7343      * Async task for writing note op stack trace, op code, package name and version to file
7344      * More specifically, writes all the collected ops from {@link #mNoteOpCallerStacktraces}
7345      */
7346     private void writeNoteOps() {
7347         synchronized (this) {
7348             mWriteNoteOpsScheduled = false;
7349         }
7350         synchronized (mNoteOpCallerStacktracesFile) {
7351             try (FileWriter writer = new FileWriter(mNoteOpCallerStacktracesFile)) {
7352                 int numTraces = mNoteOpCallerStacktraces.size();
7353                 for (int i = 0; i < numTraces; i++) {
7354                     // Writing json formatted string into file
7355                     writer.write(mNoteOpCallerStacktraces.valueAt(i).asJson());
7356                     // Comma separation, so we can wrap the entire log as a JSON object
7357                     // when all results are collected
7358                     writer.write(",");
7359                 }
7360             } catch (IOException e) {
7361                 Slog.w(TAG, "Failed to load opsValidation file for FileWriter", e);
7362             }
7363         }
7364     }
7365 
7366     /**
7367      * This class represents a NoteOp Trace object amd contains the necessary fields that will
7368      * be written to file to use for permissions data validation in JSON format
7369      */
7370     @Immutable
7371     static class NoteOpTrace {
7372         static final String STACKTRACE = "stackTrace";
7373         static final String OP = "op";
7374         static final String PACKAGENAME = "packageName";
7375         static final String VERSION = "version";
7376 
7377         private final @NonNull String mStackTrace;
7378         private final int mOp;
7379         private final @Nullable String mPackageName;
7380         private final long mVersion;
7381 
7382         /**
7383          * Initialize a NoteOp object using a JSON object containing the necessary fields
7384          *
7385          * @param jsonTrace JSON object represented as a string
7386          *
7387          * @return NoteOpTrace object initialized with JSON fields
7388          */
7389         static NoteOpTrace fromJson(String jsonTrace) {
7390             try {
7391                 // Re-add closing bracket which acted as a delimiter by the reader
7392                 JSONObject obj = new JSONObject(jsonTrace.concat("}"));
7393                 return new NoteOpTrace(obj.getString(STACKTRACE), obj.getInt(OP),
7394                         obj.getString(PACKAGENAME), obj.getLong(VERSION));
7395             } catch (JSONException e) {
7396                 // Swallow error, only meant for logging ops, should not affect flow of the code
7397                 Slog.e(TAG, "Error constructing NoteOpTrace object "
7398                         + "JSON trace format incorrect", e);
7399                 return null;
7400             }
7401         }
7402 
7403         NoteOpTrace(String stackTrace, int op, String packageName, long version) {
7404             mStackTrace = stackTrace;
7405             mOp = op;
7406             mPackageName = packageName;
7407             mVersion = version;
7408         }
7409 
7410         @Override
7411         public boolean equals(Object o) {
7412             if (this == o) return true;
7413             if (o == null || getClass() != o.getClass()) return false;
7414             NoteOpTrace that = (NoteOpTrace) o;
7415             return mOp == that.mOp
7416                     && mVersion == that.mVersion
7417                     && mStackTrace.equals(that.mStackTrace)
7418                     && Objects.equals(mPackageName, that.mPackageName);
7419         }
7420 
7421         @Override
7422         public int hashCode() {
7423             return Objects.hash(mStackTrace, mOp, mPackageName, mVersion);
7424         }
7425 
7426         /**
7427          * The object is formatted as a JSON object and returned as a String
7428          *
7429          * @return JSON formatted string
7430          */
7431         public String asJson() {
7432             return  "{"
7433                     + "\"" + STACKTRACE + "\":\"" + mStackTrace.replace("\n", "\\n")
7434                     + '\"' + ",\"" + OP + "\":" + mOp
7435                     + ",\"" + PACKAGENAME + "\":\"" + mPackageName + '\"'
7436                     + ",\"" + VERSION + "\":" + mVersion
7437                     + '}';
7438         }
7439     }
7440 
7441     /**
7442      * Collects noteOps, noteProxyOps and startOps from AppOpsManager and writes it into a file
7443      * which will be used for permissions data validation, the given parameters to this method
7444      * will be logged in json format
7445      *
7446      * @param stackTrace stacktrace from the most recent call in AppOpsManager
7447      * @param op op code
7448      * @param packageName package making call
7449      * @param version android version for this call
7450      */
7451     @Override
7452     public void collectNoteOpCallsForValidation(String stackTrace, int op, String packageName,
7453             long version) {
7454         if (!AppOpsManager.NOTE_OP_COLLECTION_ENABLED) {
7455             return;
7456         }
7457 
7458         Objects.requireNonNull(stackTrace);
7459         Preconditions.checkArgument(op >= 0);
7460         Preconditions.checkArgument(op < AppOpsManager._NUM_OP);
7461         Objects.requireNonNull(version);
7462 
7463         NoteOpTrace noteOpTrace = new NoteOpTrace(stackTrace, op, packageName, version);
7464 
7465         boolean noteOpSetWasChanged;
7466         synchronized (this) {
7467             noteOpSetWasChanged = mNoteOpCallerStacktraces.add(noteOpTrace);
7468             if (noteOpSetWasChanged && !mWriteNoteOpsScheduled) {
7469                 mWriteNoteOpsScheduled = true;
7470                 mHandler.postDelayed(PooledLambda.obtainRunnable((that) -> {
7471                     AsyncTask.execute(() -> {
7472                         that.writeNoteOps();
7473                     });
7474                 }, this), 2500);
7475             }
7476         }
7477     }
7478 
7479     @Immutable
7480     private final class CheckOpsDelegateDispatcher {
7481         private final @Nullable CheckOpsDelegate mPolicy;
7482         private final @Nullable CheckOpsDelegate mCheckOpsDelegate;
7483 
7484         CheckOpsDelegateDispatcher(@Nullable CheckOpsDelegate policy,
7485                 @Nullable CheckOpsDelegate checkOpsDelegate) {
7486             mPolicy = policy;
7487             mCheckOpsDelegate = checkOpsDelegate;
7488         }
7489 
7490         public @NonNull CheckOpsDelegate getCheckOpsDelegate() {
7491             return mCheckOpsDelegate;
7492         }
7493 
7494         public int checkOperation(int code, int uid, String packageName,
7495                 @Nullable String attributionTag, boolean raw) {
7496             if (mPolicy != null) {
7497                 if (mCheckOpsDelegate != null) {
7498                     return mPolicy.checkOperation(code, uid, packageName, attributionTag, raw,
7499                             this::checkDelegateOperationImpl);
7500                 } else {
7501                     return mPolicy.checkOperation(code, uid, packageName, attributionTag, raw,
7502                             AppOpsService.this::checkOperationImpl);
7503                 }
7504             } else if (mCheckOpsDelegate != null) {
7505                 return checkDelegateOperationImpl(code, uid, packageName, attributionTag, raw);
7506             }
7507             return checkOperationImpl(code, uid, packageName, attributionTag, raw);
7508         }
7509 
7510         private int checkDelegateOperationImpl(int code, int uid, String packageName,
7511                 @Nullable String attributionTag, boolean raw) {
7512             return mCheckOpsDelegate.checkOperation(code, uid, packageName, attributionTag, raw,
7513                     AppOpsService.this::checkOperationImpl);
7514         }
7515 
7516         public int checkAudioOperation(int code, int usage, int uid, String packageName) {
7517             if (mPolicy != null) {
7518                 if (mCheckOpsDelegate != null) {
7519                     return mPolicy.checkAudioOperation(code, usage, uid, packageName,
7520                             this::checkDelegateAudioOperationImpl);
7521                 } else {
7522                     return mPolicy.checkAudioOperation(code, usage, uid, packageName,
7523                             AppOpsService.this::checkAudioOperationImpl);
7524                 }
7525             } else if (mCheckOpsDelegate != null) {
7526                 return checkDelegateAudioOperationImpl(code, usage, uid, packageName);
7527             }
7528             return checkAudioOperationImpl(code, usage, uid, packageName);
7529         }
7530 
7531         private int checkDelegateAudioOperationImpl(int code, int usage, int uid,
7532                 String packageName) {
7533             return mCheckOpsDelegate.checkAudioOperation(code, usage, uid, packageName,
7534                     AppOpsService.this::checkAudioOperationImpl);
7535         }
7536 
7537         public SyncNotedAppOp noteOperation(int code, int uid, String packageName,
7538                 String attributionTag, boolean shouldCollectAsyncNotedOp, String message,
7539                 boolean shouldCollectMessage) {
7540             if (mPolicy != null) {
7541                 if (mCheckOpsDelegate != null) {
7542                     return mPolicy.noteOperation(code, uid, packageName, attributionTag,
7543                             shouldCollectAsyncNotedOp, message, shouldCollectMessage,
7544                             this::noteDelegateOperationImpl);
7545                 } else {
7546                     return mPolicy.noteOperation(code, uid, packageName, attributionTag,
7547                             shouldCollectAsyncNotedOp, message, shouldCollectMessage,
7548                             AppOpsService.this::noteOperationImpl);
7549                 }
7550             } else if (mCheckOpsDelegate != null) {
7551                 return noteDelegateOperationImpl(code, uid, packageName,
7552                         attributionTag, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
7553             }
7554             return noteOperationImpl(code, uid, packageName, attributionTag,
7555                     shouldCollectAsyncNotedOp, message, shouldCollectMessage);
7556         }
7557 
7558         private SyncNotedAppOp noteDelegateOperationImpl(int code, int uid,
7559                 @Nullable String packageName, @Nullable String featureId,
7560                 boolean shouldCollectAsyncNotedOp, @Nullable String message,
7561                 boolean shouldCollectMessage) {
7562             return mCheckOpsDelegate.noteOperation(code, uid, packageName, featureId,
7563                     shouldCollectAsyncNotedOp, message, shouldCollectMessage,
7564                     AppOpsService.this::noteOperationImpl);
7565         }
7566 
7567         public SyncNotedAppOp noteProxyOperation(int code, AttributionSource attributionSource,
7568                 boolean shouldCollectAsyncNotedOp, @Nullable String message,
7569                 boolean shouldCollectMessage, boolean skipProxyOperation) {
7570             if (mPolicy != null) {
7571                 if (mCheckOpsDelegate != null) {
7572                     return mPolicy.noteProxyOperation(code, attributionSource,
7573                             shouldCollectAsyncNotedOp, message, shouldCollectMessage,
7574                             skipProxyOperation, this::noteDelegateProxyOperationImpl);
7575                 } else {
7576                     return mPolicy.noteProxyOperation(code, attributionSource,
7577                             shouldCollectAsyncNotedOp, message, shouldCollectMessage,
7578                             skipProxyOperation, AppOpsService.this::noteProxyOperationImpl);
7579                 }
7580             } else if (mCheckOpsDelegate != null) {
7581                 return noteDelegateProxyOperationImpl(code,
7582                         attributionSource, shouldCollectAsyncNotedOp, message,
7583                         shouldCollectMessage, skipProxyOperation);
7584             }
7585             return noteProxyOperationImpl(code, attributionSource, shouldCollectAsyncNotedOp,
7586                     message, shouldCollectMessage,skipProxyOperation);
7587         }
7588 
7589         private SyncNotedAppOp noteDelegateProxyOperationImpl(int code,
7590                 @NonNull AttributionSource attributionSource, boolean shouldCollectAsyncNotedOp,
7591                 @Nullable String message, boolean shouldCollectMessage,
7592                 boolean skipProxyOperation) {
7593             return mCheckOpsDelegate.noteProxyOperation(code, attributionSource,
7594                     shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation,
7595                     AppOpsService.this::noteProxyOperationImpl);
7596         }
7597 
7598         public SyncNotedAppOp startOperation(IBinder token, int code, int uid,
7599                 @Nullable String packageName, @NonNull String attributionTag,
7600                 boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
7601                 @Nullable String message, boolean shouldCollectMessage,
7602                 @AttributionFlags int attributionFlags, int attributionChainId) {
7603             if (mPolicy != null) {
7604                 if (mCheckOpsDelegate != null) {
7605                     return mPolicy.startOperation(token, code, uid, packageName,
7606                             attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message,
7607                             shouldCollectMessage, attributionFlags, attributionChainId,
7608                             this::startDelegateOperationImpl);
7609                 } else {
7610                     return mPolicy.startOperation(token, code, uid, packageName, attributionTag,
7611                             startIfModeDefault, shouldCollectAsyncNotedOp, message,
7612                             shouldCollectMessage, attributionFlags, attributionChainId,
7613                             AppOpsService.this::startOperationImpl);
7614                 }
7615             } else if (mCheckOpsDelegate != null) {
7616                 return startDelegateOperationImpl(token, code, uid, packageName, attributionTag,
7617                         startIfModeDefault, shouldCollectAsyncNotedOp, message,
7618                         shouldCollectMessage, attributionFlags, attributionChainId);
7619             }
7620             return startOperationImpl(token, code, uid, packageName, attributionTag,
7621                     startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
7622                     attributionFlags, attributionChainId);
7623         }
7624 
7625         private SyncNotedAppOp startDelegateOperationImpl(IBinder token, int code, int uid,
7626                 @Nullable String packageName, @Nullable String attributionTag,
7627                 boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message,
7628                 boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
7629                 int attributionChainId) {
7630             return mCheckOpsDelegate.startOperation(token, code, uid, packageName, attributionTag,
7631                     startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
7632                     attributionFlags, attributionChainId, AppOpsService.this::startOperationImpl);
7633         }
7634 
7635         public SyncNotedAppOp startProxyOperation(int code,
7636                 @NonNull AttributionSource attributionSource, boolean startIfModeDefault,
7637                 boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
7638                 boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags,
7639                 @AttributionFlags int proxiedAttributionFlags, int attributionChainId) {
7640             if (mPolicy != null) {
7641                 if (mCheckOpsDelegate != null) {
7642                     return mPolicy.startProxyOperation(code, attributionSource,
7643                             startIfModeDefault, shouldCollectAsyncNotedOp, message,
7644                             shouldCollectMessage, skipProxyOperation, proxyAttributionFlags,
7645                             proxiedAttributionFlags, attributionChainId,
7646                             this::startDelegateProxyOperationImpl);
7647                 } else {
7648                     return mPolicy.startProxyOperation(code, attributionSource,
7649                             startIfModeDefault, shouldCollectAsyncNotedOp, message,
7650                             shouldCollectMessage, skipProxyOperation, proxyAttributionFlags,
7651                             proxiedAttributionFlags, attributionChainId,
7652                             AppOpsService.this::startProxyOperationImpl);
7653                 }
7654             } else if (mCheckOpsDelegate != null) {
7655                 return startDelegateProxyOperationImpl(code, attributionSource,
7656                         startIfModeDefault, shouldCollectAsyncNotedOp, message,
7657                         shouldCollectMessage, skipProxyOperation, proxyAttributionFlags,
7658                         proxiedAttributionFlags, attributionChainId);
7659             }
7660             return startProxyOperationImpl(code, attributionSource, startIfModeDefault,
7661                     shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation,
7662                     proxyAttributionFlags, proxiedAttributionFlags, attributionChainId);
7663         }
7664 
7665         private SyncNotedAppOp startDelegateProxyOperationImpl(int code,
7666                 @NonNull AttributionSource attributionSource, boolean startIfModeDefault,
7667                 boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
7668                 boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags,
7669                 @AttributionFlags int proxiedAttributionFlsgs, int attributionChainId) {
7670             return mCheckOpsDelegate.startProxyOperation(code, attributionSource,
7671                     startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
7672                     skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlsgs,
7673                     attributionChainId, AppOpsService.this::startProxyOperationImpl);
7674         }
7675 
7676         public void finishOperation(IBinder clientId, int code, int uid, String packageName,
7677                 String attributionTag) {
7678             if (mPolicy != null) {
7679                 if (mCheckOpsDelegate != null) {
7680                     mPolicy.finishOperation(clientId, code, uid, packageName, attributionTag,
7681                             this::finishDelegateOperationImpl);
7682                 } else {
7683                     mPolicy.finishOperation(clientId, code, uid, packageName, attributionTag,
7684                             AppOpsService.this::finishOperationImpl);
7685                 }
7686             } else if (mCheckOpsDelegate != null) {
7687                 finishDelegateOperationImpl(clientId, code, uid, packageName, attributionTag);
7688             } else {
7689                 finishOperationImpl(clientId, code, uid, packageName, attributionTag);
7690             }
7691         }
7692 
7693         private void finishDelegateOperationImpl(IBinder clientId, int code, int uid,
7694                 String packageName, String attributionTag) {
7695             mCheckOpsDelegate.finishOperation(clientId, code, uid, packageName, attributionTag,
7696                     AppOpsService.this::finishOperationImpl);
7697         }
7698 
7699         public void finishProxyOperation(int code,
7700                 @NonNull AttributionSource attributionSource, boolean skipProxyOperation) {
7701             if (mPolicy != null) {
7702                 if (mCheckOpsDelegate != null) {
7703                     mPolicy.finishProxyOperation(code, attributionSource,
7704                             skipProxyOperation, this::finishDelegateProxyOperationImpl);
7705                 } else {
7706                     mPolicy.finishProxyOperation(code, attributionSource,
7707                             skipProxyOperation, AppOpsService.this::finishProxyOperationImpl);
7708                 }
7709             } else if (mCheckOpsDelegate != null) {
7710                 finishDelegateProxyOperationImpl(code, attributionSource, skipProxyOperation);
7711             } else {
7712                 finishProxyOperationImpl(code, attributionSource, skipProxyOperation);
7713             }
7714         }
7715 
7716         private Void finishDelegateProxyOperationImpl(int code,
7717                 @NonNull AttributionSource attributionSource, boolean skipProxyOperation) {
7718             mCheckOpsDelegate.finishProxyOperation(code, attributionSource, skipProxyOperation,
7719                     AppOpsService.this::finishProxyOperationImpl);
7720             return null;
7721         }
7722     }
7723 }
7724