Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 66692500 authored by Jeff Brown's avatar Jeff Brown
Browse files

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
parent 88c66cbb
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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);
+4 −4
Original line number Diff line number Diff line
@@ -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();
    }

+1 −0
Original line number Diff line number Diff line
@@ -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);
+25 −16
Original line number Diff line number Diff line
@@ -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(