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