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

Commit 410361a9 authored by Vladimir Komsiyski's avatar Vladimir Komsiyski
Browse files

API for home support on virtual displays.

Instead of adding yet another virtual display flag, the API is in
VirtualDisplayConfig and uses WM's DisplayWindowSettings to store the
bit whether home is supported.

The difference with the existing FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
is that it also adds navigation bar and the new API doesn't. The flag
is hidden but there are existing clients of it.

Several caveats:
 - Need to use displayUniqueId instead of displayId because we should
   tell WM about the home support before the display is actually
   created and the display listeners notified.
 - Interacting with the DisplayWindowSettings requires the WM lock,
   which must not be acquired while DisplayManagerService is holding
   its own lock because this may and will sometimes cause deadlock.
 - So extracting the displayUniqueId generation logic before the DMS
   locked region of actually creating the virtual display and passing
   it to WM to store the settings.
 - Change in the virtual display uniqueId generation: reusing ids per
   package/uid causes problems in when displays with the same name
   are created and released quickly (CTS). When there are no display
   devices, the same unique id is used, but the DisplayWindowSettings
   may not have yet received the previous onDisplayRemoved callback,
   so the setting for that uniqueId is removed. Making the uniqueIds
   truly unique fixes this and there's no realistic danger of an
   overflow.

Fix: 291749213
Fix: 297167917
Test: see CTS in topic
Test: atest VirtualDisplayAdapterTest
Test: atest DisplayWindowSettingsTests
Test: atest DisplayAreaPolicyTests
Change-Id: If72696a793a9c4d63d4f8b72de7433b0dd440909
parent fe810dc2
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -4598,6 +4598,14 @@ package android.hardware.display {
    field public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1024; // 0x400
  }
  public final class VirtualDisplayConfig implements android.os.Parcelable {
    method @FlaggedApi("android.companion.virtual.flags.vdm_custom_home") public boolean isHomeSupported();
  }
  public static final class VirtualDisplayConfig.Builder {
    method @FlaggedApi("android.companion.virtual.flags.vdm_custom_home") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setHomeSupported(boolean);
  }
}
package android.hardware.hdmi {
+4 −2
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import android.companion.virtual.sensor.VirtualSensorConfig;
import android.companion.virtual.sensor.VirtualSensorDirectChannelCallback;
import android.content.ComponentName;
import android.content.Context;
import android.hardware.display.VirtualDisplayConfig;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SharedMemory;
@@ -326,8 +327,8 @@ public final class VirtualDeviceParams implements Parcelable {
     * support home activities.
     *
     * @see Builder#setHomeComponent
     * @see VirtualDisplayConfig#isHomeSupported()
     */
    // TODO(b/297168328): Link to the relevant API for creating displays with home support.
    @FlaggedApi(Flags.FLAG_VDM_CUSTOM_HOME)
    @Nullable
    public ComponentName getHomeComponent() {
@@ -737,8 +738,9 @@ public final class VirtualDeviceParams implements Parcelable {
         *
         * @param homeComponent The component name to be used as home. If unset, then the system-
         *   default secondary home activity will be used.
         *
         * @see VirtualDisplayConfig#isHomeSupported()
         */
        // TODO(b/297168328): Link to the relevant API for creating displays with home support.
        @FlaggedApi(Flags.FLAG_VDM_CUSTOM_HOME)
        @NonNull
        public Builder setHomeComponent(@Nullable ComponentName homeComponent) {
+48 −4
Original line number Diff line number Diff line
@@ -18,10 +18,12 @@ package android.hardware.display;

import static android.view.Display.DEFAULT_DISPLAY;

import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.hardware.display.DisplayManager.VirtualDisplayFlag;
import android.media.projection.MediaProjection;
import android.os.Handler;
@@ -55,6 +57,7 @@ public final class VirtualDisplayConfig implements Parcelable {
    private final boolean mWindowManagerMirroringEnabled;
    private ArraySet<String> mDisplayCategories = null;
    private final float mRequestedRefreshRate;
    private final boolean mIsHomeSupported;

    private VirtualDisplayConfig(
            @NonNull String name,
@@ -67,7 +70,8 @@ public final class VirtualDisplayConfig implements Parcelable {
            int displayIdToMirror,
            boolean windowManagerMirroringEnabled,
            @NonNull ArraySet<String> displayCategories,
            float requestedRefreshRate) {
            float requestedRefreshRate,
            boolean isHomeSupported) {
        mName = name;
        mWidth = width;
        mHeight = height;
@@ -79,6 +83,7 @@ public final class VirtualDisplayConfig implements Parcelable {
        mWindowManagerMirroringEnabled = windowManagerMirroringEnabled;
        mDisplayCategories = displayCategories;
        mRequestedRefreshRate = requestedRefreshRate;
        mIsHomeSupported = isHomeSupported;
    }

    /**
@@ -156,6 +161,18 @@ public final class VirtualDisplayConfig implements Parcelable {
        return mWindowManagerMirroringEnabled;
    }

    /**
     * Whether this virtual display supports showing home activity and wallpaper.
     *
     * @see Builder#setHomeSupported
     * @hide
     */
    @FlaggedApi(android.companion.virtual.flags.Flags.FLAG_VDM_CUSTOM_HOME)
    @SystemApi
    public boolean isHomeSupported() {
        return android.companion.virtual.flags.Flags.vdmCustomHome() && mIsHomeSupported;
    }

    /**
     * Returns the display categories.
     *
@@ -189,6 +206,7 @@ public final class VirtualDisplayConfig implements Parcelable {
        dest.writeBoolean(mWindowManagerMirroringEnabled);
        dest.writeArraySet(mDisplayCategories);
        dest.writeFloat(mRequestedRefreshRate);
        dest.writeBoolean(mIsHomeSupported);
    }

    @Override
@@ -213,7 +231,8 @@ public final class VirtualDisplayConfig implements Parcelable {
                && mDisplayIdToMirror == that.mDisplayIdToMirror
                && mWindowManagerMirroringEnabled == that.mWindowManagerMirroringEnabled
                && Objects.equals(mDisplayCategories, that.mDisplayCategories)
                && mRequestedRefreshRate == that.mRequestedRefreshRate;
                && mRequestedRefreshRate == that.mRequestedRefreshRate
                && mIsHomeSupported == that.mIsHomeSupported;
    }

    @Override
@@ -221,7 +240,7 @@ public final class VirtualDisplayConfig implements Parcelable {
        int hashCode = Objects.hash(
                mName, mWidth, mHeight, mDensityDpi, mFlags, mSurface, mUniqueId,
                mDisplayIdToMirror, mWindowManagerMirroringEnabled, mDisplayCategories,
                mRequestedRefreshRate);
                mRequestedRefreshRate, mIsHomeSupported);
        return hashCode;
    }

@@ -240,6 +259,7 @@ public final class VirtualDisplayConfig implements Parcelable {
                + " mWindowManagerMirroringEnabled=" + mWindowManagerMirroringEnabled
                + " mDisplayCategories=" + mDisplayCategories
                + " mRequestedRefreshRate=" + mRequestedRefreshRate
                + " mIsHomeSupported=" + mIsHomeSupported
                + ")";
    }

@@ -255,6 +275,7 @@ public final class VirtualDisplayConfig implements Parcelable {
        mWindowManagerMirroringEnabled = in.readBoolean();
        mDisplayCategories = (ArraySet<String>) in.readArraySet(null);
        mRequestedRefreshRate = in.readFloat();
        mIsHomeSupported = in.readBoolean();
    }

    @NonNull
@@ -286,6 +307,7 @@ public final class VirtualDisplayConfig implements Parcelable {
        private boolean mWindowManagerMirroringEnabled = false;
        private ArraySet<String> mDisplayCategories = new ArraySet<>();
        private float mRequestedRefreshRate = 0.0f;
        private boolean mIsHomeSupported = false;

        /**
         * Creates a new Builder.
@@ -421,6 +443,27 @@ public final class VirtualDisplayConfig implements Parcelable {
            return this;
        }

        /**
         * Sets whether this display supports showing home activities and wallpaper.
         *
         * <p>If set to {@code true}, then the home activity relevant to this display will be
         * automatically launched upon the display creation.</p>
         *
         * <p>Note: setting to {@code true} requires the display to be trusted. If the display is
         * not trusted, this property is ignored.</p>
         *
         * @param isHomeSupported whether home activities are supported on the display
         * @see DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED
         * @hide
         */
        @FlaggedApi(android.companion.virtual.flags.Flags.FLAG_VDM_CUSTOM_HOME)
        @SystemApi
        @NonNull
        public Builder setHomeSupported(boolean isHomeSupported) {
            mIsHomeSupported = isHomeSupported;
            return this;
        }

        /**
         * Builds the {@link VirtualDisplayConfig} instance.
         */
@@ -437,7 +480,8 @@ public final class VirtualDisplayConfig implements Parcelable {
                    mDisplayIdToMirror,
                    mWindowManagerMirroringEnabled,
                    mDisplayCategories,
                    mRequestedRefreshRate);
                    mRequestedRefreshRate,
                    mIsHomeSupported);
        }
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -811,6 +811,12 @@
      "group": "WM_DEBUG_STARTING_WINDOW",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "-1325565952": {
      "message": "Attempted to get home support flag of a display that does not exist: %d",
      "level": "WARN",
      "group": "WM_ERROR",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "-1323783276": {
      "message": "performEnableScreen: bootFinished() failed.",
      "level": "WARN",
+23 −2
Original line number Diff line number Diff line
@@ -1607,6 +1607,19 @@ public final class DisplayManagerService extends SystemService {
        final long secondToken = Binder.clearCallingIdentity();
        try {
            final int displayId;
            final String displayUniqueId = VirtualDisplayAdapter.generateDisplayUniqueId(
                    packageName, callingUid, virtualDisplayConfig);

            if (virtualDisplayConfig.isHomeSupported()) {
                if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) {
                    Slog.w(TAG, "Display created with home support but lacks "
                            + "VIRTUAL_DISPLAY_FLAG_TRUSTED, ignoring the home support request.");
                } else {
                    mWindowManagerInternal.setHomeSupportedOnDisplay(displayUniqueId,
                            Display.TYPE_VIRTUAL, true);
                }
            }

            synchronized (mSyncRoot) {
                displayId =
                        createVirtualDisplayLocked(
@@ -1614,6 +1627,7 @@ public final class DisplayManagerService extends SystemService {
                                projection,
                                callingUid,
                                packageName,
                                displayUniqueId,
                                virtualDevice,
                                surface,
                                flags,
@@ -1625,6 +1639,13 @@ public final class DisplayManagerService extends SystemService {
                }
            }

            if (displayId == Display.INVALID_DISPLAY && virtualDisplayConfig.isHomeSupported()
                    && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) {
                // Failed to create the virtual display, so we should clean up the WM settings
                // because it won't receive the onDisplayRemoved callback.
                mWindowManagerInternal.clearDisplaySettings(displayUniqueId, Display.TYPE_VIRTUAL);
            }

            // Build a session describing the MediaProjection instance, if there is one. A session
            // for a VirtualDisplay or physical display mirroring is handled in DisplayContent.
            ContentRecordingSession session = null;
@@ -1698,6 +1719,7 @@ public final class DisplayManagerService extends SystemService {
            IMediaProjection projection,
            int callingUid,
            String packageName,
            String uniqueId,
            IVirtualDevice virtualDevice,
            Surface surface,
            int flags,
@@ -1710,10 +1732,9 @@ public final class DisplayManagerService extends SystemService {
            return -1;
        }


        Slog.d(TAG, "Virtual Display: creating DisplayDevice with VirtualDisplayAdapter");
        DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
                callback, projection, callingUid, packageName, surface, flags,
                callback, projection, callingUid, packageName, uniqueId, surface, flags,
                virtualDisplayConfig);
        if (device == null) {
            Slog.w(TAG, "Virtual Display: VirtualDisplayAdapter failed to create DisplayDevice");
Loading