From f76b06a6b546f430cf85e561858ed12eedc32b81 Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Tue, 22 Sep 2015 15:03:44 -0700 Subject: [PATCH] Test more DPM APIs. Bug 24061108 Change-Id: Ia9da19f62c0f4edf53ca1f4c213f0368ec1983ba --- .../devicepolicy/DevicePolicyManagerService.java | 107 ++++--- services/tests/servicestests/AndroidManifest.xml | 22 +- .../DevicePolicyManagerServiceTestable.java | 58 +++- .../devicepolicy/DevicePolicyManagerTest.java | 331 ++++++++++++++++++--- .../server/devicepolicy/DpmMockContext.java | 48 ++- .../android/server/devicepolicy/DpmTestUtils.java | 6 + ...ummyDeviceAdmin.java => DummyDeviceAdmins.java} | 10 +- .../com/android/server/devicepolicy/MockUtils.java | 33 ++ 8 files changed, 502 insertions(+), 113 deletions(-) rename services/tests/servicestests/src/com/android/server/devicepolicy/{DummyDeviceAdmin.java => DummyDeviceAdmins.java} (75%) diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index b0a04c71db48..3f70e0c7ccae 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -271,7 +271,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final Context mContext; final PackageManager mPackageManager; final UserManager mUserManager; - final PowerManager.WakeLock mWakeLock; final LocalService mLocalService; @@ -995,7 +994,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { boolean removed = false; if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle); DevicePolicyData policy = getUserData(userHandle); - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); synchronized (this) { for (int i = policy.mAdminList.size() - 1; i >= 0; i--) { ActiveAdmin aa = policy.mAdminList.get(i); @@ -1071,7 +1070,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** Unit test will override it to inject a mock. */ @VisibleForTesting - IWindowManager newIWindowManager() { + IWindowManager getIWindowManager() { return IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE)); } @@ -1083,6 +1082,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** Unit test will override it to inject a mock. */ @VisibleForTesting + IPackageManager getIPackageManager() { + return AppGlobals.getPackageManager(); + } + + /** Unit test will override it to inject a mock. */ + @VisibleForTesting LockPatternUtils newLockPatternUtils(Context context) { return new LockPatternUtils(context); } @@ -1129,13 +1134,33 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @VisibleForTesting - WakeLock powerManagerNewWakeLock(int levelAndFlags, String tag) { - return mContext.getSystemService(PowerManager.class).newWakeLock(levelAndFlags, tag); + void powerManagerGoToSleep(long time, int reason, int flags) { + mContext.getSystemService(PowerManager.class).goToSleep(time, reason, flags); } @VisibleForTesting - void powerManagerGoToSleep(long time, int reason, int flags) { - mContext.getSystemService(PowerManager.class).goToSleep(time, reason, flags); + boolean systemPropertiesGetBoolean(String key, boolean def) { + return SystemProperties.getBoolean(key, def); + } + + @VisibleForTesting + long systemPropertiesGetLong(String key, long def) { + return SystemProperties.getLong(key, def); + } + + @VisibleForTesting + String systemPropertiesGet(String key, String def) { + return SystemProperties.get(key, def); + } + + @VisibleForTesting + String systemPropertiesGet(String key) { + return SystemProperties.get(key); + } + + @VisibleForTesting + void systemPropertiesSet(String key, String value) { + SystemProperties.set(key, value); } /** @@ -1145,14 +1170,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mContext = context; mHandler = new Handler(getMyLooper()); mOwners = newOwners(); - mUserManager = getUserManager(); - mPackageManager = getPackageManager(); - mHasFeature = mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN); - mPowerManagerInternal = getPowerManagerInternal(); - mWakeLock = powerManagerNewWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM"); - mIWindowManager = newIWindowManager(); - mNotificationManager = getNotificationManager(); + + mUserManager = Preconditions.checkNotNull(getUserManager()); + mPackageManager = Preconditions.checkNotNull(getPackageManager()); + mPowerManagerInternal = Preconditions.checkNotNull(getPowerManagerInternal()); + mIWindowManager = Preconditions.checkNotNull(getIWindowManager()); + mNotificationManager = Preconditions.checkNotNull(getNotificationManager()); + mLocalService = new LocalService(); + + mHasFeature = mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN); if (!mHasFeature) { // Skip the rest of the initialization return; @@ -1862,7 +1889,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Ensure the status of the camera is synced down to the system. Interested native services // should monitor this value and act accordingly. String cameraPropertyForUser = SYSTEM_PROP_DISABLE_CAMERA_PREFIX + policy.mUserHandle; - boolean systemState = SystemProperties.getBoolean(cameraPropertyForUser, false); + boolean systemState = systemPropertiesGetBoolean(cameraPropertyForUser, false); boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle); if (cameraDisabled != systemState) { long token = binderClearCallingIdentity(); @@ -1870,7 +1897,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { String value = cameraDisabled ? "1" : "0"; if (DBG) Slog.v(LOG_TAG, "Change in camera state [" + cameraPropertyForUser + "] = " + value); - SystemProperties.set(cameraPropertyForUser, value); + systemPropertiesSet(cameraPropertyForUser, value); } finally { binderRestoreCallingIdentity(token); } @@ -3231,7 +3258,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private boolean isExtStorageEncrypted() { - String state = SystemProperties.get("vold.decrypt"); + String state = systemPropertiesGet("vold.decrypt"); return !"".equals(state); } @@ -3969,7 +3996,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}. */ private int getEncryptionStatus() { - String status = SystemProperties.get("ro.crypto.state", "unsupported"); + String status = systemPropertiesGet("ro.crypto.state", "unsupported"); if ("encrypted".equalsIgnoreCase(status)) { final long token = binderClearCallingIdentity(); try { @@ -4377,7 +4404,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } boolean isInitializerSystemApp; try { - isInitializerSystemApp = isSystemApp(AppGlobals.getPackageManager(), + isInitializerSystemApp = isSystemApp(getIPackageManager(), initializer.getPackageName(), binderGetCallingUserHandle().getIdentifier()); } catch (RemoteException | IllegalArgumentException e) { isInitializerSystemApp = false; @@ -4528,7 +4555,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final long ident = binderClearCallingIdentity(); try { clearUserRestrictions(userHandle); - AppGlobals.getPackageManager().updatePermissionFlagsForAllApps( + getIPackageManager().updatePermissionFlagsForAllApps( PackageManager.FLAG_PERMISSION_POLICY_FIXED, 0 /* flagValues */, userHandle.getIdentifier()); } catch (RemoteException re) { @@ -4596,7 +4623,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long id = binderClearCallingIdentity(); try { if (!isDeviceOwner(activeAdmin.info.getPackageName())) { - IPackageManager ipm = AppGlobals.getPackageManager(); + IPackageManager ipm = getIPackageManager(); ipm.setComponentEnabledSetting(who, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP, userId); @@ -4857,7 +4884,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void enableIfNecessary(String packageName, int userId) { try { - IPackageManager ipm = AppGlobals.getPackageManager(); + IPackageManager ipm = getIPackageManager(); ApplicationInfo ai = ipm.getApplicationInfo(packageName, PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId); @@ -4919,7 +4946,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); long id = binderClearCallingIdentity(); try { pm.addPersistentPreferredActivity(filter, activity, userHandle); @@ -4938,7 +4965,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); long id = binderClearCallingIdentity(); try { pm.clearPackagePersistentPreferredActivities(packageName, userHandle); @@ -5074,7 +5101,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); long id = binderClearCallingIdentity(); try { UserInfo parent = mUserManager.getProfileParent(callingUserId); @@ -5105,7 +5132,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int callingUserId = UserHandle.getCallingUserId(); synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); long id = binderClearCallingIdentity(); try { UserInfo parent = mUserManager.getProfileParent(callingUserId); @@ -5144,7 +5171,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { userIdToCheck = user.profileGroupId; } - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); for (String enabledPackage : enabledPackages) { boolean systemService = false; try { @@ -5276,7 +5303,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { List installedServices = accessibilityManager.getInstalledAccessibilityServiceList(); - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); if (installedServices != null) { for (AccessibilityServiceInfo service : installedServices) { ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo; @@ -5425,7 +5452,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { List imes = inputMethodManager.getInputMethodList(); long id = binderClearCallingIdentity(); try { - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); if (imes != null) { for (InputMethodInfo ime : imes) { ServiceInfo serviceInfo = ime.getServiceInfo(); @@ -5472,7 +5499,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long id = binderClearCallingIdentity(); try { String profileOwnerPkg = profileOwnerComponent.getPackageName(); - final IPackageManager ipm = AppGlobals.getPackageManager(); + final IPackageManager ipm = getIPackageManager(); IActivityManager activityManager = getIActivityManager(); final int userHandle = user.getIdentifier(); @@ -5624,8 +5651,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Send out notifications however as some clients may want to reread the // value which actually changed due to a restriction having been applied. final String property = Settings.Secure.SYS_PROP_SETTING_VERSION; - long version = SystemProperties.getLong(property, 0) + 1; - SystemProperties.set(property, Long.toString(version)); + long version = systemPropertiesGetLong(property, 0) + 1; + systemPropertiesSet(property, Long.toString(version)); final String name = Settings.Secure.LOCATION_PROVIDERS_ALLOWED; Uri url = Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name); @@ -5660,7 +5687,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long id = binderClearCallingIdentity(); try { - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); return pm.setApplicationHiddenSettingAsUser(packageName, hidden, callingUserId); } catch (RemoteException re) { // shouldn't happen @@ -5681,7 +5708,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long id = binderClearCallingIdentity(); try { - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); return pm.getApplicationHiddenSettingAsUser(packageName, callingUserId); } catch (RemoteException re) { // shouldn't happen @@ -5718,7 +5745,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { primaryUser = um.getUserInfo(userId); } - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); if (!isSystemApp(pm, packageName, primaryUser.id)) { throw new IllegalArgumentException("Only system apps can be enabled this way."); } @@ -5755,7 +5782,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { primaryUser = um.getUserInfo(userId); } - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); List activitiesToEnable = pm.queryIntentActivities(intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), 0, // no flags @@ -5851,7 +5878,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long id = binderClearCallingIdentity(); try { - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); pm.setBlockUninstallForUser(packageName, uninstallBlocked, userId); } catch (RemoteException re) { // Shouldn't happen. @@ -5876,7 +5903,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long id = binderClearCallingIdentity(); try { - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); return pm.getBlockUninstallForUser(packageName, userId); } catch (RemoteException re) { // Shouldn't happen. @@ -6560,7 +6587,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); long ident = binderClearCallingIdentity(); try { - final ApplicationInfo ai = AppGlobals.getPackageManager() + final ApplicationInfo ai = getIPackageManager() .getApplicationInfo(packageName, 0, user.getIdentifier()); final int targetSdkVersion = ai == null ? 0 : ai.targetSdkVersion; if (targetSdkVersion < android.os.Build.VERSION_CODES.M) { @@ -6607,7 +6634,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); long ident = binderClearCallingIdentity(); try { - int granted = AppGlobals.getPackageManager().checkPermission(permission, + int granted = getIPackageManager().checkPermission(permission, packageName, user.getIdentifier()); int permFlags = packageManager.getPermissionFlags(permission, packageName, user); if ((permFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index cb2c9b72c6eb..c147bccc19b5 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -67,8 +67,26 @@ - + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index cb439ebefbbc..7e730f6b5289 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -20,6 +20,7 @@ import com.android.internal.widget.LockPatternUtils; import android.app.IActivityManager; import android.app.NotificationManager; import android.content.Context; +import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.os.Looper; import android.os.PowerManager.WakeLock; @@ -45,9 +46,9 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi public static final String DEVICE_OWNER_FILE = "device_owner2.xml"; public static final String PROFILE_OWNER_FILE_BASE = "profile_owner.xml"; - final private File mLegacyFile; - final private File mDeviceOwnerFile; - final private File mProfileOwnerBase; + private final File mLegacyFile; + private final File mDeviceOwnerFile; + private final File mProfileOwnerBase; public OwnersTestable(Context context, File dataDir) { super(context); @@ -96,47 +97,52 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi } @Override - protected Owners newOwners() { + Owners newOwners() { return new OwnersTestable(getContext(), dataDir); } @Override - protected UserManager getUserManager() { + UserManager getUserManager() { return getContext().userManager; } @Override - protected PackageManager getPackageManager() { + PackageManager getPackageManager() { return getContext().packageManager; } @Override - protected PowerManagerInternal getPowerManagerInternal() { + PowerManagerInternal getPowerManagerInternal() { return getContext().powerManagerInternal; } @Override - protected NotificationManager getNotificationManager() { + NotificationManager getNotificationManager() { return getContext().notificationManager; } @Override - protected IWindowManager newIWindowManager() { + IWindowManager getIWindowManager() { return getContext().iwindowManager; } @Override - protected IActivityManager getIActivityManager() { + IActivityManager getIActivityManager() { return getContext().iactivityManager; } @Override - protected LockPatternUtils newLockPatternUtils(Context context) { + IPackageManager getIPackageManager() { + return getContext().ipackageManager; + } + + @Override + LockPatternUtils newLockPatternUtils(Context context) { return getContext().lockPatternUtils; } @Override - protected Looper getMyLooper() { + Looper getMyLooper() { return Looper.getMainLooper(); } @@ -181,12 +187,32 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi } @Override - WakeLock powerManagerNewWakeLock(int levelAndFlags, String tag) { - return getContext().powerManager.newWakeLock(levelAndFlags, tag); + void powerManagerGoToSleep(long time, int reason, int flags) { + getContext().powerManager.goToSleep(time, reason, flags); + } + + @Override + boolean systemPropertiesGetBoolean(String key, boolean def) { + return getContext().systemProperties.getBoolean(key, def); } @Override - void powerManagerGoToSleep(long time, int reason, int flags) { - getContext().powerManager.goToSleep(time, reason, flags); + long systemPropertiesGetLong(String key, long def) { + return getContext().systemProperties.getLong(key, def); + } + + @Override + String systemPropertiesGet(String key, String def) { + return getContext().systemProperties.get(key, def); + } + + @Override + String systemPropertiesGet(String key) { + return getContext().systemProperties.get(key); + } + + @Override + void systemPropertiesSet(String key, String value) { + getContext().systemProperties.set(key, value); } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 7cce56cea39e..0da459dab0d6 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -13,33 +13,39 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.android.server.devicepolicy; import com.android.server.LocalServices; +import android.Manifest.permission; +import android.app.Activity; import android.app.admin.DeviceAdminReceiver; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.os.UserHandle; +import android.os.Bundle; import org.mockito.ArgumentCaptor; import java.util.List; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isNull; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** - * Tests for {@link DevicePolicyManager} and {@link DevicePolicyManagerService}. + * Tests for DevicePolicyManager( and DevicePolicyManagerService). * m FrameworksServicesTests && adb install \ @@ -51,9 +57,13 @@ import static org.mockito.Mockito.when; */ public class DevicePolicyManagerTest extends DpmTestBase { + private DpmMockContext mContext; public DevicePolicyManager dpm; public DevicePolicyManagerServiceTestable dpms; + public ComponentName admin1; + public ComponentName admin2; + public ComponentName admin3; @Override protected void setUp() throws Exception { @@ -67,6 +77,59 @@ public class DevicePolicyManagerTest extends DpmTestBase { LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir); dpm = new DevicePolicyManagerTestable(mContext, dpms); + + admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class); + admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class); + admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class); + + setUpPackageManagerForAdmin(admin1); + setUpPackageManagerForAdmin(admin2); + setUpPackageManagerForAdmin(admin3); + + setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED); + } + + /** + * Set up a mock result for {@link PackageManager#queryBroadcastReceivers}. We'll return + * the actual ResolveInfo for the admin component, but we need to mock PM so it'll return + * it for user {@link DpmMockContext#CALLER_USER_HANDLE}. + */ + private void setUpPackageManagerForAdmin(ComponentName admin) { + final Intent resolveIntent = new Intent(); + resolveIntent.setComponent(admin); + final List realResolveInfo = + mRealTestContext.getPackageManager().queryBroadcastReceivers( + resolveIntent, + PackageManager.GET_META_DATA); + assertNotNull(realResolveInfo); + assertEquals(1, realResolveInfo.size()); + + // We need to rewrite the UID in the activity info. + realResolveInfo.get(0).activityInfo.applicationInfo.uid = DpmMockContext.CALLER_UID; + + doReturn(realResolveInfo).when(mContext.packageManager).queryBroadcastReceivers( + MockUtils.checkIntentComponent(admin), + eq(PackageManager.GET_META_DATA + | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), + eq(DpmMockContext.CALLER_USER_HANDLE) + ); + } + + /** + * Set up a mock result for {@link IPackageManager#getApplicationInfo} for user + * {@link DpmMockContext#CALLER_USER_HANDLE}. + */ + private void setUpApplicationInfo(int enabledSetting) throws Exception { + final ApplicationInfo ai = mRealTestContext.getPackageManager().getApplicationInfo( + admin1.getPackageName(), + PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); + + ai.enabledSetting = enabledSetting; + + doReturn(ai).when(mContext.ipackageManager).getApplicationInfo( + eq(admin1.getPackageName()), + eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), + eq(DpmMockContext.CALLER_USER_HANDLE)); } public void testHasNoFeature() { @@ -84,13 +147,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { * Caller doesn't have proper permissions. */ public void testSetActiveAdmin_SecurityException() { - final ComponentName admin = new ComponentName(mRealTestContext, DummyDeviceAdmin.class); - // 1. Failure cases. // Caller doesn't have MANAGE_DEVICE_ADMINS. try { - dpm.setActiveAdmin(admin, false); + dpm.setActiveAdmin(admin1, false); fail("Didn't throw SecurityException"); } catch (SecurityException expected) { } @@ -98,62 +159,246 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Caller has MANAGE_DEVICE_ADMINS, but for different user. mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); try { - dpm.setActiveAdmin(admin, false, DpmMockContext.CALLER_USER_HANDLE + 1); + dpm.setActiveAdmin(admin1, false, DpmMockContext.CALLER_USER_HANDLE + 1); fail("Didn't throw SecurityException"); } catch (SecurityException expected) { } } - public void testSetActiveAdmin() { - final ComponentName admin = new ComponentName(mRealTestContext, DummyDeviceAdmin.class); + /** + * Test for: + * {@link DevicePolicyManager#setActiveAdmin} + * with replace=false and replace=true + * {@link DevicePolicyManager#isAdminActive} + * {@link DevicePolicyManager#isAdminActiveAsUser} + * {@link DevicePolicyManager#getActiveAdmins} + * {@link DevicePolicyManager#getActiveAdminsAsUser} + */ + public void testSetActiveAdmin() throws Exception { + // 1. Make sure the caller has proper permissions. + mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); + + // 2. Call the API. + dpm.setActiveAdmin(admin1, /* replace =*/ false); + + // 3. Verify internal calls. + + // Check if the boradcast is sent. + verify(mContext.spiedContext).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); + verify(mContext.spiedContext).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); + + verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting( + eq(admin1.getPackageName()), + eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT), + eq(PackageManager.DONT_KILL_APP), + eq(DpmMockContext.CALLER_USER_HANDLE), + anyString()); + + // TODO Verify other calls too. + + // Make sure it's active admin1. + assertTrue(dpm.isAdminActive(admin1)); + assertFalse(dpm.isAdminActive(admin2)); + assertFalse(dpm.isAdminActive(admin3)); + + // But not admin1 for a different user. + + // For this to work, caller needs android.permission.INTERACT_ACROSS_USERS_FULL. + // (Because we're checking a different user's status from CALLER_USER_HANDLE.) + mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL"); + + assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE + 1)); + assertFalse(dpm.isAdminActiveAsUser(admin2, DpmMockContext.CALLER_USER_HANDLE + 1)); + + mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL"); + + // Next, add one more admin. + // Before doing so, update the application info, now it's enabled. + setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); + + dpm.setActiveAdmin(admin2, /* replace =*/ false); + + // Now we have two admins. + assertTrue(dpm.isAdminActive(admin1)); + assertTrue(dpm.isAdminActive(admin2)); + assertFalse(dpm.isAdminActive(admin3)); + + // Admin2 was already enabled, so setApplicationEnabledSetting() shouldn't have called + // again. (times(1) because it was previously called for admin1) + verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting( + eq(admin1.getPackageName()), + eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT), + eq(PackageManager.DONT_KILL_APP), + eq(DpmMockContext.CALLER_USER_HANDLE), + anyString()); + + // 4. Add the same admin1 again without replace, which should throw. + try { + dpm.setActiveAdmin(admin1, /* replace =*/ false); + fail("Didn't throw"); + } catch (IllegalArgumentException expected) { + } + + // 5. Add the same admin1 again with replace, which should succeed. + dpm.setActiveAdmin(admin1, /* replace =*/ true); + + // TODO make sure it's replaced. + + // 6. Test getActiveAdmins() + List admins = dpm.getActiveAdmins(); + assertEquals(2, admins.size()); + assertEquals(admin1, admins.get(0)); + assertEquals(admin2, admins.get(1)); + + // Another user has no admins. + mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL"); + + assertEquals(0, DpmTestUtils.getListSizeAllowingNull( + dpm.getActiveAdminsAsUser(DpmMockContext.CALLER_USER_HANDLE + 1))); + + mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL"); + } + + /** + * Test for: + * {@link DevicePolicyManager#setActiveAdmin} + * with replace=false + */ + public void testSetActiveAdmin_twiceWithoutReplace() throws Exception { + // 1. Make sure the caller has proper permissions. + mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); + + dpm.setActiveAdmin(admin1, /* replace =*/ false); + assertTrue(dpm.isAdminActive(admin1)); + + // Add the same admin1 again without replace, which should throw. + try { + dpm.setActiveAdmin(admin1, /* replace =*/ false); + fail("Didn't throw"); + } catch (IllegalArgumentException expected) { + } + } + + /** + * Test for: + * {@link DevicePolicyManager#removeActiveAdmin} + */ + public void testRemoveActiveAdmin_SecurityException() { + mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); + + // Add admin. + + dpm.setActiveAdmin(admin1, /* replace =*/ false); + + assertTrue(dpm.isAdminActive(admin1)); - // 1. Prepare mock package manager (and other mocks) + assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); + // Directly call the DPMS method with a different userid, which should fail. + try { + dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE + 1); + fail("Didn't throw SecurityException"); + } catch (SecurityException expected) { + } + + // Try to remove active admin with a different caller userid should fail too, without + // having MANAGE_DEVICE_ADMINS. + mContext.callerPermissions.clear(); + + mContext.binder.callingUid = 1234567; + try { + dpm.removeActiveAdmin(admin1); + fail("Didn't throw SecurityException"); + } catch (SecurityException expected) { + } + } + + /** + * Test for: + * {@link DevicePolicyManager#removeActiveAdmin} + */ + public void testRemoveActiveAdmin_fromDifferentUserWithMINTERACT_ACROSS_USERS_FULL() { mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); - // Create ResolveInfo for the admin. - final Intent resolveIntent = new Intent(); - resolveIntent.setComponent(admin); - final List realResolveInfo = - mRealTestContext.getPackageManager().queryBroadcastReceivers( - resolveIntent, - PackageManager.GET_META_DATA - | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); - assertNotNull(realResolveInfo); - assertEquals(1, realResolveInfo.size()); + // Add admin1. - // We need to rewrite the UID in the activity info. - realResolveInfo.get(0).activityInfo.applicationInfo.uid = DpmMockContext.CALLER_UID; + dpm.setActiveAdmin(admin1, /* replace =*/ false); - doReturn(realResolveInfo).when(mContext.packageManager).queryBroadcastReceivers( - any(Intent.class), // TODO check the intent too. - eq(PackageManager.GET_META_DATA - | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), - eq(DpmMockContext.CALLER_USER_HANDLE) - ); + assertTrue(dpm.isAdminActive(admin1)); + assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); - // 2. Everything is ready; call the method. - dpm.setActiveAdmin(admin, false); + // Different user, but should work, because caller has proper permissions. + mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); + mContext.binder.callingUid = 1234567; + dpm.removeActiveAdmin(admin1); - // 3. Verify internal calls. + assertTrue(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); - // Check if the boradcast is sent. - final ArgumentCaptor intentCap = ArgumentCaptor.forClass(Intent.class); - final ArgumentCaptor uhCap = ArgumentCaptor.forClass(UserHandle.class); + // TODO DO Still can't be removed in this case. + } - verify(mContext.spiedContext, times(2)).sendBroadcastAsUser( - intentCap.capture(), + /** + * Test for: + * {@link DevicePolicyManager#removeActiveAdmin} + */ + public void testRemoveActiveAdmin_sameUserNoMANAGE_DEVICE_ADMINS() { + // Need MANAGE_DEVICE_ADMINS for setActiveAdmin. We'll remove it later. + mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); + + // Add admin1. + + dpm.setActiveAdmin(admin1, /* replace =*/ false); + + assertTrue(dpm.isAdminActive(admin1)); + assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); + + // Broadcast from saveSettingsLocked(). + verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); - // First call from saveSettingsLocked(). - assertEquals(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED, - intentCap.getAllValues().get(0).getAction()); + // Remove. No permissions, but same user, so it'll work. + mContext.callerPermissions.clear(); + dpm.removeActiveAdmin(admin1); - // Second call from setActiveAdmin/sendAdminCommandLocked() - assertEquals(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED, - intentCap.getAllValues().get(1).getAction()); + final ArgumentCaptor brCap = + ArgumentCaptor.forClass(BroadcastReceiver.class); - // TODO Verify other calls too. + // Is removing now, but not removed yet. + assertTrue(dpm.isAdminActive(admin1)); + assertTrue(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); + + verify(mContext.spiedContext).sendOrderedBroadcastAsUser( + MockUtils.checkIntentAction( + DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE), + isNull(String.class), + brCap.capture(), + eq(dpms.mHandler), + eq(Activity.RESULT_OK), + isNull(String.class), + isNull(Bundle.class)); + + brCap.getValue().onReceive(mContext, null); + + assertFalse(dpm.isAdminActive(admin1)); + assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); + + // Again broadcast from saveSettingsLocked(). + verify(mContext.spiedContext, times(2)).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); + + // TODO Check other internal calls. } } + diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index 864431157660..6bb9833a883c 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -16,6 +16,7 @@ package com.android.server.devicepolicy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.widget.LockPatternUtils; import android.app.IActivityManager; @@ -24,11 +25,13 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; import android.os.PowerManager.WakeLock; import android.os.PowerManagerInternal; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.test.mock.MockContext; @@ -71,27 +74,27 @@ public class DpmMockContext extends MockContext { public static final int SYSTEM_PID = 11111; public static class MockBinder { - int mCallingUid = CALLER_UID; - int mCallingPid = CALLER_PID; + public int callingUid = CALLER_UID; + public int callingPid = CALLER_PID; public long clearCallingIdentity() { - final long token = (((long) mCallingUid) << 32) | (mCallingPid); - mCallingUid = SYSTEM_UID; - mCallingPid = SYSTEM_PID; + final long token = (((long) callingUid) << 32) | (callingPid); + callingUid = SYSTEM_UID; + callingPid = SYSTEM_PID; return token; } public void restoreCallingIdentity(long token) { - mCallingUid = (int) (token >> 32); - mCallingPid = (int) token; + callingUid = (int) (token >> 32); + callingPid = (int) token; } public int getCallingUid() { - return mCallingUid; + return callingUid; } public int getCallingPid() { - return mCallingPid; + return callingPid; } public UserHandle getCallingUserHandle() { @@ -99,7 +102,7 @@ public class DpmMockContext extends MockContext { } public boolean isCallerUidMyUid() { - return mCallingUid == SYSTEM_UID; + return callingUid == SYSTEM_UID; } } @@ -118,6 +121,27 @@ public class DpmMockContext extends MockContext { } } + public static class SystemPropertiesForMock { + public boolean getBoolean(String key, boolean def) { + return false; + } + + public long getLong(String key, long def) { + return 0; + } + + public String get(String key, String def) { + return null; + } + + public String get(String key) { + return null; + } + + public void set(String key, String value) { + } + } + public final Context realTestContext; /** @@ -129,12 +153,14 @@ public class DpmMockContext extends MockContext { public final MockBinder binder; public final EnvironmentForMock environment; + public final SystemPropertiesForMock systemProperties; public final UserManager userManager; public final PowerManagerForMock powerManager; public final PowerManagerInternal powerManagerInternal; public final NotificationManager notificationManager; public final IWindowManager iwindowManager; public final IActivityManager iactivityManager; + public final IPackageManager ipackageManager; public final LockPatternUtils lockPatternUtils; /** Note this is a partial mock, not a real mock. */ @@ -146,12 +172,14 @@ public class DpmMockContext extends MockContext { realTestContext = context; binder = new MockBinder(); environment = mock(EnvironmentForMock.class); + systemProperties= mock(SystemPropertiesForMock.class); userManager = mock(UserManager.class); powerManager = mock(PowerManagerForMock.class); powerManagerInternal = mock(PowerManagerInternal.class); notificationManager = mock(NotificationManager.class); iwindowManager = mock(IWindowManager.class); iactivityManager = mock(IActivityManager.class); + ipackageManager = mock(IPackageManager.class); lockPatternUtils = mock(LockPatternUtils.class); // Package manager is huge, so we use a partial mock instead. diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java index a8e2c3ce4831..44a851abe476 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java @@ -23,6 +23,7 @@ import android.util.Printer; import org.junit.Assert; import java.io.File; +import java.util.List; public class DpmTestUtils { private DpmTestUtils() { @@ -33,6 +34,11 @@ public class DpmTestUtils { Assert.assertTrue("failed to delete dir", FileUtils.deleteContents(dir)); } dir.mkdirs(); + Log.i(DpmTestBase.TAG, "Created " + dir); + } + + public static int getListSizeAllowingNull(List list) { + return list == null ? 0 : list.size(); } public static Printer LOG_PRINTER = new Printer() { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java similarity index 75% rename from services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java rename to services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java index c47d19447395..5cd15557a80d 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java @@ -17,5 +17,11 @@ package com.android.server.devicepolicy; import android.app.admin.DeviceAdminReceiver; -public class DummyDeviceAdmin extends DeviceAdminReceiver { -} +public class DummyDeviceAdmins { + public static class Admin1 extends DeviceAdminReceiver { + } + public static class Admin2 extends DeviceAdminReceiver { + } + public static class Admin3 extends DeviceAdminReceiver { + } +} \ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java index f2a2bf7e5e13..5008fbfa3b10 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java @@ -17,6 +17,8 @@ package com.android.server.devicepolicy; import com.google.common.base.Objects; +import android.content.ComponentName; +import android.content.Intent; import android.os.UserHandle; import org.hamcrest.BaseMatcher; @@ -44,4 +46,35 @@ public class MockUtils { return Mockito.argThat(m); } + public static Intent checkIntentComponent(final ComponentName component) { + final Matcher m = new BaseMatcher() { + @Override + public boolean matches(Object item) { + if (item == null) return false; + return Objects.equal(((Intent) item).getComponent(), component); + } + + @Override + public void describeTo(Description description) { + description.appendText("Intent: component=\"" + component + "\""); + } + }; + return Mockito.argThat(m); + } + + public static Intent checkIntentAction(final String action) { + final Matcher m = new BaseMatcher() { + @Override + public boolean matches(Object item) { + if (item == null) return false; + return Objects.equal(((Intent) item).getAction(), action); + } + + @Override + public void describeTo(Description description) { + description.appendText("Intent: action=\"" + action + "\""); + } + }; + return Mockito.argThat(m); + } } -- 2.11.0