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

Commit 3e713107 authored by wilsonshih's avatar wilsonshih Committed by Wei Sheng Shih
Browse files

Use ImageReader to persist task snapshot to disk.

Which can prevent gl_texture being created for SkImage while copy a
hardware bitmap to software bitmap. So the system server won't has to
ask for an extra dmabuf during persist task snapshot.

Flag: com.android.window.flags.reduce_task_snapshot_memory_usage
Bug: 238206323
Test: dump dmabuf everytime after a close task transition finish,
verify the dmabuf won't increase in system server. Also since the task
snapshot will be removed after open transition, verify the snapshot in
the dmabuf will be removed.

Change-Id: I03f25c097bfdda5cc9ca9b6c33a30fc980103c0b
parent 2b3e35f7
Loading
Loading
Loading
Loading
+68 −13
Original line number Diff line number Diff line
@@ -24,6 +24,10 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;

import android.annotation.NonNull;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.hardware.HardwareBuffer;
import android.media.Image;
import android.media.ImageReader;
import android.os.Process;
import android.os.SystemClock;
import android.os.Trace;
@@ -33,10 +37,12 @@ import android.window.TaskSnapshot;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.TransitionAnimation;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider;
import com.android.server.wm.nano.WindowManagerProtos.TaskSnapshotProto;
import com.android.window.flags.Flags;

import java.io.File;
import java.io.FileOutputStream;
@@ -400,23 +406,20 @@ class SnapshotPersistQueue {
                Slog.e(TAG, "Invalid task snapshot hw buffer, taskId=" + mId);
                return false;
            }
            final Bitmap bitmap = Bitmap.wrapHardwareBuffer(
                    mSnapshot.getHardwareBuffer(), mSnapshot.getColorSpace());
            if (bitmap == null) {
                Slog.e(TAG, "Invalid task snapshot hw bitmap");
                return false;
            }

            final Bitmap swBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false /* isMutable */);
            final HardwareBuffer hwBuffer = mSnapshot.getHardwareBuffer();
            final int width = hwBuffer.getWidth();
            final int height = hwBuffer.getHeight();
            final int pixelFormat = hwBuffer.getFormat();
            final Bitmap swBitmap = !Flags.reduceTaskSnapshotMemoryUsage()
                    || (pixelFormat != PixelFormat.RGB_565 && pixelFormat != PixelFormat.RGBA_8888)
                    || !mSnapshot.isRealSnapshot()
                    || TransitionAnimation.hasProtectedContent(hwBuffer)
                    ? copyToSwBitmapReadBack()
                    : copyToSwBitmapDirect(width, height, pixelFormat);
            if (swBitmap == null) {
                Slog.e(TAG, "Bitmap conversion from (config=" + bitmap.getConfig() + ", isMutable="
                        + bitmap.isMutable() + ") to (config=ARGB_8888, isMutable=false) failed.");
                return false;
            }
            final int width = bitmap.getWidth();
            final int height = bitmap.getHeight();
            bitmap.recycle();

            final File file = mPersistInfoProvider.getHighResolutionBitmapFile(mId, mUserId);
            try (FileOutputStream fos = new FileOutputStream(file)) {
                swBitmap.compress(JPEG, COMPRESS_QUALITY, fos);
@@ -448,6 +451,58 @@ class SnapshotPersistQueue {
            return true;
        }

        private Bitmap copyToSwBitmapReadBack() {
            final Bitmap bitmap = Bitmap.wrapHardwareBuffer(
                    mSnapshot.getHardwareBuffer(), mSnapshot.getColorSpace());
            if (bitmap == null) {
                Slog.e(TAG, "Invalid task snapshot hw bitmap");
                return null;
            }

            final Bitmap swBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false /* isMutable */);
            if (swBitmap == null) {
                Slog.e(TAG, "Bitmap conversion from (config=" + bitmap.getConfig()
                        + ", isMutable=" + bitmap.isMutable()
                        + ") to (config=ARGB_8888, isMutable=false) failed.");
                return null;
            }
            bitmap.recycle();
            return swBitmap;
        }

        /**
         * Use ImageReader to create the software bitmap, so SkImage won't create an extra texture.
         */
        private Bitmap copyToSwBitmapDirect(int width, int height, int pixelFormat) {
            try (ImageReader ir = ImageReader.newInstance(width, height,
                    pixelFormat, 1 /* maxImages */)) {
                ir.getSurface().attachAndQueueBufferWithColorSpace(mSnapshot.getHardwareBuffer(),
                        mSnapshot.getColorSpace());
                try (Image image = ir.acquireLatestImage()) {
                    if (image == null || image.getPlaneCount() < 1) {
                        Slog.e(TAG, "Image reader cannot acquire image");
                        return null;
                    }

                    final Image.Plane[] planes = image.getPlanes();
                    if (planes.length != 1) {
                        Slog.e(TAG, "Image reader cannot get plane");
                        return null;
                    }
                    final Image.Plane plane = planes[0];
                    final int rowPadding = plane.getRowStride() - plane.getPixelStride()
                            * image.getWidth();
                    final Bitmap swBitmap = Bitmap.createBitmap(
                            image.getWidth() + rowPadding / plane.getPixelStride() /* width */,
                            image.getHeight() /* height */,
                            pixelFormat == PixelFormat.RGB_565
                                    ? Bitmap.Config.RGB_565 : Bitmap.Config.ARGB_8888);
                    swBitmap.copyPixelsFromBuffer(plane.getBuffer());
                    return swBitmap;
                }
            }
        }

        @Override
        public boolean equals(Object o) {
            if (o == null || getClass() != o.getClass()) return false;