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