From 66eb5218335886fed1978891bd0f2d04d2109563 Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Thu, 4 Sep 2014 12:56:39 -0700 Subject: [PATCH] Eliminate deadlock by deferring wipe data call The call to RecoverySystem.rebootWipeUserData() was made while holding the lock to DevicePolicyManagerService. But it blocks waiting for system_process' main thread to receive the ordered broadcast complete callback. It won't receive that callback because Keyguard is running on the main thread and is concurrently blocked on DevicePolicyManagerService. By moving the call to rebootWipeUserData() out of the synchronized block the deadlock is eliminated. Fixes bug 16870054. Change-Id: I3eb587211e5484859cc9dab7e80e5a1f6c85225d --- .../DevicePolicyManagerService.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 564a3df26e222..72e69e91f64e2 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -2998,10 +2998,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); - synchronized (this) { - DevicePolicyData policy = getUserData(userHandle); - long ident = Binder.clearCallingIdentity(); - try { + long ident = Binder.clearCallingIdentity(); + try { + boolean wipeData = false; + int identifier = 0; + synchronized (this) { + DevicePolicyData policy = getUserData(userHandle); policy.mFailedPasswordAttempts++; saveSettingsLocked(userHandle); if (mHasFeature) { @@ -3013,15 +3015,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Wipe the user/profile associated with the policy that was violated. This // is not necessarily calling user: if the policy that fired was from a // managed profile rather than the main user profile, we wipe former only. - wipeDeviceOrUserLocked(0, strictestAdmin.getUserHandle().getIdentifier()); + wipeData = true; + identifier = strictestAdmin.getUserHandle().getIdentifier(); } sendAdminCommandToSelfAndProfilesLocked( DeviceAdminReceiver.ACTION_PASSWORD_FAILED, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle); } - } finally { - Binder.restoreCallingIdentity(ident); } + if (wipeData) { + // Call without holding lock. + wipeDeviceOrUserLocked(0, identifier); + } + } finally { + Binder.restoreCallingIdentity(ident); } }