• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.appop;
18 
19 import static android.app.AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
20 import static android.app.AppOpsManager.ATTRIBUTION_FLAG_TRUSTED;
21 import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
22 import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
23 import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
24 import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
25 import static android.app.AppOpsManager.FILTER_BY_UID;
26 import static android.app.AppOpsManager.HISTORY_FLAG_GET_ATTRIBUTION_CHAINS;
27 import static android.app.AppOpsManager.HistoricalOpsRequestFilter;
28 import static android.app.AppOpsManager.KEY_BG_STATE_SETTLE_TIME;
29 import static android.app.AppOpsManager.KEY_FG_SERVICE_STATE_SETTLE_TIME;
30 import static android.app.AppOpsManager.KEY_TOP_STATE_SETTLE_TIME;
31 import static android.app.AppOpsManager.MODE_ALLOWED;
32 import static android.app.AppOpsManager.MODE_DEFAULT;
33 import static android.app.AppOpsManager.MODE_ERRORED;
34 import static android.app.AppOpsManager.MODE_FOREGROUND;
35 import static android.app.AppOpsManager.MODE_IGNORED;
36 import static android.app.AppOpsManager.OP_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 
2644         synchronized (this) {
2645             final Ops ops = getOpsLocked(uid, packageName, attributionTag,
2646                     pvr.isAttributionTagValid, pvr.bypass, /* edit */ true);
2647             if (ops == null) {
2648                 scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
2649                         AppOpsManager.MODE_IGNORED);
2650                 if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
2651                         + " package " + packageName + "flags: " +
2652                         AppOpsManager.flagsToString(flags));
2653                 return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
2654                         packageName);
2655             }
2656             final Op op = getOpLocked(ops, code, uid, true);
2657             final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
2658             if (attributedOp.isRunning()) {
2659                 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code "
2660                         + code + " startTime of in progress event="
2661                         + attributedOp.mInProgressEvents.valueAt(0).getStartTime());
2662             }
2663 
2664             final int switchCode = AppOpsManager.opToSwitch(code);
2665             final UidState uidState = ops.uidState;
2666             if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass, false)) {
2667                 attributedOp.rejected(uidState.getState(), flags);
2668                 scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
2669                         AppOpsManager.MODE_IGNORED);
2670                 return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
2671                         packageName);
2672             }
2673             // If there is a non-default per UID policy (we set UID op mode only if
2674             // non-default) it takes over, otherwise use the per package policy.
2675             if (uidState.getUidMode(switchCode) != AppOpsManager.opToDefaultMode(switchCode)) {
2676                 final int uidMode = uidState.evalMode(code, uidState.getUidMode(switchCode));
2677                 if (uidMode != AppOpsManager.MODE_ALLOWED) {
2678                     if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
2679                             + switchCode + " (" + code + ") uid " + uid + " package "
2680                             + packageName + " flags: " + AppOpsManager.flagsToString(flags));
2681                     attributedOp.rejected(uidState.getState(), flags);
2682                     scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
2683                             uidMode);
2684                     return new SyncNotedAppOp(uidMode, code, attributionTag, packageName);
2685                 }
2686             } else {
2687                 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
2688                         : op;
2689                 final int mode = switchOp.uidState.evalMode(switchOp.op, switchOp.getMode());
2690                 if (mode != AppOpsManager.MODE_ALLOWED) {
2691                     if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
2692                             + switchCode + " (" + code + ") uid " + uid + " package "
2693                             + packageName + " flags: " + AppOpsManager.flagsToString(flags));
2694                     attributedOp.rejected(uidState.getState(), flags);
2695                     scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
2696                             mode);
2697                     return new SyncNotedAppOp(mode, code, attributionTag, packageName);
2698                 }
2699             }
2700             if (DEBUG) {
2701                 Slog.d(TAG,
2702                         "noteOperation: allowing code " + code + " uid " + uid + " package "
2703                                 + packageName + (attributionTag == null ? ""
2704                                 : "." + attributionTag) + " flags: "
2705                                 + AppOpsManager.flagsToString(flags));
2706             }
2707             scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
2708                     AppOpsManager.MODE_ALLOWED);
2709             attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag,
2710                     uidState.getState(),
2711                     flags);
2712 
2713             if (shouldCollectAsyncNotedOp) {
2714                 collectAsyncNotedOp(uid, packageName, code, attributionTag, flags, message,
2715                         shouldCollectMessage);
2716             }
2717 
2718             return new SyncNotedAppOp(AppOpsManager.MODE_ALLOWED, code, attributionTag,
2719                     packageName);
2720         }
2721     }
2722 
2723     // TODO moltmann: Allow watching for attribution ops
2724     @Override
startWatchingActive(int[] ops, IAppOpsActiveCallback callback)2725     public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
2726         int watchedUid = Process.INVALID_UID;
2727         final int callingUid = Binder.getCallingUid();
2728         final int callingPid = Binder.getCallingPid();
2729         if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
2730                 != PackageManager.PERMISSION_GRANTED) {
2731             watchedUid = callingUid;
2732         }
2733         if (ops != null) {
2734             Preconditions.checkArrayElementsInRange(ops, 0,
2735                     AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
2736         }
2737         if (callback == null) {
2738             return;
2739         }
2740         synchronized (this) {
2741             SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
2742             if (callbacks == null) {
2743                 callbacks = new SparseArray<>();
2744                 mActiveWatchers.put(callback.asBinder(), callbacks);
2745             }
2746             final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
2747                     callingUid, callingPid);
2748             for (int op : ops) {
2749                 callbacks.put(op, activeCallback);
2750             }
2751         }
2752     }
2753 
2754     @Override
stopWatchingActive(IAppOpsActiveCallback callback)2755     public void stopWatchingActive(IAppOpsActiveCallback callback) {
2756         if (callback == null) {
2757             return;
2758         }
2759         synchronized (this) {
2760             final SparseArray<ActiveCallback> activeCallbacks =
2761                     mActiveWatchers.remove(callback.asBinder());
2762             if (activeCallbacks == null) {
2763                 return;
2764             }
2765             final int callbackCount = activeCallbacks.size();
2766             for (int i = 0; i < callbackCount; i++) {
2767                 activeCallbacks.valueAt(i).destroy();
2768             }
2769         }
2770     }
2771 
2772     @Override
startWatchingStarted(int[] ops, @NonNull IAppOpsStartedCallback callback)2773     public void startWatchingStarted(int[] ops, @NonNull IAppOpsStartedCallback callback) {
2774         int watchedUid = Process.INVALID_UID;
2775         final int callingUid = Binder.getCallingUid();
2776         final int callingPid = Binder.getCallingPid();
2777         if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
2778                 != PackageManager.PERMISSION_GRANTED) {
2779             watchedUid = callingUid;
2780         }
2781 
2782         Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
2783         Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
2784                 "Invalid op code in: " + Arrays.toString(ops));
2785         Objects.requireNonNull(callback, "Callback cannot be null");
2786 
2787         synchronized (this) {
2788             SparseArray<StartedCallback> callbacks = mStartedWatchers.get(callback.asBinder());
2789             if (callbacks == null) {
2790                 callbacks = new SparseArray<>();
2791                 mStartedWatchers.put(callback.asBinder(), callbacks);
2792             }
2793 
2794             final StartedCallback startedCallback = new StartedCallback(callback, watchedUid,
2795                     callingUid, callingPid);
2796             for (int op : ops) {
2797                 callbacks.put(op, startedCallback);
2798             }
2799         }
2800     }
2801 
2802     @Override
stopWatchingStarted(IAppOpsStartedCallback callback)2803     public void stopWatchingStarted(IAppOpsStartedCallback callback) {
2804         Objects.requireNonNull(callback, "Callback cannot be null");
2805 
2806         synchronized (this) {
2807             final SparseArray<StartedCallback> startedCallbacks =
2808                     mStartedWatchers.remove(callback.asBinder());
2809             if (startedCallbacks == null) {
2810                 return;
2811             }
2812 
2813             final int callbackCount = startedCallbacks.size();
2814             for (int i = 0; i < callbackCount; i++) {
2815                 startedCallbacks.valueAt(i).destroy();
2816             }
2817         }
2818     }
2819 
2820     @Override
startWatchingNoted(@onNull int[] ops, @NonNull IAppOpsNotedCallback callback)2821     public void startWatchingNoted(@NonNull int[] ops, @NonNull IAppOpsNotedCallback callback) {
2822         int watchedUid = Process.INVALID_UID;
2823         final int callingUid = Binder.getCallingUid();
2824         final int callingPid = Binder.getCallingPid();
2825         if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
2826                 != PackageManager.PERMISSION_GRANTED) {
2827             watchedUid = callingUid;
2828         }
2829         Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
2830         Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
2831                 "Invalid op code in: " + Arrays.toString(ops));
2832         Objects.requireNonNull(callback, "Callback cannot be null");
2833         synchronized (this) {
2834             SparseArray<NotedCallback> callbacks = mNotedWatchers.get(callback.asBinder());
2835             if (callbacks == null) {
2836                 callbacks = new SparseArray<>();
2837                 mNotedWatchers.put(callback.asBinder(), callbacks);
2838             }
2839             final NotedCallback notedCallback = new NotedCallback(callback, watchedUid,
2840                     callingUid, callingPid);
2841             for (int op : ops) {
2842                 callbacks.put(op, notedCallback);
2843             }
2844         }
2845     }
2846 
2847     @Override
stopWatchingNoted(IAppOpsNotedCallback callback)2848     public void stopWatchingNoted(IAppOpsNotedCallback callback) {
2849         Objects.requireNonNull(callback, "Callback cannot be null");
2850         synchronized (this) {
2851             final SparseArray<NotedCallback> notedCallbacks =
2852                     mNotedWatchers.remove(callback.asBinder());
2853             if (notedCallbacks == null) {
2854                 return;
2855             }
2856             final int callbackCount = notedCallbacks.size();
2857             for (int i = 0; i < callbackCount; i++) {
2858                 notedCallbacks.valueAt(i).destroy();
2859             }
2860         }
2861     }
2862 
2863     /**
2864      * Collect an {@link AsyncNotedAppOp}.
2865      *
2866      * @param uid The uid the op was noted for
2867      * @param packageName The package the op was noted for
2868      * @param opCode The code of the op noted
2869      * @param attributionTag attribution tag the op was noted for
2870      * @param message The message for the op noting
2871      */
collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode, @Nullable String attributionTag, @OpFlags int flags, @NonNull String message, boolean shouldCollectMessage)2872     private void collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode,
2873             @Nullable String attributionTag, @OpFlags int flags, @NonNull String message,
2874             boolean shouldCollectMessage) {
2875         Objects.requireNonNull(message);
2876 
2877         int callingUid = Binder.getCallingUid();
2878 
2879         final long token = Binder.clearCallingIdentity();
2880         try {
2881             synchronized (this) {
2882                 Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
2883 
2884                 RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
2885                 AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
2886                         attributionTag, message, System.currentTimeMillis());
2887                 final boolean[] wasNoteForwarded = {false};
2888 
2889                 if ((flags & (OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED)) != 0
2890                         && shouldCollectMessage) {
2891                     reportRuntimeAppOpAccessMessageAsyncLocked(uid, packageName, opCode,
2892                             attributionTag, message);
2893                 }
2894 
2895                 if (callbacks != null) {
2896                     callbacks.broadcast((cb) -> {
2897                         try {
2898                             cb.opNoted(asyncNotedOp);
2899                             wasNoteForwarded[0] = true;
2900                         } catch (RemoteException e) {
2901                             Slog.e(TAG,
2902                                     "Could not forward noteOp of " + opCode + " to " + packageName
2903                                             + "/" + uid + "(" + attributionTag + ")", e);
2904                         }
2905                     });
2906                 }
2907 
2908                 if (!wasNoteForwarded[0]) {
2909                     ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(key);
2910                     if (unforwardedOps == null) {
2911                         unforwardedOps = new ArrayList<>(1);
2912                         mUnforwardedAsyncNotedOps.put(key, unforwardedOps);
2913                     }
2914 
2915                     unforwardedOps.add(asyncNotedOp);
2916                     if (unforwardedOps.size() > MAX_UNFORWARDED_OPS) {
2917                         unforwardedOps.remove(0);
2918                     }
2919                 }
2920             }
2921         } finally {
2922             Binder.restoreCallingIdentity(token);
2923         }
2924     }
2925 
2926     /**
2927      * Compute a key to be used in {@link #mAsyncOpWatchers} and {@link #mUnforwardedAsyncNotedOps}
2928      *
2929      * @param packageName The package name of the app
2930      * @param uid The uid of the app
2931      *
2932      * @return They key uniquely identifying the app
2933      */
getAsyncNotedOpsKey(@onNull String packageName, int uid)2934     private @NonNull Pair<String, Integer> getAsyncNotedOpsKey(@NonNull String packageName,
2935             int uid) {
2936         return new Pair<>(packageName, uid);
2937     }
2938 
2939     @Override
startWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback)2940     public void startWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) {
2941         Objects.requireNonNull(packageName);
2942         Objects.requireNonNull(callback);
2943 
2944         int uid = Binder.getCallingUid();
2945         Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
2946 
2947         verifyAndGetBypass(uid, packageName, null);
2948 
2949         synchronized (this) {
2950             RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
2951             if (callbacks == null) {
2952                 callbacks = new RemoteCallbackList<IAppOpsAsyncNotedCallback>() {
2953                     @Override
2954                     public void onCallbackDied(IAppOpsAsyncNotedCallback callback) {
2955                         synchronized (AppOpsService.this) {
2956                             if (getRegisteredCallbackCount() == 0) {
2957                                 mAsyncOpWatchers.remove(key);
2958                             }
2959                         }
2960                     }
2961                 };
2962                 mAsyncOpWatchers.put(key, callbacks);
2963             }
2964 
2965             callbacks.register(callback);
2966         }
2967     }
2968 
2969     @Override
stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback)2970     public void stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) {
2971         Objects.requireNonNull(packageName);
2972         Objects.requireNonNull(callback);
2973 
2974         int uid = Binder.getCallingUid();
2975         Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
2976 
2977         verifyAndGetBypass(uid, packageName, null);
2978 
2979         synchronized (this) {
2980             RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
2981             if (callbacks != null) {
2982                 callbacks.unregister(callback);
2983                 if (callbacks.getRegisteredCallbackCount() == 0) {
2984                     mAsyncOpWatchers.remove(key);
2985                 }
2986             }
2987         }
2988     }
2989 
2990     @Override
extractAsyncOps(String packageName)2991     public List<AsyncNotedAppOp> extractAsyncOps(String packageName) {
2992         Objects.requireNonNull(packageName);
2993 
2994         int uid = Binder.getCallingUid();
2995 
2996         verifyAndGetBypass(uid, packageName, null);
2997 
2998         synchronized (this) {
2999             return mUnforwardedAsyncNotedOps.remove(getAsyncNotedOpsKey(packageName, uid));
3000         }
3001     }
3002 
3003     @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)3004     public SyncNotedAppOp startOperation(IBinder token, int code, int uid,
3005             @Nullable String packageName, @Nullable String attributionTag,
3006             boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
3007             String message, boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
3008             int attributionChainId) {
3009         return mCheckOpsDelegateDispatcher.startOperation(token, code, uid, packageName,
3010                 attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message,
3011                 shouldCollectMessage, attributionFlags, attributionChainId);
3012     }
3013 
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)3014     private SyncNotedAppOp startOperationImpl(@NonNull IBinder clientId, int code, int uid,
3015             @Nullable String packageName, @Nullable String attributionTag,
3016             boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @NonNull String message,
3017             boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
3018             int attributionChainId) {
3019         verifyIncomingUid(uid);
3020         verifyIncomingOp(code);
3021         if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
3022             return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
3023                     packageName);
3024         }
3025 
3026         String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
3027         if (resolvedPackageName == null) {
3028             return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
3029                     packageName);
3030         }
3031 
3032         // As a special case for OP_RECORD_AUDIO_HOTWORD, OP_RECEIVE_AMBIENT_TRIGGER_AUDIO and
3033         // OP_RECORD_AUDIO_SANDBOXED which we use only for attribution purposes and not as a check,
3034         // also make sure that the caller is allowed to access the data gated by OP_RECORD_AUDIO.
3035         //
3036         // TODO: Revert this change before Android 12.
3037         int result = MODE_DEFAULT;
3038         if (code == OP_RECORD_AUDIO_HOTWORD || code == OP_RECEIVE_AMBIENT_TRIGGER_AUDIO
3039                 || code == OP_RECORD_AUDIO_SANDBOXED) {
3040             result = checkOperation(OP_RECORD_AUDIO, uid, packageName);
3041             // Check result
3042             if (result != AppOpsManager.MODE_ALLOWED) {
3043                 return new SyncNotedAppOp(result, code, attributionTag, packageName);
3044             }
3045         }
3046         // As a special case for OP_CAMERA_SANDBOXED.
3047         if (code == OP_CAMERA_SANDBOXED) {
3048             result = checkOperation(OP_CAMERA, uid, packageName);
3049             // Check result
3050             if (result != AppOpsManager.MODE_ALLOWED) {
3051                 return new SyncNotedAppOp(result, code, attributionTag, packageName);
3052             }
3053         }
3054 
3055         return startOperationUnchecked(clientId, code, uid, packageName, attributionTag,
3056                 Process.INVALID_UID, null, null, OP_FLAG_SELF, startIfModeDefault,
3057                 shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags,
3058                 attributionChainId, /*dryRun*/ false);
3059     }
3060 
3061     @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)3062     public SyncNotedAppOp startProxyOperation(@NonNull IBinder clientId, int code,
3063             @NonNull AttributionSource attributionSource, boolean startIfModeDefault,
3064             boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
3065             boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags,
3066             @AttributionFlags int proxiedAttributionFlags, int attributionChainId) {
3067         return mCheckOpsDelegateDispatcher.startProxyOperation(clientId, code, attributionSource,
3068                 startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
3069                 skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlags,
3070                 attributionChainId);
3071     }
3072 
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)3073     private SyncNotedAppOp startProxyOperationImpl(@NonNull IBinder clientId, int code,
3074             @NonNull AttributionSource attributionSource,
3075             boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message,
3076             boolean shouldCollectMessage, boolean skipProxyOperation, @AttributionFlags
3077             int proxyAttributionFlags, @AttributionFlags int proxiedAttributionFlags,
3078             int attributionChainId) {
3079         final int proxyUid = attributionSource.getUid();
3080         final String proxyPackageName = attributionSource.getPackageName();
3081         final String proxyAttributionTag = attributionSource.getAttributionTag();
3082         final int proxiedUid = attributionSource.getNextUid();
3083         final String proxiedPackageName = attributionSource.getNextPackageName();
3084         final String proxiedAttributionTag = attributionSource.getNextAttributionTag();
3085 
3086         verifyIncomingProxyUid(attributionSource);
3087         verifyIncomingOp(code);
3088         if (!isIncomingPackageValid(proxyPackageName, UserHandle.getUserId(proxyUid))
3089                 || !isIncomingPackageValid(proxiedPackageName, UserHandle.getUserId(proxiedUid))) {
3090             return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, proxiedAttributionTag,
3091                     proxiedPackageName);
3092         }
3093 
3094         boolean isCallerTrusted = isCallerAndAttributionTrusted(attributionSource);
3095         skipProxyOperation = isCallerTrusted && skipProxyOperation;
3096 
3097         String resolvedProxyPackageName = AppOpsManager.resolvePackageName(proxyUid,
3098                 proxyPackageName);
3099         if (resolvedProxyPackageName == null) {
3100             return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, proxiedAttributionTag,
3101                     proxiedPackageName);
3102         }
3103 
3104         final boolean isChainTrusted = isCallerTrusted
3105                 && attributionChainId != ATTRIBUTION_CHAIN_ID_NONE
3106                 && ((proxyAttributionFlags & ATTRIBUTION_FLAG_TRUSTED) != 0
3107                 || (proxiedAttributionFlags & ATTRIBUTION_FLAG_TRUSTED) != 0);
3108         final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid;
3109         final boolean isProxyTrusted = mContext.checkPermission(
3110                 Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
3111                 == PackageManager.PERMISSION_GRANTED || isSelfBlame
3112                 || isChainTrusted;
3113 
3114         String resolvedProxiedPackageName = AppOpsManager.resolvePackageName(proxiedUid,
3115                 proxiedPackageName);
3116         if (resolvedProxiedPackageName == null) {
3117             return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, proxiedAttributionTag,
3118                     proxiedPackageName);
3119         }
3120 
3121         final int proxiedFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXIED
3122                 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED;
3123 
3124         if (!skipProxyOperation) {
3125             // Test if the proxied operation will succeed before starting the proxy operation
3126             final SyncNotedAppOp testProxiedOp = startOperationUnchecked(clientId, code,
3127                     proxiedUid, resolvedProxiedPackageName, proxiedAttributionTag, proxyUid,
3128                     resolvedProxyPackageName, proxyAttributionTag, proxiedFlags, startIfModeDefault,
3129                     shouldCollectAsyncNotedOp, message, shouldCollectMessage,
3130                     proxiedAttributionFlags, attributionChainId, /*dryRun*/ true);
3131             if (!shouldStartForMode(testProxiedOp.getOpMode(), startIfModeDefault)) {
3132                 return testProxiedOp;
3133             }
3134 
3135             final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
3136                     : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
3137 
3138             final SyncNotedAppOp proxyAppOp = startOperationUnchecked(clientId, code, proxyUid,
3139                     resolvedProxyPackageName, proxyAttributionTag, Process.INVALID_UID, null, null,
3140                     proxyFlags, startIfModeDefault, !isProxyTrusted, "proxy " + message,
3141                     shouldCollectMessage, proxyAttributionFlags, attributionChainId,
3142                     /*dryRun*/ false);
3143             if (!shouldStartForMode(proxyAppOp.getOpMode(), startIfModeDefault)) {
3144                 return proxyAppOp;
3145             }
3146         }
3147 
3148         return startOperationUnchecked(clientId, code, proxiedUid, resolvedProxiedPackageName,
3149                 proxiedAttributionTag, proxyUid, resolvedProxyPackageName, proxyAttributionTag,
3150                 proxiedFlags, startIfModeDefault, shouldCollectAsyncNotedOp, message,
3151                 shouldCollectMessage, proxiedAttributionFlags, attributionChainId,
3152                 /*dryRun*/ false);
3153     }
3154 
shouldStartForMode(int mode, boolean startIfModeDefault)3155     private boolean shouldStartForMode(int mode, boolean startIfModeDefault) {
3156         return (mode == MODE_ALLOWED || (mode == MODE_DEFAULT && startIfModeDefault));
3157     }
3158 
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)3159     private SyncNotedAppOp startOperationUnchecked(IBinder clientId, int code, int uid,
3160             @NonNull String packageName, @Nullable String attributionTag, int proxyUid,
3161             String proxyPackageName, @Nullable String proxyAttributionTag, @OpFlags int flags,
3162             boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @Nullable String message,
3163             boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
3164             int attributionChainId, boolean dryRun) {
3165         PackageVerificationResult pvr;
3166         try {
3167             pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName);
3168             if (!pvr.isAttributionTagValid) {
3169                 attributionTag = null;
3170             }
3171         } catch (SecurityException e) {
3172             if (Process.isIsolated(uid)) {
3173                 Slog.e(TAG, "Cannot startOperation: isolated process");
3174             } else {
3175                 Slog.e(TAG, "Cannot startOperation", e);
3176             }
3177             return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
3178                     packageName);
3179         }
3180 
3181         boolean isRestricted = false;
3182         int startType = START_TYPE_FAILED;
3183         synchronized (this) {
3184             final Ops ops = getOpsLocked(uid, packageName, attributionTag,
3185                     pvr.isAttributionTagValid, pvr.bypass, /* edit */ true);
3186             if (ops == null) {
3187                 if (!dryRun) {
3188                     scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
3189                             flags, AppOpsManager.MODE_IGNORED, startType, attributionFlags,
3190                             attributionChainId);
3191                 }
3192                 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
3193                         + " package " + packageName + " flags: "
3194                         + AppOpsManager.flagsToString(flags));
3195                 return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
3196                         packageName);
3197             }
3198             final Op op = getOpLocked(ops, code, uid, true);
3199             final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
3200             final UidState uidState = ops.uidState;
3201             isRestricted = isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass,
3202                     false);
3203             final int switchCode = AppOpsManager.opToSwitch(code);
3204             // If there is a non-default per UID policy (we set UID op mode only if
3205             // non-default) it takes over, otherwise use the per package policy.
3206             if (uidState.getUidMode(switchCode) != AppOpsManager.opToDefaultMode(switchCode)) {
3207                 final int uidMode = uidState.evalMode(code, uidState.getUidMode(switchCode));
3208                 if (!shouldStartForMode(uidMode, startIfModeDefault)) {
3209                     if (DEBUG) {
3210                         Slog.d(TAG, "startOperation: uid reject #" + uidMode + " for code "
3211                                 + switchCode + " (" + code + ") uid " + uid + " package "
3212                                 + packageName + " flags: " + AppOpsManager.flagsToString(flags));
3213                     }
3214                     if (!dryRun) {
3215                         attributedOp.rejected(uidState.getState(), flags);
3216                         scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
3217                                 flags, uidMode, startType, attributionFlags, attributionChainId);
3218                     }
3219                     return new SyncNotedAppOp(uidMode, code, attributionTag, packageName);
3220                 }
3221             } else {
3222                 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
3223                         : op;
3224                 final int mode = switchOp.uidState.evalMode(switchOp.op, switchOp.getMode());
3225                 if (mode != AppOpsManager.MODE_ALLOWED
3226                         && (!startIfModeDefault || mode != MODE_DEFAULT)) {
3227                     if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
3228                             + switchCode + " (" + code + ") uid " + uid + " package "
3229                             + packageName + " flags: " + AppOpsManager.flagsToString(flags));
3230                     if (!dryRun) {
3231                         attributedOp.rejected(uidState.getState(), flags);
3232                         scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
3233                                 flags, mode, startType, attributionFlags, attributionChainId);
3234                     }
3235                     return new SyncNotedAppOp(mode, code, attributionTag, packageName);
3236                 }
3237             }
3238             if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
3239                     + " package " + packageName + " restricted: " + isRestricted
3240                     + " flags: " + AppOpsManager.flagsToString(flags));
3241             if (!dryRun) {
3242                 try {
3243                     if (isRestricted) {
3244                         attributedOp.createPaused(clientId, proxyUid, proxyPackageName,
3245                                 proxyAttributionTag, uidState.getState(), flags,
3246                                 attributionFlags, attributionChainId);
3247                     } else {
3248                         attributedOp.started(clientId, proxyUid, proxyPackageName,
3249                                 proxyAttributionTag, uidState.getState(), flags,
3250                                 attributionFlags, attributionChainId);
3251                         startType = START_TYPE_STARTED;
3252                     }
3253                 } catch (RemoteException e) {
3254                     throw new RuntimeException(e);
3255                 }
3256                 scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag, flags,
3257                         isRestricted ? MODE_IGNORED : MODE_ALLOWED, startType, attributionFlags,
3258                         attributionChainId);
3259             }
3260         }
3261 
3262         if (shouldCollectAsyncNotedOp && !dryRun && !isRestricted) {
3263             collectAsyncNotedOp(uid, packageName, code, attributionTag, AppOpsManager.OP_FLAG_SELF,
3264                     message, shouldCollectMessage);
3265         }
3266 
3267         return new SyncNotedAppOp(isRestricted ? MODE_IGNORED : MODE_ALLOWED, code, attributionTag,
3268                 packageName);
3269     }
3270 
3271     @Override
finishOperation(IBinder clientId, int code, int uid, String packageName, String attributionTag)3272     public void finishOperation(IBinder clientId, int code, int uid, String packageName,
3273             String attributionTag) {
3274         mCheckOpsDelegateDispatcher.finishOperation(clientId, code, uid, packageName,
3275                 attributionTag);
3276     }
3277 
finishOperationImpl(IBinder clientId, int code, int uid, String packageName, String attributionTag)3278     private void finishOperationImpl(IBinder clientId, int code, int uid, String packageName,
3279             String attributionTag) {
3280         verifyIncomingUid(uid);
3281         verifyIncomingOp(code);
3282         if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
3283             return;
3284         }
3285 
3286         String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
3287         if (resolvedPackageName == null) {
3288             return;
3289         }
3290 
3291         finishOperationUnchecked(clientId, code, uid, resolvedPackageName, attributionTag);
3292     }
3293 
3294     @Override
finishProxyOperation(@onNull IBinder clientId, int code, @NonNull AttributionSource attributionSource, boolean skipProxyOperation)3295     public void finishProxyOperation(@NonNull IBinder clientId, int code,
3296             @NonNull AttributionSource attributionSource, boolean skipProxyOperation) {
3297         mCheckOpsDelegateDispatcher.finishProxyOperation(clientId, code, attributionSource,
3298                 skipProxyOperation);
3299     }
3300 
finishProxyOperationImpl(IBinder clientId, int code, @NonNull AttributionSource attributionSource, boolean skipProxyOperation)3301     private Void finishProxyOperationImpl(IBinder clientId, int code,
3302             @NonNull AttributionSource attributionSource, boolean skipProxyOperation) {
3303         final int proxyUid = attributionSource.getUid();
3304         final String proxyPackageName = attributionSource.getPackageName();
3305         final String proxyAttributionTag = attributionSource.getAttributionTag();
3306         final int proxiedUid = attributionSource.getNextUid();
3307         final String proxiedPackageName = attributionSource.getNextPackageName();
3308         final String proxiedAttributionTag = attributionSource.getNextAttributionTag();
3309 
3310         skipProxyOperation = skipProxyOperation
3311                 && isCallerAndAttributionTrusted(attributionSource);
3312 
3313         verifyIncomingProxyUid(attributionSource);
3314         verifyIncomingOp(code);
3315         if (!isIncomingPackageValid(proxyPackageName, UserHandle.getUserId(proxyUid))
3316                 || !isIncomingPackageValid(proxiedPackageName, UserHandle.getUserId(proxiedUid))) {
3317             return null;
3318         }
3319 
3320         String resolvedProxyPackageName = AppOpsManager.resolvePackageName(proxyUid,
3321                 proxyPackageName);
3322         if (resolvedProxyPackageName == null) {
3323             return null;
3324         }
3325 
3326         if (!skipProxyOperation) {
3327             finishOperationUnchecked(clientId, code, proxyUid, resolvedProxyPackageName,
3328                     proxyAttributionTag);
3329         }
3330 
3331         String resolvedProxiedPackageName = AppOpsManager.resolvePackageName(proxiedUid,
3332                 proxiedPackageName);
3333         if (resolvedProxiedPackageName == null) {
3334             return null;
3335         }
3336 
3337         finishOperationUnchecked(clientId, code, proxiedUid, resolvedProxiedPackageName,
3338                 proxiedAttributionTag);
3339 
3340         return null;
3341     }
3342 
finishOperationUnchecked(IBinder clientId, int code, int uid, String packageName, String attributionTag)3343     private void finishOperationUnchecked(IBinder clientId, int code, int uid, String packageName,
3344             String attributionTag) {
3345         PackageVerificationResult pvr;
3346         try {
3347             pvr = verifyAndGetBypass(uid, packageName, attributionTag);
3348             if (!pvr.isAttributionTagValid) {
3349                 attributionTag = null;
3350             }
3351         } catch (SecurityException e) {
3352             if (Process.isIsolated(uid)) {
3353                 Slog.e(TAG, "Cannot finishOperation: isolated process");
3354             } else {
3355                 Slog.e(TAG, "Cannot finishOperation", e);
3356             }
3357             return;
3358         }
3359 
3360         synchronized (this) {
3361             Op op = getOpLocked(code, uid, packageName, attributionTag, pvr.isAttributionTagValid,
3362                     pvr.bypass, /* edit */ true);
3363             if (op == null) {
3364                 Slog.e(TAG, "Operation not found: uid=" + uid + " pkg=" + packageName + "("
3365                         + attributionTag + ") op=" + AppOpsManager.opToName(code));
3366                 return;
3367             }
3368             final AttributedOp attributedOp = op.mAttributions.get(attributionTag);
3369             if (attributedOp == null) {
3370                 Slog.e(TAG, "Attribution not found: uid=" + uid + " pkg=" + packageName + "("
3371                         + attributionTag + ") op=" + AppOpsManager.opToName(code));
3372                 return;
3373             }
3374 
3375             if (attributedOp.isRunning() || attributedOp.isPaused()) {
3376                 attributedOp.finished(clientId);
3377             } else {
3378                 Slog.e(TAG, "Operation not started: uid=" + uid + " pkg=" + packageName + "("
3379                         + attributionTag + ") op=" + AppOpsManager.opToName(code));
3380             }
3381         }
3382     }
3383 
scheduleOpActiveChangedIfNeededLocked(int code, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean active, @AttributionFlags int attributionFlags, int attributionChainId)3384     void scheduleOpActiveChangedIfNeededLocked(int code, int uid, @NonNull
3385             String packageName, @Nullable String attributionTag, boolean active, @AttributionFlags
3386             int attributionFlags, int attributionChainId) {
3387         ArraySet<ActiveCallback> dispatchedCallbacks = null;
3388         final int callbackListCount = mActiveWatchers.size();
3389         for (int i = 0; i < callbackListCount; i++) {
3390             final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
3391             ActiveCallback callback = callbacks.get(code);
3392             if (callback != null) {
3393                 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
3394                     continue;
3395                 }
3396                 if (dispatchedCallbacks == null) {
3397                     dispatchedCallbacks = new ArraySet<>();
3398                 }
3399                 dispatchedCallbacks.add(callback);
3400             }
3401         }
3402         if (dispatchedCallbacks == null) {
3403             return;
3404         }
3405         mHandler.sendMessage(PooledLambda.obtainMessage(
3406                 AppOpsService::notifyOpActiveChanged,
3407                 this, dispatchedCallbacks, code, uid, packageName, attributionTag, active,
3408                 attributionFlags, attributionChainId));
3409     }
3410 
notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks, int code, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean active, @AttributionFlags int attributionFlags, int attributionChainId)3411     private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
3412             int code, int uid, @NonNull String packageName, @Nullable String attributionTag,
3413             boolean active, @AttributionFlags int attributionFlags, int attributionChainId) {
3414         // There are features watching for mode changes such as window manager
3415         // and location manager which are in our process. The callbacks in these
3416         // features may require permissions our remote caller does not have.
3417         final long identity = Binder.clearCallingIdentity();
3418         try {
3419             final int callbackCount = callbacks.size();
3420             for (int i = 0; i < callbackCount; i++) {
3421                 final ActiveCallback callback = callbacks.valueAt(i);
3422                 try {
3423                     if (shouldIgnoreCallback(code, callback.mCallingPid, callback.mCallingUid)) {
3424                         continue;
3425                     }
3426                     callback.mCallback.opActiveChanged(code, uid, packageName, attributionTag,
3427                             active, attributionFlags, attributionChainId);
3428                 } catch (RemoteException e) {
3429                     /* do nothing */
3430                 }
3431             }
3432         } finally {
3433             Binder.restoreCallingIdentity(identity);
3434         }
3435     }
3436 
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)3437     void scheduleOpStartedIfNeededLocked(int code, int uid, String pkgName,
3438             String attributionTag, @OpFlags int flags, @Mode int result,
3439             @AppOpsManager.OnOpStartedListener.StartedType int startedType,
3440             @AttributionFlags int attributionFlags, int attributionChainId) {
3441         ArraySet<StartedCallback> dispatchedCallbacks = null;
3442         final int callbackListCount = mStartedWatchers.size();
3443         for (int i = 0; i < callbackListCount; i++) {
3444             final SparseArray<StartedCallback> callbacks = mStartedWatchers.valueAt(i);
3445 
3446             StartedCallback callback = callbacks.get(code);
3447             if (callback != null) {
3448                 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
3449                     continue;
3450                 }
3451 
3452                 if (dispatchedCallbacks == null) {
3453                     dispatchedCallbacks = new ArraySet<>();
3454                 }
3455                 dispatchedCallbacks.add(callback);
3456             }
3457         }
3458 
3459         if (dispatchedCallbacks == null) {
3460             return;
3461         }
3462 
3463         mHandler.sendMessage(PooledLambda.obtainMessage(
3464                 AppOpsService::notifyOpStarted,
3465                 this, dispatchedCallbacks, code, uid, pkgName, attributionTag, flags,
3466                 result, startedType, attributionFlags, attributionChainId));
3467     }
3468 
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)3469     private void notifyOpStarted(ArraySet<StartedCallback> callbacks,
3470             int code, int uid, String packageName, String attributionTag, @OpFlags int flags,
3471             @Mode int result, @AppOpsManager.OnOpStartedListener.StartedType int startedType,
3472             @AttributionFlags int attributionFlags, int attributionChainId) {
3473         final long identity = Binder.clearCallingIdentity();
3474         try {
3475             final int callbackCount = callbacks.size();
3476             for (int i = 0; i < callbackCount; i++) {
3477                 final StartedCallback callback = callbacks.valueAt(i);
3478                 try {
3479                     if (shouldIgnoreCallback(code, callback.mCallingPid, callback.mCallingUid)) {
3480                         continue;
3481                     }
3482                     callback.mCallback.opStarted(code, uid, packageName, attributionTag, flags,
3483                             result, startedType, attributionFlags, attributionChainId);
3484                 } catch (RemoteException e) {
3485                     /* do nothing */
3486                 }
3487             }
3488         } finally {
3489             Binder.restoreCallingIdentity(identity);
3490         }
3491     }
3492 
scheduleOpNotedIfNeededLocked(int code, int uid, String packageName, String attributionTag, @OpFlags int flags, @Mode int result)3493     private void scheduleOpNotedIfNeededLocked(int code, int uid, String packageName,
3494             String attributionTag, @OpFlags int flags, @Mode int result) {
3495         ArraySet<NotedCallback> dispatchedCallbacks = null;
3496         final int callbackListCount = mNotedWatchers.size();
3497         for (int i = 0; i < callbackListCount; i++) {
3498             final SparseArray<NotedCallback> callbacks = mNotedWatchers.valueAt(i);
3499             final NotedCallback callback = callbacks.get(code);
3500             if (callback != null) {
3501                 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
3502                     continue;
3503                 }
3504                 if (dispatchedCallbacks == null) {
3505                     dispatchedCallbacks = new ArraySet<>();
3506                 }
3507                 dispatchedCallbacks.add(callback);
3508             }
3509         }
3510         if (dispatchedCallbacks == null) {
3511             return;
3512         }
3513         mHandler.sendMessage(PooledLambda.obtainMessage(
3514                 AppOpsService::notifyOpChecked,
3515                 this, dispatchedCallbacks, code, uid, packageName, attributionTag, flags,
3516                 result));
3517     }
3518 
notifyOpChecked(ArraySet<NotedCallback> callbacks, int code, int uid, String packageName, String attributionTag, @OpFlags int flags, @Mode int result)3519     private void notifyOpChecked(ArraySet<NotedCallback> callbacks,
3520             int code, int uid, String packageName, String attributionTag, @OpFlags int flags,
3521             @Mode int result) {
3522         // There are features watching for checks in our process. The callbacks in
3523         // these features may require permissions our remote caller does not have.
3524         final long identity = Binder.clearCallingIdentity();
3525         try {
3526             final int callbackCount = callbacks.size();
3527             for (int i = 0; i < callbackCount; i++) {
3528                 final NotedCallback callback = callbacks.valueAt(i);
3529                 try {
3530                     if (shouldIgnoreCallback(code, callback.mCallingPid, callback.mCallingUid)) {
3531                         continue;
3532                     }
3533                     callback.mCallback.opNoted(code, uid, packageName, attributionTag, flags,
3534                             result);
3535                 } catch (RemoteException e) {
3536                     /* do nothing */
3537                 }
3538             }
3539         } finally {
3540             Binder.restoreCallingIdentity(identity);
3541         }
3542     }
3543 
3544     @Override
permissionToOpCode(String permission)3545     public int permissionToOpCode(String permission) {
3546         if (permission == null) {
3547             return AppOpsManager.OP_NONE;
3548         }
3549         return AppOpsManager.permissionToOpCode(permission);
3550     }
3551 
3552     @Override
shouldCollectNotes(int opCode)3553     public boolean shouldCollectNotes(int opCode) {
3554         Preconditions.checkArgumentInRange(opCode, 0, _NUM_OP - 1, "opCode");
3555 
3556         if (AppOpsManager.shouldForceCollectNoteForOp(opCode)) {
3557             return true;
3558         }
3559 
3560         String perm = AppOpsManager.opToPermission(opCode);
3561         if (perm == null) {
3562             return false;
3563         }
3564 
3565         PermissionInfo permInfo;
3566         try {
3567             permInfo = mContext.getPackageManager().getPermissionInfo(perm, 0);
3568         } catch (PackageManager.NameNotFoundException e) {
3569             return false;
3570         }
3571 
3572         return permInfo.getProtection() == PROTECTION_DANGEROUS
3573                 || (permInfo.getProtectionFlags() & PROTECTION_FLAG_APPOP) != 0;
3574     }
3575 
verifyIncomingProxyUid(@onNull AttributionSource attributionSource)3576     private void verifyIncomingProxyUid(@NonNull AttributionSource attributionSource) {
3577         if (attributionSource.getUid() == Binder.getCallingUid()) {
3578             return;
3579         }
3580         if (Binder.getCallingPid() == Process.myPid()) {
3581             return;
3582         }
3583         if (attributionSource.isTrusted(mContext)) {
3584             return;
3585         }
3586         mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
3587                 Binder.getCallingPid(), Binder.getCallingUid(), null);
3588     }
3589 
verifyIncomingUid(int uid)3590     private void verifyIncomingUid(int uid) {
3591         if (uid == Binder.getCallingUid()) {
3592             return;
3593         }
3594         if (Binder.getCallingPid() == Process.myPid()) {
3595             return;
3596         }
3597         mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
3598                 Binder.getCallingPid(), Binder.getCallingUid(), null);
3599     }
3600 
shouldIgnoreCallback(int op, int watcherPid, int watcherUid)3601     private boolean shouldIgnoreCallback(int op, int watcherPid, int watcherUid) {
3602         // If it's a restricted read op, ignore it if watcher doesn't have manage ops permission,
3603         // as watcher should not use this to signal if the value is changed.
3604         return opRestrictsRead(op) && mContext.checkPermission(Manifest.permission.MANAGE_APPOPS,
3605                 watcherPid, watcherUid) != PackageManager.PERMISSION_GRANTED;
3606     }
3607 
verifyIncomingOp(int op)3608     private void verifyIncomingOp(int op) {
3609         if (op >= 0 && op < AppOpsManager._NUM_OP) {
3610             // Enforce manage appops permission if it's a restricted read op.
3611             if (opRestrictsRead(op)) {
3612                 mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
3613                         Binder.getCallingPid(), Binder.getCallingUid(), "verifyIncomingOp");
3614             }
3615             return;
3616         }
3617         throw new IllegalArgumentException("Bad operation #" + op);
3618     }
3619 
isIncomingPackageValid(@ullable String packageName, @UserIdInt int userId)3620     private boolean isIncomingPackageValid(@Nullable String packageName, @UserIdInt int userId) {
3621         final int callingUid = Binder.getCallingUid();
3622         // Handle the special UIDs that don't have actual packages (audioserver, cameraserver, etc).
3623         if (packageName == null || isSpecialPackage(callingUid, packageName)) {
3624             return true;
3625         }
3626 
3627         // If the package doesn't exist, #verifyAndGetBypass would throw a SecurityException in
3628         // the end. Although that exception would be caught and return, we could make it return
3629         // early.
3630         if (!isPackageExisted(packageName)) {
3631             return false;
3632         }
3633 
3634         if (getPackageManagerInternal().filterAppAccess(packageName, callingUid, userId)) {
3635             Slog.w(TAG, packageName + " not found from " + callingUid);
3636             return false;
3637         }
3638 
3639         return true;
3640     }
3641 
isSpecialPackage(int callingUid, @Nullable String packageName)3642     private boolean isSpecialPackage(int callingUid, @Nullable String packageName) {
3643         final String resolvedPackage = AppOpsManager.resolvePackageName(callingUid, packageName);
3644         return callingUid == Process.SYSTEM_UID
3645                 || resolveUid(resolvedPackage) != Process.INVALID_UID;
3646     }
3647 
isCallerAndAttributionTrusted(@onNull AttributionSource attributionSource)3648     private boolean isCallerAndAttributionTrusted(@NonNull AttributionSource attributionSource) {
3649         if (attributionSource.getUid() != Binder.getCallingUid()
3650                 && attributionSource.isTrusted(mContext)) {
3651             return true;
3652         }
3653         return mContext.checkPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
3654                 Binder.getCallingPid(), Binder.getCallingUid(), null)
3655                 == PackageManager.PERMISSION_GRANTED;
3656     }
3657 
getUidStateLocked(int uid, boolean edit)3658     private @Nullable UidState getUidStateLocked(int uid, boolean edit) {
3659         UidState uidState = mUidStates.get(uid);
3660         if (uidState == null) {
3661             if (!edit) {
3662                 return null;
3663             }
3664             uidState = new UidState(uid);
3665             mUidStates.put(uid, uidState);
3666         }
3667 
3668         return uidState;
3669     }
3670 
updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible)3671     private void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible) {
3672         synchronized (this) {
3673             getUidStateTracker().updateAppWidgetVisibility(uidPackageNames, visible);
3674         }
3675     }
3676 
3677     /**
3678      * @return {@link PackageManagerInternal}
3679      */
getPackageManagerInternal()3680     private @NonNull PackageManagerInternal getPackageManagerInternal() {
3681         if (mPackageManagerInternal == null) {
3682             mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
3683         }
3684         if (mPackageManagerInternal == null) {
3685             throw new IllegalStateException("PackageManagerInternal not loaded");
3686         }
3687 
3688         return mPackageManagerInternal;
3689     }
3690 
3691     /**
3692      * @return {@link PackageManagerLocal}
3693      */
getPackageManagerLocal()3694     private @NonNull PackageManagerLocal getPackageManagerLocal() {
3695         if (mPackageManagerLocal == null) {
3696             mPackageManagerLocal = LocalManagerRegistry.getManager(PackageManagerLocal.class);
3697         }
3698         if (mPackageManagerLocal == null) {
3699             throw new IllegalStateException("PackageManagerLocal not loaded");
3700         }
3701 
3702         return mPackageManagerLocal;
3703     }
3704 
3705     /**
3706      * @return {@link UserManagerInternal}
3707      */
getUserManagerInternal()3708     private @NonNull UserManagerInternal getUserManagerInternal() {
3709         if (mUserManagerInternal == null) {
3710             mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
3711         }
3712         if (mUserManagerInternal == null) {
3713             throw new IllegalStateException("UserManagerInternal not loaded");
3714         }
3715 
3716         return mUserManagerInternal;
3717     }
3718 
3719     /**
3720      * Create a restriction description matching the properties of the package.
3721      *
3722      * @param pkg The package to create the restriction description for
3723      *
3724      * @return The restriction matching the package
3725      */
getBypassforPackage(@onNull PackageState packageState)3726     private RestrictionBypass getBypassforPackage(@NonNull PackageState packageState) {
3727         return new RestrictionBypass(packageState.getAppId() == Process.SYSTEM_UID,
3728                 packageState.isPrivileged(), mContext.checkPermission(
3729                 android.Manifest.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS, -1,
3730                 packageState.getAppId()) == PackageManager.PERMISSION_GRANTED);
3731     }
3732 
3733     /**
3734      * @see #verifyAndGetBypass(int, String, String, String, boolean)
3735      */
verifyAndGetBypass(int uid, String packageName, @Nullable String attributionTag)3736     private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName,
3737             @Nullable String attributionTag) {
3738         return verifyAndGetBypass(uid, packageName, attributionTag, null);
3739     }
3740 
3741     /**
3742      * @see #verifyAndGetBypass(int, String, String, String, boolean)
3743      */
verifyAndGetBypass(int uid, String packageName, @Nullable String attributionTag, @Nullable String proxyPackageName)3744     private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName,
3745             @Nullable String attributionTag, @Nullable String proxyPackageName) {
3746         return verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName, false);
3747     }
3748 
3749     /**
3750      * Verify that package belongs to uid and return the {@link RestrictionBypass bypass
3751      * description} for the package, along with a boolean indicating whether the attribution tag is
3752      * valid.
3753      *
3754      * @param uid The uid the package belongs to
3755      * @param packageName The package the might belong to the uid
3756      * @param attributionTag attribution tag or {@code null} if no need to verify
3757      * @param proxyPackageName The proxy package, from which the attribution tag is to be pulled
3758      * @param suppressErrorLogs Whether to print to logcat about nonmatching parameters
3759      *
3760      * @return PackageVerificationResult containing {@link RestrictionBypass} and whether the
3761      *         attribution tag is valid
3762      */
verifyAndGetBypass(int uid, String packageName, @Nullable String attributionTag, @Nullable String proxyPackageName, boolean suppressErrorLogs)3763     private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName,
3764             @Nullable String attributionTag, @Nullable String proxyPackageName,
3765             boolean suppressErrorLogs) {
3766         if (uid == Process.ROOT_UID) {
3767             // For backwards compatibility, don't check package name for root UID.
3768             return new PackageVerificationResult(null,
3769                     /* isAttributionTagValid */ true);
3770         }
3771         if (Process.isSdkSandboxUid(uid)) {
3772             // SDK sandbox processes run in their own UID range, but their associated
3773             // UID for checks should always be the UID of the package implementing SDK sandbox
3774             // service.
3775             // TODO: We will need to modify the callers of this function instead, so
3776             // modifications and checks against the app ops state are done with the
3777             // correct UID.
3778             try {
3779                 final PackageManager pm = mContext.getPackageManager();
3780                 final String supplementalPackageName = pm.getSdkSandboxPackageName();
3781                 if (Objects.equals(packageName, supplementalPackageName)) {
3782                     uid = pm.getPackageUidAsUser(supplementalPackageName,
3783                             PackageManager.PackageInfoFlags.of(0), UserHandle.getUserId(uid));
3784                 }
3785             } catch (PackageManager.NameNotFoundException e) {
3786                 // Shouldn't happen for the supplemental package
3787                 e.printStackTrace();
3788             }
3789         }
3790 
3791 
3792         // Do not check if uid/packageName/attributionTag is already known.
3793         synchronized (this) {
3794             UidState uidState = mUidStates.get(uid);
3795             if (uidState != null && !uidState.pkgOps.isEmpty()) {
3796                 Ops ops = uidState.pkgOps.get(packageName);
3797 
3798                 if (ops != null && (attributionTag == null || ops.knownAttributionTags.contains(
3799                         attributionTag)) && ops.bypass != null) {
3800                     return new PackageVerificationResult(ops.bypass,
3801                             ops.validAttributionTags.contains(attributionTag));
3802                 }
3803             }
3804         }
3805 
3806         int callingUid = Binder.getCallingUid();
3807 
3808         // Allow any attribution tag for resolvable uids
3809         int pkgUid;
3810         if (Objects.equals(packageName, "com.android.shell")) {
3811             // Special case for the shell which is a package but should be able
3812             // to bypass app attribution tag restrictions.
3813             pkgUid = Process.SHELL_UID;
3814         } else {
3815             pkgUid = resolveUid(packageName);
3816         }
3817         if (pkgUid != Process.INVALID_UID) {
3818             if (pkgUid != UserHandle.getAppId(uid)) {
3819                 if (!suppressErrorLogs) {
3820                     Slog.e(TAG, "Bad call made by uid " + callingUid + ". "
3821                             + "Package \"" + packageName + "\" does not belong to uid " + uid
3822                             + ".");
3823                 }
3824                 String otherUidMessage = DEBUG ? " but it is really " + pkgUid : " but it is not";
3825                 throw new SecurityException("Specified package \"" + packageName + "\" under uid "
3826                         +  UserHandle.getAppId(uid) + otherUidMessage);
3827             }
3828             return new PackageVerificationResult(RestrictionBypass.UNRESTRICTED,
3829                     /* isAttributionTagValid */ true);
3830         }
3831 
3832         int userId = UserHandle.getUserId(uid);
3833         RestrictionBypass bypass = null;
3834         boolean isAttributionTagValid = false;
3835 
3836         final long ident = Binder.clearCallingIdentity();
3837         try {
3838             PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
3839             var pkgState = pmInt.getPackageStateInternal(packageName);
3840             var pkg = pkgState == null ? null : pkgState.getAndroidPackage();
3841             if (pkg != null) {
3842                 isAttributionTagValid = isAttributionInPackage(pkg, attributionTag);
3843                 pkgUid = UserHandle.getUid(userId, pkgState.getAppId());
3844                 bypass = getBypassforPackage(pkgState);
3845             }
3846             if (!isAttributionTagValid) {
3847                 AndroidPackage proxyPkg = proxyPackageName != null
3848                         ? pmInt.getPackage(proxyPackageName) : null;
3849                 // Re-check in proxy.
3850                 isAttributionTagValid = isAttributionInPackage(proxyPkg, attributionTag);
3851                 String msg;
3852                 if (pkg != null && isAttributionTagValid) {
3853                     msg = "attributionTag " + attributionTag + " declared in manifest of the proxy"
3854                             + " package " + proxyPackageName + ", this is not advised";
3855                 } else if (pkg != null) {
3856                     msg = "attributionTag " + attributionTag + " not declared in manifest of "
3857                             + packageName;
3858                 } else {
3859                     msg = "package " + packageName + " not found, can't check for "
3860                             + "attributionTag " + attributionTag;
3861                 }
3862 
3863                 try {
3864                     if (!mPlatformCompat.isChangeEnabledByPackageName(
3865                             SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE, packageName,
3866                             userId) || !mPlatformCompat.isChangeEnabledByUid(
3867                                     SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE,
3868                             callingUid)) {
3869                         // Do not override tags if overriding is not enabled for this package
3870                         isAttributionTagValid = true;
3871                     }
3872                     Slog.e(TAG, msg);
3873                 } catch (RemoteException neverHappens) {
3874                 }
3875             }
3876         } finally {
3877             Binder.restoreCallingIdentity(ident);
3878         }
3879 
3880         if (pkgUid != uid) {
3881             if (!suppressErrorLogs) {
3882                 Slog.e(TAG, "Bad call made by uid " + callingUid + ". "
3883                         + "Package \"" + packageName + "\" does not belong to uid " + uid + ".");
3884             }
3885             String otherUidMessage = DEBUG ? " but it is really " + pkgUid : " but it is not";
3886             throw new SecurityException("Specified package \"" + packageName + "\" under uid " + uid
3887                     + otherUidMessage);
3888         }
3889 
3890         return new PackageVerificationResult(bypass, isAttributionTagValid);
3891     }
3892 
isAttributionInPackage(@ullable AndroidPackage pkg, @Nullable String attributionTag)3893     private boolean isAttributionInPackage(@Nullable AndroidPackage pkg,
3894             @Nullable String attributionTag) {
3895         if (pkg == null) {
3896             return false;
3897         } else if (attributionTag == null) {
3898             return true;
3899         }
3900         if (pkg.getAttributions() != null) {
3901             int numAttributions = pkg.getAttributions().size();
3902             for (int i = 0; i < numAttributions; i++) {
3903                 if (pkg.getAttributions().get(i).getTag().equals(attributionTag)) {
3904                     return true;
3905                 }
3906             }
3907         }
3908 
3909         return false;
3910     }
3911 
3912     /**
3913      * Get (and potentially create) ops.
3914      *
3915      * @param uid The uid the package belongs to
3916      * @param packageName The name of the package
3917      * @param attributionTag attribution tag
3918      * @param isAttributionTagValid whether the given attribution tag is valid
3919      * @param bypass When to bypass certain op restrictions (can be null if edit == false)
3920      * @param edit If an ops does not exist, create the ops?
3921 
3922      * @return The ops
3923      */
getOpsLocked(int uid, String packageName, @Nullable String attributionTag, boolean isAttributionTagValid, @Nullable RestrictionBypass bypass, boolean edit)3924     private Ops getOpsLocked(int uid, String packageName, @Nullable String attributionTag,
3925             boolean isAttributionTagValid, @Nullable RestrictionBypass bypass, boolean edit) {
3926         UidState uidState = getUidStateLocked(uid, edit);
3927         if (uidState == null) {
3928             return null;
3929         }
3930 
3931         Ops ops = uidState.pkgOps.get(packageName);
3932         if (ops == null) {
3933             if (!edit) {
3934                 return null;
3935             }
3936             ops = new Ops(packageName, uidState);
3937             uidState.pkgOps.put(packageName, ops);
3938         }
3939 
3940         if (edit) {
3941             if (bypass != null) {
3942                 ops.bypass = bypass;
3943             }
3944 
3945             if (attributionTag != null) {
3946                 ops.knownAttributionTags.add(attributionTag);
3947                 if (isAttributionTagValid) {
3948                     ops.validAttributionTags.add(attributionTag);
3949                 } else {
3950                     ops.validAttributionTags.remove(attributionTag);
3951                 }
3952             }
3953         }
3954 
3955         return ops;
3956     }
3957 
scheduleWriteLocked()3958     private void scheduleWriteLocked() {
3959         if (!mWriteScheduled) {
3960             mWriteScheduled = true;
3961             mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
3962         }
3963     }
3964 
scheduleFastWriteLocked()3965     private void scheduleFastWriteLocked() {
3966         if (!mFastWriteScheduled) {
3967             mWriteScheduled = true;
3968             mFastWriteScheduled = true;
3969             mHandler.removeCallbacks(mWriteRunner);
3970             mHandler.postDelayed(mWriteRunner, 10*1000);
3971         }
3972     }
3973 
3974     /**
3975      * Get the state of an op for a uid.
3976      *
3977      * @param code The code of the op
3978      * @param uid The uid the of the package
3979      * @param packageName The package name for which to get the state for
3980      * @param attributionTag The attribution tag
3981      * @param isAttributionTagValid Whether the given attribution tag is valid
3982      * @param bypass When to bypass certain op restrictions (can be null if edit == false)
3983      * @param edit Iff {@code true} create the {@link Op} object if not yet created
3984      *
3985      * @return The {@link Op state} of the op
3986      */
getOpLocked(int code, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean isAttributionTagValid, @Nullable RestrictionBypass bypass, boolean edit)3987     private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
3988             @Nullable String attributionTag, boolean isAttributionTagValid,
3989             @Nullable RestrictionBypass bypass, boolean edit) {
3990         Ops ops = getOpsLocked(uid, packageName, attributionTag, isAttributionTagValid, bypass,
3991                 edit);
3992         if (ops == null) {
3993             return null;
3994         }
3995         return getOpLocked(ops, code, uid, edit);
3996     }
3997 
getOpLocked(Ops ops, int code, int uid, boolean edit)3998     private Op getOpLocked(Ops ops, int code, int uid, boolean edit) {
3999         Op op = ops.get(code);
4000         if (op == null) {
4001             if (!edit) {
4002                 return null;
4003             }
4004             op = new Op(ops.uidState, ops.packageName, code, uid);
4005             ops.put(code, op);
4006         }
4007         if (edit) {
4008             scheduleWriteLocked();
4009         }
4010         return op;
4011     }
4012 
isOpRestrictedDueToSuspend(int code, String packageName, int uid)4013     private boolean isOpRestrictedDueToSuspend(int code, String packageName, int uid) {
4014         if (!ArrayUtils.contains(OPS_RESTRICTED_ON_SUSPEND, code)) {
4015             return false;
4016         }
4017         final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
4018         return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid));
4019     }
4020 
isOpRestrictedLocked(int uid, int code, String packageName, String attributionTag, @Nullable RestrictionBypass appBypass, boolean isCheckOp)4021     private boolean isOpRestrictedLocked(int uid, int code, String packageName,
4022             String attributionTag, @Nullable RestrictionBypass appBypass, boolean isCheckOp) {
4023         int restrictionSetCount = mOpGlobalRestrictions.size();
4024 
4025         for (int i = 0; i < restrictionSetCount; i++) {
4026             ClientGlobalRestrictionState restrictionState = mOpGlobalRestrictions.valueAt(i);
4027             if (restrictionState.hasRestriction(code)) {
4028                 return true;
4029             }
4030         }
4031 
4032         int userHandle = UserHandle.getUserId(uid);
4033         restrictionSetCount = mOpUserRestrictions.size();
4034 
4035         for (int i = 0; i < restrictionSetCount; i++) {
4036             // For each client, check that the given op is not restricted, or that the given
4037             // package is exempt from the restriction.
4038             ClientUserRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
4039             if (restrictionState.hasRestriction(code, packageName, attributionTag, userHandle,
4040                     isCheckOp)) {
4041                 RestrictionBypass opBypass = opAllowSystemBypassRestriction(code);
4042                 if (opBypass != null) {
4043                     // If we are the system, bypass user restrictions for certain codes
4044                     synchronized (this) {
4045                         if (opBypass.isSystemUid && appBypass != null && appBypass.isSystemUid) {
4046                             return false;
4047                         }
4048                         if (opBypass.isPrivileged && appBypass != null && appBypass.isPrivileged) {
4049                             return false;
4050                         }
4051                         if (opBypass.isRecordAudioRestrictionExcept && appBypass != null
4052                                 && appBypass.isRecordAudioRestrictionExcept) {
4053                             return false;
4054                         }
4055                     }
4056                 }
4057                 return true;
4058             }
4059         }
4060         return false;
4061     }
4062 
4063     /**
4064      * Read recent accesses from persistence (mRecentAccessesFile).
4065      * If there is no mRecentAccessesFile yet, we'll need migrate from mStorageFile: first read from
4066      * mStorageFile, then all subsequent reads/writes will use mRecentAccessesFile.
4067      * If neither file exists, there's nothing to migrate.
4068      */
readRecentAccesses()4069     private void readRecentAccesses() {
4070         if (!mRecentAccessesFile.exists()) {
4071             readRecentAccesses(mStorageFile);
4072         } else {
4073             readRecentAccesses(mRecentAccessesFile);
4074         }
4075     }
4076 
readRecentAccesses(AtomicFile file)4077     private void readRecentAccesses(AtomicFile file) {
4078         synchronized (file) {
4079             synchronized (this) {
4080                 FileInputStream stream;
4081                 try {
4082                     stream = file.openRead();
4083                 } catch (FileNotFoundException e) {
4084                     Slog.i(TAG, "No existing app ops " + file.getBaseFile() + "; starting empty");
4085                     return;
4086                 }
4087                 boolean success = false;
4088                 mUidStates.clear();
4089                 mAppOpsCheckingService.clearAllModes();
4090                 try {
4091                     TypedXmlPullParser parser = Xml.resolvePullParser(stream);
4092                     int type;
4093                     while ((type = parser.next()) != XmlPullParser.START_TAG
4094                             && type != XmlPullParser.END_DOCUMENT) {
4095                         // Parse next until we reach the start or end
4096                     }
4097 
4098                     if (type != XmlPullParser.START_TAG) {
4099                         throw new IllegalStateException("no start tag found");
4100                     }
4101 
4102                     int outerDepth = parser.getDepth();
4103                     while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4104                             && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4105                         if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4106                             continue;
4107                         }
4108 
4109                         String tagName = parser.getName();
4110                         if (tagName.equals("pkg")) {
4111                             readPackage(parser);
4112                         } else if (tagName.equals("uid")) {
4113                             // uid tag may be present during migration, don't print warning.
4114                             XmlUtils.skipCurrentTag(parser);
4115                         } else {
4116                             Slog.w(TAG, "Unknown element under <app-ops>: "
4117                                     + parser.getName());
4118                             XmlUtils.skipCurrentTag(parser);
4119                         }
4120                     }
4121 
4122                     success = true;
4123                 } catch (IllegalStateException e) {
4124                     Slog.w(TAG, "Failed parsing " + e);
4125                 } catch (NullPointerException e) {
4126                     Slog.w(TAG, "Failed parsing " + e);
4127                 } catch (NumberFormatException e) {
4128                     Slog.w(TAG, "Failed parsing " + e);
4129                 } catch (XmlPullParserException e) {
4130                     Slog.w(TAG, "Failed parsing " + e);
4131                 } catch (IOException e) {
4132                     Slog.w(TAG, "Failed parsing " + e);
4133                 } catch (IndexOutOfBoundsException e) {
4134                     Slog.w(TAG, "Failed parsing " + e);
4135                 } finally {
4136                     if (!success) {
4137                         mUidStates.clear();
4138                         mAppOpsCheckingService.clearAllModes();
4139                     }
4140                     try {
4141                         stream.close();
4142                     } catch (IOException e) {
4143                     }
4144                 }
4145             }
4146         }
4147     }
4148 
readPackage(TypedXmlPullParser parser)4149     private void readPackage(TypedXmlPullParser parser)
4150             throws NumberFormatException, XmlPullParserException, IOException {
4151         String pkgName = parser.getAttributeValue(null, "n");
4152         int outerDepth = parser.getDepth();
4153         int type;
4154         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4155                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4156             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4157                 continue;
4158             }
4159 
4160             String tagName = parser.getName();
4161             if (tagName.equals("uid")) {
4162                 readUid(parser, pkgName);
4163             } else {
4164                 Slog.w(TAG, "Unknown element under <pkg>: "
4165                         + parser.getName());
4166                 XmlUtils.skipCurrentTag(parser);
4167             }
4168         }
4169     }
4170 
readUid(TypedXmlPullParser parser, String pkgName)4171     private void readUid(TypedXmlPullParser parser, String pkgName)
4172             throws NumberFormatException, XmlPullParserException, IOException {
4173         int uid = parser.getAttributeInt(null, "n");
4174         final UidState uidState = getUidStateLocked(uid, true);
4175         int outerDepth = parser.getDepth();
4176         int type;
4177         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4178                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4179             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4180                 continue;
4181             }
4182             String tagName = parser.getName();
4183             if (tagName.equals("op")) {
4184                 readOp(parser, uidState, pkgName);
4185             } else {
4186                 Slog.w(TAG, "Unknown element under <pkg>: "
4187                         + parser.getName());
4188                 XmlUtils.skipCurrentTag(parser);
4189             }
4190         }
4191     }
4192 
readAttributionOp(TypedXmlPullParser parser, @NonNull Op parent, @Nullable String attribution)4193     private void readAttributionOp(TypedXmlPullParser parser, @NonNull Op parent,
4194             @Nullable String attribution)
4195             throws NumberFormatException, IOException, XmlPullParserException {
4196         final AttributedOp attributedOp = parent.getOrCreateAttribution(parent, attribution);
4197 
4198         final long key = parser.getAttributeLong(null, "n");
4199         final int uidState = extractUidStateFromKey(key);
4200         final int opFlags = extractFlagsFromKey(key);
4201 
4202         final long accessTime = parser.getAttributeLong(null, "t", 0);
4203         final long rejectTime = parser.getAttributeLong(null, "r", 0);
4204         final long accessDuration = parser.getAttributeLong(null, "d", -1);
4205         final String proxyPkg = XmlUtils.readStringAttribute(parser, "pp");
4206         final int proxyUid = parser.getAttributeInt(null, "pu", Process.INVALID_UID);
4207         final String proxyAttributionTag = XmlUtils.readStringAttribute(parser, "pc");
4208 
4209         if (accessTime > 0) {
4210             attributedOp.accessed(accessTime, accessDuration, proxyUid, proxyPkg,
4211                     proxyAttributionTag, uidState, opFlags);
4212         }
4213         if (rejectTime > 0) {
4214             attributedOp.rejected(rejectTime, uidState, opFlags);
4215         }
4216     }
4217 
readOp(TypedXmlPullParser parser, @NonNull UidState uidState, @NonNull String pkgName)4218     private void readOp(TypedXmlPullParser parser,
4219             @NonNull UidState uidState, @NonNull String pkgName)
4220             throws NumberFormatException, XmlPullParserException, IOException {
4221         int opCode = parser.getAttributeInt(null, "n");
4222         Op op = new Op(uidState, pkgName, opCode, uidState.uid);
4223 
4224         int outerDepth = parser.getDepth();
4225         int type;
4226         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4227                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4228             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4229                 continue;
4230             }
4231             String tagName = parser.getName();
4232             if (tagName.equals("st")) {
4233                 readAttributionOp(parser, op, XmlUtils.readStringAttribute(parser, "id"));
4234             } else {
4235                 Slog.w(TAG, "Unknown element under <op>: "
4236                         + parser.getName());
4237                 XmlUtils.skipCurrentTag(parser);
4238             }
4239         }
4240 
4241         Ops ops = uidState.pkgOps.get(pkgName);
4242         if (ops == null) {
4243             ops = new Ops(pkgName, uidState);
4244             uidState.pkgOps.put(pkgName, ops);
4245         }
4246         ops.put(op.op, op);
4247     }
4248 
4249     @VisibleForTesting
writeRecentAccesses()4250     void writeRecentAccesses() {
4251         synchronized (mRecentAccessesFile) {
4252             FileOutputStream stream;
4253             try {
4254                 stream = mRecentAccessesFile.startWrite();
4255             } catch (IOException e) {
4256                 Slog.w(TAG, "Failed to write state: " + e);
4257                 return;
4258             }
4259 
4260             List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
4261 
4262             try {
4263                 TypedXmlSerializer out = Xml.resolveSerializer(stream);
4264                 out.startDocument(null, true);
4265                 out.startTag(null, "app-ops");
4266                 out.attributeInt(null, "v", CURRENT_VERSION);
4267 
4268                 if (allOps != null) {
4269                     String lastPkg = null;
4270                     for (int i=0; i<allOps.size(); i++) {
4271                         AppOpsManager.PackageOps pkg = allOps.get(i);
4272                         if (!Objects.equals(pkg.getPackageName(), lastPkg)) {
4273                             if (lastPkg != null) {
4274                                 out.endTag(null, "pkg");
4275                             }
4276                             lastPkg = pkg.getPackageName();
4277                             if (lastPkg != null) {
4278                                 out.startTag(null, "pkg");
4279                                 out.attribute(null, "n", lastPkg);
4280                             }
4281                         }
4282                         out.startTag(null, "uid");
4283                         out.attributeInt(null, "n", pkg.getUid());
4284                         List<AppOpsManager.OpEntry> ops = pkg.getOps();
4285                         for (int j=0; j<ops.size(); j++) {
4286                             AppOpsManager.OpEntry op = ops.get(j);
4287                             out.startTag(null, "op");
4288                             out.attributeInt(null, "n", op.getOp());
4289                             if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
4290                                 out.attributeInt(null, "m", op.getMode());
4291                             }
4292 
4293                             for (String attributionTag : op.getAttributedOpEntries().keySet()) {
4294                                 final AttributedOpEntry attribution =
4295                                         op.getAttributedOpEntries().get(attributionTag);
4296 
4297                                 final ArraySet<Long> keys = attribution.collectKeys();
4298 
4299                                 final int keyCount = keys.size();
4300                                 for (int k = 0; k < keyCount; k++) {
4301                                     final long key = keys.valueAt(k);
4302 
4303                                     final int uidState = AppOpsManager.extractUidStateFromKey(key);
4304                                     final int flags = AppOpsManager.extractFlagsFromKey(key);
4305 
4306                                     final long accessTime = attribution.getLastAccessTime(uidState,
4307                                             uidState, flags);
4308                                     final long rejectTime = attribution.getLastRejectTime(uidState,
4309                                             uidState, flags);
4310                                     final long accessDuration = attribution.getLastDuration(
4311                                             uidState, uidState, flags);
4312                                     // Proxy information for rejections is not backed up
4313                                     final OpEventProxyInfo proxy = attribution.getLastProxyInfo(
4314                                             uidState, uidState, flags);
4315 
4316                                     if (accessTime <= 0 && rejectTime <= 0 && accessDuration <= 0
4317                                             && proxy == null) {
4318                                         continue;
4319                                     }
4320 
4321                                     String proxyPkg = null;
4322                                     String proxyAttributionTag = null;
4323                                     int proxyUid = Process.INVALID_UID;
4324                                     if (proxy != null) {
4325                                         proxyPkg = proxy.getPackageName();
4326                                         proxyAttributionTag = proxy.getAttributionTag();
4327                                         proxyUid = proxy.getUid();
4328                                     }
4329 
4330                                     out.startTag(null, "st");
4331                                     if (attributionTag != null) {
4332                                         out.attribute(null, "id", attributionTag);
4333                                     }
4334                                     out.attributeLong(null, "n", key);
4335                                     if (accessTime > 0) {
4336                                         out.attributeLong(null, "t", accessTime);
4337                                     }
4338                                     if (rejectTime > 0) {
4339                                         out.attributeLong(null, "r", rejectTime);
4340                                     }
4341                                     if (accessDuration > 0) {
4342                                         out.attributeLong(null, "d", accessDuration);
4343                                     }
4344                                     if (proxyPkg != null) {
4345                                         out.attribute(null, "pp", proxyPkg);
4346                                     }
4347                                     if (proxyAttributionTag != null) {
4348                                         out.attribute(null, "pc", proxyAttributionTag);
4349                                     }
4350                                     if (proxyUid >= 0) {
4351                                         out.attributeInt(null, "pu", proxyUid);
4352                                     }
4353                                     out.endTag(null, "st");
4354                                 }
4355                             }
4356 
4357                             out.endTag(null, "op");
4358                         }
4359                         out.endTag(null, "uid");
4360                     }
4361                     if (lastPkg != null) {
4362                         out.endTag(null, "pkg");
4363                     }
4364                 }
4365 
4366                 out.endTag(null, "app-ops");
4367                 out.endDocument();
4368                 mRecentAccessesFile.finishWrite(stream);
4369             } catch (IOException e) {
4370                 Slog.w(TAG, "Failed to write state, restoring backup.", e);
4371                 mRecentAccessesFile.failWrite(stream);
4372             }
4373         }
4374         mHistoricalRegistry.writeAndClearDiscreteHistory();
4375     }
4376 
4377     static class Shell extends ShellCommand {
4378         final IAppOpsService mInterface;
4379         final AppOpsService mInternal;
4380 
4381         int userId = UserHandle.USER_SYSTEM;
4382         String packageName;
4383         String attributionTag;
4384         String opStr;
4385         String modeStr;
4386         int op;
4387         int mode;
4388         int packageUid;
4389         int nonpackageUid;
4390         final static Binder sBinder = new Binder();
4391         IBinder mToken;
4392         boolean targetsUid;
4393 
Shell(IAppOpsService iface, AppOpsService internal)4394         Shell(IAppOpsService iface, AppOpsService internal) {
4395             mInterface = iface;
4396             mInternal = internal;
4397             mToken = AppOpsManager.getClientId();
4398         }
4399 
4400         @Override
onCommand(String cmd)4401         public int onCommand(String cmd) {
4402             return onShellCommand(this, cmd);
4403         }
4404 
4405         @Override
onHelp()4406         public void onHelp() {
4407             PrintWriter pw = getOutPrintWriter();
4408             dumpCommandHelp(pw);
4409         }
4410 
strOpToOp(String op, PrintWriter err)4411         static private int strOpToOp(String op, PrintWriter err) {
4412             try {
4413                 return AppOpsManager.strOpToOp(op);
4414             } catch (IllegalArgumentException e) {
4415             }
4416             try {
4417                 return Integer.parseInt(op);
4418             } catch (NumberFormatException e) {
4419             }
4420             try {
4421                 return AppOpsManager.strDebugOpToOp(op);
4422             } catch (IllegalArgumentException e) {
4423                 err.println("Error: " + e.getMessage());
4424                 return -1;
4425             }
4426         }
4427 
strModeToMode(String modeStr, PrintWriter err)4428         static int strModeToMode(String modeStr, PrintWriter err) {
4429             for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
4430                 if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
4431                     return i;
4432                 }
4433             }
4434             try {
4435                 return Integer.parseInt(modeStr);
4436             } catch (NumberFormatException e) {
4437             }
4438             err.println("Error: Mode " + modeStr + " is not valid");
4439             return -1;
4440         }
4441 
parseUserOpMode(int defMode, PrintWriter err)4442         int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
4443             userId = UserHandle.USER_CURRENT;
4444             opStr = null;
4445             modeStr = null;
4446             for (String argument; (argument = getNextArg()) != null;) {
4447                 if ("--user".equals(argument)) {
4448                     userId = UserHandle.parseUserArg(getNextArgRequired());
4449                 } else {
4450                     if (opStr == null) {
4451                         opStr = argument;
4452                     } else if (modeStr == null) {
4453                         modeStr = argument;
4454                         break;
4455                     }
4456                 }
4457             }
4458             if (opStr == null) {
4459                 err.println("Error: Operation not specified.");
4460                 return -1;
4461             }
4462             op = strOpToOp(opStr, err);
4463             if (op < 0) {
4464                 return -1;
4465             }
4466             if (modeStr != null) {
4467                 if ((mode=strModeToMode(modeStr, err)) < 0) {
4468                     return -1;
4469                 }
4470             } else {
4471                 mode = defMode;
4472             }
4473             return 0;
4474         }
4475 
parseUserPackageOp(boolean reqOp, PrintWriter err)4476         int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
4477             userId = UserHandle.USER_CURRENT;
4478             packageName = null;
4479             opStr = null;
4480             for (String argument; (argument = getNextArg()) != null;) {
4481                 if ("--user".equals(argument)) {
4482                     userId = UserHandle.parseUserArg(getNextArgRequired());
4483                 } else if ("--uid".equals(argument)) {
4484                     targetsUid = true;
4485                 } else if ("--attribution".equals(argument)) {
4486                     attributionTag = getNextArgRequired();
4487                 } else {
4488                     if (packageName == null) {
4489                         packageName = argument;
4490                     } else if (opStr == null) {
4491                         opStr = argument;
4492                         break;
4493                     }
4494                 }
4495             }
4496             if (packageName == null) {
4497                 err.println("Error: Package name not specified.");
4498                 return -1;
4499             } else if (opStr == null && reqOp) {
4500                 err.println("Error: Operation not specified.");
4501                 return -1;
4502             }
4503             if (opStr != null) {
4504                 op = strOpToOp(opStr, err);
4505                 if (op < 0) {
4506                     return -1;
4507                 }
4508             } else {
4509                 op = AppOpsManager.OP_NONE;
4510             }
4511             if (userId == UserHandle.USER_CURRENT) {
4512                 userId = ActivityManager.getCurrentUser();
4513             }
4514             nonpackageUid = -1;
4515             try {
4516                 nonpackageUid = Integer.parseInt(packageName);
4517             } catch (NumberFormatException e) {
4518             }
4519             if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
4520                     && packageName.indexOf('.') < 0) {
4521                 int i = 1;
4522                 while (i < packageName.length() && packageName.charAt(i) >= '0'
4523                         && packageName.charAt(i) <= '9') {
4524                     i++;
4525                 }
4526                 if (i > 1 && i < packageName.length()) {
4527                     String userStr = packageName.substring(1, i);
4528                     try {
4529                         int user = Integer.parseInt(userStr);
4530                         char type = packageName.charAt(i);
4531                         i++;
4532                         int startTypeVal = i;
4533                         while (i < packageName.length() && packageName.charAt(i) >= '0'
4534                                 && packageName.charAt(i) <= '9') {
4535                             i++;
4536                         }
4537                         if (i > startTypeVal) {
4538                             String typeValStr = packageName.substring(startTypeVal, i);
4539                             try {
4540                                 int typeVal = Integer.parseInt(typeValStr);
4541                                 if (type == 'a') {
4542                                     nonpackageUid = UserHandle.getUid(user,
4543                                             typeVal + Process.FIRST_APPLICATION_UID);
4544                                 } else if (type == 's') {
4545                                     nonpackageUid = UserHandle.getUid(user, typeVal);
4546                                 }
4547                             } catch (NumberFormatException e) {
4548                             }
4549                         }
4550                     } catch (NumberFormatException e) {
4551                     }
4552                 }
4553             }
4554             if (nonpackageUid != -1) {
4555                 packageName = null;
4556             } else {
4557                 packageUid = resolveUid(packageName);
4558                 if (packageUid < 0) {
4559                     packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
4560                             PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
4561                 }
4562                 if (packageUid < 0) {
4563                     err.println("Error: No UID for " + packageName + " in user " + userId);
4564                     return -1;
4565                 }
4566             }
4567             return 0;
4568         }
4569     }
4570 
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)4571     @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
4572             FileDescriptor err, String[] args, ShellCallback callback,
4573             ResultReceiver resultReceiver) {
4574         (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
4575     }
4576 
dumpCommandHelp(PrintWriter pw)4577     static void dumpCommandHelp(PrintWriter pw) {
4578         pw.println("AppOps service (appops) commands:");
4579         pw.println("  help");
4580         pw.println("    Print this help text.");
4581         pw.println("  start [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> "
4582                 + "<OP> ");
4583         pw.println("    Starts a given operation for a particular application.");
4584         pw.println("  stop [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> "
4585                 + "<OP> ");
4586         pw.println("    Stops a given operation for a particular application.");
4587         pw.println("  set [--user <USER_ID>] <[--uid] PACKAGE | UID> <OP> <MODE>");
4588         pw.println("    Set the mode for a particular application and operation.");
4589         pw.println("  get [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> "
4590                 + "[<OP>]");
4591         pw.println("    Return the mode for a particular application and optional operation.");
4592         pw.println("  query-op [--user <USER_ID>] <OP> [<MODE>]");
4593         pw.println("    Print all packages that currently have the given op in the given mode.");
4594         pw.println("  reset [--user <USER_ID>] [<PACKAGE>]");
4595         pw.println("    Reset the given application or all applications to default modes.");
4596         pw.println("  write-settings");
4597         pw.println("    Immediately write pending changes to storage.");
4598         pw.println("  read-settings");
4599         pw.println("    Read the last written settings, replacing current state in RAM.");
4600         pw.println("  options:");
4601         pw.println("    <PACKAGE> an Android package name or its UID if prefixed by --uid");
4602         pw.println("    <OP>      an AppOps operation.");
4603         pw.println("    <MODE>    one of allow, ignore, deny, or default");
4604         pw.println("    <USER_ID> the user id under which the package is installed. If --user is");
4605         pw.println("              not specified, the current user is assumed.");
4606     }
4607 
onShellCommand(Shell shell, String cmd)4608     static int onShellCommand(Shell shell, String cmd) {
4609         if (cmd == null) {
4610             return shell.handleDefaultCommands(cmd);
4611         }
4612         PrintWriter pw = shell.getOutPrintWriter();
4613         PrintWriter err = shell.getErrPrintWriter();
4614         try {
4615             switch (cmd) {
4616                 case "set": {
4617                     int res = shell.parseUserPackageOp(true, err);
4618                     if (res < 0) {
4619                         return res;
4620                     }
4621                     String modeStr = shell.getNextArg();
4622                     if (modeStr == null) {
4623                         err.println("Error: Mode not specified.");
4624                         return -1;
4625                     }
4626 
4627                     final int mode = shell.strModeToMode(modeStr, err);
4628                     if (mode < 0) {
4629                         return -1;
4630                     }
4631 
4632                     if (!shell.targetsUid && shell.packageName != null) {
4633                         shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
4634                                 mode);
4635                     } else if (shell.targetsUid && shell.packageName != null) {
4636                         try {
4637                             final int uid = shell.mInternal.mContext.getPackageManager()
4638                                     .getPackageUidAsUser(shell.packageName, shell.userId);
4639                             shell.mInterface.setUidMode(shell.op, uid, mode);
4640                         } catch (PackageManager.NameNotFoundException e) {
4641                             return -1;
4642                         }
4643                     } else {
4644                         shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
4645                     }
4646                     return 0;
4647                 }
4648                 case "get": {
4649                     int res = shell.parseUserPackageOp(false, err);
4650                     if (res < 0) {
4651                         return res;
4652                     }
4653 
4654                     List<AppOpsManager.PackageOps> ops = new ArrayList<>();
4655                     if (shell.packageName != null) {
4656                         // Uid mode overrides package mode, so make sure it's also reported
4657                         List<AppOpsManager.PackageOps> r = shell.mInterface.getUidOps(
4658                                 shell.packageUid,
4659                                 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
4660                         if (r != null) {
4661                             ops.addAll(r);
4662                         }
4663                         r = shell.mInterface.getOpsForPackage(
4664                                 shell.packageUid, shell.packageName,
4665                                 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
4666                         if (r != null) {
4667                             ops.addAll(r);
4668                         }
4669                     } else {
4670                         ops = shell.mInterface.getUidOps(
4671                                 shell.nonpackageUid,
4672                                 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
4673                     }
4674                     if (ops == null || ops.size() <= 0) {
4675                         pw.println("No operations.");
4676                         if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
4677                             pw.println("Default mode: " + AppOpsManager.modeToName(
4678                                     AppOpsManager.opToDefaultMode(shell.op)));
4679                         }
4680                         return 0;
4681                     }
4682                     final long now = System.currentTimeMillis();
4683                     for (int i=0; i<ops.size(); i++) {
4684                         AppOpsManager.PackageOps packageOps = ops.get(i);
4685                         if (packageOps.getPackageName() == null) {
4686                             pw.print("Uid mode: ");
4687                         }
4688                         List<AppOpsManager.OpEntry> entries = packageOps.getOps();
4689                         for (int j=0; j<entries.size(); j++) {
4690                             AppOpsManager.OpEntry ent = entries.get(j);
4691                             pw.print(AppOpsManager.opToName(ent.getOp()));
4692                             pw.print(": ");
4693                             pw.print(AppOpsManager.modeToName(ent.getMode()));
4694                             if (shell.attributionTag == null) {
4695                                 if (ent.getLastAccessTime(OP_FLAGS_ALL) != -1) {
4696                                     pw.print("; time=");
4697                                     TimeUtils.formatDuration(
4698                                             now - ent.getLastAccessTime(OP_FLAGS_ALL), pw);
4699                                     pw.print(" ago");
4700                                 }
4701                                 if (ent.getLastRejectTime(OP_FLAGS_ALL) != -1) {
4702                                     pw.print("; rejectTime=");
4703                                     TimeUtils.formatDuration(
4704                                             now - ent.getLastRejectTime(OP_FLAGS_ALL), pw);
4705                                     pw.print(" ago");
4706                                 }
4707                                 if (ent.isRunning()) {
4708                                     pw.print(" (running)");
4709                                 } else if (ent.getLastDuration(OP_FLAGS_ALL) != -1) {
4710                                     pw.print("; duration=");
4711                                     TimeUtils.formatDuration(ent.getLastDuration(OP_FLAGS_ALL), pw);
4712                                 }
4713                             } else {
4714                                 final AppOpsManager.AttributedOpEntry attributionEnt =
4715                                         ent.getAttributedOpEntries().get(shell.attributionTag);
4716                                 if (attributionEnt != null) {
4717                                     if (attributionEnt.getLastAccessTime(OP_FLAGS_ALL) != -1) {
4718                                         pw.print("; time=");
4719                                         TimeUtils.formatDuration(
4720                                                 now - attributionEnt.getLastAccessTime(
4721                                                         OP_FLAGS_ALL), pw);
4722                                         pw.print(" ago");
4723                                     }
4724                                     if (attributionEnt.getLastRejectTime(OP_FLAGS_ALL) != -1) {
4725                                         pw.print("; rejectTime=");
4726                                         TimeUtils.formatDuration(
4727                                                 now - attributionEnt.getLastRejectTime(
4728                                                         OP_FLAGS_ALL), pw);
4729                                         pw.print(" ago");
4730                                     }
4731                                     if (attributionEnt.isRunning()) {
4732                                         pw.print(" (running)");
4733                                     } else if (attributionEnt.getLastDuration(OP_FLAGS_ALL)
4734                                             != -1) {
4735                                         pw.print("; duration=");
4736                                         TimeUtils.formatDuration(
4737                                                 attributionEnt.getLastDuration(OP_FLAGS_ALL), pw);
4738                                     }
4739                                 }
4740                             }
4741                             pw.println();
4742                         }
4743                     }
4744                     return 0;
4745                 }
4746                 case "query-op": {
4747                     int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
4748                     if (res < 0) {
4749                         return res;
4750                     }
4751                     List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
4752                             new int[] {shell.op});
4753                     if (ops == null || ops.size() <= 0) {
4754                         pw.println("No operations.");
4755                         return 0;
4756                     }
4757                     for (int i=0; i<ops.size(); i++) {
4758                         final AppOpsManager.PackageOps pkg = ops.get(i);
4759                         boolean hasMatch = false;
4760                         final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
4761                         for (int j=0; j<entries.size(); j++) {
4762                             AppOpsManager.OpEntry ent = entries.get(j);
4763                             if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
4764                                 hasMatch = true;
4765                                 break;
4766                             }
4767                         }
4768                         if (hasMatch) {
4769                             pw.println(pkg.getPackageName());
4770                         }
4771                     }
4772                     return 0;
4773                 }
4774                 case "reset": {
4775                     String packageName = null;
4776                     int userId = UserHandle.USER_CURRENT;
4777                     for (String argument; (argument = shell.getNextArg()) != null;) {
4778                         if ("--user".equals(argument)) {
4779                             String userStr = shell.getNextArgRequired();
4780                             userId = UserHandle.parseUserArg(userStr);
4781                         } else {
4782                             if (packageName == null) {
4783                                 packageName = argument;
4784                             } else {
4785                                 err.println("Error: Unsupported argument: " + argument);
4786                                 return -1;
4787                             }
4788                         }
4789                     }
4790 
4791                     if (userId == UserHandle.USER_CURRENT) {
4792                         userId = ActivityManager.getCurrentUser();
4793                     }
4794 
4795                     shell.mInterface.resetAllModes(userId, packageName);
4796                     pw.print("Reset all modes for: ");
4797                     if (userId == UserHandle.USER_ALL) {
4798                         pw.print("all users");
4799                     } else {
4800                         pw.print("user "); pw.print(userId);
4801                     }
4802                     pw.print(", ");
4803                     if (packageName == null) {
4804                         pw.println("all packages");
4805                     } else {
4806                         pw.print("package "); pw.println(packageName);
4807                     }
4808                     return 0;
4809                 }
4810                 case "write-settings": {
4811                     shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
4812                             Binder.getCallingUid(), -1);
4813                     final long token = Binder.clearCallingIdentity();
4814                     try {
4815                         synchronized (shell.mInternal) {
4816                             shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
4817                         }
4818                         shell.mInternal.writeRecentAccesses();
4819                         shell.mInternal.mAppOpsCheckingService.writeState();
4820                         pw.println("Current settings written.");
4821                     } finally {
4822                         Binder.restoreCallingIdentity(token);
4823                     }
4824                     return 0;
4825                 }
4826                 case "read-settings": {
4827                     shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
4828                             Binder.getCallingUid(), -1);
4829                     final long token = Binder.clearCallingIdentity();
4830                     try {
4831                         shell.mInternal.readRecentAccesses();
4832                         shell.mInternal.mAppOpsCheckingService.readState();
4833                         pw.println("Last settings read.");
4834                     } finally {
4835                         Binder.restoreCallingIdentity(token);
4836                     }
4837                     return 0;
4838                 }
4839                 case "start": {
4840                     int res = shell.parseUserPackageOp(true, err);
4841                     if (res < 0) {
4842                         return res;
4843                     }
4844 
4845                     if (shell.packageName != null) {
4846                         shell.mInterface.startOperation(shell.mToken, shell.op, shell.packageUid,
4847                                 shell.packageName, shell.attributionTag, true, true,
4848                                 "appops start shell command", true,
4849                                 AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR, ATTRIBUTION_CHAIN_ID_NONE);
4850                     } else {
4851                         return -1;
4852                     }
4853                     return 0;
4854                 }
4855                 case "stop": {
4856                     int res = shell.parseUserPackageOp(true, err);
4857                     if (res < 0) {
4858                         return res;
4859                     }
4860 
4861                     if (shell.packageName != null) {
4862                         shell.mInterface.finishOperation(shell.mToken, shell.op, shell.packageUid,
4863                                 shell.packageName, shell.attributionTag);
4864                     } else {
4865                         return -1;
4866                     }
4867                     return 0;
4868                 }
4869                 default:
4870                     return shell.handleDefaultCommands(cmd);
4871             }
4872         } catch (RemoteException e) {
4873             pw.println("Remote exception: " + e);
4874         }
4875         return -1;
4876     }
4877 
dumpHelp(PrintWriter pw)4878     private void dumpHelp(PrintWriter pw) {
4879         pw.println("AppOps service (appops) dump options:");
4880         pw.println("  -h");
4881         pw.println("    Print this help text.");
4882         pw.println("  --op [OP]");
4883         pw.println("    Limit output to data associated with the given app op code.");
4884         pw.println("  --mode [MODE]");
4885         pw.println("    Limit output to data associated with the given app op mode.");
4886         pw.println("  --package [PACKAGE]");
4887         pw.println("    Limit output to data associated with the given package name.");
4888         pw.println("  --attributionTag [attributionTag]");
4889         pw.println("    Limit output to data associated with the given attribution tag.");
4890         pw.println("  --include-discrete [n]");
4891         pw.println("    Include discrete ops limited to n per dimension. Use zero for no limit.");
4892         pw.println("  --watchers");
4893         pw.println("    Only output the watcher sections.");
4894         pw.println("  --history");
4895         pw.println("    Only output history.");
4896         pw.println("  --uid-state-changes");
4897         pw.println("    Include logs about uid state changes.");
4898     }
4899 
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)4900     private void dumpStatesLocked(@NonNull PrintWriter pw, @Nullable String filterAttributionTag,
4901             @HistoricalOpsRequestFilter int filter, long nowElapsed, @NonNull Op op, long now,
4902             @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix) {
4903         final int numAttributions = op.mAttributions.size();
4904         for (int i = 0; i < numAttributions; i++) {
4905             if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !Objects.equals(
4906                     op.mAttributions.keyAt(i), filterAttributionTag)) {
4907                 continue;
4908             }
4909 
4910             pw.print(prefix + op.mAttributions.keyAt(i) + "=[\n");
4911             dumpStatesLocked(pw, nowElapsed, op, op.mAttributions.keyAt(i), now, sdf, date,
4912                     prefix + "  ");
4913             pw.print(prefix + "]\n");
4914         }
4915     }
4916 
dumpStatesLocked(@onNull PrintWriter pw, long nowElapsed, @NonNull Op op, @Nullable String attributionTag, long now, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix)4917     private void dumpStatesLocked(@NonNull PrintWriter pw, long nowElapsed, @NonNull Op op,
4918             @Nullable String attributionTag, long now, @NonNull SimpleDateFormat sdf,
4919             @NonNull Date date, @NonNull String prefix) {
4920 
4921         final AttributedOpEntry entry = op.createSingleAttributionEntryLocked(
4922                 attributionTag).getAttributedOpEntries().get(attributionTag);
4923 
4924         final ArraySet<Long> keys = entry.collectKeys();
4925 
4926         final int keyCount = keys.size();
4927         for (int k = 0; k < keyCount; k++) {
4928             final long key = keys.valueAt(k);
4929 
4930             final int uidState = AppOpsManager.extractUidStateFromKey(key);
4931             final int flags = AppOpsManager.extractFlagsFromKey(key);
4932 
4933             final long accessTime = entry.getLastAccessTime(uidState, uidState, flags);
4934             final long rejectTime = entry.getLastRejectTime(uidState, uidState, flags);
4935             final long accessDuration = entry.getLastDuration(uidState, uidState, flags);
4936             final OpEventProxyInfo proxy = entry.getLastProxyInfo(uidState, uidState, flags);
4937 
4938             String proxyPkg = null;
4939             String proxyAttributionTag = null;
4940             int proxyUid = Process.INVALID_UID;
4941             if (proxy != null) {
4942                 proxyPkg = proxy.getPackageName();
4943                 proxyAttributionTag = proxy.getAttributionTag();
4944                 proxyUid = proxy.getUid();
4945             }
4946 
4947             if (accessTime > 0) {
4948                 pw.print(prefix);
4949                 pw.print("Access: ");
4950                 pw.print(AppOpsManager.keyToString(key));
4951                 pw.print(" ");
4952                 date.setTime(accessTime);
4953                 pw.print(sdf.format(date));
4954                 pw.print(" (");
4955                 TimeUtils.formatDuration(accessTime - now, pw);
4956                 pw.print(")");
4957                 if (accessDuration > 0) {
4958                     pw.print(" duration=");
4959                     TimeUtils.formatDuration(accessDuration, pw);
4960                 }
4961                 if (proxyUid >= 0) {
4962                     pw.print(" proxy[");
4963                     pw.print("uid=");
4964                     pw.print(proxyUid);
4965                     pw.print(", pkg=");
4966                     pw.print(proxyPkg);
4967                     pw.print(", attributionTag=");
4968                     pw.print(proxyAttributionTag);
4969                     pw.print("]");
4970                 }
4971                 pw.println();
4972             }
4973 
4974             if (rejectTime > 0) {
4975                 pw.print(prefix);
4976                 pw.print("Reject: ");
4977                 pw.print(AppOpsManager.keyToString(key));
4978                 date.setTime(rejectTime);
4979                 pw.print(sdf.format(date));
4980                 pw.print(" (");
4981                 TimeUtils.formatDuration(rejectTime - now, pw);
4982                 pw.print(")");
4983                 if (proxyUid >= 0) {
4984                     pw.print(" proxy[");
4985                     pw.print("uid=");
4986                     pw.print(proxyUid);
4987                     pw.print(", pkg=");
4988                     pw.print(proxyPkg);
4989                     pw.print(", attributionTag=");
4990                     pw.print(proxyAttributionTag);
4991                     pw.print("]");
4992                 }
4993                 pw.println();
4994             }
4995         }
4996 
4997         final AttributedOp attributedOp = op.mAttributions.get(attributionTag);
4998         if (attributedOp.isRunning()) {
4999             long earliestElapsedTime = Long.MAX_VALUE;
5000             long maxNumStarts = 0;
5001             int numInProgressEvents = attributedOp.mInProgressEvents.size();
5002             for (int i = 0; i < numInProgressEvents; i++) {
5003                 AttributedOp.InProgressStartOpEvent event =
5004                         attributedOp.mInProgressEvents.valueAt(i);
5005 
5006                 earliestElapsedTime = Math.min(earliestElapsedTime, event.getStartElapsedTime());
5007                 maxNumStarts = Math.max(maxNumStarts, event.mNumUnfinishedStarts);
5008             }
5009 
5010             pw.print(prefix + "Running start at: ");
5011             TimeUtils.formatDuration(nowElapsed - earliestElapsedTime, pw);
5012             pw.println();
5013 
5014             if (maxNumStarts > 1) {
5015                 pw.print(prefix + "startNesting=");
5016                 pw.println(maxNumStarts);
5017             }
5018         }
5019     }
5020 
5021     @NeverCompile // Avoid size overhead of debugging code.
5022     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)5023     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
5024         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
5025 
5026         int dumpOp = OP_NONE;
5027         String dumpPackage = null;
5028         String dumpAttributionTag = null;
5029         int dumpUid = Process.INVALID_UID;
5030         int dumpMode = -1;
5031         boolean dumpWatchers = false;
5032         // TODO ntmyren: Remove the dumpHistory and dumpFilter
5033         boolean dumpHistory = false;
5034         boolean includeDiscreteOps = false;
5035         boolean dumpUidStateChangeLogs = false;
5036         int nDiscreteOps = 10;
5037         @HistoricalOpsRequestFilter int dumpFilter = 0;
5038         boolean dumpAll = false;
5039 
5040         if (args != null) {
5041             for (int i = 0; i < args.length; i++) {
5042                 String arg = args[i];
5043                 if ("-h".equals(arg)) {
5044                     dumpHelp(pw);
5045                     return;
5046                 } else if ("-a".equals(arg)) {
5047                     // dump all data
5048                     dumpAll = true;
5049                 } else if ("--op".equals(arg)) {
5050                     i++;
5051                     if (i >= args.length) {
5052                         pw.println("No argument for --op option");
5053                         return;
5054                     }
5055                     dumpOp = Shell.strOpToOp(args[i], pw);
5056                     dumpFilter |= FILTER_BY_OP_NAMES;
5057                     if (dumpOp < 0) {
5058                         return;
5059                     }
5060                 } else if ("--package".equals(arg)) {
5061                     i++;
5062                     if (i >= args.length) {
5063                         pw.println("No argument for --package option");
5064                         return;
5065                     }
5066                     dumpPackage = args[i];
5067                     dumpFilter |= FILTER_BY_PACKAGE_NAME;
5068                     try {
5069                         dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
5070                                 PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
5071                                 0);
5072                     } catch (RemoteException e) {
5073                     }
5074                     if (dumpUid < 0) {
5075                         pw.println("Unknown package: " + dumpPackage);
5076                         return;
5077                     }
5078                     dumpUid = UserHandle.getAppId(dumpUid);
5079                     dumpFilter |= FILTER_BY_UID;
5080                 } else if ("--attributionTag".equals(arg)) {
5081                     i++;
5082                     if (i >= args.length) {
5083                         pw.println("No argument for --attributionTag option");
5084                         return;
5085                     }
5086                     dumpAttributionTag = args[i];
5087                     dumpFilter |= FILTER_BY_ATTRIBUTION_TAG;
5088                 } else if ("--mode".equals(arg)) {
5089                     i++;
5090                     if (i >= args.length) {
5091                         pw.println("No argument for --mode option");
5092                         return;
5093                     }
5094                     dumpMode = Shell.strModeToMode(args[i], pw);
5095                     if (dumpMode < 0) {
5096                         return;
5097                     }
5098                 } else if ("--watchers".equals(arg)) {
5099                     dumpWatchers = true;
5100                 } else if ("--include-discrete".equals(arg)) {
5101                     i++;
5102                     if (i >= args.length) {
5103                         pw.println("No argument for --include-discrete option");
5104                         return;
5105                     }
5106                     try {
5107                         nDiscreteOps = Integer.valueOf(args[i]);
5108                     } catch (NumberFormatException e) {
5109                         pw.println("Wrong parameter: " + args[i]);
5110                         return;
5111                     }
5112                     includeDiscreteOps = true;
5113                 } else if ("--history".equals(arg)) {
5114                     dumpHistory = true;
5115                 } else if (arg.length() > 0 && arg.charAt(0) == '-') {
5116                     pw.println("Unknown option: " + arg);
5117                     return;
5118                 } else if ("--uid-state-changes".equals(arg)) {
5119                     dumpUidStateChangeLogs = true;
5120                 } else {
5121                     pw.println("Unknown command: " + arg);
5122                     return;
5123                 }
5124             }
5125         }
5126 
5127         final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
5128         final Date date = new Date();
5129         synchronized (this) {
5130             pw.println("Current AppOps Service state:");
5131             if (!dumpHistory && !dumpWatchers) {
5132                 mConstants.dump(pw);
5133             }
5134             pw.println();
5135             final long now = System.currentTimeMillis();
5136             final long nowElapsed = SystemClock.elapsedRealtime();
5137             final long nowUptime = SystemClock.uptimeMillis();
5138             boolean needSep = false;
5139             if (dumpFilter == 0 && dumpMode < 0 && mProfileOwners != null && !dumpWatchers
5140                     && !dumpHistory) {
5141                 pw.println("  Profile owners:");
5142                 for (int poi = 0; poi < mProfileOwners.size(); poi++) {
5143                     pw.print("    User #");
5144                     pw.print(mProfileOwners.keyAt(poi));
5145                     pw.print(": ");
5146                     UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
5147                     pw.println();
5148                 }
5149                 pw.println();
5150             }
5151 
5152             if (!dumpHistory) {
5153                 needSep |= mAppOpsCheckingService.dumpListeners(dumpOp, dumpUid, dumpPackage, pw);
5154             }
5155 
5156             if (mModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
5157                 boolean printedHeader = false;
5158                 for (int i = 0; i < mModeWatchers.size(); i++) {
5159                     final ModeCallback cb = mModeWatchers.valueAt(i);
5160                     if (dumpPackage != null
5161                             && dumpUid != UserHandle.getAppId(cb.getWatchingUid())) {
5162                         continue;
5163                     }
5164                     needSep = true;
5165                     if (!printedHeader) {
5166                         pw.println("  All op mode watchers:");
5167                         printedHeader = true;
5168                     }
5169                     pw.print("    ");
5170                     pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
5171                     pw.print(": "); pw.println(cb);
5172                 }
5173             }
5174             if (mActiveWatchers.size() > 0 && dumpMode < 0) {
5175                 needSep = true;
5176                 boolean printedHeader = false;
5177                 for (int watcherNum = 0; watcherNum < mActiveWatchers.size(); watcherNum++) {
5178                     final SparseArray<ActiveCallback> activeWatchers =
5179                             mActiveWatchers.valueAt(watcherNum);
5180                     if (activeWatchers.size() <= 0) {
5181                         continue;
5182                     }
5183                     final ActiveCallback cb = activeWatchers.valueAt(0);
5184                     if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
5185                         continue;
5186                     }
5187                     if (dumpPackage != null
5188                             && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
5189                         continue;
5190                     }
5191                     if (!printedHeader) {
5192                         pw.println("  All op active watchers:");
5193                         printedHeader = true;
5194                     }
5195                     pw.print("    ");
5196                     pw.print(Integer.toHexString(System.identityHashCode(
5197                             mActiveWatchers.keyAt(watcherNum))));
5198                     pw.println(" ->");
5199                     pw.print("        [");
5200                     final int opCount = activeWatchers.size();
5201                     for (int opNum = 0; opNum < opCount; opNum++) {
5202                         if (opNum > 0) {
5203                             pw.print(' ');
5204                         }
5205                         pw.print(AppOpsManager.opToName(activeWatchers.keyAt(opNum)));
5206                         if (opNum < opCount - 1) {
5207                             pw.print(',');
5208                         }
5209                     }
5210                     pw.println("]");
5211                     pw.print("        ");
5212                     pw.println(cb);
5213                 }
5214             }
5215             if (mStartedWatchers.size() > 0 && dumpMode < 0) {
5216                 needSep = true;
5217                 boolean printedHeader = false;
5218 
5219                 final int watchersSize = mStartedWatchers.size();
5220                 for (int watcherNum = 0; watcherNum < watchersSize; watcherNum++) {
5221                     final SparseArray<StartedCallback> startedWatchers =
5222                             mStartedWatchers.valueAt(watcherNum);
5223                     if (startedWatchers.size() <= 0) {
5224                         continue;
5225                     }
5226 
5227                     final StartedCallback cb = startedWatchers.valueAt(0);
5228                     if (dumpOp >= 0 && startedWatchers.indexOfKey(dumpOp) < 0) {
5229                         continue;
5230                     }
5231 
5232                     if (dumpPackage != null
5233                             && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
5234                         continue;
5235                     }
5236 
5237                     if (!printedHeader) {
5238                         pw.println("  All op started watchers:");
5239                         printedHeader = true;
5240                     }
5241 
5242                     pw.print("    ");
5243                     pw.print(Integer.toHexString(System.identityHashCode(
5244                             mStartedWatchers.keyAt(watcherNum))));
5245                     pw.println(" ->");
5246 
5247                     pw.print("        [");
5248                     final int opCount = startedWatchers.size();
5249                     for (int opNum = 0; opNum < opCount; opNum++) {
5250                         if (opNum > 0) {
5251                             pw.print(' ');
5252                         }
5253 
5254                         pw.print(AppOpsManager.opToName(startedWatchers.keyAt(opNum)));
5255                         if (opNum < opCount - 1) {
5256                             pw.print(',');
5257                         }
5258                     }
5259                     pw.println("]");
5260 
5261                     pw.print("        ");
5262                     pw.println(cb);
5263                 }
5264             }
5265             if (mNotedWatchers.size() > 0 && dumpMode < 0) {
5266                 needSep = true;
5267                 boolean printedHeader = false;
5268                 for (int watcherNum = 0; watcherNum < mNotedWatchers.size(); watcherNum++) {
5269                     final SparseArray<NotedCallback> notedWatchers =
5270                             mNotedWatchers.valueAt(watcherNum);
5271                     if (notedWatchers.size() <= 0) {
5272                         continue;
5273                     }
5274                     final NotedCallback cb = notedWatchers.valueAt(0);
5275                     if (dumpOp >= 0 && notedWatchers.indexOfKey(dumpOp) < 0) {
5276                         continue;
5277                     }
5278                     if (dumpPackage != null
5279                             && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
5280                         continue;
5281                     }
5282                     if (!printedHeader) {
5283                         pw.println("  All op noted watchers:");
5284                         printedHeader = true;
5285                     }
5286                     pw.print("    ");
5287                     pw.print(Integer.toHexString(System.identityHashCode(
5288                             mNotedWatchers.keyAt(watcherNum))));
5289                     pw.println(" ->");
5290                     pw.print("        [");
5291                     final int opCount = notedWatchers.size();
5292                     for (int opNum = 0; opNum < opCount; opNum++) {
5293                         if (opNum > 0) {
5294                             pw.print(' ');
5295                         }
5296                         pw.print(AppOpsManager.opToName(notedWatchers.keyAt(opNum)));
5297                         if (opNum < opCount - 1) {
5298                             pw.print(',');
5299                         }
5300                     }
5301                     pw.println("]");
5302                     pw.print("        ");
5303                     pw.println(cb);
5304                 }
5305             }
5306             if (mAudioRestrictionManager.hasActiveRestrictions() && dumpOp < 0
5307                     && dumpPackage != null && dumpMode < 0 && !dumpWatchers) {
5308                 needSep = mAudioRestrictionManager.dump(pw) || needSep;
5309             }
5310             if (needSep) {
5311                 pw.println();
5312             }
5313             for (int i=0; i<mUidStates.size(); i++) {
5314                 UidState uidState = mUidStates.valueAt(i);
5315                 final SparseIntArray opModes = uidState.getNonDefaultUidModes();
5316                 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
5317 
5318                 if (dumpWatchers || dumpHistory) {
5319                     continue;
5320                 }
5321                 if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
5322                     boolean hasOp = dumpOp < 0 || (opModes != null
5323                             && opModes.indexOfKey(dumpOp) >= 0);
5324                     boolean hasPackage = dumpPackage == null || dumpUid == mUidStates.keyAt(i);
5325                     boolean hasMode = dumpMode < 0;
5326                     if (!hasMode && opModes != null) {
5327                         for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
5328                             if (opModes.valueAt(opi) == dumpMode) {
5329                                 hasMode = true;
5330                             }
5331                         }
5332                     }
5333                     if (pkgOps != null) {
5334                         for (int pkgi = 0;
5335                                  (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
5336                                  pkgi++) {
5337                             Ops ops = pkgOps.valueAt(pkgi);
5338                             if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
5339                                 hasOp = true;
5340                             }
5341                             if (!hasMode) {
5342                                 for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
5343                                     if (ops.valueAt(opi).getMode() == dumpMode) {
5344                                         hasMode = true;
5345                                     }
5346                                 }
5347                             }
5348                             if (!hasPackage && dumpPackage.equals(ops.packageName)) {
5349                                 hasPackage = true;
5350                             }
5351                         }
5352                     }
5353                     if (uidState.foregroundOps != null && !hasOp) {
5354                         if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
5355                             hasOp = true;
5356                         }
5357                     }
5358                     if (!hasOp || !hasPackage || !hasMode) {
5359                         continue;
5360                     }
5361                 }
5362 
5363                 pw.print("  Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
5364                 uidState.dump(pw, nowElapsed);
5365                 if (uidState.foregroundOps != null && (dumpMode < 0
5366                         || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
5367                     pw.println("    foregroundOps:");
5368                     for (int j = 0; j < uidState.foregroundOps.size(); j++) {
5369                         if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
5370                             continue;
5371                         }
5372                         pw.print("      ");
5373                         pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
5374                         pw.print(": ");
5375                         pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
5376                     }
5377                     pw.print("    hasForegroundWatchers=");
5378                     pw.println(uidState.hasForegroundWatchers);
5379                 }
5380                 needSep = true;
5381 
5382                 if (opModes != null) {
5383                     final int opModeCount = opModes.size();
5384                     for (int j = 0; j < opModeCount; j++) {
5385                         final int code = opModes.keyAt(j);
5386                         final int mode = opModes.valueAt(j);
5387                         if (dumpOp >= 0 && dumpOp != code) {
5388                             continue;
5389                         }
5390                         if (dumpMode >= 0 && dumpMode != mode) {
5391                             continue;
5392                         }
5393                         pw.print("      "); pw.print(AppOpsManager.opToName(code));
5394                         pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
5395                     }
5396                 }
5397 
5398                 if (pkgOps == null) {
5399                     continue;
5400                 }
5401 
5402                 for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
5403                     final Ops ops = pkgOps.valueAt(pkgi);
5404                     if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
5405                         continue;
5406                     }
5407                     boolean printedPackage = false;
5408                     for (int j=0; j<ops.size(); j++) {
5409                         final Op op = ops.valueAt(j);
5410                         final int opCode = op.op;
5411                         if (dumpOp >= 0 && dumpOp != opCode) {
5412                             continue;
5413                         }
5414                         if (dumpMode >= 0 && dumpMode != op.getMode()) {
5415                             continue;
5416                         }
5417                         if (!printedPackage) {
5418                             pw.print("    Package "); pw.print(ops.packageName); pw.println(":");
5419                             printedPackage = true;
5420                         }
5421                         pw.print("      "); pw.print(AppOpsManager.opToName(opCode));
5422                         pw.print(" ("); pw.print(AppOpsManager.modeToName(op.getMode()));
5423                         final int switchOp = AppOpsManager.opToSwitch(opCode);
5424                         if (switchOp != opCode) {
5425                             pw.print(" / switch ");
5426                             pw.print(AppOpsManager.opToName(switchOp));
5427                             final Op switchObj = ops.get(switchOp);
5428                             int mode = switchObj == null
5429                                     ? AppOpsManager.opToDefaultMode(switchOp) : switchObj.getMode();
5430                             pw.print("="); pw.print(AppOpsManager.modeToName(mode));
5431                         }
5432                         pw.println("): ");
5433                         dumpStatesLocked(pw, dumpAttributionTag, dumpFilter, nowElapsed, op, now,
5434                                 sdf, date, "        ");
5435                     }
5436                 }
5437             }
5438             if (needSep) {
5439                 pw.println();
5440             }
5441 
5442             boolean showUserRestrictions = !(dumpMode < 0 && !dumpWatchers && !dumpHistory);
5443             mAppOpsRestrictions.dumpRestrictions(pw, dumpOp, dumpPackage, showUserRestrictions);
5444 
5445             if (!dumpHistory && !dumpWatchers) {
5446                 pw.println();
5447                 if (mCheckOpsDelegateDispatcher.mPolicy != null
5448                         && mCheckOpsDelegateDispatcher.mPolicy instanceof AppOpsPolicy) {
5449                     AppOpsPolicy policy = (AppOpsPolicy) mCheckOpsDelegateDispatcher.mPolicy;
5450                     policy.dumpTags(pw);
5451                 } else {
5452                     pw.println("  AppOps policy not set.");
5453                 }
5454             }
5455 
5456             if (dumpAll || dumpUidStateChangeLogs) {
5457                 pw.println();
5458                 pw.println("Uid State Changes Event Log:");
5459                 getUidStateTracker().dumpEvents(pw);
5460             }
5461         }
5462 
5463         // Must not hold the appops lock
5464         if (dumpHistory && !dumpWatchers) {
5465             mHistoricalRegistry.dump("  ", pw, dumpUid, dumpPackage, dumpAttributionTag, dumpOp,
5466                     dumpFilter);
5467         }
5468         if (includeDiscreteOps) {
5469             pw.println("Discrete accesses: ");
5470             mHistoricalRegistry.dumpDiscreteData(pw, dumpUid, dumpPackage, dumpAttributionTag,
5471                     dumpFilter, dumpOp, sdf, date, "  ", nDiscreteOps);
5472         }
5473     }
5474 
5475     @Override
5476     public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
5477         checkSystemUid("setUserRestrictions");
5478         Objects.requireNonNull(restrictions);
5479         Objects.requireNonNull(token);
5480         for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
5481             String restriction = AppOpsManager.opToRestriction(i);
5482             if (restriction != null) {
5483                 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
5484                         userHandle, null);
5485             }
5486         }
5487     }
5488 
5489     @Override
5490     public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
5491             PackageTagsList excludedPackageTags) {
5492         if (Binder.getCallingPid() != Process.myPid()) {
5493             mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
5494                     Binder.getCallingPid(), Binder.getCallingUid(), null);
5495         }
5496         if (userHandle != UserHandle.getCallingUserId()) {
5497             if (mContext.checkCallingOrSelfPermission(Manifest.permission
5498                     .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
5499                 && mContext.checkCallingOrSelfPermission(Manifest.permission
5500                     .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
5501                 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
5502                         + " INTERACT_ACROSS_USERS to interact cross user ");
5503             }
5504         }
5505         verifyIncomingOp(code);
5506         Objects.requireNonNull(token);
5507         setUserRestrictionNoCheck(code, restricted, token, userHandle, excludedPackageTags);
5508     }
5509 
5510     private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
5511             int userHandle, PackageTagsList excludedPackageTags) {
5512         synchronized (AppOpsService.this) {
5513             ClientUserRestrictionState restrictionState = mOpUserRestrictions.get(token);
5514 
5515             if (restrictionState == null) {
5516                 try {
5517                     restrictionState = new ClientUserRestrictionState(token);
5518                 } catch (RemoteException e) {
5519                     return;
5520                 }
5521                 mOpUserRestrictions.put(token, restrictionState);
5522             }
5523 
5524             if (restrictionState.setRestriction(code, restricted, excludedPackageTags,
5525                     userHandle)) {
5526                 mHandler.sendMessage(PooledLambda.obtainMessage(
5527                         AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
5528                 mHandler.sendMessage(PooledLambda.obtainMessage(
5529                         AppOpsService::updateStartedOpModeForUser, this, code, restricted,
5530                         userHandle));
5531             }
5532 
5533             if (restrictionState.isDefault()) {
5534                 mOpUserRestrictions.remove(token);
5535                 restrictionState.destroy();
5536             }
5537         }
5538     }
5539 
5540     private void updateStartedOpModeForUser(int code, boolean restricted, int userId) {
5541         synchronized (AppOpsService.this) {
5542             int numUids = mUidStates.size();
5543             for (int uidNum = 0; uidNum < numUids; uidNum++) {
5544                 int uid = mUidStates.keyAt(uidNum);
5545                 if (userId != UserHandle.USER_ALL && UserHandle.getUserId(uid) != userId) {
5546                     continue;
5547                 }
5548                 updateStartedOpModeForUidLocked(code, restricted, uid);
5549             }
5550         }
5551     }
5552 
5553     private void updateStartedOpModeForUidLocked(int code, boolean restricted, int uid) {
5554         UidState uidState = mUidStates.get(uid);
5555         if (uidState == null) {
5556             return;
5557         }
5558 
5559         int numPkgOps = uidState.pkgOps.size();
5560         for (int pkgNum = 0; pkgNum < numPkgOps; pkgNum++) {
5561             Ops ops = uidState.pkgOps.valueAt(pkgNum);
5562             Op op = ops != null ? ops.get(code) : null;
5563             if (op == null || (op.getMode() != MODE_ALLOWED && op.getMode() != MODE_FOREGROUND)) {
5564                 continue;
5565             }
5566             int numAttrTags = op.mAttributions.size();
5567             for (int attrNum = 0; attrNum < numAttrTags; attrNum++) {
5568                 AttributedOp attrOp = op.mAttributions.valueAt(attrNum);
5569                 if (restricted && attrOp.isRunning()) {
5570                     attrOp.pause();
5571                 } else if (attrOp.isPaused()) {
5572                     attrOp.resume();
5573                 }
5574             }
5575         }
5576     }
5577 
5578     private void notifyWatchersOfChange(int code, int uid) {
5579         final ArraySet<OnOpModeChangedListener> modeChangedListenerSet;
5580         synchronized (this) {
5581             modeChangedListenerSet = mAppOpsCheckingService.getOpModeChangedListeners(code);
5582             if (modeChangedListenerSet == null) {
5583                 return;
5584             }
5585         }
5586 
5587         notifyOpChanged(modeChangedListenerSet,  code, uid, null);
5588     }
5589 
5590     @Override
5591     public void removeUser(int userHandle) throws RemoteException {
5592         checkSystemUid("removeUser");
5593         synchronized (AppOpsService.this) {
5594             final int tokenCount = mOpUserRestrictions.size();
5595             for (int i = tokenCount - 1; i >= 0; i--) {
5596                 ClientUserRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
5597                 opRestrictions.removeUser(userHandle);
5598             }
5599             removeUidsForUserLocked(userHandle);
5600         }
5601     }
5602 
5603     @Override
5604     public boolean isOperationActive(int code, int uid, String packageName) {
5605         if (Binder.getCallingUid() != uid) {
5606             if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
5607                     != PackageManager.PERMISSION_GRANTED) {
5608                 return false;
5609             }
5610         }
5611         verifyIncomingOp(code);
5612         if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
5613             return false;
5614         }
5615 
5616         final String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
5617         if (resolvedPackageName == null) {
5618             return false;
5619         }
5620         // TODO moltmann: Allow to check for attribution op activeness
5621         synchronized (AppOpsService.this) {
5622             Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, false, null, false);
5623             if (pkgOps == null) {
5624                 return false;
5625             }
5626 
5627             Op op = pkgOps.get(code);
5628             if (op == null) {
5629                 return false;
5630             }
5631 
5632             return op.isRunning();
5633         }
5634     }
5635 
5636     @Override
5637     public boolean isProxying(int op, @NonNull String proxyPackageName,
5638             @NonNull String proxyAttributionTag, int proxiedUid,
5639             @NonNull String proxiedPackageName) {
5640         Objects.requireNonNull(proxyPackageName);
5641         Objects.requireNonNull(proxiedPackageName);
5642         final long callingUid = Binder.getCallingUid();
5643         final long identity = Binder.clearCallingIdentity();
5644         try {
5645             final List<AppOpsManager.PackageOps> packageOps = getOpsForPackage(proxiedUid,
5646                     proxiedPackageName, new int[] {op});
5647             if (packageOps == null || packageOps.isEmpty()) {
5648                 return false;
5649             }
5650             final List<OpEntry> opEntries = packageOps.get(0).getOps();
5651             if (opEntries.isEmpty()) {
5652                 return false;
5653             }
5654             final OpEntry opEntry = opEntries.get(0);
5655             if (!opEntry.isRunning()) {
5656                 return false;
5657             }
5658             final OpEventProxyInfo proxyInfo = opEntry.getLastProxyInfo(
5659                     OP_FLAG_TRUSTED_PROXIED | AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED);
5660             return proxyInfo != null && callingUid == proxyInfo.getUid()
5661                     && proxyPackageName.equals(proxyInfo.getPackageName())
5662                     && Objects.equals(proxyAttributionTag, proxyInfo.getAttributionTag());
5663         } finally {
5664             Binder.restoreCallingIdentity(identity);
5665         }
5666     }
5667 
5668     @Override
5669     public void resetPackageOpsNoHistory(@NonNull String packageName) {
5670         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5671                 "resetPackageOpsNoHistory");
5672         synchronized (AppOpsService.this) {
5673             final int uid = mPackageManagerInternal.getPackageUid(packageName, 0,
5674                     UserHandle.getCallingUserId());
5675             if (uid == Process.INVALID_UID) {
5676                 return;
5677             }
5678             UidState uidState = mUidStates.get(uid);
5679             if (uidState == null) {
5680                 return;
5681             }
5682             Ops removedOps = uidState.pkgOps.remove(packageName);
5683             mAppOpsCheckingService.removePackage(packageName, UserHandle.getUserId(uid));
5684             if (removedOps != null) {
5685                 scheduleFastWriteLocked();
5686             }
5687         }
5688     }
5689 
5690     @Override
5691     public void setHistoryParameters(@AppOpsManager.HistoricalMode int mode,
5692             long baseSnapshotInterval, int compressionStep) {
5693         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5694                 "setHistoryParameters");
5695         // Must not hold the appops lock
5696         mHistoricalRegistry.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
5697     }
5698 
5699     @Override
5700     public void offsetHistory(long offsetMillis) {
5701         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5702                 "offsetHistory");
5703         // Must not hold the appops lock
5704         mHistoricalRegistry.offsetHistory(offsetMillis);
5705         mHistoricalRegistry.offsetDiscreteHistory(offsetMillis);
5706     }
5707 
5708     @Override
5709     public void addHistoricalOps(HistoricalOps ops) {
5710         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5711                 "addHistoricalOps");
5712         // Must not hold the appops lock
5713         mHistoricalRegistry.addHistoricalOps(ops);
5714     }
5715 
5716     @Override
5717     public void resetHistoryParameters() {
5718         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5719                 "resetHistoryParameters");
5720         // Must not hold the appops lock
5721         mHistoricalRegistry.resetHistoryParameters();
5722     }
5723 
5724     @Override
5725     public void clearHistory() {
5726         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5727                 "clearHistory");
5728         // Must not hold the appops lock
5729         mHistoricalRegistry.clearAllHistory();
5730     }
5731 
5732     @Override
5733     public void rebootHistory(long offlineDurationMillis) {
5734         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5735                 "rebootHistory");
5736 
5737         Preconditions.checkArgument(offlineDurationMillis >= 0);
5738 
5739         // Must not hold the appops lock
5740         mHistoricalRegistry.shutdown();
5741 
5742         if (offlineDurationMillis > 0) {
5743             SystemClock.sleep(offlineDurationMillis);
5744         }
5745 
5746         mHistoricalRegistry = new HistoricalRegistry(mHistoricalRegistry);
5747         mHistoricalRegistry.systemReady(mContext.getContentResolver());
5748         mHistoricalRegistry.persistPendingHistory();
5749     }
5750 
5751     /**
5752      * Report runtime access to AppOp together with message (including stack trace)
5753      *
5754      * @param packageName The package which reported the op
5755      * @param notedAppOp contains code of op and attributionTag provided by developer
5756      * @param message Message describing AppOp access (can be stack trace)
5757      *
5758      * @return Config for future sampling to reduce amount of reporting
5759      */
5760     @Override
5761     public MessageSamplingConfig reportRuntimeAppOpAccessMessageAndGetConfig(
5762             String packageName, SyncNotedAppOp notedAppOp, String message) {
5763         int uid = Binder.getCallingUid();
5764         Objects.requireNonNull(packageName);
5765         synchronized (this) {
5766             switchPackageIfBootTimeOrRarelyUsedLocked(packageName);
5767             if (!packageName.equals(mSampledPackage)) {
5768                 return new MessageSamplingConfig(OP_NONE, 0,
5769                         Instant.now().plus(1, ChronoUnit.HOURS).toEpochMilli());
5770             }
5771 
5772             Objects.requireNonNull(notedAppOp);
5773             Objects.requireNonNull(message);
5774 
5775             reportRuntimeAppOpAccessMessageInternalLocked(uid, packageName,
5776                     AppOpsManager.strOpToOp(notedAppOp.getOp()),
5777                     notedAppOp.getAttributionTag(), message);
5778 
5779             return new MessageSamplingConfig(mSampledAppOpCode, mAcceptableLeftDistance,
5780                     Instant.now().plus(1, ChronoUnit.HOURS).toEpochMilli());
5781         }
5782     }
5783 
5784     /**
5785      * Report runtime access to AppOp together with message (entry point for reporting
5786      * asynchronous access)
5787      * @param uid Uid of the package which reported the op
5788      * @param packageName The package which reported the op
5789      * @param opCode Code of AppOp
5790      * @param attributionTag FeautreId of AppOp reported
5791      * @param message Message describing AppOp access (can be stack trace)
5792      */
5793     private void reportRuntimeAppOpAccessMessageAsyncLocked(int uid,
5794             @NonNull String packageName, int opCode, @Nullable String attributionTag,
5795             @NonNull String message) {
5796         switchPackageIfBootTimeOrRarelyUsedLocked(packageName);
5797         if (!Objects.equals(mSampledPackage, packageName)) {
5798             return;
5799         }
5800         reportRuntimeAppOpAccessMessageInternalLocked(uid, packageName, opCode, attributionTag,
5801                 message);
5802     }
5803 
5804     /**
5805      * Decides whether reported message is within the range of watched AppOps and picks it for
5806      * reporting uniformly at random across all received messages.
5807      */
5808     private void reportRuntimeAppOpAccessMessageInternalLocked(int uid,
5809             @NonNull String packageName, int opCode, @Nullable String attributionTag,
5810             @NonNull String message) {
5811         int newLeftDistance = AppOpsManager.leftCircularDistance(opCode,
5812                 mSampledAppOpCode, _NUM_OP);
5813 
5814         if (mAcceptableLeftDistance < newLeftDistance
5815                 && mSamplingStrategy != SAMPLING_STRATEGY_UNIFORM_OPS) {
5816             return;
5817         }
5818 
5819         if (mAcceptableLeftDistance > newLeftDistance
5820                 && mSamplingStrategy != SAMPLING_STRATEGY_UNIFORM_OPS) {
5821             mAcceptableLeftDistance = newLeftDistance;
5822             mMessagesCollectedCount = 0.0f;
5823         }
5824 
5825         mMessagesCollectedCount += 1.0f;
5826         if (ThreadLocalRandom.current().nextFloat() <= 1.0f / mMessagesCollectedCount) {
5827             mCollectedRuntimePermissionMessage = new RuntimeAppOpAccessMessage(uid, opCode,
5828                     packageName, attributionTag, message, mSamplingStrategy);
5829         }
5830         return;
5831     }
5832 
5833     /** Pulls current AppOps access report and resamples package and app op to watch */
5834     @Override
5835     public @Nullable RuntimeAppOpAccessMessage collectRuntimeAppOpAccessMessage() {
5836         ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class);
5837         boolean isCallerInstrumented =
5838                 ami.getInstrumentationSourceUid(Binder.getCallingUid()) != Process.INVALID_UID;
5839         boolean isCallerSystem = Binder.getCallingPid() == Process.myPid();
5840         if (!isCallerSystem && !isCallerInstrumented) {
5841             return null;
5842         }
5843         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
5844                 Binder.getCallingPid(), Binder.getCallingUid(), null);
5845         RuntimeAppOpAccessMessage result;
5846         synchronized (this) {
5847             result = mCollectedRuntimePermissionMessage;
5848             mCollectedRuntimePermissionMessage = null;
5849         }
5850         mHandler.sendMessage(PooledLambda.obtainMessage(
5851                 AppOpsService::getPackageListAndResample,
5852                 this));
5853         return result;
5854     }
5855 
5856     /**
5857      * Checks if package is in the list of rarely used package and starts watching the new package
5858      * to collect incoming message or if collection is happening in first minutes since boot.
5859      * @param packageName
5860      */
5861     private void switchPackageIfBootTimeOrRarelyUsedLocked(@NonNull String packageName) {
5862         if (mSampledPackage == null) {
5863             if (ThreadLocalRandom.current().nextFloat() < 0.5f) {
5864                 mSamplingStrategy = SAMPLING_STRATEGY_BOOT_TIME_SAMPLING;
5865                 resampleAppOpForPackageLocked(packageName, true);
5866             }
5867         } else if (mRarelyUsedPackages.contains(packageName)) {
5868             mRarelyUsedPackages.remove(packageName);
5869             if (ThreadLocalRandom.current().nextFloat() < 0.5f) {
5870                 mSamplingStrategy = SAMPLING_STRATEGY_RARELY_USED;
5871                 resampleAppOpForPackageLocked(packageName, true);
5872             }
5873         }
5874     }
5875 
5876     /** Obtains package list and resamples package and appop to watch. */
5877     private List<String> getPackageListAndResample() {
5878         List<String> packageNames = getPackageNamesForSampling();
5879         synchronized (this) {
5880             resamplePackageAndAppOpLocked(packageNames);
5881         }
5882         return packageNames;
5883     }
5884 
5885     /** Resamples package and appop to watch from the list provided. */
5886     private void resamplePackageAndAppOpLocked(@NonNull List<String> packageNames) {
5887         if (!packageNames.isEmpty()) {
5888             if (ThreadLocalRandom.current().nextFloat() < 0.5f) {
5889                 mSamplingStrategy = SAMPLING_STRATEGY_UNIFORM;
5890                 resampleAppOpForPackageLocked(packageNames.get(
5891                         ThreadLocalRandom.current().nextInt(packageNames.size())), true);
5892             } else {
5893                 mSamplingStrategy = SAMPLING_STRATEGY_UNIFORM_OPS;
5894                 resampleAppOpForPackageLocked(packageNames.get(
5895                         ThreadLocalRandom.current().nextInt(packageNames.size())), false);
5896             }
5897         }
5898     }
5899 
5900     /** Resamples appop for the chosen package and initializes sampling state */
5901     private void resampleAppOpForPackageLocked(@NonNull String packageName, boolean pickOp) {
5902         mMessagesCollectedCount = 0.0f;
5903         mSampledAppOpCode = pickOp ? ThreadLocalRandom.current().nextInt(_NUM_OP) : OP_NONE;
5904         mAcceptableLeftDistance = _NUM_OP - 1;
5905         mSampledPackage = packageName;
5906     }
5907 
5908     /**
5909      * Creates list of rarely used packages - packages which were not used over last week or
5910      * which declared but did not use permissions over last week.
5911      *  */
5912     private void initializeRarelyUsedPackagesList(@NonNull ArraySet<String> candidates) {
5913         AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
5914         List<String> runtimeAppOpsList = getRuntimeAppOpsList();
5915         AppOpsManager.HistoricalOpsRequest histOpsRequest =
5916                 new AppOpsManager.HistoricalOpsRequest.Builder(
5917                         Math.max(Instant.now().minus(7, ChronoUnit.DAYS).toEpochMilli(), 0),
5918                         Long.MAX_VALUE).setOpNames(runtimeAppOpsList).setFlags(
5919                         OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED).build();
5920         appOps.getHistoricalOps(histOpsRequest, AsyncTask.THREAD_POOL_EXECUTOR,
5921                 new Consumer<HistoricalOps>() {
5922                     @Override
5923                     public void accept(HistoricalOps histOps) {
5924                         int uidCount = histOps.getUidCount();
5925                         for (int uidIdx = 0; uidIdx < uidCount; uidIdx++) {
5926                             final AppOpsManager.HistoricalUidOps uidOps = histOps.getUidOpsAt(
5927                                     uidIdx);
5928                             int pkgCount = uidOps.getPackageCount();
5929                             for (int pkgIdx = 0; pkgIdx < pkgCount; pkgIdx++) {
5930                                 String packageName = uidOps.getPackageOpsAt(
5931                                         pkgIdx).getPackageName();
5932                                 if (!candidates.contains(packageName)) {
5933                                     continue;
5934                                 }
5935                                 AppOpsManager.HistoricalPackageOps packageOps =
5936                                         uidOps.getPackageOpsAt(pkgIdx);
5937                                 if (packageOps.getOpCount() != 0) {
5938                                     candidates.remove(packageName);
5939                                 }
5940                             }
5941                         }
5942                         synchronized (this) {
5943                             int numPkgs = mRarelyUsedPackages.size();
5944                             for (int i = 0; i < numPkgs; i++) {
5945                                 candidates.add(mRarelyUsedPackages.valueAt(i));
5946                             }
5947                             mRarelyUsedPackages = candidates;
5948                         }
5949                     }
5950                 });
5951     }
5952 
5953     /** List of app ops related to runtime permissions */
5954     private List<String> getRuntimeAppOpsList() {
5955         ArrayList<String> result = new ArrayList();
5956         for (int i = 0; i < _NUM_OP; i++) {
5957             if (shouldCollectNotes(i)) {
5958                 result.add(opToPublicName(i));
5959             }
5960         }
5961         return result;
5962     }
5963 
5964     /** Returns list of packages to be used for package sampling */
5965     private @NonNull List<String> getPackageNamesForSampling() {
5966         List<String> packageNames = new ArrayList<>();
5967         PackageManagerInternal packageManagerInternal = LocalServices.getService(
5968                 PackageManagerInternal.class);
5969         PackageList packages = packageManagerInternal.getPackageList();
5970         for (String packageName : packages.getPackageNames()) {
5971             PackageInfo pkg = packageManagerInternal.getPackageInfo(packageName,
5972                     PackageManager.GET_PERMISSIONS, Process.myUid(), mContext.getUserId());
5973             if (isSamplingTarget(pkg)) {
5974                 packageNames.add(pkg.packageName);
5975             }
5976         }
5977         return packageNames;
5978     }
5979 
5980     /** Checks whether package should be included in sampling pool */
5981     private boolean isSamplingTarget(@Nullable PackageInfo pkg) {
5982         if (pkg == null) {
5983             return false;
5984         }
5985         String[] requestedPermissions = pkg.requestedPermissions;
5986         if (requestedPermissions == null) {
5987             return false;
5988         }
5989         for (String permission : requestedPermissions) {
5990             PermissionInfo permissionInfo;
5991             try {
5992                 permissionInfo = mContext.getPackageManager().getPermissionInfo(permission, 0);
5993             } catch (PackageManager.NameNotFoundException ignored) {
5994                 continue;
5995             }
5996             if (permissionInfo.getProtection() == PROTECTION_DANGEROUS) {
5997                 return true;
5998             }
5999         }
6000         return false;
6001     }
6002 
6003     @GuardedBy("this")
6004     private void removeUidsForUserLocked(int userHandle) {
6005         for (int i = mUidStates.size() - 1; i >= 0; --i) {
6006             final int uid = mUidStates.keyAt(i);
6007             if (UserHandle.getUserId(uid) == userHandle) {
6008                 mUidStates.valueAt(i).clear();
6009                 mUidStates.removeAt(i);
6010             }
6011         }
6012     }
6013 
6014     private void checkSystemUid(String function) {
6015         int uid = Binder.getCallingUid();
6016         if (uid != Process.SYSTEM_UID) {
6017             throw new SecurityException(function + " must by called by the system");
6018         }
6019     }
6020 
6021     private static int resolveUid(String packageName)  {
6022         if (packageName == null) {
6023             return Process.INVALID_UID;
6024         }
6025         switch (packageName) {
6026             case "root":
6027                 return Process.ROOT_UID;
6028             case "shell":
6029             case "dumpstate":
6030                 return Process.SHELL_UID;
6031             case "media":
6032                 return Process.MEDIA_UID;
6033             case "audioserver":
6034                 return Process.AUDIOSERVER_UID;
6035             case "cameraserver":
6036                 return Process.CAMERASERVER_UID;
6037         }
6038         return Process.INVALID_UID;
6039     }
6040 
6041     private static String[] getPackagesForUid(int uid) {
6042         String[] packageNames = null;
6043 
6044         // Very early during boot the package manager is not yet or not yet fully started. At this
6045         // time there are no packages yet.
6046         if (AppGlobals.getPackageManager() != null) {
6047             try {
6048                 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
6049             } catch (RemoteException e) {
6050                 /* ignore - local call */
6051             }
6052         }
6053         if (packageNames == null) {
6054             return EmptyArray.STRING;
6055         }
6056         return packageNames;
6057     }
6058 
6059     private final class ClientUserRestrictionState implements DeathRecipient {
6060         private final IBinder token;
6061 
6062         ClientUserRestrictionState(IBinder token)
6063                 throws RemoteException {
6064             token.linkToDeath(this, 0);
6065             this.token = token;
6066         }
6067 
6068         public boolean setRestriction(int code, boolean restricted,
6069                 PackageTagsList excludedPackageTags, int userId) {
6070             return mAppOpsRestrictions.setUserRestriction(token, userId, code,
6071                     restricted, excludedPackageTags);
6072         }
6073 
6074         public boolean hasRestriction(int code, String packageName, String attributionTag,
6075                 int userId, boolean isCheckOp) {
6076             return mAppOpsRestrictions.getUserRestriction(token, userId, code, packageName,
6077                     attributionTag, isCheckOp);
6078         }
6079 
6080         public void removeUser(int userId) {
6081             mAppOpsRestrictions.clearUserRestrictions(token, userId);
6082         }
6083 
6084         public boolean isDefault() {
6085             return !mAppOpsRestrictions.hasUserRestrictions(token);
6086         }
6087 
6088         @Override
6089         public void binderDied() {
6090             synchronized (AppOpsService.this) {
6091                 mAppOpsRestrictions.clearUserRestrictions(token);
6092                 mOpUserRestrictions.remove(token);
6093                 destroy();
6094             }
6095         }
6096 
6097         public void destroy() {
6098             token.unlinkToDeath(this, 0);
6099         }
6100     }
6101 
6102     private final class ClientGlobalRestrictionState implements DeathRecipient {
6103         final IBinder mToken;
6104 
6105         ClientGlobalRestrictionState(IBinder token)
6106                 throws RemoteException {
6107             token.linkToDeath(this, 0);
6108             this.mToken = token;
6109         }
6110 
6111         boolean setRestriction(int code, boolean restricted) {
6112             return mAppOpsRestrictions.setGlobalRestriction(mToken, code, restricted);
6113         }
6114 
6115         boolean hasRestriction(int code) {
6116             return mAppOpsRestrictions.getGlobalRestriction(mToken, code);
6117         }
6118 
6119         boolean isDefault() {
6120             return !mAppOpsRestrictions.hasGlobalRestrictions(mToken);
6121         }
6122 
6123         @Override
6124         public void binderDied() {
6125             mAppOpsRestrictions.clearGlobalRestrictions(mToken);
6126             mOpGlobalRestrictions.remove(mToken);
6127             destroy();
6128         }
6129 
6130         void destroy() {
6131             mToken.unlinkToDeath(this, 0);
6132         }
6133     }
6134 
6135     private final class AppOpsManagerLocalImpl implements AppOpsManagerLocal {
6136         @Override
6137         public boolean isUidInForeground(int uid) {
6138             synchronized (AppOpsService.this) {
6139                 return mUidStateTracker.isUidInForeground(uid);
6140             }
6141         }
6142     }
6143 
6144     private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
6145         @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
6146             synchronized (AppOpsService.this) {
6147                 mProfileOwners = owners;
6148             }
6149         }
6150 
6151         @Override
6152         public void updateAppWidgetVisibility(SparseArray<String> uidPackageNames,
6153                 boolean visible) {
6154             AppOpsService.this.updateAppWidgetVisibility(uidPackageNames, visible);
6155         }
6156 
6157         @Override
6158         public void setUidModeFromPermissionPolicy(int code, int uid, int mode,
6159                 @Nullable IAppOpsCallback callback) {
6160             setUidMode(code, uid, mode, callback);
6161         }
6162 
6163         @Override
6164         public void setModeFromPermissionPolicy(int code, int uid, @NonNull String packageName,
6165                 int mode, @Nullable IAppOpsCallback callback) {
6166             setMode(code, uid, packageName, mode, callback);
6167         }
6168 
6169 
6170         @Override
6171         public void setGlobalRestriction(int code, boolean restricted, IBinder token) {
6172             if (Binder.getCallingPid() != Process.myPid()) {
6173                 // TODO instead of this enforcement put in AppOpsManagerInternal
6174                 throw new SecurityException("Only the system can set global restrictions");
6175             }
6176 
6177             synchronized (AppOpsService.this) {
6178                 ClientGlobalRestrictionState restrictionState = mOpGlobalRestrictions.get(token);
6179 
6180                 if (restrictionState == null) {
6181                     try {
6182                         restrictionState = new ClientGlobalRestrictionState(token);
6183                     } catch (RemoteException  e) {
6184                         return;
6185                     }
6186                     mOpGlobalRestrictions.put(token, restrictionState);
6187                 }
6188 
6189                 if (restrictionState.setRestriction(code, restricted)) {
6190                     mHandler.sendMessage(PooledLambda.obtainMessage(
6191                             AppOpsService::notifyWatchersOfChange, AppOpsService.this, code,
6192                             UID_ANY));
6193                     mHandler.sendMessage(PooledLambda.obtainMessage(
6194                             AppOpsService::updateStartedOpModeForUser, AppOpsService.this,
6195                             code, restricted, UserHandle.USER_ALL));
6196                 }
6197 
6198                 if (restrictionState.isDefault()) {
6199                     mOpGlobalRestrictions.remove(token);
6200                     restrictionState.destroy();
6201                 }
6202             }
6203         }
6204 
6205         @Override
6206         public int getOpRestrictionCount(int code, UserHandle user, String pkg,
6207                 String attributionTag) {
6208             int number = 0;
6209             synchronized (AppOpsService.this) {
6210                 int numRestrictions = mOpUserRestrictions.size();
6211                 for (int i = 0; i < numRestrictions; i++) {
6212                     if (mOpUserRestrictions.valueAt(i)
6213                             .hasRestriction(code, pkg, attributionTag, user.getIdentifier(),
6214                                     false)) {
6215                         number++;
6216                     }
6217                 }
6218 
6219                 numRestrictions = mOpGlobalRestrictions.size();
6220                 for (int i = 0; i < numRestrictions; i++) {
6221                     if (mOpGlobalRestrictions.valueAt(i).hasRestriction(code)) {
6222                         number++;
6223                     }
6224                 }
6225             }
6226 
6227             return number;
6228         }
6229     }
6230 
6231     /**
6232      * Async task for writing note op stack trace, op code, package name and version to file
6233      * More specifically, writes all the collected ops from {@link #mNoteOpCallerStacktraces}
6234      */
6235     private void writeNoteOps() {
6236         synchronized (this) {
6237             mWriteNoteOpsScheduled = false;
6238         }
6239         synchronized (mNoteOpCallerStacktracesFile) {
6240             try (FileWriter writer = new FileWriter(mNoteOpCallerStacktracesFile)) {
6241                 int numTraces = mNoteOpCallerStacktraces.size();
6242                 for (int i = 0; i < numTraces; i++) {
6243                     // Writing json formatted string into file
6244                     writer.write(mNoteOpCallerStacktraces.valueAt(i).asJson());
6245                     // Comma separation, so we can wrap the entire log as a JSON object
6246                     // when all results are collected
6247                     writer.write(",");
6248                 }
6249             } catch (IOException e) {
6250                 Slog.w(TAG, "Failed to load opsValidation file for FileWriter", e);
6251             }
6252         }
6253     }
6254 
6255     /**
6256      * This class represents a NoteOp Trace object amd contains the necessary fields that will
6257      * be written to file to use for permissions data validation in JSON format
6258      */
6259     @Immutable
6260     static class NoteOpTrace {
6261         static final String STACKTRACE = "stackTrace";
6262         static final String OP = "op";
6263         static final String PACKAGENAME = "packageName";
6264         static final String VERSION = "version";
6265 
6266         private final @NonNull String mStackTrace;
6267         private final int mOp;
6268         private final @Nullable String mPackageName;
6269         private final long mVersion;
6270 
6271         /**
6272          * Initialize a NoteOp object using a JSON object containing the necessary fields
6273          *
6274          * @param jsonTrace JSON object represented as a string
6275          *
6276          * @return NoteOpTrace object initialized with JSON fields
6277          */
6278         static NoteOpTrace fromJson(String jsonTrace) {
6279             try {
6280                 // Re-add closing bracket which acted as a delimiter by the reader
6281                 JSONObject obj = new JSONObject(jsonTrace.concat("}"));
6282                 return new NoteOpTrace(obj.getString(STACKTRACE), obj.getInt(OP),
6283                         obj.getString(PACKAGENAME), obj.getLong(VERSION));
6284             } catch (JSONException e) {
6285                 // Swallow error, only meant for logging ops, should not affect flow of the code
6286                 Slog.e(TAG, "Error constructing NoteOpTrace object "
6287                         + "JSON trace format incorrect", e);
6288                 return null;
6289             }
6290         }
6291 
6292         NoteOpTrace(String stackTrace, int op, String packageName, long version) {
6293             mStackTrace = stackTrace;
6294             mOp = op;
6295             mPackageName = packageName;
6296             mVersion = version;
6297         }
6298 
6299         @Override
6300         public boolean equals(Object o) {
6301             if (this == o) return true;
6302             if (o == null || getClass() != o.getClass()) return false;
6303             NoteOpTrace that = (NoteOpTrace) o;
6304             return mOp == that.mOp
6305                     && mVersion == that.mVersion
6306                     && mStackTrace.equals(that.mStackTrace)
6307                     && Objects.equals(mPackageName, that.mPackageName);
6308         }
6309 
6310         @Override
6311         public int hashCode() {
6312             return Objects.hash(mStackTrace, mOp, mPackageName, mVersion);
6313         }
6314 
6315         /**
6316          * The object is formatted as a JSON object and returned as a String
6317          *
6318          * @return JSON formatted string
6319          */
6320         public String asJson() {
6321             return  "{"
6322                     + "\"" + STACKTRACE + "\":\"" + mStackTrace.replace("\n", "\\n")
6323                     + '\"' + ",\"" + OP + "\":" + mOp
6324                     + ",\"" + PACKAGENAME + "\":\"" + mPackageName + '\"'
6325                     + ",\"" + VERSION + "\":" + mVersion
6326                     + '}';
6327         }
6328     }
6329 
6330     /**
6331      * Collects noteOps, noteProxyOps and startOps from AppOpsManager and writes it into a file
6332      * which will be used for permissions data validation, the given parameters to this method
6333      * will be logged in json format
6334      *
6335      * @param stackTrace stacktrace from the most recent call in AppOpsManager
6336      * @param op op code
6337      * @param packageName package making call
6338      * @param version android version for this call
6339      */
6340     @Override
6341     public void collectNoteOpCallsForValidation(String stackTrace, int op, String packageName,
6342             long version) {
6343         if (!AppOpsManager.NOTE_OP_COLLECTION_ENABLED) {
6344             return;
6345         }
6346 
6347         Objects.requireNonNull(stackTrace);
6348         Preconditions.checkArgument(op >= 0);
6349         Preconditions.checkArgument(op < AppOpsManager._NUM_OP);
6350 
6351         NoteOpTrace noteOpTrace = new NoteOpTrace(stackTrace, op, packageName, version);
6352 
6353         boolean noteOpSetWasChanged;
6354         synchronized (this) {
6355             noteOpSetWasChanged = mNoteOpCallerStacktraces.add(noteOpTrace);
6356             if (noteOpSetWasChanged && !mWriteNoteOpsScheduled) {
6357                 mWriteNoteOpsScheduled = true;
6358                 mHandler.postDelayed(PooledLambda.obtainRunnable((that) -> {
6359                     AsyncTask.execute(() -> {
6360                         that.writeNoteOps();
6361                     });
6362                 }, this), 2500);
6363             }
6364         }
6365     }
6366 
6367     @Immutable
6368     private final class CheckOpsDelegateDispatcher {
6369         private final @Nullable CheckOpsDelegate mPolicy;
6370         private final @Nullable CheckOpsDelegate mCheckOpsDelegate;
6371 
6372         CheckOpsDelegateDispatcher(@Nullable CheckOpsDelegate policy,
6373                 @Nullable CheckOpsDelegate checkOpsDelegate) {
6374             mPolicy = policy;
6375             mCheckOpsDelegate = checkOpsDelegate;
6376         }
6377 
6378         public @NonNull CheckOpsDelegate getCheckOpsDelegate() {
6379             return mCheckOpsDelegate;
6380         }
6381 
6382         public int checkOperation(int code, int uid, String packageName,
6383                 @Nullable String attributionTag, boolean raw) {
6384             if (mPolicy != null) {
6385                 if (mCheckOpsDelegate != null) {
6386                     return mPolicy.checkOperation(code, uid, packageName, attributionTag, raw,
6387                             this::checkDelegateOperationImpl);
6388                 } else {
6389                     return mPolicy.checkOperation(code, uid, packageName, attributionTag, raw,
6390                             AppOpsService.this::checkOperationImpl);
6391                 }
6392             } else if (mCheckOpsDelegate != null) {
6393                 return checkDelegateOperationImpl(code, uid, packageName, attributionTag, raw);
6394             }
6395             return checkOperationImpl(code, uid, packageName, attributionTag, raw);
6396         }
6397 
6398         private int checkDelegateOperationImpl(int code, int uid, String packageName,
6399                 @Nullable String attributionTag, boolean raw) {
6400             return mCheckOpsDelegate.checkOperation(code, uid, packageName, attributionTag, raw,
6401                     AppOpsService.this::checkOperationImpl);
6402         }
6403 
6404         public int checkAudioOperation(int code, int usage, int uid, String packageName) {
6405             if (mPolicy != null) {
6406                 if (mCheckOpsDelegate != null) {
6407                     return mPolicy.checkAudioOperation(code, usage, uid, packageName,
6408                             this::checkDelegateAudioOperationImpl);
6409                 } else {
6410                     return mPolicy.checkAudioOperation(code, usage, uid, packageName,
6411                             AppOpsService.this::checkAudioOperationImpl);
6412                 }
6413             } else if (mCheckOpsDelegate != null) {
6414                 return checkDelegateAudioOperationImpl(code, usage, uid, packageName);
6415             }
6416             return checkAudioOperationImpl(code, usage, uid, packageName);
6417         }
6418 
6419         private int checkDelegateAudioOperationImpl(int code, int usage, int uid,
6420                 String packageName) {
6421             return mCheckOpsDelegate.checkAudioOperation(code, usage, uid, packageName,
6422                     AppOpsService.this::checkAudioOperationImpl);
6423         }
6424 
6425         public SyncNotedAppOp noteOperation(int code, int uid, String packageName,
6426                 String attributionTag, boolean shouldCollectAsyncNotedOp, String message,
6427                 boolean shouldCollectMessage) {
6428             if (mPolicy != null) {
6429                 if (mCheckOpsDelegate != null) {
6430                     return mPolicy.noteOperation(code, uid, packageName, attributionTag,
6431                             shouldCollectAsyncNotedOp, message, shouldCollectMessage,
6432                             this::noteDelegateOperationImpl);
6433                 } else {
6434                     return mPolicy.noteOperation(code, uid, packageName, attributionTag,
6435                             shouldCollectAsyncNotedOp, message, shouldCollectMessage,
6436                             AppOpsService.this::noteOperationImpl);
6437                 }
6438             } else if (mCheckOpsDelegate != null) {
6439                 return noteDelegateOperationImpl(code, uid, packageName,
6440                         attributionTag, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
6441             }
6442             return noteOperationImpl(code, uid, packageName, attributionTag,
6443                     shouldCollectAsyncNotedOp, message, shouldCollectMessage);
6444         }
6445 
6446         private SyncNotedAppOp noteDelegateOperationImpl(int code, int uid,
6447                 @Nullable String packageName, @Nullable String featureId,
6448                 boolean shouldCollectAsyncNotedOp, @Nullable String message,
6449                 boolean shouldCollectMessage) {
6450             return mCheckOpsDelegate.noteOperation(code, uid, packageName, featureId,
6451                     shouldCollectAsyncNotedOp, message, shouldCollectMessage,
6452                     AppOpsService.this::noteOperationImpl);
6453         }
6454 
6455         public SyncNotedAppOp noteProxyOperation(int code, AttributionSource attributionSource,
6456                 boolean shouldCollectAsyncNotedOp, @Nullable String message,
6457                 boolean shouldCollectMessage, boolean skipProxyOperation) {
6458             if (mPolicy != null) {
6459                 if (mCheckOpsDelegate != null) {
6460                     return mPolicy.noteProxyOperation(code, attributionSource,
6461                             shouldCollectAsyncNotedOp, message, shouldCollectMessage,
6462                             skipProxyOperation, this::noteDelegateProxyOperationImpl);
6463                 } else {
6464                     return mPolicy.noteProxyOperation(code, attributionSource,
6465                             shouldCollectAsyncNotedOp, message, shouldCollectMessage,
6466                             skipProxyOperation, AppOpsService.this::noteProxyOperationImpl);
6467                 }
6468             } else if (mCheckOpsDelegate != null) {
6469                 return noteDelegateProxyOperationImpl(code,
6470                         attributionSource, shouldCollectAsyncNotedOp, message,
6471                         shouldCollectMessage, skipProxyOperation);
6472             }
6473             return noteProxyOperationImpl(code, attributionSource, shouldCollectAsyncNotedOp,
6474                     message, shouldCollectMessage,skipProxyOperation);
6475         }
6476 
6477         private SyncNotedAppOp noteDelegateProxyOperationImpl(int code,
6478                 @NonNull AttributionSource attributionSource, boolean shouldCollectAsyncNotedOp,
6479                 @Nullable String message, boolean shouldCollectMessage,
6480                 boolean skipProxyOperation) {
6481             return mCheckOpsDelegate.noteProxyOperation(code, attributionSource,
6482                     shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation,
6483                     AppOpsService.this::noteProxyOperationImpl);
6484         }
6485 
6486         public SyncNotedAppOp startOperation(IBinder token, int code, int uid,
6487                 @Nullable String packageName, @NonNull String attributionTag,
6488                 boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
6489                 @Nullable String message, boolean shouldCollectMessage,
6490                 @AttributionFlags int attributionFlags, int attributionChainId) {
6491             if (mPolicy != null) {
6492                 if (mCheckOpsDelegate != null) {
6493                     return mPolicy.startOperation(token, code, uid, packageName,
6494                             attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message,
6495                             shouldCollectMessage, attributionFlags, attributionChainId,
6496                             this::startDelegateOperationImpl);
6497                 } else {
6498                     return mPolicy.startOperation(token, code, uid, packageName, attributionTag,
6499                             startIfModeDefault, shouldCollectAsyncNotedOp, message,
6500                             shouldCollectMessage, attributionFlags, attributionChainId,
6501                             AppOpsService.this::startOperationImpl);
6502                 }
6503             } else if (mCheckOpsDelegate != null) {
6504                 return startDelegateOperationImpl(token, code, uid, packageName, attributionTag,
6505                         startIfModeDefault, shouldCollectAsyncNotedOp, message,
6506                         shouldCollectMessage, attributionFlags, attributionChainId);
6507             }
6508             return startOperationImpl(token, code, uid, packageName, attributionTag,
6509                     startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
6510                     attributionFlags, attributionChainId);
6511         }
6512 
6513         private SyncNotedAppOp startDelegateOperationImpl(IBinder token, int code, int uid,
6514                 @Nullable String packageName, @Nullable String attributionTag,
6515                 boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message,
6516                 boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
6517                 int attributionChainId) {
6518             return mCheckOpsDelegate.startOperation(token, code, uid, packageName, attributionTag,
6519                     startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
6520                     attributionFlags, attributionChainId, AppOpsService.this::startOperationImpl);
6521         }
6522 
6523         public SyncNotedAppOp startProxyOperation(@NonNull IBinder clientId, int code,
6524                 @NonNull AttributionSource attributionSource, boolean startIfModeDefault,
6525                 boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
6526                 boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags,
6527                 @AttributionFlags int proxiedAttributionFlags, int attributionChainId) {
6528             if (mPolicy != null) {
6529                 if (mCheckOpsDelegate != null) {
6530                     return mPolicy.startProxyOperation(clientId, code, attributionSource,
6531                             startIfModeDefault, shouldCollectAsyncNotedOp, message,
6532                             shouldCollectMessage, skipProxyOperation, proxyAttributionFlags,
6533                             proxiedAttributionFlags, attributionChainId,
6534                             this::startDelegateProxyOperationImpl);
6535                 } else {
6536                     return mPolicy.startProxyOperation(clientId, code, attributionSource,
6537                             startIfModeDefault, shouldCollectAsyncNotedOp, message,
6538                             shouldCollectMessage, skipProxyOperation, proxyAttributionFlags,
6539                             proxiedAttributionFlags, attributionChainId,
6540                             AppOpsService.this::startProxyOperationImpl);
6541                 }
6542             } else if (mCheckOpsDelegate != null) {
6543                 return startDelegateProxyOperationImpl(clientId, code, attributionSource,
6544                         startIfModeDefault, shouldCollectAsyncNotedOp, message,
6545                         shouldCollectMessage, skipProxyOperation, proxyAttributionFlags,
6546                         proxiedAttributionFlags, attributionChainId);
6547             }
6548             return startProxyOperationImpl(clientId, code, attributionSource, startIfModeDefault,
6549                     shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation,
6550                     proxyAttributionFlags, proxiedAttributionFlags, attributionChainId);
6551         }
6552 
6553         private SyncNotedAppOp startDelegateProxyOperationImpl(@NonNull IBinder clientId, int code,
6554                 @NonNull AttributionSource attributionSource, boolean startIfModeDefault,
6555                 boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
6556                 boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags,
6557                 @AttributionFlags int proxiedAttributionFlsgs, int attributionChainId) {
6558             return mCheckOpsDelegate.startProxyOperation(clientId, code, attributionSource,
6559                     startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
6560                     skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlsgs,
6561                     attributionChainId, AppOpsService.this::startProxyOperationImpl);
6562         }
6563 
6564         public void finishOperation(IBinder clientId, int code, int uid, String packageName,
6565                 String attributionTag) {
6566             if (mPolicy != null) {
6567                 if (mCheckOpsDelegate != null) {
6568                     mPolicy.finishOperation(clientId, code, uid, packageName, attributionTag,
6569                             this::finishDelegateOperationImpl);
6570                 } else {
6571                     mPolicy.finishOperation(clientId, code, uid, packageName, attributionTag,
6572                             AppOpsService.this::finishOperationImpl);
6573                 }
6574             } else if (mCheckOpsDelegate != null) {
6575                 finishDelegateOperationImpl(clientId, code, uid, packageName, attributionTag);
6576             } else {
6577                 finishOperationImpl(clientId, code, uid, packageName, attributionTag);
6578             }
6579         }
6580 
6581         private void finishDelegateOperationImpl(IBinder clientId, int code, int uid,
6582                 String packageName, String attributionTag) {
6583             mCheckOpsDelegate.finishOperation(clientId, code, uid, packageName, attributionTag,
6584                     AppOpsService.this::finishOperationImpl);
6585         }
6586 
6587         public void finishProxyOperation(@NonNull IBinder clientId, int code,
6588                 @NonNull AttributionSource attributionSource, boolean skipProxyOperation) {
6589             if (mPolicy != null) {
6590                 if (mCheckOpsDelegate != null) {
6591                     mPolicy.finishProxyOperation(clientId, code, attributionSource,
6592                             skipProxyOperation, this::finishDelegateProxyOperationImpl);
6593                 } else {
6594                     mPolicy.finishProxyOperation(clientId, code, attributionSource,
6595                             skipProxyOperation, AppOpsService.this::finishProxyOperationImpl);
6596                 }
6597             } else if (mCheckOpsDelegate != null) {
6598                 finishDelegateProxyOperationImpl(clientId, code, attributionSource,
6599                         skipProxyOperation);
6600             } else {
6601                 finishProxyOperationImpl(clientId, code, attributionSource, skipProxyOperation);
6602             }
6603         }
6604 
6605         private Void finishDelegateProxyOperationImpl(@NonNull IBinder clientId, int code,
6606                 @NonNull AttributionSource attributionSource, boolean skipProxyOperation) {
6607             mCheckOpsDelegate.finishProxyOperation(clientId, code, attributionSource,
6608                     skipProxyOperation, AppOpsService.this::finishProxyOperationImpl);
6609             return null;
6610         }
6611     }
6612 }
6613