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

Commit 66a641e6 authored by Chavi Weingarten's avatar Chavi Weingarten Committed by Android (Google) Code Review
Browse files

Merge "Screen capture protected content for animations"

parents 471d6d34 b6a288ca
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -653,12 +653,14 @@ public final class SurfaceControl implements Parcelable {
        private final Rect mSourceCrop = new Rect();
        private final float mFrameScale;
        private final boolean mCaptureSecureLayers;
        private final boolean mAllowProtected;

        private CaptureArgs(Builder<? extends Builder<?>> builder) {
            mPixelFormat = builder.mPixelFormat;
            mSourceCrop.set(builder.mSourceCrop);
            mFrameScale = builder.mFrameScale;
            mCaptureSecureLayers = builder.mCaptureSecureLayers;
            mAllowProtected = builder.mAllowProtected;
        }

        /**
@@ -671,6 +673,7 @@ public final class SurfaceControl implements Parcelable {
            private final Rect mSourceCrop = new Rect();
            private float mFrameScale = 1;
            private boolean mCaptureSecureLayers;
            private boolean mAllowProtected;

            /**
             * The desired pixel format of the returned buffer.
@@ -708,6 +711,17 @@ public final class SurfaceControl implements Parcelable {
                return getThis();
            }

            /**
             * Whether to allow the screenshot of protected (DRM) content. Warning: The screenshot
             * cannot be read in unprotected space.
             *
             * @see HardwareBuffer#USAGE_PROTECTED_CONTENT
             */
            public T setAllowProtected(boolean allowProtected) {
                mAllowProtected = allowProtected;
                return getThis();
            }

            /**
             * Each sub class should return itself to allow the builder to chain properly
             */
+5 −0
Original line number Diff line number Diff line
@@ -110,6 +110,7 @@ static struct {
    jfieldID sourceCrop;
    jfieldID frameScale;
    jfieldID captureSecureLayers;
    jfieldID allowProtected;
} gCaptureArgsClassInfo;

static struct {
@@ -368,6 +369,8 @@ static void getCaptureArgs(JNIEnv* env, jobject captureArgsObject, CaptureArgs&
            env->GetFloatField(captureArgsObject, gCaptureArgsClassInfo.frameScale);
    captureArgs.captureSecureLayers =
            env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.captureSecureLayers);
    captureArgs.allowProtected =
            env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.allowProtected);
}

static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env,
@@ -1890,6 +1893,8 @@ int register_android_view_SurfaceControl(JNIEnv* env)
    gCaptureArgsClassInfo.frameScale = GetFieldIDOrDie(env, captureArgsClazz, "mFrameScale", "F");
    gCaptureArgsClassInfo.captureSecureLayers =
            GetFieldIDOrDie(env, captureArgsClazz, "mCaptureSecureLayers", "Z");
    gCaptureArgsClassInfo.allowProtected =
            GetFieldIDOrDie(env, captureArgsClazz, "mAllowProtected", "Z");

    jclass displayCaptureArgsClazz =
            FindClassOrDie(env, "android/view/SurfaceControl$DisplayCaptureArgs");
+109 −66
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.display;

import static com.android.server.wm.utils.RotationAnimationUtils.hasProtectedContent;

import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.display.DisplayManagerInternal;
@@ -35,7 +37,6 @@ import android.view.Surface;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;

import com.android.server.LocalServices;
import com.android.server.policy.WindowManagerPolicy;
@@ -75,6 +76,7 @@ final class ColorFade {

    private static final int EGL_GL_COLORSPACE_KHR = 0x309D;
    private static final int EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT = 0x3490;
    private static final int EGL_PROTECTED_CONTENT_EXT = 0x32C0;

    private final int mDisplayId;

@@ -87,7 +89,6 @@ final class ColorFade {
    private int mDisplayLayerStack; // layer stack associated with primary display
    private int mDisplayWidth;      // real width, not rotated
    private int mDisplayHeight;     // real height, not rotated
    private SurfaceSession mSurfaceSession;
    private SurfaceControl mSurfaceControl;
    private Surface mSurface;
    private NaturalSurfaceLayout mSurfaceLayout;
@@ -97,7 +98,8 @@ final class ColorFade {
    private EGLSurface mEglSurface;
    private boolean mSurfaceVisible;
    private float mSurfaceAlpha;
    private boolean mIsWideColor;
    private boolean mLastWasWideColor;
    private boolean mLastWasProtectedContent;

    // Texture names.  We only use one texture, which contains the screenshot.
    private final int[] mTexNames = new int[1];
@@ -157,9 +159,28 @@ final class ColorFade {
        mDisplayWidth = displayInfo.getNaturalWidth();
        mDisplayHeight = displayInfo.getNaturalHeight();

        // Prepare the surface for drawing.
        if (!(createSurface() && createEglContext() && createEglSurface() &&
              captureScreenshotTextureAndSetViewport())) {
        final IBinder token = SurfaceControl.getInternalDisplayToken();
        if (token == null) {
            Slog.e(TAG,
                    "Failed to take screenshot because internal display is disconnected");
            return false;
        }
        boolean isWideColor = SurfaceControl.getActiveColorMode(token)
                == Display.COLOR_MODE_DISPLAY_P3;

        // Set mPrepared here so if initialization fails, resources can be cleaned up.
        mPrepared = true;

        SurfaceControl.ScreenshotHardwareBuffer hardwareBuffer = captureScreen();
        if (hardwareBuffer == null) {
            dismiss();
            return false;
        }

        boolean isProtected = hasProtectedContent(hardwareBuffer.getHardwareBuffer());
        if (!(createSurfaceControl(hardwareBuffer.containsSecureLayers())
                && createEglContext(isProtected) && createEglSurface(isProtected, isWideColor)
                && setScreenshotTextureAndSetViewport(hardwareBuffer))) {
            dismiss();
            return false;
        }
@@ -180,7 +201,8 @@ final class ColorFade {

        // Done.
        mCreatedResources = true;
        mPrepared = true;
        mLastWasProtectedContent = isProtected;
        mLastWasWideColor = isWideColor;

        // Dejanking optimization.
        // Some GL drivers can introduce a lot of lag in the first few frames as they
@@ -466,7 +488,8 @@ final class ColorFade {
        mProjMatrix[15] = 1f;
    }

    private boolean captureScreenshotTextureAndSetViewport() {
    private boolean setScreenshotTextureAndSetViewport(
            SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer) {
        if (!attachEglContext()) {
            return false;
        }
@@ -482,27 +505,9 @@ final class ColorFade {
            final SurfaceTexture st = new SurfaceTexture(mTexNames[0]);
            final Surface s = new Surface(st);
            try {
                final IBinder token = SurfaceControl.getInternalDisplayToken();
                if (token == null) {
                    Slog.e(TAG,
                            "Failed to take screenshot because internal display is disconnected");
                    return false;
                }

                mIsWideColor = SurfaceControl.getActiveColorMode(token)
                        == Display.COLOR_MODE_DISPLAY_P3;
                SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
                        mDisplayManagerInternal.systemScreenshot(mDisplayId);
                if (screenshotBuffer == null) {
                    Slog.e(TAG, "Failed to take screenshot. Buffer is null");
                    return false;
                }
                s.attachAndQueueBufferWithColorSpace(screenshotBuffer.getHardwareBuffer(),
                        screenshotBuffer.getColorSpace());

                if (screenshotBuffer.containsSecureLayers()) {
                    mTransaction.setSecure(mSurfaceControl, true).apply();
                }
                st.updateTexImage();
                st.getTransformMatrix(mTexMatrix);
            } finally {
@@ -535,7 +540,52 @@ final class ColorFade {
        }
    }

    private boolean createEglContext() {
    private SurfaceControl.ScreenshotHardwareBuffer captureScreen() {
        SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
                mDisplayManagerInternal.systemScreenshot(mDisplayId);
        if (screenshotBuffer == null) {
            Slog.e(TAG, "Failed to take screenshot. Buffer is null");
            return null;
        }
        return screenshotBuffer;
    }

    private boolean createSurfaceControl(boolean isSecure) {
        if (mSurfaceControl != null) {
            mTransaction.setSecure(mSurfaceControl, isSecure).apply();
            return true;
        }

        try {
            final SurfaceControl.Builder builder = new SurfaceControl.Builder()
                    .setName("ColorFade")
                    .setSecure(isSecure)
                    .setCallsite("ColorFade.createSurface");
            if (mMode == MODE_FADE) {
                builder.setColorLayer();
            } else {
                builder.setBufferSize(mDisplayWidth, mDisplayHeight);
            }
            mSurfaceControl = builder.build();
        } catch (OutOfResourcesException ex) {
            Slog.e(TAG, "Unable to create surface.", ex);
            return false;
        }

        mTransaction.setLayerStack(mSurfaceControl, mDisplayLayerStack);
        mTransaction.setWindowCrop(mSurfaceControl, mDisplayWidth, mDisplayHeight);
        mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal, mDisplayId,
                mSurfaceControl);
        mSurfaceLayout.onDisplayTransaction(mTransaction);
        mTransaction.apply();

        mSurface = new Surface();
        mSurface.copyFrom(mSurfaceControl);

        return true;
    }

    private boolean createEglContext(boolean isProtected) {
        if (mEglDisplay == null) {
            mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
            if (mEglDisplay == EGL14.EGL_NO_DISPLAY) {
@@ -576,13 +626,25 @@ final class ColorFade {
            mEglConfig = eglConfigs[0];
        }

        // The old context needs to be destroyed if the protected flag has changed. The context will
        // be recreated based on the protected flag
        if (mEglContext != null && isProtected != mLastWasProtectedContent) {
            EGL14.eglDestroyContext(mEglDisplay, mEglContext);
            mEglContext = null;
        }

        if (mEglContext == null) {
            int[] eglContextAttribList = new int[] {
                    EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
                    EGL14.EGL_NONE, EGL14.EGL_NONE,
                    EGL14.EGL_NONE
            };
            mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig,
                    EGL14.EGL_NO_CONTEXT, eglContextAttribList, 0);
            if (isProtected) {
                eglContextAttribList[2] = EGL_PROTECTED_CONTENT_EXT;
                eglContextAttribList[3] = EGL14.EGL_TRUE;
            }
            mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig, EGL14.EGL_NO_CONTEXT,
                    eglContextAttribList, 0);
            if (mEglContext == null) {
                logEglError("eglCreateContext");
                return false;
@@ -591,53 +653,34 @@ final class ColorFade {
        return true;
    }

    private boolean createSurface() {
        if (mSurfaceSession == null) {
            mSurfaceSession = new SurfaceSession();
        }

        if (mSurfaceControl == null) {
            try {
                final SurfaceControl.Builder builder = new SurfaceControl.Builder(mSurfaceSession)
                        .setName("ColorFade")
                        .setCallsite("ColorFade.createSurface");
                if (mMode == MODE_FADE) {
                    builder.setColorLayer();
                } else {
                    builder.setBufferSize(mDisplayWidth, mDisplayHeight);
                }
                mSurfaceControl = builder.build();
            } catch (OutOfResourcesException ex) {
                Slog.e(TAG, "Unable to create surface.", ex);
                return false;
            }

            mTransaction.setLayerStack(mSurfaceControl, mDisplayLayerStack);
            mTransaction.setWindowCrop(mSurfaceControl, mDisplayWidth, mDisplayHeight);
            mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
                    mDisplayId, mSurfaceControl);
            mSurfaceLayout.onDisplayTransaction(mTransaction);
            mTransaction.apply();

            mSurface = new Surface();
            mSurface.copyFrom(mSurfaceControl);

        }
        return true;
    private boolean createEglSurface(boolean isProtected, boolean isWideColor) {
        // The old surface needs to be destroyed if either the protected flag or wide color flag has
        // changed. The surface will be recreated based on the new flags.
        boolean didContentAttributesChange =
                isProtected != mLastWasProtectedContent || isWideColor != mLastWasWideColor;
        if (mEglSurface != null && didContentAttributesChange) {
            EGL14.eglDestroySurface(mEglDisplay, mEglSurface);
            mEglSurface = null;
        }

    private boolean createEglSurface() {
        if (mEglSurface == null) {
            int[] eglSurfaceAttribList = new int[] {
                    EGL14.EGL_NONE,
                    EGL14.EGL_NONE,
                    EGL14.EGL_NONE,
                    EGL14.EGL_NONE,
                    EGL14.EGL_NONE
            };

            int index = 0;
            // If the current display is in wide color, then so is the screenshot.
            if (mIsWideColor) {
                eglSurfaceAttribList[0] = EGL_GL_COLORSPACE_KHR;
                eglSurfaceAttribList[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
            if (isWideColor) {
                eglSurfaceAttribList[index++] = EGL_GL_COLORSPACE_KHR;
                eglSurfaceAttribList[index++] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
            }
            if (isProtected) {
                eglSurfaceAttribList[index++] = EGL_PROTECTED_CONTENT_EXT;
                eglSurfaceAttribList[index] = EGL14.EGL_TRUE;
            }
            // turn our SurfaceControl into a Surface
            mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface,
+1 −0
Original line number Diff line number Diff line
@@ -1293,6 +1293,7 @@ public final class DisplayManagerService extends SystemService {
                            .setSize(displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight())
                            .setUseIdentityTransform(true)
                            .setCaptureSecureLayers(true)
                            .setAllowProtected(true)
                            .build();
            return SurfaceControl.captureDisplay(captureArgs);
        }
+39 −35
Original line number Diff line number Diff line
@@ -181,9 +181,25 @@ class ScreenRotationAnimation {
        mSurfaceRotationAnimationController = new SurfaceRotationAnimationController();

        // Check whether the current screen contains any secure content.
        final boolean isSecure = displayContent.hasSecureWindowOnScreen();
        boolean isSecure = displayContent.hasSecureWindowOnScreen();
        final int displayId = displayContent.getDisplayId();
        final SurfaceControl.Transaction t = mService.mTransactionFactory.get();

        try {
            SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
                    mService.mDisplayManagerInternal.systemScreenshot(displayId);
            if (screenshotBuffer == null) {
                Slog.w(TAG, "Unable to take screenshot of display " + displayId);
                return;
            }

            // If the screenshot contains secure layers, we have to make sure the
            // screenshot surface we display it in also has FLAG_SECURE so that
            // the user can not screenshot secure layers via the screenshot surface.
            if (screenshotBuffer.containsSecureLayers()) {
                isSecure = true;
            }

            mBackColorSurface = displayContent.makeChildSurface(null)
                    .setName("BackColorSurface")
                    .setColorLayer()
@@ -203,17 +219,12 @@ class ScreenRotationAnimation {
                    .setCallsite("ScreenRotationAnimation")
                    .build();

            // Capture a screenshot into the surface we just created.
            final int displayId = displayContent.getDisplayId();
            final Surface surface = mService.mSurfaceFactory.get();
            // In case display bounds change, screenshot buffer and surface may mismatch so set a
            // scaling mode.
            // In case display bounds change, screenshot buffer and surface may mismatch so
            // set a scaling mode.
            surface.copyFrom(mScreenshotLayer);
            surface.setScalingMode(Surface.SCALING_MODE_SCALE_TO_WINDOW);

            SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
                    mService.mDisplayManagerInternal.systemScreenshot(displayId);
            if (screenshotBuffer != null) {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
                    "ScreenRotationAnimation#getMedianBorderLuma");
            mStartLuma = RotationAnimationUtils.getMedianBorderLuma(
@@ -225,12 +236,7 @@ class ScreenRotationAnimation {
            } catch (RuntimeException e) {
                Slog.w(TAG, "Failed to attach screenshot - " + e.getMessage());
            }
                // If the screenshot contains secure layers, we have to make sure the
                // screenshot surface we display it in also has FLAG_SECURE so that
                // the user can not screenshot secure layers via the screenshot surface.
                if (screenshotBuffer.containsSecureLayers()) {
                    t.setSecure(mScreenshotLayer, true);
                }

            t.setLayer(mScreenshotLayer, SCREEN_FREEZE_LAYER_BASE);
            t.reparent(mBackColorSurface, displayContent.getSurfaceControl());
            t.setLayer(mBackColorSurface, -1);
@@ -238,10 +244,8 @@ class ScreenRotationAnimation {
            t.setAlpha(mBackColorSurface, 1);
            t.show(mScreenshotLayer);
            t.show(mBackColorSurface);
            } else {
                Slog.w(TAG, "Unable to take screenshot of display " + displayId);
            }
            surface.destroy();

        } catch (OutOfResourcesException e) {
            Slog.w(TAG, "Unable to allocate freeze surface", e);
        }
Loading