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