DO NOT MERGE Fix AppOpsServiceTest
am: c03b32c406
Change-Id: Icb334aaa1f7a6ad6815fb034bbac27f3ace09cdb
This commit is contained in:
@@ -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);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1110,8 +1110,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;
|
||||||
}
|
}
|
||||||
@@ -1208,8 +1208,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) {
|
||||||
@@ -1409,11 +1408,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.
|
||||||
*
|
*
|
||||||
@@ -1421,19 +1415,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;
|
||||||
@@ -1798,14 +1798,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.
|
||||||
*
|
*
|
||||||
@@ -1813,20 +1805,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isPrivileged;
|
||||||
|
|
||||||
|
try {
|
||||||
|
isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
Slog.e(TAG, "checkOperation", e);
|
||||||
|
return AppOpsManager.opToDefaultMode(code);
|
||||||
|
}
|
||||||
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (verify) {
|
if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) {
|
||||||
checkPackage(uid, packageName);
|
|
||||||
}
|
|
||||||
if (isOpRestrictedLocked(uid, code, packageName)) {
|
|
||||||
return AppOpsManager.MODE_IGNORED;
|
return AppOpsManager.MODE_IGNORED;
|
||||||
}
|
}
|
||||||
code = AppOpsManager.opToSwitch(code);
|
code = AppOpsManager.opToSwitch(code);
|
||||||
@@ -1836,7 +1834,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);
|
||||||
}
|
}
|
||||||
@@ -1941,14 +1939,12 @@ 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;
|
} catch (SecurityException ignored) {
|
||||||
} else {
|
return AppOpsManager.MODE_ERRORED;
|
||||||
return AppOpsManager.MODE_ERRORED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2011,9 +2007,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);
|
||||||
@@ -2022,7 +2025,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;
|
||||||
@@ -2181,16 +2184,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);
|
||||||
@@ -2262,8 +2274,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;
|
||||||
}
|
}
|
||||||
@@ -2513,8 +2534,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;
|
||||||
@@ -2532,47 +2621,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);
|
||||||
}
|
}
|
||||||
@@ -2580,7 +2628,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.
|
||||||
*
|
*
|
||||||
@@ -2638,23 +2686,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;
|
||||||
}
|
}
|
||||||
@@ -2684,7 +2724,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();
|
||||||
|
|
||||||
@@ -2696,8 +2737,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;
|
||||||
}
|
}
|
||||||
@@ -3068,7 +3109,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) {
|
||||||
@@ -4646,19 +4687,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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,14 @@
|
|||||||
"include-filter": "com.android.server.appop"
|
"include-filter": "com.android.server.appop"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "FrameworksMockingServicesTests",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"include-filter": "com.android.server.appop"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
|
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
|
||||||
<uses-permission android:name="android.permission.HARDWARE_TEST"/>
|
<uses-permission android:name="android.permission.HARDWARE_TEST"/>
|
||||||
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
||||||
|
|
||||||
<application android:testOnly="true"
|
<application android:testOnly="true"
|
||||||
android:debuggable="true">
|
android:debuggable="true">
|
||||||
|
|||||||
@@ -25,14 +25,27 @@ import static android.app.AppOpsManager.OP_READ_SMS;
|
|||||||
import static android.app.AppOpsManager.OP_WIFI_SCAN;
|
import static android.app.AppOpsManager.OP_WIFI_SCAN;
|
||||||
import static android.app.AppOpsManager.OP_WRITE_SMS;
|
import static android.app.AppOpsManager.OP_WRITE_SMS;
|
||||||
|
|
||||||
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
|
||||||
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||||
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
|
||||||
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
|
||||||
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
|
||||||
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static com.google.common.truth.Truth.assertWithMessage;
|
import static com.google.common.truth.Truth.assertWithMessage;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.ArgumentMatchers.nullable;
|
||||||
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.AppOpsManager;
|
import android.app.AppOpsManager;
|
||||||
import android.app.AppOpsManager.OpEntry;
|
import android.app.AppOpsManager.OpEntry;
|
||||||
import android.app.AppOpsManager.PackageOps;
|
import android.app.AppOpsManager.PackageOps;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManagerInternal;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
@@ -43,12 +56,17 @@ import androidx.test.InstrumentationRegistry;
|
|||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
|
||||||
|
import com.android.server.LocalServices;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.quality.Strictness;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -69,21 +87,46 @@ public class AppOpsServiceTest {
|
|||||||
// State will be persisted into this XML file.
|
// State will be persisted into this XML file.
|
||||||
private static final String APP_OPS_FILENAME = "appops-service-test.xml";
|
private static final String APP_OPS_FILENAME = "appops-service-test.xml";
|
||||||
|
|
||||||
|
private static final Context sContext = InstrumentationRegistry.getTargetContext();
|
||||||
|
private static final String sMyPackageName = sContext.getOpPackageName();
|
||||||
|
|
||||||
private File mAppOpsFile;
|
private File mAppOpsFile;
|
||||||
private Context mContext;
|
|
||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
private AppOpsManager mAppOpsManager;
|
|
||||||
private AppOpsService mAppOpsService;
|
private AppOpsService mAppOpsService;
|
||||||
private String mMyPackageName;
|
|
||||||
private int mMyUid;
|
private int mMyUid;
|
||||||
private long mTestStartMillis;
|
private long mTestStartMillis;
|
||||||
|
private StaticMockitoSession mMockingSession;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void mockPackageManagerInternalGetApplicationInfo() {
|
||||||
|
mMockingSession = mockitoSession()
|
||||||
|
.strictness(Strictness.LENIENT)
|
||||||
|
.spyStatic(LocalServices.class)
|
||||||
|
.startMocking();
|
||||||
|
|
||||||
|
// Mock LocalServices.getService(PackageManagerInternal.class).getApplicationInfo dependency
|
||||||
|
// needed by AppOpsService
|
||||||
|
PackageManagerInternal mockPackageManagerInternal = mock(PackageManagerInternal.class);
|
||||||
|
when(mockPackageManagerInternal.getApplicationInfo(eq(sMyPackageName), anyInt(), anyInt(),
|
||||||
|
anyInt())).thenReturn(sContext.getApplicationInfo());
|
||||||
|
doReturn(mockPackageManagerInternal).when(
|
||||||
|
() -> LocalServices.getService(PackageManagerInternal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupAppOpsService() {
|
||||||
|
mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
|
||||||
|
mAppOpsService.mContext = spy(sContext);
|
||||||
|
|
||||||
|
// Always approve all permission checks
|
||||||
|
doNothing().when(mAppOpsService.mContext).enforcePermission(anyString(), anyInt(),
|
||||||
|
anyInt(), nullable(String.class));
|
||||||
|
}
|
||||||
|
|
||||||
private static String sDefaultAppopHistoryParameters;
|
private static String sDefaultAppopHistoryParameters;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
mContext = InstrumentationRegistry.getTargetContext();
|
mAppOpsFile = new File(sContext.getFilesDir(), APP_OPS_FILENAME);
|
||||||
mAppOpsFile = new File(mContext.getFilesDir(), APP_OPS_FILENAME);
|
|
||||||
if (mAppOpsFile.exists()) {
|
if (mAppOpsFile.exists()) {
|
||||||
// Start with a clean state (persisted into XML).
|
// Start with a clean state (persisted into XML).
|
||||||
mAppOpsFile.delete();
|
mAppOpsFile.delete();
|
||||||
@@ -92,13 +135,10 @@ public class AppOpsServiceTest {
|
|||||||
HandlerThread handlerThread = new HandlerThread(TAG);
|
HandlerThread handlerThread = new HandlerThread(TAG);
|
||||||
handlerThread.start();
|
handlerThread.start();
|
||||||
mHandler = new Handler(handlerThread.getLooper());
|
mHandler = new Handler(handlerThread.getLooper());
|
||||||
mMyPackageName = mContext.getOpPackageName();
|
|
||||||
mMyUid = Process.myUid();
|
mMyUid = Process.myUid();
|
||||||
|
|
||||||
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
|
setupAppOpsService();
|
||||||
mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
|
mAppOpsService.mHistoricalRegistry.systemReady(sContext.getContentResolver());
|
||||||
mAppOpsService.mHistoricalRegistry.systemReady(mContext.getContentResolver());
|
|
||||||
mAppOpsService.mContext = mContext;
|
|
||||||
mTestStartMillis = System.currentTimeMillis();
|
mTestStartMillis = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,6 +158,11 @@ public class AppOpsServiceTest {
|
|||||||
sDefaultAppopHistoryParameters);
|
sDefaultAppopHistoryParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void resetStaticMocks() {
|
||||||
|
mMockingSession.finishMocking();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetOpsForPackage_noOpsLogged() {
|
public void testGetOpsForPackage_noOpsLogged() {
|
||||||
assertThat(getLoggedOps()).isNull();
|
assertThat(getLoggedOps()).isNull();
|
||||||
@@ -125,16 +170,16 @@ public class AppOpsServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoteOperationAndGetOpsForPackage() {
|
public void testNoteOperationAndGetOpsForPackage() {
|
||||||
mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
|
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
|
||||||
mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, mMyPackageName, MODE_ERRORED);
|
mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED);
|
||||||
|
|
||||||
// Note an op that's allowed.
|
// Note an op that's allowed.
|
||||||
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
|
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName);
|
||||||
List<PackageOps> loggedOps = getLoggedOps();
|
List<PackageOps> loggedOps = getLoggedOps();
|
||||||
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
|
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
|
||||||
|
|
||||||
// Note another op that's not allowed.
|
// Note another op that's not allowed.
|
||||||
mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, mMyPackageName);
|
mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName);
|
||||||
loggedOps = getLoggedOps();
|
loggedOps = getLoggedOps();
|
||||||
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
|
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
|
||||||
assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED);
|
assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED);
|
||||||
@@ -148,17 +193,17 @@ public class AppOpsServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testNoteOperationAndGetOpsForPackage_controlledByDifferentOp() {
|
public void testNoteOperationAndGetOpsForPackage_controlledByDifferentOp() {
|
||||||
// This op controls WIFI_SCAN
|
// This op controls WIFI_SCAN
|
||||||
mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_ALLOWED);
|
mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ALLOWED);
|
||||||
|
|
||||||
assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, mMyPackageName))
|
assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName))
|
||||||
.isEqualTo(MODE_ALLOWED);
|
.isEqualTo(MODE_ALLOWED);
|
||||||
|
|
||||||
assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, -1,
|
assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, -1,
|
||||||
MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */);
|
MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */);
|
||||||
|
|
||||||
// Now set COARSE_LOCATION to ERRORED -> this will make WIFI_SCAN disabled as well.
|
// Now set COARSE_LOCATION to ERRORED -> this will make WIFI_SCAN disabled as well.
|
||||||
mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_ERRORED);
|
mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ERRORED);
|
||||||
assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, mMyPackageName))
|
assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName))
|
||||||
.isEqualTo(MODE_ERRORED);
|
.isEqualTo(MODE_ERRORED);
|
||||||
|
|
||||||
assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, mTestStartMillis,
|
assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, mTestStartMillis,
|
||||||
@@ -168,15 +213,14 @@ public class AppOpsServiceTest {
|
|||||||
// Tests the dumping and restoring of the in-memory state to/from XML.
|
// Tests the dumping and restoring of the in-memory state to/from XML.
|
||||||
@Test
|
@Test
|
||||||
public void testStatePersistence() {
|
public void testStatePersistence() {
|
||||||
mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
|
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
|
||||||
mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, mMyPackageName, MODE_ERRORED);
|
mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED);
|
||||||
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
|
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName);
|
||||||
mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, mMyPackageName);
|
mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName);
|
||||||
mAppOpsService.writeState();
|
mAppOpsService.writeState();
|
||||||
|
|
||||||
// Create a new app ops service, and initialize its state from XML.
|
// Create a new app ops service, and initialize its state from XML.
|
||||||
mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
|
setupAppOpsService();
|
||||||
mAppOpsService.mContext = mContext;
|
|
||||||
mAppOpsService.readState();
|
mAppOpsService.readState();
|
||||||
|
|
||||||
// Query the state of the 2nd service.
|
// Query the state of the 2nd service.
|
||||||
@@ -188,13 +232,12 @@ public class AppOpsServiceTest {
|
|||||||
// Tests that ops are persisted during shutdown.
|
// Tests that ops are persisted during shutdown.
|
||||||
@Test
|
@Test
|
||||||
public void testShutdown() {
|
public void testShutdown() {
|
||||||
mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
|
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
|
||||||
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
|
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName);
|
||||||
mAppOpsService.shutdown();
|
mAppOpsService.shutdown();
|
||||||
|
|
||||||
// Create a new app ops service, and initialize its state from XML.
|
// Create a new app ops service, and initialize its state from XML.
|
||||||
mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
|
setupAppOpsService();
|
||||||
mAppOpsService.mContext = mContext;
|
|
||||||
mAppOpsService.readState();
|
mAppOpsService.readState();
|
||||||
|
|
||||||
// Query the state of the 2nd service.
|
// Query the state of the 2nd service.
|
||||||
@@ -204,21 +247,21 @@ public class AppOpsServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetOpsForPackage() {
|
public void testGetOpsForPackage() {
|
||||||
mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
|
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
|
||||||
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
|
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName);
|
||||||
|
|
||||||
// Query all ops
|
// Query all ops
|
||||||
List<PackageOps> loggedOps = mAppOpsService.getOpsForPackage(
|
List<PackageOps> loggedOps = mAppOpsService.getOpsForPackage(
|
||||||
mMyUid, mMyPackageName, null /* all ops */);
|
mMyUid, sMyPackageName, null /* all ops */);
|
||||||
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
|
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
|
||||||
|
|
||||||
// Query specific ops
|
// Query specific ops
|
||||||
loggedOps = mAppOpsService.getOpsForPackage(
|
loggedOps = mAppOpsService.getOpsForPackage(
|
||||||
mMyUid, mMyPackageName, new int[]{OP_READ_SMS, OP_WRITE_SMS});
|
mMyUid, sMyPackageName, new int[]{OP_READ_SMS, OP_WRITE_SMS});
|
||||||
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
|
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
|
||||||
|
|
||||||
// Query unknown UID
|
// Query unknown UID
|
||||||
loggedOps = mAppOpsService.getOpsForPackage(mMyUid + 1, mMyPackageName, null /* all ops */);
|
loggedOps = mAppOpsService.getOpsForPackage(mMyUid + 1, sMyPackageName, null /* all ops */);
|
||||||
assertThat(loggedOps).isNull();
|
assertThat(loggedOps).isNull();
|
||||||
|
|
||||||
// Query unknown package name
|
// Query unknown package name
|
||||||
@@ -226,31 +269,31 @@ public class AppOpsServiceTest {
|
|||||||
assertThat(loggedOps).isNull();
|
assertThat(loggedOps).isNull();
|
||||||
|
|
||||||
// Query op code that's not been logged
|
// Query op code that's not been logged
|
||||||
loggedOps = mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName,
|
loggedOps = mAppOpsService.getOpsForPackage(mMyUid, sMyPackageName,
|
||||||
new int[]{OP_WRITE_SMS});
|
new int[]{OP_WRITE_SMS});
|
||||||
assertThat(loggedOps).isNull();
|
assertThat(loggedOps).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPackageRemoved() {
|
public void testPackageRemoved() {
|
||||||
mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
|
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
|
||||||
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
|
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName);
|
||||||
|
|
||||||
List<PackageOps> loggedOps = getLoggedOps();
|
List<PackageOps> loggedOps = getLoggedOps();
|
||||||
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
|
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
|
||||||
|
|
||||||
mAppOpsService.packageRemoved(mMyUid, mMyPackageName);
|
mAppOpsService.packageRemoved(mMyUid, sMyPackageName);
|
||||||
assertThat(getLoggedOps()).isNull();
|
assertThat(getLoggedOps()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("Historical appops are disabled in Android Q")
|
@Ignore("Historical appops are disabled in Android Q")
|
||||||
@Test
|
@Test
|
||||||
public void testPackageRemovedHistoricalOps() throws InterruptedException {
|
public void testPackageRemovedHistoricalOps() throws InterruptedException {
|
||||||
mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
|
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
|
||||||
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
|
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName);
|
||||||
|
|
||||||
AppOpsManager.HistoricalOps historicalOps = new AppOpsManager.HistoricalOps(0, 15000);
|
AppOpsManager.HistoricalOps historicalOps = new AppOpsManager.HistoricalOps(0, 15000);
|
||||||
historicalOps.increaseAccessCount(OP_READ_SMS, mMyUid, mMyPackageName,
|
historicalOps.increaseAccessCount(OP_READ_SMS, mMyUid, sMyPackageName,
|
||||||
AppOpsManager.UID_STATE_PERSISTENT, 0, 1);
|
AppOpsManager.UID_STATE_PERSISTENT, 0, 1);
|
||||||
|
|
||||||
mAppOpsService.addHistoricalOps(historicalOps);
|
mAppOpsService.addHistoricalOps(historicalOps);
|
||||||
@@ -263,7 +306,7 @@ public class AppOpsServiceTest {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// First, do a fetch to ensure it's written
|
// First, do a fetch to ensure it's written
|
||||||
mAppOpsService.getHistoricalOps(mMyUid, mMyPackageName, null, 0, Long.MAX_VALUE, 0,
|
mAppOpsService.getHistoricalOps(mMyUid, sMyPackageName, null, 0, Long.MAX_VALUE, 0,
|
||||||
callback);
|
callback);
|
||||||
|
|
||||||
latchRef.get().await(5, TimeUnit.SECONDS);
|
latchRef.get().await(5, TimeUnit.SECONDS);
|
||||||
@@ -271,11 +314,11 @@ public class AppOpsServiceTest {
|
|||||||
assertThat(resultOpsRef.get().isEmpty()).isFalse();
|
assertThat(resultOpsRef.get().isEmpty()).isFalse();
|
||||||
|
|
||||||
// Then, check it's deleted on removal
|
// Then, check it's deleted on removal
|
||||||
mAppOpsService.packageRemoved(mMyUid, mMyPackageName);
|
mAppOpsService.packageRemoved(mMyUid, sMyPackageName);
|
||||||
|
|
||||||
latchRef.set(new CountDownLatch(1));
|
latchRef.set(new CountDownLatch(1));
|
||||||
|
|
||||||
mAppOpsService.getHistoricalOps(mMyUid, mMyPackageName, null, 0, Long.MAX_VALUE, 0,
|
mAppOpsService.getHistoricalOps(mMyUid, sMyPackageName, null, 0, Long.MAX_VALUE, 0,
|
||||||
callback);
|
callback);
|
||||||
|
|
||||||
latchRef.get().await(5, TimeUnit.SECONDS);
|
latchRef.get().await(5, TimeUnit.SECONDS);
|
||||||
@@ -285,8 +328,8 @@ public class AppOpsServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUidRemoved() {
|
public void testUidRemoved() {
|
||||||
mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
|
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
|
||||||
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
|
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName);
|
||||||
|
|
||||||
List<PackageOps> loggedOps = getLoggedOps();
|
List<PackageOps> loggedOps = getLoggedOps();
|
||||||
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
|
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
|
||||||
@@ -297,7 +340,7 @@ public class AppOpsServiceTest {
|
|||||||
|
|
||||||
private void setupProcStateTests() {
|
private void setupProcStateTests() {
|
||||||
// For the location proc state tests
|
// For the location proc state tests
|
||||||
mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_FOREGROUND);
|
mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_FOREGROUND);
|
||||||
mAppOpsService.mConstants.FG_SERVICE_STATE_SETTLE_TIME = 0;
|
mAppOpsService.mConstants.FG_SERVICE_STATE_SETTLE_TIME = 0;
|
||||||
mAppOpsService.mConstants.TOP_STATE_SETTLE_TIME = 0;
|
mAppOpsService.mConstants.TOP_STATE_SETTLE_TIME = 0;
|
||||||
mAppOpsService.mConstants.BG_STATE_SETTLE_TIME = 0;
|
mAppOpsService.mConstants.BG_STATE_SETTLE_TIME = 0;
|
||||||
@@ -308,18 +351,18 @@ public class AppOpsServiceTest {
|
|||||||
setupProcStateTests();
|
setupProcStateTests();
|
||||||
|
|
||||||
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
|
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
|
||||||
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
|
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
|
||||||
.isNotEqualTo(MODE_ALLOWED);
|
.isNotEqualTo(MODE_ALLOWED);
|
||||||
|
|
||||||
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP);
|
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP);
|
||||||
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
|
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
|
||||||
.isEqualTo(MODE_ALLOWED);
|
.isEqualTo(MODE_ALLOWED);
|
||||||
|
|
||||||
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
|
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
|
||||||
// Second time to make sure that settle time is overcome
|
// Second time to make sure that settle time is overcome
|
||||||
Thread.sleep(50);
|
Thread.sleep(50);
|
||||||
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
|
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
|
||||||
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
|
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
|
||||||
.isNotEqualTo(MODE_ALLOWED);
|
.isNotEqualTo(MODE_ALLOWED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,11 +371,11 @@ public class AppOpsServiceTest {
|
|||||||
setupProcStateTests();
|
setupProcStateTests();
|
||||||
|
|
||||||
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
|
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
|
||||||
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
|
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
|
||||||
.isNotEqualTo(MODE_ALLOWED);
|
.isNotEqualTo(MODE_ALLOWED);
|
||||||
|
|
||||||
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
|
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
|
||||||
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
|
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
|
||||||
.isNotEqualTo(MODE_ALLOWED);
|
.isNotEqualTo(MODE_ALLOWED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,12 +384,12 @@ public class AppOpsServiceTest {
|
|||||||
setupProcStateTests();
|
setupProcStateTests();
|
||||||
|
|
||||||
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
|
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
|
||||||
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
|
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
|
||||||
.isNotEqualTo(MODE_ALLOWED);
|
.isNotEqualTo(MODE_ALLOWED);
|
||||||
|
|
||||||
mAppOpsService.updateUidProcState(mMyUid,
|
mAppOpsService.updateUidProcState(mMyUid,
|
||||||
PROCESS_STATE_FOREGROUND_SERVICE_LOCATION);
|
PROCESS_STATE_FOREGROUND_SERVICE_LOCATION);
|
||||||
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
|
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
|
||||||
.isEqualTo(MODE_ALLOWED);
|
.isEqualTo(MODE_ALLOWED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,18 +398,18 @@ public class AppOpsServiceTest {
|
|||||||
setupProcStateTests();
|
setupProcStateTests();
|
||||||
|
|
||||||
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
|
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
|
||||||
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
|
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
|
||||||
.isNotEqualTo(MODE_ALLOWED);
|
.isNotEqualTo(MODE_ALLOWED);
|
||||||
|
|
||||||
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP);
|
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP);
|
||||||
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
|
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
|
||||||
.isEqualTo(MODE_ALLOWED);
|
.isEqualTo(MODE_ALLOWED);
|
||||||
|
|
||||||
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
|
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
|
||||||
// Second time to make sure that settle time is overcome
|
// Second time to make sure that settle time is overcome
|
||||||
Thread.sleep(50);
|
Thread.sleep(50);
|
||||||
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
|
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
|
||||||
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
|
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
|
||||||
.isNotEqualTo(MODE_ALLOWED);
|
.isNotEqualTo(MODE_ALLOWED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,30 +418,30 @@ public class AppOpsServiceTest {
|
|||||||
setupProcStateTests();
|
setupProcStateTests();
|
||||||
|
|
||||||
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
|
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
|
||||||
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
|
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
|
||||||
.isNotEqualTo(MODE_ALLOWED);
|
.isNotEqualTo(MODE_ALLOWED);
|
||||||
|
|
||||||
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP);
|
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP);
|
||||||
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
|
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
|
||||||
.isEqualTo(MODE_ALLOWED);
|
.isEqualTo(MODE_ALLOWED);
|
||||||
|
|
||||||
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION);
|
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION);
|
||||||
// Second time to make sure that settle time is overcome
|
// Second time to make sure that settle time is overcome
|
||||||
Thread.sleep(50);
|
Thread.sleep(50);
|
||||||
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION);
|
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION);
|
||||||
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
|
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
|
||||||
.isEqualTo(MODE_ALLOWED);
|
.isEqualTo(MODE_ALLOWED);
|
||||||
|
|
||||||
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
|
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
|
||||||
// Second time to make sure that settle time is overcome
|
// Second time to make sure that settle time is overcome
|
||||||
Thread.sleep(50);
|
Thread.sleep(50);
|
||||||
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
|
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
|
||||||
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
|
assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
|
||||||
.isNotEqualTo(MODE_ALLOWED);
|
.isNotEqualTo(MODE_ALLOWED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<PackageOps> getLoggedOps() {
|
private List<PackageOps> getLoggedOps() {
|
||||||
return mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName, null /* all ops */);
|
return mAppOpsService.getOpsForPackage(mMyUid, sMyPackageName, null /* all ops */);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertContainsOp(List<PackageOps> loggedOps, int opCode, long minMillis,
|
private void assertContainsOp(List<PackageOps> loggedOps, int opCode, long minMillis,
|
||||||
@@ -407,7 +450,7 @@ public class AppOpsServiceTest {
|
|||||||
boolean opLogged = false;
|
boolean opLogged = false;
|
||||||
for (PackageOps pkgOps : loggedOps) {
|
for (PackageOps pkgOps : loggedOps) {
|
||||||
assertWithMessage("Unexpected UID").that(mMyUid).isEqualTo(pkgOps.getUid());
|
assertWithMessage("Unexpected UID").that(mMyUid).isEqualTo(pkgOps.getUid());
|
||||||
assertWithMessage("Unexpected package name").that(mMyPackageName).isEqualTo(
|
assertWithMessage("Unexpected package name").that(sMyPackageName).isEqualTo(
|
||||||
pkgOps.getPackageName());
|
pkgOps.getPackageName());
|
||||||
|
|
||||||
for (OpEntry opEntry : pkgOps.getOps()) {
|
for (OpEntry opEntry : pkgOps.getOps()) {
|
||||||
Reference in New Issue
Block a user