am 4f3d5c75: am 1eb06eaa: am 8dbd4848: Merge "Add per UID control to app ops." into mnc-dev

* commit '4f3d5c75e09c7d1562506ea792428ac5a0241561':
  Add per UID control to app ops.
This commit is contained in:
Svetoslav Ganov
2015-08-01 16:54:06 +00:00
committed by Android Git Automerger
3 changed files with 410 additions and 58 deletions

View File

@@ -1233,6 +1233,14 @@ public class AppOpsManager {
return null;
}
/** @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 {

View File

@@ -38,6 +38,7 @@ interface IAppOpsService {
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);

View File

@@ -32,6 +32,7 @@ import java.util.Map;
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.Log;
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 @@ public class AppOpsService extends IAppOpsService.Stub {
}
};
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 class AppOpsService extends IAppOpsService.Stub {
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 class AppOpsService extends IAppOpsService.Stub {
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 @@ public class AppOpsService extends IAppOpsService.Stub {
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 @@ public class AppOpsService extends IAppOpsService.Stub {
}
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 @@ public class AppOpsService extends IAppOpsService.Stub {
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);
}
}
}
@@ -404,6 +465,113 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
@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()) {
@@ -414,6 +582,7 @@ public class AppOpsService extends IAppOpsService.Stub {
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 @@ public class AppOpsService extends IAppOpsService.Stub {
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;
}
}
}
if (!duplicate) {
reports.add(new Pair<>(packageName, op));
}
reports.add(new Pair<String, Integer>(packageName, op));
}
return callbacks;
}
@@ -488,16 +669,54 @@ public class AppOpsService extends IAppOpsService.Stub {
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 @@ public class AppOpsService extends IAppOpsService.Stub {
it.remove();
}
}
if (packages.size() == 0) {
mUidOps.removeAt(i);
if (uidState.isDefault()) {
mUidStates.remove(uidState.uid);
}
}
if (changed) {
scheduleFastWriteLocked();
}
@@ -552,7 +772,7 @@ public class AppOpsService extends IAppOpsService.Stub {
@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 @@ public class AppOpsService extends IAppOpsService.Stub {
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 @@ public class AppOpsService extends IAppOpsService.Stub {
}
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 @@ public class AppOpsService extends IAppOpsService.Stub {
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 @@ public class AppOpsService extends IAppOpsService.Stub {
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 @@ public class AppOpsService extends IAppOpsService.Stub {
}
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 @@ public class AppOpsService extends IAppOpsService.Stub {
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 @@ public class AppOpsService extends IAppOpsService.Stub {
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 @@ public class AppOpsService extends IAppOpsService.Stub {
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 @@ public class AppOpsService extends IAppOpsService.Stub {
Slog.w(TAG, "Failed parsing " + e);
} finally {
if (!success) {
mUidOps.clear();
mUidStates.clear();
}
try {
stream.close();
@@ -1032,6 +1300,34 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
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 @@ public class AppOpsService extends IAppOpsService.Stub {
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 @@ public class AppOpsService extends IAppOpsService.Stub {
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 @@ public class AppOpsService extends IAppOpsService.Stub {
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 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
private static String[] getPackagesForUid(int uid) {
try {
return AppGlobals.getPackageManager().getPackagesForUid(uid);
} catch (RemoteException e) {
/* ignore - local call */
}
return EmptyArray.STRING;
}
}