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

Commit dab1eb1a authored by Eric Miao's avatar Eric Miao Committed by Android (Google) Code Review
Browse files

Merge changes from topic "add-bitmap-id" into main

* changes:
  Allow more information in bitmap ashmem filenames
  Add an ID field to `class Bitmap`
parents c82eab1c 9b0d370c
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;
+7 −0
Original line number Diff line number Diff line
@@ -139,3 +139,10 @@ flag {
    purpose: PURPOSE_BUGFIX
  }
}

flag {
  name: "bitmap_ashmem_long_name"
  namespace: "core_graphics"
  description: "Whether to have more information in ashmem filenames for bitmaps"
  bug: "369619160"
}
+62 −7
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
#include "Bitmap.h"

#include <android-base/file.h>
#include "HardwareBitmapUploader.h"
#include "Properties.h"
#ifdef __ANDROID__  // Layoutlib does not support render thread
@@ -54,8 +55,18 @@
#include <SkPngEncoder.h>
#include <SkWebpEncoder.h>

#include <atomic>
#include <limits>

#ifdef __ANDROID__
#include <com_android_graphics_hwui_flags.h>
namespace hwui_flags = com::android::graphics::hwui::flags;
#else
namespace hwui_flags {
constexpr bool bitmap_ashmem_long_name() { return false; }
}
#endif

namespace android {

#ifdef __ANDROID__
@@ -86,6 +97,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) &&
@@ -117,6 +150,20 @@ static sk_sp<Bitmap> allocateBitmap(SkBitmap* bitmap, AllocPixelRef alloc) {
    return wrapper;
}

std::string Bitmap::getAshmemId(const char* tag, uint64_t bitmapId,
                                int width, int height, size_t size) {
    if (!hwui_flags::bitmap_ashmem_long_name()) {
        return "bitmap";
    }
    static std::string sCmdline = [] {
        std::string temp;
        android::base::ReadFileToString("/proc/self/cmdline", &temp);
        return temp;
    }();
    return std::format("bitmap/{}-id_{}-{}x{}-size_{}-{}",
                       tag, bitmapId, width, height, size, sCmdline);
}

sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap) {
    return allocateBitmap(bitmap, &Bitmap::allocateAshmemBitmap);
}
@@ -124,7 +171,9 @@ sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap) {
sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
#ifdef __ANDROID__
    // Create new ashmem region with read/write priv
    int fd = ashmem_create_region("bitmap", size);
    uint64_t id = getId(PixelStorageType::Ashmem);
    auto ashmemId = getAshmemId("allocate", id, info.width(), info.height(), size);
    int fd = ashmem_create_region(ashmemId.c_str(), size);
    if (fd < 0) {
        return nullptr;
    }
@@ -140,7 +189,7 @@ sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info,
        close(fd);
        return nullptr;
    }
    return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes));
    return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes, id));
#else
    return Bitmap::allocateHeapBitmap(size, info, rowBytes);
#endif
@@ -261,7 +310,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,16 +320,19 @@ 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();
}

Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes)
Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info,
               size_t rowBytes, uint64_t id)
        : SkPixelRef(info.width(), info.height(), address, rowBytes)
        , mInfo(validateAlpha(info))
        , mPixelStorageType(PixelStorageType::Ashmem) {
        , mPixelStorageType(PixelStorageType::Ashmem)
        , mId(id != INVALID_BITMAP_ID ? id : getId(mPixelStorageType)) {
    mPixelStorage.ashmem.address = address;
    mPixelStorage.ashmem.fd = fd;
    mPixelStorage.ashmem.size = mappedSize;
@@ -293,7 +346,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 +632,7 @@ void Bitmap::setGainmap(sp<uirenderer::Gainmap>&& gainmap) {
}

std::mutex Bitmap::mLock{};

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

+18 −5
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
@@ -79,6 +79,9 @@ public:
    static sk_sp<Bitmap> allocateHeapBitmap(const SkImageInfo& info);
    static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& i, size_t rowBytes);

    static std::string getAshmemId(const char* tag, uint64_t bitmapId,
                                   int width, int height, size_t size);

    /* The createFrom factories construct a new Bitmap object by wrapping the already allocated
     * memory that is provided as an input param.
     */
@@ -104,6 +107,10 @@ public:
    void setColorSpace(sk_sp<SkColorSpace> colorSpace);
    void setAlphaType(SkAlphaType alphaType);

    uint64_t getId() const {
        return mId;
    }

    void getSkBitmap(SkBitmap* outBitmap);

    SkBitmap getSkBitmap() {
@@ -177,11 +184,14 @@ public:
  static bool compress(const SkBitmap& bitmap, JavaCompressFormat format,
                       int32_t quality, SkWStream* stream);
private:
    static constexpr uint64_t INVALID_BITMAP_ID = 0u;

    static sk_sp<Bitmap> allocateAshmemBitmap(size_t size, const SkImageInfo& i, size_t rowBytes);

    Bitmap(void* address, size_t allocSize, const SkImageInfo& info, size_t rowBytes);
    Bitmap(SkPixelRef& pixelRef, const SkImageInfo& info);
    Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes);
    Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes,
           uint64_t id = INVALID_BITMAP_ID);
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
    Bitmap(AHardwareBuffer* buffer, const SkImageInfo& info, size_t rowBytes,
           BitmapPalette palette);
@@ -229,6 +239,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;
+12 −6
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) {
@@ -668,14 +669,20 @@ static binder_status_t writeBlobFromFd(AParcel* parcel, int32_t size, int fd) {
    return STATUS_OK;
}

static binder_status_t writeBlob(AParcel* parcel, const int32_t size, const void* data, bool immutable) {
static binder_status_t writeBlob(AParcel* parcel, uint64_t bitmapId, const SkBitmap& bitmap) {
    const size_t size = bitmap.computeByteSize();
    const void* data = bitmap.getPixels();
    const bool immutable = bitmap.isImmutable();

    if (size <= 0 || data == nullptr) {
        return STATUS_NOT_ENOUGH_DATA;
    }
    binder_status_t error = STATUS_OK;
    if (shouldUseAshmem(parcel, size)) {
        // Create new ashmem region with read/write priv
        base::unique_fd fd(ashmem_create_region("bitmap", size));
        auto ashmemId = Bitmap::getAshmemId("writeblob", bitmapId,
                                            bitmap.width(), bitmap.height(), size);
        base::unique_fd fd(ashmem_create_region(ashmemId.c_str(), size));
        if (fd.get() < 0) {
            return STATUS_NO_MEMORY;
        }
@@ -883,8 +890,7 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
          p.allowFds() ? "allowed" : "forbidden");
#endif

    size_t size = bitmap.computeByteSize();
    status = writeBlob(p.get(), size, bitmap.getPixels(), bitmap.isImmutable());
    status = writeBlob(p.get(), bitmapWrapper->bitmap().getId(), bitmap);
    if (status) {
        doThrowRE(env, "Could not copy bitmap to parcel blob.");
        return JNI_FALSE;