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

Commit b989023e authored by Dennis Kiilerich's avatar Dennis Kiilerich
Browse files

Pass never-blank state from VirtualDisplayAdapter to SurfaceFlinger.

The never-blank concept is translated in VirtualDisplayAdapter to be a power-optimised display (instead of a performance optimised display) in the downstream components. This concept indicates that these displays (created via DisplayManager instead of through a virtual device) depend on another display's presence and activeness to be continually rendered and shown. The display they depend on instead optimises for performance when it is on, meaning that all the related displays have good performance.

For cases where dependent display/power optimisation information is not available (calls to DisplayControl#createVirtualDisplay(String, boolean) and SurfaceComposerClient::createVirtualDisplay), the dependent display/power optimisation state is defaulted to true since these are system calls and this preserves the previous behaviour.

Bug: 342681202

Flag: EXEMPT refactor

Test: Flashed build on test device, ran Android Auto Projected
Change-Id: I21d916635c161c3309928edc541e4ee0f3921b25
parent b3b82705
Loading
Loading
Loading
Loading
+9 −4
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ import java.util.Objects;
 */
public class DisplayControl {
    private static native IBinder nativeCreateVirtualDisplay(String name, boolean secure,
            String uniqueId, float requestedRefreshRate);
            boolean optimizeForPower, String uniqueId, float requestedRefreshRate);
    private static native void nativeDestroyVirtualDisplay(IBinder displayToken);
    private static native void nativeOverrideHdrTypes(IBinder displayToken, int[] modes);
    private static native long[] nativeGetPhysicalDisplayIds();
@@ -49,7 +49,7 @@ public class DisplayControl {
     */
    public static IBinder createVirtualDisplay(String name, boolean secure) {
        Objects.requireNonNull(name, "name must not be null");
        return nativeCreateVirtualDisplay(name, secure, "", 0.0f);
        return nativeCreateVirtualDisplay(name, secure, true, "", 0.0f);
    }

    /**
@@ -57,6 +57,10 @@ public class DisplayControl {
     *
     * @param name The name of the virtual display.
     * @param secure Whether this display is secure.
     * @param optimizeForPower Whether SurfaceFlinger should optimize for power (instead of
     *                         performance). Such displays will depend on another display for it to
     *                         be shown and rendered, and that display will optimize for
     *                         performance when it is on.
     * @param uniqueId The unique ID for the display.
     * @param requestedRefreshRate The requested refresh rate in frames per second.
     * For best results, specify a divisor of the physical refresh rate, e.g., 30 or 60 on
@@ -66,10 +70,11 @@ public class DisplayControl {
     * @return The token reference for the display in SurfaceFlinger.
     */
    public static IBinder createVirtualDisplay(String name, boolean secure,
            String uniqueId, float requestedRefreshRate) {
            boolean optimizeForPower, String uniqueId, float requestedRefreshRate) {
        Objects.requireNonNull(name, "name must not be null");
        Objects.requireNonNull(uniqueId, "uniqueId must not be null");
        return nativeCreateVirtualDisplay(name, secure, uniqueId, requestedRefreshRate);
        return nativeCreateVirtualDisplay(name, secure, optimizeForPower, uniqueId,
                requestedRefreshRate);
    }

    /**
+23 −11
Original line number Diff line number Diff line
@@ -103,9 +103,9 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
            Context context, Handler handler, Listener listener, DisplayManagerFlags featureFlags) {
        this(syncRoot, context, handler, listener, new SurfaceControlDisplayFactory() {
            @Override
            public IBinder createDisplay(String name, boolean secure, String uniqueId,
                                         float requestedRefreshRate) {
                return DisplayControl.createVirtualDisplay(name, secure, uniqueId,
            public IBinder createDisplay(String name, boolean secure, boolean optimizeForPower,
                    String uniqueId, float requestedRefreshRate) {
                return DisplayControl.createVirtualDisplay(name, secure, optimizeForPower, uniqueId,
                        requestedRefreshRate);
            }

@@ -182,9 +182,13 @@ public class VirtualDisplayAdapter extends DisplayAdapter {

        String name = virtualDisplayConfig.getName();
        boolean secure = (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
        boolean neverBlank = isNeverBlank(flags);

        IBinder displayToken = mSurfaceControlDisplayFactory.createDisplay(name, secure, uniqueId,
                virtualDisplayConfig.getRequestedRefreshRate());
        // Never-blank displays are considered to be dependent on another display to be rendered.
        // As a result, such displays should optimize for power instead of performance when it is
        // powered on.
        IBinder displayToken = mSurfaceControlDisplayFactory.createDisplay(name, secure, neverBlank,
                uniqueId, virtualDisplayConfig.getRequestedRefreshRate());
        MediaProjectionCallback mediaProjectionCallback =  null;
        if (projection != null) {
            mediaProjectionCallback = new MediaProjectionCallback(appToken);
@@ -318,6 +322,12 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
        return mVirtualDisplayDevices.remove(appToken);
    }

    private static boolean isNeverBlank(int flags) {
        // Private non-mirror displays are never blank and always on.
        return (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0
                && (flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0;
    }

    private final class VirtualDisplayDevice extends DisplayDevice implements DeathRecipient {
        private static final int PENDING_SURFACE_CHANGE = 0x01;
        private static final int PENDING_RESIZE = 0x02;
@@ -377,9 +387,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
            mCallback = callback;
            mProjection = projection;
            mMediaProjectionCallback = mediaProjectionCallback;
            // Private non-mirror displays are never blank and always on.
            mNeverBlank = (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0
                    && (flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0;
            mNeverBlank = isNeverBlank(flags);
            if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()
                    && !mNeverBlank) {
                // The display's power state depends on the power state of the state of its
@@ -782,6 +790,10 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
         *
         * @param name The name of the display.
         * @param secure Whether this display is secure.
         * @param optimizeForPower Whether SurfaceFlinger should optimize for power (instead of
         *                         performance). Such displays will depend on another display for
         *                         it to be shown and rendered, and that display will optimize for
         *                         performance when it is on.
         * @param uniqueId The unique ID for the display.
         * @param requestedRefreshRate
         *     The refresh rate, frames per second, to request on the virtual display.
@@ -791,8 +803,8 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
         *     the refresh rate of the leader physical display.
         * @return The token reference for the display in SurfaceFlinger.
         */
        IBinder createDisplay(String name, boolean secure, String uniqueId,
                              float requestedRefreshRate);
        IBinder createDisplay(String name, boolean secure, boolean optimizeForPower,
                String uniqueId, float requestedRefreshRate);

        /**
         * Destroy a display in SurfaceFlinger.
+4 −3
Original line number Diff line number Diff line
@@ -24,12 +24,13 @@
namespace android {

static jobject nativeCreateVirtualDisplay(JNIEnv* env, jclass clazz, jstring nameObj,
                                          jboolean secure, jstring uniqueIdStr,
                                          jfloat requestedRefreshRate) {
                                          jboolean secure, jboolean optimizeForPower,
                                          jstring uniqueIdStr, jfloat requestedRefreshRate) {
    const ScopedUtfChars name(env, nameObj);
    const ScopedUtfChars uniqueId(env, uniqueIdStr);
    sp<IBinder> token(SurfaceComposerClient::createVirtualDisplay(std::string(name.c_str()),
                                                                  bool(secure),
                                                                  bool(optimizeForPower),
                                                                  std::string(uniqueId.c_str()),
                                                                  requestedRefreshRate));
    return javaObjectForIBinder(env, token);
@@ -182,7 +183,7 @@ static jobject nativeGetPhysicalDisplayToken(JNIEnv* env, jclass clazz, jlong ph

static const JNINativeMethod sDisplayMethods[] = {
        // clang-format off
    {"nativeCreateVirtualDisplay", "(Ljava/lang/String;ZLjava/lang/String;F)Landroid/os/IBinder;",
    {"nativeCreateVirtualDisplay", "(Ljava/lang/String;ZZLjava/lang/String;F)Landroid/os/IBinder;",
            (void*)nativeCreateVirtualDisplay },
    {"nativeDestroyVirtualDisplay", "(Landroid/os/IBinder;)V",
            (void*)nativeDestroyVirtualDisplay },
+2 −1
Original line number Diff line number Diff line
@@ -324,7 +324,8 @@ public class DisplayManagerServiceTest {
            return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener,
                    new VirtualDisplayAdapter.SurfaceControlDisplayFactory() {
                        @Override
                        public IBinder createDisplay(String name, boolean secure, String uniqueId,
                        public IBinder createDisplay(String name, boolean secure,
                                boolean optimizeForPower, String uniqueId,
                                float requestedRefreshRate) {
                            return mMockDisplayToken;
                        }
+44 −1
Original line number Diff line number Diff line
@@ -416,7 +416,7 @@ public class VirtualDisplayAdapterTest {
        final String uniqueId = "uniqueId";
        final IBinder displayToken = new Binder();
        when(mMockSufaceControlDisplayFactory.createDisplay(
                any(), anyBoolean(), eq(uniqueId), anyFloat()))
                any(), anyBoolean(), anyBoolean(), eq(uniqueId), anyFloat()))
                .thenReturn(displayToken);

        // The display needs to be public, otherwise it will be considered never blank.
@@ -456,6 +456,49 @@ public class VirtualDisplayAdapterTest {
        verify(mMockCallback).onPaused();
    }

    @EnableFlags(
            android.companion.virtualdevice.flags.Flags.FLAG_CORRECT_VIRTUAL_DISPLAY_POWER_STATE)
    @Test
    public void createVirtualDisplayLocked_neverBlank_optimizesForPower() {
        final String uniqueId = "uniqueId";
        final IBinder displayToken = new Binder();
        final String name = "name";
        when(mVirtualDisplayConfigMock.getName()).thenReturn(name);
        when(mMockSufaceControlDisplayFactory.createDisplay(
                any(), anyBoolean(), anyBoolean(), eq(uniqueId), anyFloat()))
                .thenReturn(displayToken);

        // Use a private display to cause the display to be never blank.
        mAdapter.createVirtualDisplayLocked(mMockCallback,
                /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage",
                uniqueId, /* surface= */ mSurfaceMock, 0, mVirtualDisplayConfigMock);

        verify(mMockSufaceControlDisplayFactory).createDisplay(eq(name), eq(false), eq(true),
                eq(uniqueId), anyFloat());
    }

    @EnableFlags(
            android.companion.virtualdevice.flags.Flags.FLAG_CORRECT_VIRTUAL_DISPLAY_POWER_STATE)
    @Test
    public void createVirtualDisplayLocked_blankable_optimizesForPerformance() {
        final String uniqueId = "uniqueId";
        final IBinder displayToken = new Binder();
        final String name = "name";
        when(mVirtualDisplayConfigMock.getName()).thenReturn(name);
        when(mMockSufaceControlDisplayFactory.createDisplay(
                any(), anyBoolean(), anyBoolean(), eq(uniqueId), anyFloat()))
                .thenReturn(displayToken);

        // Use a public display to cause the display to be blankable
        mAdapter.createVirtualDisplayLocked(mMockCallback,
                /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage",
                uniqueId, /* surface= */ mSurfaceMock, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
                mVirtualDisplayConfigMock);

        verify(mMockSufaceControlDisplayFactory).createDisplay(eq(name), eq(false), eq(false),
                eq(uniqueId), anyFloat());
    }

    private IVirtualDisplayCallback createCallback() {
        return new IVirtualDisplayCallback.Stub() {