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

Commit 7112c6e2 authored by Eric Miao's avatar Eric Miao
Browse files

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
parent 6ae0cc56
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -102,6 +102,8 @@ public final class Bitmap implements Parcelable {

    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 @@ public final class Bitmap implements Parcelable {
    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;
+32 −4
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@
#include <SkPngEncoder.h>
#include <SkWebpEncoder.h>

#include <atomic>
#include <limits>

namespace android {
@@ -86,6 +87,28 @@ static uint64_t AHardwareBuffer_getAllocationSize(AHardwareBuffer* aHardwareBuff
}
#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 @@ void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes) {
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(void* address, size_t size, const SkImageInfo& info, size_t rowBy
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(SkPixelRef& pixelRef, const SkImageInfo& info)
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 @@ Bitmap::Bitmap(AHardwareBuffer* buffer, const SkImageInfo& info, size_t rowBytes
        , 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 @@ void Bitmap::setGainmap(sp<uirenderer::Gainmap>&& gainmap) {
}

std::mutex Bitmap::mLock{};

size_t Bitmap::mTotalBitmapBytes = 0;
size_t Bitmap::mTotalBitmapCount = 0;

+11 −4
Original line number Diff line number Diff line
@@ -37,10 +37,10 @@ class SkWStream;
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 @@ public:
    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 @@ private:

    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;
+3 −2
Original line number Diff line number Diff line
@@ -196,7 +196,7 @@ jobject createBitmap(JNIEnv* env, Bitmap* bitmap,
        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 @@ jobject createBitmap(JNIEnv* env, Bitmap* bitmap,
        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) {