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