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.Collections;
29import java.util.HashMap;
30import java.util.Iterator;
31import java.util.List;
32import java.util.Map;
33
34import android.app.ActivityManager;
35import android.app.ActivityThread;
36import android.app.AppGlobals;
37import android.app.AppOpsManager;
38import android.content.Context;
39import android.content.pm.ApplicationInfo;
40import android.content.pm.IPackageManager;
41import android.content.pm.PackageManager;
42import android.media.AudioAttributes;
43import android.os.AsyncTask;
44import android.os.Binder;
45import android.os.Bundle;
46import android.os.Handler;
47import android.os.IBinder;
48import android.os.Process;
49import android.os.RemoteException;
50import android.os.ServiceManager;
51import android.os.UserHandle;
52import android.os.storage.MountServiceInternal;
53import android.util.ArrayMap;
54import android.util.ArraySet;
55import android.util.AtomicFile;
56import android.util.Log;
57import android.util.Pair;
58import android.util.Slog;
59import android.util.SparseArray;
60import android.util.SparseIntArray;
61import android.util.TimeUtils;
62import android.util.Xml;
63
64import com.android.internal.app.IAppOpsService;
65import com.android.internal.app.IAppOpsCallback;
66import com.android.internal.os.Zygote;
67import com.android.internal.util.ArrayUtils;
68import com.android.internal.util.FastXmlSerializer;
69import com.android.internal.util.XmlUtils;
70
71import libcore.util.EmptyArray;
72import org.xmlpull.v1.XmlPullParser;
73import org.xmlpull.v1.XmlPullParserException;
74import org.xmlpull.v1.XmlSerializer;
75
76public class AppOpsService extends IAppOpsService.Stub {
77    static final String TAG = "AppOps";
78    static final boolean DEBUG = false;
79
80    // Write at most every 30 minutes.
81    static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
82
83    Context mContext;
84    final AtomicFile mFile;
85    final Handler mHandler;
86
87    boolean mWriteScheduled;
88    boolean mFastWriteScheduled;
89    final Runnable mWriteRunner = new Runnable() {
90        public void run() {
91            synchronized (AppOpsService.this) {
92                mWriteScheduled = false;
93                mFastWriteScheduled = false;
94                AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
95                    @Override protected Void doInBackground(Void... params) {
96                        writeState();
97                        return null;
98                    }
99                };
100                task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
101            }
102        }
103    };
104
105    final SparseArray<UidState> mUidStates = new SparseArray<>();
106
107    private final SparseArray<boolean[]> mOpRestrictions = new SparseArray<boolean[]>();
108
109    private static final class UidState {
110        public final int uid;
111        public ArrayMap<String, Ops> pkgOps;
112        public SparseIntArray opModes;
113
114        public UidState(int uid) {
115            this.uid = uid;
116        }
117
118        public void clear() {
119            pkgOps = null;
120            opModes = null;
121        }
122
123        public boolean isDefault() {
124            return (pkgOps == null || pkgOps.isEmpty())
125                    && (opModes == null || opModes.size() <= 0);
126        }
127    }
128
129    public final static class Ops extends SparseArray<Op> {
130        public final String packageName;
131        public final UidState uidState;
132        public final boolean isPrivileged;
133
134        public Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
135            packageName = _packageName;
136            uidState = _uidState;
137            isPrivileged = _isPrivileged;
138        }
139    }
140
141    public final static class Op {
142        public final int uid;
143        public final String packageName;
144        public int proxyUid = -1;
145        public String proxyPackageName;
146        public final int op;
147        public int mode;
148        public int duration;
149        public long time;
150        public long rejectTime;
151        public int nesting;
152
153        public Op(int _uid, String _packageName, int _op) {
154            uid = _uid;
155            packageName = _packageName;
156            op = _op;
157            mode = AppOpsManager.opToDefaultMode(op);
158        }
159    }
160
161    final SparseArray<ArrayList<Callback>> mOpModeWatchers
162            = new SparseArray<ArrayList<Callback>>();
163    final ArrayMap<String, ArrayList<Callback>> mPackageModeWatchers
164            = new ArrayMap<String, ArrayList<Callback>>();
165    final ArrayMap<IBinder, Callback> mModeWatchers
166            = new ArrayMap<IBinder, Callback>();
167    final SparseArray<SparseArray<Restriction>> mAudioRestrictions
168            = new SparseArray<SparseArray<Restriction>>();
169
170    public final class Callback implements DeathRecipient {
171        final IAppOpsCallback mCallback;
172
173        public Callback(IAppOpsCallback callback) {
174            mCallback = callback;
175            try {
176                mCallback.asBinder().linkToDeath(this, 0);
177            } catch (RemoteException e) {
178            }
179        }
180
181        public void unlinkToDeath() {
182            mCallback.asBinder().unlinkToDeath(this, 0);
183        }
184
185        @Override
186        public void binderDied() {
187            stopWatchingMode(mCallback);
188        }
189    }
190
191    final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<IBinder, ClientState>();
192
193    public final class ClientState extends Binder implements DeathRecipient {
194        final IBinder mAppToken;
195        final int mPid;
196        final ArrayList<Op> mStartedOps;
197
198        public ClientState(IBinder appToken) {
199            mAppToken = appToken;
200            mPid = Binder.getCallingPid();
201            if (appToken instanceof Binder) {
202                // For local clients, there is no reason to track them.
203                mStartedOps = null;
204            } else {
205                mStartedOps = new ArrayList<Op>();
206                try {
207                    mAppToken.linkToDeath(this, 0);
208                } catch (RemoteException e) {
209                }
210            }
211        }
212
213        @Override
214        public String toString() {
215            return "ClientState{" +
216                    "mAppToken=" + mAppToken +
217                    ", " + (mStartedOps != null ? ("pid=" + mPid) : "local") +
218                    '}';
219        }
220
221        @Override
222        public void binderDied() {
223            synchronized (AppOpsService.this) {
224                for (int i=mStartedOps.size()-1; i>=0; i--) {
225                    finishOperationLocked(mStartedOps.get(i));
226                }
227                mClients.remove(mAppToken);
228            }
229        }
230    }
231
232    public AppOpsService(File storagePath, Handler handler) {
233        mFile = new AtomicFile(storagePath);
234        mHandler = handler;
235        readState();
236    }
237
238    public void publish(Context context) {
239        mContext = context;
240        ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
241    }
242
243    public void systemReady() {
244        synchronized (this) {
245            boolean changed = false;
246            for (int i = mUidStates.size() - 1; i >= 0; i--) {
247                UidState uidState = mUidStates.valueAt(i);
248
249                String[] packageNames = getPackagesForUid(uidState.uid);
250                if (ArrayUtils.isEmpty(packageNames)) {
251                    uidState.clear();
252                    mUidStates.removeAt(i);
253                    changed = true;
254                    continue;
255                }
256
257                ArrayMap<String, Ops> pkgs = uidState.pkgOps;
258                if (pkgs == null) {
259                    continue;
260                }
261
262                Iterator<Ops> it = pkgs.values().iterator();
263                while (it.hasNext()) {
264                    Ops ops = it.next();
265                    int curUid = -1;
266                    try {
267                        curUid = AppGlobals.getPackageManager().getPackageUidEtc(ops.packageName,
268                                PackageManager.GET_UNINSTALLED_PACKAGES,
269                                UserHandle.getUserId(ops.uidState.uid));
270                    } catch (RemoteException ignored) {
271                    }
272                    if (curUid != ops.uidState.uid) {
273                        Slog.i(TAG, "Pruning old package " + ops.packageName
274                                + "/" + ops.uidState + ": new uid=" + curUid);
275                        it.remove();
276                        changed = true;
277                    }
278                }
279
280                if (uidState.isDefault()) {
281                    mUidStates.removeAt(i);
282                }
283            }
284            if (changed) {
285                scheduleFastWriteLocked();
286            }
287        }
288
289        MountServiceInternal mountServiceInternal = LocalServices.getService(
290                MountServiceInternal.class);
291        mountServiceInternal.addExternalStoragePolicy(
292                new MountServiceInternal.ExternalStorageMountPolicy() {
293                    @Override
294                    public int getMountMode(int uid, String packageName) {
295                        if (Process.isIsolated(uid)) {
296                            return Zygote.MOUNT_EXTERNAL_NONE;
297                        }
298                        if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
299                                packageName) != AppOpsManager.MODE_ALLOWED) {
300                            return Zygote.MOUNT_EXTERNAL_NONE;
301                        }
302                        if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
303                                packageName) != AppOpsManager.MODE_ALLOWED) {
304                            return Zygote.MOUNT_EXTERNAL_READ;
305                        }
306                        return Zygote.MOUNT_EXTERNAL_WRITE;
307                    }
308
309                    @Override
310                    public boolean hasExternalStorage(int uid, String packageName) {
311                        final int mountMode = getMountMode(uid, packageName);
312                        return mountMode == Zygote.MOUNT_EXTERNAL_READ
313                                || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
314                    }
315                });
316    }
317
318    public void packageRemoved(int uid, String packageName) {
319        synchronized (this) {
320            UidState uidState = mUidStates.get(uid);
321            if (uidState == null) {
322                return;
323            }
324
325            boolean changed = false;
326
327            // Remove any package state if such.
328            if (uidState.pkgOps != null && uidState.pkgOps.remove(packageName) != null) {
329                changed = true;
330            }
331
332            // If we just nuked the last package state check if the UID is valid.
333            if (changed && uidState.pkgOps.isEmpty()
334                    && getPackagesForUid(uid).length <= 0) {
335                mUidStates.remove(uid);
336            }
337
338            if (changed) {
339                scheduleFastWriteLocked();
340            }
341        }
342    }
343
344    public void uidRemoved(int uid) {
345        synchronized (this) {
346            if (mUidStates.indexOfKey(uid) >= 0) {
347                mUidStates.remove(uid);
348                scheduleFastWriteLocked();
349            }
350        }
351    }
352
353    public void shutdown() {
354        Slog.w(TAG, "Writing app ops before shutdown...");
355        boolean doWrite = false;
356        synchronized (this) {
357            if (mWriteScheduled) {
358                mWriteScheduled = false;
359                doWrite = true;
360            }
361        }
362        if (doWrite) {
363            writeState();
364        }
365    }
366
367    private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
368        ArrayList<AppOpsManager.OpEntry> resOps = null;
369        if (ops == null) {
370            resOps = new ArrayList<AppOpsManager.OpEntry>();
371            for (int j=0; j<pkgOps.size(); j++) {
372                Op curOp = pkgOps.valueAt(j);
373                resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
374                        curOp.rejectTime, curOp.duration, curOp.proxyUid,
375                        curOp.proxyPackageName));
376            }
377        } else {
378            for (int j=0; j<ops.length; j++) {
379                Op curOp = pkgOps.get(ops[j]);
380                if (curOp != null) {
381                    if (resOps == null) {
382                        resOps = new ArrayList<AppOpsManager.OpEntry>();
383                    }
384                    resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
385                            curOp.rejectTime, curOp.duration, curOp.proxyUid,
386                            curOp.proxyPackageName));
387                }
388            }
389        }
390        return resOps;
391    }
392
393    @Override
394    public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
395        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
396                Binder.getCallingPid(), Binder.getCallingUid(), null);
397        ArrayList<AppOpsManager.PackageOps> res = null;
398        synchronized (this) {
399            final int uidStateCount = mUidStates.size();
400            for (int i = 0; i < uidStateCount; i++) {
401                UidState uidState = mUidStates.valueAt(i);
402                if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
403                    continue;
404                }
405                ArrayMap<String, Ops> packages = uidState.pkgOps;
406                final int packageCount = packages.size();
407                for (int j = 0; j < packageCount; j++) {
408                    Ops pkgOps = packages.valueAt(j);
409                    ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
410                    if (resOps != null) {
411                        if (res == null) {
412                            res = new ArrayList<AppOpsManager.PackageOps>();
413                        }
414                        AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
415                                pkgOps.packageName, pkgOps.uidState.uid, resOps);
416                        res.add(resPackage);
417                    }
418                }
419            }
420        }
421        return res;
422    }
423
424    @Override
425    public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
426            int[] ops) {
427        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
428                Binder.getCallingPid(), Binder.getCallingUid(), null);
429        synchronized (this) {
430            Ops pkgOps = getOpsLocked(uid, packageName, false);
431            if (pkgOps == null) {
432                return null;
433            }
434            ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
435            if (resOps == null) {
436                return null;
437            }
438            ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
439            AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
440                    pkgOps.packageName, pkgOps.uidState.uid, resOps);
441            res.add(resPackage);
442            return res;
443        }
444    }
445
446    private void pruneOp(Op op, int uid, String packageName) {
447        if (op.time == 0 && op.rejectTime == 0) {
448            Ops ops = getOpsLocked(uid, packageName, false);
449            if (ops != null) {
450                ops.remove(op.op);
451                if (ops.size() <= 0) {
452                    UidState uidState = ops.uidState;
453                    ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
454                    if (pkgOps != null) {
455                        pkgOps.remove(ops.packageName);
456                        if (pkgOps.isEmpty()) {
457                            uidState.pkgOps = null;
458                        }
459                        if (uidState.isDefault()) {
460                            mUidStates.remove(uid);
461                        }
462                    }
463                }
464            }
465        }
466    }
467
468    @Override
469    public void setUidMode(int code, int uid, int mode) {
470        if (Binder.getCallingPid() != Process.myPid()) {
471            mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
472                    Binder.getCallingPid(), Binder.getCallingUid(), null);
473        }
474        verifyIncomingOp(code);
475        code = AppOpsManager.opToSwitch(code);
476
477        synchronized (this) {
478            final int defaultMode = AppOpsManager.opToDefaultMode(code);
479
480            UidState uidState = getUidStateLocked(uid, false);
481            if (uidState == null) {
482                if (mode == defaultMode) {
483                    return;
484                }
485                uidState = new UidState(uid);
486                uidState.opModes = new SparseIntArray();
487                uidState.opModes.put(code, mode);
488                mUidStates.put(uid, uidState);
489                scheduleWriteLocked();
490            } else if (uidState.opModes == null) {
491                if (mode != defaultMode) {
492                    uidState.opModes = new SparseIntArray();
493                    uidState.opModes.put(code, mode);
494                    scheduleWriteLocked();
495                }
496            } else {
497                if (uidState.opModes.get(code) == mode) {
498                    return;
499                }
500                if (mode == defaultMode) {
501                    uidState.opModes.delete(code);
502                    if (uidState.opModes.size() <= 0) {
503                        uidState.opModes = null;
504                    }
505                } else {
506                    uidState.opModes.put(code, mode);
507                }
508                scheduleWriteLocked();
509            }
510        }
511
512        String[] uidPackageNames = getPackagesForUid(uid);
513        ArrayMap<Callback, ArraySet<String>> callbackSpecs = null;
514
515        ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
516        if (callbacks != null) {
517            final int callbackCount = callbacks.size();
518            for (int i = 0; i < callbackCount; i++) {
519                Callback callback = callbacks.get(i);
520                ArraySet<String> changedPackages = new ArraySet<>();
521                Collections.addAll(changedPackages, uidPackageNames);
522                callbackSpecs = new ArrayMap<>();
523                callbackSpecs.put(callback, changedPackages);
524            }
525        }
526
527        for (String uidPackageName : uidPackageNames) {
528            callbacks = mPackageModeWatchers.get(uidPackageName);
529            if (callbacks != null) {
530                if (callbackSpecs == null) {
531                    callbackSpecs = new ArrayMap<>();
532                }
533                final int callbackCount = callbacks.size();
534                for (int i = 0; i < callbackCount; i++) {
535                    Callback callback = callbacks.get(i);
536                    ArraySet<String> changedPackages = callbackSpecs.get(callback);
537                    if (changedPackages == null) {
538                        changedPackages = new ArraySet<>();
539                        callbackSpecs.put(callback, changedPackages);
540                    }
541                    changedPackages.add(uidPackageName);
542                }
543            }
544        }
545
546        if (callbackSpecs == null) {
547            return;
548        }
549
550        // There are components watching for mode changes such as window manager
551        // and location manager which are in our process. The callbacks in these
552        // components may require permissions our remote caller does not have.
553        final long identity = Binder.clearCallingIdentity();
554        try {
555            for (int i = 0; i < callbackSpecs.size(); i++) {
556                Callback callback = callbackSpecs.keyAt(i);
557                ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
558                try {
559                    if (reportedPackageNames == null) {
560                        callback.mCallback.opChanged(code, null);
561                    } else {
562                        final int reportedPackageCount = reportedPackageNames.size();
563                        for (int j = 0; j < reportedPackageCount; j++) {
564                            String reportedPackageName = reportedPackageNames.valueAt(j);
565                            callback.mCallback.opChanged(code, reportedPackageName);
566                        }
567                    }
568                } catch (RemoteException e) {
569                    Log.w(TAG, "Error dispatching op op change", e);
570                }
571            }
572        } finally {
573            Binder.restoreCallingIdentity(identity);
574        }
575    }
576
577    @Override
578    public void setMode(int code, int uid, String packageName, int mode) {
579        if (Binder.getCallingPid() != Process.myPid()) {
580            mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
581                    Binder.getCallingPid(), Binder.getCallingUid(), null);
582        }
583        verifyIncomingOp(code);
584        ArrayList<Callback> repCbs = null;
585        code = AppOpsManager.opToSwitch(code);
586        synchronized (this) {
587            UidState uidState = getUidStateLocked(uid, false);
588            Op op = getOpLocked(code, uid, packageName, true);
589            if (op != null) {
590                if (op.mode != mode) {
591                    op.mode = mode;
592                    ArrayList<Callback> cbs = mOpModeWatchers.get(code);
593                    if (cbs != null) {
594                        if (repCbs == null) {
595                            repCbs = new ArrayList<Callback>();
596                        }
597                        repCbs.addAll(cbs);
598                    }
599                    cbs = mPackageModeWatchers.get(packageName);
600                    if (cbs != null) {
601                        if (repCbs == null) {
602                            repCbs = new ArrayList<Callback>();
603                        }
604                        repCbs.addAll(cbs);
605                    }
606                    if (mode == AppOpsManager.opToDefaultMode(op.op)) {
607                        // If going into the default mode, prune this op
608                        // if there is nothing else interesting in it.
609                        pruneOp(op, uid, packageName);
610                    }
611                    scheduleFastWriteLocked();
612                }
613            }
614        }
615        if (repCbs != null) {
616            // There are components watching for mode changes such as window manager
617            // and location manager which are in our process. The callbacks in these
618            // components may require permissions our remote caller does not have.
619            final long identity = Binder.clearCallingIdentity();
620            try {
621                for (int i = 0; i < repCbs.size(); i++) {
622                    try {
623                        repCbs.get(i).mCallback.opChanged(code, packageName);
624                    } catch (RemoteException e) {
625                    }
626                }
627            } finally {
628                Binder.restoreCallingIdentity(identity);
629            }
630        }
631    }
632
633    private static HashMap<Callback, ArrayList<Pair<String, Integer>>> addCallbacks(
634            HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks,
635            String packageName, int op, ArrayList<Callback> cbs) {
636        if (cbs == null) {
637            return callbacks;
638        }
639        if (callbacks == null) {
640            callbacks = new HashMap<Callback, ArrayList<Pair<String, Integer>>>();
641        }
642        boolean duplicate = false;
643        for (int i=0; i<cbs.size(); i++) {
644            Callback cb = cbs.get(i);
645            ArrayList<Pair<String, Integer>> reports = callbacks.get(cb);
646            if (reports == null) {
647                reports = new ArrayList<Pair<String, Integer>>();
648                callbacks.put(cb, reports);
649            } else {
650                final int reportCount = reports.size();
651                for (int j = 0; j < reportCount; j++) {
652                    Pair<String, Integer> report = reports.get(j);
653                    if (report.second == op && report.first.equals(packageName)) {
654                        duplicate = true;
655                        break;
656                    }
657                }
658            }
659            if (!duplicate) {
660                reports.add(new Pair<>(packageName, op));
661            }
662        }
663        return callbacks;
664    }
665
666    @Override
667    public void resetAllModes(int reqUserId, String reqPackageName) {
668        final int callingPid = Binder.getCallingPid();
669        final int callingUid = Binder.getCallingUid();
670        mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
671                callingPid, callingUid, null);
672        reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
673                true, true, "resetAllModes", null);
674
675        int reqUid = -1;
676        if (reqPackageName != null) {
677            try {
678                reqUid = AppGlobals.getPackageManager().getPackageUid(
679                        reqPackageName, reqUserId);
680            } catch (RemoteException e) {
681                /* ignore - local call */
682            }
683        }
684
685        HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks = null;
686        synchronized (this) {
687            boolean changed = false;
688            for (int i = mUidStates.size() - 1; i >= 0; i--) {
689                UidState uidState = mUidStates.valueAt(i);
690
691                SparseIntArray opModes = uidState.opModes;
692                if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
693                    final int uidOpCount = opModes.size();
694                    for (int j = uidOpCount - 1; j >= 0; j--) {
695                        final int code = opModes.keyAt(j);
696                        if (AppOpsManager.opAllowsReset(code)) {
697                            opModes.removeAt(j);
698                            if (opModes.size() <= 0) {
699                                uidState.opModes = null;
700                            }
701                            for (String packageName : getPackagesForUid(uidState.uid)) {
702                                callbacks = addCallbacks(callbacks, packageName, code,
703                                        mOpModeWatchers.get(code));
704                                callbacks = addCallbacks(callbacks, packageName, code,
705                                        mPackageModeWatchers.get(packageName));
706                            }
707                        }
708                    }
709                }
710
711                if (uidState.pkgOps == null) {
712                    continue;
713                }
714
715                if (reqUserId != UserHandle.USER_ALL
716                        && reqUserId != UserHandle.getUserId(uidState.uid)) {
717                    // Skip any ops for a different user
718                    continue;
719                }
720
721                Map<String, Ops> packages = uidState.pkgOps;
722                Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
723                while (it.hasNext()) {
724                    Map.Entry<String, Ops> ent = it.next();
725                    String packageName = ent.getKey();
726                    if (reqPackageName != null && !reqPackageName.equals(packageName)) {
727                        // Skip any ops for a different package
728                        continue;
729                    }
730                    Ops pkgOps = ent.getValue();
731                    for (int j=pkgOps.size()-1; j>=0; j--) {
732                        Op curOp = pkgOps.valueAt(j);
733                        if (AppOpsManager.opAllowsReset(curOp.op)
734                                && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
735                            curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
736                            changed = true;
737                            callbacks = addCallbacks(callbacks, packageName, curOp.op,
738                                    mOpModeWatchers.get(curOp.op));
739                            callbacks = addCallbacks(callbacks, packageName, curOp.op,
740                                    mPackageModeWatchers.get(packageName));
741                            if (curOp.time == 0 && curOp.rejectTime == 0) {
742                                pkgOps.removeAt(j);
743                            }
744                        }
745                    }
746                    if (pkgOps.size() == 0) {
747                        it.remove();
748                    }
749                }
750                if (uidState.isDefault()) {
751                    mUidStates.remove(uidState.uid);
752                }
753            }
754
755            if (changed) {
756                scheduleFastWriteLocked();
757            }
758        }
759        if (callbacks != null) {
760            for (Map.Entry<Callback, ArrayList<Pair<String, Integer>>> ent : callbacks.entrySet()) {
761                Callback cb = ent.getKey();
762                ArrayList<Pair<String, Integer>> reports = ent.getValue();
763                for (int i=0; i<reports.size(); i++) {
764                    Pair<String, Integer> rep = reports.get(i);
765                    try {
766                        cb.mCallback.opChanged(rep.second, rep.first);
767                    } catch (RemoteException e) {
768                    }
769                }
770            }
771        }
772    }
773
774    @Override
775    public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
776        synchronized (this) {
777            op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
778            Callback cb = mModeWatchers.get(callback.asBinder());
779            if (cb == null) {
780                cb = new Callback(callback);
781                mModeWatchers.put(callback.asBinder(), cb);
782            }
783            if (op != AppOpsManager.OP_NONE) {
784                ArrayList<Callback> cbs = mOpModeWatchers.get(op);
785                if (cbs == null) {
786                    cbs = new ArrayList<Callback>();
787                    mOpModeWatchers.put(op, cbs);
788                }
789                cbs.add(cb);
790            }
791            if (packageName != null) {
792                ArrayList<Callback> cbs = mPackageModeWatchers.get(packageName);
793                if (cbs == null) {
794                    cbs = new ArrayList<Callback>();
795                    mPackageModeWatchers.put(packageName, cbs);
796                }
797                cbs.add(cb);
798            }
799        }
800    }
801
802    @Override
803    public void stopWatchingMode(IAppOpsCallback callback) {
804        synchronized (this) {
805            Callback cb = mModeWatchers.remove(callback.asBinder());
806            if (cb != null) {
807                cb.unlinkToDeath();
808                for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
809                    ArrayList<Callback> cbs = mOpModeWatchers.valueAt(i);
810                    cbs.remove(cb);
811                    if (cbs.size() <= 0) {
812                        mOpModeWatchers.removeAt(i);
813                    }
814                }
815                for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
816                    ArrayList<Callback> cbs = mPackageModeWatchers.valueAt(i);
817                    cbs.remove(cb);
818                    if (cbs.size() <= 0) {
819                        mPackageModeWatchers.removeAt(i);
820                    }
821                }
822            }
823        }
824    }
825
826    @Override
827    public IBinder getToken(IBinder clientToken) {
828        synchronized (this) {
829            ClientState cs = mClients.get(clientToken);
830            if (cs == null) {
831                cs = new ClientState(clientToken);
832                mClients.put(clientToken, cs);
833            }
834            return cs;
835        }
836    }
837
838    @Override
839    public int checkOperation(int code, int uid, String packageName) {
840        verifyIncomingUid(uid);
841        verifyIncomingOp(code);
842        synchronized (this) {
843            if (isOpRestricted(uid, code, packageName)) {
844                return AppOpsManager.MODE_IGNORED;
845            }
846            code = AppOpsManager.opToSwitch(code);
847            UidState uidState = getUidStateLocked(uid, false);
848            if (uidState != null && uidState.opModes != null) {
849                final int uidMode = uidState.opModes.get(code);
850                if (uidMode != AppOpsManager.MODE_ALLOWED) {
851                    return uidMode;
852                }
853            }
854            Op op = getOpLocked(code, uid, packageName, false);
855            if (op == null) {
856                return AppOpsManager.opToDefaultMode(code);
857            }
858            return op.mode;
859        }
860    }
861
862    @Override
863    public int checkAudioOperation(int code, int usage, int uid, String packageName) {
864        synchronized (this) {
865            final int mode = checkRestrictionLocked(code, usage, uid, packageName);
866            if (mode != AppOpsManager.MODE_ALLOWED) {
867                return mode;
868            }
869        }
870        return checkOperation(code, uid, packageName);
871    }
872
873    private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
874        final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
875        if (usageRestrictions != null) {
876            final Restriction r = usageRestrictions.get(usage);
877            if (r != null && !r.exceptionPackages.contains(packageName)) {
878                return r.mode;
879            }
880        }
881        return AppOpsManager.MODE_ALLOWED;
882    }
883
884    @Override
885    public void setAudioRestriction(int code, int usage, int uid, int mode,
886            String[] exceptionPackages) {
887        verifyIncomingUid(uid);
888        verifyIncomingOp(code);
889        synchronized (this) {
890            SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
891            if (usageRestrictions == null) {
892                usageRestrictions = new SparseArray<Restriction>();
893                mAudioRestrictions.put(code, usageRestrictions);
894            }
895            usageRestrictions.remove(usage);
896            if (mode != AppOpsManager.MODE_ALLOWED) {
897                final Restriction r = new Restriction();
898                r.mode = mode;
899                if (exceptionPackages != null) {
900                    final int N = exceptionPackages.length;
901                    r.exceptionPackages = new ArraySet<String>(N);
902                    for (int i = 0; i < N; i++) {
903                        final String pkg = exceptionPackages[i];
904                        if (pkg != null) {
905                            r.exceptionPackages.add(pkg.trim());
906                        }
907                    }
908                }
909                usageRestrictions.put(usage, r);
910            }
911        }
912    }
913
914    @Override
915    public int checkPackage(int uid, String packageName) {
916        synchronized (this) {
917            if (getOpsRawLocked(uid, packageName, true) != null) {
918                return AppOpsManager.MODE_ALLOWED;
919            } else {
920                return AppOpsManager.MODE_ERRORED;
921            }
922        }
923    }
924
925    @Override
926    public int noteProxyOperation(int code, String proxyPackageName,
927            int proxiedUid, String proxiedPackageName) {
928        verifyIncomingOp(code);
929        final int proxyMode = noteOperationUnchecked(code, Binder.getCallingUid(),
930                proxyPackageName, -1, null);
931        if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
932            return proxyMode;
933        }
934        return noteOperationUnchecked(code, proxiedUid, proxiedPackageName,
935                Binder.getCallingUid(), proxyPackageName);
936    }
937
938    @Override
939    public int noteOperation(int code, int uid, String packageName) {
940        verifyIncomingUid(uid);
941        verifyIncomingOp(code);
942        return noteOperationUnchecked(code, uid, packageName, 0, null);
943    }
944
945    private int noteOperationUnchecked(int code, int uid, String packageName,
946            int proxyUid, String proxyPackageName) {
947        synchronized (this) {
948            Ops ops = getOpsLocked(uid, packageName, true);
949            if (ops == null) {
950                if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
951                        + " package " + packageName);
952                return AppOpsManager.MODE_ERRORED;
953            }
954            Op op = getOpLocked(ops, code, true);
955            if (isOpRestricted(uid, code, packageName)) {
956                return AppOpsManager.MODE_IGNORED;
957            }
958            if (op.duration == -1) {
959                Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
960                        + " code " + code + " time=" + op.time + " duration=" + op.duration);
961            }
962            op.duration = 0;
963            final int switchCode = AppOpsManager.opToSwitch(code);
964            UidState uidState = ops.uidState;
965            if (uidState.opModes != null) {
966                final int uidMode = uidState.opModes.get(switchCode);
967                if (uidMode != AppOpsManager.MODE_ALLOWED) {
968                    if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
969                            + switchCode + " (" + code + ") uid " + uid + " package "
970                            + packageName);
971                    op.rejectTime = System.currentTimeMillis();
972                    return uidMode;
973                }
974            }
975            final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
976            if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
977                if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
978                        + switchCode + " (" + code + ") uid " + uid + " package " + packageName);
979                op.rejectTime = System.currentTimeMillis();
980                return switchOp.mode;
981            }
982            if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
983                    + " package " + packageName);
984            op.time = System.currentTimeMillis();
985            op.rejectTime = 0;
986            op.proxyUid = proxyUid;
987            op.proxyPackageName = proxyPackageName;
988            return AppOpsManager.MODE_ALLOWED;
989        }
990    }
991
992    @Override
993    public int startOperation(IBinder token, int code, int uid, String packageName) {
994        verifyIncomingUid(uid);
995        verifyIncomingOp(code);
996        ClientState client = (ClientState)token;
997        synchronized (this) {
998            Ops ops = getOpsLocked(uid, packageName, true);
999            if (ops == null) {
1000                if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
1001                        + " package " + packageName);
1002                return AppOpsManager.MODE_ERRORED;
1003            }
1004            Op op = getOpLocked(ops, code, true);
1005            if (isOpRestricted(uid, code, packageName)) {
1006                return AppOpsManager.MODE_IGNORED;
1007            }
1008            final int switchCode = AppOpsManager.opToSwitch(code);
1009            UidState uidState = ops.uidState;
1010            if (uidState.opModes != null) {
1011                final int uidMode = uidState.opModes.get(switchCode);
1012                if (uidMode != AppOpsManager.MODE_ALLOWED) {
1013                    if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
1014                            + switchCode + " (" + code + ") uid " + uid + " package "
1015                            + packageName);
1016                    op.rejectTime = System.currentTimeMillis();
1017                    return uidMode;
1018                }
1019            }
1020            final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
1021            if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
1022                if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code "
1023                        + switchCode + " (" + code + ") uid " + uid + " package " + packageName);
1024                op.rejectTime = System.currentTimeMillis();
1025                return switchOp.mode;
1026            }
1027            if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid
1028                    + " package " + packageName);
1029            if (op.nesting == 0) {
1030                op.time = System.currentTimeMillis();
1031                op.rejectTime = 0;
1032                op.duration = -1;
1033            }
1034            op.nesting++;
1035            if (client.mStartedOps != null) {
1036                client.mStartedOps.add(op);
1037            }
1038            return AppOpsManager.MODE_ALLOWED;
1039        }
1040    }
1041
1042    @Override
1043    public void finishOperation(IBinder token, int code, int uid, String packageName) {
1044        verifyIncomingUid(uid);
1045        verifyIncomingOp(code);
1046        ClientState client = (ClientState)token;
1047        synchronized (this) {
1048            Op op = getOpLocked(code, uid, packageName, true);
1049            if (op == null) {
1050                return;
1051            }
1052            if (client.mStartedOps != null) {
1053                if (!client.mStartedOps.remove(op)) {
1054                    throw new IllegalStateException("Operation not started: uid" + op.uid
1055                            + " pkg=" + op.packageName + " op=" + op.op);
1056                }
1057            }
1058            finishOperationLocked(op);
1059        }
1060    }
1061
1062    @Override
1063    public int permissionToOpCode(String permission) {
1064        return AppOpsManager.permissionToOpCode(permission);
1065    }
1066
1067    void finishOperationLocked(Op op) {
1068        if (op.nesting <= 1) {
1069            if (op.nesting == 1) {
1070                op.duration = (int)(System.currentTimeMillis() - op.time);
1071                op.time += op.duration;
1072            } else {
1073                Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
1074                        + op.packageName + " code " + op.op + " time=" + op.time
1075                        + " duration=" + op.duration + " nesting=" + op.nesting);
1076            }
1077            op.nesting = 0;
1078        } else {
1079            op.nesting--;
1080        }
1081    }
1082
1083    private void verifyIncomingUid(int uid) {
1084        if (uid == Binder.getCallingUid()) {
1085            return;
1086        }
1087        if (Binder.getCallingPid() == Process.myPid()) {
1088            return;
1089        }
1090        mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
1091                Binder.getCallingPid(), Binder.getCallingUid(), null);
1092    }
1093
1094    private void verifyIncomingOp(int op) {
1095        if (op >= 0 && op < AppOpsManager._NUM_OP) {
1096            return;
1097        }
1098        throw new IllegalArgumentException("Bad operation #" + op);
1099    }
1100
1101    private UidState getUidStateLocked(int uid, boolean edit) {
1102        UidState uidState = mUidStates.get(uid);
1103        if (uidState == null) {
1104            if (!edit) {
1105                return null;
1106            }
1107            uidState = new UidState(uid);
1108            mUidStates.put(uid, uidState);
1109        }
1110        return uidState;
1111    }
1112
1113    private Ops getOpsLocked(int uid, String packageName, boolean edit) {
1114        if (uid == 0) {
1115            packageName = "root";
1116        } else if (uid == Process.SHELL_UID) {
1117            packageName = "com.android.shell";
1118        }
1119        return getOpsRawLocked(uid, packageName, edit);
1120    }
1121
1122    private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
1123        UidState uidState = getUidStateLocked(uid, edit);
1124        if (uidState == null) {
1125            return null;
1126        }
1127
1128        if (uidState.pkgOps == null) {
1129            if (!edit) {
1130                return null;
1131            }
1132            uidState.pkgOps = new ArrayMap<>();
1133        }
1134
1135        Ops ops = uidState.pkgOps.get(packageName);
1136        if (ops == null) {
1137            if (!edit) {
1138                return null;
1139            }
1140            boolean isPrivileged = false;
1141            // This is the first time we have seen this package name under this uid,
1142            // so let's make sure it is valid.
1143            if (uid != 0) {
1144                final long ident = Binder.clearCallingIdentity();
1145                try {
1146                    int pkgUid = -1;
1147                    try {
1148                        ApplicationInfo appInfo = ActivityThread.getPackageManager()
1149                                .getApplicationInfo(packageName, 0, UserHandle.getUserId(uid));
1150                        if (appInfo != null) {
1151                            pkgUid = appInfo.uid;
1152                            isPrivileged = (appInfo.privateFlags
1153                                    & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
1154                        } else {
1155                            if ("media".equals(packageName)) {
1156                                pkgUid = Process.MEDIA_UID;
1157                                isPrivileged = false;
1158                            }
1159                        }
1160                    } catch (RemoteException e) {
1161                        Slog.w(TAG, "Could not contact PackageManager", e);
1162                    }
1163                    if (pkgUid != uid) {
1164                        // Oops!  The package name is not valid for the uid they are calling
1165                        // under.  Abort.
1166                        Slog.w(TAG, "Bad call: specified package " + packageName
1167                                + " under uid " + uid + " but it is really " + pkgUid);
1168                        return null;
1169                    }
1170                } finally {
1171                    Binder.restoreCallingIdentity(ident);
1172                }
1173            }
1174            ops = new Ops(packageName, uidState, isPrivileged);
1175            uidState.pkgOps.put(packageName, ops);
1176        }
1177        return ops;
1178    }
1179
1180    private void scheduleWriteLocked() {
1181        if (!mWriteScheduled) {
1182            mWriteScheduled = true;
1183            mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
1184        }
1185    }
1186
1187    private void scheduleFastWriteLocked() {
1188        if (!mFastWriteScheduled) {
1189            mWriteScheduled = true;
1190            mFastWriteScheduled = true;
1191            mHandler.removeCallbacks(mWriteRunner);
1192            mHandler.postDelayed(mWriteRunner, 10*1000);
1193        }
1194    }
1195
1196    private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
1197        Ops ops = getOpsLocked(uid, packageName, edit);
1198        if (ops == null) {
1199            return null;
1200        }
1201        return getOpLocked(ops, code, edit);
1202    }
1203
1204    private Op getOpLocked(Ops ops, int code, boolean edit) {
1205        Op op = ops.get(code);
1206        if (op == null) {
1207            if (!edit) {
1208                return null;
1209            }
1210            op = new Op(ops.uidState.uid, ops.packageName, code);
1211            ops.put(code, op);
1212        }
1213        if (edit) {
1214            scheduleWriteLocked();
1215        }
1216        return op;
1217    }
1218
1219    private boolean isOpRestricted(int uid, int code, String packageName) {
1220        int userHandle = UserHandle.getUserId(uid);
1221        boolean[] opRestrictions = mOpRestrictions.get(userHandle);
1222        if ((opRestrictions != null) && opRestrictions[code]) {
1223            if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
1224                synchronized (this) {
1225                    Ops ops = getOpsLocked(uid, packageName, true);
1226                    if ((ops != null) && ops.isPrivileged) {
1227                        return false;
1228                    }
1229                }
1230            }
1231            return true;
1232        }
1233        return false;
1234    }
1235
1236    void readState() {
1237        synchronized (mFile) {
1238            synchronized (this) {
1239                FileInputStream stream;
1240                try {
1241                    stream = mFile.openRead();
1242                } catch (FileNotFoundException e) {
1243                    Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
1244                    return;
1245                }
1246                boolean success = false;
1247                mUidStates.clear();
1248                try {
1249                    XmlPullParser parser = Xml.newPullParser();
1250                    parser.setInput(stream, StandardCharsets.UTF_8.name());
1251                    int type;
1252                    while ((type = parser.next()) != XmlPullParser.START_TAG
1253                            && type != XmlPullParser.END_DOCUMENT) {
1254                        ;
1255                    }
1256
1257                    if (type != XmlPullParser.START_TAG) {
1258                        throw new IllegalStateException("no start tag found");
1259                    }
1260
1261                    int outerDepth = parser.getDepth();
1262                    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1263                            && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1264                        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1265                            continue;
1266                        }
1267
1268                        String tagName = parser.getName();
1269                        if (tagName.equals("pkg")) {
1270                            readPackage(parser);
1271                        } else if (tagName.equals("uid")) {
1272                            readUidOps(parser);
1273                        } else {
1274                            Slog.w(TAG, "Unknown element under <app-ops>: "
1275                                    + parser.getName());
1276                            XmlUtils.skipCurrentTag(parser);
1277                        }
1278                    }
1279                    success = true;
1280                } catch (IllegalStateException e) {
1281                    Slog.w(TAG, "Failed parsing " + e);
1282                } catch (NullPointerException e) {
1283                    Slog.w(TAG, "Failed parsing " + e);
1284                } catch (NumberFormatException e) {
1285                    Slog.w(TAG, "Failed parsing " + e);
1286                } catch (XmlPullParserException e) {
1287                    Slog.w(TAG, "Failed parsing " + e);
1288                } catch (IOException e) {
1289                    Slog.w(TAG, "Failed parsing " + e);
1290                } catch (IndexOutOfBoundsException e) {
1291                    Slog.w(TAG, "Failed parsing " + e);
1292                } finally {
1293                    if (!success) {
1294                        mUidStates.clear();
1295                    }
1296                    try {
1297                        stream.close();
1298                    } catch (IOException e) {
1299                    }
1300                }
1301            }
1302        }
1303    }
1304
1305    void readUidOps(XmlPullParser parser) throws NumberFormatException,
1306            XmlPullParserException, IOException {
1307        final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
1308        int outerDepth = parser.getDepth();
1309        int type;
1310        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1311                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1312            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1313                continue;
1314            }
1315
1316            String tagName = parser.getName();
1317            if (tagName.equals("op")) {
1318                final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
1319                final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
1320                UidState uidState = getUidStateLocked(uid, true);
1321                if (uidState.opModes == null) {
1322                    uidState.opModes = new SparseIntArray();
1323                }
1324                uidState.opModes.put(code, mode);
1325            } else {
1326                Slog.w(TAG, "Unknown element under <uid-ops>: "
1327                        + parser.getName());
1328                XmlUtils.skipCurrentTag(parser);
1329            }
1330        }
1331    }
1332
1333    void readPackage(XmlPullParser parser) throws NumberFormatException,
1334            XmlPullParserException, IOException {
1335        String pkgName = parser.getAttributeValue(null, "n");
1336        int outerDepth = parser.getDepth();
1337        int type;
1338        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1339                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1340            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1341                continue;
1342            }
1343
1344            String tagName = parser.getName();
1345            if (tagName.equals("uid")) {
1346                readUid(parser, pkgName);
1347            } else {
1348                Slog.w(TAG, "Unknown element under <pkg>: "
1349                        + parser.getName());
1350                XmlUtils.skipCurrentTag(parser);
1351            }
1352        }
1353    }
1354
1355    void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
1356            XmlPullParserException, IOException {
1357        int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
1358        String isPrivilegedString = parser.getAttributeValue(null, "p");
1359        boolean isPrivileged = false;
1360        if (isPrivilegedString == null) {
1361            try {
1362                IPackageManager packageManager = ActivityThread.getPackageManager();
1363                if (packageManager != null) {
1364                    ApplicationInfo appInfo = ActivityThread.getPackageManager()
1365                            .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
1366                    if (appInfo != null) {
1367                        isPrivileged = (appInfo.privateFlags
1368                                & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
1369                    }
1370                } else {
1371                    // Could not load data, don't add to cache so it will be loaded later.
1372                    return;
1373                }
1374            } catch (RemoteException e) {
1375                Slog.w(TAG, "Could not contact PackageManager", e);
1376            }
1377        } else {
1378            isPrivileged = Boolean.parseBoolean(isPrivilegedString);
1379        }
1380        int outerDepth = parser.getDepth();
1381        int type;
1382        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1383                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1384            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1385                continue;
1386            }
1387
1388            String tagName = parser.getName();
1389            if (tagName.equals("op")) {
1390                Op op = new Op(uid, pkgName, Integer.parseInt(parser.getAttributeValue(null, "n")));
1391                String mode = parser.getAttributeValue(null, "m");
1392                if (mode != null) {
1393                    op.mode = Integer.parseInt(mode);
1394                }
1395                String time = parser.getAttributeValue(null, "t");
1396                if (time != null) {
1397                    op.time = Long.parseLong(time);
1398                }
1399                time = parser.getAttributeValue(null, "r");
1400                if (time != null) {
1401                    op.rejectTime = Long.parseLong(time);
1402                }
1403                String dur = parser.getAttributeValue(null, "d");
1404                if (dur != null) {
1405                    op.duration = Integer.parseInt(dur);
1406                }
1407                String proxyUid = parser.getAttributeValue(null, "pu");
1408                if (proxyUid != null) {
1409                    op.proxyUid = Integer.parseInt(proxyUid);
1410                }
1411                String proxyPackageName = parser.getAttributeValue(null, "pp");
1412                if (proxyPackageName != null) {
1413                    op.proxyPackageName = proxyPackageName;
1414                }
1415
1416                UidState uidState = getUidStateLocked(uid, true);
1417                if (uidState.pkgOps == null) {
1418                    uidState.pkgOps = new ArrayMap<>();
1419                }
1420
1421                Ops ops = uidState.pkgOps.get(pkgName);
1422                if (ops == null) {
1423                    ops = new Ops(pkgName, uidState, isPrivileged);
1424                    uidState.pkgOps.put(pkgName, ops);
1425                }
1426                ops.put(op.op, op);
1427            } else {
1428                Slog.w(TAG, "Unknown element under <pkg>: "
1429                        + parser.getName());
1430                XmlUtils.skipCurrentTag(parser);
1431            }
1432        }
1433    }
1434
1435    void writeState() {
1436        synchronized (mFile) {
1437            List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
1438
1439            FileOutputStream stream;
1440            try {
1441                stream = mFile.startWrite();
1442            } catch (IOException e) {
1443                Slog.w(TAG, "Failed to write state: " + e);
1444                return;
1445            }
1446
1447            try {
1448                XmlSerializer out = new FastXmlSerializer();
1449                out.setOutput(stream, StandardCharsets.UTF_8.name());
1450                out.startDocument(null, true);
1451                out.startTag(null, "app-ops");
1452
1453                final int uidStateCount = mUidStates.size();
1454                for (int i = 0; i < uidStateCount; i++) {
1455                    UidState uidState = mUidStates.valueAt(i);
1456                    if (uidState.opModes != null && uidState.opModes.size() > 0) {
1457                        out.startTag(null, "uid");
1458                        out.attribute(null, "n", Integer.toString(uidState.uid));
1459                        SparseIntArray uidOpModes = uidState.opModes;
1460                        final int opCount = uidOpModes.size();
1461                        for (int j = 0; j < opCount; j++) {
1462                            final int op = uidOpModes.keyAt(j);
1463                            final int mode = uidOpModes.valueAt(j);
1464                            out.startTag(null, "op");
1465                            out.attribute(null, "n", Integer.toString(op));
1466                            out.attribute(null, "m", Integer.toString(mode));
1467                            out.endTag(null, "op");
1468                        }
1469                        out.endTag(null, "uid");
1470                    }
1471                }
1472
1473                if (allOps != null) {
1474                    String lastPkg = null;
1475                    for (int i=0; i<allOps.size(); i++) {
1476                        AppOpsManager.PackageOps pkg = allOps.get(i);
1477                        if (!pkg.getPackageName().equals(lastPkg)) {
1478                            if (lastPkg != null) {
1479                                out.endTag(null, "pkg");
1480                            }
1481                            lastPkg = pkg.getPackageName();
1482                            out.startTag(null, "pkg");
1483                            out.attribute(null, "n", lastPkg);
1484                        }
1485                        out.startTag(null, "uid");
1486                        out.attribute(null, "n", Integer.toString(pkg.getUid()));
1487                        synchronized (this) {
1488                            Ops ops = getOpsLocked(pkg.getUid(), pkg.getPackageName(), false);
1489                            // Should always be present as the list of PackageOps is generated
1490                            // from Ops.
1491                            if (ops != null) {
1492                                out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
1493                            } else {
1494                                out.attribute(null, "p", Boolean.toString(false));
1495                            }
1496                        }
1497                        List<AppOpsManager.OpEntry> ops = pkg.getOps();
1498                        for (int j=0; j<ops.size(); j++) {
1499                            AppOpsManager.OpEntry op = ops.get(j);
1500                            out.startTag(null, "op");
1501                            out.attribute(null, "n", Integer.toString(op.getOp()));
1502                            if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
1503                                out.attribute(null, "m", Integer.toString(op.getMode()));
1504                            }
1505                            long time = op.getTime();
1506                            if (time != 0) {
1507                                out.attribute(null, "t", Long.toString(time));
1508                            }
1509                            time = op.getRejectTime();
1510                            if (time != 0) {
1511                                out.attribute(null, "r", Long.toString(time));
1512                            }
1513                            int dur = op.getDuration();
1514                            if (dur != 0) {
1515                                out.attribute(null, "d", Integer.toString(dur));
1516                            }
1517                            int proxyUid = op.getProxyUid();
1518                            if (proxyUid != -1) {
1519                                out.attribute(null, "pu", Integer.toString(proxyUid));
1520                            }
1521                            String proxyPackageName = op.getProxyPackageName();
1522                            if (proxyPackageName != null) {
1523                                out.attribute(null, "pp", proxyPackageName);
1524                            }
1525                            out.endTag(null, "op");
1526                        }
1527                        out.endTag(null, "uid");
1528                    }
1529                    if (lastPkg != null) {
1530                        out.endTag(null, "pkg");
1531                    }
1532                }
1533
1534                out.endTag(null, "app-ops");
1535                out.endDocument();
1536                mFile.finishWrite(stream);
1537            } catch (IOException e) {
1538                Slog.w(TAG, "Failed to write state, restoring backup.", e);
1539                mFile.failWrite(stream);
1540            }
1541        }
1542    }
1543
1544    private void dumpHelp(PrintWriter pw) {
1545        pw.println("AppOps service (appops) dump options:");
1546        pw.println("  [-h] [CMD]");
1547        pw.println("  -h: print this help text.");
1548        pw.println("Commands:");
1549        pw.println("  write-settings");
1550        pw.println("    Immediately write pending changes to storage.");
1551        pw.println("  read-settings");
1552        pw.println("    Read the last written settings, replacing current state in RAM.");
1553    }
1554
1555    @Override
1556    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1557        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1558                != PackageManager.PERMISSION_GRANTED) {
1559            pw.println("Permission Denial: can't dump ApOps service from from pid="
1560                    + Binder.getCallingPid()
1561                    + ", uid=" + Binder.getCallingUid());
1562            return;
1563        }
1564
1565        if (args != null) {
1566            for (int i=0; i<args.length; i++) {
1567                String arg = args[i];
1568                if ("-h".equals(arg)) {
1569                    dumpHelp(pw);
1570                    return;
1571                } else if ("-a".equals(arg)) {
1572                    // dump all data
1573                } else if ("write-settings".equals(arg)) {
1574                    long token = Binder.clearCallingIdentity();
1575                    try {
1576                        synchronized (this) {
1577                            mHandler.removeCallbacks(mWriteRunner);
1578                        }
1579                        writeState();
1580                        pw.println("Current settings written.");
1581                    } finally {
1582                        Binder.restoreCallingIdentity(token);
1583                    }
1584                    return;
1585                } else if ("read-settings".equals(arg)) {
1586                    long token = Binder.clearCallingIdentity();
1587                    try {
1588                        readState();
1589                        pw.println("Last settings read.");
1590                    } finally {
1591                        Binder.restoreCallingIdentity(token);
1592                    }
1593                    return;
1594                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
1595                    pw.println("Unknown option: " + arg);
1596                    return;
1597                } else {
1598                    pw.println("Unknown command: " + arg);
1599                    return;
1600                }
1601            }
1602        }
1603
1604        synchronized (this) {
1605            pw.println("Current AppOps Service state:");
1606            final long now = System.currentTimeMillis();
1607            boolean needSep = false;
1608            if (mOpModeWatchers.size() > 0) {
1609                needSep = true;
1610                pw.println("  Op mode watchers:");
1611                for (int i=0; i<mOpModeWatchers.size(); i++) {
1612                    pw.print("    Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
1613                    pw.println(":");
1614                    ArrayList<Callback> callbacks = mOpModeWatchers.valueAt(i);
1615                    for (int j=0; j<callbacks.size(); j++) {
1616                        pw.print("      #"); pw.print(j); pw.print(": ");
1617                        pw.println(callbacks.get(j));
1618                    }
1619                }
1620            }
1621            if (mPackageModeWatchers.size() > 0) {
1622                needSep = true;
1623                pw.println("  Package mode watchers:");
1624                for (int i=0; i<mPackageModeWatchers.size(); i++) {
1625                    pw.print("    Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
1626                    pw.println(":");
1627                    ArrayList<Callback> callbacks = mPackageModeWatchers.valueAt(i);
1628                    for (int j=0; j<callbacks.size(); j++) {
1629                        pw.print("      #"); pw.print(j); pw.print(": ");
1630                        pw.println(callbacks.get(j));
1631                    }
1632                }
1633            }
1634            if (mModeWatchers.size() > 0) {
1635                needSep = true;
1636                pw.println("  All mode watchers:");
1637                for (int i=0; i<mModeWatchers.size(); i++) {
1638                    pw.print("    "); pw.print(mModeWatchers.keyAt(i));
1639                    pw.print(" -> "); pw.println(mModeWatchers.valueAt(i));
1640                }
1641            }
1642            if (mClients.size() > 0) {
1643                needSep = true;
1644                pw.println("  Clients:");
1645                for (int i=0; i<mClients.size(); i++) {
1646                    pw.print("    "); pw.print(mClients.keyAt(i)); pw.println(":");
1647                    ClientState cs = mClients.valueAt(i);
1648                    pw.print("      "); pw.println(cs);
1649                    if (cs.mStartedOps != null && cs.mStartedOps.size() > 0) {
1650                        pw.println("      Started ops:");
1651                        for (int j=0; j<cs.mStartedOps.size(); j++) {
1652                            Op op = cs.mStartedOps.get(j);
1653                            pw.print("        "); pw.print("uid="); pw.print(op.uid);
1654                            pw.print(" pkg="); pw.print(op.packageName);
1655                            pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
1656                        }
1657                    }
1658                }
1659            }
1660            if (mAudioRestrictions.size() > 0) {
1661                boolean printedHeader = false;
1662                for (int o=0; o<mAudioRestrictions.size(); o++) {
1663                    final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
1664                    final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
1665                    for (int i=0; i<restrictions.size(); i++) {
1666                        if (!printedHeader){
1667                            pw.println("  Audio Restrictions:");
1668                            printedHeader = true;
1669                            needSep = true;
1670                        }
1671                        final int usage = restrictions.keyAt(i);
1672                        pw.print("    "); pw.print(op);
1673                        pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
1674                        Restriction r = restrictions.valueAt(i);
1675                        pw.print(": mode="); pw.println(r.mode);
1676                        if (!r.exceptionPackages.isEmpty()) {
1677                            pw.println("      Exceptions:");
1678                            for (int j=0; j<r.exceptionPackages.size(); j++) {
1679                                pw.print("        "); pw.println(r.exceptionPackages.valueAt(j));
1680                            }
1681                        }
1682                    }
1683                }
1684            }
1685            if (needSep) {
1686                pw.println();
1687            }
1688            for (int i=0; i<mUidStates.size(); i++) {
1689                UidState uidState = mUidStates.valueAt(i);
1690
1691                pw.print("  Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
1692
1693                SparseIntArray opModes = uidState.opModes;
1694                if (opModes != null) {
1695                    final int opModeCount = opModes.size();
1696                    for (int j = 0; j < opModeCount; j++) {
1697                        final int code = opModes.keyAt(j);
1698                        final int mode = opModes.valueAt(j);
1699                        pw.print("      "); pw.print(AppOpsManager.opToName(code));
1700                        pw.print(": mode="); pw.println(mode);
1701                    }
1702                }
1703
1704                ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
1705                if (pkgOps == null) {
1706                    continue;
1707                }
1708
1709                for (Ops ops : pkgOps.values()) {
1710                    pw.print("    Package "); pw.print(ops.packageName); pw.println(":");
1711                    for (int j=0; j<ops.size(); j++) {
1712                        Op op = ops.valueAt(j);
1713                        pw.print("      "); pw.print(AppOpsManager.opToName(op.op));
1714                        pw.print(": mode="); pw.print(op.mode);
1715                        if (op.time != 0) {
1716                            pw.print("; time="); TimeUtils.formatDuration(now-op.time, pw);
1717                            pw.print(" ago");
1718                        }
1719                        if (op.rejectTime != 0) {
1720                            pw.print("; rejectTime="); TimeUtils.formatDuration(now-op.rejectTime, pw);
1721                            pw.print(" ago");
1722                        }
1723                        if (op.duration == -1) {
1724                            pw.print(" (running)");
1725                        } else if (op.duration != 0) {
1726                            pw.print("; duration="); TimeUtils.formatDuration(op.duration, pw);
1727                        }
1728                        pw.println();
1729                    }
1730                }
1731            }
1732        }
1733    }
1734
1735    private static final class Restriction {
1736        private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
1737        int mode;
1738        ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
1739    }
1740
1741    @Override
1742    public void setUserRestrictions(Bundle restrictions, int userHandle) throws RemoteException {
1743        checkSystemUid("setUserRestrictions");
1744        boolean[] opRestrictions = mOpRestrictions.get(userHandle);
1745        if (opRestrictions == null) {
1746            opRestrictions = new boolean[AppOpsManager._NUM_OP];
1747            mOpRestrictions.put(userHandle, opRestrictions);
1748        }
1749        for (int i = 0; i < opRestrictions.length; ++i) {
1750            String restriction = AppOpsManager.opToRestriction(i);
1751            if (restriction != null) {
1752                opRestrictions[i] = restrictions.getBoolean(restriction, false);
1753            } else {
1754                opRestrictions[i] = false;
1755            }
1756        }
1757    }
1758
1759    @Override
1760    public void removeUser(int userHandle) throws RemoteException {
1761        checkSystemUid("removeUser");
1762        mOpRestrictions.remove(userHandle);
1763    }
1764
1765    private void checkSystemUid(String function) {
1766        int uid = Binder.getCallingUid();
1767        if (uid != Process.SYSTEM_UID) {
1768            throw new SecurityException(function + " must by called by the system");
1769        }
1770    }
1771
1772    private static String[] getPackagesForUid(int uid) {
1773        String[] packageNames = null;
1774        try {
1775            packageNames= AppGlobals.getPackageManager().getPackagesForUid(uid);
1776        } catch (RemoteException e) {
1777            /* ignore - local call */
1778        }
1779        if (packageNames == null) {
1780            return EmptyArray.STRING;
1781        }
1782        return packageNames;
1783    }
1784}
1785