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