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