diff options
4 files changed, 422 insertions, 129 deletions
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index ab0001ca8c3c..13389e35943c 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -109,6 +109,48 @@ public class AppOpsManager {       */      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 class AppOpsManager {      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 @@ public class AppOpsManager {                  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 class AppOpsManager {          }          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 class AppOpsManager {          }          public int getDuration() { -            return mDuration == -1 ? (int)(System.currentTimeMillis()-mTime) : mDuration; +            return mDuration;          }          public int getProxyUid() { @@ -1529,8 +1606,8 @@ public class AppOpsManager {          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 @@ public class AppOpsManager {          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 b8601910497a..d818bd6580f7 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.ResultReceiver;  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.FileOutputStream;  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 @@ public class AppOpsService extends IAppOpsService.Stub {      // 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 @@ public class AppOpsService extends IAppOpsService.Stub {      @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 class AppOpsService extends IAppOpsService.Stub {          }      } -    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; - -        public Op(int _uid, String _packageName, int _op) { -            uid = _uid; +    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; + +        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 @@ public class AppOpsService extends IAppOpsService.Stub {      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 @@ public class AppOpsService extends IAppOpsService.Stub {              return sb.toString();          } -        public void unlinkToDeath() { +        void unlinkToDeath() {              mCallback.asBinder().unlinkToDeath(this, 0);          } @@ -232,13 +318,13 @@ public class AppOpsService extends IAppOpsService.Stub {          }      } -    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 @@ public class AppOpsService extends IAppOpsService.Stub {              return sb.toString();          } -        public void destroy() { +        void destroy() {              mCallback.asBinder().unlinkToDeath(this, 0);          } @@ -277,12 +363,12 @@ public class AppOpsService extends IAppOpsService.Stub {      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 @@ public class AppOpsService extends IAppOpsService.Stub {                      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 class AppOpsService extends IAppOpsService.Stub {          }      } +    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 @@ public class AppOpsService extends IAppOpsService.Stub {      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 @@ public class AppOpsService extends IAppOpsService.Stub {                  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 @@ public class AppOpsService extends IAppOpsService.Stub {      }      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 @@ public class AppOpsService extends IAppOpsService.Stub {                                      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 @@ public class AppOpsService extends IAppOpsService.Stub {      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 @@ public class AppOpsService extends IAppOpsService.Stub {                      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 @@ public class AppOpsService extends IAppOpsService.Stub {                      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 @@ public class AppOpsService extends IAppOpsService.Stub {          }          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 @@ public class AppOpsService extends IAppOpsService.Stub {                      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 @@ public class AppOpsService extends IAppOpsService.Stub {                      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 @@ public class AppOpsService extends IAppOpsService.Stub {                  return;              }              finishOperationLocked(op, /*finishNested*/ false); -            if (op.nesting <= 0) { +            if (op.startNesting <= 0) {                  scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);              }          } @@ -1476,18 +1597,22 @@ public class AppOpsService extends IAppOpsService.Stub {      }      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); +            } +            if (op.startNesting >= 1) { +                op.uidState.startNesting -= op.startNesting;              } -            op.nesting = 0; +            op.startNesting = 0;          } else { -            op.nesting--; +            op.startNesting--; +            op.uidState.startNesting--;          }      } @@ -1617,7 +1742,7 @@ public class AppOpsService extends IAppOpsService.Stub {              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 @@ public class AppOpsService extends IAppOpsService.Stub {                  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 @@ public class AppOpsService extends IAppOpsService.Stub {              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 @@ public class AppOpsService extends IAppOpsService.Stub {                              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 @@ public class AppOpsService extends IAppOpsService.Stub {          }          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 @@ public class AppOpsService extends IAppOpsService.Stub {          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 @@ public class AppOpsService extends IAppOpsService.Stub {          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 @@ public class AppOpsService extends IAppOpsService.Stub {                          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 @@ public class AppOpsService extends IAppOpsService.Stub {                  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 @@ public class AppOpsService extends IAppOpsService.Stub {                          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 @@ public class AppOpsService extends IAppOpsService.Stub {                      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(); +                        } +                        if (op.startNesting != 0) { +                            pw.print("          startNesting="); +                            pw.println(op.startNesting);                          } -                        pw.println();                      }                  }              } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ae26c2377f28..7170119a9765 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 @@ public class ActivityManagerService extends IActivityManager.Stub      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 f74ac4709890..5db20b029105 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 @@ public class ClipboardService extends SystemService {      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 {  |