From 8a9e7a1f9490dc0c103c82fac74087459ddf4c16 Mon Sep 17 00:00:00 2001 From: Obi Okafor Date: Thu, 11 Mar 2010 01:00:02 +0100 Subject: Fix for deadlock between StatusBarService and NotificationManagerService A ServerThread holding a lock on mQueue in StatusBarService invoked a callback in NotificationManagerService which required a lock on mNotificationList. At the same time, a BinderThread holding a lock on mNotificationList was attempting to post a message to StatusBarService which requires lock on mQueue. The fix is to release the lock on mQueue in handleMessage() before running the actions at the end of the method. --- .../android/server/status/StatusBarService.java | 33 +++++++++++++--------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java index 34921d66cdc8..9ccd38b6fc95 100644 --- a/services/java/com/android/server/status/StatusBarService.java +++ b/services/java/com/android/server/status/StatusBarService.java @@ -552,15 +552,17 @@ public class StatusBarService extends IStatusBar.Stub doRevealAnimation(); return; } + boolean expand = false; + boolean doExpand = false; + boolean doDisable = false; + int disableWhat = 0; + synchronized (mQueue) { boolean wasExpanded = mExpanded; // for each one in the queue, find all of the ones with the same key // and collapse that down into a final op and/or call to setVisibility, etc - boolean expand = wasExpanded; - boolean doExpand = false; - boolean doDisable = false; - int disableWhat = 0; + expand = wasExpanded; int N = mQueue.size(); while (N > 0) { PendingOp op = mQueue.get(0); @@ -634,18 +636,21 @@ public class StatusBarService extends IStatusBar.Stub if (mQueue.size() != 0) { throw new RuntimeException("Assertion failed: mQueue.size=" + mQueue.size()); } - if (doExpand) { - // this is last so that we capture all of the pending changes before doing it - if (expand) { - animateExpand(); - } else { - animateCollapse(); - } - } - if (doDisable) { - performDisableActions(disableWhat); + } + // This must be done outside the synchronized block above to prevent a deadlock where + // we call into the NotificationManagerService and it is in turn attempting to post a + // message to our queue. + if (doExpand) { + // this is last so that we capture all of the pending changes before doing it + if (expand) { + animateExpand(); + } else { + animateCollapse(); } } + if (doDisable) { + performDisableActions(disableWhat); + } } } -- cgit v1.2.3-59-g8ed1b