diff options
Diffstat (limited to 'services/java/com/android/server/AppOpsService.java')
-rw-r--r-- | services/java/com/android/server/AppOpsService.java | 182 |
1 files changed, 154 insertions, 28 deletions
diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java index 7a107e7760df..6b4d24843d5b 100644 --- a/services/java/com/android/server/AppOpsService.java +++ b/services/java/com/android/server/AppOpsService.java @@ -40,6 +40,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.util.ArrayMap; import android.util.AtomicFile; import android.util.Log; import android.util.Slog; @@ -97,6 +98,8 @@ public class AppOpsService extends IAppOpsService.Stub { } public final static class Op { + public final int uid; + public final String packageName; public final int op; public int mode; public int duration; @@ -104,7 +107,9 @@ public class AppOpsService extends IAppOpsService.Stub { public long rejectTime; public int nesting; - public Op(int _op) { + public Op(int _uid, String _packageName, int _op) { + uid = _uid; + packageName = _packageName; op = _op; mode = AppOpsManager.MODE_ALLOWED; } @@ -112,10 +117,10 @@ public class AppOpsService extends IAppOpsService.Stub { final SparseArray<ArrayList<Callback>> mOpModeWatchers = new SparseArray<ArrayList<Callback>>(); - final HashMap<String, ArrayList<Callback>> mPackageModeWatchers - = new HashMap<String, ArrayList<Callback>>(); - final HashMap<IBinder, Callback> mModeWatchers - = new HashMap<IBinder, Callback>(); + final ArrayMap<String, ArrayList<Callback>> mPackageModeWatchers + = new ArrayMap<String, ArrayList<Callback>>(); + final ArrayMap<IBinder, Callback> mModeWatchers + = new ArrayMap<IBinder, Callback>(); public final class Callback implements DeathRecipient { final IAppOpsCallback mCallback; @@ -138,6 +143,47 @@ public class AppOpsService extends IAppOpsService.Stub { } } + final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<IBinder, ClientState>(); + + public final class ClientState extends Binder implements DeathRecipient { + final IBinder mAppToken; + final int mPid; + final ArrayList<Op> mStartedOps; + + public ClientState(IBinder appToken) { + mAppToken = appToken; + mPid = Binder.getCallingPid(); + if (appToken instanceof Binder) { + // For local clients, there is no reason to track them. + mStartedOps = null; + } else { + mStartedOps = new ArrayList<Op>(); + try { + mAppToken.linkToDeath(this, 0); + } catch (RemoteException e) { + } + } + } + + @Override + public String toString() { + return "ClientState{" + + "mAppToken=" + mAppToken + + ", " + (mStartedOps != null ? ("pid=" + mPid) : "local") + + '}'; + } + + @Override + public void binderDied() { + synchronized (AppOpsService.this) { + for (int i=mStartedOps.size()-1; i>=0; i--) { + finishOperationLocked(mStartedOps.get(i)); + } + mClients.remove(mAppToken); + } + } + } + public AppOpsService(File storagePath) { mFile = new AtomicFile(storagePath); mHandler = new Handler(); @@ -380,21 +426,18 @@ public class AppOpsService extends IAppOpsService.Stub { Callback cb = mModeWatchers.remove(callback.asBinder()); if (cb != null) { cb.unlinkToDeath(); - for (int i=0; i<mOpModeWatchers.size(); i++) { + for (int i=mOpModeWatchers.size()-1; i>=0; i--) { ArrayList<Callback> cbs = mOpModeWatchers.valueAt(i); cbs.remove(cb); if (cbs.size() <= 0) { mOpModeWatchers.removeAt(i); } } - if (mPackageModeWatchers.size() > 0) { - Iterator<ArrayList<Callback>> it = mPackageModeWatchers.values().iterator(); - while (it.hasNext()) { - ArrayList<Callback> cbs = it.next(); - cbs.remove(cb); - if (cbs.size() <= 0) { - it.remove(); - } + for (int i=mPackageModeWatchers.size()-1; i>=0; i--) { + ArrayList<Callback> cbs = mPackageModeWatchers.valueAt(i); + cbs.remove(cb); + if (cbs.size() <= 0) { + mPackageModeWatchers.removeAt(i); } } } @@ -402,6 +445,18 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override + public IBinder getToken(IBinder clientToken) { + synchronized (this) { + ClientState cs = mClients.get(clientToken); + if (cs == null) { + cs = new ClientState(clientToken); + mClients.put(clientToken, cs); + } + return cs; + } + } + + @Override public int checkOperation(int code, int uid, String packageName) { verifyIncomingUid(uid); verifyIncomingOp(code); @@ -448,9 +503,10 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override - public int startOperation(int code, int uid, String packageName) { + public int startOperation(IBinder token, int code, int uid, String packageName) { verifyIncomingUid(uid); verifyIncomingOp(code); + ClientState client = (ClientState)token; synchronized (this) { Ops ops = getOpsLocked(uid, packageName, true); if (ops == null) { @@ -475,32 +531,46 @@ public class AppOpsService extends IAppOpsService.Stub { op.duration = -1; } op.nesting++; + if (client.mStartedOps != null) { + client.mStartedOps.add(op); + } return AppOpsManager.MODE_ALLOWED; } } @Override - public void finishOperation(int code, int uid, String packageName) { + public void finishOperation(IBinder token, int code, int uid, String packageName) { verifyIncomingUid(uid); verifyIncomingOp(code); + ClientState client = (ClientState)token; synchronized (this) { Op op = getOpLocked(code, uid, packageName, true); if (op == null) { return; } - if (op.nesting <= 1) { - if (op.nesting == 1) { - op.duration = (int)(System.currentTimeMillis() - op.time); - op.time += op.duration; - } else { - Slog.w(TAG, "Finishing op nesting under-run: uid " + uid + " pkg " + packageName - + " code " + code + " time=" + op.time + " duration=" + op.duration - + " nesting=" + op.nesting); + if (client.mStartedOps != null) { + if (!client.mStartedOps.remove(op)) { + throw new IllegalStateException("Operation not started: uid" + op.uid + + " pkg=" + op.packageName + " op=" + op.op); } - op.nesting = 0; + } + finishOperationLocked(op); + } + } + + void finishOperationLocked(Op op) { + if (op.nesting <= 1) { + if (op.nesting == 1) { + op.duration = (int)(System.currentTimeMillis() - op.time); + op.time += op.duration; } else { - op.nesting--; + Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg " + + op.packageName + " code " + op.op + " time=" + op.time + + " duration=" + op.duration + " nesting=" + op.nesting); } + op.nesting = 0; + } else { + op.nesting--; } } @@ -601,7 +671,7 @@ public class AppOpsService extends IAppOpsService.Stub { if (!edit) { return null; } - op = new Op(code); + op = new Op(ops.uid, ops.packageName, code); ops.put(code, op); } if (edit) { @@ -711,7 +781,7 @@ public class AppOpsService extends IAppOpsService.Stub { String tagName = parser.getName(); if (tagName.equals("op")) { - Op op = new Op(Integer.parseInt(parser.getAttributeValue(null, "n"))); + Op op = new Op(uid, pkgName, Integer.parseInt(parser.getAttributeValue(null, "n"))); String mode = parser.getAttributeValue(null, "m"); if (mode != null) { op.mode = Integer.parseInt(mode); @@ -831,6 +901,62 @@ public class AppOpsService extends IAppOpsService.Stub { synchronized (this) { pw.println("Current AppOps Service state:"); final long now = System.currentTimeMillis(); + boolean needSep = false; + if (mOpModeWatchers.size() > 0) { + needSep = true; + pw.println(" Op mode watchers:"); + for (int i=0; i<mOpModeWatchers.size(); i++) { + pw.print(" Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i))); + pw.println(":"); + ArrayList<Callback> callbacks = mOpModeWatchers.valueAt(i); + for (int j=0; j<callbacks.size(); j++) { + pw.print(" #"); pw.print(j); pw.print(": "); + pw.println(callbacks.get(j)); + } + } + } + if (mPackageModeWatchers.size() > 0) { + needSep = true; + pw.println(" Package mode watchers:"); + for (int i=0; i<mPackageModeWatchers.size(); i++) { + pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i)); + pw.println(":"); + ArrayList<Callback> callbacks = mPackageModeWatchers.valueAt(i); + for (int j=0; j<callbacks.size(); j++) { + pw.print(" #"); pw.print(j); pw.print(": "); + pw.println(callbacks.get(j)); + } + } + } + if (mModeWatchers.size() > 0) { + needSep = true; + pw.println(" All mode watchers:"); + for (int i=0; i<mModeWatchers.size(); i++) { + pw.print(" "); pw.print(mModeWatchers.keyAt(i)); + pw.print(" -> "); pw.println(mModeWatchers.valueAt(i)); + } + } + if (mClients.size() > 0) { + needSep = true; + pw.println(" Clients:"); + for (int i=0; i<mClients.size(); i++) { + pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":"); + ClientState cs = mClients.valueAt(i); + pw.print(" "); pw.println(cs); + if (cs.mStartedOps != null && cs.mStartedOps.size() > 0) { + pw.println(" Started ops:"); + for (int j=0; j<cs.mStartedOps.size(); j++) { + Op op = cs.mStartedOps.get(j); + pw.print(" "); pw.print("uid="); pw.print(op.uid); + pw.print(" pkg="); pw.print(op.packageName); + pw.print(" op="); pw.println(AppOpsManager.opToName(op.op)); + } + } + } + } + if (needSep) { + pw.println(); + } for (int i=0; i<mUidOps.size(); i++) { pw.print(" Uid "); UserHandle.formatUid(pw, mUidOps.keyAt(i)); pw.println(":"); HashMap<String, Ops> pkgOps = mUidOps.valueAt(i); |