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