Merge "Work on issue #78480444: Start tracking uid state in app ops" into pi-dev
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index ab0001c..13389e3 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -109,6 +109,48 @@
*/
public static final int MODE_DEFAULT = 3;
+ /**
+ * Metrics about an op when its uid is persistent.
+ * @hide
+ */
+ public static final int UID_STATE_PERSISTENT = 0;
+
+ /**
+ * Metrics about an op when its uid is at the top.
+ * @hide
+ */
+ public static final int UID_STATE_TOP = 1;
+
+ /**
+ * Metrics about an op when its uid is running a foreground service.
+ * @hide
+ */
+ public static final int UID_STATE_FOREGROUND_SERVICE = 2;
+
+ /**
+ * Metrics about an op when its uid is in the foreground for any other reasons.
+ * @hide
+ */
+ public static final int UID_STATE_FOREGROUND = 3;
+
+ /**
+ * Metrics about an op when its uid is in the background for any reason.
+ * @hide
+ */
+ public static final int UID_STATE_BACKGROUND = 4;
+
+ /**
+ * Metrics about an op when its uid is cached.
+ * @hide
+ */
+ public static final int UID_STATE_CACHED = 5;
+
+ /**
+ * Number of uid states we track.
+ * @hide
+ */
+ public static final int _NUM_UID_STATE = 6;
+
// when adding one of these:
// - increment _NUM_OP
// - define an OPSTR_* constant (marked as @SystemApi)
@@ -1471,8 +1513,8 @@
public static class OpEntry implements Parcelable {
private final int mOp;
private final int mMode;
- private final long mTime;
- private final long mRejectTime;
+ private final long[] mTimes;
+ private final long[] mRejectTimes;
private final int mDuration;
private final int mProxyUid;
private final String mProxyPackageName;
@@ -1481,8 +1523,23 @@
int proxyUid, String proxyPackage) {
mOp = op;
mMode = mode;
- mTime = time;
- mRejectTime = rejectTime;
+ mTimes = new long[_NUM_UID_STATE];
+ mRejectTimes = new long[_NUM_UID_STATE];
+ mTimes[0] = time;
+ mRejectTimes[0] = rejectTime;
+ mDuration = duration;
+ mProxyUid = proxyUid;
+ mProxyPackageName = proxyPackage;
+ }
+
+ public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration,
+ int proxyUid, String proxyPackage) {
+ mOp = op;
+ mMode = mode;
+ mTimes = new long[_NUM_UID_STATE];
+ mRejectTimes = new long[_NUM_UID_STATE];
+ System.arraycopy(times, 0, mTimes, 0, _NUM_UID_STATE);
+ System.arraycopy(rejectTimes, 0, mRejectTimes, 0, _NUM_UID_STATE);
mDuration = duration;
mProxyUid = proxyUid;
mProxyPackageName = proxyPackage;
@@ -1497,11 +1554,31 @@
}
public long getTime() {
- return mTime;
+ long time = 0;
+ for (int i = 0; i < _NUM_UID_STATE; i++) {
+ if (mTimes[i] > time) {
+ time = mTimes[i];
+ }
+ }
+ return time;
+ }
+
+ public long getTimeFor(int uidState) {
+ return mTimes[uidState];
}
public long getRejectTime() {
- return mRejectTime;
+ long time = 0;
+ for (int i = 0; i < _NUM_UID_STATE; i++) {
+ if (mRejectTimes[i] > time) {
+ time = mTimes[i];
+ }
+ }
+ return time;
+ }
+
+ public long getRejectTimeFor(int uidState) {
+ return mRejectTimes[uidState];
}
public boolean isRunning() {
@@ -1509,7 +1586,7 @@
}
public int getDuration() {
- return mDuration == -1 ? (int)(System.currentTimeMillis()-mTime) : mDuration;
+ return mDuration;
}
public int getProxyUid() {
@@ -1529,8 +1606,8 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mOp);
dest.writeInt(mMode);
- dest.writeLong(mTime);
- dest.writeLong(mRejectTime);
+ dest.writeLongArray(mTimes);
+ dest.writeLongArray(mRejectTimes);
dest.writeInt(mDuration);
dest.writeInt(mProxyUid);
dest.writeString(mProxyPackageName);
@@ -1539,8 +1616,8 @@
OpEntry(Parcel source) {
mOp = source.readInt();
mMode = source.readInt();
- mTime = source.readLong();
- mRejectTime = source.readLong();
+ mTimes = source.createLongArray();
+ mRejectTimes = source.createLongArray();
mDuration = source.readInt();
mProxyUid = source.readInt();
mProxyPackageName = source.readString();
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index b860191..d818bd6 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -39,6 +39,7 @@
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.ShellCommand;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManagerInternal;
@@ -77,14 +78,24 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
+import static android.app.AppOpsManager.UID_STATE_CACHED;
+import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
+import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
+import static android.app.AppOpsManager._NUM_UID_STATE;
+import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
+import static android.app.AppOpsManager.UID_STATE_TOP;
+
public class AppOpsService extends IAppOpsService.Stub {
static final String TAG = "AppOps";
static final boolean DEBUG = false;
@@ -100,6 +111,64 @@
// Constant meaning that any UID should be matched when dispatching callbacks
private static final int UID_ANY = -2;
+ // Map from process states to the uid states we track.
+ private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
+ UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
+ UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
+ UID_STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
+ UID_STATE_FOREGROUND_SERVICE, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+ UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
+ UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+ UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
+ UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_BACKUP
+ UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_SERVICE
+ UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_RECEIVER
+ UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
+ UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
+ UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HOME
+ UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
+ UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
+ UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+ UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_RECENT
+ UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
+ UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT
+ };
+
+ static final String[] UID_STATE_NAMES = new String[] {
+ "pers ", // UID_STATE_PERSISTENT
+ "top ", // UID_STATE_TOP
+ "fgsvc", // UID_STATE_FOREGROUND_SERVICE
+ "fg ", // UID_STATE_FOREGROUND
+ "bg ", // UID_STATE_BACKGROUND
+ "cch ", // UID_STATE_CACHED
+ };
+
+ static final String[] UID_STATE_TIME_ATTRS = new String[] {
+ "tp", // UID_STATE_PERSISTENT
+ "tt", // UID_STATE_TOP
+ "tfs", // UID_STATE_FOREGROUND_SERVICE
+ "tf", // UID_STATE_FOREGROUND
+ "tb", // UID_STATE_BACKGROUND
+ "tc", // UID_STATE_CACHED
+ };
+
+ static final String[] UID_STATE_REJECT_ATTRS = new String[] {
+ "rp", // UID_STATE_PERSISTENT
+ "rt", // UID_STATE_TOP
+ "rfs", // UID_STATE_FOREGROUND_SERVICE
+ "rf", // UID_STATE_FOREGROUND
+ "rb", // UID_STATE_BACKGROUND
+ "rc", // UID_STATE_CACHED
+ };
+
+ static final String[] MODE_NAMES = new String[] {
+ "allow", // MODE_ALLOWED
+ "ignore", // MODE_IGNORED
+ "deny", // MODE_ERRORED
+ "default", // MODE_DEFAULT
+ };
+
Context mContext;
final AtomicFile mFile;
final Handler mHandler;
@@ -133,6 +202,8 @@
@VisibleForTesting
static final class UidState {
public final int uid;
+ public int state = UID_STATE_CACHED;
+ public int startNesting;
public ArrayMap<String, Ops> pkgOps;
public SparseIntArray opModes;
@@ -151,36 +222,51 @@
}
}
- public final static class Ops extends SparseArray<Op> {
- public final String packageName;
- public final UidState uidState;
- public final boolean isPrivileged;
+ final static class Ops extends SparseArray<Op> {
+ final String packageName;
+ final UidState uidState;
+ final boolean isPrivileged;
- public Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
+ Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
packageName = _packageName;
uidState = _uidState;
isPrivileged = _isPrivileged;
}
}
- public final static class Op {
- public final int uid;
- public final String packageName;
- public int proxyUid = -1;
- public String proxyPackageName;
- public final int op;
- public int mode;
- public int duration;
- public long time;
- public long rejectTime;
- public int nesting;
+ final static class Op {
+ final UidState uidState;
+ final int uid;
+ final String packageName;
+ final int op;
+ int proxyUid = -1;
+ String proxyPackageName;
+ int mode;
+ int duration;
+ long time[] = new long[_NUM_UID_STATE];
+ long rejectTime[] = new long[_NUM_UID_STATE];
+ int startNesting;
+ long startRealtime;
- public Op(int _uid, String _packageName, int _op) {
- uid = _uid;
+ Op(UidState _uidState, String _packageName, int _op) {
+ uidState = _uidState;
+ uid = _uidState.uid;
packageName = _packageName;
op = _op;
mode = AppOpsManager.opToDefaultMode(op);
}
+
+ boolean hasAnyTime() {
+ for (int i = 0; i < AppOpsManager._NUM_UID_STATE; i++) {
+ if (time[i] != 0) {
+ return true;
+ }
+ if (rejectTime[i] != 0) {
+ return true;
+ }
+ }
+ return false;
+ }
}
final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
@@ -189,13 +275,13 @@
final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
- public final class ModeCallback implements DeathRecipient {
+ final class ModeCallback implements DeathRecipient {
final IAppOpsCallback mCallback;
final int mWatchingUid;
final int mCallingUid;
final int mCallingPid;
- public ModeCallback(IAppOpsCallback callback, int watchingUid, int callingUid,
+ ModeCallback(IAppOpsCallback callback, int watchingUid, int callingUid,
int callingPid) {
mCallback = callback;
mWatchingUid = watchingUid;
@@ -222,7 +308,7 @@
return sb.toString();
}
- public void unlinkToDeath() {
+ void unlinkToDeath() {
mCallback.asBinder().unlinkToDeath(this, 0);
}
@@ -232,13 +318,13 @@
}
}
- public final class ActiveCallback implements DeathRecipient {
+ final class ActiveCallback implements DeathRecipient {
final IAppOpsActiveCallback mCallback;
final int mWatchingUid;
final int mCallingUid;
final int mCallingPid;
- public ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
+ ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
int callingPid) {
mCallback = callback;
mWatchingUid = watchingUid;
@@ -265,7 +351,7 @@
return sb.toString();
}
- public void destroy() {
+ void destroy() {
mCallback.asBinder().unlinkToDeath(this, 0);
}
@@ -277,12 +363,12 @@
final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
- public final class ClientState extends Binder implements DeathRecipient {
+ final class ClientState extends Binder implements DeathRecipient {
final ArrayList<Op> mStartedOps = new ArrayList<>();
final IBinder mAppToken;
final int mPid;
- public ClientState(IBinder appToken) {
+ ClientState(IBinder appToken) {
mAppToken = appToken;
mPid = Binder.getCallingPid();
// Watch only for remote processes dying
@@ -453,7 +539,7 @@
if (uid == op.uid && packageName.equals(op.packageName)) {
finishOperationLocked(op, /*finishNested*/ true);
client.mStartedOps.remove(j);
- if (op.nesting <= 0) {
+ if (op.startNesting <= 0) {
scheduleOpActiveChangedIfNeededLocked(op.op,
uid, packageName, false);
}
@@ -485,6 +571,31 @@
}
}
+ public void updateUidProcState(int uid, int procState) {
+ synchronized (this) {
+ final UidState uidState = getUidStateLocked(uid, true);
+ final int newState = PROCESS_STATE_TO_UID_STATE[procState];
+ if (uidState != null && uidState.state != newState) {
+ if (uidState.startNesting != 0) {
+ // There is some actively running operation... need to find it
+ // and appropriately update its state.
+ final long now = System.currentTimeMillis();
+ for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
+ final Ops ops = uidState.pkgOps.valueAt(i);
+ for (int j = ops.size() - 1; j >= 0; j--) {
+ final Op op = ops.valueAt(j);
+ if (op.startNesting > 0) {
+ op.time[uidState.state] = now;
+ op.time[newState] = now;
+ }
+ }
+ }
+ }
+ uidState.state = newState;
+ }
+ }
+ }
+
public void shutdown() {
Slog.w(TAG, "Writing app ops before shutdown...");
boolean doWrite = false;
@@ -501,12 +612,16 @@
private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
ArrayList<AppOpsManager.OpEntry> resOps = null;
+ final long elapsedNow = SystemClock.elapsedRealtime();
if (ops == null) {
- resOps = new ArrayList<AppOpsManager.OpEntry>();
+ resOps = new ArrayList<>();
for (int j=0; j<pkgOps.size(); j++) {
Op curOp = pkgOps.valueAt(j);
+ long duration = curOp.duration == -1
+ ? (elapsedNow - curOp.startRealtime)
+ : curOp.duration;
resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
- curOp.rejectTime, curOp.duration, curOp.proxyUid,
+ curOp.rejectTime, (int) duration, curOp.proxyUid,
curOp.proxyPackageName));
}
} else {
@@ -514,10 +629,13 @@
Op curOp = pkgOps.get(ops[j]);
if (curOp != null) {
if (resOps == null) {
- resOps = new ArrayList<AppOpsManager.OpEntry>();
+ resOps = new ArrayList<>();
}
+ long duration = curOp.duration == -1
+ ? (elapsedNow - curOp.startRealtime)
+ : curOp.duration;
resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
- curOp.rejectTime, curOp.duration, curOp.proxyUid,
+ curOp.rejectTime, (int) duration, curOp.proxyUid,
curOp.proxyPackageName));
}
}
@@ -628,7 +746,7 @@
}
private void pruneOp(Op op, int uid, String packageName) {
- if (op.time == 0 && op.rejectTime == 0) {
+ if (!op.hasAnyTime()) {
Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
false /* uidMismatchExpected */);
if (ops != null) {
@@ -946,7 +1064,7 @@
mOpModeWatchers.get(curOp.op));
callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
mPackageModeWatchers.get(packageName));
- if (curOp.time == 0 && curOp.rejectTime == 0) {
+ if (!curOp.hasAnyTime()) {
pkgOps.removeAt(j);
}
}
@@ -1212,24 +1330,25 @@
private int noteOperationUnchecked(int code, int uid, String packageName,
int proxyUid, String proxyPackageName) {
synchronized (this) {
- Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
+ final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
false /* uidMismatchExpected */);
if (ops == null) {
if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
+ " package " + packageName);
return AppOpsManager.MODE_ERRORED;
}
- Op op = getOpLocked(ops, code, true);
+ final Op op = getOpLocked(ops, code, true);
if (isOpRestrictedLocked(uid, code, packageName)) {
return AppOpsManager.MODE_IGNORED;
}
+ final UidState uidState = ops.uidState;
if (op.duration == -1) {
Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
- + " code " + code + " time=" + op.time + " duration=" + op.duration);
+ + " code " + code + " time=" + op.time[uidState.state]
+ + " duration=" + op.duration);
}
op.duration = 0;
final int switchCode = AppOpsManager.opToSwitch(code);
- UidState uidState = ops.uidState;
// If there is a non-default per UID policy (we set UID op mode only if
// non-default) it takes over, otherwise use the per package policy.
if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
@@ -1238,7 +1357,7 @@
if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + op.mode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ packageName);
- op.rejectTime = System.currentTimeMillis();
+ op.rejectTime[uidState.state] = System.currentTimeMillis();
return uidMode;
}
} else {
@@ -1247,14 +1366,14 @@
if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + op.mode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ packageName);
- op.rejectTime = System.currentTimeMillis();
+ op.rejectTime[uidState.state] = System.currentTimeMillis();
return switchOp.mode;
}
}
if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
+ " package " + packageName);
- op.time = System.currentTimeMillis();
- op.rejectTime = 0;
+ op.time[uidState.state] = System.currentTimeMillis();
+ op.rejectTime[uidState.state] = 0;
op.proxyUid = proxyUid;
op.proxyPackageName = proxyPackageName;
return AppOpsManager.MODE_ALLOWED;
@@ -1323,19 +1442,19 @@
}
ClientState client = (ClientState)token;
synchronized (this) {
- Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
+ final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
false /* uidMismatchExpected */);
if (ops == null) {
if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
+ " package " + resolvedPackageName);
return AppOpsManager.MODE_ERRORED;
}
- Op op = getOpLocked(ops, code, true);
+ final Op op = getOpLocked(ops, code, true);
if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
return AppOpsManager.MODE_IGNORED;
}
final int switchCode = AppOpsManager.opToSwitch(code);
- UidState uidState = ops.uidState;
+ final UidState uidState = ops.uidState;
// If there is a non-default per UID policy (we set UID op mode only if
// non-default) it takes over, otherwise use the per package policy.
if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
@@ -1345,7 +1464,7 @@
if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + op.mode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ resolvedPackageName);
- op.rejectTime = System.currentTimeMillis();
+ op.rejectTime[uidState.state] = System.currentTimeMillis();
return uidMode;
}
} else {
@@ -1355,19 +1474,21 @@
if (DEBUG) Slog.d(TAG, "startOperation: reject #" + op.mode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ resolvedPackageName);
- op.rejectTime = System.currentTimeMillis();
+ op.rejectTime[uidState.state] = System.currentTimeMillis();
return switchOp.mode;
}
}
if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
+ " package " + resolvedPackageName);
- if (op.nesting == 0) {
- op.time = System.currentTimeMillis();
- op.rejectTime = 0;
+ if (op.startNesting == 0) {
+ op.startRealtime = SystemClock.elapsedRealtime();
+ op.time[uidState.state] = System.currentTimeMillis();
+ op.rejectTime[uidState.state] = 0;
op.duration = -1;
scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
}
- op.nesting++;
+ op.startNesting++;
+ uidState.startNesting++;
if (client.mStartedOps != null) {
client.mStartedOps.add(op);
}
@@ -1415,7 +1536,7 @@
return;
}
finishOperationLocked(op, /*finishNested*/ false);
- if (op.nesting <= 0) {
+ if (op.startNesting <= 0) {
scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
}
}
@@ -1476,18 +1597,22 @@
}
void finishOperationLocked(Op op, boolean finishNested) {
- if (op.nesting <= 1 || finishNested) {
- if (op.nesting == 1 || finishNested) {
- op.duration = (int)(System.currentTimeMillis() - op.time);
- op.time += op.duration;
+ if (op.startNesting <= 1 || finishNested) {
+ if (op.startNesting == 1 || finishNested) {
+ op.duration = (int)(SystemClock.elapsedRealtime() - op.startRealtime);
+ op.time[op.uidState.state] = System.currentTimeMillis();
} else {
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);
+ + " duration=" + op.duration + " nesting=" + op.startNesting);
}
- op.nesting = 0;
+ if (op.startNesting >= 1) {
+ op.uidState.startNesting -= op.startNesting;
+ }
+ op.startNesting = 0;
} else {
- op.nesting--;
+ op.startNesting--;
+ op.uidState.startNesting--;
}
}
@@ -1617,7 +1742,7 @@
if (!edit) {
return null;
}
- op = new Op(ops.uidState.uid, ops.packageName, code);
+ op = new Op(ops.uidState, ops.packageName, code);
ops.put(code, op);
}
if (edit) {
@@ -1750,7 +1875,7 @@
if (ops != null) {
final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
- final Op copy = new Op(op.uid, op.packageName,
+ final Op copy = new Op(op.uidState, op.packageName,
AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
copy.mode = op.mode;
ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
@@ -1860,37 +1985,86 @@
String tagName = parser.getName();
if (tagName.equals("op")) {
- 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);
- }
- String time = parser.getAttributeValue(null, "t");
- if (time != null) {
- op.time = Long.parseLong(time);
- }
- time = parser.getAttributeValue(null, "r");
- if (time != null) {
- op.rejectTime = Long.parseLong(time);
- }
- String dur = parser.getAttributeValue(null, "d");
- if (dur != null) {
- op.duration = Integer.parseInt(dur);
- }
- String proxyUid = parser.getAttributeValue(null, "pu");
- if (proxyUid != null) {
- op.proxyUid = Integer.parseInt(proxyUid);
- }
- String proxyPackageName = parser.getAttributeValue(null, "pp");
- if (proxyPackageName != null) {
- op.proxyPackageName = proxyPackageName;
- }
-
UidState uidState = getUidStateLocked(uid, true);
if (uidState.pkgOps == null) {
uidState.pkgOps = new ArrayMap<>();
}
+ Op op = new Op(uidState, pkgName,
+ Integer.parseInt(parser.getAttributeValue(null, "n")));
+
+ for (int i = parser.getAttributeCount()-1; i >= 0; i--) {
+ final String name = parser.getAttributeName(i);
+ final String value = parser.getAttributeValue(i);
+ switch (name) {
+ case "m":
+ op.mode = Integer.parseInt(value);
+ break;
+ case "d":
+ op.duration = Integer.parseInt(value);
+ break;
+ case "pu":
+ op.proxyUid = Integer.parseInt(value);
+ break;
+ case "pp":
+ op.proxyPackageName = value;
+ break;
+ case "tp":
+ op.time[AppOpsManager.UID_STATE_PERSISTENT] = Long.parseLong(value);
+ break;
+ case "tt":
+ op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
+ break;
+ case "tfs":
+ op.time[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
+ = Long.parseLong(value);
+ break;
+ case "tf":
+ op.time[AppOpsManager.UID_STATE_FOREGROUND] = Long.parseLong(value);
+ break;
+ case "tb":
+ op.time[AppOpsManager.UID_STATE_BACKGROUND] = Long.parseLong(value);
+ break;
+ case "tc":
+ op.time[AppOpsManager.UID_STATE_CACHED] = Long.parseLong(value);
+ break;
+ case "rp":
+ op.rejectTime[AppOpsManager.UID_STATE_PERSISTENT]
+ = Long.parseLong(value);
+ break;
+ case "rt":
+ op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
+ break;
+ case "rfs":
+ op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
+ = Long.parseLong(value);
+ break;
+ case "rf":
+ op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND]
+ = Long.parseLong(value);
+ break;
+ case "rb":
+ op.rejectTime[AppOpsManager.UID_STATE_BACKGROUND]
+ = Long.parseLong(value);
+ break;
+ case "rc":
+ op.rejectTime[AppOpsManager.UID_STATE_CACHED]
+ = Long.parseLong(value);
+ break;
+ case "t":
+ // Backwards compat.
+ op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
+ break;
+ case "r":
+ // Backwards compat.
+ op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
+ break;
+ default:
+ Slog.w(TAG, "Unknown attribute in 'op' tag: " + name);
+ break;
+ }
+ }
+
Ops ops = uidState.pkgOps.get(pkgName);
if (ops == null) {
ops = new Ops(pkgName, uidState, isPrivileged);
@@ -1977,13 +2151,17 @@
if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
out.attribute(null, "m", Integer.toString(op.getMode()));
}
- long time = op.getTime();
- if (time != 0) {
- out.attribute(null, "t", Long.toString(time));
- }
- time = op.getRejectTime();
- if (time != 0) {
- out.attribute(null, "r", Long.toString(time));
+ for (int k = 0; k < _NUM_UID_STATE; k++) {
+ final long time = op.getTimeFor(k);
+ if (time != 0) {
+ out.attribute(null, UID_STATE_TIME_ATTRS[k],
+ Long.toString(time));
+ }
+ final long rejectTime = op.getRejectTimeFor(k);
+ if (rejectTime != 0) {
+ out.attribute(null, UID_STATE_REJECT_ATTRS[k],
+ Long.toString(rejectTime));
+ }
}
int dur = op.getDuration();
if (dur != 0) {
@@ -2069,15 +2247,10 @@
}
int strModeToMode(String modeStr, PrintWriter err) {
- switch (modeStr) {
- case "allow":
- return AppOpsManager.MODE_ALLOWED;
- case "deny":
- return AppOpsManager.MODE_ERRORED;
- case "ignore":
- return AppOpsManager.MODE_IGNORED;
- case "default":
- return AppOpsManager.MODE_DEFAULT;
+ for (int i = MODE_NAMES.length - 1; i >= 0; i--) {
+ if (MODE_NAMES[i].equals(modeStr)) {
+ return i;
+ }
}
try {
return Integer.parseInt(modeStr);
@@ -2466,6 +2639,34 @@
pw.println(" none");
}
+ private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
+ long now, SimpleDateFormat sdf, Date date) {
+ boolean hasTime = false;
+ for (int i = 0; i < _NUM_UID_STATE; i++) {
+ if (times[i] != 0) {
+ hasTime = true;
+ break;
+ }
+ }
+ if (!hasTime) {
+ return;
+ }
+ boolean first = true;
+ for (int i = 0; i < _NUM_UID_STATE; i++) {
+ if (times[i] != 0) {
+ pw.print(first ? firstPrefix : prefix);
+ first = false;
+ pw.print(UID_STATE_NAMES[i]);
+ pw.print(" = ");
+ date.setTime(times[i]);
+ pw.print(sdf.format(date));
+ pw.print(" (");
+ TimeUtils.formatDuration(times[i]-now, pw);
+ pw.println(")");
+ }
+ }
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
@@ -2491,6 +2692,9 @@
synchronized (this) {
pw.println("Current AppOps Service state:");
final long now = System.currentTimeMillis();
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+ final Date date = new Date();
boolean needSep = false;
if (mOpModeWatchers.size() > 0) {
needSep = true;
@@ -2585,7 +2789,7 @@
pw.print(" "); pw.print(op);
pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
Restriction r = restrictions.valueAt(i);
- pw.print(": mode="); pw.println(r.mode);
+ pw.print(": mode="); pw.println(MODE_NAMES[r.mode]);
if (!r.exceptionPackages.isEmpty()) {
pw.println(" Exceptions:");
for (int j=0; j<r.exceptionPackages.size(); j++) {
@@ -2602,6 +2806,12 @@
UidState uidState = mUidStates.valueAt(i);
pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
+ pw.print(" state=");
+ pw.println(UID_STATE_NAMES[uidState.state]);
+ if (uidState.startNesting != 0) {
+ pw.print(" startNesting=");
+ pw.println(uidState.startNesting);
+ }
needSep = true;
SparseIntArray opModes = uidState.opModes;
@@ -2611,7 +2821,7 @@
final int code = opModes.keyAt(j);
final int mode = opModes.valueAt(j);
pw.print(" "); pw.print(AppOpsManager.opToName(code));
- pw.print(": mode="); pw.println(mode);
+ pw.print(": mode="); pw.println(MODE_NAMES[mode]);
}
}
@@ -2625,21 +2835,26 @@
for (int j=0; j<ops.size(); j++) {
Op op = ops.valueAt(j);
pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
- pw.print(": mode="); pw.print(op.mode);
- if (op.time != 0) {
- pw.print("; time="); TimeUtils.formatDuration(now-op.time, pw);
- pw.print(" ago");
- }
- if (op.rejectTime != 0) {
- pw.print("; rejectTime="); TimeUtils.formatDuration(now-op.rejectTime, pw);
- pw.print(" ago");
- }
+ pw.print(" ("); pw.print(MODE_NAMES[op.mode]); pw.println("): ");
+ dumpTimesLocked(pw,
+ " Access: ",
+ " ", op.time, now, sdf, date);
+ dumpTimesLocked(pw,
+ " Reject: ",
+ " ", op.rejectTime, now, sdf, date);
if (op.duration == -1) {
- pw.print(" (running)");
+ pw.print(" Running start at: ");
+ TimeUtils.formatDuration(nowElapsed-op.startRealtime, pw);
+ pw.println();
} else if (op.duration != 0) {
- pw.print("; duration="); TimeUtils.formatDuration(op.duration, pw);
+ pw.print(" duration=");
+ TimeUtils.formatDuration(op.duration, pw);
+ pw.println();
}
- pw.println();
+ if (op.startNesting != 0) {
+ pw.print(" startNesting=");
+ pw.println(op.startNesting);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ae26c23..7170119 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -22929,6 +22929,7 @@
private void noteUidProcessState(final int uid, final int state) {
mBatteryStatsService.noteUidProcessState(uid, state);
+ mAppOpsService.updateUidProcState(uid, state);
if (mTrackingAssociations) {
for (int i1=0, N1=mAssociations.size(); i1<N1; i1++) {
ArrayMap<ComponentName, SparseArray<ArrayMap<String, Association>>> targetComponents
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index f74ac47..5db20b0 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -621,7 +621,7 @@
private boolean clipboardAccessAllowed(int op, String callingPackage, int callingUid) {
// Check the AppOp.
- if (mAppOps.checkOp(op, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ if (mAppOps.noteOp(op, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
return false;
}
try {