• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2012 The Android Open Source Project
3   *
4   * Licensed under the Apache License, Version 2.0 (the "License");
5   * you may not use this file except in compliance with the License.
6   * You may obtain a copy of the License at
7   *
8   *      http://www.apache.org/licenses/LICENSE-2.0
9   *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.android.server.appop;
18  
19  import static android.app.AppOpsManager.MAX_PRIORITY_UID_STATE;
20  import static android.app.AppOpsManager.MIN_PRIORITY_UID_STATE;
21  import static android.app.AppOpsManager.OP_FLAGS_ALL;
22  import static android.app.AppOpsManager.OP_NONE;
23  import static android.app.AppOpsManager.OP_PLAY_AUDIO;
24  import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
25  import static android.app.AppOpsManager.UID_STATE_CACHED;
26  import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
27  import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
28  import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE_LOCATION;
29  import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
30  import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
31  import static android.app.AppOpsManager.UID_STATE_TOP;
32  import static android.app.AppOpsManager.modeToName;
33  import static android.app.AppOpsManager.opToName;
34  import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState;
35  
36  import android.Manifest;
37  import android.annotation.NonNull;
38  import android.annotation.Nullable;
39  import android.app.ActivityManager;
40  import android.app.ActivityThread;
41  import android.app.AppGlobals;
42  import android.app.AppOpsManager;
43  import android.app.AppOpsManager.HistoricalOps;
44  import android.app.AppOpsManager.HistoricalOpsRequest;
45  import android.app.AppOpsManager.Mode;
46  import android.app.AppOpsManager.OpEntry;
47  import android.app.AppOpsManager.OpFlags;
48  import android.app.AppOpsManagerInternal;
49  import android.app.AppOpsManagerInternal.CheckOpsDelegate;
50  import android.content.BroadcastReceiver;
51  import android.content.ContentResolver;
52  import android.content.Context;
53  import android.content.Intent;
54  import android.content.IntentFilter;
55  import android.content.pm.ApplicationInfo;
56  import android.content.pm.IPackageManager;
57  import android.content.pm.PackageManager;
58  import android.content.pm.PackageManagerInternal;
59  import android.content.pm.UserInfo;
60  import android.database.ContentObserver;
61  import android.media.AudioAttributes;
62  import android.net.Uri;
63  import android.os.AsyncTask;
64  import android.os.Binder;
65  import android.os.Bundle;
66  import android.os.Handler;
67  import android.os.IBinder;
68  import android.os.Process;
69  import android.os.RemoteCallback;
70  import android.os.RemoteException;
71  import android.os.ResultReceiver;
72  import android.os.ServiceManager;
73  import android.os.ShellCallback;
74  import android.os.ShellCommand;
75  import android.os.SystemClock;
76  import android.os.UserHandle;
77  import android.os.UserManager;
78  import android.os.storage.StorageManager;
79  import android.os.storage.StorageManagerInternal;
80  import android.provider.Settings;
81  import android.util.ArrayMap;
82  import android.util.ArraySet;
83  import android.util.AtomicFile;
84  import android.util.KeyValueListParser;
85  import android.util.LongSparseArray;
86  import android.util.LongSparseLongArray;
87  import android.util.Slog;
88  import android.util.SparseArray;
89  import android.util.SparseBooleanArray;
90  import android.util.SparseIntArray;
91  import android.util.TimeUtils;
92  import android.util.Xml;
93  
94  import com.android.internal.annotations.GuardedBy;
95  import com.android.internal.annotations.VisibleForTesting;
96  import com.android.internal.app.IAppOpsActiveCallback;
97  import com.android.internal.app.IAppOpsCallback;
98  import com.android.internal.app.IAppOpsNotedCallback;
99  import com.android.internal.app.IAppOpsService;
100  import com.android.internal.os.Zygote;
101  import com.android.internal.util.ArrayUtils;
102  import com.android.internal.util.DumpUtils;
103  import com.android.internal.util.FastXmlSerializer;
104  import com.android.internal.util.Preconditions;
105  import com.android.internal.util.XmlUtils;
106  import com.android.internal.util.function.pooled.PooledLambda;
107  import com.android.server.LocalServices;
108  import com.android.server.LockGuard;
109  
110  import libcore.util.EmptyArray;
111  
112  import org.xmlpull.v1.XmlPullParser;
113  import org.xmlpull.v1.XmlPullParserException;
114  import org.xmlpull.v1.XmlSerializer;
115  
116  import java.io.File;
117  import java.io.FileDescriptor;
118  import java.io.FileInputStream;
119  import java.io.FileNotFoundException;
120  import java.io.FileOutputStream;
121  import java.io.IOException;
122  import java.io.PrintWriter;
123  import java.nio.charset.StandardCharsets;
124  import java.text.SimpleDateFormat;
125  import java.util.ArrayList;
126  import java.util.Arrays;
127  import java.util.Collections;
128  import java.util.Date;
129  import java.util.HashMap;
130  import java.util.Iterator;
131  import java.util.List;
132  import java.util.Map;
133  
134  public class AppOpsService extends IAppOpsService.Stub {
135      static final String TAG = "AppOps";
136      static final boolean DEBUG = false;
137  
138      private static final int NO_VERSION = -1;
139      /** Increment by one every time and add the corresponding upgrade logic in
140       *  {@link #upgradeLocked(int)} below. The first version was 1 */
141      private static final int CURRENT_VERSION = 1;
142  
143      // Write at most every 30 minutes.
144      static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
145  
146      // Constant meaning that any UID should be matched when dispatching callbacks
147      private static final int UID_ANY = -2;
148  
149      // Map from process states to the uid states we track.
150      private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
151          UID_STATE_PERSISTENT,           // ActivityManager.PROCESS_STATE_PERSISTENT
152          UID_STATE_PERSISTENT,           // ActivityManager.PROCESS_STATE_PERSISTENT_UI
153          UID_STATE_TOP,                  // ActivityManager.PROCESS_STATE_TOP
154          UID_STATE_FOREGROUND_SERVICE_LOCATION,
155                                          // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION
156          UID_STATE_FOREGROUND,           // ActivityManager.PROCESS_STATE_BOUND_TOP
157          UID_STATE_FOREGROUND_SERVICE,   // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
158          UID_STATE_FOREGROUND,           // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
159          UID_STATE_FOREGROUND,           // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
160          UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
161          UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
162          UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_BACKUP
163          UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_SERVICE
164          UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_RECEIVER
165          UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_TOP_SLEEPING
166          UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
167          UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_HOME
168          UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
169          UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
170          UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
171          UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_RECENT
172          UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_EMPTY
173          UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_NONEXISTENT
174      };
175  
176      Context mContext;
177      final AtomicFile mFile;
178      final Handler mHandler;
179  
180      private final AppOpsManagerInternalImpl mAppOpsManagerInternal
181              = new AppOpsManagerInternalImpl();
182  
183      boolean mWriteScheduled;
184      boolean mFastWriteScheduled;
185      final Runnable mWriteRunner = new Runnable() {
186          public void run() {
187              synchronized (AppOpsService.this) {
188                  mWriteScheduled = false;
189                  mFastWriteScheduled = false;
190                  AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
191                      @Override protected Void doInBackground(Void... params) {
192                          writeState();
193                          return null;
194                      }
195                  };
196                  task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
197              }
198          }
199      };
200  
201      @VisibleForTesting
202      final SparseArray<UidState> mUidStates = new SparseArray<>();
203  
204      final HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this);
205  
206      long mLastRealtime;
207  
208      /*
209       * These are app op restrictions imposed per user from various parties.
210       */
211      private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
212  
213      SparseIntArray mProfileOwners;
214  
215      @GuardedBy("this")
216      private CheckOpsDelegate mCheckOpsDelegate;
217  
218      /**
219       * All times are in milliseconds. These constants are kept synchronized with the system
220       * global Settings. Any access to this class or its fields should be done while
221       * holding the AppOpsService lock.
222       */
223      @VisibleForTesting
224      final class Constants extends ContentObserver {
225          // Key names stored in the settings value.
226          private static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
227          private static final String KEY_FG_SERVICE_STATE_SETTLE_TIME
228                  = "fg_service_state_settle_time";
229          private static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
230  
231          /**
232           * How long we want for a drop in uid state from top to settle before applying it.
233           * @see Settings.Global#APP_OPS_CONSTANTS
234           * @see #KEY_TOP_STATE_SETTLE_TIME
235           */
236          public long TOP_STATE_SETTLE_TIME;
237  
238          /**
239           * How long we want for a drop in uid state from foreground to settle before applying it.
240           * @see Settings.Global#APP_OPS_CONSTANTS
241           * @see #KEY_FG_SERVICE_STATE_SETTLE_TIME
242           */
243          public long FG_SERVICE_STATE_SETTLE_TIME;
244  
245          /**
246           * How long we want for a drop in uid state from background to settle before applying it.
247           * @see Settings.Global#APP_OPS_CONSTANTS
248           * @see #KEY_BG_STATE_SETTLE_TIME
249           */
250          public long BG_STATE_SETTLE_TIME;
251  
252          private final KeyValueListParser mParser = new KeyValueListParser(',');
253          private ContentResolver mResolver;
254  
Constants(Handler handler)255          public Constants(Handler handler) {
256              super(handler);
257              updateConstants();
258          }
259  
startMonitoring(ContentResolver resolver)260          public void startMonitoring(ContentResolver resolver) {
261              mResolver = resolver;
262              mResolver.registerContentObserver(
263                      Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
264                      false, this);
265              updateConstants();
266          }
267  
268          @Override
onChange(boolean selfChange, Uri uri)269          public void onChange(boolean selfChange, Uri uri) {
270              updateConstants();
271          }
272  
updateConstants()273          private void updateConstants() {
274              String value = mResolver != null ? Settings.Global.getString(mResolver,
275                      Settings.Global.APP_OPS_CONSTANTS) : "";
276  
277              synchronized (AppOpsService.this) {
278                  try {
279                      mParser.setString(value);
280                  } catch (IllegalArgumentException e) {
281                      // Failed to parse the settings string, log this and move on
282                      // with defaults.
283                      Slog.e(TAG, "Bad app ops settings", e);
284                  }
285                  TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
286                          KEY_TOP_STATE_SETTLE_TIME, 30 * 1000L);
287                  FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
288                          KEY_FG_SERVICE_STATE_SETTLE_TIME, 10 * 1000L);
289                  BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
290                          KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
291              }
292          }
293  
dump(PrintWriter pw)294          void dump(PrintWriter pw) {
295              pw.println("  Settings:");
296  
297              pw.print("    "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("=");
298              TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw);
299              pw.println();
300              pw.print("    "); pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME); pw.print("=");
301              TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
302              pw.println();
303              pw.print("    "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("=");
304              TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
305              pw.println();
306          }
307      }
308  
309      @VisibleForTesting
310      final Constants mConstants;
311  
312      @VisibleForTesting
313      static final class UidState {
314          public final int uid;
315  
316          public int state = UID_STATE_CACHED;
317          public int pendingState = UID_STATE_CACHED;
318          public long pendingStateCommitTime;
319  
320          public int startNesting;
321          public ArrayMap<String, Ops> pkgOps;
322          public SparseIntArray opModes;
323  
324          // true indicates there is an interested observer, false there isn't but it has such an op
325          public SparseBooleanArray foregroundOps;
326          public boolean hasForegroundWatchers;
327  
UidState(int uid)328          public UidState(int uid) {
329              this.uid = uid;
330          }
331  
clear()332          public void clear() {
333              pkgOps = null;
334              opModes = null;
335          }
336  
isDefault()337          public boolean isDefault() {
338              return (pkgOps == null || pkgOps.isEmpty())
339                      && (opModes == null || opModes.size() <= 0)
340                      && (state == UID_STATE_CACHED
341                      && (pendingState == UID_STATE_CACHED));
342          }
343  
evalMode(int op, int mode)344          int evalMode(int op, int mode) {
345              if (mode == AppOpsManager.MODE_FOREGROUND) {
346                  return state <= AppOpsManager.resolveFirstUnrestrictedUidState(op)
347                          ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
348              }
349              return mode;
350          }
351  
evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers, SparseBooleanArray which)352          private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
353                  SparseBooleanArray which) {
354              boolean curValue = which.get(op, false);
355              ArraySet<ModeCallback> callbacks = watchers.get(op);
356              if (callbacks != null) {
357                  for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
358                      if ((callbacks.valueAt(cbi).mFlags
359                              & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
360                          hasForegroundWatchers = true;
361                          curValue = true;
362                      }
363                  }
364              }
365              which.put(op, curValue);
366          }
367  
evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers)368          public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
369              SparseBooleanArray which = null;
370              hasForegroundWatchers = false;
371              if (opModes != null) {
372                  for (int i = opModes.size() - 1; i >= 0; i--) {
373                      if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
374                          if (which == null) {
375                              which = new SparseBooleanArray();
376                          }
377                          evalForegroundWatchers(opModes.keyAt(i), watchers, which);
378                      }
379                  }
380              }
381              if (pkgOps != null) {
382                  for (int i = pkgOps.size() - 1; i >= 0; i--) {
383                      Ops ops = pkgOps.valueAt(i);
384                      for (int j = ops.size() - 1; j >= 0; j--) {
385                          if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
386                              if (which == null) {
387                                  which = new SparseBooleanArray();
388                              }
389                              evalForegroundWatchers(ops.keyAt(j), watchers, which);
390                          }
391                      }
392                  }
393              }
394              foregroundOps = which;
395          }
396      }
397  
398      final static class Ops extends SparseArray<Op> {
399          final String packageName;
400          final UidState uidState;
401          final boolean isPrivileged;
402  
Ops(String _packageName, UidState _uidState, boolean _isPrivileged)403          Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
404              packageName = _packageName;
405              uidState = _uidState;
406              isPrivileged = _isPrivileged;
407          }
408      }
409  
410      final static class Op {
411          int op;
412          boolean running;
413          final UidState uidState;
414          final @NonNull String packageName;
415  
416          private @Mode int mode;
417          private @Nullable LongSparseLongArray mAccessTimes;
418          private @Nullable LongSparseLongArray mRejectTimes;
419          private @Nullable LongSparseLongArray mDurations;
420          private @Nullable LongSparseLongArray mProxyUids;
421          private @Nullable LongSparseArray<String> mProxyPackageNames;
422  
423          int startNesting;
424          long startRealtime;
425  
Op(UidState uidState, String packageName, int op)426          Op(UidState uidState, String packageName, int op) {
427              this.op = op;
428              this.uidState = uidState;
429              this.packageName = packageName;
430              this.mode = AppOpsManager.opToDefaultMode(op);
431          }
432  
getMode()433          int getMode() {
434              return mode;
435          }
436  
evalMode()437          int evalMode() {
438              return uidState.evalMode(op, mode);
439          }
440  
441          /** @hide */
accessed(long time, int proxyUid, @Nullable String proxyPackageName, @AppOpsManager.UidState int uidState, @OpFlags int flags)442          public void accessed(long time, int proxyUid, @Nullable String proxyPackageName,
443              @AppOpsManager.UidState int uidState, @OpFlags int flags) {
444              final long key = AppOpsManager.makeKey(uidState, flags);
445              if (mAccessTimes == null) {
446                  mAccessTimes = new LongSparseLongArray();
447              }
448              mAccessTimes.put(key, time);
449              updateProxyState(key, proxyUid, proxyPackageName);
450              if (mDurations != null) {
451                  mDurations.delete(key);
452              }
453          }
454  
455          /** @hide */
rejected(long time, int proxyUid, @Nullable String proxyPackageName, @AppOpsManager.UidState int uidState, @OpFlags int flags)456          public void rejected(long time, int proxyUid, @Nullable String proxyPackageName,
457              @AppOpsManager.UidState int uidState, @OpFlags int flags) {
458              final long key = AppOpsManager.makeKey(uidState, flags);
459              if (mRejectTimes == null) {
460                  mRejectTimes = new LongSparseLongArray();
461              }
462              mRejectTimes.put(key, time);
463              updateProxyState(key, proxyUid, proxyPackageName);
464              if (mDurations != null) {
465                  mDurations.delete(key);
466              }
467          }
468  
469          /** @hide */
started(long time, @AppOpsManager.UidState int uidState, @OpFlags int flags)470          public void started(long time, @AppOpsManager.UidState int uidState, @OpFlags int flags) {
471              updateAccessTimeAndDuration(time, -1 /*duration*/, uidState, flags);
472              running = true;
473          }
474  
475          /** @hide */
finished(long time, long duration, @AppOpsManager.UidState int uidState, @OpFlags int flags)476          public void finished(long time, long duration, @AppOpsManager.UidState int uidState,
477              @OpFlags int flags) {
478              updateAccessTimeAndDuration(time, duration, uidState, flags);
479              running = false;
480          }
481  
482          /** @hide */
running(long time, long duration, @AppOpsManager.UidState int uidState, @OpFlags int flags)483          public void running(long time, long duration, @AppOpsManager.UidState int uidState,
484              @OpFlags int flags) {
485              updateAccessTimeAndDuration(time, duration, uidState, flags);
486          }
487  
488          /** @hide */
continuing(long duration, @AppOpsManager.UidState int uidState, @OpFlags int flags)489          public void continuing(long duration, @AppOpsManager.UidState int uidState,
490              @OpFlags int flags) {
491              final long key = AppOpsManager.makeKey(uidState, flags);
492              if (mDurations == null) {
493                  mDurations = new LongSparseLongArray();
494              }
495              mDurations.put(key, duration);
496          }
497  
updateAccessTimeAndDuration(long time, long duration, @AppOpsManager.UidState int uidState, @OpFlags int flags)498          private void updateAccessTimeAndDuration(long time, long duration,
499              @AppOpsManager.UidState int uidState, @OpFlags int flags) {
500              final long key = AppOpsManager.makeKey(uidState, flags);
501              if (mAccessTimes == null) {
502                  mAccessTimes = new LongSparseLongArray();
503              }
504              mAccessTimes.put(key, time);
505              if (mDurations == null) {
506                  mDurations = new LongSparseLongArray();
507              }
508              mDurations.put(key, duration);
509          }
510  
updateProxyState(long key, int proxyUid, @Nullable String proxyPackageName)511          private void updateProxyState(long key, int proxyUid,
512              @Nullable String proxyPackageName) {
513              if (mProxyUids == null) {
514                  mProxyUids = new LongSparseLongArray();
515              }
516              mProxyUids.put(key, proxyUid);
517              if (mProxyPackageNames == null) {
518                  mProxyPackageNames = new LongSparseArray<>();
519              }
520              mProxyPackageNames.put(key, proxyPackageName);
521          }
522  
hasAnyTime()523          boolean hasAnyTime() {
524              return (mAccessTimes != null && mAccessTimes.size() > 0)
525                  || (mRejectTimes != null && mRejectTimes.size() > 0);
526          }
527      }
528  
529      final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
530      final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
531      final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
532      final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
533      final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>();
534      final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
535  
536      final class ModeCallback implements DeathRecipient {
537          final IAppOpsCallback mCallback;
538          final int mWatchingUid;
539          final int mFlags;
540          final int mCallingUid;
541          final int mCallingPid;
542  
ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid, int callingPid)543          ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
544                  int callingPid) {
545              mCallback = callback;
546              mWatchingUid = watchingUid;
547              mFlags = flags;
548              mCallingUid = callingUid;
549              mCallingPid = callingPid;
550              try {
551                  mCallback.asBinder().linkToDeath(this, 0);
552              } catch (RemoteException e) {
553                  /*ignored*/
554              }
555          }
556  
isWatchingUid(int uid)557          public boolean isWatchingUid(int uid) {
558              return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
559          }
560  
561          @Override
toString()562          public String toString() {
563              StringBuilder sb = new StringBuilder(128);
564              sb.append("ModeCallback{");
565              sb.append(Integer.toHexString(System.identityHashCode(this)));
566              sb.append(" watchinguid=");
567              UserHandle.formatUid(sb, mWatchingUid);
568              sb.append(" flags=0x");
569              sb.append(Integer.toHexString(mFlags));
570              sb.append(" from uid=");
571              UserHandle.formatUid(sb, mCallingUid);
572              sb.append(" pid=");
573              sb.append(mCallingPid);
574              sb.append('}');
575              return sb.toString();
576          }
577  
unlinkToDeath()578          void unlinkToDeath() {
579              mCallback.asBinder().unlinkToDeath(this, 0);
580          }
581  
582          @Override
binderDied()583          public void binderDied() {
584              stopWatchingMode(mCallback);
585          }
586      }
587  
588      final class ActiveCallback implements DeathRecipient {
589          final IAppOpsActiveCallback mCallback;
590          final int mWatchingUid;
591          final int mCallingUid;
592          final int mCallingPid;
593  
ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid, int callingPid)594          ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
595                  int callingPid) {
596              mCallback = callback;
597              mWatchingUid = watchingUid;
598              mCallingUid = callingUid;
599              mCallingPid = callingPid;
600              try {
601                  mCallback.asBinder().linkToDeath(this, 0);
602              } catch (RemoteException e) {
603                  /*ignored*/
604              }
605          }
606  
607          @Override
toString()608          public String toString() {
609              StringBuilder sb = new StringBuilder(128);
610              sb.append("ActiveCallback{");
611              sb.append(Integer.toHexString(System.identityHashCode(this)));
612              sb.append(" watchinguid=");
613              UserHandle.formatUid(sb, mWatchingUid);
614              sb.append(" from uid=");
615              UserHandle.formatUid(sb, mCallingUid);
616              sb.append(" pid=");
617              sb.append(mCallingPid);
618              sb.append('}');
619              return sb.toString();
620          }
621  
destroy()622          void destroy() {
623              mCallback.asBinder().unlinkToDeath(this, 0);
624          }
625  
626          @Override
binderDied()627          public void binderDied() {
628              stopWatchingActive(mCallback);
629          }
630      }
631  
632      final class NotedCallback implements DeathRecipient {
633          final IAppOpsNotedCallback mCallback;
634          final int mWatchingUid;
635          final int mCallingUid;
636          final int mCallingPid;
637  
NotedCallback(IAppOpsNotedCallback callback, int watchingUid, int callingUid, int callingPid)638          NotedCallback(IAppOpsNotedCallback callback, int watchingUid, int callingUid,
639                  int callingPid) {
640              mCallback = callback;
641              mWatchingUid = watchingUid;
642              mCallingUid = callingUid;
643              mCallingPid = callingPid;
644              try {
645                  mCallback.asBinder().linkToDeath(this, 0);
646              } catch (RemoteException e) {
647                  /*ignored*/
648              }
649          }
650  
651          @Override
toString()652          public String toString() {
653              StringBuilder sb = new StringBuilder(128);
654              sb.append("NotedCallback{");
655              sb.append(Integer.toHexString(System.identityHashCode(this)));
656              sb.append(" watchinguid=");
657              UserHandle.formatUid(sb, mWatchingUid);
658              sb.append(" from uid=");
659              UserHandle.formatUid(sb, mCallingUid);
660              sb.append(" pid=");
661              sb.append(mCallingPid);
662              sb.append('}');
663              return sb.toString();
664          }
665  
destroy()666          void destroy() {
667              mCallback.asBinder().unlinkToDeath(this, 0);
668          }
669  
670          @Override
binderDied()671          public void binderDied() {
672              stopWatchingNoted(mCallback);
673          }
674      }
675  
676      final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
677  
678      final class ClientState extends Binder implements DeathRecipient {
679          final ArrayList<Op> mStartedOps = new ArrayList<>();
680          final IBinder mAppToken;
681          final int mPid;
682  
ClientState(IBinder appToken)683          ClientState(IBinder appToken) {
684              mAppToken = appToken;
685              mPid = Binder.getCallingPid();
686              // Watch only for remote processes dying
687              if (!(appToken instanceof Binder)) {
688                  try {
689                      mAppToken.linkToDeath(this, 0);
690                  } catch (RemoteException e) {
691                      /* do nothing */
692                  }
693              }
694          }
695  
696          @Override
toString()697          public String toString() {
698              return "ClientState{" +
699                      "mAppToken=" + mAppToken +
700                      ", " + "pid=" + mPid +
701                      '}';
702          }
703  
704          @Override
binderDied()705          public void binderDied() {
706              synchronized (AppOpsService.this) {
707                  for (int i=mStartedOps.size()-1; i>=0; i--) {
708                      finishOperationLocked(mStartedOps.get(i), /*finishNested*/ true);
709                  }
710                  mClients.remove(mAppToken);
711              }
712          }
713      }
714  
AppOpsService(File storagePath, Handler handler)715      public AppOpsService(File storagePath, Handler handler) {
716          LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
717          mFile = new AtomicFile(storagePath, "appops");
718          mHandler = handler;
719          mConstants = new Constants(mHandler);
720          readState();
721      }
722  
publish(Context context)723      public void publish(Context context) {
724          mContext = context;
725          ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
726          LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
727      }
728  
systemReady()729      public void systemReady() {
730          mConstants.startMonitoring(mContext.getContentResolver());
731          mHistoricalRegistry.systemReady(mContext.getContentResolver());
732  
733          synchronized (this) {
734              boolean changed = false;
735              for (int i = mUidStates.size() - 1; i >= 0; i--) {
736                  UidState uidState = mUidStates.valueAt(i);
737  
738                  String[] packageNames = getPackagesForUid(uidState.uid);
739                  if (ArrayUtils.isEmpty(packageNames)) {
740                      uidState.clear();
741                      mUidStates.removeAt(i);
742                      changed = true;
743                      continue;
744                  }
745  
746                  ArrayMap<String, Ops> pkgs = uidState.pkgOps;
747                  if (pkgs == null) {
748                      continue;
749                  }
750  
751                  Iterator<Ops> it = pkgs.values().iterator();
752                  while (it.hasNext()) {
753                      Ops ops = it.next();
754                      int curUid = -1;
755                      try {
756                          curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
757                                  PackageManager.MATCH_UNINSTALLED_PACKAGES,
758                                  UserHandle.getUserId(ops.uidState.uid));
759                      } catch (RemoteException ignored) {
760                      }
761                      if (curUid != ops.uidState.uid) {
762                          Slog.i(TAG, "Pruning old package " + ops.packageName
763                                  + "/" + ops.uidState + ": new uid=" + curUid);
764                          it.remove();
765                          changed = true;
766                      }
767                  }
768  
769                  if (uidState.isDefault()) {
770                      mUidStates.removeAt(i);
771                  }
772              }
773              if (changed) {
774                  scheduleFastWriteLocked();
775              }
776          }
777  
778          final IntentFilter packageSuspendFilter = new IntentFilter();
779          packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
780          packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
781          mContext.registerReceiver(new BroadcastReceiver() {
782              @Override
783              public void onReceive(Context context, Intent intent) {
784                  final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
785                  final String[] changedPkgs = intent.getStringArrayExtra(
786                          Intent.EXTRA_CHANGED_PACKAGE_LIST);
787                  ArraySet<ModeCallback> callbacks;
788                  synchronized (AppOpsService.this) {
789                      callbacks = mOpModeWatchers.get(OP_PLAY_AUDIO);
790                      if (callbacks == null) {
791                          return;
792                      }
793                      callbacks = new ArraySet<>(callbacks);
794                  }
795                  for (int i = 0; i < changedUids.length; i++) {
796                      final int changedUid = changedUids[i];
797                      final String changedPkg = changedPkgs[i];
798                      // We trust packagemanager to insert matching uid and packageNames in the
799                      // extras
800                      notifyOpChanged(callbacks, OP_PLAY_AUDIO, changedUid, changedPkg);
801                  }
802              }
803          }, packageSuspendFilter);
804  
805          PackageManagerInternal packageManagerInternal = LocalServices.getService(
806                  PackageManagerInternal.class);
807          packageManagerInternal.setExternalSourcesPolicy(
808                  new PackageManagerInternal.ExternalSourcesPolicy() {
809                      @Override
810                      public int getPackageTrustedToInstallApps(String packageName, int uid) {
811                          int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
812                                  uid, packageName);
813                          switch (appOpMode) {
814                              case AppOpsManager.MODE_ALLOWED:
815                                  return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
816                              case AppOpsManager.MODE_ERRORED:
817                                  return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
818                              default:
819                                  return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
820                          }
821                      }
822                  });
823  
824          if (!StorageManager.hasIsolatedStorage()) {
825              StorageManagerInternal storageManagerInternal = LocalServices.getService(
826                      StorageManagerInternal.class);
827              storageManagerInternal.addExternalStoragePolicy(
828                      new StorageManagerInternal.ExternalStorageMountPolicy() {
829                          @Override
830                          public int getMountMode(int uid, String packageName) {
831                              if (Process.isIsolated(uid)) {
832                                  return Zygote.MOUNT_EXTERNAL_NONE;
833                              }
834                              if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
835                                      packageName) != AppOpsManager.MODE_ALLOWED) {
836                                  return Zygote.MOUNT_EXTERNAL_NONE;
837                              }
838                              if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
839                                      packageName) != AppOpsManager.MODE_ALLOWED) {
840                                  return Zygote.MOUNT_EXTERNAL_READ;
841                              }
842                              return Zygote.MOUNT_EXTERNAL_WRITE;
843                          }
844  
845                          @Override
846                          public boolean hasExternalStorage(int uid, String packageName) {
847                              final int mountMode = getMountMode(uid, packageName);
848                              return mountMode == Zygote.MOUNT_EXTERNAL_READ
849                                      || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
850                          }
851                      });
852          }
853      }
854  
packageRemoved(int uid, String packageName)855      public void packageRemoved(int uid, String packageName) {
856          synchronized (this) {
857              UidState uidState = mUidStates.get(uid);
858              if (uidState == null) {
859                  return;
860              }
861  
862              Ops ops = null;
863  
864              // Remove any package state if such.
865              if (uidState.pkgOps != null) {
866                  ops = uidState.pkgOps.remove(packageName);
867              }
868  
869              // If we just nuked the last package state check if the UID is valid.
870              if (ops != null && uidState.pkgOps.isEmpty()
871                      && getPackagesForUid(uid).length <= 0) {
872                  mUidStates.remove(uid);
873              }
874  
875              // Finish ops other packages started on behalf of the package.
876              final int clientCount = mClients.size();
877              for (int i = 0; i < clientCount; i++) {
878                  final ClientState client = mClients.valueAt(i);
879                  if (client.mStartedOps == null) {
880                      continue;
881                  }
882                  final int opCount = client.mStartedOps.size();
883                  for (int j = opCount - 1; j >= 0; j--) {
884                      final Op op = client.mStartedOps.get(j);
885                      if (uid == op.uidState.uid && packageName.equals(op.packageName)) {
886                          finishOperationLocked(op, /*finishNested*/ true);
887                          client.mStartedOps.remove(j);
888                          if (op.startNesting <= 0) {
889                              scheduleOpActiveChangedIfNeededLocked(op.op,
890                                      uid, packageName, false);
891                          }
892                      }
893                  }
894              }
895  
896              if (ops != null) {
897                  scheduleFastWriteLocked();
898  
899                  final int opCount = ops.size();
900                  for (int i = 0; i < opCount; i++) {
901                      final Op op = ops.valueAt(i);
902                      if (op.running) {
903                          scheduleOpActiveChangedIfNeededLocked(
904                                  op.op, op.uidState.uid, op.packageName, false);
905                      }
906                  }
907              }
908  
909              mHistoricalRegistry.clearHistory(uid, packageName);
910          }
911      }
912  
uidRemoved(int uid)913      public void uidRemoved(int uid) {
914          synchronized (this) {
915              if (mUidStates.indexOfKey(uid) >= 0) {
916                  mUidStates.remove(uid);
917                  scheduleFastWriteLocked();
918              }
919          }
920      }
921  
updateUidProcState(int uid, int procState)922      public void updateUidProcState(int uid, int procState) {
923          synchronized (this) {
924              final UidState uidState = getUidStateLocked(uid, true);
925              int newState = PROCESS_STATE_TO_UID_STATE[procState];
926              if (uidState != null && uidState.pendingState != newState) {
927                  final int oldPendingState = uidState.pendingState;
928                  uidState.pendingState = newState;
929                  if (newState < uidState.state
930                          || (newState <= UID_STATE_MAX_LAST_NON_RESTRICTED
931                                  && uidState.state > UID_STATE_MAX_LAST_NON_RESTRICTED)) {
932                      // We are moving to a more important state, or the new state may be in the
933                      // foreground and the old state is in the background, then always do it
934                      // immediately.
935                      commitUidPendingStateLocked(uidState);
936                  } else if (uidState.pendingStateCommitTime == 0) {
937                      // We are moving to a less important state for the first time,
938                      // delay the application for a bit.
939                      final long settleTime;
940                      if (uidState.state <= UID_STATE_TOP) {
941                          settleTime = mConstants.TOP_STATE_SETTLE_TIME;
942                      } else if (uidState.state <= UID_STATE_FOREGROUND_SERVICE) {
943                          settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
944                      } else {
945                          settleTime = mConstants.BG_STATE_SETTLE_TIME;
946                      }
947                      uidState.pendingStateCommitTime = SystemClock.elapsedRealtime() + settleTime;
948                  }
949                  if (uidState.startNesting != 0) {
950                      // There is some actively running operation...  need to find it
951                      // and appropriately update its state.
952                      final long now = System.currentTimeMillis();
953                      for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
954                          final Ops ops = uidState.pkgOps.valueAt(i);
955                          for (int j = ops.size() - 1; j >= 0; j--) {
956                              final Op op = ops.valueAt(j);
957                              if (op.startNesting > 0) {
958                                  final long duration = SystemClock.elapsedRealtime()
959                                          - op.startRealtime;
960                                  // We don't support proxy long running ops (start/stop)
961                                  mHistoricalRegistry.increaseOpAccessDuration(op.op,
962                                          op.uidState.uid, op.packageName, oldPendingState,
963                                          AppOpsManager.OP_FLAG_SELF, duration);
964                                  // Finish the op in the old state
965                                  op.finished(now, duration, oldPendingState,
966                                          AppOpsManager.OP_FLAG_SELF);
967                                  // Start the op in the new state
968                                  op.startRealtime = now;
969                                  op.started(now, newState, AppOpsManager.OP_FLAG_SELF);
970                              }
971                          }
972                      }
973                  }
974              }
975          }
976      }
977  
shutdown()978      public void shutdown() {
979          Slog.w(TAG, "Writing app ops before shutdown...");
980          boolean doWrite = false;
981          synchronized (this) {
982              if (mWriteScheduled) {
983                  mWriteScheduled = false;
984                  doWrite = true;
985              }
986          }
987          if (doWrite) {
988              writeState();
989          }
990      }
991  
collectOps(Ops pkgOps, int[] ops)992      private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
993          ArrayList<AppOpsManager.OpEntry> resOps = null;
994          final long elapsedNow = SystemClock.elapsedRealtime();
995          if (ops == null) {
996              resOps = new ArrayList<>();
997              for (int j=0; j<pkgOps.size(); j++) {
998                  Op curOp = pkgOps.valueAt(j);
999                  resOps.add(getOpEntryForResult(curOp, elapsedNow));
1000              }
1001          } else {
1002              for (int j=0; j<ops.length; j++) {
1003                  Op curOp = pkgOps.get(ops[j]);
1004                  if (curOp != null) {
1005                      if (resOps == null) {
1006                          resOps = new ArrayList<>();
1007                      }
1008                      resOps.add(getOpEntryForResult(curOp, elapsedNow));
1009                  }
1010              }
1011          }
1012          return resOps;
1013      }
1014  
collectOps(SparseIntArray uidOps, int[] ops)1015      private ArrayList<AppOpsManager.OpEntry> collectOps(SparseIntArray uidOps, int[] ops) {
1016          if (uidOps == null) {
1017              return null;
1018          }
1019          ArrayList<AppOpsManager.OpEntry> resOps = null;
1020          if (ops == null) {
1021              resOps = new ArrayList<>();
1022              for (int j=0; j<uidOps.size(); j++) {
1023                  resOps.add(new OpEntry(uidOps.keyAt(j), uidOps.valueAt(j)));
1024              }
1025          } else {
1026              for (int j=0; j<ops.length; j++) {
1027                  int index = uidOps.indexOfKey(ops[j]);
1028                  if (index >= 0) {
1029                      if (resOps == null) {
1030                          resOps = new ArrayList<>();
1031                      }
1032                      resOps.add(new OpEntry(uidOps.keyAt(j), uidOps.valueAt(j)));
1033                  }
1034              }
1035          }
1036          return resOps;
1037      }
1038  
getOpEntryForResult(@onNull Op op, long elapsedNow)1039      private static @NonNull OpEntry getOpEntryForResult(@NonNull Op op, long elapsedNow) {
1040          if (op.running) {
1041              op.continuing(elapsedNow - op.startRealtime,
1042                  op.uidState.state, AppOpsManager.OP_FLAG_SELF);
1043          }
1044          final OpEntry entry = new OpEntry(op.op, op.running, op.mode,
1045              op.mAccessTimes != null ? op.mAccessTimes.clone() : null,
1046              op.mRejectTimes != null ? op.mRejectTimes.clone() : null,
1047              op.mDurations != null ? op.mDurations.clone() : null,
1048              op.mProxyUids != null ? op.mProxyUids.clone() : null,
1049              op.mProxyPackageNames != null ? op.mProxyPackageNames.clone() : null);
1050          return entry;
1051      }
1052  
1053      @Override
getPackagesForOps(int[] ops)1054      public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
1055          mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1056                  Binder.getCallingPid(), Binder.getCallingUid(), null);
1057          ArrayList<AppOpsManager.PackageOps> res = null;
1058          synchronized (this) {
1059              final int uidStateCount = mUidStates.size();
1060              for (int i = 0; i < uidStateCount; i++) {
1061                  UidState uidState = mUidStates.valueAt(i);
1062                  if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
1063                      continue;
1064                  }
1065                  ArrayMap<String, Ops> packages = uidState.pkgOps;
1066                  final int packageCount = packages.size();
1067                  for (int j = 0; j < packageCount; j++) {
1068                      Ops pkgOps = packages.valueAt(j);
1069                      ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
1070                      if (resOps != null) {
1071                          if (res == null) {
1072                              res = new ArrayList<AppOpsManager.PackageOps>();
1073                          }
1074                          AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
1075                                  pkgOps.packageName, pkgOps.uidState.uid, resOps);
1076                          res.add(resPackage);
1077                      }
1078                  }
1079              }
1080          }
1081          return res;
1082      }
1083  
1084      @Override
getOpsForPackage(int uid, String packageName, int[] ops)1085      public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
1086              int[] ops) {
1087          mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1088                  Binder.getCallingPid(), Binder.getCallingUid(), null);
1089          String resolvedPackageName = resolvePackageName(uid, packageName);
1090          if (resolvedPackageName == null) {
1091              return Collections.emptyList();
1092          }
1093          synchronized (this) {
1094              Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
1095                      false /* uidMismatchExpected */);
1096              if (pkgOps == null) {
1097                  return null;
1098              }
1099              ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
1100              if (resOps == null) {
1101                  return null;
1102              }
1103              ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
1104              AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
1105                      pkgOps.packageName, pkgOps.uidState.uid, resOps);
1106              res.add(resPackage);
1107              return res;
1108          }
1109      }
1110  
1111      @Override
getHistoricalOps(int uid, @NonNull String packageName, @Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis, @OpFlags int flags, @NonNull RemoteCallback callback)1112      public void getHistoricalOps(int uid, @NonNull String packageName,
1113              @Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis,
1114              @OpFlags int flags, @NonNull RemoteCallback callback) {
1115          // Use the builder to validate arguments.
1116          new HistoricalOpsRequest.Builder(
1117                  beginTimeMillis, endTimeMillis)
1118                  .setUid(uid)
1119                  .setPackageName(packageName)
1120                  .setOpNames(opNames)
1121                  .setFlags(flags)
1122                  .build();
1123          Preconditions.checkNotNull(callback, "callback cannot be null");
1124  
1125          mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1126                  Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
1127  
1128          final String[] opNamesArray = (opNames != null)
1129                  ? opNames.toArray(new String[opNames.size()]) : null;
1130  
1131          // Must not hold the appops lock
1132          mHistoricalRegistry.getHistoricalOps(uid, packageName, opNamesArray,
1133                  beginTimeMillis, endTimeMillis, flags, callback);
1134      }
1135  
1136      @Override
getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName, @Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis, @OpFlags int flags, @NonNull RemoteCallback callback)1137      public void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
1138              @Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis,
1139              @OpFlags int flags, @NonNull RemoteCallback callback) {
1140          // Use the builder to validate arguments.
1141          new HistoricalOpsRequest.Builder(
1142                  beginTimeMillis, endTimeMillis)
1143                  .setUid(uid)
1144                  .setPackageName(packageName)
1145                  .setOpNames(opNames)
1146                  .setFlags(flags)
1147                  .build();
1148          Preconditions.checkNotNull(callback, "callback cannot be null");
1149  
1150          mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
1151                  Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
1152  
1153          final String[] opNamesArray = (opNames != null)
1154                  ? opNames.toArray(new String[opNames.size()]) : null;
1155  
1156          // Must not hold the appops lock
1157          mHistoricalRegistry.getHistoricalOpsFromDiskRaw(uid, packageName, opNamesArray,
1158                  beginTimeMillis, endTimeMillis, flags, callback);
1159      }
1160  
1161      @Override
reloadNonHistoricalState()1162      public void reloadNonHistoricalState() {
1163          mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
1164                  Binder.getCallingPid(), Binder.getCallingUid(), "reloadNonHistoricalState");
1165          writeState();
1166          readState();
1167      }
1168  
1169      @Override
getUidOps(int uid, int[] ops)1170      public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
1171          mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1172                  Binder.getCallingPid(), Binder.getCallingUid(), null);
1173          synchronized (this) {
1174              UidState uidState = getUidStateLocked(uid, false);
1175              if (uidState == null) {
1176                  return null;
1177              }
1178              ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState.opModes, ops);
1179              if (resOps == null) {
1180                  return null;
1181              }
1182              ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
1183              AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
1184                      null, uidState.uid, resOps);
1185              res.add(resPackage);
1186              return res;
1187          }
1188      }
1189  
pruneOp(Op op, int uid, String packageName)1190      private void pruneOp(Op op, int uid, String packageName) {
1191          if (!op.hasAnyTime()) {
1192              Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
1193                      false /* uidMismatchExpected */);
1194              if (ops != null) {
1195                  ops.remove(op.op);
1196                  if (ops.size() <= 0) {
1197                      UidState uidState = ops.uidState;
1198                      ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
1199                      if (pkgOps != null) {
1200                          pkgOps.remove(ops.packageName);
1201                          if (pkgOps.isEmpty()) {
1202                              uidState.pkgOps = null;
1203                          }
1204                          if (uidState.isDefault()) {
1205                              mUidStates.remove(uid);
1206                          }
1207                      }
1208                  }
1209              }
1210          }
1211      }
1212  
enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid)1213      private void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
1214          if (callingPid == Process.myPid()) {
1215              return;
1216          }
1217          final int callingUser = UserHandle.getUserId(callingUid);
1218          synchronized (this) {
1219              if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
1220                  if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
1221                      // Profile owners are allowed to change modes but only for apps
1222                      // within their user.
1223                      return;
1224                  }
1225              }
1226          }
1227          mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
1228                  Binder.getCallingPid(), Binder.getCallingUid(), null);
1229      }
1230  
1231      @Override
setUidMode(int code, int uid, int mode)1232      public void setUidMode(int code, int uid, int mode) {
1233          if (DEBUG) {
1234              Slog.i(TAG, "uid " + uid + " OP_" + opToName(code) + " := " + modeToName(mode)
1235                      + " by uid " + Binder.getCallingUid());
1236          }
1237  
1238          enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
1239          verifyIncomingOp(code);
1240          code = AppOpsManager.opToSwitch(code);
1241  
1242          synchronized (this) {
1243              final int defaultMode = AppOpsManager.opToDefaultMode(code);
1244  
1245              UidState uidState = getUidStateLocked(uid, false);
1246              if (uidState == null) {
1247                  if (mode == defaultMode) {
1248                      return;
1249                  }
1250                  uidState = new UidState(uid);
1251                  uidState.opModes = new SparseIntArray();
1252                  uidState.opModes.put(code, mode);
1253                  mUidStates.put(uid, uidState);
1254                  scheduleWriteLocked();
1255              } else if (uidState.opModes == null) {
1256                  if (mode != defaultMode) {
1257                      uidState.opModes = new SparseIntArray();
1258                      uidState.opModes.put(code, mode);
1259                      scheduleWriteLocked();
1260                  }
1261              } else {
1262                  if (uidState.opModes.indexOfKey(code) >= 0 && uidState.opModes.get(code) == mode) {
1263                      return;
1264                  }
1265                  if (mode == defaultMode) {
1266                      uidState.opModes.delete(code);
1267                      if (uidState.opModes.size() <= 0) {
1268                          uidState.opModes = null;
1269                      }
1270                  } else {
1271                      uidState.opModes.put(code, mode);
1272                  }
1273                  scheduleWriteLocked();
1274              }
1275              uidState.evalForegroundOps(mOpModeWatchers);
1276          }
1277  
1278          String[] uidPackageNames = getPackagesForUid(uid);
1279          ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
1280  
1281          synchronized (this) {
1282              ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
1283              if (callbacks != null) {
1284                  final int callbackCount = callbacks.size();
1285                  for (int i = 0; i < callbackCount; i++) {
1286                      ModeCallback callback = callbacks.valueAt(i);
1287                      ArraySet<String> changedPackages = new ArraySet<>();
1288                      Collections.addAll(changedPackages, uidPackageNames);
1289                      if (callbackSpecs == null) {
1290                          callbackSpecs = new ArrayMap<>();
1291                      }
1292                      callbackSpecs.put(callback, changedPackages);
1293                  }
1294              }
1295  
1296              for (String uidPackageName : uidPackageNames) {
1297                  callbacks = mPackageModeWatchers.get(uidPackageName);
1298                  if (callbacks != null) {
1299                      if (callbackSpecs == null) {
1300                          callbackSpecs = new ArrayMap<>();
1301                      }
1302                      final int callbackCount = callbacks.size();
1303                      for (int i = 0; i < callbackCount; i++) {
1304                          ModeCallback callback = callbacks.valueAt(i);
1305                          ArraySet<String> changedPackages = callbackSpecs.get(callback);
1306                          if (changedPackages == null) {
1307                              changedPackages = new ArraySet<>();
1308                              callbackSpecs.put(callback, changedPackages);
1309                          }
1310                          changedPackages.add(uidPackageName);
1311                      }
1312                  }
1313              }
1314          }
1315  
1316          if (callbackSpecs == null) {
1317              notifyOpChangedSync(code, uid, null, mode);
1318              return;
1319          }
1320  
1321          for (int i = 0; i < callbackSpecs.size(); i++) {
1322              final ModeCallback callback = callbackSpecs.keyAt(i);
1323              final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
1324              if (reportedPackageNames == null) {
1325                  mHandler.sendMessage(PooledLambda.obtainMessage(
1326                          AppOpsService::notifyOpChanged,
1327                          this, callback, code, uid, (String) null));
1328  
1329              } else {
1330                  final int reportedPackageCount = reportedPackageNames.size();
1331                  for (int j = 0; j < reportedPackageCount; j++) {
1332                      final String reportedPackageName = reportedPackageNames.valueAt(j);
1333                      mHandler.sendMessage(PooledLambda.obtainMessage(
1334                              AppOpsService::notifyOpChanged,
1335                              this, callback, code, uid, reportedPackageName));
1336                  }
1337              }
1338          }
1339  
1340          notifyOpChangedSync(code, uid, null, mode);
1341      }
1342  
notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode)1343      private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode) {
1344          final StorageManagerInternal storageManagerInternal =
1345                  LocalServices.getService(StorageManagerInternal.class);
1346          if (storageManagerInternal != null) {
1347              storageManagerInternal.onAppOpsChanged(code, uid, packageName, mode);
1348          }
1349      }
1350  
1351      /**
1352       * Set all {@link #setMode (package) modes} for this uid to the default value.
1353       *
1354       * @param code The app-op
1355       * @param uid The uid
1356       */
setAllPkgModesToDefault(int code, int uid)1357      private void setAllPkgModesToDefault(int code, int uid) {
1358          synchronized (this) {
1359              UidState uidState = getUidStateLocked(uid, false);
1360              if (uidState == null) {
1361                  return;
1362              }
1363  
1364              ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
1365              if (pkgOps == null) {
1366                  return;
1367              }
1368  
1369              boolean scheduleWrite = false;
1370  
1371              int numPkgs = pkgOps.size();
1372              for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
1373                  Ops ops = pkgOps.valueAt(pkgNum);
1374  
1375                  Op op = ops.get(code);
1376                  if (op == null) {
1377                      continue;
1378                  }
1379  
1380                  int defaultMode = AppOpsManager.opToDefaultMode(code);
1381                  if (op.mode != defaultMode) {
1382                      op.mode = defaultMode;
1383                      scheduleWrite = true;
1384                  }
1385              }
1386  
1387              if (scheduleWrite) {
1388                  scheduleWriteLocked();
1389              }
1390          }
1391      }
1392  
1393      @Override
setMode(int code, int uid, String packageName, int mode)1394      public void setMode(int code, int uid, String packageName, int mode) {
1395          setMode(code, uid, packageName, mode, true, false);
1396      }
1397  
1398      /**
1399       * Sets the mode for a certain op and uid.
1400       *
1401       * @param code The op code to set
1402       * @param uid The UID for which to set
1403       * @param packageName The package for which to set
1404       * @param mode The new mode to set
1405       * @param verifyUid Iff {@code true}, check that the package name belongs to the uid
1406       * @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid ==
1407       *                     false})
1408       */
setMode(int code, int uid, @NonNull String packageName, int mode, boolean verifyUid, boolean isPrivileged)1409      private void setMode(int code, int uid, @NonNull String packageName, int mode,
1410              boolean verifyUid, boolean isPrivileged) {
1411          enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
1412          verifyIncomingOp(code);
1413          ArraySet<ModeCallback> repCbs = null;
1414          code = AppOpsManager.opToSwitch(code);
1415          synchronized (this) {
1416              UidState uidState = getUidStateLocked(uid, false);
1417              Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged);
1418              if (op != null) {
1419                  if (op.mode != mode) {
1420                      op.mode = mode;
1421                      if (uidState != null) {
1422                          uidState.evalForegroundOps(mOpModeWatchers);
1423                      }
1424                      ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
1425                      if (cbs != null) {
1426                          if (repCbs == null) {
1427                              repCbs = new ArraySet<>();
1428                          }
1429                          repCbs.addAll(cbs);
1430                      }
1431                      cbs = mPackageModeWatchers.get(packageName);
1432                      if (cbs != null) {
1433                          if (repCbs == null) {
1434                              repCbs = new ArraySet<>();
1435                          }
1436                          repCbs.addAll(cbs);
1437                      }
1438                      if (mode == AppOpsManager.opToDefaultMode(op.op)) {
1439                          // If going into the default mode, prune this op
1440                          // if there is nothing else interesting in it.
1441                          pruneOp(op, uid, packageName);
1442                      }
1443                      scheduleFastWriteLocked();
1444                  }
1445              }
1446          }
1447          if (repCbs != null) {
1448              mHandler.sendMessage(PooledLambda.obtainMessage(
1449                      AppOpsService::notifyOpChanged,
1450                      this, repCbs, code, uid, packageName));
1451          }
1452  
1453          notifyOpChangedSync(code, uid, packageName, mode);
1454      }
1455  
notifyOpChanged(ArraySet<ModeCallback> callbacks, int code, int uid, String packageName)1456      private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
1457              int uid, String packageName) {
1458          for (int i = 0; i < callbacks.size(); i++) {
1459              final ModeCallback callback = callbacks.valueAt(i);
1460              notifyOpChanged(callback, code, uid, packageName);
1461          }
1462      }
1463  
notifyOpChanged(ModeCallback callback, int code, int uid, String packageName)1464      private void notifyOpChanged(ModeCallback callback, int code,
1465              int uid, String packageName) {
1466          if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
1467              return;
1468          }
1469          // There are components watching for mode changes such as window manager
1470          // and location manager which are in our process. The callbacks in these
1471          // components may require permissions our remote caller does not have.
1472          final long identity = Binder.clearCallingIdentity();
1473          try {
1474              callback.mCallback.opChanged(code, uid, packageName);
1475          } catch (RemoteException e) {
1476              /* ignore */
1477          } finally {
1478              Binder.restoreCallingIdentity(identity);
1479          }
1480      }
1481  
addCallbacks( HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks, int op, int uid, String packageName, ArraySet<ModeCallback> cbs)1482      private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
1483              HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
1484              int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
1485          if (cbs == null) {
1486              return callbacks;
1487          }
1488          if (callbacks == null) {
1489              callbacks = new HashMap<>();
1490          }
1491          boolean duplicate = false;
1492          final int N = cbs.size();
1493          for (int i=0; i<N; i++) {
1494              ModeCallback cb = cbs.valueAt(i);
1495              ArrayList<ChangeRec> reports = callbacks.get(cb);
1496              if (reports == null) {
1497                  reports = new ArrayList<>();
1498                  callbacks.put(cb, reports);
1499              } else {
1500                  final int reportCount = reports.size();
1501                  for (int j = 0; j < reportCount; j++) {
1502                      ChangeRec report = reports.get(j);
1503                      if (report.op == op && report.pkg.equals(packageName)) {
1504                          duplicate = true;
1505                          break;
1506                      }
1507                  }
1508              }
1509              if (!duplicate) {
1510                  reports.add(new ChangeRec(op, uid, packageName));
1511              }
1512          }
1513          return callbacks;
1514      }
1515  
1516      static final class ChangeRec {
1517          final int op;
1518          final int uid;
1519          final String pkg;
1520  
ChangeRec(int _op, int _uid, String _pkg)1521          ChangeRec(int _op, int _uid, String _pkg) {
1522              op = _op;
1523              uid = _uid;
1524              pkg = _pkg;
1525          }
1526      }
1527  
1528      @Override
resetAllModes(int reqUserId, String reqPackageName)1529      public void resetAllModes(int reqUserId, String reqPackageName) {
1530          final int callingPid = Binder.getCallingPid();
1531          final int callingUid = Binder.getCallingUid();
1532          reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
1533                  true, true, "resetAllModes", null);
1534  
1535          int reqUid = -1;
1536          if (reqPackageName != null) {
1537              try {
1538                  reqUid = AppGlobals.getPackageManager().getPackageUid(
1539                          reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
1540              } catch (RemoteException e) {
1541                  /* ignore - local call */
1542              }
1543          }
1544  
1545          enforceManageAppOpsModes(callingPid, callingUid, reqUid);
1546  
1547          HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
1548          synchronized (this) {
1549              boolean changed = false;
1550              for (int i = mUidStates.size() - 1; i >= 0; i--) {
1551                  UidState uidState = mUidStates.valueAt(i);
1552  
1553                  SparseIntArray opModes = uidState.opModes;
1554                  if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
1555                      final int uidOpCount = opModes.size();
1556                      for (int j = uidOpCount - 1; j >= 0; j--) {
1557                          final int code = opModes.keyAt(j);
1558                          if (AppOpsManager.opAllowsReset(code)) {
1559                              opModes.removeAt(j);
1560                              if (opModes.size() <= 0) {
1561                                  uidState.opModes = null;
1562                              }
1563                              for (String packageName : getPackagesForUid(uidState.uid)) {
1564                                  callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
1565                                          mOpModeWatchers.get(code));
1566                                  callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
1567                                          mPackageModeWatchers.get(packageName));
1568                              }
1569                          }
1570                      }
1571                  }
1572  
1573                  if (uidState.pkgOps == null) {
1574                      continue;
1575                  }
1576  
1577                  if (reqUserId != UserHandle.USER_ALL
1578                          && reqUserId != UserHandle.getUserId(uidState.uid)) {
1579                      // Skip any ops for a different user
1580                      continue;
1581                  }
1582  
1583                  Map<String, Ops> packages = uidState.pkgOps;
1584                  Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
1585                  boolean uidChanged = false;
1586                  while (it.hasNext()) {
1587                      Map.Entry<String, Ops> ent = it.next();
1588                      String packageName = ent.getKey();
1589                      if (reqPackageName != null && !reqPackageName.equals(packageName)) {
1590                          // Skip any ops for a different package
1591                          continue;
1592                      }
1593                      Ops pkgOps = ent.getValue();
1594                      for (int j=pkgOps.size()-1; j>=0; j--) {
1595                          Op curOp = pkgOps.valueAt(j);
1596                          if (AppOpsManager.opAllowsReset(curOp.op)
1597                                  && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
1598                              curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
1599                              changed = true;
1600                              uidChanged = true;
1601                              final int uid = curOp.uidState.uid;
1602                              callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
1603                                      mOpModeWatchers.get(curOp.op));
1604                              callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
1605                                      mPackageModeWatchers.get(packageName));
1606                              if (!curOp.hasAnyTime()) {
1607                                  pkgOps.removeAt(j);
1608                              }
1609                          }
1610                      }
1611                      if (pkgOps.size() == 0) {
1612                          it.remove();
1613                      }
1614                  }
1615                  if (uidState.isDefault()) {
1616                      mUidStates.remove(uidState.uid);
1617                  }
1618                  if (uidChanged) {
1619                      uidState.evalForegroundOps(mOpModeWatchers);
1620                  }
1621              }
1622  
1623              if (changed) {
1624                  scheduleFastWriteLocked();
1625              }
1626          }
1627          if (callbacks != null) {
1628              for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
1629                  ModeCallback cb = ent.getKey();
1630                  ArrayList<ChangeRec> reports = ent.getValue();
1631                  for (int i=0; i<reports.size(); i++) {
1632                      ChangeRec rep = reports.get(i);
1633                      mHandler.sendMessage(PooledLambda.obtainMessage(
1634                              AppOpsService::notifyOpChanged,
1635                              this, cb, rep.op, rep.uid, rep.pkg));
1636                  }
1637              }
1638          }
1639      }
1640  
evalAllForegroundOpsLocked()1641      private void evalAllForegroundOpsLocked() {
1642          for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
1643              final UidState uidState = mUidStates.valueAt(uidi);
1644              if (uidState.foregroundOps != null) {
1645                  uidState.evalForegroundOps(mOpModeWatchers);
1646              }
1647          }
1648      }
1649  
1650      @Override
startWatchingMode(int op, String packageName, IAppOpsCallback callback)1651      public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
1652          startWatchingModeWithFlags(op, packageName, 0, callback);
1653      }
1654  
1655      @Override
startWatchingModeWithFlags(int op, String packageName, int flags, IAppOpsCallback callback)1656      public void startWatchingModeWithFlags(int op, String packageName, int flags,
1657              IAppOpsCallback callback) {
1658          int watchedUid = -1;
1659          final int callingUid = Binder.getCallingUid();
1660          final int callingPid = Binder.getCallingPid();
1661          // TODO: should have a privileged permission to protect this.
1662          // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require
1663          // the USAGE_STATS permission since this can provide information about when an
1664          // app is in the foreground?
1665          Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
1666                  AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
1667          if (callback == null) {
1668              return;
1669          }
1670          synchronized (this) {
1671              op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
1672              ModeCallback cb = mModeWatchers.get(callback.asBinder());
1673              if (cb == null) {
1674                  cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
1675                  mModeWatchers.put(callback.asBinder(), cb);
1676              }
1677              if (op != AppOpsManager.OP_NONE) {
1678                  ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op);
1679                  if (cbs == null) {
1680                      cbs = new ArraySet<>();
1681                      mOpModeWatchers.put(op, cbs);
1682                  }
1683                  cbs.add(cb);
1684              }
1685              if (packageName != null) {
1686                  ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
1687                  if (cbs == null) {
1688                      cbs = new ArraySet<>();
1689                      mPackageModeWatchers.put(packageName, cbs);
1690                  }
1691                  cbs.add(cb);
1692              }
1693              evalAllForegroundOpsLocked();
1694          }
1695      }
1696  
1697      @Override
stopWatchingMode(IAppOpsCallback callback)1698      public void stopWatchingMode(IAppOpsCallback callback) {
1699          if (callback == null) {
1700              return;
1701          }
1702          synchronized (this) {
1703              ModeCallback cb = mModeWatchers.remove(callback.asBinder());
1704              if (cb != null) {
1705                  cb.unlinkToDeath();
1706                  for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
1707                      ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
1708                      cbs.remove(cb);
1709                      if (cbs.size() <= 0) {
1710                          mOpModeWatchers.removeAt(i);
1711                      }
1712                  }
1713                  for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
1714                      ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
1715                      cbs.remove(cb);
1716                      if (cbs.size() <= 0) {
1717                          mPackageModeWatchers.removeAt(i);
1718                      }
1719                  }
1720              }
1721              evalAllForegroundOpsLocked();
1722          }
1723      }
1724  
1725      @Override
getToken(IBinder clientToken)1726      public IBinder getToken(IBinder clientToken) {
1727          synchronized (this) {
1728              ClientState cs = mClients.get(clientToken);
1729              if (cs == null) {
1730                  cs = new ClientState(clientToken);
1731                  mClients.put(clientToken, cs);
1732              }
1733              return cs;
1734          }
1735      }
1736  
getAppOpsServiceDelegate()1737      public CheckOpsDelegate getAppOpsServiceDelegate() {
1738          synchronized (this) {
1739              return mCheckOpsDelegate;
1740          }
1741      }
1742  
setAppOpsServiceDelegate(CheckOpsDelegate delegate)1743      public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) {
1744          synchronized (this) {
1745              mCheckOpsDelegate = delegate;
1746          }
1747      }
1748  
1749      @Override
checkOperationRaw(int code, int uid, String packageName)1750      public int checkOperationRaw(int code, int uid, String packageName) {
1751          return checkOperationInternal(code, uid, packageName, true /*raw*/);
1752      }
1753  
1754      @Override
checkOperation(int code, int uid, String packageName)1755      public int checkOperation(int code, int uid, String packageName) {
1756          return checkOperationInternal(code, uid, packageName, false /*raw*/);
1757      }
1758  
checkOperationInternal(int code, int uid, String packageName, boolean raw)1759      private int checkOperationInternal(int code, int uid, String packageName, boolean raw) {
1760          final CheckOpsDelegate delegate;
1761          synchronized (this) {
1762              delegate = mCheckOpsDelegate;
1763          }
1764          if (delegate == null) {
1765              return checkOperationImpl(code, uid, packageName, raw);
1766          }
1767          return delegate.checkOperation(code, uid, packageName, raw,
1768                      AppOpsService.this::checkOperationImpl);
1769      }
1770  
checkOperationImpl(int code, int uid, String packageName, boolean raw)1771      private int checkOperationImpl(int code, int uid, String packageName,
1772                  boolean raw) {
1773          verifyIncomingUid(uid);
1774          verifyIncomingOp(code);
1775          String resolvedPackageName = resolvePackageName(uid, packageName);
1776          if (resolvedPackageName == null) {
1777              return AppOpsManager.MODE_IGNORED;
1778          }
1779          return checkOperationUnchecked(code, uid, resolvedPackageName, raw);
1780      }
1781  
1782      /**
1783       * @see #checkOperationUnchecked(int, int, String, boolean, boolean)
1784       */
checkOperationUnchecked(int code, int uid, @NonNull String packageName, boolean raw)1785      private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
1786              boolean raw) {
1787          return checkOperationUnchecked(code, uid, packageName, raw, true);
1788      }
1789  
1790      /**
1791       * Get the mode of an app-op.
1792       *
1793       * @param code The code of the op
1794       * @param uid The uid of the package the op belongs to
1795       * @param packageName The package the op belongs to
1796       * @param raw If the raw state of eval-ed state should be checked.
1797       * @param verify If the code should check the package belongs to the uid
1798       *
1799       * @return The mode of the op
1800       */
checkOperationUnchecked(int code, int uid, @NonNull String packageName, boolean raw, boolean verify)1801      private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
1802                  boolean raw, boolean verify) {
1803          synchronized (this) {
1804              if (verify) {
1805                  checkPackage(uid, packageName);
1806              }
1807              if (isOpRestrictedLocked(uid, code, packageName)) {
1808                  return AppOpsManager.MODE_IGNORED;
1809              }
1810              code = AppOpsManager.opToSwitch(code);
1811              UidState uidState = getUidStateLocked(uid, false);
1812              if (uidState != null && uidState.opModes != null
1813                      && uidState.opModes.indexOfKey(code) >= 0) {
1814                  final int rawMode = uidState.opModes.get(code);
1815                  return raw ? rawMode : uidState.evalMode(code, rawMode);
1816              }
1817              Op op = getOpLocked(code, uid, packageName, false, verify, false);
1818              if (op == null) {
1819                  return AppOpsManager.opToDefaultMode(code);
1820              }
1821              return raw ? op.mode : op.evalMode();
1822          }
1823      }
1824  
1825      @Override
checkAudioOperation(int code, int usage, int uid, String packageName)1826      public int checkAudioOperation(int code, int usage, int uid, String packageName) {
1827          final CheckOpsDelegate delegate;
1828          synchronized (this) {
1829              delegate = mCheckOpsDelegate;
1830          }
1831          if (delegate == null) {
1832              return checkAudioOperationImpl(code, usage, uid, packageName);
1833          }
1834          return delegate.checkAudioOperation(code, usage, uid, packageName,
1835                  AppOpsService.this::checkAudioOperationImpl);
1836      }
1837  
checkAudioOperationImpl(int code, int usage, int uid, String packageName)1838      private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
1839          boolean suspended;
1840          try {
1841              suspended = isPackageSuspendedForUser(packageName, uid);
1842          } catch (IllegalArgumentException ex) {
1843              // Package not found.
1844              suspended = false;
1845          }
1846  
1847          if (suspended) {
1848              Slog.i(TAG, "Audio disabled for suspended package=" + packageName
1849                      + " for uid=" + uid);
1850              return AppOpsManager.MODE_IGNORED;
1851          }
1852  
1853          synchronized (this) {
1854              final int mode = checkRestrictionLocked(code, usage, uid, packageName);
1855              if (mode != AppOpsManager.MODE_ALLOWED) {
1856                  return mode;
1857              }
1858          }
1859          return checkOperation(code, uid, packageName);
1860      }
1861  
isPackageSuspendedForUser(String pkg, int uid)1862      private boolean isPackageSuspendedForUser(String pkg, int uid) {
1863          final long identity = Binder.clearCallingIdentity();
1864          try {
1865              return AppGlobals.getPackageManager().isPackageSuspendedForUser(
1866                      pkg, UserHandle.getUserId(uid));
1867          } catch (RemoteException re) {
1868              throw new SecurityException("Could not talk to package manager service");
1869          } finally {
1870              Binder.restoreCallingIdentity(identity);
1871          }
1872      }
1873  
checkRestrictionLocked(int code, int usage, int uid, String packageName)1874      private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
1875          final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1876          if (usageRestrictions != null) {
1877              final Restriction r = usageRestrictions.get(usage);
1878              if (r != null && !r.exceptionPackages.contains(packageName)) {
1879                  return r.mode;
1880              }
1881          }
1882          return AppOpsManager.MODE_ALLOWED;
1883      }
1884  
1885      @Override
setAudioRestriction(int code, int usage, int uid, int mode, String[] exceptionPackages)1886      public void setAudioRestriction(int code, int usage, int uid, int mode,
1887              String[] exceptionPackages) {
1888          enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
1889          verifyIncomingUid(uid);
1890          verifyIncomingOp(code);
1891          synchronized (this) {
1892              SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1893              if (usageRestrictions == null) {
1894                  usageRestrictions = new SparseArray<Restriction>();
1895                  mAudioRestrictions.put(code, usageRestrictions);
1896              }
1897              usageRestrictions.remove(usage);
1898              if (mode != AppOpsManager.MODE_ALLOWED) {
1899                  final Restriction r = new Restriction();
1900                  r.mode = mode;
1901                  if (exceptionPackages != null) {
1902                      final int N = exceptionPackages.length;
1903                      r.exceptionPackages = new ArraySet<String>(N);
1904                      for (int i = 0; i < N; i++) {
1905                          final String pkg = exceptionPackages[i];
1906                          if (pkg != null) {
1907                              r.exceptionPackages.add(pkg.trim());
1908                          }
1909                      }
1910                  }
1911                  usageRestrictions.put(usage, r);
1912              }
1913          }
1914  
1915          mHandler.sendMessage(PooledLambda.obtainMessage(
1916                  AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
1917      }
1918  
1919      @Override
checkPackage(int uid, String packageName)1920      public int checkPackage(int uid, String packageName) {
1921          Preconditions.checkNotNull(packageName);
1922          synchronized (this) {
1923              Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
1924                      true /* uidMismatchExpected */);
1925              if (ops != null) {
1926                  return AppOpsManager.MODE_ALLOWED;
1927              } else {
1928                  return AppOpsManager.MODE_ERRORED;
1929              }
1930          }
1931      }
1932  
1933      @Override
noteProxyOperation(int code, int proxyUid, String proxyPackageName, int proxiedUid, String proxiedPackageName)1934      public int noteProxyOperation(int code, int proxyUid,
1935              String proxyPackageName, int proxiedUid, String proxiedPackageName) {
1936          verifyIncomingUid(proxyUid);
1937          verifyIncomingOp(code);
1938  
1939          String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
1940          if (resolveProxyPackageName == null) {
1941              return AppOpsManager.MODE_IGNORED;
1942          }
1943  
1944          final boolean isProxyTrusted = mContext.checkPermission(
1945                  Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
1946                  == PackageManager.PERMISSION_GRANTED;
1947  
1948          final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
1949                  : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
1950          final int proxyMode = noteOperationUnchecked(code, proxyUid,
1951                  resolveProxyPackageName, Process.INVALID_UID, null, proxyFlags);
1952          if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
1953              return proxyMode;
1954          }
1955  
1956          String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
1957          if (resolveProxiedPackageName == null) {
1958              return AppOpsManager.MODE_IGNORED;
1959          }
1960          final int proxiedFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXIED
1961                  : AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED;
1962          return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
1963                  proxyUid, resolveProxyPackageName, proxiedFlags);
1964      }
1965  
1966      @Override
noteOperation(int code, int uid, String packageName)1967      public int noteOperation(int code, int uid, String packageName) {
1968          final CheckOpsDelegate delegate;
1969          synchronized (this) {
1970              delegate = mCheckOpsDelegate;
1971          }
1972          if (delegate == null) {
1973              return noteOperationImpl(code, uid, packageName);
1974          }
1975          return delegate.noteOperation(code, uid, packageName,
1976                  AppOpsService.this::noteOperationImpl);
1977      }
1978  
noteOperationImpl(int code, int uid, String packageName)1979      private int noteOperationImpl(int code, int uid, String packageName) {
1980          verifyIncomingUid(uid);
1981          verifyIncomingOp(code);
1982          String resolvedPackageName = resolvePackageName(uid, packageName);
1983          if (resolvedPackageName == null) {
1984              return AppOpsManager.MODE_IGNORED;
1985          }
1986          return noteOperationUnchecked(code, uid, resolvedPackageName, Process.INVALID_UID, null,
1987                  AppOpsManager.OP_FLAG_SELF);
1988      }
1989  
noteOperationUnchecked(int code, int uid, String packageName, int proxyUid, String proxyPackageName, @OpFlags int flags)1990      private int noteOperationUnchecked(int code, int uid, String packageName,
1991              int proxyUid, String proxyPackageName, @OpFlags int flags) {
1992          synchronized (this) {
1993              final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
1994                      false /* uidMismatchExpected */);
1995              if (ops == null) {
1996                  scheduleOpNotedIfNeededLocked(code, uid, packageName,
1997                          AppOpsManager.MODE_IGNORED);
1998                  if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
1999                          + " package " + packageName);
2000                  return AppOpsManager.MODE_ERRORED;
2001              }
2002              final Op op = getOpLocked(ops, code, true);
2003              if (isOpRestrictedLocked(uid, code, packageName)) {
2004                  scheduleOpNotedIfNeededLocked(code, uid, packageName,
2005                          AppOpsManager.MODE_IGNORED);
2006                  return AppOpsManager.MODE_IGNORED;
2007              }
2008              final UidState uidState = ops.uidState;
2009              if (op.running) {
2010                  final OpEntry entry = new OpEntry(op.op, op.running, op.mode, op.mAccessTimes,
2011                      op.mRejectTimes, op.mDurations, op.mProxyUids, op.mProxyPackageNames);
2012                  Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
2013                          + " code " + code + " time=" + entry.getLastAccessTime(uidState.state,
2014                          uidState.state, flags) + " duration=" + entry.getLastDuration(
2015                                  uidState.state, uidState.state, flags));
2016              }
2017  
2018              final int switchCode = AppOpsManager.opToSwitch(code);
2019              // If there is a non-default per UID policy (we set UID op mode only if
2020              // non-default) it takes over, otherwise use the per package policy.
2021              if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
2022                  final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode));
2023                  if (uidMode != AppOpsManager.MODE_ALLOWED) {
2024                      if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
2025                              + switchCode + " (" + code + ") uid " + uid + " package "
2026                              + packageName);
2027                      op.rejected(System.currentTimeMillis(), proxyUid, proxyPackageName,
2028                              uidState.state, flags);
2029                      mHistoricalRegistry.incrementOpRejected(code, uid, packageName,
2030                              uidState.state, flags);
2031                      scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode);
2032                      return uidMode;
2033                  }
2034              } else {
2035                  final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
2036                  final int mode = switchOp.evalMode();
2037                  if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
2038                      if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
2039                              + switchCode + " (" + code + ") uid " + uid + " package "
2040                              + packageName);
2041                      op.rejected(System.currentTimeMillis(), proxyUid, proxyPackageName,
2042                              uidState.state, flags);
2043                      mHistoricalRegistry.incrementOpRejected(code, uid, packageName,
2044                              uidState.state, flags);
2045                      scheduleOpNotedIfNeededLocked(code, uid, packageName, mode);
2046                      return mode;
2047                  }
2048              }
2049              if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
2050                      + " package " + packageName);
2051              op.accessed(System.currentTimeMillis(), proxyUid, proxyPackageName,
2052                      uidState.state, flags);
2053              mHistoricalRegistry.incrementOpAccessedCount(op.op, uid, packageName,
2054                      uidState.state, flags);
2055              scheduleOpNotedIfNeededLocked(code, uid, packageName,
2056                      AppOpsManager.MODE_ALLOWED);
2057              return AppOpsManager.MODE_ALLOWED;
2058          }
2059      }
2060  
2061      @Override
startWatchingActive(int[] ops, IAppOpsActiveCallback callback)2062      public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
2063          int watchedUid = -1;
2064          final int callingUid = Binder.getCallingUid();
2065          final int callingPid = Binder.getCallingPid();
2066          if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
2067                  != PackageManager.PERMISSION_GRANTED) {
2068              watchedUid = callingUid;
2069          }
2070          if (ops != null) {
2071              Preconditions.checkArrayElementsInRange(ops, 0,
2072                      AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
2073          }
2074          if (callback == null) {
2075              return;
2076          }
2077          synchronized (this) {
2078              SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
2079              if (callbacks == null) {
2080                  callbacks = new SparseArray<>();
2081                  mActiveWatchers.put(callback.asBinder(), callbacks);
2082              }
2083              final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
2084                      callingUid, callingPid);
2085              for (int op : ops) {
2086                  callbacks.put(op, activeCallback);
2087              }
2088          }
2089      }
2090  
2091      @Override
stopWatchingActive(IAppOpsActiveCallback callback)2092      public void stopWatchingActive(IAppOpsActiveCallback callback) {
2093          if (callback == null) {
2094              return;
2095          }
2096          synchronized (this) {
2097              final SparseArray<ActiveCallback> activeCallbacks =
2098                      mActiveWatchers.remove(callback.asBinder());
2099              if (activeCallbacks == null) {
2100                  return;
2101              }
2102              final int callbackCount = activeCallbacks.size();
2103              for (int i = 0; i < callbackCount; i++) {
2104                  activeCallbacks.valueAt(i).destroy();
2105              }
2106          }
2107      }
2108  
2109      @Override
startWatchingNoted(@onNull int[] ops, @NonNull IAppOpsNotedCallback callback)2110      public void startWatchingNoted(@NonNull int[] ops, @NonNull IAppOpsNotedCallback callback) {
2111          int watchedUid = Process.INVALID_UID;
2112          final int callingUid = Binder.getCallingUid();
2113          final int callingPid = Binder.getCallingPid();
2114          if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
2115                  != PackageManager.PERMISSION_GRANTED) {
2116              watchedUid = callingUid;
2117          }
2118          Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
2119          Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
2120                  "Invalid op code in: " + Arrays.toString(ops));
2121          Preconditions.checkNotNull(callback, "Callback cannot be null");
2122          synchronized (this) {
2123              SparseArray<NotedCallback> callbacks = mNotedWatchers.get(callback.asBinder());
2124              if (callbacks == null) {
2125                  callbacks = new SparseArray<>();
2126                  mNotedWatchers.put(callback.asBinder(), callbacks);
2127              }
2128              final NotedCallback notedCallback = new NotedCallback(callback, watchedUid,
2129                      callingUid, callingPid);
2130              for (int op : ops) {
2131                  callbacks.put(op, notedCallback);
2132              }
2133          }
2134      }
2135  
2136      @Override
stopWatchingNoted(IAppOpsNotedCallback callback)2137      public void stopWatchingNoted(IAppOpsNotedCallback callback) {
2138          Preconditions.checkNotNull(callback, "Callback cannot be null");
2139          synchronized (this) {
2140              final SparseArray<NotedCallback> notedCallbacks =
2141                      mNotedWatchers.remove(callback.asBinder());
2142              if (notedCallbacks == null) {
2143                  return;
2144              }
2145              final int callbackCount = notedCallbacks.size();
2146              for (int i = 0; i < callbackCount; i++) {
2147                  notedCallbacks.valueAt(i).destroy();
2148              }
2149          }
2150      }
2151  
2152      @Override
startOperation(IBinder token, int code, int uid, String packageName, boolean startIfModeDefault)2153      public int startOperation(IBinder token, int code, int uid, String packageName,
2154              boolean startIfModeDefault) {
2155          verifyIncomingUid(uid);
2156          verifyIncomingOp(code);
2157          String resolvedPackageName = resolvePackageName(uid, packageName);
2158          if (resolvedPackageName == null) {
2159              return  AppOpsManager.MODE_IGNORED;
2160          }
2161          ClientState client = (ClientState)token;
2162          synchronized (this) {
2163              final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
2164                      false /* uidMismatchExpected */);
2165              if (ops == null) {
2166                  if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
2167                          + " package " + resolvedPackageName);
2168                  return AppOpsManager.MODE_ERRORED;
2169              }
2170              final Op op = getOpLocked(ops, code, true);
2171              if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
2172                  return AppOpsManager.MODE_IGNORED;
2173              }
2174              final int switchCode = AppOpsManager.opToSwitch(code);
2175              final UidState uidState = ops.uidState;
2176              // If there is a non-default per UID policy (we set UID op mode only if
2177              // non-default) it takes over, otherwise use the per package policy.
2178              final int opCode = op.op;
2179              if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
2180                  final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode));
2181                  if (uidMode != AppOpsManager.MODE_ALLOWED
2182                          && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
2183                      if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
2184                              + switchCode + " (" + code + ") uid " + uid + " package "
2185                              + resolvedPackageName);
2186                      // We don't support proxy long running ops (start/stop)
2187                      op.rejected(System.currentTimeMillis(), -1 /*proxyUid*/,
2188                              null /*proxyPackage*/, uidState.state, AppOpsManager.OP_FLAG_SELF);
2189                      mHistoricalRegistry.incrementOpRejected(opCode, uid, packageName,
2190                              uidState.state, AppOpsManager.OP_FLAG_SELF);
2191                      return uidMode;
2192                  }
2193              } else {
2194                  final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
2195                  final int mode = switchOp.evalMode();
2196                  if (mode != AppOpsManager.MODE_ALLOWED
2197                          && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
2198                      if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
2199                              + switchCode + " (" + code + ") uid " + uid + " package "
2200                              + resolvedPackageName);
2201                      // We don't support proxy long running ops (start/stop)
2202                      op.rejected(System.currentTimeMillis(), -1 /*proxyUid*/,
2203                              null /*proxyPackage*/, uidState.state, AppOpsManager.OP_FLAG_SELF);
2204                      mHistoricalRegistry.incrementOpRejected(opCode, uid, packageName,
2205                              uidState.state, AppOpsManager.OP_FLAG_SELF);
2206                      return mode;
2207                  }
2208              }
2209              if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
2210                      + " package " + resolvedPackageName);
2211              if (op.startNesting == 0) {
2212                  op.startRealtime = SystemClock.elapsedRealtime();
2213                  // We don't support proxy long running ops (start/stop)
2214                  op.started(System.currentTimeMillis(), uidState.state,
2215                          AppOpsManager.OP_FLAG_SELF);
2216                  mHistoricalRegistry.incrementOpAccessedCount(opCode, uid, packageName,
2217                          uidState.state, AppOpsManager.OP_FLAG_SELF);
2218  
2219                  scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
2220              }
2221              op.startNesting++;
2222              uidState.startNesting++;
2223              if (client.mStartedOps != null) {
2224                  client.mStartedOps.add(op);
2225              }
2226          }
2227  
2228          return AppOpsManager.MODE_ALLOWED;
2229      }
2230  
2231      @Override
finishOperation(IBinder token, int code, int uid, String packageName)2232      public void finishOperation(IBinder token, int code, int uid, String packageName) {
2233          verifyIncomingUid(uid);
2234          verifyIncomingOp(code);
2235          String resolvedPackageName = resolvePackageName(uid, packageName);
2236          if (resolvedPackageName == null) {
2237              return;
2238          }
2239          if (!(token instanceof ClientState)) {
2240              return;
2241          }
2242          ClientState client = (ClientState) token;
2243          synchronized (this) {
2244              Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false);
2245              if (op == null) {
2246                  return;
2247              }
2248              if (!client.mStartedOps.remove(op)) {
2249                  // We finish ops when packages get removed to guarantee no dangling
2250                  // started ops. However, some part of the system may asynchronously
2251                  // finish ops for an already gone package. Hence, finishing an op
2252                  // for a non existing package is fine and we don't log as a wtf.
2253                  final long identity = Binder.clearCallingIdentity();
2254                  try {
2255                      if (LocalServices.getService(PackageManagerInternal.class).getPackageUid(
2256                              resolvedPackageName, 0, UserHandle.getUserId(uid)) < 0) {
2257                          Slog.i(TAG, "Finishing op=" + AppOpsManager.opToName(code)
2258                                  + " for non-existing package=" + resolvedPackageName
2259                                  + " in uid=" + uid);
2260                          return;
2261                      }
2262                  } finally {
2263                      Binder.restoreCallingIdentity(identity);
2264                  }
2265                  Slog.wtf(TAG, "Operation not started: uid=" + op.uidState.uid + " pkg="
2266                          + op.packageName + " op=" + AppOpsManager.opToName(op.op));
2267                  return;
2268              }
2269              finishOperationLocked(op, /*finishNested*/ false);
2270              if (op.startNesting <= 0) {
2271                  scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
2272              }
2273          }
2274      }
2275  
scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName, boolean active)2276      private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
2277              boolean active) {
2278          ArraySet<ActiveCallback> dispatchedCallbacks = null;
2279          final int callbackListCount = mActiveWatchers.size();
2280          for (int i = 0; i < callbackListCount; i++) {
2281              final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
2282              ActiveCallback callback = callbacks.get(code);
2283              if (callback != null) {
2284                  if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
2285                      continue;
2286                  }
2287                  if (dispatchedCallbacks == null) {
2288                      dispatchedCallbacks = new ArraySet<>();
2289                  }
2290                  dispatchedCallbacks.add(callback);
2291              }
2292          }
2293          if (dispatchedCallbacks == null) {
2294              return;
2295          }
2296          mHandler.sendMessage(PooledLambda.obtainMessage(
2297                  AppOpsService::notifyOpActiveChanged,
2298                  this, dispatchedCallbacks, code, uid, packageName, active));
2299      }
2300  
notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks, int code, int uid, String packageName, boolean active)2301      private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
2302              int code, int uid, String packageName, boolean active) {
2303          // There are components watching for mode changes such as window manager
2304          // and location manager which are in our process. The callbacks in these
2305          // components may require permissions our remote caller does not have.
2306          final long identity = Binder.clearCallingIdentity();
2307          try {
2308              final int callbackCount = callbacks.size();
2309              for (int i = 0; i < callbackCount; i++) {
2310                  final ActiveCallback callback = callbacks.valueAt(i);
2311                  try {
2312                      callback.mCallback.opActiveChanged(code, uid, packageName, active);
2313                  } catch (RemoteException e) {
2314                      /* do nothing */
2315                  }
2316              }
2317          } finally {
2318              Binder.restoreCallingIdentity(identity);
2319          }
2320      }
2321  
scheduleOpNotedIfNeededLocked(int code, int uid, String packageName, int result)2322      private void scheduleOpNotedIfNeededLocked(int code, int uid, String packageName,
2323              int result) {
2324          ArraySet<NotedCallback> dispatchedCallbacks = null;
2325          final int callbackListCount = mNotedWatchers.size();
2326          for (int i = 0; i < callbackListCount; i++) {
2327              final SparseArray<NotedCallback> callbacks = mNotedWatchers.valueAt(i);
2328              final NotedCallback callback = callbacks.get(code);
2329              if (callback != null) {
2330                  if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
2331                      continue;
2332                  }
2333                  if (dispatchedCallbacks == null) {
2334                      dispatchedCallbacks = new ArraySet<>();
2335                  }
2336                  dispatchedCallbacks.add(callback);
2337              }
2338          }
2339          if (dispatchedCallbacks == null) {
2340              return;
2341          }
2342          mHandler.sendMessage(PooledLambda.obtainMessage(
2343                  AppOpsService::notifyOpChecked,
2344                  this, dispatchedCallbacks, code, uid, packageName, result));
2345      }
2346  
notifyOpChecked(ArraySet<NotedCallback> callbacks, int code, int uid, String packageName, int result)2347      private void notifyOpChecked(ArraySet<NotedCallback> callbacks,
2348              int code, int uid, String packageName, int result) {
2349          // There are components watching for checks in our process. The callbacks in
2350          // these components may require permissions our remote caller does not have.
2351          final long identity = Binder.clearCallingIdentity();
2352          try {
2353              final int callbackCount = callbacks.size();
2354              for (int i = 0; i < callbackCount; i++) {
2355                  final NotedCallback callback = callbacks.valueAt(i);
2356                  try {
2357                      callback.mCallback.opNoted(code, uid, packageName, result);
2358                  } catch (RemoteException e) {
2359                      /* do nothing */
2360                  }
2361              }
2362          } finally {
2363              Binder.restoreCallingIdentity(identity);
2364          }
2365      }
2366  
2367      @Override
permissionToOpCode(String permission)2368      public int permissionToOpCode(String permission) {
2369          if (permission == null) {
2370              return AppOpsManager.OP_NONE;
2371          }
2372          return AppOpsManager.permissionToOpCode(permission);
2373      }
2374  
finishOperationLocked(Op op, boolean finishNested)2375      void finishOperationLocked(Op op, boolean finishNested) {
2376          final int opCode = op.op;
2377          final int uid = op.uidState.uid;
2378          if (op.startNesting <= 1 || finishNested) {
2379              if (op.startNesting == 1 || finishNested) {
2380                  // We don't support proxy long running ops (start/stop)
2381                  final long duration = SystemClock.elapsedRealtime() - op.startRealtime;
2382                  op.finished(System.currentTimeMillis(), duration, op.uidState.state,
2383                          AppOpsManager.OP_FLAG_SELF);
2384                  mHistoricalRegistry.increaseOpAccessDuration(opCode, uid, op.packageName,
2385                          op.uidState.state, AppOpsManager.OP_FLAG_SELF, duration);
2386              } else {
2387                  final OpEntry entry = new OpEntry(op.op, op.running, op.mode, op.mAccessTimes,
2388                      op.mRejectTimes, op.mDurations, op.mProxyUids, op.mProxyPackageNames);
2389                  Slog.w(TAG, "Finishing op nesting under-run: uid " + uid + " pkg "
2390                          + op.packageName + " code " + opCode + " time="
2391                          + entry.getLastAccessTime(OP_FLAGS_ALL)
2392                          + " duration=" + entry.getLastDuration(MAX_PRIORITY_UID_STATE,
2393                          MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL) + " nesting=" + op.startNesting);
2394              }
2395              if (op.startNesting >= 1) {
2396                  op.uidState.startNesting -= op.startNesting;
2397              }
2398              op.startNesting = 0;
2399          } else {
2400              op.startNesting--;
2401              op.uidState.startNesting--;
2402          }
2403      }
2404  
verifyIncomingUid(int uid)2405      private void verifyIncomingUid(int uid) {
2406          if (uid == Binder.getCallingUid()) {
2407              return;
2408          }
2409          if (Binder.getCallingPid() == Process.myPid()) {
2410              return;
2411          }
2412          mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
2413                  Binder.getCallingPid(), Binder.getCallingUid(), null);
2414      }
2415  
verifyIncomingOp(int op)2416      private void verifyIncomingOp(int op) {
2417          if (op >= 0 && op < AppOpsManager._NUM_OP) {
2418              return;
2419          }
2420          throw new IllegalArgumentException("Bad operation #" + op);
2421      }
2422  
getUidStateLocked(int uid, boolean edit)2423      private @Nullable UidState getUidStateLocked(int uid, boolean edit) {
2424          UidState uidState = mUidStates.get(uid);
2425          if (uidState == null) {
2426              if (!edit) {
2427                  return null;
2428              }
2429              uidState = new UidState(uid);
2430              mUidStates.put(uid, uidState);
2431          } else {
2432              if (uidState.pendingStateCommitTime != 0) {
2433                  if (uidState.pendingStateCommitTime < mLastRealtime) {
2434                      commitUidPendingStateLocked(uidState);
2435                  } else {
2436                      mLastRealtime = SystemClock.elapsedRealtime();
2437                      if (uidState.pendingStateCommitTime < mLastRealtime) {
2438                          commitUidPendingStateLocked(uidState);
2439                      }
2440                  }
2441              }
2442          }
2443          return uidState;
2444      }
2445  
commitUidPendingStateLocked(UidState uidState)2446      private void commitUidPendingStateLocked(UidState uidState) {
2447          if (uidState.hasForegroundWatchers) {
2448              for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
2449                  if (!uidState.foregroundOps.valueAt(fgi)) {
2450                      continue;
2451                  }
2452                  final int code = uidState.foregroundOps.keyAt(fgi);
2453                  // For location ops we consider fg state only if the fg service
2454                  // is of location type, for all other ops any fg service will do.
2455                  final long firstUnrestrictedUidState = resolveFirstUnrestrictedUidState(code);
2456                  final boolean resolvedLastFg = uidState.state <= firstUnrestrictedUidState;
2457                  final boolean resolvedNowFg = uidState.pendingState <= firstUnrestrictedUidState;
2458                  if (resolvedLastFg == resolvedNowFg) {
2459                      continue;
2460                  }
2461                  final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
2462                  if (callbacks != null) {
2463                      for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
2464                          final ModeCallback callback = callbacks.valueAt(cbi);
2465                          if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
2466                                  || !callback.isWatchingUid(uidState.uid)) {
2467                              continue;
2468                          }
2469                          boolean doAllPackages = uidState.opModes != null
2470                                  && uidState.opModes.indexOfKey(code) >= 0
2471                                  && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
2472                          if (uidState.pkgOps != null) {
2473                              for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
2474                                  final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
2475                                  if (op == null) {
2476                                      continue;
2477                                  }
2478                                  if (doAllPackages || op.mode == AppOpsManager.MODE_FOREGROUND) {
2479                                      mHandler.sendMessage(PooledLambda.obtainMessage(
2480                                              AppOpsService::notifyOpChanged,
2481                                              this, callback, code, uidState.uid,
2482                                              uidState.pkgOps.keyAt(pkgi)));
2483                                  }
2484                              }
2485                          }
2486                      }
2487                  }
2488              }
2489          }
2490          uidState.state = uidState.pendingState;
2491          uidState.pendingStateCommitTime = 0;
2492      }
2493  
getOpsRawLocked(int uid, String packageName, boolean edit, boolean uidMismatchExpected)2494      private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
2495              boolean uidMismatchExpected) {
2496          UidState uidState = getUidStateLocked(uid, edit);
2497          if (uidState == null) {
2498              return null;
2499          }
2500  
2501          if (uidState.pkgOps == null) {
2502              if (!edit) {
2503                  return null;
2504              }
2505              uidState.pkgOps = new ArrayMap<>();
2506          }
2507  
2508          Ops ops = uidState.pkgOps.get(packageName);
2509          if (ops == null) {
2510              if (!edit) {
2511                  return null;
2512              }
2513              boolean isPrivileged = false;
2514              // This is the first time we have seen this package name under this uid,
2515              // so let's make sure it is valid.
2516              if (uid != 0) {
2517                  final long ident = Binder.clearCallingIdentity();
2518                  try {
2519                      int pkgUid = -1;
2520                      try {
2521                          ApplicationInfo appInfo = ActivityThread.getPackageManager()
2522                                  .getApplicationInfo(packageName,
2523                                          PackageManager.MATCH_DIRECT_BOOT_AWARE
2524                                                  | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
2525                                          UserHandle.getUserId(uid));
2526                          if (appInfo != null) {
2527                              pkgUid = appInfo.uid;
2528                              isPrivileged = (appInfo.privateFlags
2529                                      & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
2530                          } else {
2531                              pkgUid = resolveUid(packageName);
2532                              if (pkgUid >= 0) {
2533                                  isPrivileged = false;
2534                              }
2535                          }
2536                      } catch (RemoteException e) {
2537                          Slog.w(TAG, "Could not contact PackageManager", e);
2538                      }
2539                      if (pkgUid != uid) {
2540                          // Oops!  The package name is not valid for the uid they are calling
2541                          // under.  Abort.
2542                          if (!uidMismatchExpected) {
2543                              RuntimeException ex = new RuntimeException("here");
2544                              ex.fillInStackTrace();
2545                              Slog.w(TAG, "Bad call: specified package " + packageName
2546                                      + " under uid " + uid + " but it is really " + pkgUid, ex);
2547                          }
2548                          return null;
2549                      }
2550                  } finally {
2551                      Binder.restoreCallingIdentity(ident);
2552                  }
2553              }
2554              ops = new Ops(packageName, uidState, isPrivileged);
2555              uidState.pkgOps.put(packageName, ops);
2556          }
2557          return ops;
2558      }
2559  
2560      /**
2561       * Get the state of all ops for a package, <b>don't verify that package belongs to uid</b>.
2562       *
2563       * <p>Usually callers should use {@link #getOpLocked} and not call this directly.
2564       *
2565       * @param uid The uid the of the package
2566       * @param packageName The package name for which to get the state for
2567       * @param edit Iff {@code true} create the {@link Ops} object if not yet created
2568       * @param isPrivileged Whether the package is privileged or not
2569       *
2570       * @return The {@link Ops state} of all ops for the package
2571       */
getOpsRawNoVerifyLocked(int uid, @NonNull String packageName, boolean edit, boolean isPrivileged)2572      private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
2573              boolean edit, boolean isPrivileged) {
2574          UidState uidState = getUidStateLocked(uid, edit);
2575          if (uidState == null) {
2576              return null;
2577          }
2578  
2579          if (uidState.pkgOps == null) {
2580              if (!edit) {
2581                  return null;
2582              }
2583              uidState.pkgOps = new ArrayMap<>();
2584          }
2585  
2586          Ops ops = uidState.pkgOps.get(packageName);
2587          if (ops == null) {
2588              if (!edit) {
2589                  return null;
2590              }
2591              ops = new Ops(packageName, uidState, isPrivileged);
2592              uidState.pkgOps.put(packageName, ops);
2593          }
2594          return ops;
2595      }
2596  
scheduleWriteLocked()2597      private void scheduleWriteLocked() {
2598          if (!mWriteScheduled) {
2599              mWriteScheduled = true;
2600              mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
2601          }
2602      }
2603  
scheduleFastWriteLocked()2604      private void scheduleFastWriteLocked() {
2605          if (!mFastWriteScheduled) {
2606              mWriteScheduled = true;
2607              mFastWriteScheduled = true;
2608              mHandler.removeCallbacks(mWriteRunner);
2609              mHandler.postDelayed(mWriteRunner, 10*1000);
2610          }
2611      }
2612  
2613      /**
2614       * Get the state of an op for a uid.
2615       *
2616       * @param code The code of the op
2617       * @param uid The uid the of the package
2618       * @param packageName The package name for which to get the state for
2619       * @param edit Iff {@code true} create the {@link Op} object if not yet created
2620       * @param verifyUid Iff {@code true} check that the package belongs to the uid
2621       * @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid
2622       *                     == false})
2623       *
2624       * @return The {@link Op state} of the op
2625       */
getOpLocked(int code, int uid, @NonNull String packageName, boolean edit, boolean verifyUid, boolean isPrivileged)2626      private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit,
2627              boolean verifyUid, boolean isPrivileged) {
2628          Ops ops;
2629  
2630          if (verifyUid) {
2631              ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */);
2632          }  else {
2633              ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
2634          }
2635  
2636          if (ops == null) {
2637              return null;
2638          }
2639          return getOpLocked(ops, code, edit);
2640      }
2641  
getOpLocked(Ops ops, int code, boolean edit)2642      private Op getOpLocked(Ops ops, int code, boolean edit) {
2643          Op op = ops.get(code);
2644          if (op == null) {
2645              if (!edit) {
2646                  return null;
2647              }
2648              op = new Op(ops.uidState, ops.packageName, code);
2649              ops.put(code, op);
2650          }
2651          if (edit) {
2652              scheduleWriteLocked();
2653          }
2654          return op;
2655      }
2656  
isOpRestrictedLocked(int uid, int code, String packageName)2657      private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
2658          int userHandle = UserHandle.getUserId(uid);
2659          final int restrictionSetCount = mOpUserRestrictions.size();
2660  
2661          for (int i = 0; i < restrictionSetCount; i++) {
2662              // For each client, check that the given op is not restricted, or that the given
2663              // package is exempt from the restriction.
2664              ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
2665              if (restrictionState.hasRestriction(code, packageName, userHandle)) {
2666                  if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
2667                      // If we are the system, bypass user restrictions for certain codes
2668                      synchronized (this) {
2669                          Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
2670                                  false /* uidMismatchExpected */);
2671                          if ((ops != null) && ops.isPrivileged) {
2672                              return false;
2673                          }
2674                      }
2675                  }
2676                  return true;
2677              }
2678          }
2679          return false;
2680      }
2681  
readState()2682      void readState() {
2683          int oldVersion = NO_VERSION;
2684          synchronized (mFile) {
2685              synchronized (this) {
2686                  FileInputStream stream;
2687                  try {
2688                      stream = mFile.openRead();
2689                  } catch (FileNotFoundException e) {
2690                      Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
2691                      return;
2692                  }
2693                  boolean success = false;
2694                  mUidStates.clear();
2695                  try {
2696                      XmlPullParser parser = Xml.newPullParser();
2697                      parser.setInput(stream, StandardCharsets.UTF_8.name());
2698                      int type;
2699                      while ((type = parser.next()) != XmlPullParser.START_TAG
2700                              && type != XmlPullParser.END_DOCUMENT) {
2701                          ;
2702                      }
2703  
2704                      if (type != XmlPullParser.START_TAG) {
2705                          throw new IllegalStateException("no start tag found");
2706                      }
2707  
2708                      final String versionString = parser.getAttributeValue(null, "v");
2709                      if (versionString != null) {
2710                          oldVersion = Integer.parseInt(versionString);
2711                      }
2712  
2713                      int outerDepth = parser.getDepth();
2714                      while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2715                              && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2716                          if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2717                              continue;
2718                          }
2719  
2720                          String tagName = parser.getName();
2721                          if (tagName.equals("pkg")) {
2722                              readPackage(parser);
2723                          } else if (tagName.equals("uid")) {
2724                              readUidOps(parser);
2725                          } else {
2726                              Slog.w(TAG, "Unknown element under <app-ops>: "
2727                                      + parser.getName());
2728                              XmlUtils.skipCurrentTag(parser);
2729                          }
2730                      }
2731                      success = true;
2732                  } catch (IllegalStateException e) {
2733                      Slog.w(TAG, "Failed parsing " + e);
2734                  } catch (NullPointerException e) {
2735                      Slog.w(TAG, "Failed parsing " + e);
2736                  } catch (NumberFormatException e) {
2737                      Slog.w(TAG, "Failed parsing " + e);
2738                  } catch (XmlPullParserException e) {
2739                      Slog.w(TAG, "Failed parsing " + e);
2740                  } catch (IOException e) {
2741                      Slog.w(TAG, "Failed parsing " + e);
2742                  } catch (IndexOutOfBoundsException e) {
2743                      Slog.w(TAG, "Failed parsing " + e);
2744                  } finally {
2745                      if (!success) {
2746                          mUidStates.clear();
2747                      }
2748                      try {
2749                          stream.close();
2750                      } catch (IOException e) {
2751                      }
2752                  }
2753              }
2754          }
2755          synchronized (this) {
2756              upgradeLocked(oldVersion);
2757          }
2758      }
2759  
upgradeRunAnyInBackgroundLocked()2760      private void upgradeRunAnyInBackgroundLocked() {
2761          for (int i = 0; i < mUidStates.size(); i++) {
2762              final UidState uidState = mUidStates.valueAt(i);
2763              if (uidState == null) {
2764                  continue;
2765              }
2766              if (uidState.opModes != null) {
2767                  final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
2768                  if (idx >= 0) {
2769                      uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
2770                          uidState.opModes.valueAt(idx));
2771                  }
2772              }
2773              if (uidState.pkgOps == null) {
2774                  continue;
2775              }
2776              boolean changed = false;
2777              for (int j = 0; j < uidState.pkgOps.size(); j++) {
2778                  Ops ops = uidState.pkgOps.valueAt(j);
2779                  if (ops != null) {
2780                      final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
2781                      if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
2782                          final Op copy = new Op(op.uidState, op.packageName,
2783                              AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
2784                          copy.mode = op.mode;
2785                          ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
2786                          changed = true;
2787                      }
2788                  }
2789              }
2790              if (changed) {
2791                  uidState.evalForegroundOps(mOpModeWatchers);
2792              }
2793          }
2794      }
2795  
upgradeLocked(int oldVersion)2796      private void upgradeLocked(int oldVersion) {
2797          if (oldVersion >= CURRENT_VERSION) {
2798              return;
2799          }
2800          Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
2801          switch (oldVersion) {
2802              case NO_VERSION:
2803                  upgradeRunAnyInBackgroundLocked();
2804                  // fall through
2805              case 1:
2806                  // for future upgrades
2807          }
2808          scheduleFastWriteLocked();
2809      }
2810  
readUidOps(XmlPullParser parser)2811      private void readUidOps(XmlPullParser parser) throws NumberFormatException,
2812              XmlPullParserException, IOException {
2813          final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
2814          int outerDepth = parser.getDepth();
2815          int type;
2816          while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2817                  && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2818              if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2819                  continue;
2820              }
2821  
2822              String tagName = parser.getName();
2823              if (tagName.equals("op")) {
2824                  final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
2825                  final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
2826                  UidState uidState = getUidStateLocked(uid, true);
2827                  if (uidState.opModes == null) {
2828                      uidState.opModes = new SparseIntArray();
2829                  }
2830                  uidState.opModes.put(code, mode);
2831              } else {
2832                  Slog.w(TAG, "Unknown element under <uid-ops>: "
2833                          + parser.getName());
2834                  XmlUtils.skipCurrentTag(parser);
2835              }
2836          }
2837      }
2838  
readPackage(XmlPullParser parser)2839      private void readPackage(XmlPullParser parser)
2840              throws NumberFormatException, XmlPullParserException, IOException {
2841          String pkgName = parser.getAttributeValue(null, "n");
2842          int outerDepth = parser.getDepth();
2843          int type;
2844          while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2845                  && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2846              if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2847                  continue;
2848              }
2849  
2850              String tagName = parser.getName();
2851              if (tagName.equals("uid")) {
2852                  readUid(parser, pkgName);
2853              } else {
2854                  Slog.w(TAG, "Unknown element under <pkg>: "
2855                          + parser.getName());
2856                  XmlUtils.skipCurrentTag(parser);
2857              }
2858          }
2859      }
2860  
readUid(XmlPullParser parser, String pkgName)2861      private void readUid(XmlPullParser parser, String pkgName)
2862              throws NumberFormatException, XmlPullParserException, IOException {
2863          int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
2864          final UidState uidState = getUidStateLocked(uid, true);
2865          String isPrivilegedString = parser.getAttributeValue(null, "p");
2866          boolean isPrivileged = false;
2867          if (isPrivilegedString == null) {
2868              try {
2869                  IPackageManager packageManager = ActivityThread.getPackageManager();
2870                  if (packageManager != null) {
2871                      ApplicationInfo appInfo = ActivityThread.getPackageManager()
2872                              .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
2873                      if (appInfo != null) {
2874                          isPrivileged = (appInfo.privateFlags
2875                                  & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
2876                      }
2877                  } else {
2878                      // Could not load data, don't add to cache so it will be loaded later.
2879                      return;
2880                  }
2881              } catch (RemoteException e) {
2882                  Slog.w(TAG, "Could not contact PackageManager", e);
2883              }
2884          } else {
2885              isPrivileged = Boolean.parseBoolean(isPrivilegedString);
2886          }
2887          int outerDepth = parser.getDepth();
2888          int type;
2889          while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2890                  && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2891              if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2892                  continue;
2893              }
2894              String tagName = parser.getName();
2895              if (tagName.equals("op")) {
2896                  readOp(parser, uidState, pkgName, isPrivileged);
2897              } else {
2898                  Slog.w(TAG, "Unknown element under <pkg>: "
2899                          + parser.getName());
2900                  XmlUtils.skipCurrentTag(parser);
2901              }
2902          }
2903          uidState.evalForegroundOps(mOpModeWatchers);
2904      }
2905  
readOp(XmlPullParser parser, @NonNull UidState uidState, @NonNull String pkgName, boolean isPrivileged)2906      private void readOp(XmlPullParser parser, @NonNull UidState uidState,
2907              @NonNull String pkgName, boolean isPrivileged) throws NumberFormatException,
2908              XmlPullParserException, IOException {
2909          Op op = new Op(uidState, pkgName,
2910                  Integer.parseInt(parser.getAttributeValue(null, "n")));
2911  
2912          final int mode = XmlUtils.readIntAttribute(parser, "m",
2913                  AppOpsManager.opToDefaultMode(op.op));
2914          op.mode = mode;
2915  
2916          int outerDepth = parser.getDepth();
2917          int type;
2918          while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2919                  && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2920              if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2921                  continue;
2922              }
2923              String tagName = parser.getName();
2924              if (tagName.equals("st")) {
2925                  final long key = XmlUtils.readLongAttribute(parser, "n");
2926  
2927                  final int flags = AppOpsManager.extractFlagsFromKey(key);
2928                  final int state = AppOpsManager.extractUidStateFromKey(key);
2929  
2930                  final long accessTime = XmlUtils.readLongAttribute(parser, "t", 0);
2931                  final long rejectTime = XmlUtils.readLongAttribute(parser, "r", 0);
2932                  final long accessDuration = XmlUtils.readLongAttribute(parser, "d", 0);
2933                  final String proxyPkg = XmlUtils.readStringAttribute(parser, "pp");
2934                  final int proxyUid = XmlUtils.readIntAttribute(parser, "pu", 0);
2935  
2936                  if (accessTime > 0) {
2937                      op.accessed(accessTime, proxyUid, proxyPkg, state, flags);
2938                  }
2939                  if (rejectTime > 0) {
2940                      op.rejected(rejectTime, proxyUid, proxyPkg, state, flags);
2941                  }
2942                  if (accessDuration > 0) {
2943                      op.running(accessTime, accessDuration, state, flags);
2944                  }
2945              } else {
2946                  Slog.w(TAG, "Unknown element under <op>: "
2947                          + parser.getName());
2948                  XmlUtils.skipCurrentTag(parser);
2949              }
2950          }
2951  
2952          if (uidState.pkgOps == null) {
2953              uidState.pkgOps = new ArrayMap<>();
2954          }
2955          Ops ops = uidState.pkgOps.get(pkgName);
2956          if (ops == null) {
2957              ops = new Ops(pkgName, uidState, isPrivileged);
2958              uidState.pkgOps.put(pkgName, ops);
2959          }
2960          ops.put(op.op, op);
2961      }
2962  
writeState()2963      void writeState() {
2964          synchronized (mFile) {
2965              FileOutputStream stream;
2966              try {
2967                  stream = mFile.startWrite();
2968              } catch (IOException e) {
2969                  Slog.w(TAG, "Failed to write state: " + e);
2970                  return;
2971              }
2972  
2973              List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
2974  
2975              try {
2976                  XmlSerializer out = new FastXmlSerializer();
2977                  out.setOutput(stream, StandardCharsets.UTF_8.name());
2978                  out.startDocument(null, true);
2979                  out.startTag(null, "app-ops");
2980                  out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
2981  
2982                  final int uidStateCount = mUidStates.size();
2983                  for (int i = 0; i < uidStateCount; i++) {
2984                      UidState uidState = mUidStates.valueAt(i);
2985                      if (uidState.opModes != null && uidState.opModes.size() > 0) {
2986                          out.startTag(null, "uid");
2987                          out.attribute(null, "n", Integer.toString(uidState.uid));
2988                          SparseIntArray uidOpModes = uidState.opModes;
2989                          final int opCount = uidOpModes.size();
2990                          for (int j = 0; j < opCount; j++) {
2991                              final int op = uidOpModes.keyAt(j);
2992                              final int mode = uidOpModes.valueAt(j);
2993                              out.startTag(null, "op");
2994                              out.attribute(null, "n", Integer.toString(op));
2995                              out.attribute(null, "m", Integer.toString(mode));
2996                              out.endTag(null, "op");
2997                          }
2998                          out.endTag(null, "uid");
2999                      }
3000                  }
3001  
3002                  if (allOps != null) {
3003                      String lastPkg = null;
3004                      for (int i=0; i<allOps.size(); i++) {
3005                          AppOpsManager.PackageOps pkg = allOps.get(i);
3006                          if (!pkg.getPackageName().equals(lastPkg)) {
3007                              if (lastPkg != null) {
3008                                  out.endTag(null, "pkg");
3009                              }
3010                              lastPkg = pkg.getPackageName();
3011                              out.startTag(null, "pkg");
3012                              out.attribute(null, "n", lastPkg);
3013                          }
3014                          out.startTag(null, "uid");
3015                          out.attribute(null, "n", Integer.toString(pkg.getUid()));
3016                          synchronized (this) {
3017                              Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
3018                                      false /* edit */, false /* uidMismatchExpected */);
3019                              // Should always be present as the list of PackageOps is generated
3020                              // from Ops.
3021                              if (ops != null) {
3022                                  out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
3023                              } else {
3024                                  out.attribute(null, "p", Boolean.toString(false));
3025                              }
3026                          }
3027                          List<AppOpsManager.OpEntry> ops = pkg.getOps();
3028                          for (int j=0; j<ops.size(); j++) {
3029                              AppOpsManager.OpEntry op = ops.get(j);
3030                              out.startTag(null, "op");
3031                              out.attribute(null, "n", Integer.toString(op.getOp()));
3032                              if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
3033                                  out.attribute(null, "m", Integer.toString(op.getMode()));
3034                              }
3035  
3036                              final LongSparseArray keys = op.collectKeys();
3037                              if (keys == null || keys.size() <= 0) {
3038                                  out.endTag(null, "op");
3039                                  continue;
3040                              }
3041  
3042                              final int keyCount = keys.size();
3043                              for (int k = 0; k < keyCount; k++) {
3044                                  final long key = keys.keyAt(k);
3045  
3046                                  final int uidState = AppOpsManager.extractUidStateFromKey(key);
3047                                  final int flags = AppOpsManager.extractFlagsFromKey(key);
3048  
3049                                  final long accessTime = op.getLastAccessTime(
3050                                          uidState, uidState, flags);
3051                                  final long rejectTime = op.getLastRejectTime(
3052                                          uidState, uidState, flags);
3053                                  final long accessDuration = op.getLastDuration(
3054                                          uidState, uidState, flags);
3055                                  final String proxyPkg = op.getProxyPackageName(uidState, flags);
3056                                  final int proxyUid = op.getProxyUid(uidState, flags);
3057  
3058                                  if (accessTime <= 0 && rejectTime <= 0 && accessDuration <= 0
3059                                          && proxyPkg == null && proxyUid < 0) {
3060                                      continue;
3061                                  }
3062  
3063                                  out.startTag(null, "st");
3064                                  out.attribute(null, "n", Long.toString(key));
3065                                  if (accessTime > 0) {
3066                                      out.attribute(null, "t", Long.toString(accessTime));
3067                                  }
3068                                  if (rejectTime > 0) {
3069                                      out.attribute(null, "r", Long.toString(rejectTime));
3070                                  }
3071                                  if (accessDuration > 0) {
3072                                      out.attribute(null, "d", Long.toString(accessDuration));
3073                                  }
3074                                  if (proxyPkg != null) {
3075                                      out.attribute(null, "pp", proxyPkg);
3076                                  }
3077                                  if (proxyUid >= 0) {
3078                                      out.attribute(null, "pu", Integer.toString(proxyUid));
3079                                  }
3080                                  out.endTag(null, "st");
3081                              }
3082  
3083                              out.endTag(null, "op");
3084                          }
3085                          out.endTag(null, "uid");
3086                      }
3087                      if (lastPkg != null) {
3088                          out.endTag(null, "pkg");
3089                      }
3090                  }
3091  
3092                  out.endTag(null, "app-ops");
3093                  out.endDocument();
3094                  mFile.finishWrite(stream);
3095              } catch (IOException e) {
3096                  Slog.w(TAG, "Failed to write state, restoring backup.", e);
3097                  mFile.failWrite(stream);
3098              }
3099          }
3100      }
3101  
3102      static class Shell extends ShellCommand {
3103          final IAppOpsService mInterface;
3104          final AppOpsService mInternal;
3105  
3106          int userId = UserHandle.USER_SYSTEM;
3107          String packageName;
3108          String opStr;
3109          String modeStr;
3110          int op;
3111          int mode;
3112          int packageUid;
3113          int nonpackageUid;
3114          final static Binder sBinder = new Binder();
3115          IBinder mToken;
3116          boolean targetsUid;
3117  
Shell(IAppOpsService iface, AppOpsService internal)3118          Shell(IAppOpsService iface, AppOpsService internal) {
3119              mInterface = iface;
3120              mInternal = internal;
3121              try {
3122                  mToken = mInterface.getToken(sBinder);
3123              } catch (RemoteException e) {
3124              }
3125          }
3126  
3127          @Override
onCommand(String cmd)3128          public int onCommand(String cmd) {
3129              return onShellCommand(this, cmd);
3130          }
3131  
3132          @Override
onHelp()3133          public void onHelp() {
3134              PrintWriter pw = getOutPrintWriter();
3135              dumpCommandHelp(pw);
3136          }
3137  
strOpToOp(String op, PrintWriter err)3138          static private int strOpToOp(String op, PrintWriter err) {
3139              try {
3140                  return AppOpsManager.strOpToOp(op);
3141              } catch (IllegalArgumentException e) {
3142              }
3143              try {
3144                  return Integer.parseInt(op);
3145              } catch (NumberFormatException e) {
3146              }
3147              try {
3148                  return AppOpsManager.strDebugOpToOp(op);
3149              } catch (IllegalArgumentException e) {
3150                  err.println("Error: " + e.getMessage());
3151                  return -1;
3152              }
3153          }
3154  
strModeToMode(String modeStr, PrintWriter err)3155          static int strModeToMode(String modeStr, PrintWriter err) {
3156              for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
3157                  if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
3158                      return i;
3159                  }
3160              }
3161              try {
3162                  return Integer.parseInt(modeStr);
3163              } catch (NumberFormatException e) {
3164              }
3165              err.println("Error: Mode " + modeStr + " is not valid");
3166              return -1;
3167          }
3168  
parseUserOpMode(int defMode, PrintWriter err)3169          int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
3170              userId = UserHandle.USER_CURRENT;
3171              opStr = null;
3172              modeStr = null;
3173              for (String argument; (argument = getNextArg()) != null;) {
3174                  if ("--user".equals(argument)) {
3175                      userId = UserHandle.parseUserArg(getNextArgRequired());
3176                  } else {
3177                      if (opStr == null) {
3178                          opStr = argument;
3179                      } else if (modeStr == null) {
3180                          modeStr = argument;
3181                          break;
3182                      }
3183                  }
3184              }
3185              if (opStr == null) {
3186                  err.println("Error: Operation not specified.");
3187                  return -1;
3188              }
3189              op = strOpToOp(opStr, err);
3190              if (op < 0) {
3191                  return -1;
3192              }
3193              if (modeStr != null) {
3194                  if ((mode=strModeToMode(modeStr, err)) < 0) {
3195                      return -1;
3196                  }
3197              } else {
3198                  mode = defMode;
3199              }
3200              return 0;
3201          }
3202  
parseUserPackageOp(boolean reqOp, PrintWriter err)3203          int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
3204              userId = UserHandle.USER_CURRENT;
3205              packageName = null;
3206              opStr = null;
3207              for (String argument; (argument = getNextArg()) != null;) {
3208                  if ("--user".equals(argument)) {
3209                      userId = UserHandle.parseUserArg(getNextArgRequired());
3210                  } else if ("--uid".equals(argument)) {
3211                      targetsUid = true;
3212                  } else {
3213                      if (packageName == null) {
3214                          packageName = argument;
3215                      } else if (opStr == null) {
3216                          opStr = argument;
3217                          break;
3218                      }
3219                  }
3220              }
3221              if (packageName == null) {
3222                  err.println("Error: Package name not specified.");
3223                  return -1;
3224              } else if (opStr == null && reqOp) {
3225                  err.println("Error: Operation not specified.");
3226                  return -1;
3227              }
3228              if (opStr != null) {
3229                  op = strOpToOp(opStr, err);
3230                  if (op < 0) {
3231                      return -1;
3232                  }
3233              } else {
3234                  op = AppOpsManager.OP_NONE;
3235              }
3236              if (userId == UserHandle.USER_CURRENT) {
3237                  userId = ActivityManager.getCurrentUser();
3238              }
3239              nonpackageUid = -1;
3240              try {
3241                  nonpackageUid = Integer.parseInt(packageName);
3242              } catch (NumberFormatException e) {
3243              }
3244              if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
3245                      && packageName.indexOf('.') < 0) {
3246                  int i = 1;
3247                  while (i < packageName.length() && packageName.charAt(i) >= '0'
3248                          && packageName.charAt(i) <= '9') {
3249                      i++;
3250                  }
3251                  if (i > 1 && i < packageName.length()) {
3252                      String userStr = packageName.substring(1, i);
3253                      try {
3254                          int user = Integer.parseInt(userStr);
3255                          char type = packageName.charAt(i);
3256                          i++;
3257                          int startTypeVal = i;
3258                          while (i < packageName.length() && packageName.charAt(i) >= '0'
3259                                  && packageName.charAt(i) <= '9') {
3260                              i++;
3261                          }
3262                          if (i > startTypeVal) {
3263                              String typeValStr = packageName.substring(startTypeVal, i);
3264                              try {
3265                                  int typeVal = Integer.parseInt(typeValStr);
3266                                  if (type == 'a') {
3267                                      nonpackageUid = UserHandle.getUid(user,
3268                                              typeVal + Process.FIRST_APPLICATION_UID);
3269                                  } else if (type == 's') {
3270                                      nonpackageUid = UserHandle.getUid(user, typeVal);
3271                                  }
3272                              } catch (NumberFormatException e) {
3273                              }
3274                          }
3275                      } catch (NumberFormatException e) {
3276                      }
3277                  }
3278              }
3279              if (nonpackageUid != -1) {
3280                  packageName = null;
3281              } else {
3282                  packageUid = resolveUid(packageName);
3283                  if (packageUid < 0) {
3284                      packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
3285                              PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
3286                  }
3287                  if (packageUid < 0) {
3288                      err.println("Error: No UID for " + packageName + " in user " + userId);
3289                      return -1;
3290                  }
3291              }
3292              return 0;
3293          }
3294      }
3295  
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)3296      @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
3297              FileDescriptor err, String[] args, ShellCallback callback,
3298              ResultReceiver resultReceiver) {
3299          (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
3300      }
3301  
dumpCommandHelp(PrintWriter pw)3302      static void dumpCommandHelp(PrintWriter pw) {
3303          pw.println("AppOps service (appops) commands:");
3304          pw.println("  help");
3305          pw.println("    Print this help text.");
3306          pw.println("  start [--user <USER_ID>] <PACKAGE | UID> <OP> ");
3307          pw.println("    Starts a given operation for a particular application.");
3308          pw.println("  stop [--user <USER_ID>] <PACKAGE | UID> <OP> ");
3309          pw.println("    Stops a given operation for a particular application.");
3310          pw.println("  set [--user <USER_ID>] <[--uid] PACKAGE | UID> <OP> <MODE>");
3311          pw.println("    Set the mode for a particular application and operation.");
3312          pw.println("  get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
3313          pw.println("    Return the mode for a particular application and optional operation.");
3314          pw.println("  query-op [--user <USER_ID>] <OP> [<MODE>]");
3315          pw.println("    Print all packages that currently have the given op in the given mode.");
3316          pw.println("  reset [--user <USER_ID>] [<PACKAGE>]");
3317          pw.println("    Reset the given application or all applications to default modes.");
3318          pw.println("  write-settings");
3319          pw.println("    Immediately write pending changes to storage.");
3320          pw.println("  read-settings");
3321          pw.println("    Read the last written settings, replacing current state in RAM.");
3322          pw.println("  options:");
3323          pw.println("    <PACKAGE> an Android package name or its UID if prefixed by --uid");
3324          pw.println("    <OP>      an AppOps operation.");
3325          pw.println("    <MODE>    one of allow, ignore, deny, or default");
3326          pw.println("    <USER_ID> the user id under which the package is installed. If --user is not");
3327          pw.println("              specified, the current user is assumed.");
3328      }
3329  
onShellCommand(Shell shell, String cmd)3330      static int onShellCommand(Shell shell, String cmd) {
3331          if (cmd == null) {
3332              return shell.handleDefaultCommands(cmd);
3333          }
3334          PrintWriter pw = shell.getOutPrintWriter();
3335          PrintWriter err = shell.getErrPrintWriter();
3336          try {
3337              switch (cmd) {
3338                  case "set": {
3339                      int res = shell.parseUserPackageOp(true, err);
3340                      if (res < 0) {
3341                          return res;
3342                      }
3343                      String modeStr = shell.getNextArg();
3344                      if (modeStr == null) {
3345                          err.println("Error: Mode not specified.");
3346                          return -1;
3347                      }
3348  
3349                      final int mode = shell.strModeToMode(modeStr, err);
3350                      if (mode < 0) {
3351                          return -1;
3352                      }
3353  
3354                      if (!shell.targetsUid && shell.packageName != null) {
3355                          shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
3356                                  mode);
3357                      } else if (shell.targetsUid && shell.packageName != null) {
3358                          try {
3359                              final int uid = shell.mInternal.mContext.getPackageManager()
3360                                      .getPackageUid(shell.packageName, shell.userId);
3361                              shell.mInterface.setUidMode(shell.op, uid, mode);
3362                          } catch (PackageManager.NameNotFoundException e) {
3363                              return -1;
3364                          }
3365                      } else {
3366                          shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
3367                      }
3368                      return 0;
3369                  }
3370                  case "get": {
3371                      int res = shell.parseUserPackageOp(false, err);
3372                      if (res < 0) {
3373                          return res;
3374                      }
3375  
3376                      List<AppOpsManager.PackageOps> ops = new ArrayList<>();
3377                      if (shell.packageName != null) {
3378                          // Uid mode overrides package mode, so make sure it's also reported
3379                          List<AppOpsManager.PackageOps> r = shell.mInterface.getUidOps(
3380                                  shell.packageUid,
3381                                  shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
3382                          if (r != null) {
3383                              ops.addAll(r);
3384                          }
3385                          r = shell.mInterface.getOpsForPackage(
3386                                  shell.packageUid, shell.packageName,
3387                                  shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
3388                          if (r != null) {
3389                              ops.addAll(r);
3390                          }
3391                      } else {
3392                          ops = shell.mInterface.getUidOps(
3393                                  shell.nonpackageUid,
3394                                  shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
3395                      }
3396                      if (ops == null || ops.size() <= 0) {
3397                          pw.println("No operations.");
3398                          if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
3399                              pw.println("Default mode: " + AppOpsManager.modeToName(
3400                                      AppOpsManager.opToDefaultMode(shell.op)));
3401                          }
3402                          return 0;
3403                      }
3404                      final long now = System.currentTimeMillis();
3405                      for (int i=0; i<ops.size(); i++) {
3406                          AppOpsManager.PackageOps packageOps = ops.get(i);
3407                          if (packageOps.getPackageName() == null) {
3408                              pw.print("Uid mode: ");
3409                          }
3410                          List<AppOpsManager.OpEntry> entries = packageOps.getOps();
3411                          for (int j=0; j<entries.size(); j++) {
3412                              AppOpsManager.OpEntry ent = entries.get(j);
3413                              pw.print(AppOpsManager.opToName(ent.getOp()));
3414                              pw.print(": ");
3415                              pw.print(AppOpsManager.modeToName(ent.getMode()));
3416                              if (ent.getTime() != 0) {
3417                                  pw.print("; time=");
3418                                  TimeUtils.formatDuration(now - ent.getTime(), pw);
3419                                  pw.print(" ago");
3420                              }
3421                              if (ent.getRejectTime() != 0) {
3422                                  pw.print("; rejectTime=");
3423                                  TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
3424                                  pw.print(" ago");
3425                              }
3426                              if (ent.getDuration() == -1) {
3427                                  pw.print(" (running)");
3428                              } else if (ent.getDuration() != 0) {
3429                                  pw.print("; duration=");
3430                                  TimeUtils.formatDuration(ent.getDuration(), pw);
3431                              }
3432                              pw.println();
3433                          }
3434                      }
3435                      return 0;
3436                  }
3437                  case "query-op": {
3438                      int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
3439                      if (res < 0) {
3440                          return res;
3441                      }
3442                      List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
3443                              new int[] {shell.op});
3444                      if (ops == null || ops.size() <= 0) {
3445                          pw.println("No operations.");
3446                          return 0;
3447                      }
3448                      for (int i=0; i<ops.size(); i++) {
3449                          final AppOpsManager.PackageOps pkg = ops.get(i);
3450                          boolean hasMatch = false;
3451                          final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
3452                          for (int j=0; j<entries.size(); j++) {
3453                              AppOpsManager.OpEntry ent = entries.get(j);
3454                              if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
3455                                  hasMatch = true;
3456                                  break;
3457                              }
3458                          }
3459                          if (hasMatch) {
3460                              pw.println(pkg.getPackageName());
3461                          }
3462                      }
3463                      return 0;
3464                  }
3465                  case "reset": {
3466                      String packageName = null;
3467                      int userId = UserHandle.USER_CURRENT;
3468                      for (String argument; (argument = shell.getNextArg()) != null;) {
3469                          if ("--user".equals(argument)) {
3470                              String userStr = shell.getNextArgRequired();
3471                              userId = UserHandle.parseUserArg(userStr);
3472                          } else {
3473                              if (packageName == null) {
3474                                  packageName = argument;
3475                              } else {
3476                                  err.println("Error: Unsupported argument: " + argument);
3477                                  return -1;
3478                              }
3479                          }
3480                      }
3481  
3482                      if (userId == UserHandle.USER_CURRENT) {
3483                          userId = ActivityManager.getCurrentUser();
3484                      }
3485  
3486                      shell.mInterface.resetAllModes(userId, packageName);
3487                      pw.print("Reset all modes for: ");
3488                      if (userId == UserHandle.USER_ALL) {
3489                          pw.print("all users");
3490                      } else {
3491                          pw.print("user "); pw.print(userId);
3492                      }
3493                      pw.print(", ");
3494                      if (packageName == null) {
3495                          pw.println("all packages");
3496                      } else {
3497                          pw.print("package "); pw.println(packageName);
3498                      }
3499                      return 0;
3500                  }
3501                  case "write-settings": {
3502                      shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
3503                              Binder.getCallingUid(), -1);
3504                      long token = Binder.clearCallingIdentity();
3505                      try {
3506                          synchronized (shell.mInternal) {
3507                              shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
3508                          }
3509                          shell.mInternal.writeState();
3510                          pw.println("Current settings written.");
3511                      } finally {
3512                          Binder.restoreCallingIdentity(token);
3513                      }
3514                      return 0;
3515                  }
3516                  case "read-settings": {
3517                      shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
3518                              Binder.getCallingUid(), -1);
3519                      long token = Binder.clearCallingIdentity();
3520                      try {
3521                          shell.mInternal.readState();
3522                          pw.println("Last settings read.");
3523                      } finally {
3524                          Binder.restoreCallingIdentity(token);
3525                      }
3526                      return 0;
3527                  }
3528                  case "start": {
3529                      int res = shell.parseUserPackageOp(true, err);
3530                      if (res < 0) {
3531                          return res;
3532                      }
3533  
3534                      if (shell.packageName != null) {
3535                          shell.mInterface.startOperation(shell.mToken,
3536                                  shell.op, shell.packageUid, shell.packageName, true);
3537                      } else {
3538                          return -1;
3539                      }
3540                      return 0;
3541                  }
3542                  case "stop": {
3543                      int res = shell.parseUserPackageOp(true, err);
3544                      if (res < 0) {
3545                          return res;
3546                      }
3547  
3548                      if (shell.packageName != null) {
3549                          shell.mInterface.finishOperation(shell.mToken,
3550                                  shell.op, shell.packageUid, shell.packageName);
3551                      } else {
3552                          return -1;
3553                      }
3554                      return 0;
3555                  }
3556                  default:
3557                      return shell.handleDefaultCommands(cmd);
3558              }
3559          } catch (RemoteException e) {
3560              pw.println("Remote exception: " + e);
3561          }
3562          return -1;
3563      }
3564  
dumpHelp(PrintWriter pw)3565      private void dumpHelp(PrintWriter pw) {
3566          pw.println("AppOps service (appops) dump options:");
3567          pw.println("  -h");
3568          pw.println("    Print this help text.");
3569          pw.println("  --op [OP]");
3570          pw.println("    Limit output to data associated with the given app op code.");
3571          pw.println("  --mode [MODE]");
3572          pw.println("    Limit output to data associated with the given app op mode.");
3573          pw.println("  --package [PACKAGE]");
3574          pw.println("    Limit output to data associated with the given package name.");
3575          pw.println("  --watchers");
3576          pw.println("    Only output the watcher sections.");
3577      }
3578  
dumpStatesLocked(@onNull PrintWriter pw, @NonNull Op op, long now, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix)3579      private void dumpStatesLocked(@NonNull PrintWriter pw, @NonNull Op op,
3580              long now, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix) {
3581  
3582          final OpEntry entry = new OpEntry(op.op, op.running, op.mode, op.mAccessTimes,
3583              op.mRejectTimes, op.mDurations, op.mProxyUids, op.mProxyPackageNames);
3584  
3585          final LongSparseArray keys = entry.collectKeys();
3586          if (keys == null || keys.size() <= 0) {
3587              return;
3588          }
3589  
3590          final int keyCount = keys.size();
3591          for (int k = 0; k < keyCount; k++) {
3592              final long key = keys.keyAt(k);
3593  
3594              final int uidState = AppOpsManager.extractUidStateFromKey(key);
3595              final int flags = AppOpsManager.extractFlagsFromKey(key);
3596  
3597              final long accessTime = entry.getLastAccessTime(
3598                      uidState, uidState, flags);
3599              final long rejectTime = entry.getLastRejectTime(
3600                      uidState, uidState, flags);
3601              final long accessDuration = entry.getLastDuration(
3602                      uidState, uidState, flags);
3603              final String proxyPkg = entry.getProxyPackageName(uidState, flags);
3604              final int proxyUid = entry.getProxyUid(uidState, flags);
3605  
3606              if (accessTime > 0) {
3607                  pw.print(prefix);
3608                  pw.print("Access: ");
3609                  pw.print(AppOpsManager.keyToString(key));
3610                  pw.print(" ");
3611                  date.setTime(accessTime);
3612                  pw.print(sdf.format(date));
3613                  pw.print(" (");
3614                  TimeUtils.formatDuration(accessTime - now, pw);
3615                  pw.print(")");
3616                  if (accessDuration > 0) {
3617                      pw.print(" duration=");
3618                      TimeUtils.formatDuration(accessDuration, pw);
3619                  }
3620                  if (proxyUid >= 0) {
3621                      pw.print(" proxy[");
3622                      pw.print("uid=");
3623                      pw.print(proxyUid);
3624                      pw.print(", pkg=");
3625                      pw.print(proxyPkg);
3626                      pw.print("]");
3627                  }
3628                  pw.println();
3629              }
3630  
3631              if (rejectTime > 0) {
3632                  pw.print(prefix);
3633                  pw.print("Reject: ");
3634                  pw.print(AppOpsManager.keyToString(key));
3635                  date.setTime(rejectTime);
3636                  pw.print(sdf.format(date));
3637                  pw.print(" (");
3638                  TimeUtils.formatDuration(rejectTime - now, pw);
3639                  pw.print(")");
3640                  if (proxyUid >= 0) {
3641                      pw.print(" proxy[");
3642                      pw.print("uid=");
3643                      pw.print(proxyUid);
3644                      pw.print(", pkg=");
3645                      pw.print(proxyPkg);
3646                      pw.print("]");
3647                  }
3648                  pw.println();
3649              }
3650          }
3651      }
3652  
3653      @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)3654      protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3655          if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
3656  
3657          int dumpOp = OP_NONE;
3658          String dumpPackage = null;
3659          int dumpUid = Process.INVALID_UID;
3660          int dumpMode = -1;
3661          boolean dumpWatchers = false;
3662          boolean dumpHistory = false;
3663  
3664          if (args != null) {
3665              for (int i=0; i<args.length; i++) {
3666                  String arg = args[i];
3667                  if ("-h".equals(arg)) {
3668                      dumpHelp(pw);
3669                      return;
3670                  } else if ("-a".equals(arg)) {
3671                      // dump all data
3672                  } else if ("--op".equals(arg)) {
3673                      i++;
3674                      if (i >= args.length) {
3675                          pw.println("No argument for --op option");
3676                          return;
3677                      }
3678                      dumpOp = Shell.strOpToOp(args[i], pw);
3679                      if (dumpOp < 0) {
3680                          return;
3681                      }
3682                  } else if ("--package".equals(arg)) {
3683                      i++;
3684                      if (i >= args.length) {
3685                          pw.println("No argument for --package option");
3686                          return;
3687                      }
3688                      dumpPackage = args[i];
3689                      try {
3690                          dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
3691                                  PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
3692                                  0);
3693                      } catch (RemoteException e) {
3694                      }
3695                      if (dumpUid < 0) {
3696                          pw.println("Unknown package: " + dumpPackage);
3697                          return;
3698                      }
3699                      dumpUid = UserHandle.getAppId(dumpUid);
3700                  } else if ("--mode".equals(arg)) {
3701                      i++;
3702                      if (i >= args.length) {
3703                          pw.println("No argument for --mode option");
3704                          return;
3705                      }
3706                      dumpMode = Shell.strModeToMode(args[i], pw);
3707                      if (dumpMode < 0) {
3708                          return;
3709                      }
3710                  } else if ("--watchers".equals(arg)) {
3711                      dumpWatchers = true;
3712                  } else if (arg.length() > 0 && arg.charAt(0) == '-'){
3713                      pw.println("Unknown option: " + arg);
3714                      return;
3715                  } else {
3716                      pw.println("Unknown command: " + arg);
3717                      return;
3718                  }
3719              }
3720          }
3721  
3722          synchronized (this) {
3723              pw.println("Current AppOps Service state:");
3724              if (!dumpHistory && !dumpWatchers) {
3725                  mConstants.dump(pw);
3726              }
3727              pw.println();
3728              final long now = System.currentTimeMillis();
3729              final long nowElapsed = SystemClock.elapsedRealtime();
3730              final long nowUptime = SystemClock.uptimeMillis();
3731              final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
3732              final Date date = new Date();
3733              boolean needSep = false;
3734              if (dumpOp < 0 && dumpMode < 0 && dumpPackage == null && mProfileOwners != null
3735                      && !dumpWatchers && !dumpHistory) {
3736                  pw.println("  Profile owners:");
3737                  for (int poi = 0; poi < mProfileOwners.size(); poi++) {
3738                      pw.print("    User #");
3739                      pw.print(mProfileOwners.keyAt(poi));
3740                      pw.print(": ");
3741                      UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
3742                      pw.println();
3743                  }
3744                  pw.println();
3745              }
3746              if (mOpModeWatchers.size() > 0 && !dumpHistory) {
3747                  boolean printedHeader = false;
3748                  for (int i=0; i<mOpModeWatchers.size(); i++) {
3749                      if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
3750                          continue;
3751                      }
3752                      boolean printedOpHeader = false;
3753                      ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
3754                      for (int j=0; j<callbacks.size(); j++) {
3755                          final ModeCallback cb = callbacks.valueAt(j);
3756                          if (dumpPackage != null
3757                                  && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3758                              continue;
3759                          }
3760                          needSep = true;
3761                          if (!printedHeader) {
3762                              pw.println("  Op mode watchers:");
3763                              printedHeader = true;
3764                          }
3765                          if (!printedOpHeader) {
3766                              pw.print("    Op ");
3767                              pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
3768                              pw.println(":");
3769                              printedOpHeader = true;
3770                          }
3771                          pw.print("      #"); pw.print(j); pw.print(": ");
3772                          pw.println(cb);
3773                      }
3774                  }
3775              }
3776              if (mPackageModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
3777                  boolean printedHeader = false;
3778                  for (int i=0; i<mPackageModeWatchers.size(); i++) {
3779                      if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
3780                          continue;
3781                      }
3782                      needSep = true;
3783                      if (!printedHeader) {
3784                          pw.println("  Package mode watchers:");
3785                          printedHeader = true;
3786                      }
3787                      pw.print("    Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
3788                      pw.println(":");
3789                      ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
3790                      for (int j=0; j<callbacks.size(); j++) {
3791                          pw.print("      #"); pw.print(j); pw.print(": ");
3792                          pw.println(callbacks.valueAt(j));
3793                      }
3794                  }
3795              }
3796              if (mModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
3797                  boolean printedHeader = false;
3798                  for (int i=0; i<mModeWatchers.size(); i++) {
3799                      final ModeCallback cb = mModeWatchers.valueAt(i);
3800                      if (dumpPackage != null
3801                              && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3802                          continue;
3803                      }
3804                      needSep = true;
3805                      if (!printedHeader) {
3806                          pw.println("  All op mode watchers:");
3807                          printedHeader = true;
3808                      }
3809                      pw.print("    ");
3810                      pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
3811                      pw.print(": "); pw.println(cb);
3812                  }
3813              }
3814              if (mActiveWatchers.size() > 0 && dumpMode < 0) {
3815                  needSep = true;
3816                  boolean printedHeader = false;
3817                  for (int watcherNum = 0; watcherNum < mActiveWatchers.size(); watcherNum++) {
3818                      final SparseArray<ActiveCallback> activeWatchers =
3819                              mActiveWatchers.valueAt(watcherNum);
3820                      if (activeWatchers.size() <= 0) {
3821                          continue;
3822                      }
3823                      final ActiveCallback cb = activeWatchers.valueAt(0);
3824                      if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
3825                          continue;
3826                      }
3827                      if (dumpPackage != null
3828                              && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3829                          continue;
3830                      }
3831                      if (!printedHeader) {
3832                          pw.println("  All op active watchers:");
3833                          printedHeader = true;
3834                      }
3835                      pw.print("    ");
3836                      pw.print(Integer.toHexString(System.identityHashCode(
3837                              mActiveWatchers.keyAt(watcherNum))));
3838                      pw.println(" ->");
3839                      pw.print("        [");
3840                      final int opCount = activeWatchers.size();
3841                      for (int opNum = 0; opNum < opCount; opNum++) {
3842                          if (opNum > 0) {
3843                              pw.print(' ');
3844                          }
3845                          pw.print(AppOpsManager.opToName(activeWatchers.keyAt(opNum)));
3846                          if (opNum < opCount - 1) {
3847                              pw.print(',');
3848                          }
3849                      }
3850                      pw.println("]");
3851                      pw.print("        ");
3852                      pw.println(cb);
3853                  }
3854              }
3855              if (mNotedWatchers.size() > 0 && dumpMode < 0) {
3856                  needSep = true;
3857                  boolean printedHeader = false;
3858                  for (int i = 0; i < mNotedWatchers.size(); i++) {
3859                      final SparseArray<NotedCallback> notedWatchers = mNotedWatchers.valueAt(i);
3860                      if (notedWatchers.size() <= 0) {
3861                          continue;
3862                      }
3863                      final NotedCallback cb = notedWatchers.valueAt(0);
3864                      if (dumpOp >= 0 && notedWatchers.indexOfKey(dumpOp) < 0) {
3865                          continue;
3866                      }
3867                      if (dumpPackage != null
3868                              && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3869                          continue;
3870                      }
3871                      if (!printedHeader) {
3872                          pw.println("  All op noted watchers:");
3873                          printedHeader = true;
3874                      }
3875                      pw.print("    ");
3876                      pw.print(Integer.toHexString(System.identityHashCode(
3877                              mNotedWatchers.keyAt(i))));
3878                      pw.println(" ->");
3879                      pw.print("        [");
3880                      final int opCount = notedWatchers.size();
3881                      for (i = 0; i < opCount; i++) {
3882                          if (i > 0) {
3883                              pw.print(' ');
3884                          }
3885                          pw.print(AppOpsManager.opToName(notedWatchers.keyAt(i)));
3886                          if (i < opCount - 1) {
3887                              pw.print(',');
3888                          }
3889                      }
3890                      pw.println("]");
3891                      pw.print("        ");
3892                      pw.println(cb);
3893                  }
3894              }
3895              if (mClients.size() > 0 && dumpMode < 0 && !dumpWatchers && !dumpHistory) {
3896                  needSep = true;
3897                  boolean printedHeader = false;
3898                  for (int i=0; i<mClients.size(); i++) {
3899                      boolean printedClient = false;
3900                      ClientState cs = mClients.valueAt(i);
3901                      if (cs.mStartedOps.size() > 0) {
3902                          boolean printedStarted = false;
3903                          for (int j=0; j<cs.mStartedOps.size(); j++) {
3904                              Op op = cs.mStartedOps.get(j);
3905                              if (dumpOp >= 0 && op.op != dumpOp) {
3906                                  continue;
3907                              }
3908                              if (dumpPackage != null && !dumpPackage.equals(op.packageName)) {
3909                                  continue;
3910                              }
3911                              if (!printedHeader) {
3912                                  pw.println("  Clients:");
3913                                  printedHeader = true;
3914                              }
3915                              if (!printedClient) {
3916                                  pw.print("    "); pw.print(mClients.keyAt(i)); pw.println(":");
3917                                  pw.print("      "); pw.println(cs);
3918                                  printedClient = true;
3919                              }
3920                              if (!printedStarted) {
3921                                  pw.println("      Started ops:");
3922                                  printedStarted = true;
3923                              }
3924                              pw.print("        "); pw.print("uid="); pw.print(op.uidState.uid);
3925                              pw.print(" pkg="); pw.print(op.packageName);
3926                              pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
3927                          }
3928                      }
3929                  }
3930              }
3931              if (mAudioRestrictions.size() > 0 && dumpOp < 0 && dumpPackage != null
3932                      && dumpMode < 0 && !dumpWatchers && !dumpWatchers) {
3933                  boolean printedHeader = false;
3934                  for (int o=0; o<mAudioRestrictions.size(); o++) {
3935                      final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
3936                      final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
3937                      for (int i=0; i<restrictions.size(); i++) {
3938                          if (!printedHeader){
3939                              pw.println("  Audio Restrictions:");
3940                              printedHeader = true;
3941                              needSep = true;
3942                          }
3943                          final int usage = restrictions.keyAt(i);
3944                          pw.print("    "); pw.print(op);
3945                          pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
3946                          Restriction r = restrictions.valueAt(i);
3947                          pw.print(": mode="); pw.println(AppOpsManager.modeToName(r.mode));
3948                          if (!r.exceptionPackages.isEmpty()) {
3949                              pw.println("      Exceptions:");
3950                              for (int j=0; j<r.exceptionPackages.size(); j++) {
3951                                  pw.print("        "); pw.println(r.exceptionPackages.valueAt(j));
3952                              }
3953                          }
3954                      }
3955                  }
3956              }
3957              if (needSep) {
3958                  pw.println();
3959              }
3960              for (int i=0; i<mUidStates.size(); i++) {
3961                  UidState uidState = mUidStates.valueAt(i);
3962                  final SparseIntArray opModes = uidState.opModes;
3963                  final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
3964  
3965                  if (dumpWatchers || dumpHistory) {
3966                      continue;
3967                  }
3968                  if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
3969                      boolean hasOp = dumpOp < 0 || (uidState.opModes != null
3970                              && uidState.opModes.indexOfKey(dumpOp) >= 0);
3971                      boolean hasPackage = dumpPackage == null;
3972                      boolean hasMode = dumpMode < 0;
3973                      if (!hasMode && opModes != null) {
3974                          for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
3975                              if (opModes.valueAt(opi) == dumpMode) {
3976                                  hasMode = true;
3977                              }
3978                          }
3979                      }
3980                      if (pkgOps != null) {
3981                          for (int pkgi = 0;
3982                                   (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
3983                                   pkgi++) {
3984                              Ops ops = pkgOps.valueAt(pkgi);
3985                              if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
3986                                  hasOp = true;
3987                              }
3988                              if (!hasMode) {
3989                                  for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
3990                                      if (ops.valueAt(opi).mode == dumpMode) {
3991                                          hasMode = true;
3992                                      }
3993                                  }
3994                              }
3995                              if (!hasPackage && dumpPackage.equals(ops.packageName)) {
3996                                  hasPackage = true;
3997                              }
3998                          }
3999                      }
4000                      if (uidState.foregroundOps != null && !hasOp) {
4001                          if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
4002                              hasOp = true;
4003                          }
4004                      }
4005                      if (!hasOp || !hasPackage || !hasMode) {
4006                          continue;
4007                      }
4008                  }
4009  
4010                  pw.print("  Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
4011                  pw.print("    state=");
4012                  pw.println(AppOpsManager.getUidStateName(uidState.state));
4013                  if (uidState.state != uidState.pendingState) {
4014                      pw.print("    pendingState=");
4015                      pw.println(AppOpsManager.getUidStateName(uidState.pendingState));
4016                  }
4017                  if (uidState.pendingStateCommitTime != 0) {
4018                      pw.print("    pendingStateCommitTime=");
4019                      TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw);
4020                      pw.println();
4021                  }
4022                  if (uidState.startNesting != 0) {
4023                      pw.print("    startNesting=");
4024                      pw.println(uidState.startNesting);
4025                  }
4026                  if (uidState.foregroundOps != null && (dumpMode < 0
4027                          || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
4028                      pw.println("    foregroundOps:");
4029                      for (int j = 0; j < uidState.foregroundOps.size(); j++) {
4030                          if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
4031                              continue;
4032                          }
4033                          pw.print("      ");
4034                          pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
4035                          pw.print(": ");
4036                          pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
4037                      }
4038                      pw.print("    hasForegroundWatchers=");
4039                      pw.println(uidState.hasForegroundWatchers);
4040                  }
4041                  needSep = true;
4042  
4043                  if (opModes != null) {
4044                      final int opModeCount = opModes.size();
4045                      for (int j = 0; j < opModeCount; j++) {
4046                          final int code = opModes.keyAt(j);
4047                          final int mode = opModes.valueAt(j);
4048                          if (dumpOp >= 0 && dumpOp != code) {
4049                              continue;
4050                          }
4051                          if (dumpMode >= 0 && dumpMode != mode) {
4052                              continue;
4053                          }
4054                          pw.print("      "); pw.print(AppOpsManager.opToName(code));
4055                          pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
4056                      }
4057                  }
4058  
4059                  if (pkgOps == null) {
4060                      continue;
4061                  }
4062  
4063                  for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
4064                      final Ops ops = pkgOps.valueAt(pkgi);
4065                      if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
4066                          continue;
4067                      }
4068                      boolean printedPackage = false;
4069                      for (int j=0; j<ops.size(); j++) {
4070                          final Op op = ops.valueAt(j);
4071                          final int opCode = op.op;
4072                          if (dumpOp >= 0 && dumpOp != opCode) {
4073                              continue;
4074                          }
4075                          if (dumpMode >= 0 && dumpMode != op.mode) {
4076                              continue;
4077                          }
4078                          if (!printedPackage) {
4079                              pw.print("    Package "); pw.print(ops.packageName); pw.println(":");
4080                              printedPackage = true;
4081                          }
4082                          pw.print("      "); pw.print(AppOpsManager.opToName(opCode));
4083                          pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
4084                          final int switchOp = AppOpsManager.opToSwitch(opCode);
4085                          if (switchOp != opCode) {
4086                              pw.print(" / switch ");
4087                              pw.print(AppOpsManager.opToName(switchOp));
4088                              final Op switchObj = ops.get(switchOp);
4089                              int mode = switchObj != null ? switchObj.mode
4090                                      : AppOpsManager.opToDefaultMode(switchOp);
4091                              pw.print("="); pw.print(AppOpsManager.modeToName(mode));
4092                          }
4093                          pw.println("): ");
4094                          dumpStatesLocked(pw, op, now, sdf, date, "          ");
4095                          if (op.running) {
4096                              pw.print("          Running start at: ");
4097                              TimeUtils.formatDuration(nowElapsed-op.startRealtime, pw);
4098                              pw.println();
4099                          }
4100                          if (op.startNesting != 0) {
4101                              pw.print("          startNesting=");
4102                              pw.println(op.startNesting);
4103                          }
4104                      }
4105                  }
4106              }
4107              if (needSep) {
4108                  pw.println();
4109              }
4110  
4111              final int userRestrictionCount = mOpUserRestrictions.size();
4112              for (int i = 0; i < userRestrictionCount; i++) {
4113                  IBinder token = mOpUserRestrictions.keyAt(i);
4114                  ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
4115                  boolean printedTokenHeader = false;
4116  
4117                  if (dumpMode >= 0 || dumpWatchers || dumpHistory) {
4118                      continue;
4119                  }
4120  
4121                  final int restrictionCount = restrictionState.perUserRestrictions != null
4122                          ? restrictionState.perUserRestrictions.size() : 0;
4123                  if (restrictionCount > 0 && dumpPackage == null) {
4124                      boolean printedOpsHeader = false;
4125                      for (int j = 0; j < restrictionCount; j++) {
4126                          int userId = restrictionState.perUserRestrictions.keyAt(j);
4127                          boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
4128                          if (restrictedOps == null) {
4129                              continue;
4130                          }
4131                          if (dumpOp >= 0 && (dumpOp >= restrictedOps.length
4132                                  || !restrictedOps[dumpOp])) {
4133                              continue;
4134                          }
4135                          if (!printedTokenHeader) {
4136                              pw.println("  User restrictions for token " + token + ":");
4137                              printedTokenHeader = true;
4138                          }
4139                          if (!printedOpsHeader) {
4140                              pw.println("      Restricted ops:");
4141                              printedOpsHeader = true;
4142                          }
4143                          StringBuilder restrictedOpsValue = new StringBuilder();
4144                          restrictedOpsValue.append("[");
4145                          final int restrictedOpCount = restrictedOps.length;
4146                          for (int k = 0; k < restrictedOpCount; k++) {
4147                              if (restrictedOps[k]) {
4148                                  if (restrictedOpsValue.length() > 1) {
4149                                      restrictedOpsValue.append(", ");
4150                                  }
4151                                  restrictedOpsValue.append(AppOpsManager.opToName(k));
4152                              }
4153                          }
4154                          restrictedOpsValue.append("]");
4155                          pw.print("        "); pw.print("user: "); pw.print(userId);
4156                                  pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
4157                      }
4158                  }
4159  
4160                  final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
4161                          ? restrictionState.perUserExcludedPackages.size() : 0;
4162                  if (excludedPackageCount > 0 && dumpOp < 0) {
4163                      boolean printedPackagesHeader = false;
4164                      for (int j = 0; j < excludedPackageCount; j++) {
4165                          int userId = restrictionState.perUserExcludedPackages.keyAt(j);
4166                          String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
4167                          if (packageNames == null) {
4168                              continue;
4169                          }
4170                          boolean hasPackage;
4171                          if (dumpPackage != null) {
4172                              hasPackage = false;
4173                              for (String pkg : packageNames) {
4174                                  if (dumpPackage.equals(pkg)) {
4175                                      hasPackage = true;
4176                                      break;
4177                                  }
4178                              }
4179                          } else {
4180                              hasPackage = true;
4181                          }
4182                          if (!hasPackage) {
4183                              continue;
4184                          }
4185                          if (!printedTokenHeader) {
4186                              pw.println("  User restrictions for token " + token + ":");
4187                              printedTokenHeader = true;
4188                          }
4189                          if (!printedPackagesHeader) {
4190                              pw.println("      Excluded packages:");
4191                              printedPackagesHeader = true;
4192                          }
4193                          pw.print("        "); pw.print("user: "); pw.print(userId);
4194                                  pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
4195                      }
4196                  }
4197              }
4198          }
4199  
4200          // Must not hold the appops lock
4201          if (dumpHistory && !dumpWatchers) {
4202              mHistoricalRegistry.dump("  ", pw, dumpUid, dumpPackage, dumpOp);
4203          }
4204      }
4205  
4206      private static final class Restriction {
4207          private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
4208          int mode;
4209          ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
4210      }
4211  
4212      @Override
setUserRestrictions(Bundle restrictions, IBinder token, int userHandle)4213      public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
4214          checkSystemUid("setUserRestrictions");
4215          Preconditions.checkNotNull(restrictions);
4216          Preconditions.checkNotNull(token);
4217          for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
4218              String restriction = AppOpsManager.opToRestriction(i);
4219              if (restriction != null) {
4220                  setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
4221                          userHandle, null);
4222              }
4223          }
4224      }
4225  
4226      @Override
setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, String[] exceptionPackages)4227      public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
4228              String[] exceptionPackages) {
4229          if (Binder.getCallingPid() != Process.myPid()) {
4230              mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
4231                      Binder.getCallingPid(), Binder.getCallingUid(), null);
4232          }
4233          if (userHandle != UserHandle.getCallingUserId()) {
4234              if (mContext.checkCallingOrSelfPermission(Manifest.permission
4235                      .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
4236                  && mContext.checkCallingOrSelfPermission(Manifest.permission
4237                      .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
4238                  throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
4239                          + " INTERACT_ACROSS_USERS to interact cross user ");
4240              }
4241          }
4242          verifyIncomingOp(code);
4243          Preconditions.checkNotNull(token);
4244          setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
4245      }
4246  
setUserRestrictionNoCheck(int code, boolean restricted, IBinder token, int userHandle, String[] exceptionPackages)4247      private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
4248              int userHandle, String[] exceptionPackages) {
4249          synchronized (AppOpsService.this) {
4250              ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
4251  
4252              if (restrictionState == null) {
4253                  try {
4254                      restrictionState = new ClientRestrictionState(token);
4255                  } catch (RemoteException e) {
4256                      return;
4257                  }
4258                  mOpUserRestrictions.put(token, restrictionState);
4259              }
4260  
4261              if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
4262                  mHandler.sendMessage(PooledLambda.obtainMessage(
4263                          AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
4264              }
4265  
4266              if (restrictionState.isDefault()) {
4267                  mOpUserRestrictions.remove(token);
4268                  restrictionState.destroy();
4269              }
4270          }
4271      }
4272  
notifyWatchersOfChange(int code, int uid)4273      private void notifyWatchersOfChange(int code, int uid) {
4274          final ArraySet<ModeCallback> clonedCallbacks;
4275          synchronized (this) {
4276              ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
4277              if (callbacks == null) {
4278                  return;
4279              }
4280              clonedCallbacks = new ArraySet<>(callbacks);
4281          }
4282  
4283          notifyOpChanged(clonedCallbacks,  code, uid, null);
4284      }
4285  
4286      @Override
removeUser(int userHandle)4287      public void removeUser(int userHandle) throws RemoteException {
4288          checkSystemUid("removeUser");
4289          synchronized (AppOpsService.this) {
4290              final int tokenCount = mOpUserRestrictions.size();
4291              for (int i = tokenCount - 1; i >= 0; i--) {
4292                  ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
4293                  opRestrictions.removeUser(userHandle);
4294              }
4295              removeUidsForUserLocked(userHandle);
4296          }
4297      }
4298  
4299      @Override
isOperationActive(int code, int uid, String packageName)4300      public boolean isOperationActive(int code, int uid, String packageName) {
4301          if (Binder.getCallingUid() != uid) {
4302              if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
4303                      != PackageManager.PERMISSION_GRANTED) {
4304                  return false;
4305              }
4306          }
4307          verifyIncomingOp(code);
4308          final String resolvedPackageName = resolvePackageName(uid, packageName);
4309          if (resolvedPackageName == null) {
4310              return false;
4311          }
4312          synchronized (AppOpsService.this) {
4313              for (int i = mClients.size() - 1; i >= 0; i--) {
4314                  final ClientState client = mClients.valueAt(i);
4315                  for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
4316                      final Op op = client.mStartedOps.get(j);
4317                      if (op.op == code && op.uidState.uid == uid) return true;
4318                  }
4319              }
4320          }
4321          return false;
4322      }
4323  
4324      @Override
setHistoryParameters(@ppOpsManager.HistoricalMode int mode, long baseSnapshotInterval, int compressionStep)4325      public void setHistoryParameters(@AppOpsManager.HistoricalMode int mode,
4326              long baseSnapshotInterval, int compressionStep) {
4327          mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
4328                  "setHistoryParameters");
4329          // Must not hold the appops lock
4330          mHistoricalRegistry.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
4331      }
4332  
4333      @Override
offsetHistory(long offsetMillis)4334      public void offsetHistory(long offsetMillis) {
4335          mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
4336                  "offsetHistory");
4337          // Must not hold the appops lock
4338          mHistoricalRegistry.offsetHistory(offsetMillis);
4339      }
4340  
4341      @Override
addHistoricalOps(HistoricalOps ops)4342      public void addHistoricalOps(HistoricalOps ops) {
4343          mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
4344                  "addHistoricalOps");
4345          // Must not hold the appops lock
4346          mHistoricalRegistry.addHistoricalOps(ops);
4347      }
4348  
4349      @Override
resetHistoryParameters()4350      public void resetHistoryParameters() {
4351          mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
4352                  "resetHistoryParameters");
4353          // Must not hold the appops lock
4354          mHistoricalRegistry.resetHistoryParameters();
4355      }
4356  
4357      @Override
clearHistory()4358      public void clearHistory() {
4359          mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
4360                  "clearHistory");
4361          // Must not hold the appops lock
4362          mHistoricalRegistry.clearHistory();
4363      }
4364  
removeUidsForUserLocked(int userHandle)4365      private void removeUidsForUserLocked(int userHandle) {
4366          for (int i = mUidStates.size() - 1; i >= 0; --i) {
4367              final int uid = mUidStates.keyAt(i);
4368              if (UserHandle.getUserId(uid) == userHandle) {
4369                  mUidStates.removeAt(i);
4370              }
4371          }
4372      }
4373  
checkSystemUid(String function)4374      private void checkSystemUid(String function) {
4375          int uid = Binder.getCallingUid();
4376          if (uid != Process.SYSTEM_UID) {
4377              throw new SecurityException(function + " must by called by the system");
4378          }
4379      }
4380  
resolvePackageName(int uid, String packageName)4381      private static String resolvePackageName(int uid, String packageName)  {
4382          if (uid == Process.ROOT_UID) {
4383              return "root";
4384          } else if (uid == Process.SHELL_UID) {
4385              return "com.android.shell";
4386          } else if (uid == Process.MEDIA_UID) {
4387              return "media";
4388          } else if (uid == Process.AUDIOSERVER_UID) {
4389              return "audioserver";
4390          } else if (uid == Process.CAMERASERVER_UID) {
4391              return "cameraserver";
4392          } else if (uid == Process.SYSTEM_UID && packageName == null) {
4393              return "android";
4394          }
4395          return packageName;
4396      }
4397  
resolveUid(String packageName)4398      private static int resolveUid(String packageName)  {
4399          if (packageName == null) {
4400              return -1;
4401          }
4402          switch (packageName) {
4403              case "root":
4404                  return Process.ROOT_UID;
4405              case "shell":
4406                  return Process.SHELL_UID;
4407              case "media":
4408                  return Process.MEDIA_UID;
4409              case "audioserver":
4410                  return Process.AUDIOSERVER_UID;
4411              case "cameraserver":
4412                  return Process.CAMERASERVER_UID;
4413          }
4414          return -1;
4415      }
4416  
getPackagesForUid(int uid)4417      private static String[] getPackagesForUid(int uid) {
4418          String[] packageNames = null;
4419  
4420          // Very early during boot the package manager is not yet or not yet fully started. At this
4421          // time there are no packages yet.
4422          if (AppGlobals.getPackageManager() != null) {
4423              try {
4424                  packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
4425              } catch (RemoteException e) {
4426                  /* ignore - local call */
4427              }
4428          }
4429          if (packageNames == null) {
4430              return EmptyArray.STRING;
4431          }
4432          return packageNames;
4433      }
4434  
4435      private final class ClientRestrictionState implements DeathRecipient {
4436          private final IBinder token;
4437          SparseArray<boolean[]> perUserRestrictions;
4438          SparseArray<String[]> perUserExcludedPackages;
4439  
ClientRestrictionState(IBinder token)4440          public ClientRestrictionState(IBinder token)
4441                  throws RemoteException {
4442              token.linkToDeath(this, 0);
4443              this.token = token;
4444          }
4445  
setRestriction(int code, boolean restricted, String[] excludedPackages, int userId)4446          public boolean setRestriction(int code, boolean restricted,
4447                  String[] excludedPackages, int userId) {
4448              boolean changed = false;
4449  
4450              if (perUserRestrictions == null && restricted) {
4451                  perUserRestrictions = new SparseArray<>();
4452              }
4453  
4454              int[] users;
4455              if (userId == UserHandle.USER_ALL) {
4456                  List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
4457  
4458                  users = new int[liveUsers.size()];
4459                  for (int i = 0; i < liveUsers.size(); i++) {
4460                      users[i] = liveUsers.get(i).id;
4461                  }
4462              } else {
4463                  users = new int[]{userId};
4464              }
4465  
4466              if (perUserRestrictions != null) {
4467                  int numUsers = users.length;
4468  
4469                  for (int i = 0; i < numUsers; i++) {
4470                      int thisUserId = users[i];
4471  
4472                      boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
4473                      if (userRestrictions == null && restricted) {
4474                          userRestrictions = new boolean[AppOpsManager._NUM_OP];
4475                          perUserRestrictions.put(thisUserId, userRestrictions);
4476                      }
4477                      if (userRestrictions != null && userRestrictions[code] != restricted) {
4478                          userRestrictions[code] = restricted;
4479                          if (!restricted && isDefault(userRestrictions)) {
4480                              perUserRestrictions.remove(thisUserId);
4481                              userRestrictions = null;
4482                          }
4483                          changed = true;
4484                      }
4485  
4486                      if (userRestrictions != null) {
4487                          final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
4488                          if (perUserExcludedPackages == null && !noExcludedPackages) {
4489                              perUserExcludedPackages = new SparseArray<>();
4490                          }
4491                          if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
4492                                  perUserExcludedPackages.get(thisUserId))) {
4493                              if (noExcludedPackages) {
4494                                  perUserExcludedPackages.remove(thisUserId);
4495                                  if (perUserExcludedPackages.size() <= 0) {
4496                                      perUserExcludedPackages = null;
4497                                  }
4498                              } else {
4499                                  perUserExcludedPackages.put(thisUserId, excludedPackages);
4500                              }
4501                              changed = true;
4502                          }
4503                      }
4504                  }
4505              }
4506  
4507              return changed;
4508          }
4509  
hasRestriction(int restriction, String packageName, int userId)4510          public boolean hasRestriction(int restriction, String packageName, int userId) {
4511              if (perUserRestrictions == null) {
4512                  return false;
4513              }
4514              boolean[] restrictions = perUserRestrictions.get(userId);
4515              if (restrictions == null) {
4516                  return false;
4517              }
4518              if (!restrictions[restriction]) {
4519                  return false;
4520              }
4521              if (perUserExcludedPackages == null) {
4522                  return true;
4523              }
4524              String[] perUserExclusions = perUserExcludedPackages.get(userId);
4525              if (perUserExclusions == null) {
4526                  return true;
4527              }
4528              return !ArrayUtils.contains(perUserExclusions, packageName);
4529          }
4530  
removeUser(int userId)4531          public void removeUser(int userId) {
4532              if (perUserExcludedPackages != null) {
4533                  perUserExcludedPackages.remove(userId);
4534                  if (perUserExcludedPackages.size() <= 0) {
4535                      perUserExcludedPackages = null;
4536                  }
4537              }
4538              if (perUserRestrictions != null) {
4539                  perUserRestrictions.remove(userId);
4540                  if (perUserRestrictions.size() <= 0) {
4541                      perUserRestrictions = null;
4542                  }
4543              }
4544          }
4545  
isDefault()4546          public boolean isDefault() {
4547              return perUserRestrictions == null || perUserRestrictions.size() <= 0;
4548          }
4549  
4550          @Override
binderDied()4551          public void binderDied() {
4552              synchronized (AppOpsService.this) {
4553                  mOpUserRestrictions.remove(token);
4554                  if (perUserRestrictions == null) {
4555                      return;
4556                  }
4557                  final int userCount = perUserRestrictions.size();
4558                  for (int i = 0; i < userCount; i++) {
4559                      final boolean[] restrictions = perUserRestrictions.valueAt(i);
4560                      final int restrictionCount = restrictions.length;
4561                      for (int j = 0; j < restrictionCount; j++) {
4562                          if (restrictions[j]) {
4563                              final int changedCode = j;
4564                              mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
4565                          }
4566                      }
4567                  }
4568                  destroy();
4569              }
4570          }
4571  
destroy()4572          public void destroy() {
4573              token.unlinkToDeath(this, 0);
4574          }
4575  
isDefault(boolean[] array)4576          private boolean isDefault(boolean[] array) {
4577              if (ArrayUtils.isEmpty(array)) {
4578                  return true;
4579              }
4580              for (boolean value : array) {
4581                  if (value) {
4582                      return false;
4583                  }
4584              }
4585              return true;
4586          }
4587      }
4588  
4589      private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
setDeviceAndProfileOwners(SparseIntArray owners)4590          @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
4591              synchronized (AppOpsService.this) {
4592                  mProfileOwners = owners;
4593              }
4594          }
4595  
4596          @Override
setUidMode(int code, int uid, int mode)4597          public void setUidMode(int code, int uid, int mode) {
4598              AppOpsService.this.setUidMode(code, uid, mode);
4599          }
4600  
4601          @Override
setAllPkgModesToDefault(int code, int uid)4602          public void setAllPkgModesToDefault(int code, int uid) {
4603              AppOpsService.this.setAllPkgModesToDefault(code, uid);
4604          }
4605  
4606          @Override
checkOperationUnchecked(int code, int uid, @NonNull String packageName)4607          public @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName) {
4608              return AppOpsService.this.checkOperationUnchecked(code, uid, packageName, true, false);
4609          }
4610      }
4611  }
4612