Home | History | Annotate | Download | only in server
      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 
    124         public UidState(int uid) {
    125             this.uid = uid;
    126         }
    127 
    128         public void clear() {
    129             pkgOps = null;
    130             opModes = null;
    131         }
    132 
    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 
    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 
    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 
    179         public Callback(IAppOpsCallback callback) {
    180             mCallback = callback;
    181             try {
    182                 mCallback.asBinder().linkToDeath(this, 0);
    183             } catch (RemoteException e) {
    184             }
    185         }
    186 
    187         public void unlinkToDeath() {
    188             mCallback.asBinder().unlinkToDeath(this, 0);
    189         }
    190 
    191         @Override
    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 
    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
    220         public String toString() {
    221             return "ClientState{" +
    222                     "mAppToken=" + mAppToken +
    223                     ", " + (mStartedOps != null ? ("pid=" + mPid) : "local") +
    224                     '}';
    225         }
    226 
    227         @Override
    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 
    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 
    245     public void publish(Context context) {
    246         mContext = context;
    247         ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
    248     }
    249 
    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 
    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 
    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 
    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 
    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 
    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
    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
    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
    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 
    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
    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
    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 
    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 
    748         ChangeRec(int _op, int _uid, String _pkg) {
    749             op = _op;
    750             uid = _uid;
    751             pkg = _pkg;
    752         }
    753     }
    754 
    755     @Override
    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
    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
    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
    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
    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
    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 
    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 
    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
   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
   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
   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
   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 
   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
   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
   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
   1213     public int permissionToOpCode(String permission) {
   1214         if (permission == null) {
   1215             return AppOpsManager.OP_NONE;
   1216         }
   1217         return AppOpsManager.permissionToOpCode(permission);
   1218     }
   1219 
   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 
   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 
   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 
   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 
   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 
   1334     private void scheduleWriteLocked() {
   1335         if (!mWriteScheduled) {
   1336             mWriteScheduled = true;
   1337             mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
   1338         }
   1339     }
   1340 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   1718         Shell(IAppOpsService iface, AppOpsService internal) {
   1719             mInterface = iface;
   1720             mInternal = internal;
   1721         }
   1722 
   1723         @Override
   1724         public int onCommand(String cmd) {
   1725             return onShellCommand(this, cmd);
   1726         }
   1727 
   1728         @Override
   1729         public void onHelp() {
   1730             PrintWriter pw = getOutPrintWriter();
   1731             dumpCommandHelp(pw);
   1732         }
   1733 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   2126     private void dumpHelp(PrintWriter pw) {
   2127         pw.println("AppOps service (appops) dump options:");
   2128         pw.println("  none");
   2129     }
   2130 
   2131     @Override
   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
   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
   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 
   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 
   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
   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 
   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 
   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 
   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 
   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 
   2493         public ClientRestrictionState(IBinder token)
   2494                 throws RemoteException {
   2495             token.linkToDeath(this, 0);
   2496             this.token = token;
   2497         }
   2498 
   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 
   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 
   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 
   2581         public boolean isDefault() {
   2582             return perUserRestrictions == null || perUserRestrictions.size() <= 0;
   2583         }
   2584 
   2585         @Override
   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 
   2607         public void destroy() {
   2608             token.unlinkToDeath(this, 0);
   2609         }
   2610 
   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