From 7f1e3f3e93a9a42e221cffb09c5950135069bde2 Mon Sep 17 00:00:00 2001 From: riddle_hsu Date: Tue, 8 Jul 2014 04:30:19 +0800 Subject: [ActivityManager] Prevent potential deadlock from system error dialog and InputMethodManager. Sympton: When application crash in a special timing and system server's InputMethodManager is binding, deadlock may occur. Root Cause: Thread(1): When using InputMethodManager in system server, it will lock mH(handler) of InputMethodManager, and sometimes it will call to InputMethodManagerService::showCurrentInputLocked and will call bindService at some condition, then it will also lock ActivityManagerService. Thread(2): When an application crashed, it will lock ActivityManager when showing crash dialog, inside the dialog, it will call setEnabled of Button and lock mH of InputMethodManager.setEnable of TextView will lock IMM's handler. So the deadlock happened as the flow: (2) lock AMS -> (1)lock mH -> (2)wait mH -> (1) wait AMS Solution: Reduce nested lock of error dialog: post message to let (2) lock mH after release AMS lock. Change-Id: Id85c29406236db3b5fca9655fde1fcaf0afd1337 --- services/java/com/android/server/am/BaseErrorDialog.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) mode change 100644 => 100755 services/java/com/android/server/am/BaseErrorDialog.java diff --git a/services/java/com/android/server/am/BaseErrorDialog.java b/services/java/com/android/server/am/BaseErrorDialog.java old mode 100644 new mode 100755 index 6ede8f8..35bdee0 --- a/services/java/com/android/server/am/BaseErrorDialog.java +++ b/services/java/com/android/server/am/BaseErrorDialog.java @@ -27,6 +27,11 @@ import android.view.WindowManager; import android.widget.Button; class BaseErrorDialog extends AlertDialog { + private static final int ENABLE_BUTTONS = 0; + private static final int DISABLE_BUTTONS = 1; + + private boolean mConsuming = true; + public BaseErrorDialog(Context context) { super(context, com.android.internal.R.style.Theme_Dialog_AppError); @@ -41,8 +46,8 @@ class BaseErrorDialog extends AlertDialog { public void onStart() { super.onStart(); - setEnabled(false); - mHandler.sendMessageDelayed(mHandler.obtainMessage(0), 1000); + mHandler.sendEmptyMessage(DISABLE_BUTTONS); + mHandler.sendMessageDelayed(mHandler.obtainMessage(ENABLE_BUTTONS), 1000); } public boolean dispatchKeyEvent(KeyEvent event) { @@ -71,12 +76,12 @@ class BaseErrorDialog extends AlertDialog { private Handler mHandler = new Handler() { public void handleMessage(Message msg) { - if (msg.what == 0) { + if (msg.what == ENABLE_BUTTONS) { mConsuming = false; setEnabled(true); + } else if (msg.what == DISABLE_BUTTONS) { + setEnabled(false); } } }; - - private boolean mConsuming = true; } -- cgit v1.1