Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --cc services/core/java/com/android/server/AppOpsService.java
- index 786d757557d,2a7c9d66a7c..00000000000
- --- a/services/core/java/com/android/server/AppOpsService.java
- +++ b/services/core/java/com/android/server/AppOpsService.java
- @@@ -17,13 -20,15 +20,18 @@@
- package com.android.server;
- import android.Manifest;
- --import android.app.ActivityManager;
- import android.app.ActivityThread;
- import android.app.AppGlobals;
- import android.app.AppOpsManager;
- +import android.app.AppOpsManagerInternal;
- ++import android.app.Dialog;
- ++import android.content.BroadcastReceiver;
- +import android.content.ContentResolver;
- + import android.app.Dialog;
- + import android.content.BroadcastReceiver;
- import android.content.Context;
- + import android.content.Intent;
- + import android.content.IntentFilter;
- import android.content.pm.ApplicationInfo;
- import android.content.pm.IPackageManager;
- import android.content.pm.PackageManager;
- @@@ -69,7 -69,7 +79,8 @@@ import com.android.internal.util.DumpUt
- import com.android.internal.util.FastXmlSerializer;
- import com.android.internal.util.Preconditions;
- import com.android.internal.util.XmlUtils;
- +import com.android.internal.util.function.pooled.PooledLambda;
- + import com.android.server.PermissionDialogReqQueue.PermissionDialogReq;
- import libcore.util.EmptyArray;
- @@@ -116,67 -100,17 +127,73 @@@ public class AppOpsService extends IApp
- // Write at most every 30 minutes.
- static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
- + // 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
- ++ "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
- + };
- +
- + // Location of policy file.
- + static final String DEFAULT_POLICY_FILE = "/system/etc/appops_policy.xml";
- +
- Context mContext;
- final AtomicFile mFile;
- final Handler mHandler;
- + final Looper mLooper;
- + final boolean mStrictEnable;
- + AppOpsPolicy mPolicy;
- + private PowerManager mPowerManager;
- + private final AppOpsManagerInternalImpl mAppOpsManagerInternal
- + = new AppOpsManagerInternalImpl();
- +
- boolean mWriteScheduled;
- boolean mFastWriteScheduled;
- final Runnable mWriteRunner = new Runnable() {
- @@@ -205,109 -136,17 +222,117 @@@
- */
- private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
- + SparseIntArray mProfileOwners;
- +
- + private Runnable mSuSessionChangedRunner = new Runnable() {
- + @Override
- + public void run() {
- + mContext.sendBroadcastAsUser(new Intent(AppOpsManager.ACTION_SU_SESSION_CHANGED),
- + UserHandle.ALL);
- + }
- + };
- +
- + /**
- + * All times are in milliseconds. These constants are kept synchronized with the system
- + * global Settings. Any access to this class or its fields should be done while
- + * holding the AppOpsService lock.
- + */
- + private final class Constants extends ContentObserver {
- + // Key names stored in the settings value.
- + private static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
- + private static final String KEY_FG_SERVICE_STATE_SETTLE_TIME
- + = "fg_service_state_settle_time";
- + private static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
- +
- + /**
- + * How long we want for a drop in uid state from top to settle before applying it.
- + * @see Settings.Global#APP_OPS_CONSTANTS
- + * @see #KEY_TOP_STATE_SETTLE_TIME
- + */
- + public long TOP_STATE_SETTLE_TIME;
- +
- + /**
- + * How long we want for a drop in uid state from foreground to settle before applying it.
- + * @see Settings.Global#APP_OPS_CONSTANTS
- + * @see #KEY_FG_SERVICE_STATE_SETTLE_TIME
- + */
- + public long FG_SERVICE_STATE_SETTLE_TIME;
- +
- + /**
- + * How long we want for a drop in uid state from background to settle before applying it.
- + * @see Settings.Global#APP_OPS_CONSTANTS
- + * @see #KEY_BG_STATE_SETTLE_TIME
- + */
- + public long BG_STATE_SETTLE_TIME;
- +
- + private final KeyValueListParser mParser = new KeyValueListParser(',');
- + private ContentResolver mResolver;
- +
- + public Constants(Handler handler) {
- + super(handler);
- + updateConstants();
- + }
- +
- + public void startMonitoring(ContentResolver resolver) {
- + mResolver = resolver;
- + mResolver.registerContentObserver(
- + Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
- + false, this);
- + updateConstants();
- + }
- +
- + @Override
- + public void onChange(boolean selfChange, Uri uri) {
- + updateConstants();
- + }
- - private static final class UidState {
- + private void updateConstants() {
- + String value = mResolver != null ? Settings.Global.getString(mResolver,
- + Settings.Global.APP_OPS_CONSTANTS) : "";
- +
- + synchronized (AppOpsService.this) {
- + try {
- + mParser.setString(value);
- + } catch (IllegalArgumentException e) {
- + // Failed to parse the settings string, log this and move on
- + // with defaults.
- + Slog.e(TAG, "Bad app ops settings", e);
- + }
- + TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
- + KEY_TOP_STATE_SETTLE_TIME, 30 * 1000L);
- + FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
- + KEY_FG_SERVICE_STATE_SETTLE_TIME, 10 * 1000L);
- + BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
- + KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
- + }
- + }
- +
- + void dump(PrintWriter pw) {
- + pw.println(" Settings:");
- +
- + pw.print(" "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("=");
- + TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw);
- + pw.println();
- + pw.print(" "); pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME); pw.print("=");
- + TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
- + pw.println();
- + pw.print(" "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("=");
- + TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
- + pw.println();
- + }
- + }
- +
- + private final Constants mConstants;
- +
- + @VisibleForTesting
- + static final class UidState {
- public final int uid;
- +
- + public int state = UID_STATE_CACHED;
- + public int pendingState = UID_STATE_CACHED;
- + public long pendingStateCommitTime;
- +
- + public int startNesting;
- public ArrayMap<String, Ops> pkgOps;
- public SparseIntArray opModes;
- @@@ -395,65 -177,45 +420,74 @@@
- }
- }
- - 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;
- -
- - Op(UidState _uidState, String _packageName, int _op) {
- + public int noteOpCount;
- + public int startOpCount;
- + public PermissionDialogReqQueue dialogReqQueue;
- + final ArrayList<IBinder> clientTokens;
- + public int allowedCount;
- + public int ignoredCount;
- + public int delayedCount;
- +
- - public Op(int _uid, String _packageName, int _op, int _mode) {
- - uid = _uid;
- ++ Op(UidState _uidState, String _packageName, int _op, int _mode) {
- + uidState = _uidState;
- + uid = _uidState.uid;
- packageName = _packageName;
- op = _op;
- - mode = AppOpsManager.opToDefaultMode(op);
- + mode = _mode;
- + dialogReqQueue = new PermissionDialogReqQueue();
- + clientTokens = new ArrayList<IBinder>();
- }
- +
- + 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;
- + }
- +
- + int getMode() {
- + return uidState.evalMode(mode);
- + }
- }
- - final SparseArray<ArraySet<Callback>> mOpModeWatchers = new SparseArray<>();
- - final ArrayMap<String, ArraySet<Callback>> mPackageModeWatchers = new ArrayMap<>();
- - final ArrayMap<IBinder, Callback> mModeWatchers = new ArrayMap<>();
- + final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
- + final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
- + final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
- + final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
- final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
- - public final class Callback implements DeathRecipient {
- + final class ModeCallback implements DeathRecipient {
- final IAppOpsCallback mCallback;
- + final int mWatchingUid;
- + final int mFlags;
- + final int mCallingUid;
- + final int mCallingPid;
- - public Callback(IAppOpsCallback callback) {
- + ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
- + int callingPid) {
- mCallback = callback;
- + mWatchingUid = watchingUid;
- + mFlags = flags;
- + mCallingUid = callingUid;
- + mCallingPid = callingPid;
- try {
- mCallback.asBinder().linkToDeath(this, 0);
- } catch (RemoteException e) {
- @@@ -575,16 -282,17 +616,19 @@@
- public AppOpsService(File storagePath, Handler handler) {
- LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
- - mFile = new AtomicFile(storagePath);
- + mFile = new AtomicFile(storagePath, "appops");
- mHandler = handler;
- + mConstants = new Constants(mHandler);
- + mLooper = Looper.myLooper();
- + mStrictEnable = AppOpsManager.isStrictEnable();
- readState();
- }
- public void publish(Context context) {
- mContext = context;
- + readPolicy();
- ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
- + LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
- }
- public void systemReady() {
- @@@ -807,33 -483,24 +887,33 @@@
- 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);
- + final boolean running = curOp.duration == -1;
- + long duration = running
- + ? (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, running, curOp.proxyUid,
- - curOp.proxyPackageName));
- + curOp.proxyPackageName, curOp.allowedCount, curOp.ignoredCount));
- }
- } else {
- for (int j=0; j<ops.length; j++) {
- Op curOp = pkgOps.get(ops[j]);
- if (curOp != null) {
- if (resOps == null) {
- - resOps = new ArrayList<AppOpsManager.OpEntry>();
- + resOps = new ArrayList<>();
- }
- + final boolean running = curOp.duration == -1;
- + final long duration = running
- + ? (elapsedNow - curOp.startRealtime)
- + : curOp.duration;
- resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
- - curOp.rejectTime, curOp.duration, curOp.proxyUid,
- - curOp.proxyPackageName, curOp.allowedCount, curOp.ignoredCount));
- + curOp.rejectTime, (int) duration, running, curOp.proxyUid,
- - curOp.proxyPackageName));
- ++ curOp.proxyPackageName), curOp.allowedCount, curOp.ignoredCount);
- }
- }
- }
- @@@ -1271,11 -911,12 +1352,13 @@@
- Ops pkgOps = ent.getValue();
- for (int j=pkgOps.size()-1; j>=0; j--) {
- Op curOp = pkgOps.valueAt(j);
- + int defaultMode = getDefaultMode(curOp.op, curOp.uid,
- + curOp.packageName);
- if (AppOpsManager.opAllowsReset(curOp.op)
- - && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
- - curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
- + && curOp.mode != defaultMode) {
- + curOp.mode = defaultMode;
- changed = true;
- + uidChanged = true;
- callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
- mOpModeWatchers.get(curOp.op));
- callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
- @@@ -1564,23 -1172,22 +1647,25 @@@
- private int noteOperationUnchecked(int code, int uid, String packageName,
- int proxyUid, String proxyPackageName) {
- + PermissionDialogReq req = null;
- synchronized (this) {
- - Ops ops = getOpsRawLocked(uid, packageName, true);
- + final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
- + false /* uidMismatchExpected */);
- if (ops == null) {
- - if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
- + 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)) {
- + op.ignoredCount++;
- 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);
- @@@ -1597,79 -1205,92 +1682,144 @@@
- }
- } else {
- final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
- - if (switchOp.mode != AppOpsManager.MODE_ALLOWED
- - && switchOp.mode != AppOpsManager.MODE_ASK) {
- - if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
- - + switchCode + " (" + code + ") uid " + uid + " package "
- - + packageName);
- - op.rejectTime = System.currentTimeMillis();
- + final int mode = switchOp.getMode();
- - if (mode != AppOpsManager.MODE_ALLOWED) {
- ++ if (mode != AppOpsManager.MODE_ALLOWED && mode != AppOpsManager.MODE_ASK) {
- + if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
- + + switchCode + " (" + code + ") uid " + uid + " package "
- + + packageName);
- + op.rejectTime[uidState.state] = System.currentTimeMillis();
- + op.ignoredCount++;
- - return switchOp.mode;
- - } else if (switchOp.mode == AppOpsManager.MODE_ASK) {
- + return mode;
- ++ } else if (mode == AppOpsManager.MODE_ASK) {
- + if (Looper.myLooper() == mLooper) {
- + Log.e(TAG,
- + "noteOperation: This method will deadlock if called from the main thread. (Code: "
- + + code
- + + " uid: "
- + + uid
- + + " package: "
- + + packageName + ")");
- - return switchOp.mode;
- ++ return mode;
- + }
- +
- + if (DEBUG) {
- + Log.d(TAG, "Package " + op.packageName + " has " + op.noteOpCount
- + + " requests and " + op.startOpCount + " start requests with "
- + + op.ignoredCount + " ignored at " + op.time +
- + " with a duration of "
- + + op.duration + " while being delayed " + op.delayedCount +
- + " times");
- + Log.d(TAG, "Total pkops for " + ops.packageName + " "
- + + ops.uidState.pkgOps.size());
- + }
- +
- + // First drop all request events if the device is not interactive, next
- + // check what the global pkg ops count for the package,
- + // then check op scoped count. High frequency request ops will be delayed until
- + // their delay count ceiling is met. This is to mitigate the overloading the
- + // main activity manager service handler and having watchdog kill our service.
- + // Google play services likes to share its uid with numerous packages to avoid
- + // having to grant permissions from the users perspective and thus is the worst
- + // example of overloading this queue -- so, to not encourage bad behavior,
- + // we move them to the back of the line. NOTE: these values are magic, and may need
- + // tuning. Ideally we'd want a ringbuffer or token bucket here to do proper rate
- + // limiting.
- + final boolean isInteractive = mPowerManager.isInteractive();
- + if (isInteractive &&
- + (ops.uidState.pkgOps.size() < AppOpsPolicy.RATE_LIMIT_OPS_TOTAL_PKG_COUNT
- + && op.noteOpCount < AppOpsPolicy.RATE_LIMIT_OP_COUNT
- + || op.delayedCount > AppOpsPolicy.RATE_LIMIT_OP_DELAY_CEILING)) {
- +
- + // Reset delayed count, most ops will never need this
- + if (op.delayedCount > 0) {
- + if (DEBUG) Log.d(TAG, "Resetting delayed count for " + op.packageName);
- + op.delayedCount = 0;
- + }
- +
- + op.noteOpCount++;
- + req = askOperationLocked(code, uid, packageName, switchOp);
- + } else {
- + if (isInteractive) {
- + op.delayedCount++;
- + }
- + op.ignoredCount++;
- + return AppOpsManager.MODE_IGNORED;
- + }
- }
- }
- - if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
- - + " package " + packageName);
- - op.time[uidState.state] = System.currentTimeMillis();
- - op.rejectTime[uidState.state] = 0;
- - op.proxyUid = proxyUid;
- - op.proxyPackageName = proxyPackageName;
- - return AppOpsManager.MODE_ALLOWED;
- + if (req == null) {
- - if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
- ++ 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;
- + broadcastOpIfNeeded(code);
- + op.allowedCount++;
- + return AppOpsManager.MODE_ALLOWED;
- + }
- }
- +
- + int result = req.get();
- + broadcastOpIfNeeded(code);
- + return result;
- }
- @Override
- - public int startOperation(IBinder token, int code, int uid, String packageName) {
- + public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
- + int watchedUid = -1;
- + final int callingUid = Binder.getCallingUid();
- + final int callingPid = Binder.getCallingPid();
- + if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
- + != PackageManager.PERMISSION_GRANTED) {
- + watchedUid = callingUid;
- + }
- + if (ops != null) {
- + Preconditions.checkArrayElementsInRange(ops, 0,
- + AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
- + }
- + if (callback == null) {
- + return;
- + }
- + synchronized (this) {
- + SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
- + if (callbacks == null) {
- + callbacks = new SparseArray<>();
- + mActiveWatchers.put(callback.asBinder(), callbacks);
- + }
- + final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
- + callingUid, callingPid);
- + for (int op : ops) {
- + callbacks.put(op, activeCallback);
- + }
- + }
- + }
- +
- + @Override
- + public void stopWatchingActive(IAppOpsActiveCallback callback) {
- + if (callback == null) {
- + return;
- + }
- + synchronized (this) {
- + final SparseArray<ActiveCallback> activeCallbacks =
- + mActiveWatchers.remove(callback.asBinder());
- + if (activeCallbacks == null) {
- + return;
- + }
- + final int callbackCount = activeCallbacks.size();
- + for (int i = 0; i < callbackCount; i++) {
- + // Apps ops are mapped to a singleton
- + if (i == 0) {
- + activeCallbacks.valueAt(i).destroy();
- + }
- + }
- + }
- + }
- +
- + @Override
- + public int startOperation(IBinder token, int code, int uid, String packageName,
- + boolean startIfModeDefault) {
- + final PermissionDialogReq req;
- verifyIncomingUid(uid);
- verifyIncomingOp(code);
- String resolvedPackageName = resolvePackageName(uid, packageName);
- @@@ -1685,53 -1305,67 +1835,78 @@@
- + " package " + resolvedPackageName);
- return AppOpsManager.MODE_ERRORED;
- }
- - Op op = getOpLocked(ops, code, true);
- + final Op op = getOpLocked(ops, code, true);
- if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
- + op.ignoredCount++;
- return AppOpsManager.MODE_IGNORED;
- }
- final int switchCode = AppOpsManager.opToSwitch(code);
- - UidState uidState = ops.uidState;
- - if (uidState.opModes != null) {
- - final int uidMode = uidState.opModes.get(switchCode);
- - if (uidMode != AppOpsManager.MODE_ALLOWED) {
- - if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
- + 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) {
- + final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
- - if (uidMode != AppOpsManager.MODE_ALLOWED
- ++ if (uidMode != AppOpsManager.MODE_ALLOWED && mode != AppOpsManager.MODE_ASK
- + && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
- + if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
- + switchCode + " (" + code + ") uid " + uid + " package "
- + resolvedPackageName);
- - op.rejectTime = System.currentTimeMillis();
- + op.rejectTime[uidState.state] = System.currentTimeMillis();
- ++ op.ignoredCount++;
- return uidMode;
- }
- + } else {
- + final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
- + final int mode = switchOp.getMode();
- - if (mode != AppOpsManager.MODE_ALLOWED
- ++ if (mode != AppOpsManager.MODE_ALLOWED && mode != AppOpsManager.MODE_ASK
- + && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
- + if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
- + + switchCode + " (" + code + ") uid " + uid + " package "
- + + resolvedPackageName);
- + op.rejectTime[uidState.state] = System.currentTimeMillis();
- ++ op.ignoredCount++;
- + return mode;
- + }
- }
- - if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
- - + " package " + resolvedPackageName);
- - 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.startNesting++;
- - uidState.startNesting++;
- - if (client.mStartedOps != null) {
- - client.mStartedOps.add(op);
- - final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
- - if (switchOp.mode != AppOpsManager.MODE_ALLOWED
- - && switchOp.mode != AppOpsManager.MODE_ASK) {
- - if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code "
- - + switchCode + " (" + code + ") uid " + uid + " package "
- - + resolvedPackageName);
- - op.rejectTime = System.currentTimeMillis();
- - op.ignoredCount++;
- - return switchOp.mode;
- - } else if (switchOp.mode == AppOpsManager.MODE_ALLOWED) {
- - if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code
- - + " uid " + uid + " package " + resolvedPackageName);
- - if (op.nesting == 0) {
- - op.time = System.currentTimeMillis();
- - op.rejectTime = 0;
- ++ if (mode == AppOpsManager.MODE_ALLOWED) {
- ++ if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
- ++ + " package " + resolvedPackageName);
- ++ if (op.startNesting == 0) {
- ++ op.startRealtime = SystemClock.elapsedRealtime();
- ++ op.time[uidState.state] = System.currentTimeMillis();
- ++ op.rejectTime[uidState.state] = 0;
- + op.duration = -1;
- + op.allowedCount++;
- ++ scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
- + }
- - op.nesting++;
- ++ op.startNesting++;
- ++ uidState.startNesting++;
- + if (client.mStartedOps != null) {
- + client.mStartedOps.add(op);
- + }
- + broadcastOpIfNeeded(code);
- + return AppOpsManager.MODE_ALLOWED;
- + } else {
- + if (Looper.myLooper() == mLooper) {
- + Log.e(TAG,
- + "startOperation: This method will deadlock if called from the main thread. (Code: "
- + + code
- + + " uid: "
- + + uid
- + + " package: "
- + + resolvedPackageName + ")");
- + return switchOp.mode;
- + }
- + op.startOpCount++;
- + IBinder clientToken = client.mAppToken;
- + op.clientTokens.add(clientToken);
- + req = askOperationLocked(code, uid, resolvedPackageName, switchOp);
- }
- }
- +
- - return AppOpsManager.MODE_ALLOWED;
- + int result = req.get();
- + broadcastOpIfNeeded(code);
- + return result;
- }
- @Override
- @@@ -1751,78 -1385,15 +1926,79 @@@
- if (op == null) {
- return;
- }
- - if (client.mStartedOps != null) {
- - if (!client.mStartedOps.remove(op)) {
- - throw new IllegalStateException("Operation not started: uid" + op.uid
- - + " pkg=" + op.packageName + " op=" + op.op);
- + if (!client.mStartedOps.remove(op)) {
- + // We finish ops when packages get removed to guarantee no dangling
- + // started ops. However, some part of the system may asynchronously
- + // finish ops for an already gone package. Hence, finishing an op
- + // for a non existing package is fine and we don't log as a wtf.
- + final long identity = Binder.clearCallingIdentity();
- + try {
- + if (LocalServices.getService(PackageManagerInternal.class).getPackageUid(
- + resolvedPackageName, 0, UserHandle.getUserId(uid)) < 0) {
- + Slog.i(TAG, "Finishing op=" + AppOpsManager.opToName(code)
- + + " for non-existing package=" + resolvedPackageName
- + + " in uid=" + uid);
- + return;
- + }
- + } finally {
- + Binder.restoreCallingIdentity(identity);
- + }
- + Slog.wtf(TAG, "Operation not started: uid=" + op.uid + " pkg="
- + + op.packageName + " op=" + AppOpsManager.opToName(op.op));
- + return;
- + }
- + finishOperationLocked(op, /*finishNested*/ false);
- + if (op.startNesting <= 0) {
- + scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
- + }
- + }
- + }
- +
- + private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
- + boolean active) {
- + ArraySet<ActiveCallback> dispatchedCallbacks = null;
- + final int callbackListCount = mActiveWatchers.size();
- + for (int i = 0; i < callbackListCount; i++) {
- + final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
- + ActiveCallback callback = callbacks.get(code);
- + if (callback != null) {
- + if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
- + continue;
- + }
- + if (dispatchedCallbacks == null) {
- + dispatchedCallbacks = new ArraySet<>();
- + }
- + dispatchedCallbacks.add(callback);
- + }
- + }
- + if (dispatchedCallbacks == null) {
- + return;
- + }
- + mHandler.sendMessage(PooledLambda.obtainMessage(
- + AppOpsService::notifyOpActiveChanged,
- + this, dispatchedCallbacks, code, uid, packageName, active));
- + }
- +
- + private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
- + int code, int uid, String packageName, boolean active) {
- + // There are components watching for mode changes such as window manager
- + // and location manager which are in our process. The callbacks in these
- + // components may require permissions our remote caller does not have.
- + final long identity = Binder.clearCallingIdentity();
- + try {
- + final int callbackCount = callbacks.size();
- + for (int i = 0; i < callbackCount; i++) {
- + final ActiveCallback callback = callbacks.valueAt(i);
- + try {
- + callback.mCallback.opActiveChanged(code, uid, packageName, active);
- + } catch (RemoteException e) {
- + /* do nothing */
- }
- }
- - finishOperationLocked(op);
- + } finally {
- + Binder.restoreCallingIdentity(identity);
- }
- + broadcastOpIfNeeded(code);
- }
- @Override
- @@@ -2030,7 -1553,8 +2211,8 @@@
- if (!edit) {
- return null;
- }
- - op = new Op(ops.uidState, ops.packageName, code);
- + mode = getDefaultMode(code, ops.uidState.uid, ops.packageName);
- - op = new Op(ops.uidState.uid, ops.packageName, code, mode);
- ++ op = new Op(ops.uidState, ops.packageName, code, mode);
- ops.put(code, op);
- }
- if (edit) {
- @@@ -2278,86 -1741,66 +2460,111 @@@
- String tagName = parser.getName();
- if (tagName.equals("op")) {
- + int code = Integer
- + .parseInt(parser.getAttributeValue(null, "n"));
- + // use op name string if it exists
- + String codeNameStr = parser.getAttributeValue(null, "ns");
- + if (codeNameStr != null) {
- + // returns OP_NONE if it could not be mapped
- + code = AppOpsManager.nameToOp(codeNameStr);
- + }
- + // skip op codes that are out of bounds
- + if (code == AppOpsManager.OP_NONE
- + || code >= AppOpsManager._NUM_OP) {
- + continue;
- + }
- - Op op = new Op(uid, pkgName, code, AppOpsManager.MODE_ERRORED);
- - String mode = parser.getAttributeValue(null, "m");
- - if (mode != null) {
- - op.mode = Integer.parseInt(mode);
- - } else {
- - String sDefualtMode = parser.getAttributeValue(null, "dm");
- - int defaultMode;
- - if (sDefualtMode != null) {
- - defaultMode = Integer.parseInt(sDefualtMode);
- - } else {
- - defaultMode = getDefaultMode(code, uid, pkgName);
- - }
- - op.mode = defaultMode;
- - }
- - 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;
- - }
- - String allowed = parser.getAttributeValue(null, "ac");
- - if (allowed != null) {
- - op.allowedCount = Integer.parseInt(allowed);
- - }
- - String ignored = parser.getAttributeValue(null, "ic");
- - if (ignored != null) {
- - op.ignoredCount = Integer.parseInt(ignored);
- - }
- 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")));
- ++ Op op = new Op(uidState, pkgName, code, AppOpsManager.MODE_ERRORED);
- +
- + for (int i = parser.getAttributeCount()-1; i >= 0; i--) {
- + final String name = parser.getAttributeName(i);
- + final String value = parser.getAttributeValue(i);
- + switch (name) {
- ++ case "ac":
- ++ op.allowedCount = Integer.parseInt(value);
- ++ break;
- + case "m":
- + op.mode = Integer.parseInt(value);
- + break;
- ++ case "dm":
- ++ if (value != null) {
- ++ op.mode = Integer.parseInt(value);
- ++ } else {
- ++ op.mode = getDefaultMode(code, uidState.uid, pkgName);
- ++ }
- ++ break;
- + case "d":
- + op.duration = Integer.parseInt(value);
- + break;
- ++ case "ic":
- ++ op.ignoredCount = 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);
- @@@ -2445,20 -1882,21 +2652,25 @@@
- AppOpsManager.OpEntry op = ops.get(j);
- out.startTag(null, "op");
- out.attribute(null, "n", Integer.toString(op.getOp()));
- - if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
- + out.attribute(null, "ns", AppOpsManager.opToName(op.getOp()));
- + int defaultMode = getDefaultMode(op.getOp(),
- + pkg.getUid(), pkg.getPackageName());
- + if (op.getMode() != defaultMode) {
- out.attribute(null, "m", Integer.toString(op.getMode()));
- + } else {
- + out.attribute(null, "dm", Integer.toString(defaultMode));
- }
- - 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.getLastTimeFor(k);
- + if (time != 0) {
- + out.attribute(null, UID_STATE_TIME_ATTRS[k],
- + Long.toString(time));
- + }
- + final long rejectTime = op.getLastRejectTimeFor(k);
- + if (rejectTime != 0) {
- + out.attribute(null, UID_STATE_REJECT_ATTRS[k],
- + Long.toString(rejectTime));
- + }
- }
- int dur = op.getDuration();
- if (dur != 0) {
- @@@ -3566,8 -2718,176 +3786,176 @@@
- }
- }
- + final class AskRunnable implements Runnable {
- + final int code;
- + final int uid;
- + final String packageName;
- + final Op op;
- + final PermissionDialogReq request;
- +
- + public AskRunnable(int code, int uid, String packageName, Op op,
- + PermissionDialogReq request) {
- + super();
- + this.code = code;
- + this.uid = uid;
- + this.packageName = packageName;
- + this.op = op;
- + this.request = request;
- + }
- +
- + @Override
- + public void run() {
- + PermissionDialog permDialog = null;
- + synchronized (AppOpsService.this) {
- + Log.e(TAG, "Creating dialog box");
- + op.dialogReqQueue.register(request);
- + if (op.dialogReqQueue.getDialog() == null) {
- + permDialog = new PermissionDialog(mContext,
- + AppOpsService.this, code, uid, packageName);
- + op.dialogReqQueue.setDialog(permDialog);
- + }
- + }
- + if (permDialog != null) {
- + permDialog.show();
- + }
- + }
- + }
- +
- + private PermissionDialogReq askOperationLocked(int code, int uid,
- + String packageName, Op op) {
- + PermissionDialogReq request = new PermissionDialogReq();
- + mHandler.post(new AskRunnable(code, uid, packageName, op, request));
- + return request;
- + }
- +
- + private int getDefaultMode(int code, int uid, String packageName) {
- + int mode = AppOpsManager.opToDefaultMode(code,
- + isStrict(code, uid, packageName));
- + if (AppOpsManager.isStrictOp(code) && mPolicy != null) {
- + int policyMode = mPolicy.getDefualtMode(code, packageName);
- + if (policyMode != AppOpsManager.MODE_ERRORED) {
- + mode = policyMode;
- + }
- + }
- + return mode;
- + }
- +
- + private boolean isStrict(int code, int uid, String packageName) {
- + if (!mStrictEnable)
- + return false;
- +
- + return UserHandle.isApp(uid);
- + }
- +
- + private void printOperationLocked(Op op, int mode, String operation) {
- + if(op != null) {
- + int switchCode = AppOpsManager.opToSwitch(op.op);
- + if (mode == AppOpsManager.MODE_IGNORED) {
- + if (DEBUG) Log.d(TAG, operation + ": reject #" + mode + " for code "
- + + switchCode + " (" + op.op + ") uid " + op.uid + " package "
- + + op.packageName);
- + } else if (mode == AppOpsManager.MODE_ALLOWED) {
- + if (DEBUG) Log.d(TAG, operation + ": allowing code " + op.op + " uid "
- + + op.uid
- + + " package " + op.packageName);
- + }
- + }
- + }
- +
- + private void recordOperationLocked(int code, int uid, String packageName,
- + int mode) {
- + Op op = getOpLocked(code, uid, packageName, false);
- + if (op != null) {
- + if (op.noteOpCount != 0) {
- + printOperationLocked(op, mode, "noteOperartion");
- + }
- + if (op.startOpCount != 0) {
- + printOperationLocked(op, mode, "startOperation");
- + }
- + if (mode == AppOpsManager.MODE_IGNORED) {
- + op.rejectTime = System.currentTimeMillis();
- + } else if (mode == AppOpsManager.MODE_ALLOWED) {
- + if (op.noteOpCount != 0) {
- + op.time = System.currentTimeMillis();
- + op.rejectTime = 0;
- + }
- + if (op.startOpCount != 0) {
- + if (op.nesting == 0) {
- + op.time = System.currentTimeMillis();
- + op.rejectTime = 0;
- + op.duration = -1;
- + }
- + op.nesting = op.nesting + op.startOpCount;
- + while (op.clientTokens.size() != 0) {
- + IBinder clientToken = op.clientTokens.get(0);
- + ClientState client = mClients.get(clientToken);
- + if (client != null) {
- + if (client.mStartedOps != null) {
- + client.mStartedOps.add(op);
- + }
- + }
- + op.clientTokens.remove(0);
- + }
- + }
- + }
- + op.clientTokens.clear();
- + op.startOpCount = 0;
- + op.noteOpCount = 0;
- + }
- + }
- +
- + public void notifyOperation(int code, int uid, String packageName,
- + int mode, boolean remember) {
- + verifyIncomingUid(uid);
- + verifyIncomingOp(code);
- + ArrayList<Callback> repCbs = null;
- + int switchCode = AppOpsManager.opToSwitch(code);
- + synchronized (this) {
- + recordOperationLocked(code, uid, packageName, mode);
- + Op op = getOpLocked(switchCode, uid, packageName, true);
- + if (op != null) {
- + // Send result to all waiting client
- + if (op.dialogReqQueue.getDialog() != null) {
- + op.dialogReqQueue.notifyAll(mode);
- + op.dialogReqQueue.setDialog(null);
- + }
- + if (remember && op.mode != mode) {
- + op.mode = mode;
- + ArraySet<Callback> cbs = mOpModeWatchers.get(switchCode);
- + if (cbs != null) {
- + if (repCbs == null) {
- + repCbs = new ArrayList<Callback>();
- + }
- + repCbs.addAll(cbs);
- + }
- + cbs = mPackageModeWatchers.get(packageName);
- + if (cbs != null) {
- + if (repCbs == null) {
- + repCbs = new ArrayList<Callback>();
- + }
- + repCbs.addAll(cbs);
- + }
- + if (mode == getDefaultMode(op.op, op.uid, op.packageName)) {
- + // If going into the default mode, prune this op
- + // if there is nothing else interesting in it.
- + pruneOp(op, uid, packageName);
- + }
- + scheduleWriteLocked();
- + }
- + }
- + }
- + if (repCbs != null) {
- + for (int i = 0; i < repCbs.size(); i++) {
- + try {
- + repCbs.get(i).mCallback.opChanged(switchCode, uid, packageName);
- + } catch (RemoteException e) {
- + }
- + }
- + }
- + }
- +
- private static String resolvePackageName(int uid, String packageName) {
- - if (uid == 0) {
- + if (uid == Process.ROOT_UID) {
- return "root";
- } else if (uid == Process.SHELL_UID) {
- return "com.android.shell";
- @@@ -3769,11 -3064,74 +4157,82 @@@
- }
- }
- + private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
- + @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
- + synchronized (AppOpsService.this) {
- + mProfileOwners = owners;
- + }
- + }
- + }
- ++
- + private void broadcastOpIfNeeded(int op) {
- + switch (op) {
- + case AppOpsManager.OP_SU:
- + mHandler.post(mSuSessionChangedRunner);
- + break;
- + default:
- + break;
- + }
- + }
- +
- + private void readPolicy() {
- + if (mStrictEnable) {
- + mPolicy = new AppOpsPolicy(new File(DEFAULT_POLICY_FILE), mContext);
- + mPolicy.readPolicy();
- + mPolicy.debugPoilcy();
- + } else {
- + mPolicy = null;
- + }
- + }
- +
- + public boolean isControlAllowed(int code, String packageName) {
- + boolean isShow = true;
- + if (mPolicy != null) {
- + isShow = mPolicy.isControlAllowed(code, packageName);
- + }
- + return isShow;
- + }
- +
- + @Override
- + public boolean getPrivacyGuardSettingForPackage(int uid, String packageName) {
- + for (int op : AppOpsManager.PRIVACY_GUARD_OP_STATES) {
- + int switchOp = AppOpsManager.opToSwitch(op);
- + int mode = checkOperation(op, uid, packageName);
- + if (mode != AppOpsManager.MODE_ALLOWED && mode != AppOpsManager.MODE_IGNORED) {
- + return true;
- + }
- + }
- + return false;
- + }
- +
- + @Override
- + public void setPrivacyGuardSettingForPackage(int uid, String packageName, boolean state) {
- + for (int op : AppOpsManager.PRIVACY_GUARD_OP_STATES) {
- + int switchOp = AppOpsManager.opToSwitch(op);
- + setMode(switchOp, uid, packageName, state
- + ? AppOpsManager.MODE_ASK : AppOpsManager.MODE_ALLOWED);
- + }
- + }
- +
- + @Override
- + public void resetCounters() {
- + mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
- + Binder.getCallingPid(), Binder.getCallingUid(), null);
- + synchronized (this) {
- + for (int i = 0; i < mUidStates.size(); i++) {
- + final UidState uidState = mUidStates.valueAt(i);
- + for (Map.Entry<String, Ops> ent : uidState.pkgOps.entrySet()) {
- + String packageName = ent.getKey();
- + Ops pkgOps = ent.getValue();
- + for (int j = 0; j < pkgOps.size(); j++) {
- + Op curOp = pkgOps.valueAt(j);
- + curOp.allowedCount = 0;
- + curOp.ignoredCount = 0;
- + }
- + }
- + }
- + // ensure the counter reset persists
- + scheduleWriteLocked();
- + }
- + }
- }
Add Comment
Please, Sign In to add comment