Home | History | Annotate | Download | only in server
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server;
     18 
     19 import java.io.File;
     20 import java.io.FileDescriptor;
     21 import java.io.FileInputStream;
     22 import java.io.FileNotFoundException;
     23 import java.io.FileOutputStream;
     24 import java.io.IOException;
     25 import java.io.PrintWriter;
     26 import java.nio.charset.StandardCharsets;
     27 import java.util.ArrayList;
     28 import java.util.Collections;
     29 import java.util.HashMap;
     30 import java.util.Iterator;
     31 import java.util.List;
     32 import java.util.Map;
     33 
     34 import android.app.ActivityManager;
     35 import android.app.ActivityThread;
     36 import android.app.AppGlobals;
     37 import android.app.AppOpsManager;
     38 import android.content.Context;
     39 import android.content.pm.ApplicationInfo;
     40 import android.content.pm.IPackageManager;
     41 import android.content.pm.PackageManager;
     42 import android.content.pm.PackageManager.NameNotFoundException;
     43 import android.media.AudioAttributes;
     44 import android.os.AsyncTask;
     45 import android.os.Binder;
     46 import android.os.Bundle;
     47 import android.os.Handler;
     48 import android.os.IBinder;
     49 import android.os.Process;
     50 import android.os.RemoteException;
     51 import android.os.ServiceManager;
     52 import android.os.UserHandle;
     53 import android.os.storage.MountServiceInternal;
     54 import android.util.ArrayMap;
     55 import android.util.ArraySet;
     56 import android.util.AtomicFile;
     57 import android.util.Log;
     58 import android.util.Pair;
     59 import android.util.Slog;
     60 import android.util.SparseArray;
     61 import android.util.SparseIntArray;
     62 import android.util.TimeUtils;
     63 import android.util.Xml;
     64 
     65 import com.android.internal.app.IAppOpsService;
     66 import com.android.internal.app.IAppOpsCallback;
     67 import com.android.internal.os.Zygote;
     68 import com.android.internal.util.ArrayUtils;
     69 import com.android.internal.util.FastXmlSerializer;
     70 import com.android.internal.util.XmlUtils;
     71 
     72 import libcore.util.EmptyArray;
     73 import org.xmlpull.v1.XmlPullParser;
     74 import org.xmlpull.v1.XmlPullParserException;
     75 import org.xmlpull.v1.XmlSerializer;
     76 
     77 public class AppOpsService extends IAppOpsService.Stub {
     78     static final String TAG = "AppOps";
     79     static final boolean DEBUG = false;
     80 
     81     // Write at most every 30 minutes.
     82     static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
     83 
     84     Context mContext;
     85     final AtomicFile mFile;
     86     final Handler mHandler;
     87 
     88     boolean mWriteScheduled;
     89     boolean mFastWriteScheduled;
     90     final Runnable mWriteRunner = new Runnable() {
     91         public void run() {
     92             synchronized (AppOpsService.this) {
     93                 mWriteScheduled = false;
     94                 mFastWriteScheduled = false;
     95                 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
     96                     @Override protected Void doInBackground(Void... params) {
     97                         writeState();
     98                         return null;
     99                     }
    100                 };
    101                 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
    102             }
    103         }
    104     };
    105 
    106     final SparseArray<UidState> mUidStates = new SparseArray<>();
    107 
    108     private final SparseArray<boolean[]> mOpRestrictions = new SparseArray<boolean[]>();
    109 
    110     private static final class UidState {
    111         public final int uid;
    112         public ArrayMap<String, Ops> pkgOps;
    113         public SparseIntArray opModes;
    114 
    115         public UidState(int uid) {
    116             this.uid = uid;
    117         }
    118 
    119         public void clear() {
    120             pkgOps = null;
    121             opModes = null;
    122         }
    123 
    124         public boolean isDefault() {
    125             return (pkgOps == null || pkgOps.isEmpty())
    126                     && (opModes == null || opModes.size() <= 0);
    127         }
    128     }
    129 
    130     public final static class Ops extends SparseArray<Op> {
    131         public final String packageName;
    132         public final UidState uidState;
    133         public final boolean isPrivileged;
    134 
    135         public Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
    136             packageName = _packageName;
    137             uidState = _uidState;
    138             isPrivileged = _isPrivileged;
    139         }
    140     }
    141 
    142     public final static class Op {
    143         public final int uid;
    144         public final String packageName;
    145         public int proxyUid = -1;
    146         public String proxyPackageName;
    147         public final int op;
    148         public int mode;
    149         public int duration;
    150         public long time;
    151         public long rejectTime;
    152         public int nesting;
    153 
    154         public Op(int _uid, String _packageName, int _op) {
    155             uid = _uid;
    156             packageName = _packageName;
    157             op = _op;
    158             mode = AppOpsManager.opToDefaultMode(op);
    159         }
    160     }
    161 
    162     final SparseArray<ArrayList<Callback>> mOpModeWatchers
    163             = new SparseArray<ArrayList<Callback>>();
    164     final ArrayMap<String, ArrayList<Callback>> mPackageModeWatchers
    165             = new ArrayMap<String, ArrayList<Callback>>();
    166     final ArrayMap<IBinder, Callback> mModeWatchers
    167             = new ArrayMap<IBinder, Callback>();
    168     final SparseArray<SparseArray<Restriction>> mAudioRestrictions
    169             = new SparseArray<SparseArray<Restriction>>();
    170 
    171     public final class Callback implements DeathRecipient {
    172         final IAppOpsCallback mCallback;
    173 
    174         public Callback(IAppOpsCallback callback) {
    175             mCallback = callback;
    176             try {
    177                 mCallback.asBinder().linkToDeath(this, 0);
    178             } catch (RemoteException e) {
    179             }
    180         }
    181 
    182         public void unlinkToDeath() {
    183             mCallback.asBinder().unlinkToDeath(this, 0);
    184         }
    185 
    186         @Override
    187         public void binderDied() {
    188             stopWatchingMode(mCallback);
    189         }
    190     }
    191 
    192     final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<IBinder, ClientState>();
    193 
    194     public final class ClientState extends Binder implements DeathRecipient {
    195         final IBinder mAppToken;
    196         final int mPid;
    197         final ArrayList<Op> mStartedOps;
    198 
    199         public ClientState(IBinder appToken) {
    200             mAppToken = appToken;
    201             mPid = Binder.getCallingPid();
    202             if (appToken instanceof Binder) {
    203                 // For local clients, there is no reason to track them.
    204                 mStartedOps = null;
    205             } else {
    206                 mStartedOps = new ArrayList<Op>();
    207                 try {
    208                     mAppToken.linkToDeath(this, 0);
    209                 } catch (RemoteException e) {
    210                 }
    211             }
    212         }
    213 
    214         @Override
    215         public String toString() {
    216             return "ClientState{" +
    217                     "mAppToken=" + mAppToken +
    218                     ", " + (mStartedOps != null ? ("pid=" + mPid) : "local") +
    219                     '}';
    220         }
    221 
    222         @Override
    223         public void binderDied() {
    224             synchronized (AppOpsService.this) {
    225                 for (int i=mStartedOps.size()-1; i>=0; i--) {
    226                     finishOperationLocked(mStartedOps.get(i));
    227                 }
    228                 mClients.remove(mAppToken);
    229             }
    230         }
    231     }
    232 
    233     public AppOpsService(File storagePath, Handler handler) {
    234         mFile = new AtomicFile(storagePath);
    235         mHandler = handler;
    236         readState();
    237     }
    238 
    239     public void publish(Context context) {
    240         mContext = context;
    241         ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
    242     }
    243 
    244     public void systemReady() {
    245         synchronized (this) {
    246             boolean changed = false;
    247             for (int i = mUidStates.size() - 1; i >= 0; i--) {
    248                 UidState uidState = mUidStates.valueAt(i);
    249 
    250                 String[] packageNames = getPackagesForUid(uidState.uid);
    251                 if (ArrayUtils.isEmpty(packageNames)) {
    252                     uidState.clear();
    253                     mUidStates.removeAt(i);
    254                     changed = true;
    255                     continue;
    256                 }
    257 
    258                 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
    259                 if (pkgs == null) {
    260                     continue;
    261                 }
    262 
    263                 Iterator<Ops> it = pkgs.values().iterator();
    264                 while (it.hasNext()) {
    265                     Ops ops = it.next();
    266                     int curUid;
    267                     try {
    268                         curUid = mContext.getPackageManager().getPackageUid(ops.packageName,
    269                                 UserHandle.getUserId(ops.uidState.uid));
    270                     } catch (NameNotFoundException e) {
    271                         curUid = -1;
    272                     }
    273                     if (curUid != ops.uidState.uid) {
    274                         Slog.i(TAG, "Pruning old package " + ops.packageName
    275                                 + "/" + ops.uidState + ": new uid=" + curUid);
    276                         it.remove();
    277                         changed = true;
    278                     }
    279                 }
    280 
    281                 if (uidState.isDefault()) {
    282                     mUidStates.removeAt(i);
    283                 }
    284             }
    285             if (changed) {
    286                 scheduleFastWriteLocked();
    287             }
    288         }
    289 
    290         MountServiceInternal mountServiceInternal = LocalServices.getService(
    291                 MountServiceInternal.class);
    292         mountServiceInternal.addExternalStoragePolicy(
    293                 new MountServiceInternal.ExternalStorageMountPolicy() {
    294                     @Override
    295                     public int getMountMode(int uid, String packageName) {
    296                         if (Process.isIsolated(uid)) {
    297                             return Zygote.MOUNT_EXTERNAL_NONE;
    298                         }
    299                         if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
    300                                 packageName) != AppOpsManager.MODE_ALLOWED) {
    301                             return Zygote.MOUNT_EXTERNAL_NONE;
    302                         }
    303                         if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
    304                                 packageName) != AppOpsManager.MODE_ALLOWED) {
    305                             return Zygote.MOUNT_EXTERNAL_READ;
    306                         }
    307                         return Zygote.MOUNT_EXTERNAL_WRITE;
    308                     }
    309 
    310                     @Override
    311                     public boolean hasExternalStorage(int uid, String packageName) {
    312                         final int mountMode = getMountMode(uid, packageName);
    313                         return mountMode == Zygote.MOUNT_EXTERNAL_READ
    314                                 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
    315                     }
    316                 });
    317     }
    318 
    319     public void packageRemoved(int uid, String packageName) {
    320         synchronized (this) {
    321             UidState uidState = mUidStates.get(uid);
    322             if (uidState == null) {
    323                 return;
    324             }
    325 
    326             boolean changed = false;
    327 
    328             // Remove any package state if such.
    329             if (uidState.pkgOps != null && uidState.pkgOps.remove(packageName) != null) {
    330                 changed = true;
    331             }
    332 
    333             // If we just nuked the last package state check if the UID is valid.
    334             if (changed && uidState.pkgOps.isEmpty()
    335                     && getPackagesForUid(uid).length <= 0) {
    336                 mUidStates.remove(uid);
    337             }
    338 
    339             if (changed) {
    340                 scheduleFastWriteLocked();
    341             }
    342         }
    343     }
    344 
    345     public void uidRemoved(int uid) {
    346         synchronized (this) {
    347             if (mUidStates.indexOfKey(uid) >= 0) {
    348                 mUidStates.remove(uid);
    349                 scheduleFastWriteLocked();
    350             }
    351         }
    352     }
    353 
    354     public void shutdown() {
    355         Slog.w(TAG, "Writing app ops before shutdown...");
    356         boolean doWrite = false;
    357         synchronized (this) {
    358             if (mWriteScheduled) {
    359                 mWriteScheduled = false;
    360                 doWrite = true;
    361             }
    362         }
    363         if (doWrite) {
    364             writeState();
    365         }
    366     }
    367 
    368     private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
    369         ArrayList<AppOpsManager.OpEntry> resOps = null;
    370         if (ops == null) {
    371             resOps = new ArrayList<AppOpsManager.OpEntry>();
    372             for (int j=0; j<pkgOps.size(); j++) {
    373                 Op curOp = pkgOps.valueAt(j);
    374                 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
    375                         curOp.rejectTime, curOp.duration, curOp.proxyUid,
    376                         curOp.proxyPackageName));
    377             }
    378         } else {
    379             for (int j=0; j<ops.length; j++) {
    380                 Op curOp = pkgOps.get(ops[j]);
    381                 if (curOp != null) {
    382                     if (resOps == null) {
    383                         resOps = new ArrayList<AppOpsManager.OpEntry>();
    384                     }
    385                     resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
    386                             curOp.rejectTime, curOp.duration, curOp.proxyUid,
    387                             curOp.proxyPackageName));
    388                 }
    389             }
    390         }
    391         return resOps;
    392     }
    393 
    394     @Override
    395     public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
    396         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
    397                 Binder.getCallingPid(), Binder.getCallingUid(), null);
    398         ArrayList<AppOpsManager.PackageOps> res = null;
    399         synchronized (this) {
    400             final int uidStateCount = mUidStates.size();
    401             for (int i = 0; i < uidStateCount; i++) {
    402                 UidState uidState = mUidStates.valueAt(i);
    403                 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
    404                     continue;
    405                 }
    406                 ArrayMap<String, Ops> packages = uidState.pkgOps;
    407                 final int packageCount = packages.size();
    408                 for (int j = 0; j < packageCount; j++) {
    409                     Ops pkgOps = packages.valueAt(j);
    410                     ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
    411                     if (resOps != null) {
    412                         if (res == null) {
    413                             res = new ArrayList<AppOpsManager.PackageOps>();
    414                         }
    415                         AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
    416                                 pkgOps.packageName, pkgOps.uidState.uid, resOps);
    417                         res.add(resPackage);
    418                     }
    419                 }
    420             }
    421         }
    422         return res;
    423     }
    424 
    425     @Override
    426     public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
    427             int[] ops) {
    428         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
    429                 Binder.getCallingPid(), Binder.getCallingUid(), null);
    430         synchronized (this) {
    431             Ops pkgOps = getOpsLocked(uid, packageName, false);
    432             if (pkgOps == null) {
    433                 return null;
    434             }
    435             ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
    436             if (resOps == null) {
    437                 return null;
    438             }
    439             ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
    440             AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
    441                     pkgOps.packageName, pkgOps.uidState.uid, resOps);
    442             res.add(resPackage);
    443             return res;
    444         }
    445     }
    446 
    447     private void pruneOp(Op op, int uid, String packageName) {
    448         if (op.time == 0 && op.rejectTime == 0) {
    449             Ops ops = getOpsLocked(uid, packageName, false);
    450             if (ops != null) {
    451                 ops.remove(op.op);
    452                 if (ops.size() <= 0) {
    453                     UidState uidState = ops.uidState;
    454                     ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
    455                     if (pkgOps != null) {
    456                         pkgOps.remove(ops.packageName);
    457                         if (pkgOps.isEmpty()) {
    458                             uidState.pkgOps = null;
    459                         }
    460                         if (uidState.isDefault()) {
    461                             mUidStates.remove(uid);
    462                         }
    463                     }
    464                 }
    465             }
    466         }
    467     }
    468 
    469     @Override
    470     public void setUidMode(int code, int uid, int mode) {
    471         if (Binder.getCallingPid() != Process.myPid()) {
    472             mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
    473                     Binder.getCallingPid(), Binder.getCallingUid(), null);
    474         }
    475         verifyIncomingOp(code);
    476         code = AppOpsManager.opToSwitch(code);
    477 
    478         synchronized (this) {
    479             final int defaultMode = AppOpsManager.opToDefaultMode(code);
    480 
    481             UidState uidState = getUidStateLocked(uid, false);
    482             if (uidState == null) {
    483                 if (mode == defaultMode) {
    484                     return;
    485                 }
    486                 uidState = new UidState(uid);
    487                 uidState.opModes = new SparseIntArray();
    488                 uidState.opModes.put(code, mode);
    489                 mUidStates.put(uid, uidState);
    490                 scheduleWriteLocked();
    491             } else if (uidState.opModes == null) {
    492                 if (mode != defaultMode) {
    493                     uidState.opModes = new SparseIntArray();
    494                     uidState.opModes.put(code, mode);
    495                     scheduleWriteLocked();
    496                 }
    497             } else {
    498                 if (uidState.opModes.get(code) == mode) {
    499                     return;
    500                 }
    501                 if (mode == defaultMode) {
    502                     uidState.opModes.delete(code);
    503                     if (uidState.opModes.size() <= 0) {
    504                         uidState.opModes = null;
    505                     }
    506                 } else {
    507                     uidState.opModes.put(code, mode);
    508                 }
    509                 scheduleWriteLocked();
    510             }
    511         }
    512 
    513         String[] uidPackageNames = getPackagesForUid(uid);
    514         ArrayMap<Callback, ArraySet<String>> callbackSpecs = null;
    515 
    516         ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
    517         if (callbacks != null) {
    518             final int callbackCount = callbacks.size();
    519             for (int i = 0; i < callbackCount; i++) {
    520                 Callback callback = callbacks.get(i);
    521                 ArraySet<String> changedPackages = new ArraySet<>();
    522                 Collections.addAll(changedPackages, uidPackageNames);
    523                 callbackSpecs = new ArrayMap<>();
    524                 callbackSpecs.put(callback, changedPackages);
    525             }
    526         }
    527 
    528         for (String uidPackageName : uidPackageNames) {
    529             callbacks = mPackageModeWatchers.get(uidPackageName);
    530             if (callbacks != null) {
    531                 if (callbackSpecs == null) {
    532                     callbackSpecs = new ArrayMap<>();
    533                 }
    534                 final int callbackCount = callbacks.size();
    535                 for (int i = 0; i < callbackCount; i++) {
    536                     Callback callback = callbacks.get(i);
    537                     ArraySet<String> changedPackages = callbackSpecs.get(callback);
    538                     if (changedPackages == null) {
    539                         changedPackages = new ArraySet<>();
    540                         callbackSpecs.put(callback, changedPackages);
    541                     }
    542                     changedPackages.add(uidPackageName);
    543                 }
    544             }
    545         }
    546 
    547         if (callbackSpecs == null) {
    548             return;
    549         }
    550 
    551         // There are components watching for mode changes such as window manager
    552         // and location manager which are in our process. The callbacks in these
    553         // components may require permissions our remote caller does not have.
    554         final long identity = Binder.clearCallingIdentity();
    555         try {
    556             for (int i = 0; i < callbackSpecs.size(); i++) {
    557                 Callback callback = callbackSpecs.keyAt(i);
    558                 ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
    559                 try {
    560                     if (reportedPackageNames == null) {
    561                         callback.mCallback.opChanged(code, null);
    562                     } else {
    563                         final int reportedPackageCount = reportedPackageNames.size();
    564                         for (int j = 0; j < reportedPackageCount; j++) {
    565                             String reportedPackageName = reportedPackageNames.valueAt(j);
    566                             callback.mCallback.opChanged(code, reportedPackageName);
    567                         }
    568                     }
    569                 } catch (RemoteException e) {
    570                     Log.w(TAG, "Error dispatching op op change", e);
    571                 }
    572             }
    573         } finally {
    574             Binder.restoreCallingIdentity(identity);
    575         }
    576     }
    577 
    578     @Override
    579     public void setMode(int code, int uid, String packageName, int mode) {
    580         if (Binder.getCallingPid() != Process.myPid()) {
    581             mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
    582                     Binder.getCallingPid(), Binder.getCallingUid(), null);
    583         }
    584         verifyIncomingOp(code);
    585         ArrayList<Callback> repCbs = null;
    586         code = AppOpsManager.opToSwitch(code);
    587         synchronized (this) {
    588             UidState uidState = getUidStateLocked(uid, false);
    589             Op op = getOpLocked(code, uid, packageName, true);
    590             if (op != null) {
    591                 if (op.mode != mode) {
    592                     op.mode = mode;
    593                     ArrayList<Callback> cbs = mOpModeWatchers.get(code);
    594                     if (cbs != null) {
    595                         if (repCbs == null) {
    596                             repCbs = new ArrayList<Callback>();
    597                         }
    598                         repCbs.addAll(cbs);
    599                     }
    600                     cbs = mPackageModeWatchers.get(packageName);
    601                     if (cbs != null) {
    602                         if (repCbs == null) {
    603                             repCbs = new ArrayList<Callback>();
    604                         }
    605                         repCbs.addAll(cbs);
    606                     }
    607                     if (mode == AppOpsManager.opToDefaultMode(op.op)) {
    608                         // If going into the default mode, prune this op
    609                         // if there is nothing else interesting in it.
    610                         pruneOp(op, uid, packageName);
    611                     }
    612                     scheduleFastWriteLocked();
    613                 }
    614             }
    615         }
    616         if (repCbs != null) {
    617             // There are components watching for mode changes such as window manager
    618             // and location manager which are in our process. The callbacks in these
    619             // components may require permissions our remote caller does not have.
    620             final long identity = Binder.clearCallingIdentity();
    621             try {
    622                 for (int i = 0; i < repCbs.size(); i++) {
    623                     try {
    624                         repCbs.get(i).mCallback.opChanged(code, packageName);
    625                     } catch (RemoteException e) {
    626                     }
    627                 }
    628             } finally {
    629                 Binder.restoreCallingIdentity(identity);
    630             }
    631         }
    632     }
    633 
    634     private static HashMap<Callback, ArrayList<Pair<String, Integer>>> addCallbacks(
    635             HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks,
    636             String packageName, int op, ArrayList<Callback> cbs) {
    637         if (cbs == null) {
    638             return callbacks;
    639         }
    640         if (callbacks == null) {
    641             callbacks = new HashMap<Callback, ArrayList<Pair<String, Integer>>>();
    642         }
    643         boolean duplicate = false;
    644         for (int i=0; i<cbs.size(); i++) {
    645             Callback cb = cbs.get(i);
    646             ArrayList<Pair<String, Integer>> reports = callbacks.get(cb);
    647             if (reports == null) {
    648                 reports = new ArrayList<Pair<String, Integer>>();
    649                 callbacks.put(cb, reports);
    650             } else {
    651                 final int reportCount = reports.size();
    652                 for (int j = 0; j < reportCount; j++) {
    653                     Pair<String, Integer> report = reports.get(j);
    654                     if (report.second == op && report.first.equals(packageName)) {
    655                         duplicate = true;
    656                         break;
    657                     }
    658                 }
    659             }
    660             if (!duplicate) {
    661                 reports.add(new Pair<>(packageName, op));
    662             }
    663         }
    664         return callbacks;
    665     }
    666 
    667     @Override
    668     public void resetAllModes(int reqUserId, String reqPackageName) {
    669         final int callingPid = Binder.getCallingPid();
    670         final int callingUid = Binder.getCallingUid();
    671         mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
    672                 callingPid, callingUid, null);
    673         reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
    674                 true, true, "resetAllModes", null);
    675 
    676         int reqUid = -1;
    677         if (reqPackageName != null) {
    678             try {
    679                 reqUid = AppGlobals.getPackageManager().getPackageUid(
    680                         reqPackageName, reqUserId);
    681             } catch (RemoteException e) {
    682                 /* ignore - local call */
    683             }
    684         }
    685 
    686         HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks = null;
    687         synchronized (this) {
    688             boolean changed = false;
    689             for (int i = mUidStates.size() - 1; i >= 0; i--) {
    690                 UidState uidState = mUidStates.valueAt(i);
    691 
    692                 SparseIntArray opModes = uidState.opModes;
    693                 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
    694                     final int uidOpCount = opModes.size();
    695                     for (int j = uidOpCount - 1; j >= 0; j--) {
    696                         final int code = opModes.keyAt(j);
    697                         if (AppOpsManager.opAllowsReset(code)) {
    698                             opModes.removeAt(j);
    699                             if (opModes.size() <= 0) {
    700                                 uidState.opModes = null;
    701                             }
    702                             for (String packageName : getPackagesForUid(uidState.uid)) {
    703                                 callbacks = addCallbacks(callbacks, packageName, code,
    704                                         mOpModeWatchers.get(code));
    705                                 callbacks = addCallbacks(callbacks, packageName, code,
    706                                         mPackageModeWatchers.get(packageName));
    707                             }
    708                         }
    709                     }
    710                 }
    711 
    712                 if (uidState.pkgOps == null) {
    713                     continue;
    714                 }
    715 
    716                 if (reqUserId != UserHandle.USER_ALL
    717                         && reqUserId != UserHandle.getUserId(uidState.uid)) {
    718                     // Skip any ops for a different user
    719                     continue;
    720                 }
    721 
    722                 Map<String, Ops> packages = uidState.pkgOps;
    723                 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
    724                 while (it.hasNext()) {
    725                     Map.Entry<String, Ops> ent = it.next();
    726                     String packageName = ent.getKey();
    727                     if (reqPackageName != null && !reqPackageName.equals(packageName)) {
    728                         // Skip any ops for a different package
    729                         continue;
    730                     }
    731                     Ops pkgOps = ent.getValue();
    732                     for (int j=pkgOps.size()-1; j>=0; j--) {
    733                         Op curOp = pkgOps.valueAt(j);
    734                         if (AppOpsManager.opAllowsReset(curOp.op)
    735                                 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
    736                             curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
    737                             changed = true;
    738                             callbacks = addCallbacks(callbacks, packageName, curOp.op,
    739                                     mOpModeWatchers.get(curOp.op));
    740                             callbacks = addCallbacks(callbacks, packageName, curOp.op,
    741                                     mPackageModeWatchers.get(packageName));
    742                             if (curOp.time == 0 && curOp.rejectTime == 0) {
    743                                 pkgOps.removeAt(j);
    744                             }
    745                         }
    746                     }
    747                     if (pkgOps.size() == 0) {
    748                         it.remove();
    749                     }
    750                 }
    751                 if (uidState.isDefault()) {
    752                     mUidStates.remove(uidState.uid);
    753                 }
    754             }
    755 
    756             if (changed) {
    757                 scheduleFastWriteLocked();
    758             }
    759         }
    760         if (callbacks != null) {
    761             for (Map.Entry<Callback, ArrayList<Pair<String, Integer>>> ent : callbacks.entrySet()) {
    762                 Callback cb = ent.getKey();
    763                 ArrayList<Pair<String, Integer>> reports = ent.getValue();
    764                 for (int i=0; i<reports.size(); i++) {
    765                     Pair<String, Integer> rep = reports.get(i);
    766                     try {
    767                         cb.mCallback.opChanged(rep.second, rep.first);
    768                     } catch (RemoteException e) {
    769                     }
    770                 }
    771             }
    772         }
    773     }
    774 
    775     @Override
    776     public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
    777         synchronized (this) {
    778             op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
    779             Callback cb = mModeWatchers.get(callback.asBinder());
    780             if (cb == null) {
    781                 cb = new Callback(callback);
    782                 mModeWatchers.put(callback.asBinder(), cb);
    783             }
    784             if (op != AppOpsManager.OP_NONE) {
    785                 ArrayList<Callback> cbs = mOpModeWatchers.get(op);
    786                 if (cbs == null) {
    787                     cbs = new ArrayList<Callback>();
    788                     mOpModeWatchers.put(op, cbs);
    789                 }
    790                 cbs.add(cb);
    791             }
    792             if (packageName != null) {
    793                 ArrayList<Callback> cbs = mPackageModeWatchers.get(packageName);
    794                 if (cbs == null) {
    795                     cbs = new ArrayList<Callback>();
    796                     mPackageModeWatchers.put(packageName, cbs);
    797                 }
    798                 cbs.add(cb);
    799             }
    800         }
    801     }
    802 
    803     @Override
    804     public void stopWatchingMode(IAppOpsCallback callback) {
    805         synchronized (this) {
    806             Callback cb = mModeWatchers.remove(callback.asBinder());
    807             if (cb != null) {
    808                 cb.unlinkToDeath();
    809                 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
    810                     ArrayList<Callback> cbs = mOpModeWatchers.valueAt(i);
    811                     cbs.remove(cb);
    812                     if (cbs.size() <= 0) {
    813                         mOpModeWatchers.removeAt(i);
    814                     }
    815                 }
    816                 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
    817                     ArrayList<Callback> cbs = mPackageModeWatchers.valueAt(i);
    818                     cbs.remove(cb);
    819                     if (cbs.size() <= 0) {
    820                         mPackageModeWatchers.removeAt(i);
    821                     }
    822                 }
    823             }
    824         }
    825     }
    826 
    827     @Override
    828     public IBinder getToken(IBinder clientToken) {
    829         synchronized (this) {
    830             ClientState cs = mClients.get(clientToken);
    831             if (cs == null) {
    832                 cs = new ClientState(clientToken);
    833                 mClients.put(clientToken, cs);
    834             }
    835             return cs;
    836         }
    837     }
    838 
    839     @Override
    840     public int checkOperation(int code, int uid, String packageName) {
    841         verifyIncomingUid(uid);
    842         verifyIncomingOp(code);
    843         synchronized (this) {
    844             if (isOpRestricted(uid, code, packageName)) {
    845                 return AppOpsManager.MODE_IGNORED;
    846             }
    847             code = AppOpsManager.opToSwitch(code);
    848             UidState uidState = getUidStateLocked(uid, false);
    849             if (uidState != null && uidState.opModes != null) {
    850                 final int uidMode = uidState.opModes.get(code);
    851                 if (uidMode != AppOpsManager.MODE_ALLOWED) {
    852                     return uidMode;
    853                 }
    854             }
    855             Op op = getOpLocked(code, uid, packageName, false);
    856             if (op == null) {
    857                 return AppOpsManager.opToDefaultMode(code);
    858             }
    859             return op.mode;
    860         }
    861     }
    862 
    863     @Override
    864     public int checkAudioOperation(int code, int usage, int uid, String packageName) {
    865         synchronized (this) {
    866             final int mode = checkRestrictionLocked(code, usage, uid, packageName);
    867             if (mode != AppOpsManager.MODE_ALLOWED) {
    868                 return mode;
    869             }
    870         }
    871         return checkOperation(code, uid, packageName);
    872     }
    873 
    874     private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
    875         final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
    876         if (usageRestrictions != null) {
    877             final Restriction r = usageRestrictions.get(usage);
    878             if (r != null && !r.exceptionPackages.contains(packageName)) {
    879                 return r.mode;
    880             }
    881         }
    882         return AppOpsManager.MODE_ALLOWED;
    883     }
    884 
    885     @Override
    886     public void setAudioRestriction(int code, int usage, int uid, int mode,
    887             String[] exceptionPackages) {
    888         verifyIncomingUid(uid);
    889         verifyIncomingOp(code);
    890         synchronized (this) {
    891             SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
    892             if (usageRestrictions == null) {
    893                 usageRestrictions = new SparseArray<Restriction>();
    894                 mAudioRestrictions.put(code, usageRestrictions);
    895             }
    896             usageRestrictions.remove(usage);
    897             if (mode != AppOpsManager.MODE_ALLOWED) {
    898                 final Restriction r = new Restriction();
    899                 r.mode = mode;
    900                 if (exceptionPackages != null) {
    901                     final int N = exceptionPackages.length;
    902                     r.exceptionPackages = new ArraySet<String>(N);
    903                     for (int i = 0; i < N; i++) {
    904                         final String pkg = exceptionPackages[i];
    905                         if (pkg != null) {
    906                             r.exceptionPackages.add(pkg.trim());
    907                         }
    908                     }
    909                 }
    910                 usageRestrictions.put(usage, r);
    911             }
    912         }
    913     }
    914 
    915     @Override
    916     public int checkPackage(int uid, String packageName) {
    917         synchronized (this) {
    918             if (getOpsRawLocked(uid, packageName, true) != null) {
    919                 return AppOpsManager.MODE_ALLOWED;
    920             } else {
    921                 return AppOpsManager.MODE_ERRORED;
    922             }
    923         }
    924     }
    925 
    926     @Override
    927     public int noteProxyOperation(int code, String proxyPackageName,
    928             int proxiedUid, String proxiedPackageName) {
    929         verifyIncomingOp(code);
    930         final int proxyMode = noteOperationUnchecked(code, Binder.getCallingUid(),
    931                 proxyPackageName, -1, null);
    932         if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
    933             return proxyMode;
    934         }
    935         return noteOperationUnchecked(code, proxiedUid, proxiedPackageName,
    936                 Binder.getCallingUid(), proxyPackageName);
    937     }
    938 
    939     @Override
    940     public int noteOperation(int code, int uid, String packageName) {
    941         verifyIncomingUid(uid);
    942         verifyIncomingOp(code);
    943         return noteOperationUnchecked(code, uid, packageName, 0, null);
    944     }
    945 
    946     private int noteOperationUnchecked(int code, int uid, String packageName,
    947             int proxyUid, String proxyPackageName) {
    948         synchronized (this) {
    949             Ops ops = getOpsLocked(uid, packageName, true);
    950             if (ops == null) {
    951                 if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
    952                         + " package " + packageName);
    953                 return AppOpsManager.MODE_ERRORED;
    954             }
    955             Op op = getOpLocked(ops, code, true);
    956             if (isOpRestricted(uid, code, packageName)) {
    957                 return AppOpsManager.MODE_IGNORED;
    958             }
    959             if (op.duration == -1) {
    960                 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
    961                         + " code " + code + " time=" + op.time + " duration=" + op.duration);
    962             }
    963             op.duration = 0;
    964             final int switchCode = AppOpsManager.opToSwitch(code);
    965             UidState uidState = ops.uidState;
    966             if (uidState.opModes != null) {
    967                 final int uidMode = uidState.opModes.get(switchCode);
    968                 if (uidMode != AppOpsManager.MODE_ALLOWED) {
    969                     if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
    970                             + switchCode + " (" + code + ") uid " + uid + " package "
    971                             + packageName);
    972                     op.rejectTime = System.currentTimeMillis();
    973                     return uidMode;
    974                 }
    975             }
    976             final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
    977             if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
    978                 if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
    979                         + switchCode + " (" + code + ") uid " + uid + " package " + packageName);
    980                 op.rejectTime = System.currentTimeMillis();
    981                 return switchOp.mode;
    982             }
    983             if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
    984                     + " package " + packageName);
    985             op.time = System.currentTimeMillis();
    986             op.rejectTime = 0;
    987             op.proxyUid = proxyUid;
    988             op.proxyPackageName = proxyPackageName;
    989             return AppOpsManager.MODE_ALLOWED;
    990         }
    991     }
    992 
    993     @Override
    994     public int startOperation(IBinder token, int code, int uid, String packageName) {
    995         verifyIncomingUid(uid);
    996         verifyIncomingOp(code);
    997         ClientState client = (ClientState)token;
    998         synchronized (this) {
    999             Ops ops = getOpsLocked(uid, packageName, true);
   1000             if (ops == null) {
   1001                 if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
   1002                         + " package " + packageName);
   1003                 return AppOpsManager.MODE_ERRORED;
   1004             }
   1005             Op op = getOpLocked(ops, code, true);
   1006             if (isOpRestricted(uid, code, packageName)) {
   1007                 return AppOpsManager.MODE_IGNORED;
   1008             }
   1009             final int switchCode = AppOpsManager.opToSwitch(code);
   1010             UidState uidState = ops.uidState;
   1011             if (uidState.opModes != null) {
   1012                 final int uidMode = uidState.opModes.get(switchCode);
   1013                 if (uidMode != AppOpsManager.MODE_ALLOWED) {
   1014                     if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
   1015                             + switchCode + " (" + code + ") uid " + uid + " package "
   1016                             + packageName);
   1017                     op.rejectTime = System.currentTimeMillis();
   1018                     return uidMode;
   1019                 }
   1020             }
   1021             final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
   1022             if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
   1023                 if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code "
   1024                         + switchCode + " (" + code + ") uid " + uid + " package " + packageName);
   1025                 op.rejectTime = System.currentTimeMillis();
   1026                 return switchOp.mode;
   1027             }
   1028             if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid
   1029                     + " package " + packageName);
   1030             if (op.nesting == 0) {
   1031                 op.time = System.currentTimeMillis();
   1032                 op.rejectTime = 0;
   1033                 op.duration = -1;
   1034             }
   1035             op.nesting++;
   1036             if (client.mStartedOps != null) {
   1037                 client.mStartedOps.add(op);
   1038             }
   1039             return AppOpsManager.MODE_ALLOWED;
   1040         }
   1041     }
   1042 
   1043     @Override
   1044     public void finishOperation(IBinder token, int code, int uid, String packageName) {
   1045         verifyIncomingUid(uid);
   1046         verifyIncomingOp(code);
   1047         ClientState client = (ClientState)token;
   1048         synchronized (this) {
   1049             Op op = getOpLocked(code, uid, packageName, true);
   1050             if (op == null) {
   1051                 return;
   1052             }
   1053             if (client.mStartedOps != null) {
   1054                 if (!client.mStartedOps.remove(op)) {
   1055                     throw new IllegalStateException("Operation not started: uid" + op.uid
   1056                             + " pkg=" + op.packageName + " op=" + op.op);
   1057                 }
   1058             }
   1059             finishOperationLocked(op);
   1060         }
   1061     }
   1062 
   1063     @Override
   1064     public int permissionToOpCode(String permission) {
   1065         return AppOpsManager.permissionToOpCode(permission);
   1066     }
   1067 
   1068     void finishOperationLocked(Op op) {
   1069         if (op.nesting <= 1) {
   1070             if (op.nesting == 1) {
   1071                 op.duration = (int)(System.currentTimeMillis() - op.time);
   1072                 op.time += op.duration;
   1073             } else {
   1074                 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
   1075                         + op.packageName + " code " + op.op + " time=" + op.time
   1076                         + " duration=" + op.duration + " nesting=" + op.nesting);
   1077             }
   1078             op.nesting = 0;
   1079         } else {
   1080             op.nesting--;
   1081         }
   1082     }
   1083 
   1084     private void verifyIncomingUid(int uid) {
   1085         if (uid == Binder.getCallingUid()) {
   1086             return;
   1087         }
   1088         if (Binder.getCallingPid() == Process.myPid()) {
   1089             return;
   1090         }
   1091         mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
   1092                 Binder.getCallingPid(), Binder.getCallingUid(), null);
   1093     }
   1094 
   1095     private void verifyIncomingOp(int op) {
   1096         if (op >= 0 && op < AppOpsManager._NUM_OP) {
   1097             return;
   1098         }
   1099         throw new IllegalArgumentException("Bad operation #" + op);
   1100     }
   1101 
   1102     private UidState getUidStateLocked(int uid, boolean edit) {
   1103         UidState uidState = mUidStates.get(uid);
   1104         if (uidState == null) {
   1105             if (!edit) {
   1106                 return null;
   1107             }
   1108             uidState = new UidState(uid);
   1109             mUidStates.put(uid, uidState);
   1110         }
   1111         return uidState;
   1112     }
   1113 
   1114     private Ops getOpsLocked(int uid, String packageName, boolean edit) {
   1115         if (uid == 0) {
   1116             packageName = "root";
   1117         } else if (uid == Process.SHELL_UID) {
   1118             packageName = "com.android.shell";
   1119         }
   1120         return getOpsRawLocked(uid, packageName, edit);
   1121     }
   1122 
   1123     private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
   1124         UidState uidState = getUidStateLocked(uid, edit);
   1125         if (uidState == null) {
   1126             return null;
   1127         }
   1128 
   1129         if (uidState.pkgOps == null) {
   1130             if (!edit) {
   1131                 return null;
   1132             }
   1133             uidState.pkgOps = new ArrayMap<>();
   1134         }
   1135 
   1136         Ops ops = uidState.pkgOps.get(packageName);
   1137         if (ops == null) {
   1138             if (!edit) {
   1139                 return null;
   1140             }
   1141             boolean isPrivileged = false;
   1142             // This is the first time we have seen this package name under this uid,
   1143             // so let's make sure it is valid.
   1144             if (uid != 0) {
   1145                 final long ident = Binder.clearCallingIdentity();
   1146                 try {
   1147                     int pkgUid = -1;
   1148                     try {
   1149                         ApplicationInfo appInfo = ActivityThread.getPackageManager()
   1150                                 .getApplicationInfo(packageName, 0, UserHandle.getUserId(uid));
   1151                         if (appInfo != null) {
   1152                             pkgUid = appInfo.uid;
   1153                             isPrivileged = (appInfo.privateFlags
   1154                                     & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
   1155                         } else {
   1156                             if ("media".equals(packageName)) {
   1157                                 pkgUid = Process.MEDIA_UID;
   1158                                 isPrivileged = false;
   1159                             }
   1160                         }
   1161                     } catch (RemoteException e) {
   1162                         Slog.w(TAG, "Could not contact PackageManager", e);
   1163                     }
   1164                     if (pkgUid != uid) {
   1165                         // Oops!  The package name is not valid for the uid they are calling
   1166                         // under.  Abort.
   1167                         Slog.w(TAG, "Bad call: specified package " + packageName
   1168                                 + " under uid " + uid + " but it is really " + pkgUid);
   1169                         return null;
   1170                     }
   1171                 } finally {
   1172                     Binder.restoreCallingIdentity(ident);
   1173                 }
   1174             }
   1175             ops = new Ops(packageName, uidState, isPrivileged);
   1176             uidState.pkgOps.put(packageName, ops);
   1177         }
   1178         return ops;
   1179     }
   1180 
   1181     private void scheduleWriteLocked() {
   1182         if (!mWriteScheduled) {
   1183             mWriteScheduled = true;
   1184             mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
   1185         }
   1186     }
   1187 
   1188     private void scheduleFastWriteLocked() {
   1189         if (!mFastWriteScheduled) {
   1190             mWriteScheduled = true;
   1191             mFastWriteScheduled = true;
   1192             mHandler.removeCallbacks(mWriteRunner);
   1193             mHandler.postDelayed(mWriteRunner, 10*1000);
   1194         }
   1195     }
   1196 
   1197     private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
   1198         Ops ops = getOpsLocked(uid, packageName, edit);
   1199         if (ops == null) {
   1200             return null;
   1201         }
   1202         return getOpLocked(ops, code, edit);
   1203     }
   1204 
   1205     private Op getOpLocked(Ops ops, int code, boolean edit) {
   1206         Op op = ops.get(code);
   1207         if (op == null) {
   1208             if (!edit) {
   1209                 return null;
   1210             }
   1211             op = new Op(ops.uidState.uid, ops.packageName, code);
   1212             ops.put(code, op);
   1213         }
   1214         if (edit) {
   1215             scheduleWriteLocked();
   1216         }
   1217         return op;
   1218     }
   1219 
   1220     private boolean isOpRestricted(int uid, int code, String packageName) {
   1221         int userHandle = UserHandle.getUserId(uid);
   1222         boolean[] opRestrictions = mOpRestrictions.get(userHandle);
   1223         if ((opRestrictions != null) && opRestrictions[code]) {
   1224             if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
   1225                 synchronized (this) {
   1226                     Ops ops = getOpsLocked(uid, packageName, true);
   1227                     if ((ops != null) && ops.isPrivileged) {
   1228                         return false;
   1229                     }
   1230                 }
   1231             }
   1232             return true;
   1233         }
   1234         return false;
   1235     }
   1236 
   1237     void readState() {
   1238         synchronized (mFile) {
   1239             synchronized (this) {
   1240                 FileInputStream stream;
   1241                 try {
   1242                     stream = mFile.openRead();
   1243                 } catch (FileNotFoundException e) {
   1244                     Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
   1245                     return;
   1246                 }
   1247                 boolean success = false;
   1248                 mUidStates.clear();
   1249                 try {
   1250                     XmlPullParser parser = Xml.newPullParser();
   1251                     parser.setInput(stream, StandardCharsets.UTF_8.name());
   1252                     int type;
   1253                     while ((type = parser.next()) != XmlPullParser.START_TAG
   1254                             && type != XmlPullParser.END_DOCUMENT) {
   1255                         ;
   1256                     }
   1257 
   1258                     if (type != XmlPullParser.START_TAG) {
   1259                         throw new IllegalStateException("no start tag found");
   1260                     }
   1261 
   1262                     int outerDepth = parser.getDepth();
   1263                     while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
   1264                             && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
   1265                         if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   1266                             continue;
   1267                         }
   1268 
   1269                         String tagName = parser.getName();
   1270                         if (tagName.equals("pkg")) {
   1271                             readPackage(parser);
   1272                         } else if (tagName.equals("uid")) {
   1273                             readUidOps(parser);
   1274                         } else {
   1275                             Slog.w(TAG, "Unknown element under <app-ops>: "
   1276                                     + parser.getName());
   1277                             XmlUtils.skipCurrentTag(parser);
   1278                         }
   1279                     }
   1280                     success = true;
   1281                 } catch (IllegalStateException e) {
   1282                     Slog.w(TAG, "Failed parsing " + e);
   1283                 } catch (NullPointerException e) {
   1284                     Slog.w(TAG, "Failed parsing " + e);
   1285                 } catch (NumberFormatException e) {
   1286                     Slog.w(TAG, "Failed parsing " + e);
   1287                 } catch (XmlPullParserException e) {
   1288                     Slog.w(TAG, "Failed parsing " + e);
   1289                 } catch (IOException e) {
   1290                     Slog.w(TAG, "Failed parsing " + e);
   1291                 } catch (IndexOutOfBoundsException e) {
   1292                     Slog.w(TAG, "Failed parsing " + e);
   1293                 } finally {
   1294                     if (!success) {
   1295                         mUidStates.clear();
   1296                     }
   1297                     try {
   1298                         stream.close();
   1299                     } catch (IOException e) {
   1300                     }
   1301                 }
   1302             }
   1303         }
   1304     }
   1305 
   1306     void readUidOps(XmlPullParser parser) throws NumberFormatException,
   1307             XmlPullParserException, IOException {
   1308         final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
   1309         int outerDepth = parser.getDepth();
   1310         int type;
   1311         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
   1312                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
   1313             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   1314                 continue;
   1315             }
   1316 
   1317             String tagName = parser.getName();
   1318             if (tagName.equals("op")) {
   1319                 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
   1320                 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
   1321                 UidState uidState = getUidStateLocked(uid, true);
   1322                 if (uidState.opModes == null) {
   1323                     uidState.opModes = new SparseIntArray();
   1324                 }
   1325                 uidState.opModes.put(code, mode);
   1326             } else {
   1327                 Slog.w(TAG, "Unknown element under <uid-ops>: "
   1328                         + parser.getName());
   1329                 XmlUtils.skipCurrentTag(parser);
   1330             }
   1331         }
   1332     }
   1333 
   1334     void readPackage(XmlPullParser parser) throws NumberFormatException,
   1335             XmlPullParserException, IOException {
   1336         String pkgName = parser.getAttributeValue(null, "n");
   1337         int outerDepth = parser.getDepth();
   1338         int type;
   1339         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
   1340                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
   1341             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   1342                 continue;
   1343             }
   1344 
   1345             String tagName = parser.getName();
   1346             if (tagName.equals("uid")) {
   1347                 readUid(parser, pkgName);
   1348             } else {
   1349                 Slog.w(TAG, "Unknown element under <pkg>: "
   1350                         + parser.getName());
   1351                 XmlUtils.skipCurrentTag(parser);
   1352             }
   1353         }
   1354     }
   1355 
   1356     void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
   1357             XmlPullParserException, IOException {
   1358         int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
   1359         String isPrivilegedString = parser.getAttributeValue(null, "p");
   1360         boolean isPrivileged = false;
   1361         if (isPrivilegedString == null) {
   1362             try {
   1363                 IPackageManager packageManager = ActivityThread.getPackageManager();
   1364                 if (packageManager != null) {
   1365                     ApplicationInfo appInfo = ActivityThread.getPackageManager()
   1366                             .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
   1367                     if (appInfo != null) {
   1368                         isPrivileged = (appInfo.privateFlags
   1369                                 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
   1370                     }
   1371                 } else {
   1372                     // Could not load data, don't add to cache so it will be loaded later.
   1373                     return;
   1374                 }
   1375             } catch (RemoteException e) {
   1376                 Slog.w(TAG, "Could not contact PackageManager", e);
   1377             }
   1378         } else {
   1379             isPrivileged = Boolean.parseBoolean(isPrivilegedString);
   1380         }
   1381         int outerDepth = parser.getDepth();
   1382         int type;
   1383         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
   1384                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
   1385             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   1386                 continue;
   1387             }
   1388 
   1389             String tagName = parser.getName();
   1390             if (tagName.equals("op")) {
   1391                 Op op = new Op(uid, pkgName, Integer.parseInt(parser.getAttributeValue(null, "n")));
   1392                 String mode = parser.getAttributeValue(null, "m");
   1393                 if (mode != null) {
   1394                     op.mode = Integer.parseInt(mode);
   1395                 }
   1396                 String time = parser.getAttributeValue(null, "t");
   1397                 if (time != null) {
   1398                     op.time = Long.parseLong(time);
   1399                 }
   1400                 time = parser.getAttributeValue(null, "r");
   1401                 if (time != null) {
   1402                     op.rejectTime = Long.parseLong(time);
   1403                 }
   1404                 String dur = parser.getAttributeValue(null, "d");
   1405                 if (dur != null) {
   1406                     op.duration = Integer.parseInt(dur);
   1407                 }
   1408                 String proxyUid = parser.getAttributeValue(null, "pu");
   1409                 if (proxyUid != null) {
   1410                     op.proxyUid = Integer.parseInt(proxyUid);
   1411                 }
   1412                 String proxyPackageName = parser.getAttributeValue(null, "pp");
   1413                 if (proxyPackageName != null) {
   1414                     op.proxyPackageName = proxyPackageName;
   1415                 }
   1416 
   1417                 UidState uidState = getUidStateLocked(uid, true);
   1418                 if (uidState.pkgOps == null) {
   1419                     uidState.pkgOps = new ArrayMap<>();
   1420                 }
   1421 
   1422                 Ops ops = uidState.pkgOps.get(pkgName);
   1423                 if (ops == null) {
   1424                     ops = new Ops(pkgName, uidState, isPrivileged);
   1425                     uidState.pkgOps.put(pkgName, ops);
   1426                 }
   1427                 ops.put(op.op, op);
   1428             } else {
   1429                 Slog.w(TAG, "Unknown element under <pkg>: "
   1430                         + parser.getName());
   1431                 XmlUtils.skipCurrentTag(parser);
   1432             }
   1433         }
   1434     }
   1435 
   1436     void writeState() {
   1437         synchronized (mFile) {
   1438             List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
   1439 
   1440             FileOutputStream stream;
   1441             try {
   1442                 stream = mFile.startWrite();
   1443             } catch (IOException e) {
   1444                 Slog.w(TAG, "Failed to write state: " + e);
   1445                 return;
   1446             }
   1447 
   1448             try {
   1449                 XmlSerializer out = new FastXmlSerializer();
   1450                 out.setOutput(stream, StandardCharsets.UTF_8.name());
   1451                 out.startDocument(null, true);
   1452                 out.startTag(null, "app-ops");
   1453 
   1454                 final int uidStateCount = mUidStates.size();
   1455                 for (int i = 0; i < uidStateCount; i++) {
   1456                     UidState uidState = mUidStates.valueAt(i);
   1457                     if (uidState.opModes != null && uidState.opModes.size() > 0) {
   1458                         out.startTag(null, "uid");
   1459                         out.attribute(null, "n", Integer.toString(uidState.uid));
   1460                         SparseIntArray uidOpModes = uidState.opModes;
   1461                         final int opCount = uidOpModes.size();
   1462                         for (int j = 0; j < opCount; j++) {
   1463                             final int op = uidOpModes.keyAt(j);
   1464                             final int mode = uidOpModes.valueAt(j);
   1465                             out.startTag(null, "op");
   1466                             out.attribute(null, "n", Integer.toString(op));
   1467                             out.attribute(null, "m", Integer.toString(mode));
   1468                             out.endTag(null, "op");
   1469                         }
   1470                         out.endTag(null, "uid");
   1471                     }
   1472                 }
   1473 
   1474                 if (allOps != null) {
   1475                     String lastPkg = null;
   1476                     for (int i=0; i<allOps.size(); i++) {
   1477                         AppOpsManager.PackageOps pkg = allOps.get(i);
   1478                         if (!pkg.getPackageName().equals(lastPkg)) {
   1479                             if (lastPkg != null) {
   1480                                 out.endTag(null, "pkg");
   1481                             }
   1482                             lastPkg = pkg.getPackageName();
   1483                             out.startTag(null, "pkg");
   1484                             out.attribute(null, "n", lastPkg);
   1485                         }
   1486                         out.startTag(null, "uid");
   1487                         out.attribute(null, "n", Integer.toString(pkg.getUid()));
   1488                         synchronized (this) {
   1489                             Ops ops = getOpsLocked(pkg.getUid(), pkg.getPackageName(), false);
   1490                             // Should always be present as the list of PackageOps is generated
   1491                             // from Ops.
   1492                             if (ops != null) {
   1493                                 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
   1494                             } else {
   1495                                 out.attribute(null, "p", Boolean.toString(false));
   1496                             }
   1497                         }
   1498                         List<AppOpsManager.OpEntry> ops = pkg.getOps();
   1499                         for (int j=0; j<ops.size(); j++) {
   1500                             AppOpsManager.OpEntry op = ops.get(j);
   1501                             out.startTag(null, "op");
   1502                             out.attribute(null, "n", Integer.toString(op.getOp()));
   1503                             if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
   1504                                 out.attribute(null, "m", Integer.toString(op.getMode()));
   1505                             }
   1506                             long time = op.getTime();
   1507                             if (time != 0) {
   1508                                 out.attribute(null, "t", Long.toString(time));
   1509                             }
   1510                             time = op.getRejectTime();
   1511                             if (time != 0) {
   1512                                 out.attribute(null, "r", Long.toString(time));
   1513                             }
   1514                             int dur = op.getDuration();
   1515                             if (dur != 0) {
   1516                                 out.attribute(null, "d", Integer.toString(dur));
   1517                             }
   1518                             int proxyUid = op.getProxyUid();
   1519                             if (proxyUid != -1) {
   1520                                 out.attribute(null, "pu", Integer.toString(proxyUid));
   1521                             }
   1522                             String proxyPackageName = op.getProxyPackageName();
   1523                             if (proxyPackageName != null) {
   1524                                 out.attribute(null, "pp", proxyPackageName);
   1525                             }
   1526                             out.endTag(null, "op");
   1527                         }
   1528                         out.endTag(null, "uid");
   1529                     }
   1530                     if (lastPkg != null) {
   1531                         out.endTag(null, "pkg");
   1532                     }
   1533                 }
   1534 
   1535                 out.endTag(null, "app-ops");
   1536                 out.endDocument();
   1537                 mFile.finishWrite(stream);
   1538             } catch (IOException e) {
   1539                 Slog.w(TAG, "Failed to write state, restoring backup.", e);
   1540                 mFile.failWrite(stream);
   1541             }
   1542         }
   1543     }
   1544 
   1545     private void dumpHelp(PrintWriter pw) {
   1546         pw.println("AppOps service (appops) dump options:");
   1547         pw.println("  [-h] [CMD]");
   1548         pw.println("  -h: print this help text.");
   1549         pw.println("Commands:");
   1550         pw.println("  write-settings");
   1551         pw.println("    Immediately write pending changes to storage.");
   1552         pw.println("  read-settings");
   1553         pw.println("    Read the last written settings, replacing current state in RAM.");
   1554     }
   1555 
   1556     @Override
   1557     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1558         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
   1559                 != PackageManager.PERMISSION_GRANTED) {
   1560             pw.println("Permission Denial: can't dump ApOps service from from pid="
   1561                     + Binder.getCallingPid()
   1562                     + ", uid=" + Binder.getCallingUid());
   1563             return;
   1564         }
   1565 
   1566         if (args != null) {
   1567             for (int i=0; i<args.length; i++) {
   1568                 String arg = args[i];
   1569                 if ("-h".equals(arg)) {
   1570                     dumpHelp(pw);
   1571                     return;
   1572                 } else if ("-a".equals(arg)) {
   1573                     // dump all data
   1574                 } else if ("write-settings".equals(arg)) {
   1575                     long token = Binder.clearCallingIdentity();
   1576                     try {
   1577                         synchronized (this) {
   1578                             mHandler.removeCallbacks(mWriteRunner);
   1579                         }
   1580                         writeState();
   1581                         pw.println("Current settings written.");
   1582                     } finally {
   1583                         Binder.restoreCallingIdentity(token);
   1584                     }
   1585                     return;
   1586                 } else if ("read-settings".equals(arg)) {
   1587                     long token = Binder.clearCallingIdentity();
   1588                     try {
   1589                         readState();
   1590                         pw.println("Last settings read.");
   1591                     } finally {
   1592                         Binder.restoreCallingIdentity(token);
   1593                     }
   1594                     return;
   1595                 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
   1596                     pw.println("Unknown option: " + arg);
   1597                     return;
   1598                 } else {
   1599                     pw.println("Unknown command: " + arg);
   1600                     return;
   1601                 }
   1602             }
   1603         }
   1604 
   1605         synchronized (this) {
   1606             pw.println("Current AppOps Service state:");
   1607             final long now = System.currentTimeMillis();
   1608             boolean needSep = false;
   1609             if (mOpModeWatchers.size() > 0) {
   1610                 needSep = true;
   1611                 pw.println("  Op mode watchers:");
   1612                 for (int i=0; i<mOpModeWatchers.size(); i++) {
   1613                     pw.print("    Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
   1614                     pw.println(":");
   1615                     ArrayList<Callback> callbacks = mOpModeWatchers.valueAt(i);
   1616                     for (int j=0; j<callbacks.size(); j++) {
   1617                         pw.print("      #"); pw.print(j); pw.print(": ");
   1618                         pw.println(callbacks.get(j));
   1619                     }
   1620                 }
   1621             }
   1622             if (mPackageModeWatchers.size() > 0) {
   1623                 needSep = true;
   1624                 pw.println("  Package mode watchers:");
   1625                 for (int i=0; i<mPackageModeWatchers.size(); i++) {
   1626                     pw.print("    Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
   1627                     pw.println(":");
   1628                     ArrayList<Callback> callbacks = mPackageModeWatchers.valueAt(i);
   1629                     for (int j=0; j<callbacks.size(); j++) {
   1630                         pw.print("      #"); pw.print(j); pw.print(": ");
   1631                         pw.println(callbacks.get(j));
   1632                     }
   1633                 }
   1634             }
   1635             if (mModeWatchers.size() > 0) {
   1636                 needSep = true;
   1637                 pw.println("  All mode watchers:");
   1638                 for (int i=0; i<mModeWatchers.size(); i++) {
   1639                     pw.print("    "); pw.print(mModeWatchers.keyAt(i));
   1640                     pw.print(" -> "); pw.println(mModeWatchers.valueAt(i));
   1641                 }
   1642             }
   1643             if (mClients.size() > 0) {
   1644                 needSep = true;
   1645                 pw.println("  Clients:");
   1646                 for (int i=0; i<mClients.size(); i++) {
   1647                     pw.print("    "); pw.print(mClients.keyAt(i)); pw.println(":");
   1648                     ClientState cs = mClients.valueAt(i);
   1649                     pw.print("      "); pw.println(cs);
   1650                     if (cs.mStartedOps != null && cs.mStartedOps.size() > 0) {
   1651                         pw.println("      Started ops:");
   1652                         for (int j=0; j<cs.mStartedOps.size(); j++) {
   1653                             Op op = cs.mStartedOps.get(j);
   1654                             pw.print("        "); pw.print("uid="); pw.print(op.uid);
   1655                             pw.print(" pkg="); pw.print(op.packageName);
   1656                             pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
   1657                         }
   1658                     }
   1659                 }
   1660             }
   1661             if (mAudioRestrictions.size() > 0) {
   1662                 boolean printedHeader = false;
   1663                 for (int o=0; o<mAudioRestrictions.size(); o++) {
   1664                     final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
   1665                     final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
   1666                     for (int i=0; i<restrictions.size(); i++) {
   1667                         if (!printedHeader){
   1668                             pw.println("  Audio Restrictions:");
   1669                             printedHeader = true;
   1670                             needSep = true;
   1671                         }
   1672                         final int usage = restrictions.keyAt(i);
   1673                         pw.print("    "); pw.print(op);
   1674                         pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
   1675                         Restriction r = restrictions.valueAt(i);
   1676                         pw.print(": mode="); pw.println(r.mode);
   1677                         if (!r.exceptionPackages.isEmpty()) {
   1678                             pw.println("      Exceptions:");
   1679                             for (int j=0; j<r.exceptionPackages.size(); j++) {
   1680                                 pw.print("        "); pw.println(r.exceptionPackages.valueAt(j));
   1681                             }
   1682                         }
   1683                     }
   1684                 }
   1685             }
   1686             if (needSep) {
   1687                 pw.println();
   1688             }
   1689             for (int i=0; i<mUidStates.size(); i++) {
   1690                 UidState uidState = mUidStates.valueAt(i);
   1691 
   1692                 pw.print("  Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
   1693 
   1694                 SparseIntArray opModes = uidState.opModes;
   1695                 if (opModes != null) {
   1696                     final int opModeCount = opModes.size();
   1697                     for (int j = 0; j < opModeCount; j++) {
   1698                         final int code = opModes.keyAt(j);
   1699                         final int mode = opModes.valueAt(j);
   1700                         pw.print("      "); pw.print(AppOpsManager.opToName(code));
   1701                         pw.print(": mode="); pw.println(mode);
   1702                     }
   1703                 }
   1704 
   1705                 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
   1706                 if (pkgOps == null) {
   1707                     continue;
   1708                 }
   1709 
   1710                 for (Ops ops : pkgOps.values()) {
   1711                     pw.print("    Package "); pw.print(ops.packageName); pw.println(":");
   1712                     for (int j=0; j<ops.size(); j++) {
   1713                         Op op = ops.valueAt(j);
   1714                         pw.print("      "); pw.print(AppOpsManager.opToName(op.op));
   1715                         pw.print(": mode="); pw.print(op.mode);
   1716                         if (op.time != 0) {
   1717                             pw.print("; time="); TimeUtils.formatDuration(now-op.time, pw);
   1718                             pw.print(" ago");
   1719                         }
   1720                         if (op.rejectTime != 0) {
   1721                             pw.print("; rejectTime="); TimeUtils.formatDuration(now-op.rejectTime, pw);
   1722                             pw.print(" ago");
   1723                         }
   1724                         if (op.duration == -1) {
   1725                             pw.print(" (running)");
   1726                         } else if (op.duration != 0) {
   1727                             pw.print("; duration="); TimeUtils.formatDuration(op.duration, pw);
   1728                         }
   1729                         pw.println();
   1730                     }
   1731                 }
   1732             }
   1733         }
   1734     }
   1735 
   1736     private static final class Restriction {
   1737         private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
   1738         int mode;
   1739         ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
   1740     }
   1741 
   1742     @Override
   1743     public void setUserRestrictions(Bundle restrictions, int userHandle) throws RemoteException {
   1744         checkSystemUid("setUserRestrictions");
   1745         boolean[] opRestrictions = mOpRestrictions.get(userHandle);
   1746         if (opRestrictions == null) {
   1747             opRestrictions = new boolean[AppOpsManager._NUM_OP];
   1748             mOpRestrictions.put(userHandle, opRestrictions);
   1749         }
   1750         for (int i = 0; i < opRestrictions.length; ++i) {
   1751             String restriction = AppOpsManager.opToRestriction(i);
   1752             if (restriction != null) {
   1753                 opRestrictions[i] = restrictions.getBoolean(restriction, false);
   1754             } else {
   1755                 opRestrictions[i] = false;
   1756             }
   1757         }
   1758     }
   1759 
   1760     @Override
   1761     public void removeUser(int userHandle) throws RemoteException {
   1762         checkSystemUid("removeUser");
   1763         mOpRestrictions.remove(userHandle);
   1764     }
   1765 
   1766     private void checkSystemUid(String function) {
   1767         int uid = Binder.getCallingUid();
   1768         if (uid != Process.SYSTEM_UID) {
   1769             throw new SecurityException(function + " must by called by the system");
   1770         }
   1771     }
   1772 
   1773     private static String[] getPackagesForUid(int uid) {
   1774         String[] packageNames = null;
   1775         try {
   1776             packageNames= AppGlobals.getPackageManager().getPackagesForUid(uid);
   1777         } catch (RemoteException e) {
   1778             /* ignore - local call */
   1779         }
   1780         if (packageNames == null) {
   1781             return EmptyArray.STRING;
   1782         }
   1783         return packageNames;
   1784     }
   1785 }
   1786