User restriction for disallowing window creation
Block any types of windows that could by used by apps to create
views on top of a locked app. This can be used by device admins
in conjunction with lock task mode.
Added a way for system (and priv apps) to bypass user restrictions
for specified op codes.
Bug: 15279535
Change-Id: I2381530ef6226a5bb32a99bb4030baafb39bf564
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 176ba5d..14a462e 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -29,8 +29,11 @@
import java.util.List;
import java.util.Map;
+import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.media.AudioService;
@@ -102,10 +105,12 @@
public final static class Ops extends SparseArray<Op> {
public final String packageName;
public final int uid;
+ public final boolean isPrivileged;
- public Ops(String _packageName, int _uid) {
+ public Ops(String _packageName, int _uid, boolean _isPrivileged) {
packageName = _packageName;
uid = _uid;
+ isPrivileged = _isPrivileged;
}
}
@@ -560,7 +565,7 @@
verifyIncomingUid(uid);
verifyIncomingOp(code);
synchronized (this) {
- if (isOpRestricted(uid, code)) {
+ if (isOpRestricted(uid, code, packageName)) {
return AppOpsManager.MODE_IGNORED;
}
Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false);
@@ -646,7 +651,7 @@
return AppOpsManager.MODE_ERRORED;
}
Op op = getOpLocked(ops, code, true);
- if (isOpRestricted(uid, code)) {
+ if (isOpRestricted(uid, code, packageName)) {
return AppOpsManager.MODE_IGNORED;
}
if (op.duration == -1) {
@@ -683,7 +688,7 @@
return AppOpsManager.MODE_ERRORED;
}
Op op = getOpLocked(ops, code, true);
- if (isOpRestricted(uid, code)) {
+ if (isOpRestricted(uid, code, packageName)) {
return AppOpsManager.MODE_IGNORED;
}
final int switchCode = AppOpsManager.opToSwitch(code);
@@ -782,6 +787,7 @@
if (!edit) {
return null;
}
+ boolean isPrivileged = false;
// This is the first time we have seen this package name under this uid,
// so let's make sure it is valid.
if (uid != 0) {
@@ -789,12 +795,19 @@
try {
int pkgUid = -1;
try {
- pkgUid = mContext.getPackageManager().getPackageUid(packageName,
- UserHandle.getUserId(uid));
- } catch (NameNotFoundException e) {
- if ("media".equals(packageName)) {
- pkgUid = Process.MEDIA_UID;
+ ApplicationInfo appInfo = ActivityThread.getPackageManager()
+ .getApplicationInfo(packageName, 0, UserHandle.getUserId(uid));
+ if (appInfo != null) {
+ pkgUid = appInfo.uid;
+ isPrivileged = (appInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+ } else {
+ if ("media".equals(packageName)) {
+ pkgUid = Process.MEDIA_UID;
+ isPrivileged = false;
+ }
}
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Could not contact PackageManager", e);
}
if (pkgUid != uid) {
// Oops! The package name is not valid for the uid they are calling
@@ -807,7 +820,7 @@
Binder.restoreCallingIdentity(ident);
}
}
- ops = new Ops(packageName, uid);
+ ops = new Ops(packageName, uid, isPrivileged);
pkgOps.put(packageName, ops);
}
return ops;
@@ -851,10 +864,18 @@
return op;
}
- private boolean isOpRestricted(int uid, int code) {
+ private boolean isOpRestricted(int uid, int code, String packageName) {
int userHandle = UserHandle.getUserId(uid);
boolean[] opRestrictions = mOpRestrictions.get(userHandle);
if ((opRestrictions != null) && opRestrictions[code]) {
+ if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
+ synchronized (this) {
+ Ops ops = getOpsLocked(uid, packageName, true);
+ if ((ops != null) && ops.isPrivileged) {
+ return false;
+ }
+ }
+ }
if (userHandle == UserHandle.USER_OWNER) {
if (uid != mDeviceOwnerUid) {
return true;
@@ -959,6 +980,27 @@
void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
XmlPullParserException, IOException {
int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
+ String isPrivilegedString = parser.getAttributeValue(null, "p");
+ boolean isPrivileged = false;
+ if (isPrivilegedString == null) {
+ try {
+ IPackageManager packageManager = ActivityThread.getPackageManager();
+ if (packageManager != null) {
+ ApplicationInfo appInfo = ActivityThread.getPackageManager()
+ .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
+ if (appInfo != null) {
+ isPrivileged = (appInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+ }
+ } else {
+ // Could not load data, don't add to cache so it will be loaded later.
+ return;
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Could not contact PackageManager", e);
+ }
+ } else {
+ isPrivileged = Boolean.parseBoolean(isPrivilegedString);
+ }
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -993,7 +1035,7 @@
}
Ops ops = pkgOps.get(pkgName);
if (ops == null) {
- ops = new Ops(pkgName, uid);
+ ops = new Ops(pkgName, uid, isPrivileged);
pkgOps.put(pkgName, ops);
}
ops.put(op.op, op);
@@ -1037,6 +1079,16 @@
}
out.startTag(null, "uid");
out.attribute(null, "n", Integer.toString(pkg.getUid()));
+ synchronized (this) {
+ Ops ops = getOpsLocked(pkg.getUid(), pkg.getPackageName(), false);
+ // Should always be present as the list of PackageOps is generated
+ // from Ops.
+ if (ops != null) {
+ out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
+ } else {
+ out.attribute(null, "p", Boolean.toString(false));
+ }
+ }
List<AppOpsManager.OpEntry> ops = pkg.getOps();
for (int j=0; j<ops.size(); j++) {
AppOpsManager.OpEntry op = ops.get(j);