Update DPM.reboot with new restriction
DPM.reboot() should not be called when there is an ongoing call on the
device.
Bug:27531799
Change-Id: Idc1fa4c7aa79b20ec9c2afcccf855455ee316787
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ec1e3e6..c0d4a3e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -51,6 +51,7 @@
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 @@
}
/**
- * 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 b48c185..6582b29 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.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 @@
final IPackageManager mIPackageManager;
final UserManager mUserManager;
final UserManagerInternal mUserManagerInternal;
+ final TelephonyManager mTelephonyManager;
private final LockPatternUtils mLockPatternUtils;
/**
@@ -1354,6 +1356,10 @@
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 @@
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();
@@ -8309,6 +8316,10 @@
}
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 aaec1e9..35777ce 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.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 @@
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 e897e3d..6c2bdda 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.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 @@
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 @@
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 b05309a..8e2ef70 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.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 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 @@
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());