Loading core/java/android/app/ActivityThread.java +11 −2 Original line number Diff line number Diff line Loading @@ -1050,6 +1050,8 @@ public final class ActivityThread extends ClientTransactionHandler public boolean managed; public boolean mallocInfo; public boolean runGc; // compression format to dump bitmaps, null if no bitmaps to be dumped public String dumpBitmaps; String path; ParcelFileDescriptor fd; RemoteCallback finishCallback; Loading Loading @@ -1442,11 +1444,12 @@ public final class ActivityThread extends ClientTransactionHandler } @Override public void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, String path, ParcelFileDescriptor fd, RemoteCallback finishCallback) { public void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, String dumpBitmaps, String path, ParcelFileDescriptor fd, RemoteCallback finishCallback) { DumpHeapData dhd = new DumpHeapData(); dhd.managed = managed; dhd.mallocInfo = mallocInfo; dhd.dumpBitmaps = dumpBitmaps; dhd.runGc = runGc; dhd.path = path; try { Loading Loading @@ -6731,6 +6734,9 @@ public final class ActivityThread extends ClientTransactionHandler System.runFinalization(); System.gc(); } if (dhd.dumpBitmaps != null) { Bitmap.dumpAll(dhd.dumpBitmaps); } try (ParcelFileDescriptor fd = dhd.fd) { if (dhd.managed) { Debug.dumpHprofData(dhd.path, fd.getFileDescriptor()); Loading Loading @@ -6758,6 +6764,9 @@ public final class ActivityThread extends ClientTransactionHandler if (dhd.finishCallback != null) { dhd.finishCallback.sendResult(null); } if (dhd.dumpBitmaps != null) { Bitmap.dumpAll(null); // clear dump } } final void handleDispatchPackageBroadcast(int cmd, String[] packages) { Loading core/java/android/app/IActivityManager.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -392,7 +392,7 @@ interface IActivityManager { oneway void getMimeTypeFilterAsync(in Uri uri, int userId, in RemoteCallback resultCallback); // Cause the specified process to dump the specified heap. boolean dumpHeap(in String process, int userId, boolean managed, boolean mallocInfo, boolean runGc, in String path, in ParcelFileDescriptor fd, boolean runGc, in String dumpBitmaps, in String path, in ParcelFileDescriptor fd, in RemoteCallback finishCallback); @UnsupportedAppUsage boolean isUserRunning(int userid, int flags); Loading core/java/android/app/IApplicationThread.aidl +2 −1 Original line number Diff line number Diff line Loading @@ -116,7 +116,8 @@ oneway interface IApplicationThread { void scheduleSuicide(); void dispatchPackageBroadcast(int cmd, in String[] packages); void scheduleCrash(in String msg, int typeId, in Bundle extras); void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, in String path, void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, in String dumpBitmaps, in String path, in ParcelFileDescriptor fd, in RemoteCallback finishCallback); void dumpActivity(in ParcelFileDescriptor fd, IBinder servicetoken, in String prefix, in String[] args); Loading graphics/java/android/graphics/Bitmap.java +91 −0 Original line number Diff line number Diff line Loading @@ -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"; Loading Loading @@ -119,6 +122,11 @@ public final class Bitmap implements Parcelable { return sDefaultDensity; } /** * @hide */ private static final WeakHashMap<Bitmap, Void> sAllBitmaps = new WeakHashMap<>(); /** * Private constructor that must receive an already allocated native bitmap * int (pointer). Loading Loading @@ -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); } } /** Loading Loading @@ -1509,6 +1520,86 @@ public final class Bitmap implements Parcelable { final int nativeInt; } /** * @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. Loading services/core/java/com/android/server/am/ActivityManagerService.java +4 −2 Original line number Diff line number Diff line Loading @@ -17297,7 +17297,8 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public boolean dumpHeap(String process, int userId, boolean managed, boolean mallocInfo, boolean runGc, String path, ParcelFileDescriptor fd, RemoteCallback finishCallback) { boolean runGc, String dumpBitmaps, String path, ParcelFileDescriptor fd, RemoteCallback finishCallback) { try { // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to // its own permission (same as profileControl). Loading Loading @@ -17331,7 +17332,8 @@ public class ActivityManagerService extends IActivityManager.Stub } }, null); thread.dumpHeap(managed, mallocInfo, runGc, path, fd, intermediateCallback); thread.dumpHeap(managed, mallocInfo, runGc, dumpBitmaps, path, fd, intermediateCallback); fd = null; return true; } Loading
core/java/android/app/ActivityThread.java +11 −2 Original line number Diff line number Diff line Loading @@ -1050,6 +1050,8 @@ public final class ActivityThread extends ClientTransactionHandler public boolean managed; public boolean mallocInfo; public boolean runGc; // compression format to dump bitmaps, null if no bitmaps to be dumped public String dumpBitmaps; String path; ParcelFileDescriptor fd; RemoteCallback finishCallback; Loading Loading @@ -1442,11 +1444,12 @@ public final class ActivityThread extends ClientTransactionHandler } @Override public void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, String path, ParcelFileDescriptor fd, RemoteCallback finishCallback) { public void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, String dumpBitmaps, String path, ParcelFileDescriptor fd, RemoteCallback finishCallback) { DumpHeapData dhd = new DumpHeapData(); dhd.managed = managed; dhd.mallocInfo = mallocInfo; dhd.dumpBitmaps = dumpBitmaps; dhd.runGc = runGc; dhd.path = path; try { Loading Loading @@ -6731,6 +6734,9 @@ public final class ActivityThread extends ClientTransactionHandler System.runFinalization(); System.gc(); } if (dhd.dumpBitmaps != null) { Bitmap.dumpAll(dhd.dumpBitmaps); } try (ParcelFileDescriptor fd = dhd.fd) { if (dhd.managed) { Debug.dumpHprofData(dhd.path, fd.getFileDescriptor()); Loading Loading @@ -6758,6 +6764,9 @@ public final class ActivityThread extends ClientTransactionHandler if (dhd.finishCallback != null) { dhd.finishCallback.sendResult(null); } if (dhd.dumpBitmaps != null) { Bitmap.dumpAll(null); // clear dump } } final void handleDispatchPackageBroadcast(int cmd, String[] packages) { Loading
core/java/android/app/IActivityManager.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -392,7 +392,7 @@ interface IActivityManager { oneway void getMimeTypeFilterAsync(in Uri uri, int userId, in RemoteCallback resultCallback); // Cause the specified process to dump the specified heap. boolean dumpHeap(in String process, int userId, boolean managed, boolean mallocInfo, boolean runGc, in String path, in ParcelFileDescriptor fd, boolean runGc, in String dumpBitmaps, in String path, in ParcelFileDescriptor fd, in RemoteCallback finishCallback); @UnsupportedAppUsage boolean isUserRunning(int userid, int flags); Loading
core/java/android/app/IApplicationThread.aidl +2 −1 Original line number Diff line number Diff line Loading @@ -116,7 +116,8 @@ oneway interface IApplicationThread { void scheduleSuicide(); void dispatchPackageBroadcast(int cmd, in String[] packages); void scheduleCrash(in String msg, int typeId, in Bundle extras); void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, in String path, void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, in String dumpBitmaps, in String path, in ParcelFileDescriptor fd, in RemoteCallback finishCallback); void dumpActivity(in ParcelFileDescriptor fd, IBinder servicetoken, in String prefix, in String[] args); Loading
graphics/java/android/graphics/Bitmap.java +91 −0 Original line number Diff line number Diff line Loading @@ -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"; Loading Loading @@ -119,6 +122,11 @@ public final class Bitmap implements Parcelable { return sDefaultDensity; } /** * @hide */ private static final WeakHashMap<Bitmap, Void> sAllBitmaps = new WeakHashMap<>(); /** * Private constructor that must receive an already allocated native bitmap * int (pointer). Loading Loading @@ -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); } } /** Loading Loading @@ -1509,6 +1520,86 @@ public final class Bitmap implements Parcelable { final int nativeInt; } /** * @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. Loading
services/core/java/com/android/server/am/ActivityManagerService.java +4 −2 Original line number Diff line number Diff line Loading @@ -17297,7 +17297,8 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public boolean dumpHeap(String process, int userId, boolean managed, boolean mallocInfo, boolean runGc, String path, ParcelFileDescriptor fd, RemoteCallback finishCallback) { boolean runGc, String dumpBitmaps, String path, ParcelFileDescriptor fd, RemoteCallback finishCallback) { try { // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to // its own permission (same as profileControl). Loading Loading @@ -17331,7 +17332,8 @@ public class ActivityManagerService extends IActivityManager.Stub } }, null); thread.dumpHeap(managed, mallocInfo, runGc, path, fd, intermediateCallback); thread.dumpHeap(managed, mallocInfo, runGc, dumpBitmaps, path, fd, intermediateCallback); fd = null; return true; }