diff options
author | Jeff Brown <jeffbrown@google.com> | 2012-10-18 16:13:44 -0700 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2012-10-18 17:37:39 -0700 |
commit | 66692500344cab2f53cdb6ee1545c567fff7cb16 (patch) | |
tree | c58290fc3cee7aebced1d2d1756f792dde0b0a6e /services | |
parent | 88c66cbb00a572ac8280f0e0ea38079d48ec59f3 (diff) | |
download | frameworks_base-66692500344cab2f53cdb6ee1545c567fff7cb16.zip frameworks_base-66692500344cab2f53cdb6ee1545c567fff7cb16.tar.gz frameworks_base-66692500344cab2f53cdb6ee1545c567fff7cb16.tar.bz2 |
Fix deadlock.
The display manager must never call into the activity manager with
its lock held. Make it clear that the adapters are constructed
while holding the syncroot lock.
Bug: 7377631
Change-Id: I1557313cbb31dcad9b5a46919a88a5a1c1af3e9b
Diffstat (limited to 'services')
5 files changed, 32 insertions, 20 deletions
diff --git a/services/java/com/android/server/display/DisplayAdapter.java b/services/java/com/android/server/display/DisplayAdapter.java index abc1d32..b411a0d 100644 --- a/services/java/com/android/server/display/DisplayAdapter.java +++ b/services/java/com/android/server/display/DisplayAdapter.java @@ -42,6 +42,7 @@ abstract class DisplayAdapter { public static final int DISPLAY_DEVICE_EVENT_CHANGED = 2; public static final int DISPLAY_DEVICE_EVENT_REMOVED = 3; + // Called with SyncRoot lock held. public DisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, String name) { mSyncRoot = syncRoot; diff --git a/services/java/com/android/server/display/HeadlessDisplayAdapter.java b/services/java/com/android/server/display/HeadlessDisplayAdapter.java index 7ec537f..919733d 100644 --- a/services/java/com/android/server/display/HeadlessDisplayAdapter.java +++ b/services/java/com/android/server/display/HeadlessDisplayAdapter.java @@ -29,6 +29,7 @@ import android.util.DisplayMetrics; final class HeadlessDisplayAdapter extends DisplayAdapter { private static final String TAG = "HeadlessDisplayAdapter"; + // Called with SyncRoot lock held. public HeadlessDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener) { super(syncRoot, context, handler, listener, TAG); diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/java/com/android/server/display/LocalDisplayAdapter.java index fe38d7f..d6c5248 100644 --- a/services/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/java/com/android/server/display/LocalDisplayAdapter.java @@ -44,21 +44,21 @@ final class LocalDisplayAdapter extends DisplayAdapter { private final SparseArray<LocalDisplayDevice> mDevices = new SparseArray<LocalDisplayDevice>(); - private final HotplugDisplayEventReceiver mHotplugReceiver; + private HotplugDisplayEventReceiver mHotplugReceiver; private final PhysicalDisplayInfo mTempPhys = new PhysicalDisplayInfo(); + // Called with SyncRoot lock held. public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener) { super(syncRoot, context, handler, listener, TAG); - mHotplugReceiver = new HotplugDisplayEventReceiver(handler.getLooper()); } @Override public void registerLocked() { - // TODO: listen for notifications from Surface Flinger about - // built-in displays being added or removed and rescan as needed. super.registerLocked(); + + mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper()); scanDisplaysLocked(); } diff --git a/services/java/com/android/server/display/OverlayDisplayAdapter.java b/services/java/com/android/server/display/OverlayDisplayAdapter.java index dfacf2a..937ebcf 100644 --- a/services/java/com/android/server/display/OverlayDisplayAdapter.java +++ b/services/java/com/android/server/display/OverlayDisplayAdapter.java @@ -64,6 +64,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter { new ArrayList<OverlayDisplayHandle>(); private String mCurrentOverlaySetting = ""; + // Called with SyncRoot lock held. public OverlayDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, Handler uiHandler) { super(syncRoot, context, handler, listener, TAG); diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java index 66eac88..f9d58af 100644 --- a/services/java/com/android/server/display/WifiDisplayAdapter.java +++ b/services/java/com/android/server/display/WifiDisplayAdapter.java @@ -73,8 +73,8 @@ final class WifiDisplayAdapter extends DisplayAdapter { private final boolean mSupportsProtectedBuffers; private final NotificationManager mNotificationManager; - private final PendingIntent mSettingsPendingIntent; - private final PendingIntent mDisconnectPendingIntent; + private PendingIntent mSettingsPendingIntent; + private PendingIntent mDisconnectPendingIntent; private WifiDisplayController mDisplayController; private WifiDisplayDevice mDisplayDevice; @@ -90,6 +90,7 @@ final class WifiDisplayAdapter extends DisplayAdapter { private boolean mPendingStatusChangeBroadcast; private boolean mPendingNotificationUpdate; + // Called with SyncRoot lock held. public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, PersistentDataStore persistentDataStore) { @@ -100,20 +101,6 @@ final class WifiDisplayAdapter extends DisplayAdapter { com.android.internal.R.bool.config_wifiDisplaySupportsProtectedBuffers); mNotificationManager = (NotificationManager)context.getSystemService( Context.NOTIFICATION_SERVICE); - - Intent settingsIntent = new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS); - settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED - | Intent.FLAG_ACTIVITY_CLEAR_TOP); - mSettingsPendingIntent = PendingIntent.getActivityAsUser( - context, 0, settingsIntent, 0, null, UserHandle.CURRENT); - - Intent disconnectIntent = new Intent(ACTION_DISCONNECT); - mDisconnectPendingIntent = PendingIntent.getBroadcastAsUser( - context, 0, disconnectIntent, 0, UserHandle.CURRENT); - - context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, - new IntentFilter(ACTION_DISCONNECT), null, mHandler); } @Override @@ -153,6 +140,9 @@ final class WifiDisplayAdapter extends DisplayAdapter { public void run() { mDisplayController = new WifiDisplayController( getContext(), getHandler(), mWifiDisplayListener); + + getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, + new IntentFilter(ACTION_DISCONNECT), null, mHandler); } }); } @@ -366,12 +356,31 @@ final class WifiDisplayAdapter extends DisplayAdapter { isConnected = (mDisplayDevice != null); } + // Cancel the old notification if there is one. mNotificationManager.cancelAsUser(null, R.string.wifi_display_notification_title, UserHandle.ALL); if (isConnected) { Context context = getContext(); + // Initialize pending intents for the notification outside of the lock because + // creating a pending intent requires a call into the activity manager. + if (mSettingsPendingIntent == null) { + Intent settingsIntent = new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS); + settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED + | Intent.FLAG_ACTIVITY_CLEAR_TOP); + mSettingsPendingIntent = PendingIntent.getActivityAsUser( + context, 0, settingsIntent, 0, null, UserHandle.CURRENT); + } + + if (mDisconnectPendingIntent == null) { + Intent disconnectIntent = new Intent(ACTION_DISCONNECT); + mDisconnectPendingIntent = PendingIntent.getBroadcastAsUser( + context, 0, disconnectIntent, 0, UserHandle.CURRENT); + } + + // Post the notification. Resources r = context.getResources(); Notification notification = new Notification.Builder(context) .setContentTitle(r.getString( |