summaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
authorEric Miao <ericymiao@google.com>2024-02-06 10:28:44 -0800
committerEric Miao <ericymiao@google.com>2024-04-02 11:35:43 -0700
commitd48d873a2f6dfdcb3962b08bfa025ddb398bb57d (patch)
treec072ee30e10f9ba053b1e9127503275e2ae220cd /graphics
parent9a885d7439b4dff37f15e562fb1b15e959f76caf (diff)
downloadbase-d48d873a2f6dfdcb3962b08bfa025ddb398bb57d.tar.gz
Add compressed bitmaps to be included in `am dumpheap`
Bug: 328443220 `android.graphics.Bitmap` class used to have a field of byte array `mBuffer` for its content. This allowed the bitmap content to be included as part of `am dumpheap`. However, this field was removed when Bitmap was migrated to use native memory. This CL allows contents of bitmaps to be compressed and included as part of `am dumpheap`, with added command line switch '-b <format>'. For example, the command below will include the contents of the bitmaps compressed in PNG format as part of the heap dump. `am dumpheap -b png com.google.android.apps.photos` This is done with a few key changes below: 1. Every bitmap instance created will be tracked by a static `WeakHashMap`. This is so that 1) the bitmap instances are used as weak keys and can be garbage collected normally, and 2) when a bitmap instance is garbage collected, its entry in `WeakHashMap` will also be removed, so the size of the map itself is limited 2. A static field `Bitmap.dumpData` is introduced, and will record every bitmap's `nativePtr` and its compressed content when bitmap dump is enabled during a heap dump 3. `Bitmap.dumpData` will be cleared after the heap is dumped, the recorded information as well as buffers with compressed contents will be garbage collected thereafter. Change-Id: I37b6ea6b947565d1ac5a6bbc5b462c3ceedebec1
Diffstat (limited to 'graphics')
-rw-r--r--graphics/java/android/graphics/Bitmap.java91
1 files changed, 91 insertions, 0 deletions
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 250362b1e1e3..319f115d7427 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -41,12 +41,15 @@ import dalvik.annotation.optimization.CriticalNative;
import libcore.util.NativeAllocationRegistry;
import java.io.IOException;
+import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
+import java.util.ArrayList;
+import java.util.WeakHashMap;
public final class Bitmap implements Parcelable {
private static final String TAG = "Bitmap";
@@ -120,6 +123,11 @@ public final class Bitmap implements Parcelable {
}
/**
+ * @hide
+ */
+ private static final WeakHashMap<Bitmap, Void> sAllBitmaps = new WeakHashMap<>();
+
+ /**
* Private constructor that must receive an already allocated native bitmap
* int (pointer).
*/
@@ -162,6 +170,9 @@ public final class Bitmap implements Parcelable {
Bitmap.class.getClassLoader(), nativeGetNativeFinalizer(), allocationByteCount);
}
registry.registerNativeAllocation(this, nativeBitmap);
+ synchronized (Bitmap.class) {
+ sAllBitmaps.put(this, null);
+ }
}
/**
@@ -1510,6 +1521,86 @@ public final class Bitmap implements Parcelable {
}
/**
+ * @hide
+ */
+ private static final class DumpData {
+ private int count;
+ private int format;
+ private long[] natives;
+ private byte[][] buffers;
+ private int max;
+
+ public DumpData(@NonNull CompressFormat format, int max) {
+ this.max = max;
+ this.format = format.nativeInt;
+ this.natives = new long[max];
+ this.buffers = new byte[max][];
+ this.count = 0;
+ }
+
+ public void add(long nativePtr, byte[] buffer) {
+ natives[count] = nativePtr;
+ buffers[count] = buffer;
+ count = (count >= max) ? max : count + 1;
+ }
+
+ public int size() {
+ return count;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ private static DumpData dumpData = null;
+
+
+ /**
+ * @hide
+ *
+ * Dump all the bitmaps with their contents compressed into dumpData
+ *
+ * @param format format of the compressed image, null to clear dump data
+ */
+ public static void dumpAll(@Nullable String format) {
+ if (format == null) {
+ /* release the dump data */
+ dumpData = null;
+ return;
+ }
+ final CompressFormat fmt;
+ if (format.equals("jpg") || format.equals("jpeg")) {
+ fmt = CompressFormat.JPEG;
+ } else if (format.equals("png")) {
+ fmt = CompressFormat.PNG;
+ } else if (format.equals("webp")) {
+ fmt = CompressFormat.WEBP_LOSSLESS;
+ } else {
+ Log.w(TAG, "No bitmaps dumped: unrecognized format " + format);
+ return;
+ }
+
+ final ArrayList<Bitmap> allBitmaps;
+ synchronized (Bitmap.class) {
+ allBitmaps = new ArrayList<>(sAllBitmaps.size());
+ for (Bitmap bitmap : sAllBitmaps.keySet()) {
+ if (bitmap != null && !bitmap.isRecycled()) {
+ allBitmaps.add(bitmap);
+ }
+ }
+ }
+
+ dumpData = new DumpData(fmt, allBitmaps.size());
+ for (Bitmap bitmap : allBitmaps) {
+ ByteArrayOutputStream bas = new ByteArrayOutputStream();
+ if (bitmap.compress(fmt, 90, bas)) {
+ dumpData.add(bitmap.getNativeInstance(), bas.toByteArray());
+ }
+ }
+ Log.i(TAG, dumpData.size() + "/" + allBitmaps.size() + " bitmaps dumped");
+ }
+
+ /**
* Number of bytes of temp storage we use for communicating between the
* native compressor and the java OutputStream.
*/