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