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;
18 
19 import java.io.File;
20 import java.io.FileDescriptor;
21 import java.io.FileInputStream;
22 import java.io.FileNotFoundException;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.io.PrintWriter;
26 import java.nio.charset.StandardCharsets;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.Map;
34 
35 import android.Manifest;
36 import android.app.ActivityManager;
37 import android.app.ActivityThread;
38 import android.app.AppGlobals;
39 import android.app.AppOpsManager;
40 import android.content.Context;
41 import android.content.pm.ApplicationInfo;
42 import android.content.pm.IPackageManager;
43 import android.content.pm.PackageManager;
44 import android.content.pm.PackageManagerInternal;
45 import android.media.AudioAttributes;
46 import android.os.AsyncTask;
47 import android.os.Binder;
48 import android.os.Bundle;
49 import android.os.Handler;
50 import android.os.IBinder;
51 import android.os.Process;
52 import android.os.RemoteException;
53 import android.os.ResultReceiver;
54 import android.os.ServiceManager;
55 import android.os.ShellCallback;
56 import android.os.ShellCommand;
57 import android.os.UserHandle;
58 import android.os.storage.StorageManagerInternal;
59 import android.util.ArrayMap;
60 import android.util.ArraySet;
61 import android.util.AtomicFile;
62 import android.util.Log;
63 import android.util.Slog;
64 import android.util.SparseArray;
65 import android.util.SparseIntArray;
66 import android.util.TimeUtils;
67 import android.util.Xml;
68 
69 import com.android.internal.app.IAppOpsService;
70 import com.android.internal.app.IAppOpsCallback;
71 import com.android.internal.os.Zygote;
72 import com.android.internal.util.ArrayUtils;
73 import com.android.internal.util.DumpUtils;
74 import com.android.internal.util.FastXmlSerializer;
75 import com.android.internal.util.Preconditions;
76 import com.android.internal.util.XmlUtils;
77 
78 import libcore.util.EmptyArray;
79 import org.xmlpull.v1.XmlPullParser;
80 import org.xmlpull.v1.XmlPullParserException;
81 import org.xmlpull.v1.XmlSerializer;
82 
83 public class AppOpsService extends IAppOpsService.Stub {
84     static final String TAG = "AppOps";
85     static final boolean DEBUG = false;
86 
87     // Write at most every 30 minutes.
88     static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
89 
90     Context mContext;
91     final AtomicFile mFile;
92     final Handler mHandler;
93 
94     boolean mWriteScheduled;
95     boolean mFastWriteScheduled;
96     final Runnable mWriteRunner = new Runnable() {
97         public void run() {
98             synchronized (AppOpsService.this) {
99                 mWriteScheduled = false;
100                 mFastWriteScheduled = false;
101                 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
102                     @Override protected Void doInBackground(Void... params) {
103                         writeState();
104                         return null;
105                     }
106                 };
107                 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
108             }
109         }
110     };
111 
112     private final SparseArray<UidState> mUidStates = new SparseArray<>();
113 
114     /*
115      * These are app op restrictions imposed per user from various parties.
116      */
117     private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
118 
119     private static final class UidState {
120         public final int uid;
121         public ArrayMap<String, Ops> pkgOps;
122         public SparseIntArray opModes;
123 
UidState(int uid)124         public UidState(int uid) {
125             this.uid = uid;
126         }
127 
clear()128         public void clear() {
129             pkgOps = null;
130             opModes = null;
131         }
132 
isDefault()133         public boolean isDefault() {
134             return (pkgOps == null || pkgOps.isEmpty())
135                     && (opModes == null || opModes.size() <= 0);
136         }
137     }
138 
139     public final static class Ops extends SparseArray<Op> {
140         public final String packageName;
141         public final UidState uidState;
142         public final boolean isPrivileged;
143 
Ops(String _packageName, UidState _uidState, boolean _isPrivileged)144         public Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
145             packageName = _packageName;
146             uidState = _uidState;
147             isPrivileged = _isPrivileged;
148         }
149     }
150 
151     public final static class Op {
152         public final int uid;
153         public final String packageName;
154         public int proxyUid = -1;
155         public String proxyPackageName;
156         public final int op;
157         public int mode;
158         public int duration;
159         public long time;
160         public long rejectTime;
161         public int nesting;
162 
Op(int _uid, String _packageName, int _op)163         public Op(int _uid, String _packageName, int _op) {
164             uid = _uid;
165             packageName = _packageName;
166             op = _op;
167             mode = AppOpsManager.opToDefaultMode(op);
168         }
169     }
170 
171     final SparseArray<ArraySet<Callback>> mOpModeWatchers = new SparseArray<>();
172     final ArrayMap<String, ArraySet<Callback>> mPackageModeWatchers = new ArrayMap<>();
173     final ArrayMap<IBinder, Callback> mModeWatchers = new ArrayMap<>();
174     final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
175 
176     public final class Callback implements DeathRecipient {
177         final IAppOpsCallback mCallback;
178 
Callback(IAppOpsCallback callback)179         public Callback(IAppOpsCallback callback) {
180             mCallback = callback;
181             try {
182                 mCallback.asBinder().linkToDeath(this, 0);
183             } catch (RemoteException e) {
184             }
185         }
186 
unlinkToDeath()187         public void unlinkToDeath() {
188             mCallback.asBinder().unlinkToDeath(this, 0);
189         }
190 
191         @Override
binderDied()192         public void binderDied() {
193             stopWatchingMode(mCallback);
194         }
195     }
196 
197     final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<IBinder, ClientState>();
198 
199     public final class ClientState extends Binder implements DeathRecipient {
200         final IBinder mAppToken;
201         final int mPid;
202         final ArrayList<Op> mStartedOps;
203 
ClientState(IBinder appToken)204         public ClientState(IBinder appToken) {
205             mAppToken = appToken;
206             mPid = Binder.getCallingPid();
207             if (appToken instanceof Binder) {
208                 // For local clients, there is no reason to track them.
209                 mStartedOps = null;
210             } else {
211                 mStartedOps = new ArrayList<Op>();
212                 try {
213                     mAppToken.linkToDeath(this, 0);
214                 } catch (RemoteException e) {
215                 }
216             }
217         }
218 
219         @Override
toString()220         public String toString() {
221             return "ClientState{" +
222                     "mAppToken=" + mAppToken +
223                     ", " + (mStartedOps != null ? ("pid=" + mPid) : "local") +
224                     '}';
225         }
226 
227         @Override
binderDied()228         public void binderDied() {
229             synchronized (AppOpsService.this) {
230                 for (int i=mStartedOps.size()-1; i>=0; i--) {
231                     finishOperationLocked(mStartedOps.get(i));
232                 }
233                 mClients.remove(mAppToken);
234             }
235         }
236     }
237 
AppOpsService(File storagePath, Handler handler)238     public AppOpsService(File storagePath, Handler handler) {
239         LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
240         mFile = new AtomicFile(storagePath);
241         mHandler = handler;
242         readState();
243     }
244 
publish(Context context)245     public void publish(Context context) {
246         mContext = context;
247         ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
248     }
249 
systemReady()250     public void systemReady() {
251         synchronized (this) {
252             boolean changed = false;
253             for (int i = mUidStates.size() - 1; i >= 0; i--) {
254                 UidState uidState = mUidStates.valueAt(i);
255 
256                 String[] packageNames = getPackagesForUid(uidState.uid);
257                 if (ArrayUtils.isEmpty(packageNames)) {
258                     uidState.clear();
259                     mUidStates.removeAt(i);
260                     changed = true;
261                     continue;
262                 }
263 
264                 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
265                 if (pkgs == null) {
266                     continue;
267                 }
268 
269                 Iterator<Ops> it = pkgs.values().iterator();
270                 while (it.hasNext()) {
271                     Ops ops = it.next();
272                     int curUid = -1;
273                     try {
274                         curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
275                                 PackageManager.MATCH_UNINSTALLED_PACKAGES,
276                                 UserHandle.getUserId(ops.uidState.uid));
277                     } catch (RemoteException ignored) {
278                     }
279                     if (curUid != ops.uidState.uid) {
280                         Slog.i(TAG, "Pruning old package " + ops.packageName
281                                 + "/" + ops.uidState + ": new uid=" + curUid);
282                         it.remove();
283                         changed = true;
284                     }
285                 }
286 
287                 if (uidState.isDefault()) {
288                     mUidStates.removeAt(i);
289                 }
290             }
291             if (changed) {
292                 scheduleFastWriteLocked();
293             }
294         }
295 
296         PackageManagerInternal packageManagerInternal = LocalServices.getService(
297                 PackageManagerInternal.class);
298         packageManagerInternal.setExternalSourcesPolicy(
299                 new PackageManagerInternal.ExternalSourcesPolicy() {
300                     @Override
301                     public int getPackageTrustedToInstallApps(String packageName, int uid) {
302                         int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
303                                 uid, packageName);
304                         switch (appOpMode) {
305                             case AppOpsManager.MODE_ALLOWED:
306                                 return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
307                             case AppOpsManager.MODE_ERRORED:
308                                 return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
309                             default:
310                                 return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
311                         }
312                     }
313                 });
314 
315         StorageManagerInternal storageManagerInternal = LocalServices.getService(
316                 StorageManagerInternal.class);
317         storageManagerInternal.addExternalStoragePolicy(
318                 new StorageManagerInternal.ExternalStorageMountPolicy() {
319                     @Override
320                     public int getMountMode(int uid, String packageName) {
321                         if (Process.isIsolated(uid)) {
322                             return Zygote.MOUNT_EXTERNAL_NONE;
323                         }
324                         if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
325                                 packageName) != AppOpsManager.MODE_ALLOWED) {
326                             return Zygote.MOUNT_EXTERNAL_NONE;
327                         }
328                         if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
329                                 packageName) != AppOpsManager.MODE_ALLOWED) {
330                             return Zygote.MOUNT_EXTERNAL_READ;
331                         }
332                         return Zygote.MOUNT_EXTERNAL_WRITE;
333                     }
334 
335                     @Override
336                     public boolean hasExternalStorage(int uid, String packageName) {
337                         final int mountMode = getMountMode(uid, packageName);
338                         return mountMode == Zygote.MOUNT_EXTERNAL_READ
339                                 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
340                     }
341                 });
342     }
343 
packageRemoved(int uid, String packageName)344     public void packageRemoved(int uid, String packageName) {
345         synchronized (this) {
346             UidState uidState = mUidStates.get(uid);
347             if (uidState == null) {
348                 return;
349             }
350 
351             boolean changed = false;
352 
353             // Remove any package state if such.
354             if (uidState.pkgOps != null && uidState.pkgOps.remove(packageName) != null) {
355                 changed = true;
356             }
357 
358             // If we just nuked the last package state check if the UID is valid.
359             if (changed && uidState.pkgOps.isEmpty()
360                     && getPackagesForUid(uid).length <= 0) {
361                 mUidStates.remove(uid);
362             }
363 
364             if (changed) {
365                 scheduleFastWriteLocked();
366             }
367         }
368     }
369 
uidRemoved(int uid)370     public void uidRemoved(int uid) {
371         synchronized (this) {
372             if (mUidStates.indexOfKey(uid) >= 0) {
373                 mUidStates.remove(uid);
374                 scheduleFastWriteLocked();
375             }
376         }
377     }
378 
shutdown()379     public void shutdown() {
380         Slog.w(TAG, "Writing app ops before shutdown...");
381         boolean doWrite = false;
382         synchronized (this) {
383             if (mWriteScheduled) {
384                 mWriteScheduled = false;
385                 doWrite = true;
386             }
387         }
388         if (doWrite) {
389             writeState();
390         }
391     }
392 
collectOps(Ops pkgOps, int[] ops)393     private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
394         ArrayList<AppOpsManager.OpEntry> resOps = null;
395         if (ops == null) {
396             resOps = new ArrayList<AppOpsManager.OpEntry>();
397             for (int j=0; j<pkgOps.size(); j++) {
398                 Op curOp = pkgOps.valueAt(j);
399                 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
400                         curOp.rejectTime, curOp.duration, curOp.proxyUid,
401                         curOp.proxyPackageName));
402             }
403         } else {
404             for (int j=0; j<ops.length; j++) {
405                 Op curOp = pkgOps.get(ops[j]);
406                 if (curOp != null) {
407                     if (resOps == null) {
408                         resOps = new ArrayList<AppOpsManager.OpEntry>();
409                     }
410                     resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
411                             curOp.rejectTime, curOp.duration, curOp.proxyUid,
412                             curOp.proxyPackageName));
413                 }
414             }
415         }
416         return resOps;
417     }
418 
collectOps(SparseIntArray uidOps, int[] ops)419     private ArrayList<AppOpsManager.OpEntry> collectOps(SparseIntArray uidOps, int[] ops) {
420         ArrayList<AppOpsManager.OpEntry> resOps = null;
421         if (ops == null) {
422             resOps = new ArrayList<>();
423             for (int j=0; j<uidOps.size(); j++) {
424                 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(j), uidOps.valueAt(j),
425                         0, 0, 0, -1, null));
426             }
427         } else {
428             for (int j=0; j<ops.length; j++) {
429                 int index = uidOps.indexOfKey(ops[j]);
430                 if (index >= 0) {
431                     if (resOps == null) {
432                         resOps = new ArrayList<>();
433                     }
434                     resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(index), uidOps.valueAt(index),
435                             0, 0, 0, -1, null));
436                 }
437             }
438         }
439         return resOps;
440     }
441 
442     @Override
getPackagesForOps(int[] ops)443     public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
444         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
445                 Binder.getCallingPid(), Binder.getCallingUid(), null);
446         ArrayList<AppOpsManager.PackageOps> res = null;
447         synchronized (this) {
448             final int uidStateCount = mUidStates.size();
449             for (int i = 0; i < uidStateCount; i++) {
450                 UidState uidState = mUidStates.valueAt(i);
451                 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
452                     continue;
453                 }
454                 ArrayMap<String, Ops> packages = uidState.pkgOps;
455                 final int packageCount = packages.size();
456                 for (int j = 0; j < packageCount; j++) {
457                     Ops pkgOps = packages.valueAt(j);
458                     ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
459                     if (resOps != null) {
460                         if (res == null) {
461                             res = new ArrayList<AppOpsManager.PackageOps>();
462                         }
463                         AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
464                                 pkgOps.packageName, pkgOps.uidState.uid, resOps);
465                         res.add(resPackage);
466                     }
467                 }
468             }
469         }
470         return res;
471     }
472 
473     @Override
getOpsForPackage(int uid, String packageName, int[] ops)474     public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
475             int[] ops) {
476         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
477                 Binder.getCallingPid(), Binder.getCallingUid(), null);
478         String resolvedPackageName = resolvePackageName(uid, packageName);
479         if (resolvedPackageName == null) {
480             return Collections.emptyList();
481         }
482         synchronized (this) {
483             Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false);
484             if (pkgOps == null) {
485                 return null;
486             }
487             ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
488             if (resOps == null) {
489                 return null;
490             }
491             ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
492             AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
493                     pkgOps.packageName, pkgOps.uidState.uid, resOps);
494             res.add(resPackage);
495             return res;
496         }
497     }
498 
499     @Override
getUidOps(int uid, int[] ops)500     public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
501         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
502                 Binder.getCallingPid(), Binder.getCallingUid(), null);
503         synchronized (this) {
504             UidState uidState = getUidStateLocked(uid, false);
505             if (uidState == null) {
506                 return null;
507             }
508             ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState.opModes, ops);
509             if (resOps == null) {
510                 return null;
511             }
512             ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
513             AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
514                     null, uidState.uid, resOps);
515             res.add(resPackage);
516             return res;
517         }
518     }
519 
pruneOp(Op op, int uid, String packageName)520     private void pruneOp(Op op, int uid, String packageName) {
521         if (op.time == 0 && op.rejectTime == 0) {
522             Ops ops = getOpsRawLocked(uid, packageName, false);
523             if (ops != null) {
524                 ops.remove(op.op);
525                 if (ops.size() <= 0) {
526                     UidState uidState = ops.uidState;
527                     ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
528                     if (pkgOps != null) {
529                         pkgOps.remove(ops.packageName);
530                         if (pkgOps.isEmpty()) {
531                             uidState.pkgOps = null;
532                         }
533                         if (uidState.isDefault()) {
534                             mUidStates.remove(uid);
535                         }
536                     }
537                 }
538             }
539         }
540     }
541 
542     @Override
setUidMode(int code, int uid, int mode)543     public void setUidMode(int code, int uid, int mode) {
544         if (Binder.getCallingPid() != Process.myPid()) {
545             mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
546                     Binder.getCallingPid(), Binder.getCallingUid(), null);
547         }
548         verifyIncomingOp(code);
549         code = AppOpsManager.opToSwitch(code);
550 
551         synchronized (this) {
552             final int defaultMode = AppOpsManager.opToDefaultMode(code);
553 
554             UidState uidState = getUidStateLocked(uid, false);
555             if (uidState == null) {
556                 if (mode == defaultMode) {
557                     return;
558                 }
559                 uidState = new UidState(uid);
560                 uidState.opModes = new SparseIntArray();
561                 uidState.opModes.put(code, mode);
562                 mUidStates.put(uid, uidState);
563                 scheduleWriteLocked();
564             } else if (uidState.opModes == null) {
565                 if (mode != defaultMode) {
566                     uidState.opModes = new SparseIntArray();
567                     uidState.opModes.put(code, mode);
568                     scheduleWriteLocked();
569                 }
570             } else {
571                 if (uidState.opModes.get(code) == mode) {
572                     return;
573                 }
574                 if (mode == defaultMode) {
575                     uidState.opModes.delete(code);
576                     if (uidState.opModes.size() <= 0) {
577                         uidState.opModes = null;
578                     }
579                 } else {
580                     uidState.opModes.put(code, mode);
581                 }
582                 scheduleWriteLocked();
583             }
584         }
585 
586         String[] uidPackageNames = getPackagesForUid(uid);
587         ArrayMap<Callback, ArraySet<String>> callbackSpecs = null;
588 
589         synchronized (this) {
590             ArraySet<Callback> callbacks = mOpModeWatchers.get(code);
591             if (callbacks != null) {
592                 final int callbackCount = callbacks.size();
593                 for (int i = 0; i < callbackCount; i++) {
594                     Callback callback = callbacks.valueAt(i);
595                     ArraySet<String> changedPackages = new ArraySet<>();
596                     Collections.addAll(changedPackages, uidPackageNames);
597                     callbackSpecs = new ArrayMap<>();
598                     callbackSpecs.put(callback, changedPackages);
599                 }
600             }
601 
602             for (String uidPackageName : uidPackageNames) {
603                 callbacks = mPackageModeWatchers.get(uidPackageName);
604                 if (callbacks != null) {
605                     if (callbackSpecs == null) {
606                         callbackSpecs = new ArrayMap<>();
607                     }
608                     final int callbackCount = callbacks.size();
609                     for (int i = 0; i < callbackCount; i++) {
610                         Callback callback = callbacks.valueAt(i);
611                         ArraySet<String> changedPackages = callbackSpecs.get(callback);
612                         if (changedPackages == null) {
613                             changedPackages = new ArraySet<>();
614                             callbackSpecs.put(callback, changedPackages);
615                         }
616                         changedPackages.add(uidPackageName);
617                     }
618                 }
619             }
620         }
621 
622         if (callbackSpecs == null) {
623             return;
624         }
625 
626         // There are components watching for mode changes such as window manager
627         // and location manager which are in our process. The callbacks in these
628         // components may require permissions our remote caller does not have.
629         final long identity = Binder.clearCallingIdentity();
630         try {
631             for (int i = 0; i < callbackSpecs.size(); i++) {
632                 Callback callback = callbackSpecs.keyAt(i);
633                 ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
634                 try {
635                     if (reportedPackageNames == null) {
636                         callback.mCallback.opChanged(code, uid, null);
637                     } else {
638                         final int reportedPackageCount = reportedPackageNames.size();
639                         for (int j = 0; j < reportedPackageCount; j++) {
640                             String reportedPackageName = reportedPackageNames.valueAt(j);
641                             callback.mCallback.opChanged(code, uid, reportedPackageName);
642                         }
643                     }
644                 } catch (RemoteException e) {
645                     Log.w(TAG, "Error dispatching op op change", e);
646                 }
647             }
648         } finally {
649             Binder.restoreCallingIdentity(identity);
650         }
651     }
652 
653     @Override
setMode(int code, int uid, String packageName, int mode)654     public void setMode(int code, int uid, String packageName, int mode) {
655         if (Binder.getCallingPid() != Process.myPid()) {
656             mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
657                     Binder.getCallingPid(), Binder.getCallingUid(), null);
658         }
659         verifyIncomingOp(code);
660         ArrayList<Callback> repCbs = null;
661         code = AppOpsManager.opToSwitch(code);
662         synchronized (this) {
663             UidState uidState = getUidStateLocked(uid, false);
664             Op op = getOpLocked(code, uid, packageName, true);
665             if (op != null) {
666                 if (op.mode != mode) {
667                     op.mode = mode;
668                     ArraySet<Callback> cbs = mOpModeWatchers.get(code);
669                     if (cbs != null) {
670                         if (repCbs == null) {
671                             repCbs = new ArrayList<>();
672                         }
673                         repCbs.addAll(cbs);
674                     }
675                     cbs = mPackageModeWatchers.get(packageName);
676                     if (cbs != null) {
677                         if (repCbs == null) {
678                             repCbs = new ArrayList<>();
679                         }
680                         repCbs.addAll(cbs);
681                     }
682                     if (mode == AppOpsManager.opToDefaultMode(op.op)) {
683                         // If going into the default mode, prune this op
684                         // if there is nothing else interesting in it.
685                         pruneOp(op, uid, packageName);
686                     }
687                     scheduleFastWriteLocked();
688                 }
689             }
690         }
691         if (repCbs != null) {
692             // There are components watching for mode changes such as window manager
693             // and location manager which are in our process. The callbacks in these
694             // components may require permissions our remote caller does not have.
695             final long identity = Binder.clearCallingIdentity();
696             try {
697                 for (int i = 0; i < repCbs.size(); i++) {
698                     try {
699                         repCbs.get(i).mCallback.opChanged(code, uid, packageName);
700                     } catch (RemoteException e) {
701                     }
702                 }
703             } finally {
704                 Binder.restoreCallingIdentity(identity);
705             }
706         }
707     }
708 
addCallbacks( HashMap<Callback, ArrayList<ChangeRec>> callbacks, int op, int uid, String packageName, ArraySet<Callback> cbs)709     private static HashMap<Callback, ArrayList<ChangeRec>> addCallbacks(
710             HashMap<Callback, ArrayList<ChangeRec>> callbacks,
711             int op, int uid, String packageName, ArraySet<Callback> cbs) {
712         if (cbs == null) {
713             return callbacks;
714         }
715         if (callbacks == null) {
716             callbacks = new HashMap<>();
717         }
718         boolean duplicate = false;
719         final int N = cbs.size();
720         for (int i=0; i<N; i++) {
721             Callback cb = cbs.valueAt(i);
722             ArrayList<ChangeRec> reports = callbacks.get(cb);
723             if (reports == null) {
724                 reports = new ArrayList<>();
725                 callbacks.put(cb, reports);
726             } else {
727                 final int reportCount = reports.size();
728                 for (int j = 0; j < reportCount; j++) {
729                     ChangeRec report = reports.get(j);
730                     if (report.op == op && report.pkg.equals(packageName)) {
731                         duplicate = true;
732                         break;
733                     }
734                 }
735             }
736             if (!duplicate) {
737                 reports.add(new ChangeRec(op, uid, packageName));
738             }
739         }
740         return callbacks;
741     }
742 
743     static final class ChangeRec {
744         final int op;
745         final int uid;
746         final String pkg;
747 
ChangeRec(int _op, int _uid, String _pkg)748         ChangeRec(int _op, int _uid, String _pkg) {
749             op = _op;
750             uid = _uid;
751             pkg = _pkg;
752         }
753     }
754 
755     @Override
resetAllModes(int reqUserId, String reqPackageName)756     public void resetAllModes(int reqUserId, String reqPackageName) {
757         final int callingPid = Binder.getCallingPid();
758         final int callingUid = Binder.getCallingUid();
759         mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
760                 callingPid, callingUid, null);
761         reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
762                 true, true, "resetAllModes", null);
763 
764         int reqUid = -1;
765         if (reqPackageName != null) {
766             try {
767                 reqUid = AppGlobals.getPackageManager().getPackageUid(
768                         reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
769             } catch (RemoteException e) {
770                 /* ignore - local call */
771             }
772         }
773 
774         HashMap<Callback, ArrayList<ChangeRec>> callbacks = null;
775         synchronized (this) {
776             boolean changed = false;
777             for (int i = mUidStates.size() - 1; i >= 0; i--) {
778                 UidState uidState = mUidStates.valueAt(i);
779 
780                 SparseIntArray opModes = uidState.opModes;
781                 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
782                     final int uidOpCount = opModes.size();
783                     for (int j = uidOpCount - 1; j >= 0; j--) {
784                         final int code = opModes.keyAt(j);
785                         if (AppOpsManager.opAllowsReset(code)) {
786                             opModes.removeAt(j);
787                             if (opModes.size() <= 0) {
788                                 uidState.opModes = null;
789                             }
790                             for (String packageName : getPackagesForUid(uidState.uid)) {
791                                 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
792                                         mOpModeWatchers.get(code));
793                                 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
794                                         mPackageModeWatchers.get(packageName));
795                             }
796                         }
797                     }
798                 }
799 
800                 if (uidState.pkgOps == null) {
801                     continue;
802                 }
803 
804                 if (reqUserId != UserHandle.USER_ALL
805                         && reqUserId != UserHandle.getUserId(uidState.uid)) {
806                     // Skip any ops for a different user
807                     continue;
808                 }
809 
810                 Map<String, Ops> packages = uidState.pkgOps;
811                 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
812                 while (it.hasNext()) {
813                     Map.Entry<String, Ops> ent = it.next();
814                     String packageName = ent.getKey();
815                     if (reqPackageName != null && !reqPackageName.equals(packageName)) {
816                         // Skip any ops for a different package
817                         continue;
818                     }
819                     Ops pkgOps = ent.getValue();
820                     for (int j=pkgOps.size()-1; j>=0; j--) {
821                         Op curOp = pkgOps.valueAt(j);
822                         if (AppOpsManager.opAllowsReset(curOp.op)
823                                 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
824                             curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
825                             changed = true;
826                             callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
827                                     mOpModeWatchers.get(curOp.op));
828                             callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
829                                     mPackageModeWatchers.get(packageName));
830                             if (curOp.time == 0 && curOp.rejectTime == 0) {
831                                 pkgOps.removeAt(j);
832                             }
833                         }
834                     }
835                     if (pkgOps.size() == 0) {
836                         it.remove();
837                     }
838                 }
839                 if (uidState.isDefault()) {
840                     mUidStates.remove(uidState.uid);
841                 }
842             }
843 
844             if (changed) {
845                 scheduleFastWriteLocked();
846             }
847         }
848         if (callbacks != null) {
849             for (Map.Entry<Callback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
850                 Callback cb = ent.getKey();
851                 ArrayList<ChangeRec> reports = ent.getValue();
852                 for (int i=0; i<reports.size(); i++) {
853                     ChangeRec rep = reports.get(i);
854                     try {
855                         cb.mCallback.opChanged(rep.op, rep.uid, rep.pkg);
856                     } catch (RemoteException e) {
857                     }
858                 }
859             }
860         }
861     }
862 
863     @Override
startWatchingMode(int op, String packageName, IAppOpsCallback callback)864     public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
865         if (callback == null) {
866             return;
867         }
868         synchronized (this) {
869             op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
870             Callback cb = mModeWatchers.get(callback.asBinder());
871             if (cb == null) {
872                 cb = new Callback(callback);
873                 mModeWatchers.put(callback.asBinder(), cb);
874             }
875             if (op != AppOpsManager.OP_NONE) {
876                 ArraySet<Callback> cbs = mOpModeWatchers.get(op);
877                 if (cbs == null) {
878                     cbs = new ArraySet<>();
879                     mOpModeWatchers.put(op, cbs);
880                 }
881                 cbs.add(cb);
882             }
883             if (packageName != null) {
884                 ArraySet<Callback> cbs = mPackageModeWatchers.get(packageName);
885                 if (cbs == null) {
886                     cbs = new ArraySet<>();
887                     mPackageModeWatchers.put(packageName, cbs);
888                 }
889                 cbs.add(cb);
890             }
891         }
892     }
893 
894     @Override
stopWatchingMode(IAppOpsCallback callback)895     public void stopWatchingMode(IAppOpsCallback callback) {
896         if (callback == null) {
897             return;
898         }
899         synchronized (this) {
900             Callback cb = mModeWatchers.remove(callback.asBinder());
901             if (cb != null) {
902                 cb.unlinkToDeath();
903                 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
904                     ArraySet<Callback> cbs = mOpModeWatchers.valueAt(i);
905                     cbs.remove(cb);
906                     if (cbs.size() <= 0) {
907                         mOpModeWatchers.removeAt(i);
908                     }
909                 }
910                 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
911                     ArraySet<Callback> cbs = mPackageModeWatchers.valueAt(i);
912                     cbs.remove(cb);
913                     if (cbs.size() <= 0) {
914                         mPackageModeWatchers.removeAt(i);
915                     }
916                 }
917             }
918         }
919     }
920 
921     @Override
getToken(IBinder clientToken)922     public IBinder getToken(IBinder clientToken) {
923         synchronized (this) {
924             ClientState cs = mClients.get(clientToken);
925             if (cs == null) {
926                 cs = new ClientState(clientToken);
927                 mClients.put(clientToken, cs);
928             }
929             return cs;
930         }
931     }
932 
933     @Override
checkOperation(int code, int uid, String packageName)934     public int checkOperation(int code, int uid, String packageName) {
935         verifyIncomingUid(uid);
936         verifyIncomingOp(code);
937         String resolvedPackageName = resolvePackageName(uid, packageName);
938         if (resolvedPackageName == null) {
939             return AppOpsManager.MODE_IGNORED;
940         }
941         synchronized (this) {
942             if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
943                 return AppOpsManager.MODE_IGNORED;
944             }
945             code = AppOpsManager.opToSwitch(code);
946             UidState uidState = getUidStateLocked(uid, false);
947             if (uidState != null && uidState.opModes != null
948                     && uidState.opModes.indexOfKey(code) >= 0) {
949                 return uidState.opModes.get(code);
950             }
951             Op op = getOpLocked(code, uid, resolvedPackageName, false);
952             if (op == null) {
953                 return AppOpsManager.opToDefaultMode(code);
954             }
955             return op.mode;
956         }
957     }
958 
959     @Override
checkAudioOperation(int code, int usage, int uid, String packageName)960     public int checkAudioOperation(int code, int usage, int uid, String packageName) {
961         boolean suspended;
962         try {
963             suspended = isPackageSuspendedForUser(packageName, uid);
964         } catch (IllegalArgumentException ex) {
965             // Package not found.
966             suspended = false;
967         }
968 
969         if (suspended) {
970             Log.i(TAG, "Audio disabled for suspended package=" + packageName + " for uid=" + uid);
971             return AppOpsManager.MODE_IGNORED;
972         }
973 
974         synchronized (this) {
975             final int mode = checkRestrictionLocked(code, usage, uid, packageName);
976             if (mode != AppOpsManager.MODE_ALLOWED) {
977                 return mode;
978             }
979         }
980         return checkOperation(code, uid, packageName);
981     }
982 
isPackageSuspendedForUser(String pkg, int uid)983     private boolean isPackageSuspendedForUser(String pkg, int uid) {
984         try {
985             return AppGlobals.getPackageManager().isPackageSuspendedForUser(
986                     pkg, UserHandle.getUserId(uid));
987         } catch (RemoteException re) {
988             throw new SecurityException("Could not talk to package manager service");
989         }
990     }
991 
checkRestrictionLocked(int code, int usage, int uid, String packageName)992     private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
993         final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
994         if (usageRestrictions != null) {
995             final Restriction r = usageRestrictions.get(usage);
996             if (r != null && !r.exceptionPackages.contains(packageName)) {
997                 return r.mode;
998             }
999         }
1000         return AppOpsManager.MODE_ALLOWED;
1001     }
1002 
1003     @Override
setAudioRestriction(int code, int usage, int uid, int mode, String[] exceptionPackages)1004     public void setAudioRestriction(int code, int usage, int uid, int mode,
1005             String[] exceptionPackages) {
1006         verifyIncomingUid(uid);
1007         verifyIncomingOp(code);
1008         synchronized (this) {
1009             SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1010             if (usageRestrictions == null) {
1011                 usageRestrictions = new SparseArray<Restriction>();
1012                 mAudioRestrictions.put(code, usageRestrictions);
1013             }
1014             usageRestrictions.remove(usage);
1015             if (mode != AppOpsManager.MODE_ALLOWED) {
1016                 final Restriction r = new Restriction();
1017                 r.mode = mode;
1018                 if (exceptionPackages != null) {
1019                     final int N = exceptionPackages.length;
1020                     r.exceptionPackages = new ArraySet<String>(N);
1021                     for (int i = 0; i < N; i++) {
1022                         final String pkg = exceptionPackages[i];
1023                         if (pkg != null) {
1024                             r.exceptionPackages.add(pkg.trim());
1025                         }
1026                     }
1027                 }
1028                 usageRestrictions.put(usage, r);
1029             }
1030         }
1031         notifyWatchersOfChange(code);
1032     }
1033 
1034     @Override
checkPackage(int uid, String packageName)1035     public int checkPackage(int uid, String packageName) {
1036         Preconditions.checkNotNull(packageName);
1037         synchronized (this) {
1038             if (getOpsRawLocked(uid, packageName, true) != null) {
1039                 return AppOpsManager.MODE_ALLOWED;
1040             } else {
1041                 return AppOpsManager.MODE_ERRORED;
1042             }
1043         }
1044     }
1045 
1046     @Override
noteProxyOperation(int code, String proxyPackageName, int proxiedUid, String proxiedPackageName)1047     public int noteProxyOperation(int code, String proxyPackageName,
1048             int proxiedUid, String proxiedPackageName) {
1049         verifyIncomingOp(code);
1050         final int proxyUid = Binder.getCallingUid();
1051         String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
1052         if (resolveProxyPackageName == null) {
1053             return AppOpsManager.MODE_IGNORED;
1054         }
1055         final int proxyMode = noteOperationUnchecked(code, proxyUid,
1056                 resolveProxyPackageName, -1, null);
1057         if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
1058             return proxyMode;
1059         }
1060         String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
1061         if (resolveProxiedPackageName == null) {
1062             return AppOpsManager.MODE_IGNORED;
1063         }
1064         return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
1065                 proxyMode, resolveProxyPackageName);
1066     }
1067 
1068     @Override
noteOperation(int code, int uid, String packageName)1069     public int noteOperation(int code, int uid, String packageName) {
1070         verifyIncomingUid(uid);
1071         verifyIncomingOp(code);
1072         String resolvedPackageName = resolvePackageName(uid, packageName);
1073         if (resolvedPackageName == null) {
1074             return AppOpsManager.MODE_IGNORED;
1075         }
1076         return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
1077     }
1078 
noteOperationUnchecked(int code, int uid, String packageName, int proxyUid, String proxyPackageName)1079     private int noteOperationUnchecked(int code, int uid, String packageName,
1080             int proxyUid, String proxyPackageName) {
1081         synchronized (this) {
1082             Ops ops = getOpsRawLocked(uid, packageName, true);
1083             if (ops == null) {
1084                 if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
1085                         + " package " + packageName);
1086                 return AppOpsManager.MODE_ERRORED;
1087             }
1088             Op op = getOpLocked(ops, code, true);
1089             if (isOpRestrictedLocked(uid, code, packageName)) {
1090                 return AppOpsManager.MODE_IGNORED;
1091             }
1092             if (op.duration == -1) {
1093                 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
1094                         + " code " + code + " time=" + op.time + " duration=" + op.duration);
1095             }
1096             op.duration = 0;
1097             final int switchCode = AppOpsManager.opToSwitch(code);
1098             UidState uidState = ops.uidState;
1099             // If there is a non-default per UID policy (we set UID op mode only if
1100             // non-default) it takes over, otherwise use the per package policy.
1101             if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
1102                 final int uidMode = uidState.opModes.get(switchCode);
1103                 if (uidMode != AppOpsManager.MODE_ALLOWED) {
1104                     if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
1105                             + switchCode + " (" + code + ") uid " + uid + " package "
1106                             + packageName);
1107                     op.rejectTime = System.currentTimeMillis();
1108                     return uidMode;
1109                 }
1110             } else {
1111                 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
1112                 if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
1113                     if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
1114                             + switchCode + " (" + code + ") uid " + uid + " package "
1115                             + packageName);
1116                     op.rejectTime = System.currentTimeMillis();
1117                     return switchOp.mode;
1118                 }
1119             }
1120             if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
1121                     + " package " + packageName);
1122             op.time = System.currentTimeMillis();
1123             op.rejectTime = 0;
1124             op.proxyUid = proxyUid;
1125             op.proxyPackageName = proxyPackageName;
1126             return AppOpsManager.MODE_ALLOWED;
1127         }
1128     }
1129 
1130     @Override
startOperation(IBinder token, int code, int uid, String packageName)1131     public int startOperation(IBinder token, int code, int uid, String packageName) {
1132         verifyIncomingUid(uid);
1133         verifyIncomingOp(code);
1134         String resolvedPackageName = resolvePackageName(uid, packageName);
1135         if (resolvedPackageName == null) {
1136             return  AppOpsManager.MODE_IGNORED;
1137         }
1138         ClientState client = (ClientState)token;
1139         synchronized (this) {
1140             Ops ops = getOpsRawLocked(uid, resolvedPackageName, true);
1141             if (ops == null) {
1142                 if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
1143                         + " package " + resolvedPackageName);
1144                 return AppOpsManager.MODE_ERRORED;
1145             }
1146             Op op = getOpLocked(ops, code, true);
1147             if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
1148                 return AppOpsManager.MODE_IGNORED;
1149             }
1150             final int switchCode = AppOpsManager.opToSwitch(code);
1151             UidState uidState = ops.uidState;
1152             if (uidState.opModes != null) {
1153                 final int uidMode = uidState.opModes.get(switchCode);
1154                 if (uidMode != AppOpsManager.MODE_ALLOWED) {
1155                     if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
1156                             + switchCode + " (" + code + ") uid " + uid + " package "
1157                             + resolvedPackageName);
1158                     op.rejectTime = System.currentTimeMillis();
1159                     return uidMode;
1160                 }
1161             }
1162             final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
1163             if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
1164                 if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code "
1165                         + switchCode + " (" + code + ") uid " + uid + " package "
1166                         + resolvedPackageName);
1167                 op.rejectTime = System.currentTimeMillis();
1168                 return switchOp.mode;
1169             }
1170             if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid
1171                     + " package " + resolvedPackageName);
1172             if (op.nesting == 0) {
1173                 op.time = System.currentTimeMillis();
1174                 op.rejectTime = 0;
1175                 op.duration = -1;
1176             }
1177             op.nesting++;
1178             if (client.mStartedOps != null) {
1179                 client.mStartedOps.add(op);
1180             }
1181             return AppOpsManager.MODE_ALLOWED;
1182         }
1183     }
1184 
1185     @Override
finishOperation(IBinder token, int code, int uid, String packageName)1186     public void finishOperation(IBinder token, int code, int uid, String packageName) {
1187         verifyIncomingUid(uid);
1188         verifyIncomingOp(code);
1189         String resolvedPackageName = resolvePackageName(uid, packageName);
1190         if (resolvedPackageName == null) {
1191             return;
1192         }
1193         if (!(token instanceof ClientState)) {
1194             return;
1195         }
1196         ClientState client = (ClientState) token;
1197         synchronized (this) {
1198             Op op = getOpLocked(code, uid, resolvedPackageName, true);
1199             if (op == null) {
1200                 return;
1201             }
1202             if (client.mStartedOps != null) {
1203                 if (!client.mStartedOps.remove(op)) {
1204                     throw new IllegalStateException("Operation not started: uid" + op.uid
1205                             + " pkg=" + op.packageName + " op=" + op.op);
1206                 }
1207             }
1208             finishOperationLocked(op);
1209         }
1210     }
1211 
1212     @Override
permissionToOpCode(String permission)1213     public int permissionToOpCode(String permission) {
1214         if (permission == null) {
1215             return AppOpsManager.OP_NONE;
1216         }
1217         return AppOpsManager.permissionToOpCode(permission);
1218     }
1219 
finishOperationLocked(Op op)1220     void finishOperationLocked(Op op) {
1221         if (op.nesting <= 1) {
1222             if (op.nesting == 1) {
1223                 op.duration = (int)(System.currentTimeMillis() - op.time);
1224                 op.time += op.duration;
1225             } else {
1226                 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
1227                         + op.packageName + " code " + op.op + " time=" + op.time
1228                         + " duration=" + op.duration + " nesting=" + op.nesting);
1229             }
1230             op.nesting = 0;
1231         } else {
1232             op.nesting--;
1233         }
1234     }
1235 
verifyIncomingUid(int uid)1236     private void verifyIncomingUid(int uid) {
1237         if (uid == Binder.getCallingUid()) {
1238             return;
1239         }
1240         if (Binder.getCallingPid() == Process.myPid()) {
1241             return;
1242         }
1243         mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
1244                 Binder.getCallingPid(), Binder.getCallingUid(), null);
1245     }
1246 
verifyIncomingOp(int op)1247     private void verifyIncomingOp(int op) {
1248         if (op >= 0 && op < AppOpsManager._NUM_OP) {
1249             return;
1250         }
1251         throw new IllegalArgumentException("Bad operation #" + op);
1252     }
1253 
getUidStateLocked(int uid, boolean edit)1254     private UidState getUidStateLocked(int uid, boolean edit) {
1255         UidState uidState = mUidStates.get(uid);
1256         if (uidState == null) {
1257             if (!edit) {
1258                 return null;
1259             }
1260             uidState = new UidState(uid);
1261             mUidStates.put(uid, uidState);
1262         }
1263         return uidState;
1264     }
1265 
getOpsRawLocked(int uid, String packageName, boolean edit)1266     private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
1267         UidState uidState = getUidStateLocked(uid, edit);
1268         if (uidState == null) {
1269             return null;
1270         }
1271 
1272         if (uidState.pkgOps == null) {
1273             if (!edit) {
1274                 return null;
1275             }
1276             uidState.pkgOps = new ArrayMap<>();
1277         }
1278 
1279         Ops ops = uidState.pkgOps.get(packageName);
1280         if (ops == null) {
1281             if (!edit) {
1282                 return null;
1283             }
1284             boolean isPrivileged = false;
1285             // This is the first time we have seen this package name under this uid,
1286             // so let's make sure it is valid.
1287             if (uid != 0) {
1288                 final long ident = Binder.clearCallingIdentity();
1289                 try {
1290                     int pkgUid = -1;
1291                     try {
1292                         ApplicationInfo appInfo = ActivityThread.getPackageManager()
1293                                 .getApplicationInfo(packageName,
1294                                         PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
1295                                         UserHandle.getUserId(uid));
1296                         if (appInfo != null) {
1297                             pkgUid = appInfo.uid;
1298                             isPrivileged = (appInfo.privateFlags
1299                                     & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
1300                         } else {
1301                             if ("media".equals(packageName)) {
1302                                 pkgUid = Process.MEDIA_UID;
1303                                 isPrivileged = false;
1304                             } else if ("audioserver".equals(packageName)) {
1305                                 pkgUid = Process.AUDIOSERVER_UID;
1306                                 isPrivileged = false;
1307                             } else if ("cameraserver".equals(packageName)) {
1308                                 pkgUid = Process.CAMERASERVER_UID;
1309                                 isPrivileged = false;
1310                             }
1311                         }
1312                     } catch (RemoteException e) {
1313                         Slog.w(TAG, "Could not contact PackageManager", e);
1314                     }
1315                     if (pkgUid != uid) {
1316                         // Oops!  The package name is not valid for the uid they are calling
1317                         // under.  Abort.
1318                         RuntimeException ex = new RuntimeException("here");
1319                         ex.fillInStackTrace();
1320                         Slog.w(TAG, "Bad call: specified package " + packageName
1321                                 + " under uid " + uid + " but it is really " + pkgUid, ex);
1322                         return null;
1323                     }
1324                 } finally {
1325                     Binder.restoreCallingIdentity(ident);
1326                 }
1327             }
1328             ops = new Ops(packageName, uidState, isPrivileged);
1329             uidState.pkgOps.put(packageName, ops);
1330         }
1331         return ops;
1332     }
1333 
scheduleWriteLocked()1334     private void scheduleWriteLocked() {
1335         if (!mWriteScheduled) {
1336             mWriteScheduled = true;
1337             mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
1338         }
1339     }
1340 
scheduleFastWriteLocked()1341     private void scheduleFastWriteLocked() {
1342         if (!mFastWriteScheduled) {
1343             mWriteScheduled = true;
1344             mFastWriteScheduled = true;
1345             mHandler.removeCallbacks(mWriteRunner);
1346             mHandler.postDelayed(mWriteRunner, 10*1000);
1347         }
1348     }
1349 
getOpLocked(int code, int uid, String packageName, boolean edit)1350     private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
1351         Ops ops = getOpsRawLocked(uid, packageName, edit);
1352         if (ops == null) {
1353             return null;
1354         }
1355         return getOpLocked(ops, code, edit);
1356     }
1357 
getOpLocked(Ops ops, int code, boolean edit)1358     private Op getOpLocked(Ops ops, int code, boolean edit) {
1359         Op op = ops.get(code);
1360         if (op == null) {
1361             if (!edit) {
1362                 return null;
1363             }
1364             op = new Op(ops.uidState.uid, ops.packageName, code);
1365             ops.put(code, op);
1366         }
1367         if (edit) {
1368             scheduleWriteLocked();
1369         }
1370         return op;
1371     }
1372 
isOpRestrictedLocked(int uid, int code, String packageName)1373     private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
1374         int userHandle = UserHandle.getUserId(uid);
1375         final int restrictionSetCount = mOpUserRestrictions.size();
1376 
1377         for (int i = 0; i < restrictionSetCount; i++) {
1378             // For each client, check that the given op is not restricted, or that the given
1379             // package is exempt from the restriction.
1380             ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
1381             if (restrictionState.hasRestriction(code, packageName, userHandle)) {
1382                 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
1383                     // If we are the system, bypass user restrictions for certain codes
1384                     synchronized (this) {
1385                         Ops ops = getOpsRawLocked(uid, packageName, true);
1386                         if ((ops != null) && ops.isPrivileged) {
1387                             return false;
1388                         }
1389                     }
1390                 }
1391                 return true;
1392             }
1393         }
1394         return false;
1395     }
1396 
readState()1397     void readState() {
1398         synchronized (mFile) {
1399             synchronized (this) {
1400                 FileInputStream stream;
1401                 try {
1402                     stream = mFile.openRead();
1403                 } catch (FileNotFoundException e) {
1404                     Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
1405                     return;
1406                 }
1407                 boolean success = false;
1408                 mUidStates.clear();
1409                 try {
1410                     XmlPullParser parser = Xml.newPullParser();
1411                     parser.setInput(stream, StandardCharsets.UTF_8.name());
1412                     int type;
1413                     while ((type = parser.next()) != XmlPullParser.START_TAG
1414                             && type != XmlPullParser.END_DOCUMENT) {
1415                         ;
1416                     }
1417 
1418                     if (type != XmlPullParser.START_TAG) {
1419                         throw new IllegalStateException("no start tag found");
1420                     }
1421 
1422                     int outerDepth = parser.getDepth();
1423                     while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1424                             && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1425                         if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1426                             continue;
1427                         }
1428 
1429                         String tagName = parser.getName();
1430                         if (tagName.equals("pkg")) {
1431                             readPackage(parser);
1432                         } else if (tagName.equals("uid")) {
1433                             readUidOps(parser);
1434                         } else {
1435                             Slog.w(TAG, "Unknown element under <app-ops>: "
1436                                     + parser.getName());
1437                             XmlUtils.skipCurrentTag(parser);
1438                         }
1439                     }
1440                     success = true;
1441                 } catch (IllegalStateException e) {
1442                     Slog.w(TAG, "Failed parsing " + e);
1443                 } catch (NullPointerException e) {
1444                     Slog.w(TAG, "Failed parsing " + e);
1445                 } catch (NumberFormatException e) {
1446                     Slog.w(TAG, "Failed parsing " + e);
1447                 } catch (XmlPullParserException e) {
1448                     Slog.w(TAG, "Failed parsing " + e);
1449                 } catch (IOException e) {
1450                     Slog.w(TAG, "Failed parsing " + e);
1451                 } catch (IndexOutOfBoundsException e) {
1452                     Slog.w(TAG, "Failed parsing " + e);
1453                 } finally {
1454                     if (!success) {
1455                         mUidStates.clear();
1456                     }
1457                     try {
1458                         stream.close();
1459                     } catch (IOException e) {
1460                     }
1461                 }
1462             }
1463         }
1464     }
1465 
readUidOps(XmlPullParser parser)1466     void readUidOps(XmlPullParser parser) throws NumberFormatException,
1467             XmlPullParserException, IOException {
1468         final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
1469         int outerDepth = parser.getDepth();
1470         int type;
1471         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1472                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1473             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1474                 continue;
1475             }
1476 
1477             String tagName = parser.getName();
1478             if (tagName.equals("op")) {
1479                 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
1480                 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
1481                 UidState uidState = getUidStateLocked(uid, true);
1482                 if (uidState.opModes == null) {
1483                     uidState.opModes = new SparseIntArray();
1484                 }
1485                 uidState.opModes.put(code, mode);
1486             } else {
1487                 Slog.w(TAG, "Unknown element under <uid-ops>: "
1488                         + parser.getName());
1489                 XmlUtils.skipCurrentTag(parser);
1490             }
1491         }
1492     }
1493 
readPackage(XmlPullParser parser)1494     void readPackage(XmlPullParser parser) throws NumberFormatException,
1495             XmlPullParserException, IOException {
1496         String pkgName = parser.getAttributeValue(null, "n");
1497         int outerDepth = parser.getDepth();
1498         int type;
1499         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1500                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1501             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1502                 continue;
1503             }
1504 
1505             String tagName = parser.getName();
1506             if (tagName.equals("uid")) {
1507                 readUid(parser, pkgName);
1508             } else {
1509                 Slog.w(TAG, "Unknown element under <pkg>: "
1510                         + parser.getName());
1511                 XmlUtils.skipCurrentTag(parser);
1512             }
1513         }
1514     }
1515 
readUid(XmlPullParser parser, String pkgName)1516     void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
1517             XmlPullParserException, IOException {
1518         int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
1519         String isPrivilegedString = parser.getAttributeValue(null, "p");
1520         boolean isPrivileged = false;
1521         if (isPrivilegedString == null) {
1522             try {
1523                 IPackageManager packageManager = ActivityThread.getPackageManager();
1524                 if (packageManager != null) {
1525                     ApplicationInfo appInfo = ActivityThread.getPackageManager()
1526                             .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
1527                     if (appInfo != null) {
1528                         isPrivileged = (appInfo.privateFlags
1529                                 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
1530                     }
1531                 } else {
1532                     // Could not load data, don't add to cache so it will be loaded later.
1533                     return;
1534                 }
1535             } catch (RemoteException e) {
1536                 Slog.w(TAG, "Could not contact PackageManager", e);
1537             }
1538         } else {
1539             isPrivileged = Boolean.parseBoolean(isPrivilegedString);
1540         }
1541         int outerDepth = parser.getDepth();
1542         int type;
1543         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1544                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1545             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1546                 continue;
1547             }
1548 
1549             String tagName = parser.getName();
1550             if (tagName.equals("op")) {
1551                 Op op = new Op(uid, pkgName, Integer.parseInt(parser.getAttributeValue(null, "n")));
1552                 String mode = parser.getAttributeValue(null, "m");
1553                 if (mode != null) {
1554                     op.mode = Integer.parseInt(mode);
1555                 }
1556                 String time = parser.getAttributeValue(null, "t");
1557                 if (time != null) {
1558                     op.time = Long.parseLong(time);
1559                 }
1560                 time = parser.getAttributeValue(null, "r");
1561                 if (time != null) {
1562                     op.rejectTime = Long.parseLong(time);
1563                 }
1564                 String dur = parser.getAttributeValue(null, "d");
1565                 if (dur != null) {
1566                     op.duration = Integer.parseInt(dur);
1567                 }
1568                 String proxyUid = parser.getAttributeValue(null, "pu");
1569                 if (proxyUid != null) {
1570                     op.proxyUid = Integer.parseInt(proxyUid);
1571                 }
1572                 String proxyPackageName = parser.getAttributeValue(null, "pp");
1573                 if (proxyPackageName != null) {
1574                     op.proxyPackageName = proxyPackageName;
1575                 }
1576 
1577                 UidState uidState = getUidStateLocked(uid, true);
1578                 if (uidState.pkgOps == null) {
1579                     uidState.pkgOps = new ArrayMap<>();
1580                 }
1581 
1582                 Ops ops = uidState.pkgOps.get(pkgName);
1583                 if (ops == null) {
1584                     ops = new Ops(pkgName, uidState, isPrivileged);
1585                     uidState.pkgOps.put(pkgName, ops);
1586                 }
1587                 ops.put(op.op, op);
1588             } else {
1589                 Slog.w(TAG, "Unknown element under <pkg>: "
1590                         + parser.getName());
1591                 XmlUtils.skipCurrentTag(parser);
1592             }
1593         }
1594     }
1595 
writeState()1596     void writeState() {
1597         synchronized (mFile) {
1598             List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
1599 
1600             FileOutputStream stream;
1601             try {
1602                 stream = mFile.startWrite();
1603             } catch (IOException e) {
1604                 Slog.w(TAG, "Failed to write state: " + e);
1605                 return;
1606             }
1607 
1608             try {
1609                 XmlSerializer out = new FastXmlSerializer();
1610                 out.setOutput(stream, StandardCharsets.UTF_8.name());
1611                 out.startDocument(null, true);
1612                 out.startTag(null, "app-ops");
1613 
1614                 final int uidStateCount = mUidStates.size();
1615                 for (int i = 0; i < uidStateCount; i++) {
1616                     UidState uidState = mUidStates.valueAt(i);
1617                     if (uidState.opModes != null && uidState.opModes.size() > 0) {
1618                         out.startTag(null, "uid");
1619                         out.attribute(null, "n", Integer.toString(uidState.uid));
1620                         SparseIntArray uidOpModes = uidState.opModes;
1621                         final int opCount = uidOpModes.size();
1622                         for (int j = 0; j < opCount; j++) {
1623                             final int op = uidOpModes.keyAt(j);
1624                             final int mode = uidOpModes.valueAt(j);
1625                             out.startTag(null, "op");
1626                             out.attribute(null, "n", Integer.toString(op));
1627                             out.attribute(null, "m", Integer.toString(mode));
1628                             out.endTag(null, "op");
1629                         }
1630                         out.endTag(null, "uid");
1631                     }
1632                 }
1633 
1634                 if (allOps != null) {
1635                     String lastPkg = null;
1636                     for (int i=0; i<allOps.size(); i++) {
1637                         AppOpsManager.PackageOps pkg = allOps.get(i);
1638                         if (!pkg.getPackageName().equals(lastPkg)) {
1639                             if (lastPkg != null) {
1640                                 out.endTag(null, "pkg");
1641                             }
1642                             lastPkg = pkg.getPackageName();
1643                             out.startTag(null, "pkg");
1644                             out.attribute(null, "n", lastPkg);
1645                         }
1646                         out.startTag(null, "uid");
1647                         out.attribute(null, "n", Integer.toString(pkg.getUid()));
1648                         synchronized (this) {
1649                             Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), false);
1650                             // Should always be present as the list of PackageOps is generated
1651                             // from Ops.
1652                             if (ops != null) {
1653                                 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
1654                             } else {
1655                                 out.attribute(null, "p", Boolean.toString(false));
1656                             }
1657                         }
1658                         List<AppOpsManager.OpEntry> ops = pkg.getOps();
1659                         for (int j=0; j<ops.size(); j++) {
1660                             AppOpsManager.OpEntry op = ops.get(j);
1661                             out.startTag(null, "op");
1662                             out.attribute(null, "n", Integer.toString(op.getOp()));
1663                             if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
1664                                 out.attribute(null, "m", Integer.toString(op.getMode()));
1665                             }
1666                             long time = op.getTime();
1667                             if (time != 0) {
1668                                 out.attribute(null, "t", Long.toString(time));
1669                             }
1670                             time = op.getRejectTime();
1671                             if (time != 0) {
1672                                 out.attribute(null, "r", Long.toString(time));
1673                             }
1674                             int dur = op.getDuration();
1675                             if (dur != 0) {
1676                                 out.attribute(null, "d", Integer.toString(dur));
1677                             }
1678                             int proxyUid = op.getProxyUid();
1679                             if (proxyUid != -1) {
1680                                 out.attribute(null, "pu", Integer.toString(proxyUid));
1681                             }
1682                             String proxyPackageName = op.getProxyPackageName();
1683                             if (proxyPackageName != null) {
1684                                 out.attribute(null, "pp", proxyPackageName);
1685                             }
1686                             out.endTag(null, "op");
1687                         }
1688                         out.endTag(null, "uid");
1689                     }
1690                     if (lastPkg != null) {
1691                         out.endTag(null, "pkg");
1692                     }
1693                 }
1694 
1695                 out.endTag(null, "app-ops");
1696                 out.endDocument();
1697                 mFile.finishWrite(stream);
1698             } catch (IOException e) {
1699                 Slog.w(TAG, "Failed to write state, restoring backup.", e);
1700                 mFile.failWrite(stream);
1701             }
1702         }
1703     }
1704 
1705     static class Shell extends ShellCommand {
1706         final IAppOpsService mInterface;
1707         final AppOpsService mInternal;
1708 
1709         int userId = UserHandle.USER_SYSTEM;
1710         String packageName;
1711         String opStr;
1712         String modeStr;
1713         int op;
1714         int mode;
1715         int packageUid;
1716         int nonpackageUid;
1717 
Shell(IAppOpsService iface, AppOpsService internal)1718         Shell(IAppOpsService iface, AppOpsService internal) {
1719             mInterface = iface;
1720             mInternal = internal;
1721         }
1722 
1723         @Override
onCommand(String cmd)1724         public int onCommand(String cmd) {
1725             return onShellCommand(this, cmd);
1726         }
1727 
1728         @Override
onHelp()1729         public void onHelp() {
1730             PrintWriter pw = getOutPrintWriter();
1731             dumpCommandHelp(pw);
1732         }
1733 
strOpToOp(String op, PrintWriter err)1734         private int strOpToOp(String op, PrintWriter err) {
1735             try {
1736                 return AppOpsManager.strOpToOp(op);
1737             } catch (IllegalArgumentException e) {
1738             }
1739             try {
1740                 return Integer.parseInt(op);
1741             } catch (NumberFormatException e) {
1742             }
1743             try {
1744                 return AppOpsManager.strDebugOpToOp(op);
1745             } catch (IllegalArgumentException e) {
1746                 err.println("Error: " + e.getMessage());
1747                 return -1;
1748             }
1749         }
1750 
strModeToMode(String modeStr, PrintWriter err)1751         int strModeToMode(String modeStr, PrintWriter err) {
1752             switch (modeStr) {
1753                 case "allow":
1754                     return AppOpsManager.MODE_ALLOWED;
1755                 case "deny":
1756                     return AppOpsManager.MODE_ERRORED;
1757                 case "ignore":
1758                     return AppOpsManager.MODE_IGNORED;
1759                 case "default":
1760                     return AppOpsManager.MODE_DEFAULT;
1761             }
1762             try {
1763                 return Integer.parseInt(modeStr);
1764             } catch (NumberFormatException e) {
1765             }
1766             err.println("Error: Mode " + modeStr + " is not valid");
1767             return -1;
1768         }
1769 
parseUserOpMode(int defMode, PrintWriter err)1770         int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
1771             userId = UserHandle.USER_CURRENT;
1772             opStr = null;
1773             modeStr = null;
1774             for (String argument; (argument = getNextArg()) != null;) {
1775                 if ("--user".equals(argument)) {
1776                     userId = UserHandle.parseUserArg(getNextArgRequired());
1777                 } else {
1778                     if (opStr == null) {
1779                         opStr = argument;
1780                     } else if (modeStr == null) {
1781                         modeStr = argument;
1782                         break;
1783                     }
1784                 }
1785             }
1786             if (opStr == null) {
1787                 err.println("Error: Operation not specified.");
1788                 return -1;
1789             }
1790             op = strOpToOp(opStr, err);
1791             if (op < 0) {
1792                 return -1;
1793             }
1794             if (modeStr != null) {
1795                 if ((mode=strModeToMode(modeStr, err)) < 0) {
1796                     return -1;
1797                 }
1798             } else {
1799                 mode = defMode;
1800             }
1801             return 0;
1802         }
1803 
parseUserPackageOp(boolean reqOp, PrintWriter err)1804         int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
1805             userId = UserHandle.USER_CURRENT;
1806             packageName = null;
1807             opStr = null;
1808             for (String argument; (argument = getNextArg()) != null;) {
1809                 if ("--user".equals(argument)) {
1810                     userId = UserHandle.parseUserArg(getNextArgRequired());
1811                 } else {
1812                     if (packageName == null) {
1813                         packageName = argument;
1814                     } else if (opStr == null) {
1815                         opStr = argument;
1816                         break;
1817                     }
1818                 }
1819             }
1820             if (packageName == null) {
1821                 err.println("Error: Package name not specified.");
1822                 return -1;
1823             } else if (opStr == null && reqOp) {
1824                 err.println("Error: Operation not specified.");
1825                 return -1;
1826             }
1827             if (opStr != null) {
1828                 op = strOpToOp(opStr, err);
1829                 if (op < 0) {
1830                     return -1;
1831                 }
1832             } else {
1833                 op = AppOpsManager.OP_NONE;
1834             }
1835             if (userId == UserHandle.USER_CURRENT) {
1836                 userId = ActivityManager.getCurrentUser();
1837             }
1838             nonpackageUid = -1;
1839             try {
1840                 nonpackageUid = Integer.parseInt(packageName);
1841             } catch (NumberFormatException e) {
1842             }
1843             if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
1844                     && packageName.indexOf('.') < 0) {
1845                 int i = 1;
1846                 while (i < packageName.length() && packageName.charAt(i) >= '0'
1847                         && packageName.charAt(i) <= '9') {
1848                     i++;
1849                 }
1850                 if (i > 1 && i < packageName.length()) {
1851                     String userStr = packageName.substring(1, i);
1852                     try {
1853                         int user = Integer.parseInt(userStr);
1854                         char type = packageName.charAt(i);
1855                         i++;
1856                         int startTypeVal = i;
1857                         while (i < packageName.length() && packageName.charAt(i) >= '0'
1858                                 && packageName.charAt(i) <= '9') {
1859                             i++;
1860                         }
1861                         if (i > startTypeVal) {
1862                             String typeValStr = packageName.substring(startTypeVal, i);
1863                             try {
1864                                 int typeVal = Integer.parseInt(typeValStr);
1865                                 if (type == 'a') {
1866                                     nonpackageUid = UserHandle.getUid(user,
1867                                             typeVal + Process.FIRST_APPLICATION_UID);
1868                                 } else if (type == 's') {
1869                                     nonpackageUid = UserHandle.getUid(user, typeVal);
1870                                 }
1871                             } catch (NumberFormatException e) {
1872                             }
1873                         }
1874                     } catch (NumberFormatException e) {
1875                     }
1876                 }
1877             }
1878             if (nonpackageUid != -1) {
1879                 packageName = null;
1880             } else {
1881                 if ("root".equals(packageName)) {
1882                     packageUid = 0;
1883                 } else {
1884                     packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
1885                             PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1886                 }
1887                 if (packageUid < 0) {
1888                     err.println("Error: No UID for " + packageName + " in user " + userId);
1889                     return -1;
1890                 }
1891             }
1892             return 0;
1893         }
1894     }
1895 
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)1896     @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
1897             FileDescriptor err, String[] args, ShellCallback callback,
1898             ResultReceiver resultReceiver) {
1899         (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
1900     }
1901 
dumpCommandHelp(PrintWriter pw)1902     static void dumpCommandHelp(PrintWriter pw) {
1903         pw.println("AppOps service (appops) commands:");
1904         pw.println("  help");
1905         pw.println("    Print this help text.");
1906         pw.println("  set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>");
1907         pw.println("    Set the mode for a particular application and operation.");
1908         pw.println("  get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
1909         pw.println("    Return the mode for a particular application and optional operation.");
1910         pw.println("  query-op [--user <USER_ID>] <OP> [<MODE>]");
1911         pw.println("    Print all packages that currently have the given op in the given mode.");
1912         pw.println("  reset [--user <USER_ID>] [<PACKAGE>]");
1913         pw.println("    Reset the given application or all applications to default modes.");
1914         pw.println("  write-settings");
1915         pw.println("    Immediately write pending changes to storage.");
1916         pw.println("  read-settings");
1917         pw.println("    Read the last written settings, replacing current state in RAM.");
1918         pw.println("  options:");
1919         pw.println("    <PACKAGE> an Android package name.");
1920         pw.println("    <OP>      an AppOps operation.");
1921         pw.println("    <MODE>    one of allow, ignore, deny, or default");
1922         pw.println("    <USER_ID> the user id under which the package is installed. If --user is not");
1923         pw.println("              specified, the current user is assumed.");
1924     }
1925 
onShellCommand(Shell shell, String cmd)1926     static int onShellCommand(Shell shell, String cmd) {
1927         if (cmd == null) {
1928             return shell.handleDefaultCommands(cmd);
1929         }
1930         PrintWriter pw = shell.getOutPrintWriter();
1931         PrintWriter err = shell.getErrPrintWriter();
1932         try {
1933             switch (cmd) {
1934                 case "set": {
1935                     int res = shell.parseUserPackageOp(true, err);
1936                     if (res < 0) {
1937                         return res;
1938                     }
1939                     String modeStr = shell.getNextArg();
1940                     if (modeStr == null) {
1941                         err.println("Error: Mode not specified.");
1942                         return -1;
1943                     }
1944 
1945                     final int mode = shell.strModeToMode(modeStr, err);
1946                     if (mode < 0) {
1947                         return -1;
1948                     }
1949 
1950                     if (shell.packageName != null) {
1951                         shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
1952                                 mode);
1953                     } else {
1954                         shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
1955                     }
1956                     return 0;
1957                 }
1958                 case "get": {
1959                     int res = shell.parseUserPackageOp(false, err);
1960                     if (res < 0) {
1961                         return res;
1962                     }
1963 
1964                     List<AppOpsManager.PackageOps> ops;
1965                     if (shell.packageName != null) {
1966                         ops = shell.mInterface.getOpsForPackage(
1967                                 shell.packageUid, shell.packageName,
1968                                 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
1969                     } else {
1970                         ops = shell.mInterface.getUidOps(
1971                                 shell.nonpackageUid,
1972                                 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
1973                     }
1974                     if (ops == null || ops.size() <= 0) {
1975                         pw.println("No operations.");
1976                         return 0;
1977                     }
1978                     final long now = System.currentTimeMillis();
1979                     for (int i=0; i<ops.size(); i++) {
1980                         List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
1981                         for (int j=0; j<entries.size(); j++) {
1982                             AppOpsManager.OpEntry ent = entries.get(j);
1983                             pw.print(AppOpsManager.opToName(ent.getOp()));
1984                             pw.print(": ");
1985                             switch (ent.getMode()) {
1986                                 case AppOpsManager.MODE_ALLOWED:
1987                                     pw.print("allow");
1988                                     break;
1989                                 case AppOpsManager.MODE_IGNORED:
1990                                     pw.print("ignore");
1991                                     break;
1992                                 case AppOpsManager.MODE_ERRORED:
1993                                     pw.print("deny");
1994                                     break;
1995                                 case AppOpsManager.MODE_DEFAULT:
1996                                     pw.print("default");
1997                                     break;
1998                                 default:
1999                                     pw.print("mode=");
2000                                     pw.print(ent.getMode());
2001                                     break;
2002                             }
2003                             if (ent.getTime() != 0) {
2004                                 pw.print("; time=");
2005                                 TimeUtils.formatDuration(now - ent.getTime(), pw);
2006                                 pw.print(" ago");
2007                             }
2008                             if (ent.getRejectTime() != 0) {
2009                                 pw.print("; rejectTime=");
2010                                 TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
2011                                 pw.print(" ago");
2012                             }
2013                             if (ent.getDuration() == -1) {
2014                                 pw.print(" (running)");
2015                             } else if (ent.getDuration() != 0) {
2016                                 pw.print("; duration=");
2017                                 TimeUtils.formatDuration(ent.getDuration(), pw);
2018                             }
2019                             pw.println();
2020                         }
2021                     }
2022                     return 0;
2023                 }
2024                 case "query-op": {
2025                     int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
2026                     if (res < 0) {
2027                         return res;
2028                     }
2029                     List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
2030                             new int[] {shell.op});
2031                     if (ops == null || ops.size() <= 0) {
2032                         pw.println("No operations.");
2033                         return 0;
2034                     }
2035                     for (int i=0; i<ops.size(); i++) {
2036                         final AppOpsManager.PackageOps pkg = ops.get(i);
2037                         boolean hasMatch = false;
2038                         final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
2039                         for (int j=0; j<entries.size(); j++) {
2040                             AppOpsManager.OpEntry ent = entries.get(j);
2041                             if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
2042                                 hasMatch = true;
2043                                 break;
2044                             }
2045                         }
2046                         if (hasMatch) {
2047                             pw.println(pkg.getPackageName());
2048                         }
2049                     }
2050                     return 0;
2051                 }
2052                 case "reset": {
2053                     String packageName = null;
2054                     int userId = UserHandle.USER_CURRENT;
2055                     for (String argument; (argument = shell.getNextArg()) != null;) {
2056                         if ("--user".equals(argument)) {
2057                             String userStr = shell.getNextArgRequired();
2058                             userId = UserHandle.parseUserArg(userStr);
2059                         } else {
2060                             if (packageName == null) {
2061                                 packageName = argument;
2062                             } else {
2063                                 err.println("Error: Unsupported argument: " + argument);
2064                                 return -1;
2065                             }
2066                         }
2067                     }
2068 
2069                     if (userId == UserHandle.USER_CURRENT) {
2070                         userId = ActivityManager.getCurrentUser();
2071                     }
2072 
2073                     shell.mInterface.resetAllModes(userId, packageName);
2074                     pw.print("Reset all modes for: ");
2075                     if (userId == UserHandle.USER_ALL) {
2076                         pw.print("all users");
2077                     } else {
2078                         pw.print("user "); pw.print(userId);
2079                     }
2080                     pw.print(", ");
2081                     if (packageName == null) {
2082                         pw.println("all packages");
2083                     } else {
2084                         pw.print("package "); pw.println(packageName);
2085                     }
2086                     return 0;
2087                 }
2088                 case "write-settings": {
2089                     shell.mInternal.mContext.enforcePermission(
2090                             android.Manifest.permission.UPDATE_APP_OPS_STATS,
2091                             Binder.getCallingPid(), Binder.getCallingUid(), null);
2092                     long token = Binder.clearCallingIdentity();
2093                     try {
2094                         synchronized (shell.mInternal) {
2095                             shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
2096                         }
2097                         shell.mInternal.writeState();
2098                         pw.println("Current settings written.");
2099                     } finally {
2100                         Binder.restoreCallingIdentity(token);
2101                     }
2102                     return 0;
2103                 }
2104                 case "read-settings": {
2105                     shell.mInternal.mContext.enforcePermission(
2106                             android.Manifest.permission.UPDATE_APP_OPS_STATS,
2107                             Binder.getCallingPid(), Binder.getCallingUid(), null);
2108                     long token = Binder.clearCallingIdentity();
2109                     try {
2110                         shell.mInternal.readState();
2111                         pw.println("Last settings read.");
2112                     } finally {
2113                         Binder.restoreCallingIdentity(token);
2114                     }
2115                     return 0;
2116                 }
2117                 default:
2118                     return shell.handleDefaultCommands(cmd);
2119             }
2120         } catch (RemoteException e) {
2121             pw.println("Remote exception: " + e);
2122         }
2123         return -1;
2124     }
2125 
dumpHelp(PrintWriter pw)2126     private void dumpHelp(PrintWriter pw) {
2127         pw.println("AppOps service (appops) dump options:");
2128         pw.println("  none");
2129     }
2130 
2131     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)2132     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2133         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
2134 
2135         if (args != null) {
2136             for (int i=0; i<args.length; i++) {
2137                 String arg = args[i];
2138                 if ("-h".equals(arg)) {
2139                     dumpHelp(pw);
2140                     return;
2141                 } else if ("-a".equals(arg)) {
2142                     // dump all data
2143                 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
2144                     pw.println("Unknown option: " + arg);
2145                     return;
2146                 } else {
2147                     pw.println("Unknown command: " + arg);
2148                     return;
2149                 }
2150             }
2151         }
2152 
2153         synchronized (this) {
2154             pw.println("Current AppOps Service state:");
2155             final long now = System.currentTimeMillis();
2156             boolean needSep = false;
2157             if (mOpModeWatchers.size() > 0) {
2158                 needSep = true;
2159                 pw.println("  Op mode watchers:");
2160                 for (int i=0; i<mOpModeWatchers.size(); i++) {
2161                     pw.print("    Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
2162                     pw.println(":");
2163                     ArraySet<Callback> callbacks = mOpModeWatchers.valueAt(i);
2164                     for (int j=0; j<callbacks.size(); j++) {
2165                         pw.print("      #"); pw.print(j); pw.print(": ");
2166                         pw.println(callbacks.valueAt(j));
2167                     }
2168                 }
2169             }
2170             if (mPackageModeWatchers.size() > 0) {
2171                 needSep = true;
2172                 pw.println("  Package mode watchers:");
2173                 for (int i=0; i<mPackageModeWatchers.size(); i++) {
2174                     pw.print("    Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
2175                     pw.println(":");
2176                     ArraySet<Callback> callbacks = mPackageModeWatchers.valueAt(i);
2177                     for (int j=0; j<callbacks.size(); j++) {
2178                         pw.print("      #"); pw.print(j); pw.print(": ");
2179                         pw.println(callbacks.valueAt(j));
2180                     }
2181                 }
2182             }
2183             if (mModeWatchers.size() > 0) {
2184                 needSep = true;
2185                 pw.println("  All mode watchers:");
2186                 for (int i=0; i<mModeWatchers.size(); i++) {
2187                     pw.print("    "); pw.print(mModeWatchers.keyAt(i));
2188                     pw.print(" -> "); pw.println(mModeWatchers.valueAt(i));
2189                 }
2190             }
2191             if (mClients.size() > 0) {
2192                 needSep = true;
2193                 pw.println("  Clients:");
2194                 for (int i=0; i<mClients.size(); i++) {
2195                     pw.print("    "); pw.print(mClients.keyAt(i)); pw.println(":");
2196                     ClientState cs = mClients.valueAt(i);
2197                     pw.print("      "); pw.println(cs);
2198                     if (cs.mStartedOps != null && cs.mStartedOps.size() > 0) {
2199                         pw.println("      Started ops:");
2200                         for (int j=0; j<cs.mStartedOps.size(); j++) {
2201                             Op op = cs.mStartedOps.get(j);
2202                             pw.print("        "); pw.print("uid="); pw.print(op.uid);
2203                             pw.print(" pkg="); pw.print(op.packageName);
2204                             pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
2205                         }
2206                     }
2207                 }
2208             }
2209             if (mAudioRestrictions.size() > 0) {
2210                 boolean printedHeader = false;
2211                 for (int o=0; o<mAudioRestrictions.size(); o++) {
2212                     final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
2213                     final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
2214                     for (int i=0; i<restrictions.size(); i++) {
2215                         if (!printedHeader){
2216                             pw.println("  Audio Restrictions:");
2217                             printedHeader = true;
2218                             needSep = true;
2219                         }
2220                         final int usage = restrictions.keyAt(i);
2221                         pw.print("    "); pw.print(op);
2222                         pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
2223                         Restriction r = restrictions.valueAt(i);
2224                         pw.print(": mode="); pw.println(r.mode);
2225                         if (!r.exceptionPackages.isEmpty()) {
2226                             pw.println("      Exceptions:");
2227                             for (int j=0; j<r.exceptionPackages.size(); j++) {
2228                                 pw.print("        "); pw.println(r.exceptionPackages.valueAt(j));
2229                             }
2230                         }
2231                     }
2232                 }
2233             }
2234             if (needSep) {
2235                 pw.println();
2236             }
2237             for (int i=0; i<mUidStates.size(); i++) {
2238                 UidState uidState = mUidStates.valueAt(i);
2239 
2240                 pw.print("  Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
2241                 needSep = true;
2242 
2243                 SparseIntArray opModes = uidState.opModes;
2244                 if (opModes != null) {
2245                     final int opModeCount = opModes.size();
2246                     for (int j = 0; j < opModeCount; j++) {
2247                         final int code = opModes.keyAt(j);
2248                         final int mode = opModes.valueAt(j);
2249                         pw.print("      "); pw.print(AppOpsManager.opToName(code));
2250                         pw.print(": mode="); pw.println(mode);
2251                     }
2252                 }
2253 
2254                 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
2255                 if (pkgOps == null) {
2256                     continue;
2257                 }
2258 
2259                 for (Ops ops : pkgOps.values()) {
2260                     pw.print("    Package "); pw.print(ops.packageName); pw.println(":");
2261                     for (int j=0; j<ops.size(); j++) {
2262                         Op op = ops.valueAt(j);
2263                         pw.print("      "); pw.print(AppOpsManager.opToName(op.op));
2264                         pw.print(": mode="); pw.print(op.mode);
2265                         if (op.time != 0) {
2266                             pw.print("; time="); TimeUtils.formatDuration(now-op.time, pw);
2267                             pw.print(" ago");
2268                         }
2269                         if (op.rejectTime != 0) {
2270                             pw.print("; rejectTime="); TimeUtils.formatDuration(now-op.rejectTime, pw);
2271                             pw.print(" ago");
2272                         }
2273                         if (op.duration == -1) {
2274                             pw.print(" (running)");
2275                         } else if (op.duration != 0) {
2276                             pw.print("; duration="); TimeUtils.formatDuration(op.duration, pw);
2277                         }
2278                         pw.println();
2279                     }
2280                 }
2281             }
2282             if (needSep) {
2283                 pw.println();
2284             }
2285 
2286             final int userRestrictionCount = mOpUserRestrictions.size();
2287             for (int i = 0; i < userRestrictionCount; i++) {
2288                 IBinder token = mOpUserRestrictions.keyAt(i);
2289                 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
2290                 pw.println("  User restrictions for token " + token + ":");
2291 
2292                 final int restrictionCount = restrictionState.perUserRestrictions != null
2293                         ? restrictionState.perUserRestrictions.size() : 0;
2294                 if (restrictionCount > 0) {
2295                     pw.println("      Restricted ops:");
2296                     for (int j = 0; j < restrictionCount; j++) {
2297                         int userId = restrictionState.perUserRestrictions.keyAt(j);
2298                         boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
2299                         if (restrictedOps == null) {
2300                             continue;
2301                         }
2302                         StringBuilder restrictedOpsValue = new StringBuilder();
2303                         restrictedOpsValue.append("[");
2304                         final int restrictedOpCount = restrictedOps.length;
2305                         for (int k = 0; k < restrictedOpCount; k++) {
2306                             if (restrictedOps[k]) {
2307                                 if (restrictedOpsValue.length() > 1) {
2308                                     restrictedOpsValue.append(", ");
2309                                 }
2310                                 restrictedOpsValue.append(AppOpsManager.opToName(k));
2311                             }
2312                         }
2313                         restrictedOpsValue.append("]");
2314                         pw.print("        "); pw.print("user: "); pw.print(userId);
2315                                 pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
2316                     }
2317                 }
2318 
2319                 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
2320                         ? restrictionState.perUserExcludedPackages.size() : 0;
2321                 if (excludedPackageCount > 0) {
2322                     pw.println("      Excluded packages:");
2323                     for (int j = 0; j < excludedPackageCount; j++) {
2324                         int userId = restrictionState.perUserExcludedPackages.keyAt(j);
2325                         String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
2326                         pw.print("        "); pw.print("user: "); pw.print(userId);
2327                                 pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
2328                     }
2329                 }
2330             }
2331         }
2332     }
2333 
2334     private static final class Restriction {
2335         private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
2336         int mode;
2337         ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
2338     }
2339 
2340     @Override
setUserRestrictions(Bundle restrictions, IBinder token, int userHandle)2341     public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
2342         checkSystemUid("setUserRestrictions");
2343         Preconditions.checkNotNull(restrictions);
2344         Preconditions.checkNotNull(token);
2345         for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
2346             String restriction = AppOpsManager.opToRestriction(i);
2347             if (restriction != null) {
2348                 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
2349                         userHandle, null);
2350             }
2351         }
2352     }
2353 
2354     @Override
setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, String[] exceptionPackages)2355     public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
2356             String[] exceptionPackages) {
2357         if (Binder.getCallingPid() != Process.myPid()) {
2358             mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
2359                     Binder.getCallingPid(), Binder.getCallingUid(), null);
2360         }
2361         if (userHandle != UserHandle.getCallingUserId()) {
2362             if (mContext.checkCallingOrSelfPermission(Manifest.permission
2363                     .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
2364                 && mContext.checkCallingOrSelfPermission(Manifest.permission
2365                     .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
2366                 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
2367                         + " INTERACT_ACROSS_USERS to interact cross user ");
2368             }
2369         }
2370         verifyIncomingOp(code);
2371         Preconditions.checkNotNull(token);
2372         setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
2373     }
2374 
setUserRestrictionNoCheck(int code, boolean restricted, IBinder token, int userHandle, String[] exceptionPackages)2375     private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
2376             int userHandle, String[] exceptionPackages) {
2377         boolean notifyChange = false;
2378 
2379         synchronized (AppOpsService.this) {
2380             ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
2381 
2382             if (restrictionState == null) {
2383                 try {
2384                     restrictionState = new ClientRestrictionState(token);
2385                 } catch (RemoteException e) {
2386                     return;
2387                 }
2388                 mOpUserRestrictions.put(token, restrictionState);
2389             }
2390 
2391             if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
2392                 notifyChange = true;
2393             }
2394 
2395             if (restrictionState.isDefault()) {
2396                 mOpUserRestrictions.remove(token);
2397                 restrictionState.destroy();
2398             }
2399         }
2400 
2401         if (notifyChange) {
2402             notifyWatchersOfChange(code);
2403         }
2404     }
2405 
notifyWatchersOfChange(int code)2406     private void notifyWatchersOfChange(int code) {
2407         final ArraySet<Callback> clonedCallbacks;
2408         synchronized (this) {
2409             ArraySet<Callback> callbacks = mOpModeWatchers.get(code);
2410             if (callbacks == null) {
2411                 return;
2412             }
2413             clonedCallbacks = new ArraySet<>(callbacks);
2414         }
2415 
2416         // There are components watching for mode changes such as window manager
2417         // and location manager which are in our process. The callbacks in these
2418         // components may require permissions our remote caller does not have.
2419         final long identity = Binder.clearCallingIdentity();
2420         try {
2421             final int callbackCount = clonedCallbacks.size();
2422             for (int i = 0; i < callbackCount; i++) {
2423                 Callback callback = clonedCallbacks.valueAt(i);
2424                 try {
2425                     callback.mCallback.opChanged(code, -1, null);
2426                 } catch (RemoteException e) {
2427                     Log.w(TAG, "Error dispatching op op change", e);
2428                 }
2429             }
2430         } finally {
2431             Binder.restoreCallingIdentity(identity);
2432         }
2433     }
2434 
2435     @Override
removeUser(int userHandle)2436     public void removeUser(int userHandle) throws RemoteException {
2437         checkSystemUid("removeUser");
2438         synchronized (AppOpsService.this) {
2439             final int tokenCount = mOpUserRestrictions.size();
2440             for (int i = tokenCount - 1; i >= 0; i--) {
2441                 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
2442                 opRestrictions.removeUser(userHandle);
2443             }
2444             removeUidsForUserLocked(userHandle);
2445         }
2446     }
2447 
removeUidsForUserLocked(int userHandle)2448     private void removeUidsForUserLocked(int userHandle) {
2449         for (int i = mUidStates.size() - 1; i >= 0; --i) {
2450             final int uid = mUidStates.keyAt(i);
2451             if (UserHandle.getUserId(uid) == userHandle) {
2452                 mUidStates.removeAt(i);
2453             }
2454         }
2455     }
2456 
checkSystemUid(String function)2457     private void checkSystemUid(String function) {
2458         int uid = Binder.getCallingUid();
2459         if (uid != Process.SYSTEM_UID) {
2460             throw new SecurityException(function + " must by called by the system");
2461         }
2462     }
2463 
resolvePackageName(int uid, String packageName)2464     private static String resolvePackageName(int uid, String packageName)  {
2465         if (uid == 0) {
2466             return "root";
2467         } else if (uid == Process.SHELL_UID) {
2468             return "com.android.shell";
2469         } else if (uid == Process.SYSTEM_UID && packageName == null) {
2470             return "android";
2471         }
2472         return packageName;
2473     }
2474 
getPackagesForUid(int uid)2475     private static String[] getPackagesForUid(int uid) {
2476         String[] packageNames = null;
2477         try {
2478             packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
2479         } catch (RemoteException e) {
2480             /* ignore - local call */
2481         }
2482         if (packageNames == null) {
2483             return EmptyArray.STRING;
2484         }
2485         return packageNames;
2486     }
2487 
2488     private final class ClientRestrictionState implements DeathRecipient {
2489         private final IBinder token;
2490         SparseArray<boolean[]> perUserRestrictions;
2491         SparseArray<String[]> perUserExcludedPackages;
2492 
ClientRestrictionState(IBinder token)2493         public ClientRestrictionState(IBinder token)
2494                 throws RemoteException {
2495             token.linkToDeath(this, 0);
2496             this.token = token;
2497         }
2498 
setRestriction(int code, boolean restricted, String[] excludedPackages, int userId)2499         public boolean setRestriction(int code, boolean restricted,
2500                 String[] excludedPackages, int userId) {
2501             boolean changed = false;
2502 
2503             if (perUserRestrictions == null && restricted) {
2504                 perUserRestrictions = new SparseArray<>();
2505             }
2506 
2507             if (perUserRestrictions != null) {
2508                 boolean[] userRestrictions = perUserRestrictions.get(userId);
2509                 if (userRestrictions == null && restricted) {
2510                     userRestrictions = new boolean[AppOpsManager._NUM_OP];
2511                     perUserRestrictions.put(userId, userRestrictions);
2512                 }
2513                 if (userRestrictions != null && userRestrictions[code] != restricted) {
2514                     userRestrictions[code] = restricted;
2515                     if (!restricted && isDefault(userRestrictions)) {
2516                         perUserRestrictions.remove(userId);
2517                         userRestrictions = null;
2518                     }
2519                     changed = true;
2520                 }
2521 
2522                 if (userRestrictions != null) {
2523                     final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
2524                     if (perUserExcludedPackages == null && !noExcludedPackages) {
2525                         perUserExcludedPackages = new SparseArray<>();
2526                     }
2527                     if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
2528                             perUserExcludedPackages.get(userId))) {
2529                         if (noExcludedPackages) {
2530                             perUserExcludedPackages.remove(userId);
2531                             if (perUserExcludedPackages.size() <= 0) {
2532                                 perUserExcludedPackages = null;
2533                             }
2534                         } else {
2535                             perUserExcludedPackages.put(userId, excludedPackages);
2536                         }
2537                         changed = true;
2538                     }
2539                 }
2540             }
2541 
2542             return changed;
2543         }
2544 
hasRestriction(int restriction, String packageName, int userId)2545         public boolean hasRestriction(int restriction, String packageName, int userId) {
2546             if (perUserRestrictions == null) {
2547                 return false;
2548             }
2549             boolean[] restrictions = perUserRestrictions.get(userId);
2550             if (restrictions == null) {
2551                 return false;
2552             }
2553             if (!restrictions[restriction]) {
2554                 return false;
2555             }
2556             if (perUserExcludedPackages == null) {
2557                 return true;
2558             }
2559             String[] perUserExclusions = perUserExcludedPackages.get(userId);
2560             if (perUserExclusions == null) {
2561                 return true;
2562             }
2563             return !ArrayUtils.contains(perUserExclusions, packageName);
2564         }
2565 
removeUser(int userId)2566         public void removeUser(int userId) {
2567             if (perUserExcludedPackages != null) {
2568                 perUserExcludedPackages.remove(userId);
2569                 if (perUserExcludedPackages.size() <= 0) {
2570                     perUserExcludedPackages = null;
2571                 }
2572             }
2573             if (perUserRestrictions != null) {
2574                 perUserRestrictions.remove(userId);
2575                 if (perUserRestrictions.size() <= 0) {
2576                     perUserRestrictions = null;
2577                 }
2578             }
2579         }
2580 
isDefault()2581         public boolean isDefault() {
2582             return perUserRestrictions == null || perUserRestrictions.size() <= 0;
2583         }
2584 
2585         @Override
binderDied()2586         public void binderDied() {
2587             synchronized (AppOpsService.this) {
2588                 mOpUserRestrictions.remove(token);
2589                 if (perUserRestrictions == null) {
2590                     return;
2591                 }
2592                 final int userCount = perUserRestrictions.size();
2593                 for (int i = 0; i < userCount; i++) {
2594                     final boolean[] restrictions = perUserRestrictions.valueAt(i);
2595                     final int restrictionCount = restrictions.length;
2596                     for (int j = 0; j < restrictionCount; j++) {
2597                         if (restrictions[j]) {
2598                             final int changedCode = j;
2599                             mHandler.post(() -> notifyWatchersOfChange(changedCode));
2600                         }
2601                     }
2602                 }
2603                 destroy();
2604             }
2605         }
2606 
destroy()2607         public void destroy() {
2608             token.unlinkToDeath(this, 0);
2609         }
2610 
isDefault(boolean[] array)2611         private boolean isDefault(boolean[] array) {
2612             if (ArrayUtils.isEmpty(array)) {
2613                 return true;
2614             }
2615             for (boolean value : array) {
2616                 if (value) {
2617                     return false;
2618                 }
2619             }
2620             return true;
2621         }
2622     }
2623 }
2624