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