diff options
5 files changed, 109 insertions, 12 deletions
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 1dd34e63d244..851cf50a7585 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -6467,7 +6467,10 @@ public class DevicePolicyManager { /** * @hide - * Force update user setup completed status + * Force update user setup completed status. This API has no effect on user build. + * @throws {@link SecurityException} if the caller has no + * {@link android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS} or the caller is + * not {@link UserHandle.SYSTEM_USER} */ public void forceUpdateUserSetupComplete() { try { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index de41dc7962c9..9c4b94eab310 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -1393,6 +1393,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return IAudioService.Stub.asInterface(ServiceManager.getService(Context.AUDIO_SERVICE)); } + boolean isBuildDebuggable() { + return Build.IS_DEBUGGABLE; + } + LockPatternUtils newLockPatternUtils() { return new LockPatternUtils(mContext); } @@ -8999,6 +9003,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null); } + private void enforceCallerSystemUserHandle() { + final int callingUid = mInjector.binderGetCallingUid(); + final int userId = UserHandle.getUserId(callingUid); + if (userId != UserHandle.USER_SYSTEM) { + throw new SecurityException("Caller has to be in user 0"); + } + } + @Override public boolean isUninstallInQueue(final String packageName) { enforceCanManageDeviceAdmin(); @@ -9163,17 +9175,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void forceUpdateUserSetupComplete() { enforceCanManageProfileAndDeviceOwners(); - List<UserInfo> users = mUserManager.getUsers(true); - final int N = users.size(); - for (int i = 0; i < N; i++) { - int userHandle = users.get(i).id; - boolean isUserCompleted = mInjector.settingsSecureGetIntForUser( - Settings.Secure.USER_SETUP_COMPLETE, 0, userHandle) != 0; - DevicePolicyData policy = getUserData(userHandle); - policy.mUserSetupComplete = isUserCompleted; - synchronized (this) { - saveSettingsLocked(userHandle); - } + enforceCallerSystemUserHandle(); + // no effect if it's called from user build + if (!mInjector.isBuildDebuggable()) { + return; + } + final int userId = UserHandle.USER_SYSTEM; + boolean isUserCompleted = mInjector.settingsSecureGetIntForUser( + Settings.Secure.USER_SETUP_COMPLETE, 0, userId) != 0; + DevicePolicyData policy = getUserData(userId); + policy.mUserSetupComplete = isUserCompleted; + synchronized (this) { + saveSettingsLocked(userId); } } 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 6cb4a8238727..80be62b3f2a2 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -357,5 +357,10 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi TelephonyManager getTelephonyManager() { return context.telephonyManager; } + + @Override + boolean isBuildDebuggable() { + return context.buildMock.isDebuggable; + } } } 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 2d96bff29bd7..0fd128641180 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -2117,6 +2117,76 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); } + public void testForceUpdateUserSetupComplete_permission() { + // GIVEN the permission MANAGE_PROFILE_AND_DEVICE_OWNERS is not granted + try { + dpm.forceUpdateUserSetupComplete(); + fail("Didn't throw SecurityException"); + } catch (SecurityException expected) { + } + } + + public void testForceUpdateUserSetupComplete_systemUser() { + mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); + // GIVEN calling from user 20 + mContext.binder.callingUid = DpmMockContext.CALLER_UID; + try { + dpm.forceUpdateUserSetupComplete(); + fail("Didn't throw SecurityException"); + } catch (SecurityException expected) { + } + } + + public void testForceUpdateUserSetupComplete_userbuild() { + mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); + mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; + + final int userId = UserHandle.USER_SYSTEM; + // GIVEN userComplete is false in SettingsProvider + setUserSetupCompleteForUser(false, userId); + + // GIVEN userComplete is true in DPM + DevicePolicyManagerService.DevicePolicyData userData = + new DevicePolicyManagerService.DevicePolicyData(userId); + userData.mUserSetupComplete = true; + dpms.mUserData.put(UserHandle.USER_SYSTEM, userData); + + // GIVEN it's user build + mContext.buildMock.isDebuggable = false; + + assertTrue(dpms.hasUserSetupCompleted()); + + dpm.forceUpdateUserSetupComplete(); + + // THEN the state in dpms is not changed + assertTrue(dpms.hasUserSetupCompleted()); + } + + public void testForceUpdateUserSetupComplete_userDebugbuild() { + mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); + mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; + + final int userId = UserHandle.USER_SYSTEM; + // GIVEN userComplete is false in SettingsProvider + setUserSetupCompleteForUser(false, userId); + + // GIVEN userComplete is true in DPM + DevicePolicyManagerService.DevicePolicyData userData = + new DevicePolicyManagerService.DevicePolicyData(userId); + userData.mUserSetupComplete = true; + dpms.mUserData.put(UserHandle.USER_SYSTEM, userData); + + // GIVEN it's userdebug build + mContext.buildMock.isDebuggable = true; + + assertTrue(dpms.hasUserSetupCompleted()); + + dpm.forceUpdateUserSetupComplete(); + + // THEN the state in dpms is not changed + assertFalse(dpms.hasUserSetupCompleted()); + } + private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) { when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0, userhandle)).thenReturn(isUserSetupComplete ? 1 : 0); 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 0783afc0dfd4..37430ad5dfac 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -132,6 +132,10 @@ public class DpmMockContext extends MockContext { } } + public static class BuildMock { + public boolean isDebuggable = true; + } + public static class PowerManagerForMock { public WakeLock newWakeLock(int levelAndFlags, String tag) { return null; @@ -272,6 +276,8 @@ public class DpmMockContext extends MockContext { private final ArrayList<UserInfo> mUserInfos = new ArrayList<>(); + public final BuildMock buildMock = new BuildMock(); + public DpmMockContext(Context context, File dataDir) { realTestContext = context; |