AppOpsService.java revision 72e3983d38f656cfa8c7a038eb80bdd9ea06768e
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;
41a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.util.Slog;
42a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.util.SparseArray;
43a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport android.util.TimeUtils;
4435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport android.util.Xml;
45a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
46a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornimport com.android.internal.app.IAppOpsService;
4735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport com.android.internal.util.FastXmlSerializer;
4835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport com.android.internal.util.XmlUtils;
4935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
5035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport org.xmlpull.v1.XmlPullParser;
5135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport org.xmlpull.v1.XmlPullParserException;
5235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackbornimport org.xmlpull.v1.XmlSerializer;
53a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
54a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackbornpublic class AppOpsService extends IAppOpsService.Stub {
55a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    static final String TAG = "AppOps";
5635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    static final boolean DEBUG = false;
5735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
5835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    // Write at most every 30 minutes.
5935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
60a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
61a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    Context mContext;
62a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    final AtomicFile mFile;
6335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    final Handler mHandler;
6435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
6535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    boolean mWriteScheduled;
6635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    final Runnable mWriteRunner = new Runnable() {
6735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        public void run() {
6835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            synchronized (AppOpsService.this) {
6935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                mWriteScheduled = false;
7035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
7135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    @Override protected Void doInBackground(Void... params) {
7235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        writeState();
7335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        return null;
7435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
7535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                };
7635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
7735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
7835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        }
7935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    };
80a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
81a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    final SparseArray<HashMap<String, Ops>> mUidOps
82a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            = new SparseArray<HashMap<String, Ops>>();
83a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
84a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    final static class Ops extends SparseArray<Op> {
85a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        public final String packageName;
8635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        public final int uid;
87a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
8835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        public Ops(String _packageName, int _uid) {
89a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            packageName = _packageName;
9035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            uid = _uid;
91a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
92a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
93a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
94a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    final static class Op {
95a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        public final int op;
96a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        public int duration;
97a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        public long time;
9835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        public int nesting;
99a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
100a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        public Op(int _op) {
101a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            op = _op;
102a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
103a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
104a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
10535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    public AppOpsService(File storagePath) {
10635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        mFile = new AtomicFile(storagePath);
10735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        mHandler = new Handler();
10835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        readState();
109a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
110a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
111a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    public void publish(Context context) {
112a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        mContext = context;
113a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
114a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
115a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
116a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    public void shutdown() {
117a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        Slog.w(TAG, "Writing app ops before shutdown...");
11835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        boolean doWrite = false;
11935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        synchronized (this) {
12035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (mWriteScheduled) {
12135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                mWriteScheduled = false;
12235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                doWrite = true;
12335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
12435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        }
12535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        if (doWrite) {
12635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            writeState();
12735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        }
128a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
129a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
13072e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn    private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
13172e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        ArrayList<AppOpsManager.OpEntry> resOps = null;
13272e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        if (ops == null) {
13372e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            resOps = new ArrayList<AppOpsManager.OpEntry>();
13472e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            for (int j=0; j<pkgOps.size(); j++) {
13572e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                Op curOp = pkgOps.valueAt(j);
13672e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.time,
13772e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                        curOp.duration));
13872e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            }
13972e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        } else {
14072e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            for (int j=0; j<ops.length; j++) {
14172e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                Op curOp = pkgOps.get(ops[j]);
14272e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                if (curOp != null) {
14372e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                    if (resOps == null) {
14472e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                        resOps = new ArrayList<AppOpsManager.OpEntry>();
14572e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                    }
14672e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                    resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.time,
14772e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                            curOp.duration));
14872e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                }
14972e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            }
15072e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        }
15172e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        return resOps;
15272e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn    }
15372e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn
154a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    @Override
15535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
15635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
15735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                Binder.getCallingPid(), Binder.getCallingUid(), null);
15835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        ArrayList<AppOpsManager.PackageOps> res = null;
159a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        synchronized (this) {
16035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            for (int i=0; i<mUidOps.size(); i++) {
16135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                HashMap<String, Ops> packages = mUidOps.valueAt(i);
16235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                for (Ops pkgOps : packages.values()) {
16372e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                    ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
16435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    if (resOps != null) {
16535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        if (res == null) {
16635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            res = new ArrayList<AppOpsManager.PackageOps>();
16735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        }
16835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
16935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                                pkgOps.packageName, pkgOps.uid, resOps);
17035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        res.add(resPackage);
17135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
17235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                }
173a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
174a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
17535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        return res;
176a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
177a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
178a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    @Override
17972e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn    public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
18072e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            int[] ops) {
18172e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
18272e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                Binder.getCallingPid(), Binder.getCallingUid(), null);
18372e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        synchronized (this) {
18472e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            Ops pkgOps = getOpsLocked(uid, packageName, false);
18572e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            if (pkgOps == null) {
18672e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                return null;
18772e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            }
18872e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
18972e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            if (resOps == null) {
19072e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                return null;
19172e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            }
19272e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
19372e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
19472e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn                    pkgOps.packageName, pkgOps.uid, resOps);
19572e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            res.add(resPackage);
19672e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            return res;
19772e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        }
19872e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn    }
19972e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn
20072e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn    @Override
20135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    public int checkOperation(int code, int uid, String packageName) {
202a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        uid = handleIncomingUid(uid);
203a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        synchronized (this) {
20435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            Op op = getOpLocked(code, uid, packageName, false);
205a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            if (op == null) {
20635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                return AppOpsManager.MODE_ALLOWED;
207a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
208a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
209a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        return AppOpsManager.MODE_ALLOWED;
210a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
211a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
212a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    @Override
21335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    public int noteOperation(int code, int uid, String packageName) {
214a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        uid = handleIncomingUid(uid);
215a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        synchronized (this) {
21635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            Op op = getOpLocked(code, uid, packageName, true);
217a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            if (op == null) {
21835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                return AppOpsManager.MODE_IGNORED;
219a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
22035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (op.duration == -1) {
22135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
222a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                        + " code " + code + " time=" + op.time + " duration=" + op.duration);
223a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
22435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            op.time = System.currentTimeMillis();
22535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            op.duration = 0;
226a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
22735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        return AppOpsManager.MODE_ALLOWED;
228a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
229a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
230a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    @Override
23135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    public int startOperation(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) {
236a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                return AppOpsManager.MODE_IGNORED;
237a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
23835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (op.nesting == 0) {
23935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                op.time = System.currentTimeMillis();
24035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                op.duration = -1;
241a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
24235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            op.nesting++;
243a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
244a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        return AppOpsManager.MODE_ALLOWED;
245a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
246a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
247a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    @Override
24835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    public void finishOperation(int code, int uid, String packageName) {
249a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        uid = handleIncomingUid(uid);
250a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        synchronized (this) {
25135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            Op op = getOpLocked(code, uid, packageName, true);
252a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            if (op == null) {
253a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                return;
254a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
25535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (op.nesting <= 1) {
25635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                if (op.nesting == 1) {
25735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    op.duration = (int)(System.currentTimeMillis() - op.time);
25835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } else {
25935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Slog.w(TAG, "Finishing op nesting under-run: uid " + uid + " pkg " + packageName
26035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        + " code " + code + " time=" + op.time + " duration=" + op.duration
26135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        + " nesting=" + op.nesting);
26235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                }
263e799175b6ba3aadd972f4b861758d675d1f93987Dianne Hackborn                op.nesting = 0;
26435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            } else {
26535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                op.nesting--;
266a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
267a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
268a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
269a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
270a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    private int handleIncomingUid(int uid) {
271a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        if (uid == Binder.getCallingUid()) {
272a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            return uid;
273a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
274a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        if (Binder.getCallingPid() == Process.myPid()) {
275a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            return uid;
276a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
277a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
278a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                Binder.getCallingPid(), Binder.getCallingUid(), null);
279a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        return uid;
280a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
281a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
28272e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn    private Ops getOpsLocked(int uid, String packageName, boolean edit) {
283a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        HashMap<String, Ops> pkgOps = mUidOps.get(uid);
284a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        if (pkgOps == null) {
28535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (!edit) {
28635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                return null;
28735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
288a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            pkgOps = new HashMap<String, Ops>();
289a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            mUidOps.put(uid, pkgOps);
290a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
291a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        Ops ops = pkgOps.get(packageName);
292a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        if (ops == null) {
29335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (!edit) {
29435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                return null;
29535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
296a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            // This is the first time we have seen this package name under this uid,
297a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            // so let's make sure it is valid.
298002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn            final long ident = Binder.clearCallingIdentity();
299002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn            try {
300002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                int pkgUid = -1;
301a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                try {
302002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                    pkgUid = mContext.getPackageManager().getPackageUid(packageName,
303002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                            UserHandle.getUserId(uid));
304002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                } catch (NameNotFoundException e) {
305a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                }
306002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                if (pkgUid != uid) {
307002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                    // Oops!  The package name is not valid for the uid they are calling
308002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                    // under.  Abort.
309002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                    Slog.w(TAG, "Bad call: specified package " + packageName
310002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                            + " under uid " + uid + " but it is really " + pkgUid);
311002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                    return null;
312002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                }
313002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn            } finally {
314002a54e2291eeb3a3fd0b6b3f9dbc96a7c805062Dianne Hackborn                Binder.restoreCallingIdentity(ident);
315a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
31635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            ops = new Ops(packageName, uid);
317a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            pkgOps.put(packageName, ops);
318a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
31972e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        return ops;
32072e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn    }
32172e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn
32272e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn    private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
32372e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        Ops ops = getOpsLocked(uid, packageName, edit);
32472e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        if (ops == null) {
32572e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn            return null;
32672e3983d38f656cfa8c7a038eb80bdd9ea06768eDianne Hackborn        }
327a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        Op op = ops.get(code);
328a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        if (op == null) {
32935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (!edit) {
33035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                return null;
33135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
332a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            op = new Op(code);
333a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            ops.put(code, op);
334a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
33535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        if (edit && !mWriteScheduled) {
33635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            mWriteScheduled = true;
33735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
33835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        }
339a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        return op;
340a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
341a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
34235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    void readState() {
34335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        synchronized (mFile) {
34435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            synchronized (this) {
34535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                FileInputStream stream;
34635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                try {
34735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    stream = mFile.openRead();
34835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } catch (FileNotFoundException e) {
34935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
35035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    return;
35135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                }
35235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                boolean success = false;
35335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                try {
35435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    XmlPullParser parser = Xml.newPullParser();
35535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    parser.setInput(stream, null);
35635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    int type;
35735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    while ((type = parser.next()) != XmlPullParser.START_TAG
35835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            && type != XmlPullParser.END_DOCUMENT) {
35935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        ;
36035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
36135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
36235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    if (type != XmlPullParser.START_TAG) {
36335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        throw new IllegalStateException("no start tag found");
36435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
36535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
36635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    int outerDepth = parser.getDepth();
36735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
36835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
36935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
37035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            continue;
37135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        }
37235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
37335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        String tagName = parser.getName();
37435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        if (tagName.equals("pkg")) {
37535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            readPackage(parser);
37635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        } else {
37735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            Slog.w(TAG, "Unknown element under <app-ops>: "
37835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                                    + parser.getName());
37935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            XmlUtils.skipCurrentTag(parser);
38035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        }
38135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
38235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    success = true;
38335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } catch (IllegalStateException e) {
38435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Slog.w(TAG, "Failed parsing " + e);
38535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } catch (NullPointerException e) {
38635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Slog.w(TAG, "Failed parsing " + e);
38735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } catch (NumberFormatException e) {
38835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Slog.w(TAG, "Failed parsing " + e);
38935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } catch (XmlPullParserException e) {
39035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Slog.w(TAG, "Failed parsing " + e);
39135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } catch (IOException e) {
39235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Slog.w(TAG, "Failed parsing " + e);
39335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } catch (IndexOutOfBoundsException e) {
39435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Slog.w(TAG, "Failed parsing " + e);
39535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                } finally {
39635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    if (!success) {
39735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        mUidOps.clear();
39835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
39935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    try {
40035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        stream.close();
40135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    } catch (IOException e) {
40235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
40335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                }
40435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
40535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        }
40635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    }
40735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
40835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    void readPackage(XmlPullParser parser) throws NumberFormatException,
40935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            XmlPullParserException, IOException {
41035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        String pkgName = parser.getAttributeValue(null, "n");
41135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        int outerDepth = parser.getDepth();
41235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        int type;
41335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
41435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
41535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
41635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                continue;
41735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
41835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
41935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            String tagName = parser.getName();
42035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (tagName.equals("uid")) {
42135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                readUid(parser, pkgName);
42235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            } else {
42335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                Slog.w(TAG, "Unknown element under <pkg>: "
42435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        + parser.getName());
42535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                XmlUtils.skipCurrentTag(parser);
42635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
42735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        }
42835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    }
42935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
43035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
43135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            XmlPullParserException, IOException {
43235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
43335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        int outerDepth = parser.getDepth();
43435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        int type;
43535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
43635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
43735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
43835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                continue;
43935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
44035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
44135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            String tagName = parser.getName();
44235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (tagName.equals("op")) {
44335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                Op op = new Op(Integer.parseInt(parser.getAttributeValue(null, "n")));
44435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                op.time = Long.parseLong(parser.getAttributeValue(null, "t"));
44535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                op.duration = Integer.parseInt(parser.getAttributeValue(null, "d"));
44635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                HashMap<String, Ops> pkgOps = mUidOps.get(uid);
44735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                if (pkgOps == null) {
44835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    pkgOps = new HashMap<String, Ops>();
44935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    mUidOps.put(uid, pkgOps);
45035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                }
45135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                Ops ops = pkgOps.get(pkgName);
45235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                if (ops == null) {
45335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    ops = new Ops(pkgName, uid);
45435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    pkgOps.put(pkgName, ops);
45535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                }
45635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                ops.put(op.op, op);
45735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            } else {
45835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                Slog.w(TAG, "Unknown element under <pkg>: "
45935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        + parser.getName());
46035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                XmlUtils.skipCurrentTag(parser);
46135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
46235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        }
46335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    }
46435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
46535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    void writeState() {
46635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        synchronized (mFile) {
46735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
46835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
46935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            FileOutputStream stream;
47035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            try {
47135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                stream = mFile.startWrite();
47235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            } catch (IOException e) {
47335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                Slog.w(TAG, "Failed to write state: " + e);
47435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                return;
47535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
47635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
47735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            try {
47835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                XmlSerializer out = new FastXmlSerializer();
47935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                out.setOutput(stream, "utf-8");
48035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                out.startDocument(null, true);
48135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                out.startTag(null, "app-ops");
48235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
48335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                if (allOps != null) {
48435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    String lastPkg = null;
48535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    for (int i=0; i<allOps.size(); i++) {
48635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        AppOpsManager.PackageOps pkg = allOps.get(i);
48735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        if (!pkg.getPackageName().equals(lastPkg)) {
48835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            if (lastPkg != null) {
48935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                                out.endTag(null, "pkg");
49035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            }
49135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            lastPkg = pkg.getPackageName();
49235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            out.startTag(null, "pkg");
49335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            out.attribute(null, "n", lastPkg);
49435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        }
49535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        out.startTag(null, "uid");
49635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        out.attribute(null, "n", Integer.toString(pkg.getUid()));
49735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        List<AppOpsManager.OpEntry> ops = pkg.getOps();
49835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        for (int j=0; j<ops.size(); j++) {
49935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            AppOpsManager.OpEntry op = ops.get(j);
50035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            out.startTag(null, "op");
50135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            out.attribute(null, "n", Integer.toString(op.getOp()));
50235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            out.attribute(null, "t", Long.toString(op.getTime()));
50335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            out.attribute(null, "d", Integer.toString(op.getDuration()));
50435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            out.endTag(null, "op");
50535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        }
50635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        out.endTag(null, "uid");
50735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
50835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    if (lastPkg != null) {
50935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        out.endTag(null, "pkg");
51035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    }
51135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                }
51235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
51335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                out.endTag(null, "app-ops");
51435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                out.endDocument();
51535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                mFile.finishWrite(stream);
51635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            } catch (IOException e) {
51735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                Slog.w(TAG, "Failed to write state, restoring backup.", e);
51835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                mFile.failWrite(stream);
51935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            }
52035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        }
52135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    }
52235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn
523a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    @Override
524a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
525a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
526a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                != PackageManager.PERMISSION_GRANTED) {
527a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            pw.println("Permission Denial: can't dump ApOps service from from pid="
528a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                    + Binder.getCallingPid()
529a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                    + ", uid=" + Binder.getCallingUid());
530a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            return;
531a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
532a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn
533a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        synchronized (this) {
534a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            pw.println("Current AppOps Service state:");
535a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            for (int i=0; i<mUidOps.size(); i++) {
536a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                pw.print("  Uid "); UserHandle.formatUid(pw, mUidOps.keyAt(i)); pw.println(":");
537a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                HashMap<String, Ops> pkgOps = mUidOps.valueAt(i);
538a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                for (Ops ops : pkgOps.values()) {
539a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                    pw.print("    Package "); pw.print(ops.packageName); pw.println(":");
540a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                    for (int j=0; j<ops.size(); j++) {
541a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                        Op op = ops.valueAt(j);
542a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                        pw.print("      "); pw.print(AppOpsManager.opToString(op.op));
543a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                        pw.print(": time=");
544a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                        TimeUtils.formatDuration(System.currentTimeMillis()-op.time, pw);
545a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                        pw.print(" ago");
546a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                        if (op.duration == -1) {
547a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                            pw.println(" (running)");
548a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                        } else {
549a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                            pw.print("; duration=");
550a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                                    TimeUtils.formatDuration(op.duration, pw);
551a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                                    pw.println();
552a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                        }
553a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                    }
554a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn                }
555a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn            }
556a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn        }
557a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn    }
558a06de0f29b58df9246779cc4bfd8f06f7205ddb6Dianne Hackborn}
559