Merge "Add per UID control to app ops." into mnc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
8dbd484850
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user