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