Add an ID field to `class Bitmap`

Bug: 369619160
Flag: NONE no public API change

To be able to better reason about bitmaps, we added a private mId
field to `class Bitmap`.  This allows the same ID to be used in
heapdump and in log/debugging code for better association.

Change-Id: I5f775167266c87428c717014fa01cb73c59a44c9
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 461a5ae..dfded73 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -102,6 +102,8 @@
 
     private static volatile int sDefaultDensity = -1;
 
+    private long mId;
+
     /**
      * For backwards compatibility, allows the app layer to change the default
      * density when running old apps.
@@ -152,18 +154,19 @@
     Bitmap(long nativeBitmap, int width, int height, int density,
             boolean requestPremultiplied, byte[] ninePatchChunk,
             NinePatch.InsetStruct ninePatchInsets) {
-        this(nativeBitmap, width, height, density, requestPremultiplied, ninePatchChunk,
+        this(0, nativeBitmap, width, height, density, requestPremultiplied, ninePatchChunk,
                 ninePatchInsets, true);
     }
 
     // called from JNI and Bitmap_Delegate.
-    Bitmap(long nativeBitmap, int width, int height, int density,
+    Bitmap(long id, long nativeBitmap, int width, int height, int density,
             boolean requestPremultiplied, byte[] ninePatchChunk,
             NinePatch.InsetStruct ninePatchInsets, boolean fromMalloc) {
         if (nativeBitmap == 0) {
             throw new RuntimeException("internal error: native bitmap is 0");
         }
 
+        mId = id;
         mWidth = width;
         mHeight = height;
         mRequestPremultiplied = requestPremultiplied;
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index b73380e..3848b5a 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -54,6 +54,7 @@
 #include <SkPngEncoder.h>
 #include <SkWebpEncoder.h>
 
+#include <atomic>
 #include <limits>
 
 namespace android {
@@ -86,6 +87,28 @@
 }
 #endif
 
+// generate an ID for this Bitmap, id is a 64-bit integer of 3 parts:
+//   0000xxxxxx - the lower 6 decimal digits is a monotonically increasing number
+//   000x000000 - the 7th decimal digit is the storage type (see PixelStorageType)
+//   xxx0000000 - the 8th decimal digit and above is the current pid
+//
+//   e.g. 43231000076 - means this bitmap is the 76th bitmap created, has the
+//   storage type of 'Heap', and is created in a process with pid 4323.
+//
+//   NOTE:
+//   1) the monotonic number could increase beyond 1000,000 and wrap around, which
+//   only happens when more than 1,000,000 bitmaps have been created over time.
+//   This could result in two IDs being the same despite being really rare.
+//   2) the IDs are intentionally represented in decimal to make it easier to
+//   reason and associate with numbers shown in heap dump (mostly in decimal)
+//   and PIDs shown in different tools (mostly in decimal as well).
+uint64_t Bitmap::getId(PixelStorageType type) {
+    static std::atomic<uint64_t> idCounter{0};
+    return (idCounter.fetch_add(1) % 1000000)
+        + static_cast<uint64_t>(type) * 1000000
+        + static_cast<uint64_t>(getpid()) * 10000000;
+}
+
 bool Bitmap::computeAllocationSize(size_t rowBytes, int height, size_t* size) {
     return 0 <= height && height <= std::numeric_limits<size_t>::max() &&
            !__builtin_mul_overflow(rowBytes, (size_t)height, size) &&
@@ -261,7 +284,8 @@
 Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes)
         : SkPixelRef(info.width(), info.height(), address, rowBytes)
         , mInfo(validateAlpha(info))
-        , mPixelStorageType(PixelStorageType::Heap) {
+        , mPixelStorageType(PixelStorageType::Heap)
+        , mId(getId(mPixelStorageType)) {
     mPixelStorage.heap.address = address;
     mPixelStorage.heap.size = size;
     traceBitmapCreate();
@@ -270,7 +294,8 @@
 Bitmap::Bitmap(SkPixelRef& pixelRef, const SkImageInfo& info)
         : SkPixelRef(info.width(), info.height(), pixelRef.pixels(), pixelRef.rowBytes())
         , mInfo(validateAlpha(info))
-        , mPixelStorageType(PixelStorageType::WrappedPixelRef) {
+        , mPixelStorageType(PixelStorageType::WrappedPixelRef)
+        , mId(getId(mPixelStorageType)) {
     pixelRef.ref();
     mPixelStorage.wrapped.pixelRef = &pixelRef;
     traceBitmapCreate();
@@ -279,7 +304,8 @@
 Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes)
         : SkPixelRef(info.width(), info.height(), address, rowBytes)
         , mInfo(validateAlpha(info))
-        , mPixelStorageType(PixelStorageType::Ashmem) {
+        , mPixelStorageType(PixelStorageType::Ashmem)
+        , mId(getId(mPixelStorageType)) {
     mPixelStorage.ashmem.address = address;
     mPixelStorage.ashmem.fd = fd;
     mPixelStorage.ashmem.size = mappedSize;
@@ -293,7 +319,8 @@
         , mInfo(validateAlpha(info))
         , mPixelStorageType(PixelStorageType::Hardware)
         , mPalette(palette)
-        , mPaletteGenerationId(getGenerationID()) {
+        , mPaletteGenerationId(getGenerationID())
+        , mId(getId(mPixelStorageType)) {
     mPixelStorage.hardware.buffer = buffer;
     mPixelStorage.hardware.size = AHardwareBuffer_getAllocationSize(buffer);
     AHardwareBuffer_acquire(buffer);
@@ -578,6 +605,7 @@
 }
 
 std::mutex Bitmap::mLock{};
+
 size_t Bitmap::mTotalBitmapBytes = 0;
 size_t Bitmap::mTotalBitmapCount = 0;
 
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 3d55d85..9bbca5b 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -37,10 +37,10 @@
 namespace android {
 
 enum class PixelStorageType {
-    WrappedPixelRef,
-    Heap,
-    Ashmem,
-    Hardware,
+    WrappedPixelRef = 0,
+    Heap = 1,
+    Ashmem = 2,
+    Hardware = 3,
 };
 
 // TODO: Find a better home for this. It's here because hwui/Bitmap is exported and CanvasTransform
@@ -104,6 +104,10 @@
     void setColorSpace(sk_sp<SkColorSpace> colorSpace);
     void setAlphaType(SkAlphaType alphaType);
 
+    uint64_t getId() const {
+        return mId;
+    }
+
     void getSkBitmap(SkBitmap* outBitmap);
 
     SkBitmap getSkBitmap() {
@@ -229,6 +233,9 @@
 
     sk_sp<SkImage> mImage;  // Cache is used only for HW Bitmaps with Skia pipeline.
 
+    uint64_t mId;                // unique ID for this bitmap
+    static uint64_t getId(PixelStorageType type);
+
     // for tracing total number and memory usage of bitmaps
     static std::mutex mLock;
     static size_t mTotalBitmapBytes;
diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp
index 010c4e8..f349ad9 100644
--- a/libs/hwui/jni/Bitmap.cpp
+++ b/libs/hwui/jni/Bitmap.cpp
@@ -196,7 +196,7 @@
         int density) {
     static jmethodID gBitmap_constructorMethodID =
         GetMethodIDOrDie(env, gBitmap_class,
-            "<init>", "(JIIIZ[BLandroid/graphics/NinePatch$InsetStruct;Z)V");
+            "<init>", "(JJIIIZ[BLandroid/graphics/NinePatch$InsetStruct;Z)V");
 
     bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
     bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
@@ -209,7 +209,8 @@
         bitmapWrapper->bitmap().setImmutable();
     }
     jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
-            reinterpret_cast<jlong>(bitmapWrapper), bitmap->width(), bitmap->height(), density,
+            static_cast<jlong>(bitmap->getId()), reinterpret_cast<jlong>(bitmapWrapper),
+            bitmap->width(), bitmap->height(), density,
             isPremultiplied, ninePatchChunk, ninePatchInsets, fromMalloc);
 
     if (env->ExceptionCheck() != 0) {