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