AppOpsService.java revision a8bbd76d9b5249c64ef31aa162e9a84abaad39ba
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
17package com.android.server;
18
19import java.io.File;
20import java.io.FileDescriptor;
21import java.io.FileInputStream;
22import java.io.FileNotFoundException;
23import java.io.FileOutputStream;
24import java.io.IOException;
25import java.io.PrintWriter;
26import java.nio.charset.StandardCharsets;
27import java.util.ArrayList;
28import java.util.Arrays;
29import java.util.Collections;
30import java.util.HashMap;
31import java.util.Iterator;
32import java.util.List;
33import java.util.Map;
34
35import android.Manifest;
36import android.app.ActivityManager;
37import android.app.ActivityThread;
38import android.app.AppGlobals;
39import android.app.AppOpsManager;
40import android.content.Context;
41import android.content.pm.ApplicationInfo;
42import android.content.pm.IPackageManager;
43import android.content.pm.PackageManager;
44import android.media.AudioAttributes;
45import android.os.AsyncTask;
46import android.os.Binder;
47import android.os.Bundle;
48import android.os.Handler;
49import android.os.IBinder;
50import android.os.Process;
51import android.os.RemoteException;
52import android.os.ResultReceiver;
53import android.os.ServiceManager;
54import android.os.ShellCommand;
55import android.os.UserHandle;
56import android.os.storage.MountServiceInternal;
57import android.util.ArrayMap;
58import android.util.ArraySet;
59import android.util.AtomicFile;
60import android.util.Log;
61import android.util.Slog;
62import android.util.SparseArray;
63import android.util.SparseIntArray;
64import android.util.TimeUtils;
65import android.util.Xml;
66
67import com.android.internal.app.IAppOpsService;
68import com.android.internal.app.IAppOpsCallback;
69import com.android.internal.os.Zygote;
70import com.android.internal.util.ArrayUtils;
71import com.android.internal.util.FastXmlSerializer;
72import com.android.internal.util.Preconditions;
73import com.android.internal.util.XmlUtils;
74
75import libcore.util.EmptyArray;
76import org.xmlpull.v1.XmlPullParser;
77import org.xmlpull.v1.XmlPullParserException;
78import org.xmlpull.v1.XmlSerializer;
79
80public 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
121        public UidState(int uid) {
122            this.uid = uid;
123        }
124
125        public void clear() {
126            pkgOps = null;
127            opModes = null;
128        }
129
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
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
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
180        public Callback(IAppOpsCallback callback) {
181            mCallback = callback;
182            try {
183                mCallback.asBinder().linkToDeath(this, 0);
184            } catch (RemoteException e) {
185            }
186        }
187
188        public void unlinkToDeath() {
189            mCallback.asBinder().unlinkToDeath(this, 0);
190        }
191
192        @Override
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
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
221        public String toString() {
222            return "ClientState{" +
223                    "mAppToken=" + mAppToken +
224                    ", " + (mStartedOps != null ? ("pid=" + mPid) : "local") +
225                    '}';
226        }
227
228        @Override
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
239    public AppOpsService(File storagePath, Handler handler) {
240        mFile = new AtomicFile(storagePath);
241        mHandler = handler;
242        readState();
243    }
244
245    public void publish(Context context) {
246        mContext = context;
247        ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
248    }
249
250    public void systemReady() {
251        synchronized (this) {
252            boolean changed = false;
253            for (int i = mUidStates.size() - 1; i >= 0; i--) {
254                UidState uidState = mUidStates.valueAt(i);
255
256                String[] packageNames = getPackagesForUid(uidState.uid);
257                if (ArrayUtils.isEmpty(packageNames)) {
258                    uidState.clear();
259                    mUidStates.removeAt(i);
260                    changed = true;
261                    continue;
262                }
263
264                ArrayMap<String, Ops> pkgs = uidState.pkgOps;
265                if (pkgs == null) {
266                    continue;
267                }
268
269                Iterator<Ops> it = pkgs.values().iterator();
270                while (it.hasNext()) {
271                    Ops ops = it.next();
272                    int curUid = -1;
273                    try {
274                        curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
275                                PackageManager.MATCH_UNINSTALLED_PACKAGES,
276                                UserHandle.getUserId(ops.uidState.uid));
277                    } catch (RemoteException ignored) {
278                    }
279                    if (curUid != ops.uidState.uid) {
280                        Slog.i(TAG, "Pruning old package " + ops.packageName
281                                + "/" + ops.uidState + ": new uid=" + curUid);
282                        it.remove();
283                        changed = true;
284                    }
285                }
286
287                if (uidState.isDefault()) {
288                    mUidStates.removeAt(i);
289                }
290            }
291            if (changed) {
292                scheduleFastWriteLocked();
293            }
294        }
295
296        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
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
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
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
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
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
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
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
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
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
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
684        ChangeRec(int _op, int _uid, String _pkg) {
685            op = _op;
686            uid = _uid;
687            pkg = _pkg;
688        }
689    }
690
691    @Override
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1151    public int permissionToOpCode(String permission) {
1152        if (permission == null) {
1153            return AppOpsManager.OP_NONE;
1154        }
1155        return AppOpsManager.permissionToOpCode(permission);
1156    }
1157
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
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
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
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
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
1272    private void scheduleWriteLocked() {
1273        if (!mWriteScheduled) {
1274            mWriteScheduled = true;
1275            mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
1276        }
1277    }
1278
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
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
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
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                    && 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                return true;
1329            }
1330        }
1331        return false;
1332    }
1333
1334    void readState() {
1335        synchronized (mFile) {
1336            synchronized (this) {
1337                FileInputStream stream;
1338                try {
1339                    stream = mFile.openRead();
1340                } catch (FileNotFoundException e) {
1341                    Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
1342                    return;
1343                }
1344                boolean success = false;
1345                mUidStates.clear();
1346                try {
1347                    XmlPullParser parser = Xml.newPullParser();
1348                    parser.setInput(stream, StandardCharsets.UTF_8.name());
1349                    int type;
1350                    while ((type = parser.next()) != XmlPullParser.START_TAG
1351                            && type != XmlPullParser.END_DOCUMENT) {
1352                        ;
1353                    }
1354
1355                    if (type != XmlPullParser.START_TAG) {
1356                        throw new IllegalStateException("no start tag found");
1357                    }
1358
1359                    int outerDepth = parser.getDepth();
1360                    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1361                            && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1362                        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1363                            continue;
1364                        }
1365
1366                        String tagName = parser.getName();
1367                        if (tagName.equals("pkg")) {
1368                            readPackage(parser);
1369                        } else if (tagName.equals("uid")) {
1370                            readUidOps(parser);
1371                        } else {
1372                            Slog.w(TAG, "Unknown element under <app-ops>: "
1373                                    + parser.getName());
1374                            XmlUtils.skipCurrentTag(parser);
1375                        }
1376                    }
1377                    success = true;
1378                } catch (IllegalStateException e) {
1379                    Slog.w(TAG, "Failed parsing " + e);
1380                } catch (NullPointerException e) {
1381                    Slog.w(TAG, "Failed parsing " + e);
1382                } catch (NumberFormatException e) {
1383                    Slog.w(TAG, "Failed parsing " + e);
1384                } catch (XmlPullParserException e) {
1385                    Slog.w(TAG, "Failed parsing " + e);
1386                } catch (IOException e) {
1387                    Slog.w(TAG, "Failed parsing " + e);
1388                } catch (IndexOutOfBoundsException e) {
1389                    Slog.w(TAG, "Failed parsing " + e);
1390                } finally {
1391                    if (!success) {
1392                        mUidStates.clear();
1393                    }
1394                    try {
1395                        stream.close();
1396                    } catch (IOException e) {
1397                    }
1398                }
1399            }
1400        }
1401    }
1402
1403    void readUidOps(XmlPullParser parser) throws NumberFormatException,
1404            XmlPullParserException, IOException {
1405        final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
1406        int outerDepth = parser.getDepth();
1407        int type;
1408        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1409                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1410            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1411                continue;
1412            }
1413
1414            String tagName = parser.getName();
1415            if (tagName.equals("op")) {
1416                final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
1417                final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
1418                UidState uidState = getUidStateLocked(uid, true);
1419                if (uidState.opModes == null) {
1420                    uidState.opModes = new SparseIntArray();
1421                }
1422                uidState.opModes.put(code, mode);
1423            } else {
1424                Slog.w(TAG, "Unknown element under <uid-ops>: "
1425                        + parser.getName());
1426                XmlUtils.skipCurrentTag(parser);
1427            }
1428        }
1429    }
1430
1431    void readPackage(XmlPullParser parser) throws NumberFormatException,
1432            XmlPullParserException, IOException {
1433        String pkgName = parser.getAttributeValue(null, "n");
1434        int outerDepth = parser.getDepth();
1435        int type;
1436        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1437                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1438            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1439                continue;
1440            }
1441
1442            String tagName = parser.getName();
1443            if (tagName.equals("uid")) {
1444                readUid(parser, pkgName);
1445            } else {
1446                Slog.w(TAG, "Unknown element under <pkg>: "
1447                        + parser.getName());
1448                XmlUtils.skipCurrentTag(parser);
1449            }
1450        }
1451    }
1452
1453    void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
1454            XmlPullParserException, IOException {
1455        int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
1456        String isPrivilegedString = parser.getAttributeValue(null, "p");
1457        boolean isPrivileged = false;
1458        if (isPrivilegedString == null) {
1459            try {
1460                IPackageManager packageManager = ActivityThread.getPackageManager();
1461                if (packageManager != null) {
1462                    ApplicationInfo appInfo = ActivityThread.getPackageManager()
1463                            .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
1464                    if (appInfo != null) {
1465                        isPrivileged = (appInfo.privateFlags
1466                                & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
1467                    }
1468                } else {
1469                    // Could not load data, don't add to cache so it will be loaded later.
1470                    return;
1471                }
1472            } catch (RemoteException e) {
1473                Slog.w(TAG, "Could not contact PackageManager", e);
1474            }
1475        } else {
1476            isPrivileged = Boolean.parseBoolean(isPrivilegedString);
1477        }
1478        int outerDepth = parser.getDepth();
1479        int type;
1480        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1481                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1482            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1483                continue;
1484            }
1485
1486            String tagName = parser.getName();
1487            if (tagName.equals("op")) {
1488                Op op = new Op(uid, pkgName, Integer.parseInt(parser.getAttributeValue(null, "n")));
1489                String mode = parser.getAttributeValue(null, "m");
1490                if (mode != null) {
1491                    op.mode = Integer.parseInt(mode);
1492                }
1493                String time = parser.getAttributeValue(null, "t");
1494                if (time != null) {
1495                    op.time = Long.parseLong(time);
1496                }
1497                time = parser.getAttributeValue(null, "r");
1498                if (time != null) {
1499                    op.rejectTime = Long.parseLong(time);
1500                }
1501                String dur = parser.getAttributeValue(null, "d");
1502                if (dur != null) {
1503                    op.duration = Integer.parseInt(dur);
1504                }
1505                String proxyUid = parser.getAttributeValue(null, "pu");
1506                if (proxyUid != null) {
1507                    op.proxyUid = Integer.parseInt(proxyUid);
1508                }
1509                String proxyPackageName = parser.getAttributeValue(null, "pp");
1510                if (proxyPackageName != null) {
1511                    op.proxyPackageName = proxyPackageName;
1512                }
1513
1514                UidState uidState = getUidStateLocked(uid, true);
1515                if (uidState.pkgOps == null) {
1516                    uidState.pkgOps = new ArrayMap<>();
1517                }
1518
1519                Ops ops = uidState.pkgOps.get(pkgName);
1520                if (ops == null) {
1521                    ops = new Ops(pkgName, uidState, isPrivileged);
1522                    uidState.pkgOps.put(pkgName, ops);
1523                }
1524                ops.put(op.op, op);
1525            } else {
1526                Slog.w(TAG, "Unknown element under <pkg>: "
1527                        + parser.getName());
1528                XmlUtils.skipCurrentTag(parser);
1529            }
1530        }
1531    }
1532
1533    void writeState() {
1534        synchronized (mFile) {
1535            List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
1536
1537            FileOutputStream stream;
1538            try {
1539                stream = mFile.startWrite();
1540            } catch (IOException e) {
1541                Slog.w(TAG, "Failed to write state: " + e);
1542                return;
1543            }
1544
1545            try {
1546                XmlSerializer out = new FastXmlSerializer();
1547                out.setOutput(stream, StandardCharsets.UTF_8.name());
1548                out.startDocument(null, true);
1549                out.startTag(null, "app-ops");
1550
1551                final int uidStateCount = mUidStates.size();
1552                for (int i = 0; i < uidStateCount; i++) {
1553                    UidState uidState = mUidStates.valueAt(i);
1554                    if (uidState.opModes != null && uidState.opModes.size() > 0) {
1555                        out.startTag(null, "uid");
1556                        out.attribute(null, "n", Integer.toString(uidState.uid));
1557                        SparseIntArray uidOpModes = uidState.opModes;
1558                        final int opCount = uidOpModes.size();
1559                        for (int j = 0; j < opCount; j++) {
1560                            final int op = uidOpModes.keyAt(j);
1561                            final int mode = uidOpModes.valueAt(j);
1562                            out.startTag(null, "op");
1563                            out.attribute(null, "n", Integer.toString(op));
1564                            out.attribute(null, "m", Integer.toString(mode));
1565                            out.endTag(null, "op");
1566                        }
1567                        out.endTag(null, "uid");
1568                    }
1569                }
1570
1571                if (allOps != null) {
1572                    String lastPkg = null;
1573                    for (int i=0; i<allOps.size(); i++) {
1574                        AppOpsManager.PackageOps pkg = allOps.get(i);
1575                        if (!pkg.getPackageName().equals(lastPkg)) {
1576                            if (lastPkg != null) {
1577                                out.endTag(null, "pkg");
1578                            }
1579                            lastPkg = pkg.getPackageName();
1580                            out.startTag(null, "pkg");
1581                            out.attribute(null, "n", lastPkg);
1582                        }
1583                        out.startTag(null, "uid");
1584                        out.attribute(null, "n", Integer.toString(pkg.getUid()));
1585                        synchronized (this) {
1586                            Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), false);
1587                            // Should always be present as the list of PackageOps is generated
1588                            // from Ops.
1589                            if (ops != null) {
1590                                out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
1591                            } else {
1592                                out.attribute(null, "p", Boolean.toString(false));
1593                            }
1594                        }
1595                        List<AppOpsManager.OpEntry> ops = pkg.getOps();
1596                        for (int j=0; j<ops.size(); j++) {
1597                            AppOpsManager.OpEntry op = ops.get(j);
1598                            out.startTag(null, "op");
1599                            out.attribute(null, "n", Integer.toString(op.getOp()));
1600                            if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
1601                                out.attribute(null, "m", Integer.toString(op.getMode()));
1602                            }
1603                            long time = op.getTime();
1604                            if (time != 0) {
1605                                out.attribute(null, "t", Long.toString(time));
1606                            }
1607                            time = op.getRejectTime();
1608                            if (time != 0) {
1609                                out.attribute(null, "r", Long.toString(time));
1610                            }
1611                            int dur = op.getDuration();
1612                            if (dur != 0) {
1613                                out.attribute(null, "d", Integer.toString(dur));
1614                            }
1615                            int proxyUid = op.getProxyUid();
1616                            if (proxyUid != -1) {
1617                                out.attribute(null, "pu", Integer.toString(proxyUid));
1618                            }
1619                            String proxyPackageName = op.getProxyPackageName();
1620                            if (proxyPackageName != null) {
1621                                out.attribute(null, "pp", proxyPackageName);
1622                            }
1623                            out.endTag(null, "op");
1624                        }
1625                        out.endTag(null, "uid");
1626                    }
1627                    if (lastPkg != null) {
1628                        out.endTag(null, "pkg");
1629                    }
1630                }
1631
1632                out.endTag(null, "app-ops");
1633                out.endDocument();
1634                mFile.finishWrite(stream);
1635            } catch (IOException e) {
1636                Slog.w(TAG, "Failed to write state, restoring backup.", e);
1637                mFile.failWrite(stream);
1638            }
1639        }
1640    }
1641
1642    static class Shell extends ShellCommand {
1643        final IAppOpsService mInterface;
1644        final AppOpsService mInternal;
1645
1646        int userId = UserHandle.USER_SYSTEM;
1647        String packageName;
1648        String opStr;
1649        String modeStr;
1650        int op;
1651        int mode;
1652        int packageUid;
1653
1654        Shell(IAppOpsService iface, AppOpsService internal) {
1655            mInterface = iface;
1656            mInternal = internal;
1657        }
1658
1659        @Override
1660        public int onCommand(String cmd) {
1661            return onShellCommand(this, cmd);
1662        }
1663
1664        @Override
1665        public void onHelp() {
1666            PrintWriter pw = getOutPrintWriter();
1667            dumpCommandHelp(pw);
1668        }
1669
1670        private int strOpToOp(String op, PrintWriter err) {
1671            try {
1672                return AppOpsManager.strOpToOp(op);
1673            } catch (IllegalArgumentException e) {
1674            }
1675            try {
1676                return Integer.parseInt(op);
1677            } catch (NumberFormatException e) {
1678            }
1679            try {
1680                return AppOpsManager.strDebugOpToOp(op);
1681            } catch (IllegalArgumentException e) {
1682                err.println("Error: " + e.getMessage());
1683                return -1;
1684            }
1685        }
1686
1687        int strModeToMode(String modeStr, PrintWriter err) {
1688            switch (modeStr) {
1689                case "allow":
1690                    return AppOpsManager.MODE_ALLOWED;
1691                case "deny":
1692                    return AppOpsManager.MODE_ERRORED;
1693                case "ignore":
1694                    return AppOpsManager.MODE_IGNORED;
1695                case "default":
1696                    return AppOpsManager.MODE_DEFAULT;
1697            }
1698            try {
1699                return Integer.parseInt(modeStr);
1700            } catch (NumberFormatException e) {
1701            }
1702            err.println("Error: Mode " + modeStr + " is not valid");
1703            return -1;
1704        }
1705
1706        int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
1707            userId = UserHandle.USER_CURRENT;
1708            opStr = null;
1709            modeStr = null;
1710            for (String argument; (argument = getNextArg()) != null;) {
1711                if ("--user".equals(argument)) {
1712                    userId = UserHandle.parseUserArg(getNextArgRequired());
1713                } else {
1714                    if (opStr == null) {
1715                        opStr = argument;
1716                    } else if (modeStr == null) {
1717                        modeStr = argument;
1718                        break;
1719                    }
1720                }
1721            }
1722            if (opStr == null) {
1723                err.println("Error: Operation not specified.");
1724                return -1;
1725            }
1726            op = strOpToOp(opStr, err);
1727            if (op < 0) {
1728                return -1;
1729            }
1730            if (modeStr != null) {
1731                if ((mode=strModeToMode(modeStr, err)) < 0) {
1732                    return -1;
1733                }
1734            } else {
1735                mode = defMode;
1736            }
1737            return 0;
1738        }
1739
1740        int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
1741            userId = UserHandle.USER_CURRENT;
1742            packageName = null;
1743            opStr = null;
1744            for (String argument; (argument = getNextArg()) != null;) {
1745                if ("--user".equals(argument)) {
1746                    userId = UserHandle.parseUserArg(getNextArgRequired());
1747                } else {
1748                    if (packageName == null) {
1749                        packageName = argument;
1750                    } else if (opStr == null) {
1751                        opStr = argument;
1752                        break;
1753                    }
1754                }
1755            }
1756            if (packageName == null) {
1757                err.println("Error: Package name not specified.");
1758                return -1;
1759            } else if (opStr == null && reqOp) {
1760                err.println("Error: Operation not specified.");
1761                return -1;
1762            }
1763            if (opStr != null) {
1764                op = strOpToOp(opStr, err);
1765                if (op < 0) {
1766                    return -1;
1767                }
1768            } else {
1769                op = AppOpsManager.OP_NONE;
1770            }
1771            if (userId == UserHandle.USER_CURRENT) {
1772                userId = ActivityManager.getCurrentUser();
1773            }
1774            if ("root".equals(packageName)) {
1775                packageUid = 0;
1776            } else {
1777                packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
1778                        PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1779            }
1780            if (packageUid < 0) {
1781                err.println("Error: No UID for " + packageName + " in user " + userId);
1782                return -1;
1783            }
1784            return 0;
1785        }
1786    }
1787
1788    @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
1789            FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
1790        (new Shell(this, this)).exec(this, in, out, err, args, resultReceiver);
1791    }
1792
1793    static void dumpCommandHelp(PrintWriter pw) {
1794        pw.println("AppOps service (appops) commands:");
1795        pw.println("  help");
1796        pw.println("    Print this help text.");
1797        pw.println("  set [--user <USER_ID>] <PACKAGE> <OP> <MODE>");
1798        pw.println("    Set the mode for a particular application and operation.");
1799        pw.println("  get [--user <USER_ID>] <PACKAGE> [<OP>]");
1800        pw.println("    Return the mode for a particular application and optional operation.");
1801        pw.println("  query-op [--user <USER_ID>] <OP> [<MODE>]");
1802        pw.println("    Print all packages that currently have the given op in the given mode.");
1803        pw.println("  reset [--user <USER_ID>] [<PACKAGE>]");
1804        pw.println("    Reset the given application or all applications to default modes.");
1805        pw.println("  write-settings");
1806        pw.println("    Immediately write pending changes to storage.");
1807        pw.println("  read-settings");
1808        pw.println("    Read the last written settings, replacing current state in RAM.");
1809        pw.println("  options:");
1810        pw.println("    <PACKAGE> an Android package name.");
1811        pw.println("    <OP>      an AppOps operation.");
1812        pw.println("    <MODE>    one of allow, ignore, deny, or default");
1813        pw.println("    <USER_ID> the user id under which the package is installed. If --user is not");
1814        pw.println("              specified, the current user is assumed.");
1815    }
1816
1817    static int onShellCommand(Shell shell, String cmd) {
1818        if (cmd == null) {
1819            return shell.handleDefaultCommands(cmd);
1820        }
1821        PrintWriter pw = shell.getOutPrintWriter();
1822        PrintWriter err = shell.getErrPrintWriter();
1823        try {
1824            switch (cmd) {
1825                case "set": {
1826                    int res = shell.parseUserPackageOp(true, err);
1827                    if (res < 0) {
1828                        return res;
1829                    }
1830                    String modeStr = shell.getNextArg();
1831                    if (modeStr == null) {
1832                        err.println("Error: Mode not specified.");
1833                        return -1;
1834                    }
1835
1836                    final int mode = shell.strModeToMode(modeStr, err);
1837                    if (mode < 0) {
1838                        return -1;
1839                    }
1840
1841                    shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName, mode);
1842                    return 0;
1843                }
1844                case "get": {
1845                    int res = shell.parseUserPackageOp(false, err);
1846                    if (res < 0) {
1847                        return res;
1848                    }
1849
1850                    List<AppOpsManager.PackageOps> ops = shell.mInterface.getOpsForPackage(
1851                            shell.packageUid, shell.packageName,
1852                            shell.op != AppOpsManager.OP_NONE ? new int[] {shell.op} : null);
1853                    if (ops == null || ops.size() <= 0) {
1854                        pw.println("No operations.");
1855                        return 0;
1856                    }
1857                    final long now = System.currentTimeMillis();
1858                    for (int i=0; i<ops.size(); i++) {
1859                        List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
1860                        for (int j=0; j<entries.size(); j++) {
1861                            AppOpsManager.OpEntry ent = entries.get(j);
1862                            pw.print(AppOpsManager.opToName(ent.getOp()));
1863                            pw.print(": ");
1864                            switch (ent.getMode()) {
1865                                case AppOpsManager.MODE_ALLOWED:
1866                                    pw.print("allow");
1867                                    break;
1868                                case AppOpsManager.MODE_IGNORED:
1869                                    pw.print("ignore");
1870                                    break;
1871                                case AppOpsManager.MODE_ERRORED:
1872                                    pw.print("deny");
1873                                    break;
1874                                case AppOpsManager.MODE_DEFAULT:
1875                                    pw.print("default");
1876                                    break;
1877                                default:
1878                                    pw.print("mode=");
1879                                    pw.print(ent.getMode());
1880                                    break;
1881                            }
1882                            if (ent.getTime() != 0) {
1883                                pw.print("; time=");
1884                                TimeUtils.formatDuration(now - ent.getTime(), pw);
1885                                pw.print(" ago");
1886                            }
1887                            if (ent.getRejectTime() != 0) {
1888                                pw.print("; rejectTime=");
1889                                TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
1890                                pw.print(" ago");
1891                            }
1892                            if (ent.getDuration() == -1) {
1893                                pw.print(" (running)");
1894                            } else if (ent.getDuration() != 0) {
1895                                pw.print("; duration=");
1896                                TimeUtils.formatDuration(ent.getDuration(), pw);
1897                            }
1898                            pw.println();
1899                        }
1900                    }
1901                    return 0;
1902                }
1903                case "query-op": {
1904                    int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
1905                    if (res < 0) {
1906                        return res;
1907                    }
1908                    List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
1909                            new int[] {shell.op});
1910                    if (ops == null || ops.size() <= 0) {
1911                        pw.println("No operations.");
1912                        return 0;
1913                    }
1914                    for (int i=0; i<ops.size(); i++) {
1915                        final AppOpsManager.PackageOps pkg = ops.get(i);
1916                        boolean hasMatch = false;
1917                        final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
1918                        for (int j=0; j<entries.size(); j++) {
1919                            AppOpsManager.OpEntry ent = entries.get(j);
1920                            if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
1921                                hasMatch = true;
1922                                break;
1923                            }
1924                        }
1925                        if (hasMatch) {
1926                            pw.println(pkg.getPackageName());
1927                        }
1928                    }
1929                    return 0;
1930                }
1931                case "reset": {
1932                    String packageName = null;
1933                    int userId = UserHandle.USER_CURRENT;
1934                    for (String argument; (argument = shell.getNextArg()) != null;) {
1935                        if ("--user".equals(argument)) {
1936                            String userStr = shell.getNextArgRequired();
1937                            userId = UserHandle.parseUserArg(userStr);
1938                        } else {
1939                            if (packageName == null) {
1940                                packageName = argument;
1941                            } else {
1942                                err.println("Error: Unsupported argument: " + argument);
1943                                return -1;
1944                            }
1945                        }
1946                    }
1947
1948                    if (userId == UserHandle.USER_CURRENT) {
1949                        userId = ActivityManager.getCurrentUser();
1950                    }
1951
1952                    shell.mInterface.resetAllModes(userId, packageName);
1953                    pw.print("Reset all modes for: ");
1954                    if (userId == UserHandle.USER_ALL) {
1955                        pw.print("all users");
1956                    } else {
1957                        pw.print("user "); pw.print(userId);
1958                    }
1959                    pw.print(", ");
1960                    if (packageName == null) {
1961                        pw.println("all packages");
1962                    } else {
1963                        pw.print("package "); pw.println(packageName);
1964                    }
1965                    return 0;
1966                }
1967                case "write-settings": {
1968                    shell.mInternal.mContext.enforcePermission(
1969                            android.Manifest.permission.UPDATE_APP_OPS_STATS,
1970                            Binder.getCallingPid(), Binder.getCallingUid(), null);
1971                    long token = Binder.clearCallingIdentity();
1972                    try {
1973                        synchronized (shell.mInternal) {
1974                            shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
1975                        }
1976                        shell.mInternal.writeState();
1977                        pw.println("Current settings written.");
1978                    } finally {
1979                        Binder.restoreCallingIdentity(token);
1980                    }
1981                    return 0;
1982                }
1983                case "read-settings": {
1984                    shell.mInternal.mContext.enforcePermission(
1985                            android.Manifest.permission.UPDATE_APP_OPS_STATS,
1986                            Binder.getCallingPid(), Binder.getCallingUid(), null);
1987                    long token = Binder.clearCallingIdentity();
1988                    try {
1989                        shell.mInternal.readState();
1990                        pw.println("Last settings read.");
1991                    } finally {
1992                        Binder.restoreCallingIdentity(token);
1993                    }
1994                    return 0;
1995                }
1996                default:
1997                    return shell.handleDefaultCommands(cmd);
1998            }
1999        } catch (RemoteException e) {
2000            pw.println("Remote exception: " + e);
2001        }
2002        return -1;
2003    }
2004
2005    private void dumpHelp(PrintWriter pw) {
2006        pw.println("AppOps service (appops) dump options:");
2007        pw.println("  none");
2008    }
2009
2010    @Override
2011    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2012        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2013                != PackageManager.PERMISSION_GRANTED) {
2014            pw.println("Permission Denial: can't dump ApOps service from from pid="
2015                    + Binder.getCallingPid()
2016                    + ", uid=" + Binder.getCallingUid());
2017            return;
2018        }
2019
2020        if (args != null) {
2021            for (int i=0; i<args.length; i++) {
2022                String arg = args[i];
2023                if ("-h".equals(arg)) {
2024                    dumpHelp(pw);
2025                    return;
2026                } else if ("-a".equals(arg)) {
2027                    // dump all data
2028                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
2029                    pw.println("Unknown option: " + arg);
2030                    return;
2031                } else {
2032                    pw.println("Unknown command: " + arg);
2033                    return;
2034                }
2035            }
2036        }
2037
2038        synchronized (this) {
2039            pw.println("Current AppOps Service state:");
2040            final long now = System.currentTimeMillis();
2041            boolean needSep = false;
2042            if (mOpModeWatchers.size() > 0) {
2043                needSep = true;
2044                pw.println("  Op mode watchers:");
2045                for (int i=0; i<mOpModeWatchers.size(); i++) {
2046                    pw.print("    Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
2047                    pw.println(":");
2048                    ArrayList<Callback> callbacks = mOpModeWatchers.valueAt(i);
2049                    for (int j=0; j<callbacks.size(); j++) {
2050                        pw.print("      #"); pw.print(j); pw.print(": ");
2051                        pw.println(callbacks.get(j));
2052                    }
2053                }
2054            }
2055            if (mPackageModeWatchers.size() > 0) {
2056                needSep = true;
2057                pw.println("  Package mode watchers:");
2058                for (int i=0; i<mPackageModeWatchers.size(); i++) {
2059                    pw.print("    Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
2060                    pw.println(":");
2061                    ArrayList<Callback> callbacks = mPackageModeWatchers.valueAt(i);
2062                    for (int j=0; j<callbacks.size(); j++) {
2063                        pw.print("      #"); pw.print(j); pw.print(": ");
2064                        pw.println(callbacks.get(j));
2065                    }
2066                }
2067            }
2068            if (mModeWatchers.size() > 0) {
2069                needSep = true;
2070                pw.println("  All mode watchers:");
2071                for (int i=0; i<mModeWatchers.size(); i++) {
2072                    pw.print("    "); pw.print(mModeWatchers.keyAt(i));
2073                    pw.print(" -> "); pw.println(mModeWatchers.valueAt(i));
2074                }
2075            }
2076            if (mClients.size() > 0) {
2077                needSep = true;
2078                pw.println("  Clients:");
2079                for (int i=0; i<mClients.size(); i++) {
2080                    pw.print("    "); pw.print(mClients.keyAt(i)); pw.println(":");
2081                    ClientState cs = mClients.valueAt(i);
2082                    pw.print("      "); pw.println(cs);
2083                    if (cs.mStartedOps != null && cs.mStartedOps.size() > 0) {
2084                        pw.println("      Started ops:");
2085                        for (int j=0; j<cs.mStartedOps.size(); j++) {
2086                            Op op = cs.mStartedOps.get(j);
2087                            pw.print("        "); pw.print("uid="); pw.print(op.uid);
2088                            pw.print(" pkg="); pw.print(op.packageName);
2089                            pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
2090                        }
2091                    }
2092                }
2093            }
2094            if (mAudioRestrictions.size() > 0) {
2095                boolean printedHeader = false;
2096                for (int o=0; o<mAudioRestrictions.size(); o++) {
2097                    final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
2098                    final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
2099                    for (int i=0; i<restrictions.size(); i++) {
2100                        if (!printedHeader){
2101                            pw.println("  Audio Restrictions:");
2102                            printedHeader = true;
2103                            needSep = true;
2104                        }
2105                        final int usage = restrictions.keyAt(i);
2106                        pw.print("    "); pw.print(op);
2107                        pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
2108                        Restriction r = restrictions.valueAt(i);
2109                        pw.print(": mode="); pw.println(r.mode);
2110                        if (!r.exceptionPackages.isEmpty()) {
2111                            pw.println("      Exceptions:");
2112                            for (int j=0; j<r.exceptionPackages.size(); j++) {
2113                                pw.print("        "); pw.println(r.exceptionPackages.valueAt(j));
2114                            }
2115                        }
2116                    }
2117                }
2118            }
2119            if (needSep) {
2120                pw.println();
2121            }
2122            for (int i=0; i<mUidStates.size(); i++) {
2123                UidState uidState = mUidStates.valueAt(i);
2124
2125                pw.print("  Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
2126
2127                SparseIntArray opModes = uidState.opModes;
2128                if (opModes != null) {
2129                    final int opModeCount = opModes.size();
2130                    for (int j = 0; j < opModeCount; j++) {
2131                        final int code = opModes.keyAt(j);
2132                        final int mode = opModes.valueAt(j);
2133                        pw.print("      "); pw.print(AppOpsManager.opToName(code));
2134                        pw.print(": mode="); pw.println(mode);
2135                    }
2136                }
2137
2138                ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
2139                if (pkgOps == null) {
2140                    continue;
2141                }
2142
2143                for (Ops ops : pkgOps.values()) {
2144                    pw.print("    Package "); pw.print(ops.packageName); pw.println(":");
2145                    for (int j=0; j<ops.size(); j++) {
2146                        Op op = ops.valueAt(j);
2147                        pw.print("      "); pw.print(AppOpsManager.opToName(op.op));
2148                        pw.print(": mode="); pw.print(op.mode);
2149                        if (op.time != 0) {
2150                            pw.print("; time="); TimeUtils.formatDuration(now-op.time, pw);
2151                            pw.print(" ago");
2152                        }
2153                        if (op.rejectTime != 0) {
2154                            pw.print("; rejectTime="); TimeUtils.formatDuration(now-op.rejectTime, pw);
2155                            pw.print(" ago");
2156                        }
2157                        if (op.duration == -1) {
2158                            pw.print(" (running)");
2159                        } else if (op.duration != 0) {
2160                            pw.print("; duration="); TimeUtils.formatDuration(op.duration, pw);
2161                        }
2162                        pw.println();
2163                    }
2164                }
2165            }
2166        }
2167    }
2168
2169    private static final class Restriction {
2170        private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
2171        int mode;
2172        ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
2173    }
2174
2175    @Override
2176    public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
2177        checkSystemUid("setUserRestrictions");
2178        Preconditions.checkNotNull(restrictions);
2179        Preconditions.checkNotNull(token);
2180        for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
2181            String restriction = AppOpsManager.opToRestriction(i);
2182            if (restriction != null && restrictions.getBoolean(restriction, false)) {
2183                setUserRestrictionNoCheck(i, true, token, userHandle, null);
2184            }
2185        }
2186    }
2187
2188    @Override
2189    public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
2190            String[] exceptionPackages) {
2191        if (Binder.getCallingPid() != Process.myPid()) {
2192            mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
2193                    Binder.getCallingPid(), Binder.getCallingUid(), null);
2194        }
2195        if (userHandle != UserHandle.getCallingUserId()) {
2196            if (mContext.checkCallingOrSelfPermission(Manifest.permission
2197                    .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
2198                && mContext.checkCallingOrSelfPermission(Manifest.permission
2199                    .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
2200                throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
2201                        + " INTERACT_ACROSS_USERS to interact cross user ");
2202            }
2203        }
2204        verifyIncomingOp(code);
2205        Preconditions.checkNotNull(token);
2206        setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
2207    }
2208
2209    private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
2210            int userHandle, String[] exceptionPackages) {
2211        ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
2212
2213        if (restrictionState == null) {
2214            try {
2215                restrictionState = new ClientRestrictionState(token);
2216            } catch (RemoteException e) {
2217                return;
2218            }
2219            mOpUserRestrictions.put(token, restrictionState);
2220        }
2221
2222        if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
2223            notifyWatchersOfChange(code);
2224        }
2225
2226        if (restrictionState.isDefault()) {
2227            mOpUserRestrictions.remove(token);
2228            restrictionState.destroy();
2229        }
2230    }
2231
2232    private void notifyWatchersOfChange(int code) {
2233        final ArrayList<Callback> clonedCallbacks;
2234        synchronized (this) {
2235            ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
2236            if (callbacks == null) {
2237                return;
2238            }
2239            clonedCallbacks = new ArrayList<>(callbacks);
2240        }
2241
2242        // There are components watching for mode changes such as window manager
2243        // and location manager which are in our process. The callbacks in these
2244        // components may require permissions our remote caller does not have.s
2245        final long identity = Binder.clearCallingIdentity();
2246        try {
2247            final int callbackCount = clonedCallbacks.size();
2248            for (int i = 0; i < callbackCount; i++) {
2249                Callback callback = clonedCallbacks.get(i);
2250                try {
2251                    callback.mCallback.opChanged(code, -1, null);
2252                } catch (RemoteException e) {
2253                    Log.w(TAG, "Error dispatching op op change", e);
2254                }
2255            }
2256        } finally {
2257            Binder.restoreCallingIdentity(identity);
2258        }
2259    }
2260
2261    @Override
2262    public void removeUser(int userHandle) throws RemoteException {
2263        checkSystemUid("removeUser");
2264        final int tokenCount = mOpUserRestrictions.size();
2265        for (int i = tokenCount - 1; i >= 0; i--) {
2266            ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
2267            opRestrictions.removeUser(userHandle);
2268        }
2269    }
2270
2271    private void checkSystemUid(String function) {
2272        int uid = Binder.getCallingUid();
2273        if (uid != Process.SYSTEM_UID) {
2274            throw new SecurityException(function + " must by called by the system");
2275        }
2276    }
2277
2278    private static String resolvePackageName(int uid, String packageName)  {
2279        if (uid == 0) {
2280            return "root";
2281        } else if (uid == Process.SHELL_UID) {
2282            return "com.android.shell";
2283        } else if (uid == Process.SYSTEM_UID && packageName == null) {
2284            return "android";
2285        }
2286        return packageName;
2287    }
2288
2289    private static String[] getPackagesForUid(int uid) {
2290        String[] packageNames = null;
2291        try {
2292            packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
2293        } catch (RemoteException e) {
2294            /* ignore - local call */
2295        }
2296        if (packageNames == null) {
2297            return EmptyArray.STRING;
2298        }
2299        return packageNames;
2300    }
2301
2302    private final class ClientRestrictionState implements DeathRecipient {
2303        private final IBinder token;
2304        SparseArray<boolean[]> perUserRestrictions;
2305        SparseArray<String[]> perUserExcludedPackages;
2306
2307        public ClientRestrictionState(IBinder token)
2308                throws RemoteException {
2309            token.linkToDeath(this, 0);
2310            this.token = token;
2311        }
2312
2313        public boolean setRestriction(int code, boolean restricted,
2314                String[] excludedPackages, int userId) {
2315            boolean changed = false;
2316
2317            if (perUserRestrictions == null && restricted) {
2318                perUserRestrictions = new SparseArray<>();
2319            }
2320
2321            if (perUserRestrictions != null) {
2322                boolean[] userRestrictions = perUserRestrictions.get(userId);
2323                if (userRestrictions == null && restricted) {
2324                    userRestrictions = new boolean[AppOpsManager._NUM_OP];
2325                    perUserRestrictions.put(userId, userRestrictions);
2326                }
2327                if (userRestrictions != null && userRestrictions[code] != restricted) {
2328                    userRestrictions[code] = restricted;
2329                    if (!restricted && isDefault(userRestrictions)) {
2330                        perUserRestrictions.remove(userId);
2331                        userRestrictions = null;
2332                    }
2333                    changed = true;
2334                }
2335
2336                if (userRestrictions != null) {
2337                    final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
2338                    if (perUserExcludedPackages == null && !noExcludedPackages) {
2339                        perUserExcludedPackages = new SparseArray<>();
2340                    }
2341                    if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
2342                            perUserExcludedPackages.get(userId))) {
2343                        if (noExcludedPackages) {
2344                            perUserExcludedPackages.remove(userId);
2345                            if (perUserExcludedPackages.size() <= 0) {
2346                                perUserExcludedPackages = null;
2347                            }
2348                        } else {
2349                            perUserExcludedPackages.put(userId, excludedPackages);
2350                        }
2351                        changed = true;
2352                    }
2353                }
2354            }
2355
2356            return changed;
2357        }
2358
2359        public boolean hasRestriction(int restriction, String packageName, int userId) {
2360            if (perUserRestrictions == null) {
2361                return false;
2362            }
2363            boolean[] restrictions = perUserRestrictions.get(userId);
2364            if (restrictions == null) {
2365                return false;
2366            }
2367            if (!restrictions[restriction]) {
2368                return false;
2369            }
2370            if (perUserExcludedPackages == null) {
2371                return true;
2372            }
2373            String[] perUserExclusions = perUserExcludedPackages.get(userId);
2374            if (perUserExclusions == null) {
2375                return true;
2376            }
2377            return !ArrayUtils.contains(perUserExclusions, packageName);
2378        }
2379
2380        public void removeUser(int userId) {
2381            if (perUserExcludedPackages != null) {
2382                perUserExcludedPackages.remove(userId);
2383                if (perUserExcludedPackages.size() <= 0) {
2384                    perUserExcludedPackages = null;
2385                }
2386            }
2387        }
2388
2389        public boolean isDefault() {
2390            return perUserRestrictions == null || perUserRestrictions.size() <= 0;
2391        }
2392
2393        @Override
2394        public void binderDied() {
2395            synchronized (AppOpsService.this) {
2396                mOpUserRestrictions.remove(token);
2397                if (perUserRestrictions == null) {
2398                    return;
2399                }
2400                final int userCount = perUserRestrictions.size();
2401                for (int i = 0; i < userCount; i++) {
2402                    final boolean[] restrictions = perUserRestrictions.valueAt(i);
2403                    final int restrictionCount = restrictions.length;
2404                    for (int j = 0; j < restrictionCount; j++) {
2405                        if (restrictions[j]) {
2406                            final int changedCode = j;
2407                            mHandler.post(() -> notifyWatchersOfChange(changedCode));
2408                        }
2409                    }
2410                }
2411                destroy();
2412            }
2413        }
2414
2415        public void destroy() {
2416            token.unlinkToDeath(this, 0);
2417        }
2418
2419        private boolean isDefault(boolean[] array) {
2420            if (ArrayUtils.isEmpty(array)) {
2421                return true;
2422            }
2423            for (boolean value : array) {
2424                if (value) {
2425                    return false;
2426                }
2427            }
2428            return true;
2429        }
2430    }
2431}
2432