diff options
5 files changed, 50 insertions, 2 deletions
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index ec1e3e67fbe3..c0d4a3e835cf 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -51,6 +51,7 @@ import android.provider.ContactsContract.Directory; import android.provider.Settings; import android.security.Credentials; import android.service.restrictions.RestrictionsReceiver; +import android.telephony.TelephonyManager; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -5566,7 +5567,10 @@ public class DevicePolicyManager { } /** - * Called by device owner to reboot the device. + * Called by device owner to reboot the device. If there is an ongoing call on the device, + * throws an {@link IllegalStateException}. + * @throws IllegalStateException if device has an ongoing call. + * @see TelephonyManager#CALL_STATE_IDLE */ public void reboot(@NonNull ComponentName admin) { try { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 2e8b02652faa..16e73fc12278 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -115,6 +115,7 @@ import android.security.IKeyChainService; import android.security.KeyChain; import android.security.KeyChain.KeyChainConnection; import android.service.persistentdata.PersistentDataBlockManager; +import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -306,6 +307,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final IPackageManager mIPackageManager; final UserManager mUserManager; final UserManagerInternal mUserManagerInternal; + final TelephonyManager mTelephonyManager; private final LockPatternUtils mLockPatternUtils; /** @@ -1354,6 +1356,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return LocalServices.getService(PowerManagerInternal.class); } + TelephonyManager getTelephonyManager() { + return TelephonyManager.from(mContext); + } + IWindowManager getIWindowManager() { return IWindowManager.Stub .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE)); @@ -1542,6 +1548,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mUserManager = Preconditions.checkNotNull(injector.getUserManager()); mUserManagerInternal = Preconditions.checkNotNull(injector.getUserManagerInternal()); mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager()); + mTelephonyManager = Preconditions.checkNotNull(injector.getTelephonyManager()); mLocalService = new LocalService(); mLockPatternUtils = injector.newLockPatternUtils(); @@ -8334,6 +8341,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } long ident = mInjector.binderClearCallingIdentity(); try { + // Make sure there are no ongoing calls on the device. + if (mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) { + throw new IllegalStateException("Cannot be called with ongoing call on the device"); + } mInjector.powerManagerReboot(PowerManager.REBOOT_REQUESTED_BY_DEVICE_OWNER); } finally { mInjector.binderRestoreCallingIdentity(ident); 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 aaec1e9241cf..35777ce86c4a 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -29,6 +29,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; import android.os.storage.StorageManager; +import android.telephony.TelephonyManager; import android.view.IWindowManager; import java.io.File; @@ -322,5 +323,10 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi boolean securityLogIsLoggingEnabled() { return context.settings.securityLogIsLoggingEnabled(); } + + @Override + TelephonyManager getTelephonyManager() { + return context.telephonyManager; + } } } 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 e897e3d20edf..6c2bdda3e21a 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -33,6 +33,7 @@ import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.telephony.TelephonyManager; import android.test.MoreAsserts; import android.test.suitebuilder.annotation.SmallTest; import android.util.ArraySet; @@ -1491,7 +1492,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress(admin1)); } - public void testRebootCanOnlyBeCalledByDeviceOwner() throws Exception { + public void testReboot() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); @@ -1524,6 +1525,29 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.clearProfileOwner(admin1); assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM)); + // admin1 is DO. + // Set current call state of device to ringing. + when(mContext.telephonyManager.getCallState()) + .thenReturn(TelephonyManager.CALL_STATE_RINGING); + try { + dpm.reboot(admin1); + fail("DPM.reboot() called when receiveing a call, should thrown IllegalStateException"); + } catch (IllegalStateException expected) { + MoreAsserts.assertContainsRegex("ongoing call on the device", expected.getMessage()); + } + + // Set current call state of device to dialing/active. + when(mContext.telephonyManager.getCallState()) + .thenReturn(TelephonyManager.CALL_STATE_OFFHOOK); + try { + dpm.reboot(admin1); + fail("DPM.reboot() called when dialing, should thrown IllegalStateException"); + } catch (IllegalStateException expected) { + MoreAsserts.assertContainsRegex("ongoing call on the device", expected.getMessage()); + } + + // Set current call state of device to idle. + when(mContext.telephonyManager.getCallState()).thenReturn(TelephonyManager.CALL_STATE_IDLE); dpm.reboot(admin1); } 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 b05309af49ab..8e2ef703f3c6 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -40,6 +40,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; import android.os.storage.StorageManager; +import android.telephony.TelephonyManager; import android.test.mock.MockContentResolver; import android.test.mock.MockContext; import android.view.IWindowManager; @@ -262,6 +263,7 @@ public class DpmMockContext extends MockContext { public final WifiManager wifiManager; public final SettingsForMock settings; public final MockContentResolver contentResolver; + public final TelephonyManager telephonyManager; /** Note this is a partial mock, not a real mock. */ public final PackageManager packageManager; @@ -295,6 +297,7 @@ public class DpmMockContext extends MockContext { storageManager = mock(StorageManagerForMock.class); wifiManager = mock(WifiManager.class); settings = mock(SettingsForMock.class); + telephonyManager = mock(TelephonyManager.class); // Package manager is huge, so we use a partial mock instead. packageManager = spy(context.getPackageManager()); |