From 3222d3f40dd76c871c557915e9fb6174997e5aa4 Mon Sep 17 00:00:00 2001 From: Ahan Wu Date: Wed, 11 Mar 2020 20:24:00 +0800 Subject: [PATCH] Recycle the bitmap as soon as possible Recycle the bitmap as soon as possible to release native heap. According to meminfo, it uses around 20MB less than the version which waits for gc. Bug: 149744069 Bug: 147379974 Test: mp sysuig and reboot to lockscreen Test: adb shell dumpsys meminfo com.android.systemui Change-Id: I513edc62b868e6c9a6a3e3b7420961acc606eb0f --- .../glwallpaper/ImageProcessHelper.java | 29 +++-- .../glwallpaper/ImageWallpaperRenderer.java | 113 ++++++++++++------ .../android/systemui/ImageWallpaperTest.java | 2 +- .../ImageWallpaperRendererTest.java | 1 + 4 files changed, 101 insertions(+), 44 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java index 54eca0e266922..703d5910500a5 100644 --- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java @@ -16,6 +16,8 @@ package com.android.systemui.glwallpaper; +import static com.android.systemui.glwallpaper.ImageWallpaperRenderer.WallpaperTexture; + import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -66,15 +68,15 @@ class ImageProcessHelper { private float mThreshold = DEFAULT_THRESHOLD; - void start(Bitmap bitmap) { - new ThresholdComputeTask(mHandler).execute(bitmap); + void start(WallpaperTexture texture) { + new ThresholdComputeTask(mHandler).execute(texture); } float getThreshold() { return Math.min(mThreshold, MAX_THRESHOLD); } - private static class ThresholdComputeTask extends AsyncTask { + private static class ThresholdComputeTask extends AsyncTask { private Handler mUpdateHandler; ThresholdComputeTask(Handler handler) { @@ -83,13 +85,22 @@ class ImageProcessHelper { } @Override - protected Float doInBackground(Bitmap... bitmaps) { - Bitmap bitmap = bitmaps[0]; - if (bitmap != null) { - return new Threshold().compute(bitmap); + protected Float doInBackground(WallpaperTexture... textures) { + WallpaperTexture texture = textures[0]; + final float[] threshold = new float[] {DEFAULT_THRESHOLD}; + if (texture == null) { + Log.e(TAG, "ThresholdComputeTask: WallpaperTexture not initialized"); + return threshold[0]; } - Log.e(TAG, "ThresholdComputeTask: Can't get bitmap"); - return DEFAULT_THRESHOLD; + + texture.use(bitmap -> { + if (bitmap != null) { + threshold[0] = new Threshold().compute(bitmap); + } else { + Log.e(TAG, "ThresholdComputeTask: Can't get bitmap"); + } + }); + return threshold[0]; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java index ed6675dcba2e6..e9ddb3831b1ab 100644 --- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java @@ -36,6 +36,8 @@ import com.android.systemui.R; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; /** * A GL renderer for image wallpaper. @@ -47,7 +49,6 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer, private static final float SCALE_VIEWPORT_MAX = 1.1f; private static final boolean DEBUG = true; - private final WallpaperManager mWallpaperManager; private final ImageGLProgram mProgram; private final ImageGLWallpaper mWallpaper; private final ImageProcessHelper mImageProcessHelper; @@ -57,18 +58,18 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer, private final Rect mScissor; private final Rect mSurfaceSize = new Rect(); private final Rect mViewport = new Rect(); - private Bitmap mBitmap; private boolean mScissorMode; private float mXOffset; private float mYOffset; - private boolean mWcgContent; + private final WallpaperTexture mTexture; public ImageWallpaperRenderer(Context context, SurfaceProxy proxy) { - mWallpaperManager = context.getSystemService(WallpaperManager.class); - if (mWallpaperManager == null) { + final WallpaperManager wpm = context.getSystemService(WallpaperManager.class); + if (wpm == null) { Log.w(TAG, "WallpaperManager not available"); } + mTexture = new WallpaperTexture(wpm); DisplayInfo displayInfo = new DisplayInfo(); context.getDisplay().getDisplayInfo(displayInfo); @@ -90,15 +91,13 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer, } protected void startProcessingImage() { - if (loadBitmap()) { - // Compute threshold of the image, this is an async work. - mImageProcessHelper.start(mBitmap); - } + // Compute threshold of the image, this is an async work. + mImageProcessHelper.start(mTexture); } @Override public boolean isWcgContent() { - return mWcgContent; + return mTexture.isWcgContent(); } @Override @@ -107,30 +106,12 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer, mProgram.useGLProgram( R.raw.image_wallpaper_vertex_shader, R.raw.image_wallpaper_fragment_shader); - if (!loadBitmap()) { - Log.w(TAG, "reload bitmap failed!"); - } - - mWallpaper.setup(mBitmap); - mBitmap = null; - } - - protected boolean loadBitmap() { - if (DEBUG) { - Log.d(TAG, "loadBitmap: mBitmap=" + mBitmap); - } - if (mWallpaperManager != null && mBitmap == null) { - mBitmap = mWallpaperManager.getBitmap(false /* hardware */); - mWcgContent = mWallpaperManager.wallpaperSupportsWcg(WallpaperManager.FLAG_SYSTEM); - mWallpaperManager.forgetLoadedWallpaper(); - if (mBitmap != null) { - mSurfaceSize.set(0, 0, mBitmap.getWidth(), mBitmap.getHeight()); + mTexture.use(bitmap -> { + if (bitmap == null) { + Log.w(TAG, "reload texture failed!"); } - } - if (DEBUG) { - Log.d(TAG, "loadBitmap done"); - } - return mBitmap != null; + mWallpaper.setup(bitmap); + }); } @Override @@ -174,6 +155,8 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer, @Override public Size reportSurfaceSize() { + mTexture.use(null); + mSurfaceSize.set(mTexture.getTextureDimensions()); return new Size(mSurfaceSize.width(), mSurfaceSize.height()); } @@ -235,7 +218,69 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer, out.print(prefix); out.print("mYOffset="); out.print(mYOffset); out.print(prefix); out.print("threshold="); out.print(mImageProcessHelper.getThreshold()); out.print(prefix); out.print("mReveal="); out.print(mImageRevealHelper.getReveal()); - out.print(prefix); out.print("mWcgContent="); out.print(mWcgContent); + out.print(prefix); out.print("mWcgContent="); out.print(isWcgContent()); mWallpaper.dump(prefix, fd, out, args); } + + static class WallpaperTexture { + private final AtomicInteger mRefCount; + private final Rect mDimensions; + private final WallpaperManager mWallpaperManager; + private Bitmap mBitmap; + private boolean mWcgContent; + + private WallpaperTexture(WallpaperManager wallpaperManager) { + mWallpaperManager = wallpaperManager; + mRefCount = new AtomicInteger(); + mDimensions = new Rect(); + } + + public void use(Consumer consumer) { + mRefCount.incrementAndGet(); + synchronized (mRefCount) { + if (mBitmap == null) { + mBitmap = mWallpaperManager.getBitmap(false /* hardware */); + mWcgContent = mWallpaperManager.wallpaperSupportsWcg( + WallpaperManager.FLAG_SYSTEM); + mWallpaperManager.forgetLoadedWallpaper(); + if (mBitmap != null) { + mDimensions.set(0, 0, mBitmap.getWidth(), mBitmap.getHeight()); + } else { + Log.w(TAG, "Can't get bitmap"); + } + } + } + if (consumer != null) { + consumer.accept(mBitmap); + } + synchronized (mRefCount) { + final int count = mRefCount.decrementAndGet(); + if (count == 0 && mBitmap != null) { + if (DEBUG) { + Log.v(TAG, "WallpaperTexture: release 0x" + getHash() + + ", refCount=" + count); + } + mBitmap.recycle(); + mBitmap = null; + } + } + } + + private boolean isWcgContent() { + return mWcgContent; + } + + private String getHash() { + return mBitmap != null ? Integer.toHexString(mBitmap.hashCode()) : "null"; + } + + private Rect getTextureDimensions() { + return mDimensions; + } + + @Override + public String toString() { + return "{" + getHash() + ", " + mRefCount.get() + "}"; + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java index 678cfd23e3a5e..475023e2506db 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java @@ -134,7 +134,7 @@ public class ImageWallpaperTest extends SysuiTestCase { return new ImageWallpaperRenderer(mMockContext, engine) { @Override public void startProcessingImage() { - loadBitmap(); + // No - Op } }; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java index d881fd51712d6..d61be37692c4b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java @@ -92,6 +92,7 @@ public class ImageWallpaperRendererTest extends SysuiTestCase { mWpmSpy.setBitmap(p3Bitmap); ImageWallpaperRenderer rendererP3 = new ImageWallpaperRenderer(mContext, mSurfaceProxy); + rendererP3.reportSurfaceSize(); assertThat(rendererP3.isWcgContent()).isTrue(); mWpmSpy.setBitmap(srgbBitmap);