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

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

Move setting the display state out of the critical section.

Setting the display power state currently happens while holding the
display manager lock.  This change moves it out of the lock to
ensure other services don't get stuck for several hundred
milliseconds.

Unfortunately, surface flinger ends up stalled a little later
so this only solves part of the problem.

Bug: 17623774
Change-Id: I201137c5e7f82c776f28a436845fcf3191fd0ca5
parent f7efd5c6
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -108,8 +108,12 @@ abstract class DisplayDevice {

    /**
     * Sets the display state, if supported.
     *
     * @return A runnable containing work to be deferred until after we have
     * exited the critical section, or null if none.
     */
    public void requestDisplayStateLocked(int state) {
    public Runnable requestDisplayStateLocked(int state) {
        return null;
    }

    /**
+34 −9
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
@@ -214,6 +215,11 @@ public final class DisplayManagerService extends SystemService {
    private final DisplayViewport mTempDefaultViewport = new DisplayViewport();
    private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport();

    // Temporary list of deferred work to perform when setting the display state.
    // Only used by requestDisplayState.  The field is self-synchronized and only
    // intended for use inside of the requestGlobalDisplayStateInternal function.
    private final ArrayList<Runnable> mTempDisplayStateWorkQueue = new ArrayList<Runnable>();

    public DisplayManagerService(Context context) {
        super(context);
        mContext = context;
@@ -318,13 +324,28 @@ public final class DisplayManagerService extends SystemService {
    }

    private void requestGlobalDisplayStateInternal(int state) {
        synchronized (mTempDisplayStateWorkQueue) {
            try {
                // Update the display state within the lock.
                synchronized (mSyncRoot) {
                    if (mGlobalDisplayState != state) {
                        mGlobalDisplayState = state;
                updateGlobalDisplayStateLocked();
                        updateGlobalDisplayStateLocked(mTempDisplayStateWorkQueue);
                        scheduleTraversalLocked(false);
                    }
                }

                // Setting the display power state can take hundreds of milliseconds
                // to complete so we defer the most expensive part of the work until
                // after we have exited the critical section to avoid blocking other
                // threads for a long time.
                for (int i = 0; i < mTempDisplayStateWorkQueue.size(); i++) {
                    mTempDisplayStateWorkQueue.get(i).run();
                }
            } finally {
                mTempDisplayStateWorkQueue.clear();
            }
        }
    }

    private DisplayInfo getDisplayInfoInternal(int displayId, int callingUid) {
@@ -669,21 +690,25 @@ public final class DisplayManagerService extends SystemService {
        scheduleTraversalLocked(false);
    }

    private void updateGlobalDisplayStateLocked() {
    private void updateGlobalDisplayStateLocked(List<Runnable> workQueue) {
        final int count = mDisplayDevices.size();
        for (int i = 0; i < count; i++) {
            DisplayDevice device = mDisplayDevices.get(i);
            updateDisplayStateLocked(device);
            Runnable runnable = updateDisplayStateLocked(device);
            if (runnable != null) {
                workQueue.add(runnable);
            }
        }
    }

    private void updateDisplayStateLocked(DisplayDevice device) {
    private Runnable updateDisplayStateLocked(DisplayDevice device) {
        // Blank or unblank the display immediately to match the state requested
        // by the display power controller (if known).
        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
        if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
            device.requestDisplayStateLocked(mGlobalDisplayState);
            return device.requestDisplayStateLocked(mGlobalDisplayState);
        }
        return null;
    }

    // Adds a new logical display based on the given display device.
+20 −8
Original line number Diff line number Diff line
@@ -222,19 +222,31 @@ final class LocalDisplayAdapter extends DisplayAdapter {
        }

        @Override
        public void requestDisplayStateLocked(int state) {
        public Runnable requestDisplayStateLocked(final int state) {
            if (mState != state) {
                final int displayId = mBuiltInDisplayId;
                final IBinder token = getDisplayTokenLocked();
                final int mode = getPowerModeForState(state);
                mState = state;
                updateDeviceInfoLocked();

                // Defer actually setting the display power mode until we have exited
                // the critical section since it can take hundreds of milliseconds
                // to complete.
                return new Runnable() {
                    @Override
                    public void run() {
                        Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState("
                        + Display.stateToString(state) + ", id=" + mBuiltInDisplayId + ")");
                                + Display.stateToString(state) + ", id=" + displayId + ")");
                        try {
                    SurfaceControl.setDisplayPowerMode(getDisplayTokenLocked(), mode);
                            SurfaceControl.setDisplayPowerMode(token, mode);
                        } finally {
                            Trace.traceEnd(Trace.TRACE_TAG_POWER);
                        }
                mState = state;
                updateDeviceInfoLocked();
                    }
                };
            }
            return null;
        }

        @Override
+2 −1
Original line number Diff line number Diff line
@@ -188,7 +188,7 @@ final class VirtualDisplayAdapter extends DisplayAdapter {
        }

        @Override
        public void requestDisplayStateLocked(int state) {
        public Runnable requestDisplayStateLocked(int state) {
            if (state != mDisplayState) {
                mDisplayState = state;
                if (state == Display.STATE_OFF) {
@@ -197,6 +197,7 @@ final class VirtualDisplayAdapter extends DisplayAdapter {
                    mCallback.dispatchDisplayResumed();
                }
            }
            return null;
        }

        @Override