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