Merge "Further flesh out app ops foreground state." into pi-dev

This commit is contained in:
Dianne Hackborn
2018-05-10 05:49:08 +00:00
committed by Android (Google) Code Review
5 changed files with 423 additions and 58 deletions

View File

@@ -118,6 +118,13 @@ public class AppOpsManager {
*/
public static final int MODE_FOREGROUND = 4;
/**
* Flag for {@link #startWatchingMode(String, String, int, OnOpChangedListener)}:
* Also get reports if the foreground state of an op's uid changes. This only works
* when watching a particular op, not when watching a package.
* @hide
*/
public static final int WATCH_FOREGROUND_CHANGES = 1 << 0;
/**
* @hide
@@ -1898,6 +1905,21 @@ public class AppOpsManager {
startWatchingMode(strOpToOp(op), packageName, callback);
}
/**
* Monitor for changes to the operating mode for the given op in the given app package.
* You can watch op changes only for your UID.
*
* @param op The operation to monitor, one of OPSTR_*.
* @param packageName The name of the application to monitor.
* @param flags Option flags: any combination of {@link #WATCH_FOREGROUND_CHANGES} or 0.
* @param callback Where to report changes.
* @hide
*/
public void startWatchingMode(String op, String packageName, int flags,
final OnOpChangedListener callback) {
startWatchingMode(strOpToOp(op), packageName, flags, callback);
}
/**
* Monitor for changes to the operating mode for the given op in the given app package.
*
@@ -1911,6 +1933,24 @@ public class AppOpsManager {
*/
@RequiresPermission(value=android.Manifest.permission.WATCH_APPOPS, conditional=true)
public void startWatchingMode(int op, String packageName, final OnOpChangedListener callback) {
startWatchingMode(op, packageName, 0, callback);
}
/**
* Monitor for changes to the operating mode for the given op in the given app package.
*
* <p> If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission
* you can watch changes only for your UID.
*
* @param op The operation to monitor, one of OP_*.
* @param packageName The name of the application to monitor.
* @param flags Option flags: any combination of {@link #WATCH_FOREGROUND_CHANGES} or 0.
* @param callback Where to report changes.
* @hide
*/
@RequiresPermission(value=android.Manifest.permission.WATCH_APPOPS, conditional=true)
public void startWatchingMode(int op, String packageName, int flags,
final OnOpChangedListener callback) {
synchronized (mModeWatchers) {
IAppOpsCallback cb = mModeWatchers.get(callback);
if (cb == null) {
@@ -1927,7 +1967,7 @@ public class AppOpsManager {
mModeWatchers.put(callback, cb);
}
try {
mService.startWatchingMode(op, packageName, cb);
mService.startWatchingModeWithFlags(op, packageName, flags, cb);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2079,6 +2119,19 @@ public class AppOpsManager {
return checkOpNoThrow(strOpToOp(op), uid, packageName);
}
/**
* Like {@link #checkOp} but returns the <em>raw</em> mode associated with the op.
* Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}.
* @hide
*/
public int unsafeCheckOpRaw(String op, int uid, String packageName) {
try {
return mService.checkOperation(strOpToOp(op), uid, packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Make note of an application performing an operation. Note that you must pass
* in both the uid and name of the application to be checked; this function will verify
@@ -2217,7 +2270,8 @@ public class AppOpsManager {
*/
public int checkOpNoThrow(int op, int uid, String packageName) {
try {
return mService.checkOperation(op, uid, packageName);
int mode = mService.checkOperation(op, uid, packageName);
return mode == AppOpsManager.MODE_FOREGROUND ? AppOpsManager.MODE_ALLOWED : mode;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}

View File

@@ -10424,6 +10424,25 @@ public final class Settings {
*/
public static final String ACTIVITY_MANAGER_CONSTANTS = "activity_manager_constants";
/**
* App ops specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
*
* "state_settle_time=10000"
*
* The following keys are supported:
*
* <pre>
* state_settle_time (long)
* </pre>
*
* <p>
* Type: string
* @hide
* @see com.android.server.AppOpsService.Constants
*/
public static final String APP_OPS_CONSTANTS = "app_ops_constants";
/**
* Device Idle (Doze) specific settings.
* This is encoded as a key=value list, separated by commas. Ex:

View File

@@ -54,4 +54,6 @@ interface IAppOpsService {
void startWatchingActive(in int[] ops, IAppOpsActiveCallback callback);
void stopWatchingActive(IAppOpsActiveCallback callback);
boolean isOperationActive(int code, int uid, String packageName);
void startWatchingModeWithFlags(int op, String packageName, int flags, IAppOpsCallback callback);
}

View File

@@ -115,6 +115,7 @@ public class SettingsBackupTest {
Settings.Global.APN_DB_UPDATE_CONTENT_URL,
Settings.Global.APN_DB_UPDATE_METADATA_URL,
Settings.Global.APP_IDLE_CONSTANTS,
Settings.Global.APP_OPS_CONSTANTS,
Settings.Global.APP_STANDBY_ENABLED,
Settings.Global.ASSISTED_GPS_ENABLED,
Settings.Global.AUDIO_SAFE_VOLUME_STATE,

View File

@@ -21,13 +21,16 @@ import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.media.AudioAttributes;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
@@ -43,9 +46,11 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManagerInternal;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.KeyValueListParser;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -109,9 +114,6 @@ public class AppOpsService extends IAppOpsService.Stub {
// Write at most every 30 minutes.
static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
// How long we want for a drop in uid state to settle before applying it.
static final long STATE_SETTLE_TIME = 10*1000;
// Constant meaning that any UID should be matched when dispatching callbacks
private static final int UID_ANY = -2;
@@ -198,6 +200,75 @@ public class AppOpsService extends IAppOpsService.Stub {
*/
private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
/**
* 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_STATE_SETTLE_TIME = "state_settle_time";
/**
* How long we want for a drop in uid state to settle before applying it.
* @see Settings.Global#APP_OPS_CONSTANTS
* @see #KEY_STATE_SETTLE_TIME
*/
public long 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.DEVICE_IDLE_CONSTANTS),
false, this);
updateConstants();
}
@Override
public void onChange(boolean selfChange, Uri uri) {
updateConstants();
}
private void updateConstants() {
synchronized (AppOpsService.this) {
try {
if (mResolver != null) {
mParser.setString(Settings.Global.getString(mResolver,
Settings.Global.APP_OPS_CONSTANTS));
} else {
mParser.setString("");
}
} catch (IllegalArgumentException e) {
// Failed to parse the settings string, log this and move on
// with defaults.
Slog.e(TAG, "Bad app ops settings", e);
}
STATE_SETTLE_TIME = mParser.getDurationMillis(
KEY_STATE_SETTLE_TIME, 10 * 1000L);
}
}
void dump(PrintWriter pw) {
pw.println(" Settings:");
pw.print(" "); pw.print(KEY_STATE_SETTLE_TIME); pw.print("=");
TimeUtils.formatDuration(STATE_SETTLE_TIME, pw);
pw.println();
}
}
private final Constants mConstants;
@VisibleForTesting
static final class UidState {
public final int uid;
@@ -210,7 +281,9 @@ public class AppOpsService extends IAppOpsService.Stub {
public ArrayMap<String, Ops> pkgOps;
public SparseIntArray opModes;
// true indicates there is an interested observer, false there isn't but it has such an op
public SparseBooleanArray foregroundOps;
public boolean hasForegroundWatchers;
public UidState(int uid) {
this.uid = uid;
@@ -234,8 +307,35 @@ public class AppOpsService extends IAppOpsService.Stub {
return mode;
}
public void evalForegroundOps() {
private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
SparseBooleanArray which) {
boolean curValue = which.get(op, false);
ArraySet<ModeCallback> callbacks = watchers.get(op);
if (callbacks != null) {
for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
if ((callbacks.valueAt(cbi).mFlags
& AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
hasForegroundWatchers = true;
curValue = true;
}
}
}
which.put(op, curValue);
}
public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
SparseBooleanArray which = null;
hasForegroundWatchers = false;
if (opModes != null) {
for (int i = opModes.size() - 1; i >= 0; i--) {
if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
if (which == null) {
which = new SparseBooleanArray();
}
evalForegroundWatchers(opModes.keyAt(i), watchers, which);
}
}
}
if (pkgOps != null) {
for (int i = pkgOps.size() - 1; i >= 0; i--) {
Ops ops = pkgOps.valueAt(i);
@@ -244,7 +344,7 @@ public class AppOpsService extends IAppOpsService.Stub {
if (which == null) {
which = new SparseBooleanArray();
}
which.put(ops.keyAt(j), true);
evalForegroundWatchers(ops.keyAt(j), watchers, which);
}
}
}
@@ -313,13 +413,15 @@ public class AppOpsService extends IAppOpsService.Stub {
final class ModeCallback implements DeathRecipient {
final IAppOpsCallback mCallback;
final int mWatchingUid;
final int mFlags;
final int mCallingUid;
final int mCallingPid;
ModeCallback(IAppOpsCallback callback, int watchingUid, int callingUid,
ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
int callingPid) {
mCallback = callback;
mWatchingUid = watchingUid;
mFlags = flags;
mCallingUid = callingUid;
mCallingPid = callingPid;
try {
@@ -328,6 +430,10 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
public boolean isWatchingUid(int uid) {
return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(128);
@@ -335,6 +441,8 @@ public class AppOpsService extends IAppOpsService.Stub {
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(" watchinguid=");
UserHandle.formatUid(sb, mWatchingUid);
sb.append(" flags=0x");
sb.append(Integer.toHexString(mFlags));
sb.append(" from uid=");
UserHandle.formatUid(sb, mCallingUid);
sb.append(" pid=");
@@ -439,6 +547,7 @@ public class AppOpsService extends IAppOpsService.Stub {
LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
mFile = new AtomicFile(storagePath, "appops");
mHandler = handler;
mConstants = new Constants(mHandler);
readState();
}
@@ -449,6 +558,7 @@ public class AppOpsService extends IAppOpsService.Stub {
public void systemReady() {
synchronized (this) {
mConstants.startMonitoring(mContext.getContentResolver());
boolean changed = false;
for (int i = mUidStates.size() - 1; i >= 0; i--) {
UidState uidState = mUidStates.valueAt(i);
@@ -611,14 +721,16 @@ public class AppOpsService extends IAppOpsService.Stub {
final UidState uidState = getUidStateLocked(uid, true);
final int newState = PROCESS_STATE_TO_UID_STATE[procState];
if (uidState != null && uidState.pendingState != newState) {
final int oldPendingState = uidState.pendingState;
uidState.pendingState = newState;
if (newState < uidState.state) {
// We are moving to a more important state, always do it immediately.
uidState.state = newState;
uidState.pendingStateCommitTime = 0;
commitUidPendingStateLocked(uidState);
} else if (uidState.pendingStateCommitTime == 0) {
// We are moving to a less important state for the first time,
// delay the application for a bit.
uidState.pendingStateCommitTime = SystemClock.uptimeMillis() + STATE_SETTLE_TIME;
uidState.pendingStateCommitTime = SystemClock.uptimeMillis() +
mConstants.STATE_SETTLE_TIME;
}
if (uidState.startNesting != 0) {
// There is some actively running operation... need to find it
@@ -629,13 +741,12 @@ public class AppOpsService extends IAppOpsService.Stub {
for (int j = ops.size() - 1; j >= 0; j--) {
final Op op = ops.valueAt(j);
if (op.startNesting > 0) {
op.time[uidState.pendingState] = now;
op.time[oldPendingState] = now;
op.time[newState] = now;
}
}
}
}
uidState.pendingState = newState;
}
}
}
@@ -867,7 +978,9 @@ public class AppOpsService extends IAppOpsService.Stub {
ModeCallback callback = callbacks.valueAt(i);
ArraySet<String> changedPackages = new ArraySet<>();
Collections.addAll(changedPackages, uidPackageNames);
callbackSpecs = new ArrayMap<>();
if (callbackSpecs == null) {
callbackSpecs = new ArrayMap<>();
}
callbackSpecs.put(callback, changedPackages);
}
}
@@ -932,7 +1045,7 @@ public class AppOpsService extends IAppOpsService.Stub {
if (op.mode != mode) {
op.mode = mode;
if (uidState != null) {
uidState.evalForegroundOps();
uidState.evalForegroundOps(mOpModeWatchers);
}
ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
if (cbs != null) {
@@ -1126,7 +1239,7 @@ public class AppOpsService extends IAppOpsService.Stub {
mUidStates.remove(uidState.uid);
}
if (uidChanged) {
uidState.evalForegroundOps();
uidState.evalForegroundOps(mOpModeWatchers);
}
}
@@ -1148,8 +1261,23 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
private void evalAllForegroundOpsLocked() {
for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
final UidState uidState = mUidStates.valueAt(uidi);
if (uidState.foregroundOps != null) {
uidState.evalForegroundOps(mOpModeWatchers);
}
}
}
@Override
public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
startWatchingModeWithFlags(op, packageName, 0, callback);
}
@Override
public void startWatchingModeWithFlags(int op, String packageName, int flags,
IAppOpsCallback callback) {
int watchedUid = -1;
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
@@ -1166,7 +1294,7 @@ public class AppOpsService extends IAppOpsService.Stub {
op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
ModeCallback cb = mModeWatchers.get(callback.asBinder());
if (cb == null) {
cb = new ModeCallback(callback, watchedUid, callingUid, callingPid);
cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
mModeWatchers.put(callback.asBinder(), cb);
}
if (op != AppOpsManager.OP_NONE) {
@@ -1185,6 +1313,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
cbs.add(cb);
}
evalAllForegroundOpsLocked();
}
}
@@ -1212,6 +1341,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
}
evalAllForegroundOpsLocked();
}
}
@@ -1249,7 +1379,7 @@ public class AppOpsService extends IAppOpsService.Stub {
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
return op.mode == AppOpsManager.MODE_FOREGROUND ? AppOpsManager.MODE_ALLOWED : op.mode;
return op.mode;
}
}
@@ -1699,13 +1829,11 @@ public class AppOpsService extends IAppOpsService.Stub {
} else {
if (uidState.pendingStateCommitTime != 0) {
if (uidState.pendingStateCommitTime < mLastUptime) {
uidState.state = uidState.pendingState;
uidState.pendingStateCommitTime = 0;
commitUidPendingStateLocked(uidState);
} else {
mLastUptime = SystemClock.uptimeMillis();
if (uidState.pendingStateCommitTime < mLastUptime) {
uidState.state = uidState.pendingState;
uidState.pendingStateCommitTime = 0;
commitUidPendingStateLocked(uidState);
}
}
}
@@ -1713,6 +1841,44 @@ public class AppOpsService extends IAppOpsService.Stub {
return uidState;
}
private void commitUidPendingStateLocked(UidState uidState) {
uidState.state = uidState.pendingState;
uidState.pendingStateCommitTime = 0;
if (uidState.hasForegroundWatchers) {
for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
if (!uidState.foregroundOps.valueAt(fgi)) {
continue;
}
final int code = uidState.foregroundOps.keyAt(fgi);
final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
if (callbacks != null) {
for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
final ModeCallback callback = callbacks.valueAt(cbi);
if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
|| !callback.isWatchingUid(uidState.uid)) {
continue;
}
boolean doAllPackages = uidState.opModes != null
&& uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
if (uidState.pkgOps != null) {
for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
if (doAllPackages || (op != null
&& op.mode == AppOpsManager.MODE_FOREGROUND)) {
mHandler.sendMessage(PooledLambda.obtainMessage(
AppOpsService::notifyOpChanged,
this, callback, code, uidState.uid,
uidState.pkgOps.keyAt(pkgi)));
}
}
}
}
}
}
}
}
private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
boolean uidMismatchExpected) {
UidState uidState = getUidStateLocked(uid, edit);
@@ -1952,7 +2118,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
if (changed) {
uidState.evalForegroundOps();
uidState.evalForegroundOps(mOpModeWatchers);
}
}
}
@@ -2151,7 +2317,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
UidState uidState = getUidStateLocked(uid, false);
if (uidState != null) {
uidState.evalForegroundOps();
uidState.evalForegroundOps(mOpModeWatchers);
}
}
@@ -2322,7 +2488,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
int strModeToMode(String modeStr, PrintWriter err) {
static int strModeToMode(String modeStr, PrintWriter err) {
for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
return i;
@@ -2716,6 +2882,10 @@ public class AppOpsService extends IAppOpsService.Stub {
pw.println(" Print this help text.");
pw.println(" --op [OP]");
pw.println(" Limit output to data associated with the given app op code.");
pw.println(" --mode [MODE]");
pw.println(" Limit output to data associated with the given app op mode.");
pw.println(" --package [PACKAGE]");
pw.println(" Limit output to data associated with the given package name.");
}
private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
@@ -2751,6 +2921,9 @@ public class AppOpsService extends IAppOpsService.Stub {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
int dumpOp = -1;
String dumpPackage = null;
int dumpUid = -1;
int dumpMode = -1;
if (args != null) {
for (int i=0; i<args.length; i++) {
@@ -2770,6 +2943,34 @@ public class AppOpsService extends IAppOpsService.Stub {
if (dumpOp < 0) {
return;
}
} else if ("--package".equals(arg)) {
i++;
if (i >= args.length) {
pw.println("No argument for --package option");
return;
}
dumpPackage = args[i];
try {
dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
0);
} catch (RemoteException e) {
}
if (dumpUid < 0) {
pw.println("Unknown package: " + dumpPackage);
return;
}
dumpUid = UserHandle.getAppId(dumpUid);
} else if ("--mode".equals(arg)) {
i++;
if (i >= args.length) {
pw.println("No argument for --mode option");
return;
}
dumpMode = Shell.strModeToMode(args[i], pw);
if (dumpMode < 0) {
return;
}
} else if (arg.length() > 0 && arg.charAt(0) == '-'){
pw.println("Unknown option: " + arg);
return;
@@ -2782,6 +2983,8 @@ public class AppOpsService extends IAppOpsService.Stub {
synchronized (this) {
pw.println("Current AppOps Service state:");
mConstants.dump(pw);
pw.println();
final long now = System.currentTimeMillis();
final long nowElapsed = SystemClock.elapsedRealtime();
final long nowUptime = SystemClock.uptimeMillis();
@@ -2789,29 +2992,46 @@ public class AppOpsService extends IAppOpsService.Stub {
final Date date = new Date();
boolean needSep = false;
if (mOpModeWatchers.size() > 0) {
needSep = true;
boolean printedHeader = false;
for (int i=0; i<mOpModeWatchers.size(); i++) {
if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
continue;
}
if (!printedHeader) {
pw.println(" Op mode watchers:");
printedHeader = true;
}
pw.print(" Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
pw.println(":");
boolean printedOpHeader = false;
ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
for (int j=0; j<callbacks.size(); j++) {
final ModeCallback cb = callbacks.valueAt(j);
if (dumpPackage != null && cb.mWatchingUid >= 0
&& dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
continue;
}
needSep = true;
if (!printedHeader) {
pw.println(" Op mode watchers:");
printedHeader = true;
}
if (!printedOpHeader) {
pw.print(" Op ");
pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
pw.println(":");
printedOpHeader = true;
}
pw.print(" #"); pw.print(j); pw.print(": ");
pw.println(callbacks.valueAt(j));
pw.println(cb);
}
}
}
if (mPackageModeWatchers.size() > 0) {
needSep = true;
pw.println(" Package mode watchers:");
if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
boolean printedHeader = false;
for (int i=0; i<mPackageModeWatchers.size(); i++) {
if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
continue;
}
needSep = true;
if (!printedHeader) {
pw.println(" Package mode watchers:");
printedHeader = true;
}
pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
pw.println(":");
ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
@@ -2822,15 +3042,24 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
if (mModeWatchers.size() > 0 && dumpOp < 0) {
needSep = true;
pw.println(" All op mode watchers:");
boolean printedHeader = false;
for (int i=0; i<mModeWatchers.size(); i++) {
final ModeCallback cb = mModeWatchers.valueAt(i);
if (dumpPackage != null && cb.mWatchingUid >= 0
&& dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
continue;
}
needSep = true;
if (!printedHeader) {
pw.println(" All op mode watchers:");
printedHeader = true;
}
pw.print(" ");
pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
pw.print(": "); pw.println(mModeWatchers.valueAt(i));
pw.print(": "); pw.println(cb);
}
}
if (mActiveWatchers.size() > 0) {
if (mActiveWatchers.size() > 0 && dumpMode < 0) {
needSep = true;
boolean printedHeader = false;
for (int i = 0; i < mActiveWatchers.size(); i++) {
@@ -2838,9 +3067,14 @@ public class AppOpsService extends IAppOpsService.Stub {
if (activeWatchers.size() <= 0) {
continue;
}
final ActiveCallback cb = activeWatchers.valueAt(0);
if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
continue;
}
if (dumpPackage != null && cb.mWatchingUid >= 0
&& dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
continue;
}
if (!printedHeader) {
pw.println(" All op active watchers:");
printedHeader = true;
@@ -2862,10 +3096,10 @@ public class AppOpsService extends IAppOpsService.Stub {
}
pw.println("]");
pw.print(" ");
pw.println(activeWatchers.valueAt(0));
pw.println(cb);
}
}
if (mClients.size() > 0) {
if (mClients.size() > 0 && dumpMode < 0) {
needSep = true;
boolean printedHeader = false;
for (int i=0; i<mClients.size(); i++) {
@@ -2878,6 +3112,9 @@ public class AppOpsService extends IAppOpsService.Stub {
if (dumpOp >= 0 && op.op != dumpOp) {
continue;
}
if (dumpPackage != null && !dumpPackage.equals(op.packageName)) {
continue;
}
if (!printedHeader) {
pw.println(" Clients:");
printedHeader = true;
@@ -2898,7 +3135,8 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
}
if (mAudioRestrictions.size() > 0 && dumpOp < 0) {
if (mAudioRestrictions.size() > 0 && dumpOp < 0 && dumpPackage != null
&& dumpMode < 0) {
boolean printedHeader = false;
for (int o=0; o<mAudioRestrictions.size(); o++) {
final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
@@ -2931,19 +3169,44 @@ public class AppOpsService extends IAppOpsService.Stub {
final SparseIntArray opModes = uidState.opModes;
final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
if (dumpOp >= 0) {
boolean hasOp = uidState.opModes != null
&& uidState.opModes.indexOfKey(dumpOp) >= 0;
if (pkgOps != null) {
for (int pkgi = 0; !hasOp && pkgi < pkgOps.size(); pkgi++) {
Ops ops = pkgOps.valueAt(pkgi);
if (ops != null && ops.indexOfKey(dumpOp) >= 0) {
hasOp = true;
continue;
if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
boolean hasOp = dumpOp < 0 || (uidState.opModes != null
&& uidState.opModes.indexOfKey(dumpOp) >= 0);
boolean hasPackage = dumpPackage == null;
boolean hasMode = dumpMode < 0;
if (!hasMode && opModes != null) {
for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
if (opModes.valueAt(opi) == dumpMode) {
hasMode = true;
}
}
}
if (!hasOp) {
if (pkgOps != null) {
for (int pkgi = 0;
(!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
pkgi++) {
Ops ops = pkgOps.valueAt(pkgi);
if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
hasOp = true;
}
if (!hasMode) {
for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
if (ops.valueAt(opi).mode == dumpMode) {
hasMode = true;
}
}
}
if (!hasPackage && dumpPackage.equals(ops.packageName)) {
hasPackage = true;
}
}
}
if (uidState.foregroundOps != null && !hasOp) {
if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
hasOp = true;
}
}
if (!hasOp || !hasPackage || !hasMode) {
continue;
}
}
@@ -2964,12 +3227,20 @@ public class AppOpsService extends IAppOpsService.Stub {
pw.print(" startNesting=");
pw.println(uidState.startNesting);
}
if (uidState.foregroundOps != null) {
if (uidState.foregroundOps != null && (dumpMode < 0
|| dumpMode == AppOpsManager.MODE_FOREGROUND)) {
pw.println(" foregroundOps:");
for (int j = 0; j < uidState.foregroundOps.size(); j++) {
pw.print(" ");
pw.println(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
continue;
}
pw.print(" ");
pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
pw.print(": ");
pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
}
pw.print(" hasForegroundWatchers=");
pw.println(uidState.hasForegroundWatchers);
}
needSep = true;
@@ -2981,6 +3252,9 @@ public class AppOpsService extends IAppOpsService.Stub {
if (dumpOp >= 0 && dumpOp != code) {
continue;
}
if (dumpMode >= 0 && dumpMode != mode) {
continue;
}
pw.print(" "); pw.print(AppOpsManager.opToName(code));
pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
}
@@ -2991,19 +3265,34 @@ public class AppOpsService extends IAppOpsService.Stub {
}
for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
Ops ops = pkgOps.valueAt(pkgi);
final Ops ops = pkgOps.valueAt(pkgi);
if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
continue;
}
boolean printedPackage = false;
for (int j=0; j<ops.size(); j++) {
Op op = ops.valueAt(j);
final Op op = ops.valueAt(j);
if (dumpOp >= 0 && dumpOp != op.op) {
continue;
}
if (dumpMode >= 0 && dumpMode != op.mode) {
continue;
}
if (!printedPackage) {
pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
printedPackage = true;
}
pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
final int switchOp = AppOpsManager.opToSwitch(op.op);
if (switchOp != op.op) {
pw.print(" / switch ");
pw.print(AppOpsManager.opToName(switchOp));
final Op switchObj = ops.get(switchOp);
int mode = switchObj != null
? switchObj.mode : AppOpsManager.opToDefaultMode(switchOp);
pw.print("="); pw.print(AppOpsManager.modeToName(mode));
}
pw.println("): ");
dumpTimesLocked(pw,
" Access: ",