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