Merge changes from topic "SetModeNoEntanglement-qt-qpr1-dev" into qt-qpr1-dev

* changes:
  DO NOT MERGE Don't throw exception in AppOpsManager.checkOp
  DO NOT MERGE Remove unnecessary internal APIs.
  DO NOT MERGE SetMode: Don't call into PM with AppOps lock held
This commit is contained in:
TreeHugger Robot
2020-01-14 19:43:27 +00:00
committed by Android (Google) Code Review
2 changed files with 147 additions and 145 deletions

View File

@@ -16,7 +16,6 @@
package android.app; package android.app;
import android.annotation.NonNull;
import android.util.SparseIntArray; import android.util.SparseIntArray;
import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.QuadFunction;
@@ -76,20 +75,6 @@ public abstract class AppOpsManagerInternal {
*/ */
public abstract void setDeviceAndProfileOwners(SparseIntArray owners); public abstract void setDeviceAndProfileOwners(SparseIntArray owners);
/**
* Sets the app-ops mode for a certain app-op and uid.
*
* <p>Similar as {@link AppOpsManager#setUidMode} but does not require the package manager to be
* working. Hence this can be used very early during boot.
*
* <p>Only for internal callers. Does <u>not</u> verify that package name belongs to uid.
*
* @param code The op code to set.
* @param uid The UID for which to set.
* @param mode The new mode to set.
*/
public abstract void setUidMode(int code, int uid, int mode);
/** /**
* Set all {@link #setMode (package) modes} for this uid to the default value. * Set all {@link #setMode (package) modes} for this uid to the default value.
* *
@@ -97,18 +82,4 @@ public abstract class AppOpsManagerInternal {
* @param uid The uid * @param uid The uid
*/ */
public abstract void setAllPkgModesToDefault(int code, int uid); public abstract void setAllPkgModesToDefault(int code, int uid);
/**
* Get the (raw) mode of an app-op.
*
* <p>Does <u>not</u> verify that package belongs to uid. The caller needs to do that.
*
* @param code The code of the op
* @param uid The uid of the package the op belongs to
* @param packageName The package the op belongs to
*
* @return The mode of the op
*/
public abstract @AppOpsManager.Mode int checkOperationUnchecked(int code, int uid,
@NonNull String packageName);
} }

View File

@@ -1105,8 +1105,8 @@ public class AppOpsService extends IAppOpsService.Stub {
return Collections.emptyList(); return Collections.emptyList();
} }
synchronized (this) { synchronized (this) {
Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */, Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* isPrivileged */,
false /* uidMismatchExpected */); false /* edit */);
if (pkgOps == null) { if (pkgOps == null) {
return null; return null;
} }
@@ -1203,8 +1203,7 @@ public class AppOpsService extends IAppOpsService.Stub {
private void pruneOp(Op op, int uid, String packageName) { private void pruneOp(Op op, int uid, String packageName) {
if (!op.hasAnyTime()) { if (!op.hasAnyTime()) {
Ops ops = getOpsRawLocked(uid, packageName, false /* edit */, Ops ops = getOpsRawLocked(uid, packageName, false /* isPrivileged */, false /* edit */);
false /* uidMismatchExpected */);
if (ops != null) { if (ops != null) {
ops.remove(op.op); ops.remove(op.op);
if (ops.size() <= 0) { if (ops.size() <= 0) {
@@ -1404,11 +1403,6 @@ public class AppOpsService extends IAppOpsService.Stub {
} }
} }
@Override
public void setMode(int code, int uid, String packageName, int mode) {
setMode(code, uid, packageName, mode, true, false);
}
/** /**
* Sets the mode for a certain op and uid. * Sets the mode for a certain op and uid.
* *
@@ -1416,19 +1410,25 @@ public class AppOpsService extends IAppOpsService.Stub {
* @param uid The UID for which to set * @param uid The UID for which to set
* @param packageName The package for which to set * @param packageName The package for which to set
* @param mode The new mode to set * @param mode The new mode to set
* @param verifyUid Iff {@code true}, check that the package name belongs to the uid
* @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid ==
* false})
*/ */
private void setMode(int code, int uid, @NonNull String packageName, int mode, @Override
boolean verifyUid, boolean isPrivileged) { public void setMode(int code, int uid, @NonNull String packageName, int mode) {
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid); enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingOp(code); verifyIncomingOp(code);
ArraySet<ModeCallback> repCbs = null; ArraySet<ModeCallback> repCbs = null;
code = AppOpsManager.opToSwitch(code); code = AppOpsManager.opToSwitch(code);
boolean isPrivileged;
try {
isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
} catch (SecurityException e) {
Slog.e(TAG, "Cannot setMode", e);
return;
}
synchronized (this) { synchronized (this) {
UidState uidState = getUidStateLocked(uid, false); UidState uidState = getUidStateLocked(uid, false);
Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged); Op op = getOpLocked(code, uid, packageName, isPrivileged, true);
if (op != null) { if (op != null) {
if (op.mode != mode) { if (op.mode != mode) {
op.mode = mode; op.mode = mode;
@@ -1793,14 +1793,6 @@ public class AppOpsService extends IAppOpsService.Stub {
return checkOperationUnchecked(code, uid, resolvedPackageName, raw); return checkOperationUnchecked(code, uid, resolvedPackageName, raw);
} }
/**
* @see #checkOperationUnchecked(int, int, String, boolean, boolean)
*/
private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
boolean raw) {
return checkOperationUnchecked(code, uid, packageName, raw, true);
}
/** /**
* Get the mode of an app-op. * Get the mode of an app-op.
* *
@@ -1808,20 +1800,26 @@ public class AppOpsService extends IAppOpsService.Stub {
* @param uid The uid of the package the op belongs to * @param uid The uid of the package the op belongs to
* @param packageName The package the op belongs to * @param packageName The package the op belongs to
* @param raw If the raw state of eval-ed state should be checked. * @param raw If the raw state of eval-ed state should be checked.
* @param verify If the code should check the package belongs to the uid
* *
* @return The mode of the op * @return The mode of the op
*/ */
private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName, private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
boolean raw, boolean verify) { boolean raw) {
if (isOpRestrictedDueToSuspend(code, packageName, uid)) { if (isOpRestrictedDueToSuspend(code, packageName, uid)) {
return AppOpsManager.MODE_IGNORED; return AppOpsManager.MODE_IGNORED;
} }
synchronized (this) {
if (verify) { boolean isPrivileged;
checkPackage(uid, packageName);
try {
isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
} catch (SecurityException e) {
Slog.e(TAG, "checkOperation", e);
return AppOpsManager.opToDefaultMode(code);
} }
if (isOpRestrictedLocked(uid, code, packageName)) {
synchronized (this) {
if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) {
return AppOpsManager.MODE_IGNORED; return AppOpsManager.MODE_IGNORED;
} }
code = AppOpsManager.opToSwitch(code); code = AppOpsManager.opToSwitch(code);
@@ -1831,7 +1829,7 @@ public class AppOpsService extends IAppOpsService.Stub {
final int rawMode = uidState.opModes.get(code); final int rawMode = uidState.opModes.get(code);
return raw ? rawMode : uidState.evalMode(code, rawMode); return raw ? rawMode : uidState.evalMode(code, rawMode);
} }
Op op = getOpLocked(code, uid, packageName, false, verify, false); Op op = getOpLocked(code, uid, packageName, false, false);
if (op == null) { if (op == null) {
return AppOpsManager.opToDefaultMode(code); return AppOpsManager.opToDefaultMode(code);
} }
@@ -1936,16 +1934,14 @@ public class AppOpsService extends IAppOpsService.Stub {
@Override @Override
public int checkPackage(int uid, String packageName) { public int checkPackage(int uid, String packageName) {
Preconditions.checkNotNull(packageName); Preconditions.checkNotNull(packageName);
synchronized (this) { try {
Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, verifyAndGetIsPrivileged(uid, packageName);
true /* uidMismatchExpected */);
if (ops != null) {
return AppOpsManager.MODE_ALLOWED; return AppOpsManager.MODE_ALLOWED;
} else { } catch (SecurityException ignored) {
return AppOpsManager.MODE_ERRORED; return AppOpsManager.MODE_ERRORED;
} }
} }
}
@Override @Override
public int noteProxyOperation(int code, int proxyUid, public int noteProxyOperation(int code, int proxyUid,
@@ -2006,9 +2002,16 @@ public class AppOpsService extends IAppOpsService.Stub {
private int noteOperationUnchecked(int code, int uid, String packageName, private int noteOperationUnchecked(int code, int uid, String packageName,
int proxyUid, String proxyPackageName, @OpFlags int flags) { int proxyUid, String proxyPackageName, @OpFlags int flags) {
boolean isPrivileged;
try {
isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
} catch (SecurityException e) {
Slog.e(TAG, "noteOperation", e);
return AppOpsManager.MODE_ERRORED;
}
synchronized (this) { synchronized (this) {
final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, final Ops ops = getOpsRawLocked(uid, packageName, isPrivileged, true /* edit */);
false /* uidMismatchExpected */);
if (ops == null) { if (ops == null) {
scheduleOpNotedIfNeededLocked(code, uid, packageName, scheduleOpNotedIfNeededLocked(code, uid, packageName,
AppOpsManager.MODE_IGNORED); AppOpsManager.MODE_IGNORED);
@@ -2017,7 +2020,7 @@ public class AppOpsService extends IAppOpsService.Stub {
return AppOpsManager.MODE_ERRORED; return AppOpsManager.MODE_ERRORED;
} }
final Op op = getOpLocked(ops, code, true); final Op op = getOpLocked(ops, code, true);
if (isOpRestrictedLocked(uid, code, packageName)) { if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) {
scheduleOpNotedIfNeededLocked(code, uid, packageName, scheduleOpNotedIfNeededLocked(code, uid, packageName,
AppOpsManager.MODE_IGNORED); AppOpsManager.MODE_IGNORED);
return AppOpsManager.MODE_IGNORED; return AppOpsManager.MODE_IGNORED;
@@ -2176,16 +2179,25 @@ public class AppOpsService extends IAppOpsService.Stub {
return AppOpsManager.MODE_IGNORED; return AppOpsManager.MODE_IGNORED;
} }
ClientState client = (ClientState)token; ClientState client = (ClientState)token;
boolean isPrivileged;
try {
isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
} catch (SecurityException e) {
Slog.e(TAG, "startOperation", e);
return AppOpsManager.MODE_ERRORED;
}
synchronized (this) { synchronized (this) {
final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */, final Ops ops = getOpsRawLocked(uid, resolvedPackageName, isPrivileged,
false /* uidMismatchExpected */); true /* edit */);
if (ops == null) { if (ops == null) {
if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
+ " package " + resolvedPackageName); + " package " + resolvedPackageName);
return AppOpsManager.MODE_ERRORED; return AppOpsManager.MODE_ERRORED;
} }
final Op op = getOpLocked(ops, code, true); final Op op = getOpLocked(ops, code, true);
if (isOpRestrictedLocked(uid, code, resolvedPackageName)) { if (isOpRestrictedLocked(uid, code, resolvedPackageName, isPrivileged)) {
return AppOpsManager.MODE_IGNORED; return AppOpsManager.MODE_IGNORED;
} }
final int switchCode = AppOpsManager.opToSwitch(code); final int switchCode = AppOpsManager.opToSwitch(code);
@@ -2257,8 +2269,17 @@ public class AppOpsService extends IAppOpsService.Stub {
return; return;
} }
ClientState client = (ClientState) token; ClientState client = (ClientState) token;
boolean isPrivileged;
try {
isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
} catch (SecurityException e) {
Slog.e(TAG, "Cannot finishOperation", e);
return;
}
synchronized (this) { synchronized (this) {
Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false); Op op = getOpLocked(code, uid, resolvedPackageName, isPrivileged, true);
if (op == null) { if (op == null) {
return; return;
} }
@@ -2508,8 +2529,76 @@ public class AppOpsService extends IAppOpsService.Stub {
uidState.pendingStateCommitTime = 0; uidState.pendingStateCommitTime = 0;
} }
private Ops getOpsRawLocked(int uid, String packageName, boolean edit, /**
boolean uidMismatchExpected) { * Verify that package belongs to uid and return whether the package is privileged.
*
* @param uid The uid the package belongs to
* @param packageName The package the might belong to the uid
*
* @return {@code true} iff the package is privileged
*/
private boolean verifyAndGetIsPrivileged(int uid, String packageName) {
if (uid == Process.ROOT_UID) {
// For backwards compatibility, don't check package name for root UID.
return false;
}
// Do not check if uid/packageName is already known
synchronized (this) {
UidState uidState = mUidStates.get(uid);
if (uidState != null && uidState.pkgOps != null) {
Ops ops = uidState.pkgOps.get(packageName);
if (ops != null) {
return ops.isPrivileged;
}
}
}
boolean isPrivileged = false;
final long ident = Binder.clearCallingIdentity();
try {
int pkgUid;
ApplicationInfo appInfo = LocalServices.getService(PackageManagerInternal.class)
.getApplicationInfo(packageName, PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
| PackageManager.MATCH_UNINSTALLED_PACKAGES
| PackageManager.MATCH_INSTANT,
Process.SYSTEM_UID, UserHandle.getUserId(uid));
if (appInfo != null) {
pkgUid = appInfo.uid;
isPrivileged = (appInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
} else {
pkgUid = resolveUid(packageName);
if (pkgUid >= 0) {
isPrivileged = false;
}
}
if (pkgUid != uid) {
throw new SecurityException("Specified package " + packageName + " under uid " + uid
+ " but it is really " + pkgUid);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
return isPrivileged;
}
/**
* Get (and potentially create) ops.
*
* @param uid The uid the package belongs to
* @param packageName The name of the package
* @param isPrivileged If the package is privilidged (ignored if {@code edit} is false)
* @param edit If an ops does not exist, create the ops?
* @return
*/
private Ops getOpsRawLocked(int uid, String packageName, boolean isPrivileged, boolean edit) {
UidState uidState = getUidStateLocked(uid, edit); UidState uidState = getUidStateLocked(uid, edit);
if (uidState == null) { if (uidState == null) {
return null; return null;
@@ -2527,47 +2616,6 @@ public class AppOpsService extends IAppOpsService.Stub {
if (!edit) { if (!edit) {
return null; 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) {
final long ident = Binder.clearCallingIdentity();
try {
int pkgUid = -1;
try {
ApplicationInfo appInfo = ActivityThread.getPackageManager()
.getApplicationInfo(packageName,
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
UserHandle.getUserId(uid));
if (appInfo != null) {
pkgUid = appInfo.uid;
isPrivileged = (appInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
} else {
pkgUid = resolveUid(packageName);
if (pkgUid >= 0) {
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
// under. Abort.
if (!uidMismatchExpected) {
RuntimeException ex = new RuntimeException("here");
ex.fillInStackTrace();
Slog.w(TAG, "Bad call: specified package " + packageName
+ " under uid " + uid + " but it is really " + pkgUid, ex);
}
return null;
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
ops = new Ops(packageName, uidState, isPrivileged); ops = new Ops(packageName, uidState, isPrivileged);
uidState.pkgOps.put(packageName, ops); uidState.pkgOps.put(packageName, ops);
} }
@@ -2575,7 +2623,7 @@ public class AppOpsService extends IAppOpsService.Stub {
} }
/** /**
* Get the state of all ops for a package, <b>don't verify that package belongs to uid</b>. * Get the state of all ops for a package.
* *
* <p>Usually callers should use {@link #getOpLocked} and not call this directly. * <p>Usually callers should use {@link #getOpLocked} and not call this directly.
* *
@@ -2633,23 +2681,15 @@ public class AppOpsService extends IAppOpsService.Stub {
* @param code The code of the op * @param code The code of the op
* @param uid The uid the of the package * @param uid The uid the of the package
* @param packageName The package name for which to get the state for * @param packageName The package name for which to get the state for
* @param isPrivileged Whether the package is privileged or not (only used if {@code edit
* == true})
* @param edit Iff {@code true} create the {@link Op} object if not yet created * @param edit Iff {@code true} create the {@link Op} object if not yet created
* @param verifyUid Iff {@code true} check that the package belongs to the uid
* @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid
* == false})
* *
* @return The {@link Op state} of the op * @return The {@link Op state} of the op
*/ */
private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit, private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
boolean verifyUid, boolean isPrivileged) { boolean isPrivileged, boolean edit) {
Ops ops; Ops ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
if (verifyUid) {
ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */);
} else {
ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
}
if (ops == null) { if (ops == null) {
return null; return null;
} }
@@ -2679,7 +2719,8 @@ public class AppOpsService extends IAppOpsService.Stub {
return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid)); return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid));
} }
private boolean isOpRestrictedLocked(int uid, int code, String packageName) { private boolean isOpRestrictedLocked(int uid, int code, String packageName,
boolean isPrivileged) {
int userHandle = UserHandle.getUserId(uid); int userHandle = UserHandle.getUserId(uid);
final int restrictionSetCount = mOpUserRestrictions.size(); final int restrictionSetCount = mOpUserRestrictions.size();
@@ -2691,8 +2732,8 @@ public class AppOpsService extends IAppOpsService.Stub {
if (AppOpsManager.opAllowSystemBypassRestriction(code)) { if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
// If we are the system, bypass user restrictions for certain codes // If we are the system, bypass user restrictions for certain codes
synchronized (this) { synchronized (this) {
Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, Ops ops = getOpsRawLocked(uid, packageName, isPrivileged,
false /* uidMismatchExpected */); true /* edit */);
if ((ops != null) && ops.isPrivileged) { if ((ops != null) && ops.isPrivileged) {
return false; return false;
} }
@@ -3063,7 +3104,7 @@ public class AppOpsService extends IAppOpsService.Stub {
out.attribute(null, "n", Integer.toString(pkg.getUid())); out.attribute(null, "n", Integer.toString(pkg.getUid()));
synchronized (this) { synchronized (this) {
Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
false /* edit */, false /* uidMismatchExpected */); false /* isPrivileged */, false /* edit */);
// Should always be present as the list of PackageOps is generated // Should always be present as the list of PackageOps is generated
// from Ops. // from Ops.
if (ops != null) { if (ops != null) {
@@ -4641,19 +4682,9 @@ public class AppOpsService extends IAppOpsService.Stub {
} }
} }
@Override
public void setUidMode(int code, int uid, int mode) {
AppOpsService.this.setUidMode(code, uid, mode);
}
@Override @Override
public void setAllPkgModesToDefault(int code, int uid) { public void setAllPkgModesToDefault(int code, int uid) {
AppOpsService.this.setAllPkgModesToDefault(code, uid); AppOpsService.this.setAllPkgModesToDefault(code, uid);
} }
@Override
public @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName) {
return AppOpsService.this.checkOperationUnchecked(code, uid, packageName, true, false);
}
} }
} }