Make DPM/DPMS unit-testable
- Now all services that DPMS uses are injectable.
- Introduce some wrappers to make static methods and final class mockable.
(e.g. for Binder.getCallingUid())
- In unit tests we replace those with Mockito mocks, except we use a partial
mock for PackageManager, because we use way too many methods of this and
most of them are okay to use directly.
- To install a partial mock to PackageManager, I needed to make
ApplicationPackageManager @hide public non-final.
- For a starter, added tests for DPM.setAmin().
Bug 24061108
Change-Id: I2afd51d8bc0038992d5f9be38c686260be775b75
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 0cd02dd..5544a71 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -93,8 +93,8 @@
import java.util.Map;
import java.util.Objects;
-/*package*/
-final class ApplicationPackageManager extends PackageManager {
+/** @hide */
+public class ApplicationPackageManager extends PackageManager {
private static final String TAG = "ApplicationPackageManager";
private final static boolean DEBUG_ICONS = false;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 3d264c6..288a2cb 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -240,7 +240,7 @@
new CachedServiceFetcher<DevicePolicyManager>() {
@Override
public DevicePolicyManager createService(ContextImpl ctx) {
- return DevicePolicyManager.create(ctx, ctx.mMainThread.getHandler());
+ return DevicePolicyManager.create(ctx);
}});
registerService(Context.DOWNLOAD_SERVICE, DownloadManager.class,
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ac50699..e6484e9 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -32,7 +32,6 @@
import android.graphics.Bitmap;
import android.net.ProxyInfo;
import android.os.Bundle;
-import android.os.Handler;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteCallback;
@@ -45,6 +44,7 @@
import android.service.restrictions.RestrictionsReceiver;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.org.conscrypt.TrustedCertificateStore;
import org.xmlpull.v1.XmlPullParserException;
@@ -87,18 +87,30 @@
private final Context mContext;
private final IDevicePolicyManager mService;
- private DevicePolicyManager(Context context, Handler handler) {
- mContext = context;
- mService = IDevicePolicyManager.Stub.asInterface(
- ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
+ private DevicePolicyManager(Context context) {
+ this(context, IDevicePolicyManager.Stub.asInterface(
+ ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)));
}
/** @hide */
- public static DevicePolicyManager create(Context context, Handler handler) {
- DevicePolicyManager me = new DevicePolicyManager(context, handler);
+ @VisibleForTesting
+ protected DevicePolicyManager(Context context, IDevicePolicyManager service) {
+ mContext = context;
+ mService = service;
+ }
+
+ /** @hide */
+ public static DevicePolicyManager create(Context context) {
+ DevicePolicyManager me = new DevicePolicyManager(context);
return me.mService != null ? me : null;
}
+ /** @hide test will override it. */
+ @VisibleForTesting
+ protected int myUserId() {
+ return UserHandle.myUserId();
+ }
+
/**
* Activity action: Starts the provisioning flow which sets up a managed profile.
*
@@ -823,7 +835,7 @@
* active (enabled) in the system.
*/
public boolean isAdminActive(@NonNull ComponentName admin) {
- return isAdminActiveAsUser(admin, UserHandle.myUserId());
+ return isAdminActiveAsUser(admin, myUserId());
}
/**
@@ -863,7 +875,7 @@
* returned.
*/
public List<ComponentName> getActiveAdmins() {
- return getActiveAdminsAsUser(UserHandle.myUserId());
+ return getActiveAdminsAsUser(myUserId());
}
/**
@@ -889,7 +901,7 @@
public boolean packageHasActiveAdmins(String packageName) {
if (mService != null) {
try {
- return mService.packageHasActiveAdmins(packageName, UserHandle.myUserId());
+ return mService.packageHasActiveAdmins(packageName, myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -906,7 +918,7 @@
public void removeActiveAdmin(@NonNull ComponentName admin) {
if (mService != null) {
try {
- mService.removeActiveAdmin(admin, UserHandle.myUserId());
+ mService.removeActiveAdmin(admin, myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -925,7 +937,7 @@
public boolean hasGrantedPolicy(@NonNull ComponentName admin, int usesPolicy) {
if (mService != null) {
try {
- return mService.hasGrantedPolicy(admin, usesPolicy, UserHandle.myUserId());
+ return mService.hasGrantedPolicy(admin, usesPolicy, myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1040,7 +1052,7 @@
* all admins.
*/
public int getPasswordQuality(@Nullable ComponentName admin) {
- return getPasswordQuality(admin, UserHandle.myUserId());
+ return getPasswordQuality(admin, myUserId());
}
/** @hide per-user version */
@@ -1093,7 +1105,7 @@
* all admins.
*/
public int getPasswordMinimumLength(@Nullable ComponentName admin) {
- return getPasswordMinimumLength(admin, UserHandle.myUserId());
+ return getPasswordMinimumLength(admin, myUserId());
}
/** @hide per-user version */
@@ -1154,7 +1166,7 @@
* password.
*/
public int getPasswordMinimumUpperCase(@Nullable ComponentName admin) {
- return getPasswordMinimumUpperCase(admin, UserHandle.myUserId());
+ return getPasswordMinimumUpperCase(admin, myUserId());
}
/** @hide per-user version */
@@ -1215,7 +1227,7 @@
* password.
*/
public int getPasswordMinimumLowerCase(@Nullable ComponentName admin) {
- return getPasswordMinimumLowerCase(admin, UserHandle.myUserId());
+ return getPasswordMinimumLowerCase(admin, myUserId());
}
/** @hide per-user version */
@@ -1273,7 +1285,7 @@
* @return The minimum number of letters required in the password.
*/
public int getPasswordMinimumLetters(@Nullable ComponentName admin) {
- return getPasswordMinimumLetters(admin, UserHandle.myUserId());
+ return getPasswordMinimumLetters(admin, myUserId());
}
/** @hide per-user version */
@@ -1332,7 +1344,7 @@
* @return The minimum number of numerical digits required in the password.
*/
public int getPasswordMinimumNumeric(@Nullable ComponentName admin) {
- return getPasswordMinimumNumeric(admin, UserHandle.myUserId());
+ return getPasswordMinimumNumeric(admin, myUserId());
}
/** @hide per-user version */
@@ -1390,7 +1402,7 @@
* @return The minimum number of symbols required in the password.
*/
public int getPasswordMinimumSymbols(@Nullable ComponentName admin) {
- return getPasswordMinimumSymbols(admin, UserHandle.myUserId());
+ return getPasswordMinimumSymbols(admin, myUserId());
}
/** @hide per-user version */
@@ -1449,7 +1461,7 @@
* @return The minimum number of letters required in the password.
*/
public int getPasswordMinimumNonLetter(@Nullable ComponentName admin) {
- return getPasswordMinimumNonLetter(admin, UserHandle.myUserId());
+ return getPasswordMinimumNonLetter(admin, myUserId());
}
/** @hide per-user version */
@@ -1540,7 +1552,7 @@
public long getPasswordExpirationTimeout(@Nullable ComponentName admin) {
if (mService != null) {
try {
- return mService.getPasswordExpirationTimeout(admin, UserHandle.myUserId());
+ return mService.getPasswordExpirationTimeout(admin, myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1561,7 +1573,7 @@
public long getPasswordExpiration(@Nullable ComponentName admin) {
if (mService != null) {
try {
- return mService.getPasswordExpiration(admin, UserHandle.myUserId());
+ return mService.getPasswordExpiration(admin, myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1577,7 +1589,7 @@
* @return The length of the password history
*/
public int getPasswordHistoryLength(@Nullable ComponentName admin) {
- return getPasswordHistoryLength(admin, UserHandle.myUserId());
+ return getPasswordHistoryLength(admin, myUserId());
}
/** @hide per-user version */
@@ -1617,7 +1629,7 @@
public boolean isActivePasswordSufficient() {
if (mService != null) {
try {
- return mService.isActivePasswordSufficient(UserHandle.myUserId());
+ return mService.isActivePasswordSufficient(myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1636,7 +1648,7 @@
public int getCurrentFailedPasswordAttempts() {
if (mService != null) {
try {
- return mService.getCurrentFailedPasswordAttempts(UserHandle.myUserId());
+ return mService.getCurrentFailedPasswordAttempts(myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1698,7 +1710,7 @@
* all admins.
*/
public int getMaximumFailedPasswordsForWipe(@Nullable ComponentName admin) {
- return getMaximumFailedPasswordsForWipe(admin, UserHandle.myUserId());
+ return getMaximumFailedPasswordsForWipe(admin, myUserId());
}
/** @hide per-user version */
@@ -1818,7 +1830,7 @@
* all admins if admin is null. Returns 0 if there are no restrictions.
*/
public long getMaximumTimeToLock(@Nullable ComponentName admin) {
- return getMaximumTimeToLock(admin, UserHandle.myUserId());
+ return getMaximumTimeToLock(admin, myUserId());
}
/** @hide per-user version */
@@ -1881,7 +1893,7 @@
public void wipeData(int flags) {
if (mService != null) {
try {
- mService.wipeData(flags, UserHandle.myUserId());
+ mService.wipeData(flags, myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1995,7 +2007,7 @@
public ComponentName getGlobalProxyAdmin() {
if (mService != null) {
try {
- return mService.getGlobalProxyAdmin(UserHandle.myUserId());
+ return mService.getGlobalProxyAdmin(myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -2145,7 +2157,7 @@
public boolean getStorageEncryption(@Nullable ComponentName admin) {
if (mService != null) {
try {
- return mService.getStorageEncryption(admin, UserHandle.myUserId());
+ return mService.getStorageEncryption(admin, myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -2173,7 +2185,7 @@
* or {@link #ENCRYPTION_STATUS_ACTIVE}.
*/
public int getStorageEncryptionStatus() {
- return getStorageEncryptionStatus(UserHandle.myUserId());
+ return getStorageEncryptionStatus(myUserId());
}
/** @hide per-user version */
@@ -2410,7 +2422,7 @@
* have disabled the camera
*/
public boolean getCameraDisabled(@Nullable ComponentName admin) {
- return getCameraDisabled(admin, UserHandle.myUserId());
+ return getCameraDisabled(admin, myUserId());
}
/** @hide per-user version */
@@ -2457,7 +2469,7 @@
* have disabled screen capture.
*/
public boolean getScreenCaptureDisabled(@Nullable ComponentName admin) {
- return getScreenCaptureDisabled(admin, UserHandle.myUserId());
+ return getScreenCaptureDisabled(admin, myUserId());
}
/** @hide per-user version */
@@ -2557,7 +2569,7 @@
* for a list.
*/
public int getKeyguardDisabledFeatures(@Nullable ComponentName admin) {
- return getKeyguardDisabledFeatures(admin, UserHandle.myUserId());
+ return getKeyguardDisabledFeatures(admin, myUserId());
}
/** @hide per-user version */
@@ -2590,7 +2602,7 @@
* @hide
*/
public void setActiveAdmin(@NonNull ComponentName policyReceiver, boolean refreshing) {
- setActiveAdmin(policyReceiver, refreshing, UserHandle.myUserId());
+ setActiveAdmin(policyReceiver, refreshing, myUserId());
}
/**
@@ -2627,7 +2639,7 @@
public void getRemoveWarning(@Nullable ComponentName admin, RemoteCallback result) {
if (mService != null) {
try {
- mService.getRemoveWarning(admin, result, UserHandle.myUserId());
+ mService.getRemoveWarning(admin, result, myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -2956,7 +2968,7 @@
throws IllegalArgumentException {
if (mService != null) {
try {
- final int myUserId = UserHandle.myUserId();
+ final int myUserId = myUserId();
mService.setActiveAdmin(admin, false, myUserId);
return mService.setProfileOwner(admin, ownerName, myUserId);
} catch (RemoteException re) {
@@ -3301,7 +3313,7 @@
*/
public List<PersistableBundle> getTrustAgentConfiguration(@Nullable ComponentName admin,
@NonNull ComponentName agent) {
- return getTrustAgentConfiguration(admin, agent, UserHandle.myUserId());
+ return getTrustAgentConfiguration(admin, agent, myUserId());
}
/** @hide per-user version */
@@ -3927,7 +3939,7 @@
* @see #setAccountManagementDisabled
*/
public String[] getAccountTypesWithManagementDisabled() {
- return getAccountTypesWithManagementDisabledAsUser(UserHandle.myUserId());
+ return getAccountTypesWithManagementDisabledAsUser(myUserId());
}
/**
diff --git a/core/java/com/android/server/LocalServices.java b/core/java/com/android/server/LocalServices.java
index 25dcb30..9c632ea 100644
--- a/core/java/com/android/server/LocalServices.java
+++ b/core/java/com/android/server/LocalServices.java
@@ -16,6 +16,8 @@
package com.android.server;
+import com.android.internal.annotations.VisibleForTesting;
+
import android.util.ArrayMap;
/**
@@ -57,4 +59,14 @@
sLocalServiceObjects.put(type, service);
}
}
+
+ /**
+ * Remove a service instance, must be only used in tests.
+ */
+ @VisibleForTesting
+ public static <T> void removeServiceForTest(Class<T> type) {
+ synchronized (sLocalServiceObjects) {
+ sLocalServiceObjects.remove(type);
+ }
+ }
}