am 9a3d898a: am 4bdf81a0: am 4f3d5c75: am 1eb06eaa: am 8dbd4848: Merge "Add per UID control to app ops." into mnc-dev
* commit '9a3d898a5802b4d3eb398fe618a4c2f202f96753':
Add per UID control to app ops.
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 862d235..42ac67c 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1234,6 +1234,14 @@
}
/** @hide */
+ public void setUidMode(int code, int uid, int mode) {
+ try {
+ mService.setUidMode(code, uid, mode);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /** @hide */
public void setMode(int code, int uid, String packageName, int mode) {
try {
mService.setMode(code, uid, packageName, mode);
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 73c4833..9fa2c23 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -38,6 +38,7 @@
int checkPackage(int uid, String packageName);
List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
+ void setUidMode(int code, int uid, int mode);
void setMode(int code, int uid, String packageName, int mode);
void resetAllModes(int reqUserId, String reqPackageName);
int checkAudioOperation(int code, int usage, int uid, String packageName);
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 417f18d..ec02789 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -32,6 +32,7 @@
import android.app.ActivityManager;
import android.app.ActivityThread;
+import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -56,15 +57,18 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.util.TimeUtils;
import android.util.Xml;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.os.Zygote;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
+import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -98,19 +102,38 @@
}
};
- final SparseArray<HashMap<String, Ops>> mUidOps
- = new SparseArray<HashMap<String, Ops>>();
+ final SparseArray<UidState> mUidStates = new SparseArray<>();
private final SparseArray<boolean[]> mOpRestrictions = new SparseArray<boolean[]>();
+ private static final class UidState {
+ public final int uid;
+ public ArrayMap<String, Ops> pkgOps;
+ public SparseIntArray opModes;
+
+ public UidState(int uid) {
+ this.uid = uid;
+ }
+
+ public void clear() {
+ pkgOps = null;
+ opModes = null;
+ }
+
+ public boolean isDefault() {
+ return (pkgOps == null || pkgOps.isEmpty())
+ && (opModes == null || opModes.size() <= 0);
+ }
+ }
+
public final static class Ops extends SparseArray<Op> {
public final String packageName;
- public final int uid;
+ public final UidState uidState;
public final boolean isPrivileged;
- public Ops(String _packageName, int _uid, boolean _isPrivileged) {
+ public Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
packageName = _packageName;
- uid = _uid;
+ uidState = _uidState;
isPrivileged = _isPrivileged;
}
}
@@ -220,27 +243,42 @@
public void systemReady() {
synchronized (this) {
boolean changed = false;
- for (int i=0; i<mUidOps.size(); i++) {
- HashMap<String, Ops> pkgs = mUidOps.valueAt(i);
+ for (int i = mUidStates.size() - 1; i >= 0; i--) {
+ UidState uidState = mUidStates.valueAt(i);
+
+ String[] packageNames = getPackagesForUid(uidState.uid);
+ if (ArrayUtils.isEmpty(packageNames)) {
+ uidState.clear();
+ mUidStates.removeAt(i);
+ changed = true;
+ continue;
+ }
+
+ ArrayMap<String, Ops> pkgs = uidState.pkgOps;
+ if (pkgs == null) {
+ continue;
+ }
+
Iterator<Ops> it = pkgs.values().iterator();
while (it.hasNext()) {
Ops ops = it.next();
int curUid;
try {
curUid = mContext.getPackageManager().getPackageUid(ops.packageName,
- UserHandle.getUserId(ops.uid));
+ UserHandle.getUserId(ops.uidState.uid));
} catch (NameNotFoundException e) {
curUid = -1;
}
- if (curUid != ops.uid) {
+ if (curUid != ops.uidState.uid) {
Slog.i(TAG, "Pruning old package " + ops.packageName
- + "/" + ops.uid + ": new uid=" + curUid);
+ + "/" + ops.uidState + ": new uid=" + curUid);
it.remove();
changed = true;
}
}
- if (pkgs.size() <= 0) {
- mUidOps.removeAt(i);
+
+ if (uidState.isDefault()) {
+ mUidStates.removeAt(i);
}
}
if (changed) {
@@ -279,22 +317,34 @@
public void packageRemoved(int uid, String packageName) {
synchronized (this) {
- HashMap<String, Ops> pkgs = mUidOps.get(uid);
- if (pkgs != null) {
- if (pkgs.remove(packageName) != null) {
- if (pkgs.size() <= 0) {
- mUidOps.remove(uid);
- }
- scheduleFastWriteLocked();
- }
+ UidState uidState = mUidStates.get(uid);
+ if (uidState == null) {
+ return;
+ }
+
+ boolean changed = false;
+
+ // Remove any package state if such.
+ if (uidState.pkgOps != null && uidState.pkgOps.remove(packageName) != null) {
+ changed = true;
+ }
+
+ // If we just nuked the last package state check if the UID is valid.
+ if (changed && uidState.pkgOps.isEmpty()
+ && getPackagesForUid(uid).length <= 0) {
+ mUidStates.remove(uid);
+ }
+
+ if (changed) {
+ scheduleFastWriteLocked();
}
}
}
public void uidRemoved(int uid) {
synchronized (this) {
- if (mUidOps.indexOfKey(uid) >= 0) {
- mUidOps.remove(uid);
+ if (mUidStates.indexOfKey(uid) >= 0) {
+ mUidStates.remove(uid);
scheduleFastWriteLocked();
}
}
@@ -346,16 +396,23 @@
Binder.getCallingPid(), Binder.getCallingUid(), null);
ArrayList<AppOpsManager.PackageOps> res = null;
synchronized (this) {
- for (int i=0; i<mUidOps.size(); i++) {
- HashMap<String, Ops> packages = mUidOps.valueAt(i);
- for (Ops pkgOps : packages.values()) {
+ final int uidStateCount = mUidStates.size();
+ for (int i = 0; i < uidStateCount; i++) {
+ UidState uidState = mUidStates.valueAt(i);
+ if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
+ continue;
+ }
+ ArrayMap<String, Ops> packages = uidState.pkgOps;
+ final int packageCount = packages.size();
+ for (int j = 0; j < packageCount; j++) {
+ Ops pkgOps = packages.valueAt(j);
ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
if (resOps != null) {
if (res == null) {
res = new ArrayList<AppOpsManager.PackageOps>();
}
AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
- pkgOps.packageName, pkgOps.uid, resOps);
+ pkgOps.packageName, pkgOps.uidState.uid, resOps);
res.add(resPackage);
}
}
@@ -380,7 +437,7 @@
}
ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
- pkgOps.packageName, pkgOps.uid, resOps);
+ pkgOps.packageName, pkgOps.uidState.uid, resOps);
res.add(resPackage);
return res;
}
@@ -392,11 +449,15 @@
if (ops != null) {
ops.remove(op.op);
if (ops.size() <= 0) {
- HashMap<String, Ops> pkgOps = mUidOps.get(uid);
+ UidState uidState = ops.uidState;
+ ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
if (pkgOps != null) {
pkgOps.remove(ops.packageName);
- if (pkgOps.size() <= 0) {
- mUidOps.remove(uid);
+ if (pkgOps.isEmpty()) {
+ uidState.pkgOps = null;
+ }
+ if (uidState.isDefault()) {
+ mUidStates.remove(uid);
}
}
}
@@ -405,6 +466,113 @@
}
@Override
+ public void setUidMode(int code, int uid, int mode) {
+ if (Binder.getCallingPid() != Process.myPid()) {
+ mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
+ Binder.getCallingPid(), Binder.getCallingUid(), null);
+ }
+ verifyIncomingOp(code);
+ code = AppOpsManager.opToSwitch(code);
+
+ synchronized (this) {
+ final int defaultMode = AppOpsManager.opToDefaultMode(code);
+
+ UidState uidState = getUidStateLocked(uid, false);
+ if (uidState == null) {
+ if (mode == defaultMode) {
+ return;
+ }
+ uidState = new UidState(uid);
+ uidState.opModes = new SparseIntArray();
+ uidState.opModes.put(code, mode);
+ mUidStates.put(uid, uidState);
+ scheduleWriteLocked();
+ } else if (uidState.opModes == null) {
+ if (mode != defaultMode) {
+ uidState.opModes = new SparseIntArray();
+ uidState.opModes.put(code, mode);
+ scheduleWriteLocked();
+ }
+ } else {
+ if (uidState.opModes.get(code) == mode) {
+ return;
+ }
+ if (mode == defaultMode) {
+ uidState.opModes.delete(code);
+ if (uidState.opModes.size() <= 0) {
+ uidState.opModes = null;
+ }
+ } else {
+ uidState.opModes.put(code, mode);
+ }
+ scheduleWriteLocked();
+ }
+ }
+
+ ArrayMap<Callback, ArraySet<String>> callbackSpecs = null;
+
+ ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
+ if (callbacks != null) {
+ final int callbackCount = callbacks.size();
+ for (int i = 0; i < callbackCount; i++) {
+ Callback callback = callbacks.get(i);
+ callbackSpecs = new ArrayMap<>();
+ callbackSpecs.put(callback, null);
+ }
+ }
+
+ String[] uidPackageNames = getPackagesForUid(uid);
+ for (String uidPackageName : uidPackageNames) {
+ callbacks = mPackageModeWatchers.get(uidPackageName);
+ if (callbacks != null) {
+ if (callbackSpecs == null) {
+ callbackSpecs = new ArrayMap<>();
+ }
+ final int callbackCount = callbacks.size();
+ for (int i = 0; i < callbackCount; i++) {
+ Callback callback = callbacks.get(i);
+ ArraySet<String> changedPackages = callbackSpecs.get(callback);
+ if (changedPackages == null) {
+ changedPackages = new ArraySet<>();
+ callbackSpecs.put(callback, changedPackages);
+ }
+ changedPackages.add(uidPackageName);
+ }
+ }
+ }
+
+ if (callbackSpecs == null) {
+ return;
+ }
+
+ // 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 {
+ for (int i = 0; i < callbackSpecs.size(); i++) {
+ Callback callback = callbackSpecs.keyAt(i);
+ ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
+ try {
+ if (reportedPackageNames == null) {
+ callback.mCallback.opChanged(code, null);
+ } else {
+ final int reportedPackageCount = reportedPackageNames.size();
+ for (int j = 0; j < reportedPackageCount; j++) {
+ String reportedPackageName = reportedPackageNames.valueAt(j);
+ callback.mCallback.opChanged(code, reportedPackageName);
+ }
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error dispatching op op change", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void setMode(int code, int uid, String packageName, int mode) {
if (Binder.getCallingPid() != Process.myPid()) {
mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
@@ -414,6 +582,7 @@
ArrayList<Callback> repCbs = null;
code = AppOpsManager.opToSwitch(code);
synchronized (this) {
+ UidState uidState = getUidStateLocked(uid, false);
Op op = getOpLocked(code, uid, packageName, true);
if (op != null) {
if (op.mode != mode) {
@@ -468,14 +637,26 @@
if (callbacks == null) {
callbacks = new HashMap<Callback, ArrayList<Pair<String, Integer>>>();
}
+ boolean duplicate = false;
for (int i=0; i<cbs.size(); i++) {
Callback cb = cbs.get(i);
ArrayList<Pair<String, Integer>> reports = callbacks.get(cb);
if (reports == null) {
reports = new ArrayList<Pair<String, Integer>>();
callbacks.put(cb, reports);
+ } else {
+ final int reportCount = reports.size();
+ for (int j = 0; j < reportCount; j++) {
+ Pair<String, Integer> report = reports.get(j);
+ if (report.second == op && report.first.equals(packageName)) {
+ duplicate = true;
+ break;
+ }
+ }
}
- reports.add(new Pair<String, Integer>(packageName, op));
+ if (!duplicate) {
+ reports.add(new Pair<>(packageName, op));
+ }
}
return callbacks;
}
@@ -488,16 +669,54 @@
callingPid, callingUid, null);
reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
true, true, "resetAllModes", null);
+
+ int reqUid = -1;
+ if (reqPackageName != null) {
+ try {
+ reqUid = AppGlobals.getPackageManager().getPackageUid(
+ reqPackageName, reqUserId);
+ } catch (RemoteException e) {
+ /* ignore - local call */
+ }
+ }
+
HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks = null;
synchronized (this) {
boolean changed = false;
- for (int i=mUidOps.size()-1; i>=0; i--) {
- HashMap<String, Ops> packages = mUidOps.valueAt(i);
+ for (int i = mUidStates.size() - 1; i >= 0; i--) {
+ UidState uidState = mUidStates.valueAt(i);
+
+ SparseIntArray opModes = uidState.opModes;
+ if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
+ final int uidOpCount = opModes.size();
+ for (int j = uidOpCount - 1; j >= 0; j--) {
+ final int code = opModes.keyAt(j);
+ if (AppOpsManager.opAllowsReset(code)) {
+ opModes.removeAt(j);
+ if (opModes.size() <= 0) {
+ uidState.opModes = null;
+ }
+ for (String packageName : getPackagesForUid(uidState.uid)) {
+ callbacks = addCallbacks(callbacks, packageName, code,
+ mOpModeWatchers.get(code));
+ callbacks = addCallbacks(callbacks, packageName, code,
+ mPackageModeWatchers.get(packageName));
+ }
+ }
+ }
+ }
+
+ if (uidState.pkgOps == null) {
+ continue;
+ }
+
if (reqUserId != UserHandle.USER_ALL
- && reqUserId != UserHandle.getUserId(mUidOps.keyAt(i))) {
+ && reqUserId != UserHandle.getUserId(uidState.uid)) {
// Skip any ops for a different user
continue;
}
+
+ Map<String, Ops> packages = uidState.pkgOps;
Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Ops> ent = it.next();
@@ -526,10 +745,11 @@
it.remove();
}
}
- if (packages.size() == 0) {
- mUidOps.removeAt(i);
+ if (uidState.isDefault()) {
+ mUidStates.remove(uidState.uid);
}
}
+
if (changed) {
scheduleFastWriteLocked();
}
@@ -552,7 +772,7 @@
@Override
public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
synchronized (this) {
- op = AppOpsManager.opToSwitch(op);
+ op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
Callback cb = mModeWatchers.get(callback.asBinder());
if (cb == null) {
cb = new Callback(callback);
@@ -621,7 +841,15 @@
if (isOpRestricted(uid, code, packageName)) {
return AppOpsManager.MODE_IGNORED;
}
- Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false);
+ code = AppOpsManager.opToSwitch(code);
+ UidState uidState = getUidStateLocked(uid, false);
+ if (uidState != null && uidState.opModes != null) {
+ final int uidMode = uidState.opModes.get(code);
+ if (uidMode != AppOpsManager.MODE_ALLOWED) {
+ return uidMode;
+ }
+ }
+ Op op = getOpLocked(code, uid, packageName, false);
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
@@ -732,6 +960,17 @@
}
op.duration = 0;
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 "
+ + switchCode + " (" + code + ") uid " + uid + " package "
+ + packageName);
+ op.rejectTime = System.currentTimeMillis();
+ return uidMode;
+ }
+ }
final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
@@ -766,6 +1005,17 @@
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 "
+ + switchCode + " (" + code + ") uid " + uid + " package "
+ + packageName);
+ op.rejectTime = System.currentTimeMillis();
+ return uidMode;
+ }
+ }
final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code "
@@ -847,6 +1097,18 @@
throw new IllegalArgumentException("Bad operation #" + op);
}
+ private UidState getUidStateLocked(int uid, boolean edit) {
+ UidState uidState = mUidStates.get(uid);
+ if (uidState == null) {
+ if (!edit) {
+ return null;
+ }
+ uidState = new UidState(uid);
+ mUidStates.put(uid, uidState);
+ }
+ return uidState;
+ }
+
private Ops getOpsLocked(int uid, String packageName, boolean edit) {
if (uid == 0) {
packageName = "root";
@@ -857,15 +1119,19 @@
}
private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
- HashMap<String, Ops> pkgOps = mUidOps.get(uid);
- if (pkgOps == null) {
+ UidState uidState = getUidStateLocked(uid, edit);
+ if (uidState == null) {
+ return null;
+ }
+
+ if (uidState.pkgOps == null) {
if (!edit) {
return null;
}
- pkgOps = new HashMap<String, Ops>();
- mUidOps.put(uid, pkgOps);
+ uidState.pkgOps = new ArrayMap<>();
}
- Ops ops = pkgOps.get(packageName);
+
+ Ops ops = uidState.pkgOps.get(packageName);
if (ops == null) {
if (!edit) {
return null;
@@ -904,8 +1170,8 @@
Binder.restoreCallingIdentity(ident);
}
}
- ops = new Ops(packageName, uid, isPrivileged);
- pkgOps.put(packageName, ops);
+ ops = new Ops(packageName, uidState, isPrivileged);
+ uidState.pkgOps.put(packageName, ops);
}
return ops;
}
@@ -940,7 +1206,7 @@
if (!edit) {
return null;
}
- op = new Op(ops.uid, ops.packageName, code);
+ op = new Op(ops.uidState.uid, ops.packageName, code);
ops.put(code, op);
}
if (edit) {
@@ -1000,6 +1266,8 @@
String tagName = parser.getName();
if (tagName.equals("pkg")) {
readPackage(parser);
+ } if (tagName.equals("uid")) {
+ readUidOps(parser);
} else {
Slog.w(TAG, "Unknown element under <app-ops>: "
+ parser.getName());
@@ -1021,7 +1289,7 @@
Slog.w(TAG, "Failed parsing " + e);
} finally {
if (!success) {
- mUidOps.clear();
+ mUidStates.clear();
}
try {
stream.close();
@@ -1032,6 +1300,34 @@
}
}
+ void readUidOps(XmlPullParser parser) throws NumberFormatException,
+ XmlPullParserException, IOException {
+ final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("op")) {
+ final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
+ final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
+ UidState uidState = getUidStateLocked(uid, true);
+ if (uidState.opModes == null) {
+ uidState.opModes = new SparseIntArray();
+ }
+ uidState.opModes.put(code, mode);
+ } else {
+ Slog.w(TAG, "Unknown element under <uid-ops>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
void readPackage(XmlPullParser parser) throws NumberFormatException,
XmlPullParserException, IOException {
String pkgName = parser.getAttributeValue(null, "n");
@@ -1114,15 +1410,16 @@
if (proxyPackageName != null) {
op.proxyPackageName = proxyPackageName;
}
- HashMap<String, Ops> pkgOps = mUidOps.get(uid);
- if (pkgOps == null) {
- pkgOps = new HashMap<String, Ops>();
- mUidOps.put(uid, pkgOps);
+
+ UidState uidState = getUidStateLocked(uid, true);
+ if (uidState.pkgOps == null) {
+ uidState.pkgOps = new ArrayMap<>();
}
- Ops ops = pkgOps.get(pkgName);
+
+ Ops ops = uidState.pkgOps.get(pkgName);
if (ops == null) {
- ops = new Ops(pkgName, uid, isPrivileged);
- pkgOps.put(pkgName, ops);
+ ops = new Ops(pkgName, uidState, isPrivileged);
+ uidState.pkgOps.put(pkgName, ops);
}
ops.put(op.op, op);
} else {
@@ -1149,7 +1446,27 @@
XmlSerializer out = new FastXmlSerializer();
out.setOutput(stream, StandardCharsets.UTF_8.name());
out.startDocument(null, true);
- out.startTag(null, "app-ops");
+ out.startTag(null, "app");
+
+ final int uidStateCount = mUidStates.size();
+ for (int i = 0; i < uidStateCount; i++) {
+ UidState uidState = mUidStates.valueAt(i);
+ if (uidState.opModes != null && uidState.opModes.size() > 0) {
+ out.startTag(null, "uid");
+ out.attribute(null, "n", Integer.toString(uidState.uid));
+ SparseIntArray uidOpModes = uidState.opModes;
+ final int opCount = uidOpModes.size();
+ for (int j = 0; j < opCount; j++) {
+ final int op = uidOpModes.keyAt(j);
+ final int mode = uidOpModes.valueAt(j);
+ out.startTag(null, "op");
+ out.attribute(null, "n", Integer.toString(op));
+ out.attribute(null, "m", Integer.toString(mode));
+ out.endTag(null, "op");
+ }
+ out.endTag(null, "uid");
+ }
+ }
if (allOps != null) {
String lastPkg = null;
@@ -1316,9 +1633,27 @@
if (needSep) {
pw.println();
}
- for (int i=0; i<mUidOps.size(); i++) {
- pw.print(" Uid "); UserHandle.formatUid(pw, mUidOps.keyAt(i)); pw.println(":");
- HashMap<String, Ops> pkgOps = mUidOps.valueAt(i);
+ for (int i=0; i<mUidStates.size(); i++) {
+ UidState uidState = mUidStates.valueAt(i);
+
+ pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
+
+ SparseIntArray opModes = uidState.opModes;
+ if (opModes != null) {
+ final int opModeCount = opModes.size();
+ for (int j = 0; j < opModeCount; j++) {
+ 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);
+ }
+ }
+
+ ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
+ if (pkgOps == null) {
+ continue;
+ }
+
for (Ops ops : pkgOps.values()) {
pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
for (int j=0; j<ops.size(); j++) {
@@ -1382,4 +1717,12 @@
}
}
+ private static String[] getPackagesForUid(int uid) {
+ try {
+ return AppGlobals.getPackageManager().getPackagesForUid(uid);
+ } catch (RemoteException e) {
+ /* ignore - local call */
+ }
+ return EmptyArray.STRING;
+ }
}