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