AppOpsService.java revision 5e45ee6752528791deb66b83d76250685de15d47
1a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn/*
2a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn * Copyright (C) 2012 The Android Open Source Project
3a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn *
4a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
5a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn * you may not use this file except in compliance with the License.
6a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn * You may obtain a copy of the License at
7a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn *
8a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
9a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn *
10a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn * Unless required by applicable law or agreed to in writing, software
11a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
12a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn * See the License for the specific language governing permissions and
14a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn * limitations under the License.
15a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn */
16a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
17a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornpackage com.android.server;
18a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
19a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport java.io.File;
20a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport java.io.FileDescriptor;
2135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport java.io.FileInputStream;
2235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport java.io.FileNotFoundException;
2335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport java.io.FileOutputStream;
2435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport java.io.IOException;
25a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport java.io.PrintWriter;
2635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport java.util.ArrayList;
27a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport java.util.HashMap;
2835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport java.util.List;
29a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
30a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.app.AppOpsManager;
31a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.content.Context;
32a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.content.pm.PackageManager;
33a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.content.pm.PackageManager.NameNotFoundException;
3435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport android.os.AsyncTask;
35a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.os.Binder;
3635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport android.os.Handler;
37a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.os.Process;
38a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.os.ServiceManager;
39a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.os.UserHandle;
40a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.util.AtomicFile;
415e45ee6752528791deb66b83d76250685de15d47Dianne Hackbornimport android.util.Log;
42a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.util.Slog;
43a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.util.SparseArray;
44a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.util.TimeUtils;
4535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport android.util.Xml;
46a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
47a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport com.android.internal.app.IAppOpsService;
4835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport com.android.internal.util.FastXmlSerializer;
4935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport com.android.internal.util.XmlUtils;
5035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
5135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport org.xmlpull.v1.XmlPullParser;
5235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport org.xmlpull.v1.XmlPullParserException;
5335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport org.xmlpull.v1.XmlSerializer;
54a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
55a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornpublic class AppOpsService extends IAppOpsService.Stub {
56a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    static final String TAG = "AppOps";
5735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    static final boolean DEBUG = false;
5835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
5935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    // Write at most every 30 minutes.
6035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
61a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
62a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    Context mContext;
63a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    final AtomicFile mFile;
6435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    final Handler mHandler;
6535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
6635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    boolean mWriteScheduled;
6735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    final Runnable mWriteRunner = new Runnable() {
6835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        public void run() {
6935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            synchronized (AppOpsService.this) {
7035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                mWriteScheduled = false;
7135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
7235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    @Override protected Void doInBackground(Void... params) {
7335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        writeState();
7435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        return null;
7535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
7635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                };
7735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
7835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
7935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        }
8035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    };
81a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
82a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    final SparseArray<HashMap<String, Ops>> mUidOps
83a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            = new SparseArray<HashMap<String, Ops>>();
84a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
85a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    final static class Ops extends SparseArray<Op> {
86a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        public final String packageName;
8735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        public final int uid;
88a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
8935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        public Ops(String _packageName, int _uid) {
90a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            packageName = _packageName;
9135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            uid = _uid;
92a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
93a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
94a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
95a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    final static class Op {
96a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        public final int op;
975e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn        public int mode;
98a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        public int duration;
99a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        public long time;
1005e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn        public long rejectTime;
10135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        public int nesting;
102a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
103a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        public Op(int _op) {
104a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            op = _op;
1055e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            mode = AppOpsManager.MODE_ALLOWED;
106a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
107a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
108a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
10935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    public AppOpsService(File storagePath) {
11035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        mFile = new AtomicFile(storagePath);
11135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        mHandler = new Handler();
11235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        readState();
113a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
114a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
115a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    public void publish(Context context) {
116a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        mContext = context;
117a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
118a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
119a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
120a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    public void shutdown() {
121a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        Slog.w(TAG, "Writing app ops before shutdown...");
12235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        boolean doWrite = false;
12335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        synchronized (this) {
12435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (mWriteScheduled) {
12535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                mWriteScheduled = false;
12635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                doWrite = true;
12735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
12835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        }
12935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        if (doWrite) {
13035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            writeState();
13135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        }
132a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
133a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
13472e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn    private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
13572e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        ArrayList<AppOpsManager.OpEntry> resOps = null;
13672e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        if (ops == null) {
13772e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            resOps = new ArrayList<AppOpsManager.OpEntry>();
13872e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            for (int j=0; j<pkgOps.size(); j++) {
13972e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                Op curOp = pkgOps.valueAt(j);
1405e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
1415e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                        curOp.rejectTime, curOp.duration));
14272e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            }
14372e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        } else {
14472e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            for (int j=0; j<ops.length; j++) {
14572e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                Op curOp = pkgOps.get(ops[j]);
14672e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                if (curOp != null) {
14772e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                    if (resOps == null) {
14872e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                        resOps = new ArrayList<AppOpsManager.OpEntry>();
14972e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                    }
1505e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                    resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
1515e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                            curOp.rejectTime, curOp.duration));
15272e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                }
15372e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            }
15472e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        }
15572e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        return resOps;
15672e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn    }
15772e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn
158a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    @Override
15935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
16035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
16135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                Binder.getCallingPid(), Binder.getCallingUid(), null);
16235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        ArrayList<AppOpsManager.PackageOps> res = null;
163a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        synchronized (this) {
16435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            for (int i=0; i<mUidOps.size(); i++) {
16535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                HashMap<String, Ops> packages = mUidOps.valueAt(i);
16635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                for (Ops pkgOps : packages.values()) {
16772e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                    ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
16835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    if (resOps != null) {
16935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        if (res == null) {
17035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            res = new ArrayList<AppOpsManager.PackageOps>();
17135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        }
17235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
17335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                                pkgOps.packageName, pkgOps.uid, resOps);
17435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        res.add(resPackage);
17535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
17635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                }
177a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
178a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
17935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        return res;
180a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
181a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
182a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    @Override
18372e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn    public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
18472e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            int[] ops) {
18572e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
18672e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                Binder.getCallingPid(), Binder.getCallingUid(), null);
18772e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        synchronized (this) {
18872e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            Ops pkgOps = getOpsLocked(uid, packageName, false);
18972e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            if (pkgOps == null) {
19072e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                return null;
19172e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            }
19272e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
19372e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            if (resOps == null) {
19472e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                return null;
19572e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            }
19672e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
19772e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
19872e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                    pkgOps.packageName, pkgOps.uid, resOps);
19972e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            res.add(resPackage);
20072e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            return res;
20172e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        }
20272e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn    }
20372e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn
20472e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn    @Override
2055e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn    public void setMode(int code, int uid, String packageName, int mode) {
2065e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn        uid = handleIncomingUid(uid);
2075e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn        synchronized (this) {
2085e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            Op op = getOpLocked(code, uid, packageName, true);
2095e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            if (op != null) {
2105e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                if (op.mode != mode) {
2115e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                    op.mode = mode;
2125e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                    scheduleWriteNowLocked();
2135e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                }
2145e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            }
2155e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn        }
2165e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn    }
2175e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn
2185e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn    @Override
21935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    public int checkOperation(int code, int uid, String packageName) {
220a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        uid = handleIncomingUid(uid);
221a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        synchronized (this) {
22235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            Op op = getOpLocked(code, uid, packageName, false);
223a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            if (op == null) {
22435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                return AppOpsManager.MODE_ALLOWED;
225a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
2265e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            return op.mode;
227a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
228a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
229a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
230a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    @Override
23135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    public int noteOperation(int code, int uid, String packageName) {
232a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        uid = handleIncomingUid(uid);
233a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        synchronized (this) {
23435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            Op op = getOpLocked(code, uid, packageName, true);
235a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            if (op == null) {
2365e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
2375e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                        + " package " + packageName);
23835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                return AppOpsManager.MODE_IGNORED;
239a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
24035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (op.duration == -1) {
24135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
242a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                        + " code " + code + " time=" + op.time + " duration=" + op.duration);
243a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
24435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            op.duration = 0;
2455e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            if (op.mode != AppOpsManager.MODE_ALLOWED) {
2465e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code " + code
2475e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                        + " uid " + uid + " package " + packageName);
2485e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                op.rejectTime = System.currentTimeMillis();
2495e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                return op.mode;
2505e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            }
2515e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
2525e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                    + " package " + packageName);
2535e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            op.time = System.currentTimeMillis();
2545e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            return AppOpsManager.MODE_ALLOWED;
255a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
256a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
257a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
258a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    @Override
25935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    public int startOperation(int code, int uid, String packageName) {
260a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        uid = handleIncomingUid(uid);
261a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        synchronized (this) {
26235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            Op op = getOpLocked(code, uid, packageName, true);
263a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            if (op == null) {
2645e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
2655e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                        + " package " + packageName);
266a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                return AppOpsManager.MODE_IGNORED;
267a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
2685e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            if (op.mode != AppOpsManager.MODE_ALLOWED) {
2695e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code " + code
2705e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                        + " uid " + uid + " package " + packageName);
2715e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                op.rejectTime = System.currentTimeMillis();
2725e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                return op.mode;
2735e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            }
2745e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid
2755e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                    + " package " + packageName);
27635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (op.nesting == 0) {
27735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                op.time = System.currentTimeMillis();
27835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                op.duration = -1;
279a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
28035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            op.nesting++;
2815e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            return AppOpsManager.MODE_ALLOWED;
282a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
283a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
284a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
285a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    @Override
28635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    public void finishOperation(int code, int uid, String packageName) {
287a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        uid = handleIncomingUid(uid);
288a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        synchronized (this) {
28935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            Op op = getOpLocked(code, uid, packageName, true);
290a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            if (op == null) {
291a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                return;
292a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
29335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (op.nesting <= 1) {
29435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                if (op.nesting == 1) {
29535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    op.duration = (int)(System.currentTimeMillis() - op.time);
29635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } else {
29735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Slog.w(TAG, "Finishing op nesting under-run: uid " + uid + " pkg " + packageName
29835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        + " code " + code + " time=" + op.time + " duration=" + op.duration
29935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        + " nesting=" + op.nesting);
30035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                }
301e799175b6ba3aadd972f4b861758d675d1f93987Dianne Hackborn                op.nesting = 0;
30235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            } else {
30335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                op.nesting--;
304a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
305a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
306a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
307a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
308a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    private int handleIncomingUid(int uid) {
309a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        if (uid == Binder.getCallingUid()) {
310a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            return uid;
311a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
312a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        if (Binder.getCallingPid() == Process.myPid()) {
313a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            return uid;
314a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
315a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
316a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                Binder.getCallingPid(), Binder.getCallingUid(), null);
317a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        return uid;
318a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
319a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
32072e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn    private Ops getOpsLocked(int uid, String packageName, boolean edit) {
321a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        HashMap<String, Ops> pkgOps = mUidOps.get(uid);
322a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        if (pkgOps == null) {
32335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (!edit) {
32435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                return null;
32535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
326a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            pkgOps = new HashMap<String, Ops>();
327a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            mUidOps.put(uid, pkgOps);
328a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
329a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        Ops ops = pkgOps.get(packageName);
330a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        if (ops == null) {
33135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (!edit) {
33235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                return null;
33335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
334a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            // This is the first time we have seen this package name under this uid,
335a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            // so let's make sure it is valid.
336002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn            final long ident = Binder.clearCallingIdentity();
337002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn            try {
338002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                int pkgUid = -1;
339a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                try {
340002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                    pkgUid = mContext.getPackageManager().getPackageUid(packageName,
341002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                            UserHandle.getUserId(uid));
342002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                } catch (NameNotFoundException e) {
343a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                }
344002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                if (pkgUid != uid) {
345002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                    // Oops!  The package name is not valid for the uid they are calling
346002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                    // under.  Abort.
347002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                    Slog.w(TAG, "Bad call: specified package " + packageName
348002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                            + " under uid " + uid + " but it is really " + pkgUid);
349002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                    return null;
350002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                }
351002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn            } finally {
352002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                Binder.restoreCallingIdentity(ident);
353a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
35435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            ops = new Ops(packageName, uid);
355a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            pkgOps.put(packageName, ops);
356a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
35772e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        return ops;
35872e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn    }
35972e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn
3605e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn    private void scheduleWriteLocked() {
3615e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn        if (!mWriteScheduled) {
3625e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            mWriteScheduled = true;
3635e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
3645e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn        }
3655e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn    }
3665e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn
3675e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn    private void scheduleWriteNowLocked() {
3685e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn        if (!mWriteScheduled) {
3695e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            mWriteScheduled = true;
3705e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn        }
3715e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn        mHandler.removeCallbacks(mWriteRunner);
3725e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn        mHandler.post(mWriteRunner);
3735e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn    }
3745e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn
37572e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn    private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
37672e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        Ops ops = getOpsLocked(uid, packageName, edit);
37772e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        if (ops == null) {
37872e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            return null;
37972e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        }
380a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        Op op = ops.get(code);
381a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        if (op == null) {
38235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (!edit) {
38335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                return null;
38435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
385a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            op = new Op(code);
386a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            ops.put(code, op);
387a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
3885e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn        if (edit) {
3895e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            scheduleWriteLocked();
39035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        }
391a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        return op;
392a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
393a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
39435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    void readState() {
39535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        synchronized (mFile) {
39635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            synchronized (this) {
39735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                FileInputStream stream;
39835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                try {
39935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    stream = mFile.openRead();
40035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } catch (FileNotFoundException e) {
40135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
40235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    return;
40335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                }
40435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                boolean success = false;
40535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                try {
40635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    XmlPullParser parser = Xml.newPullParser();
40735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    parser.setInput(stream, null);
40835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    int type;
40935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    while ((type = parser.next()) != XmlPullParser.START_TAG
41035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            && type != XmlPullParser.END_DOCUMENT) {
41135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        ;
41235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
41335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
41435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    if (type != XmlPullParser.START_TAG) {
41535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        throw new IllegalStateException("no start tag found");
41635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
41735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
41835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    int outerDepth = parser.getDepth();
41935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
42035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
42135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
42235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            continue;
42335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        }
42435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
42535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        String tagName = parser.getName();
42635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        if (tagName.equals("pkg")) {
42735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            readPackage(parser);
42835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        } else {
42935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            Slog.w(TAG, "Unknown element under <app-ops>: "
43035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                                    + parser.getName());
43135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            XmlUtils.skipCurrentTag(parser);
43235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        }
43335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
43435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    success = true;
43535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } catch (IllegalStateException e) {
43635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Slog.w(TAG, "Failed parsing " + e);
43735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } catch (NullPointerException e) {
43835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Slog.w(TAG, "Failed parsing " + e);
43935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } catch (NumberFormatException e) {
44035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Slog.w(TAG, "Failed parsing " + e);
44135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } catch (XmlPullParserException e) {
44235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Slog.w(TAG, "Failed parsing " + e);
44335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } catch (IOException e) {
44435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Slog.w(TAG, "Failed parsing " + e);
44535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } catch (IndexOutOfBoundsException e) {
44635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Slog.w(TAG, "Failed parsing " + e);
44735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } finally {
44835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    if (!success) {
44935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        mUidOps.clear();
45035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
45135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    try {
45235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        stream.close();
45335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    } catch (IOException e) {
45435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
45535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                }
45635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
45735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        }
45835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    }
45935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
46035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    void readPackage(XmlPullParser parser) throws NumberFormatException,
46135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            XmlPullParserException, IOException {
46235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        String pkgName = parser.getAttributeValue(null, "n");
46335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        int outerDepth = parser.getDepth();
46435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        int type;
46535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
46635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
46735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
46835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                continue;
46935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
47035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
47135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            String tagName = parser.getName();
47235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (tagName.equals("uid")) {
47335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                readUid(parser, pkgName);
47435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            } else {
47535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                Slog.w(TAG, "Unknown element under <pkg>: "
47635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        + parser.getName());
47735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                XmlUtils.skipCurrentTag(parser);
47835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
47935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        }
48035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    }
48135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
48235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
48335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            XmlPullParserException, IOException {
48435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
48535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        int outerDepth = parser.getDepth();
48635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        int type;
48735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
48835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
48935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
49035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                continue;
49135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
49235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
49335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            String tagName = parser.getName();
49435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (tagName.equals("op")) {
49535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                Op op = new Op(Integer.parseInt(parser.getAttributeValue(null, "n")));
4965e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                String mode = parser.getAttributeValue(null, "m");
4975e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                if (mode != null) {
4985e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                    op.mode = Integer.parseInt(mode);
4995e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                }
5005e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                String time = parser.getAttributeValue(null, "t");
5015e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                if (time != null) {
5025e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                    op.time = Long.parseLong(time);
5035e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                }
5045e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                time = parser.getAttributeValue(null, "r");
5055e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                if (time != null) {
5065e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                    op.rejectTime = Long.parseLong(time);
5075e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                }
5085e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                String dur = parser.getAttributeValue(null, "d");
5095e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                if (dur != null) {
5105e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                    op.duration = Integer.parseInt(dur);
5115e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                }
51235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                HashMap<String, Ops> pkgOps = mUidOps.get(uid);
51335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                if (pkgOps == null) {
51435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    pkgOps = new HashMap<String, Ops>();
51535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    mUidOps.put(uid, pkgOps);
51635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                }
51735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                Ops ops = pkgOps.get(pkgName);
51835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                if (ops == null) {
51935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    ops = new Ops(pkgName, uid);
52035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    pkgOps.put(pkgName, ops);
52135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                }
52235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                ops.put(op.op, op);
52335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            } else {
52435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                Slog.w(TAG, "Unknown element under <pkg>: "
52535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        + parser.getName());
52635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                XmlUtils.skipCurrentTag(parser);
52735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
52835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        }
52935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    }
53035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
53135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    void writeState() {
53235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        synchronized (mFile) {
53335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
53435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
53535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            FileOutputStream stream;
53635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            try {
53735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                stream = mFile.startWrite();
53835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            } catch (IOException e) {
53935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                Slog.w(TAG, "Failed to write state: " + e);
54035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                return;
54135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
54235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
54335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            try {
54435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                XmlSerializer out = new FastXmlSerializer();
54535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                out.setOutput(stream, "utf-8");
54635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                out.startDocument(null, true);
54735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                out.startTag(null, "app-ops");
54835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
54935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                if (allOps != null) {
55035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    String lastPkg = null;
55135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    for (int i=0; i<allOps.size(); i++) {
55235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        AppOpsManager.PackageOps pkg = allOps.get(i);
55335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        if (!pkg.getPackageName().equals(lastPkg)) {
55435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            if (lastPkg != null) {
55535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                                out.endTag(null, "pkg");
55635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            }
55735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            lastPkg = pkg.getPackageName();
55835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            out.startTag(null, "pkg");
55935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            out.attribute(null, "n", lastPkg);
56035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        }
56135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        out.startTag(null, "uid");
56235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        out.attribute(null, "n", Integer.toString(pkg.getUid()));
56335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        List<AppOpsManager.OpEntry> ops = pkg.getOps();
56435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        for (int j=0; j<ops.size(); j++) {
56535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            AppOpsManager.OpEntry op = ops.get(j);
56635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            out.startTag(null, "op");
56735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            out.attribute(null, "n", Integer.toString(op.getOp()));
5685e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                            if (op.getMode() != AppOpsManager.MODE_ALLOWED) {
5695e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                                out.attribute(null, "m", Integer.toString(op.getMode()));
5705e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                            }
5715e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                            long time = op.getTime();
5725e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                            if (time != 0) {
5735e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                                out.attribute(null, "t", Long.toString(time));
5745e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                            }
5755e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                            time = op.getRejectTime();
5765e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                            if (time != 0) {
5775e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                                out.attribute(null, "r", Long.toString(time));
5785e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                            }
5795e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                            int dur = op.getDuration();
5805e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                            if (dur != 0) {
5815e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                                out.attribute(null, "d", Integer.toString(dur));
5825e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                            }
58335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            out.endTag(null, "op");
58435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        }
58535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        out.endTag(null, "uid");
58635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
58735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    if (lastPkg != null) {
58835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        out.endTag(null, "pkg");
58935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
59035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                }
59135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
59235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                out.endTag(null, "app-ops");
59335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                out.endDocument();
59435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                mFile.finishWrite(stream);
59535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            } catch (IOException e) {
59635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                Slog.w(TAG, "Failed to write state, restoring backup.", e);
59735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                mFile.failWrite(stream);
59835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
59935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        }
60035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    }
60135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
602a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    @Override
603a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
604a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
605a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                != PackageManager.PERMISSION_GRANTED) {
606a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            pw.println("Permission Denial: can't dump ApOps service from from pid="
607a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                    + Binder.getCallingPid()
608a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                    + ", uid=" + Binder.getCallingUid());
609a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            return;
610a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
611a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
612a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        synchronized (this) {
613a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            pw.println("Current AppOps Service state:");
6145e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn            final long now = System.currentTimeMillis();
615a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            for (int i=0; i<mUidOps.size(); i++) {
616a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                pw.print("  Uid "); UserHandle.formatUid(pw, mUidOps.keyAt(i)); pw.println(":");
617a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                HashMap<String, Ops> pkgOps = mUidOps.valueAt(i);
618a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                for (Ops ops : pkgOps.values()) {
619a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                    pw.print("    Package "); pw.print(ops.packageName); pw.println(":");
620a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                    for (int j=0; j<ops.size(); j++) {
621a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                        Op op = ops.valueAt(j);
6225e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                        pw.print("      "); pw.print(AppOpsManager.opToName(op.op));
6235e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                        pw.print(": mode="); pw.print(op.mode);
6245e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                        if (op.time != 0) {
6255e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                            pw.print("; time="); TimeUtils.formatDuration(now-op.time, pw);
6265e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                            pw.print(" ago");
6275e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                        }
6285e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                        if (op.rejectTime != 0) {
6295e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                            pw.print("; rejectTime="); TimeUtils.formatDuration(now-op.rejectTime, pw);
6305e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                            pw.print(" ago");
6315e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn                        }
632a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                        if (op.duration == -1) {
633a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                            pw.println(" (running)");
634a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                        } else {
635a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                            pw.print("; duration=");
636a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                                    TimeUtils.formatDuration(op.duration, pw);
637a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                                    pw.println();
638a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                        }
639a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                    }
640a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                }
641a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
642a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
643a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
644a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn}
645