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

Commit c722618a authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "VirtualDisplay: Merge AIDL calls to stop race condition" into udc-dev

parents 2f0523ee 17469b9a
Loading
Loading
Loading
Loading
+37 −2
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArraySet;
import android.view.ContentRecordingSession;
import android.view.Display;
import android.view.Surface;

@@ -53,6 +54,8 @@ public final class VirtualDisplayConfig implements Parcelable {
    private final int mDisplayIdToMirror;
    private final boolean mWindowManagerMirroringEnabled;
    private ArraySet<String> mDisplayCategories = null;
    @Nullable
    private ContentRecordingSession mContentRecordingSession;
    private final float mRequestedRefreshRate;

    private VirtualDisplayConfig(
@@ -65,6 +68,7 @@ public final class VirtualDisplayConfig implements Parcelable {
            @Nullable String uniqueId,
            int displayIdToMirror,
            boolean windowManagerMirroringEnabled,
            ContentRecordingSession session,
            @NonNull ArraySet<String> displayCategories,
            float requestedRefreshRate) {
        mName = name;
@@ -76,6 +80,7 @@ public final class VirtualDisplayConfig implements Parcelable {
        mUniqueId = uniqueId;
        mDisplayIdToMirror = displayIdToMirror;
        mWindowManagerMirroringEnabled = windowManagerMirroringEnabled;
        mContentRecordingSession = session;
        mDisplayCategories = displayCategories;
        mRequestedRefreshRate = requestedRefreshRate;
    }
@@ -155,6 +160,17 @@ public final class VirtualDisplayConfig implements Parcelable {
        return mWindowManagerMirroringEnabled;
    }

    /**
     * Returns the recording session associated with this VirtualDisplay. Only used for
     * recording via {@link MediaProjection}.
     *
     * @hide
     */
    @Nullable
    public ContentRecordingSession getContentRecordingSession() {
        return mContentRecordingSession;
    }

    /**
     * Returns the display categories.
     *
@@ -186,6 +202,7 @@ public final class VirtualDisplayConfig implements Parcelable {
        dest.writeString8(mUniqueId);
        dest.writeInt(mDisplayIdToMirror);
        dest.writeBoolean(mWindowManagerMirroringEnabled);
        dest.writeTypedObject(mContentRecordingSession, flags);
        dest.writeArraySet(mDisplayCategories);
        dest.writeFloat(mRequestedRefreshRate);
    }
@@ -211,6 +228,7 @@ public final class VirtualDisplayConfig implements Parcelable {
                && Objects.equals(mUniqueId, that.mUniqueId)
                && mDisplayIdToMirror == that.mDisplayIdToMirror
                && mWindowManagerMirroringEnabled == that.mWindowManagerMirroringEnabled
                && Objects.equals(mContentRecordingSession, that.mContentRecordingSession)
                && Objects.equals(mDisplayCategories, that.mDisplayCategories)
                && mRequestedRefreshRate == that.mRequestedRefreshRate;
    }
@@ -219,8 +237,8 @@ public final class VirtualDisplayConfig implements Parcelable {
    public int hashCode() {
        int hashCode = Objects.hash(
                mName, mWidth, mHeight, mDensityDpi, mFlags, mSurface, mUniqueId,
                mDisplayIdToMirror, mWindowManagerMirroringEnabled, mDisplayCategories,
                mRequestedRefreshRate);
                mDisplayIdToMirror, mWindowManagerMirroringEnabled, mContentRecordingSession,
                mDisplayCategories, mRequestedRefreshRate);
        return hashCode;
    }

@@ -237,6 +255,7 @@ public final class VirtualDisplayConfig implements Parcelable {
                + " mUniqueId=" + mUniqueId
                + " mDisplayIdToMirror=" + mDisplayIdToMirror
                + " mWindowManagerMirroringEnabled=" + mWindowManagerMirroringEnabled
                + " mContentRecordingSession=" + mContentRecordingSession
                + " mDisplayCategories=" + mDisplayCategories
                + " mRequestedRefreshRate=" + mRequestedRefreshRate
                + ")";
@@ -252,6 +271,7 @@ public final class VirtualDisplayConfig implements Parcelable {
        mUniqueId = in.readString8();
        mDisplayIdToMirror = in.readInt();
        mWindowManagerMirroringEnabled = in.readBoolean();
        mContentRecordingSession = in.readTypedObject(ContentRecordingSession.CREATOR);
        mDisplayCategories = (ArraySet<String>) in.readArraySet(null);
        mRequestedRefreshRate = in.readFloat();
    }
@@ -283,6 +303,8 @@ public final class VirtualDisplayConfig implements Parcelable {
        private String mUniqueId = null;
        private int mDisplayIdToMirror = DEFAULT_DISPLAY;
        private boolean mWindowManagerMirroringEnabled = false;
        @Nullable
        private ContentRecordingSession mContentRecordingSession;
        private ArraySet<String> mDisplayCategories = new ArraySet<>();
        private float mRequestedRefreshRate = 0.0f;

@@ -374,6 +396,18 @@ public final class VirtualDisplayConfig implements Parcelable {
            return this;
        }

        /**
         * Sets the recording session associated with this {@link VirtualDisplay}. Only used for
         * recording via {@link MediaProjection}.
         *
         * @hide
         */
        @NonNull
        public Builder setContentRecordingSession(@Nullable ContentRecordingSession session) {
            mContentRecordingSession = session;
            return this;
        }

        /**
         * Sets the display categories.
         *
@@ -435,6 +469,7 @@ public final class VirtualDisplayConfig implements Parcelable {
                    mUniqueId,
                    mDisplayIdToMirror,
                    mWindowManagerMirroringEnabled,
                    mContentRecordingSession,
                    mDisplayCategories,
                    mRequestedRefreshRate);
        }
+3 −10
Original line number Diff line number Diff line
@@ -191,20 +191,13 @@ public final class MediaProjection {
            } else {
                session = ContentRecordingSession.createTaskSession(launchCookie);
            }
            // Pass in the current session details, so they are guaranteed to only be set in WMS
            // AFTER a VirtualDisplay is constructed (assuming there are no errors during set-up).
            virtualDisplayConfig.setContentRecordingSession(session);
            virtualDisplayConfig.setWindowManagerMirroringEnabled(true);
            final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
            final VirtualDisplay virtualDisplay = dm.createVirtualDisplay(this,
                    virtualDisplayConfig.build(), callback, handler, windowContext);
            if (virtualDisplay == null) {
                // Since WM handling a new display and DM creating a new VirtualDisplay is async,
                // WM may have tried to start task recording and encountered an error that required
                // stopping recording entirely. The VirtualDisplay would then be null when the
                // MediaProjection is no longer active.
                return null;
            }
            session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
            // Successfully set up, so save the current session details.
            getProjectionService().setContentRecordingSession(session, mImpl);
            return virtualDisplay;
        } catch (RemoteException e) {
            // Can not capture if WMS is not accessible, so bail out.
+42 −4
Original line number Diff line number Diff line
@@ -128,6 +128,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.Spline;
import android.view.ContentRecordingSession;
import android.view.Display;
import android.view.DisplayEventReceiver;
import android.view.DisplayInfo;
@@ -250,6 +251,7 @@ public final class DisplayManagerService extends SystemService {
    private ActivityManagerInternal mActivityManagerInternal;
    private ActivityManager mActivityManager;
    private UidImportanceListener mUidImportanceListener = new UidImportanceListener();
    @Nullable
    private IMediaProjectionManager mProjectionService;
    private DeviceStateManagerInternal mDeviceStateManager;
    @GuardedBy("mSyncRoot")
@@ -1494,8 +1496,9 @@ public final class DisplayManagerService extends SystemService {

        final long token = Binder.clearCallingIdentity();
        try {
            final int displayId;
            synchronized (mSyncRoot) {
                final int displayId =
                displayId =
                        createVirtualDisplayLocked(
                                callback,
                                projection,
@@ -1509,8 +1512,39 @@ public final class DisplayManagerService extends SystemService {
                    mDisplayWindowPolicyControllers.put(
                            displayId, Pair.create(virtualDevice, dwpc));
                }
                return displayId;
            }

            // When calling setContentRecordingSession into the WindowManagerService, the WMS
            // attempts to acquire a lock before executing its main body. Due to this, we need
            // to be sure that it isn't called while the DisplayManagerService is also holding
            // a lock, to avoid a deadlock scenario.
            final ContentRecordingSession session =
                    virtualDisplayConfig.getContentRecordingSession();

            if (displayId != Display.INVALID_DISPLAY && session != null) {
                // Only attempt to set content recording session if there are details to set and a
                // VirtualDisplay has been successfully constructed.
                session.setDisplayId(displayId);

                // We set the content recording session here on the server side instead of using
                // a second AIDL call in MediaProjection. By ensuring that a virtual display has
                // been constructed before calling setContentRecordingSession, we avoid a race
                // condition between the DMS & WMS which could lead to the MediaProjection
                // being pre-emptively torn down.
                if (!mWindowManagerInternal.setContentRecordingSession(session)) {
                    // Unable to start mirroring, so tear down projection & release VirtualDisplay.
                    try {
                        getProjectionService().stopActiveProjection();
                    } catch (RemoteException e) {
                        Slog.e(TAG, "Unable to tell MediaProjectionManagerService to stop the "
                                + "active projection", e);
                    }
                    releaseVirtualDisplayInternal(callback.asBinder());
                    return Display.INVALID_DISPLAY;
                }
            }

            return displayId;
        } finally {
            Binder.restoreCallingIdentity(token);
        }
@@ -2804,8 +2838,7 @@ public final class DisplayManagerService extends SystemService {

    private IMediaProjectionManager getProjectionService() {
        if (mProjectionService == null) {
            IBinder b = ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE);
            mProjectionService = IMediaProjectionManager.Stub.asInterface(b);
            mProjectionService = mInjector.getProjectionService();
        }
        return mProjectionService;
    }
@@ -2964,6 +2997,11 @@ public final class DisplayManagerService extends SystemService {
        boolean getHdrOutputConversionSupport() {
            return DisplayControl.getHdrOutputConversionSupport();
        }

        IMediaProjectionManager getProjectionService() {
            IBinder b = ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE);
            return  IMediaProjectionManager.Stub.asInterface(b);
        }
    }

    @VisibleForTesting
+19 −2
Original line number Diff line number Diff line
@@ -88,7 +88,17 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
    // Called with SyncRoot lock held.
    public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
            Context context, Handler handler, Listener listener) {
        this(syncRoot, context, handler, listener, DisplayControl::createDisplay);
        this(syncRoot, context, handler, listener, new SurfaceControlDisplayFactory() {
            @Override
            public IBinder createDisplay(String name, boolean secure, float requestedRefreshRate) {
                return DisplayControl.createDisplay(name, secure, requestedRefreshRate);
            }

            @Override
            public void destroyDisplay(IBinder displayToken) {
                DisplayControl.destroyDisplay(displayToken);
            }
        });
    }

    @VisibleForTesting
@@ -311,7 +321,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
                mSurface.release();
                mSurface = null;
            }
            DisplayControl.destroyDisplay(getDisplayTokenLocked());
            mSurfaceControlDisplayFactory.destroyDisplay(getDisplayTokenLocked());
            if (mProjection != null && mMediaProjectionCallback != null) {
                try {
                    mProjection.unregisterCallback(mMediaProjectionCallback);
@@ -653,5 +663,12 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
         * @return The token reference for the display in SurfaceFlinger.
         */
        IBinder createDisplay(String name, boolean secure, float requestedRefreshRate);
        
        /**
         * Destroy a display in SurfaceFlinger.
         *
         * @param displayToken The display token for the display to be destroyed.
         */
        void destroyDisplay(IBinder displayToken);
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -108,6 +108,7 @@
    <uses-permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES" />
    <uses-permission android:name="android.permission.ACCESS_CONTEXT_HUB" />
    <uses-permission android:name="android.permission.USE_BIOMETRIC_INTERNAL" />
    <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />

    <queries>
        <package android:name="com.android.servicestests.apps.suspendtestapp" />
Loading