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