From 84a2afcbfbfbbc91cbaf83d55a8ebccc987e66f1 Mon Sep 17 00:00:00 2001
From: Leon Scroggins III <scroggo@google.com>
Date: Sun, 19 Jan 2020 19:27:16 -0500
Subject: [PATCH] Update NDK methods for HARDWARE Bitmaps

Bug: 135133301
Test: I2c1e58c41e49c72fb4bdbc64989da103885d34bf

_getInfo now sets a bit in AndroidBitmapInfo.flags to indicate whether
the Bitmap has Config.HARDWARE.

For a HARDWARE Bitmap, its AHardwareBuffer can now be retrieved with
AndroidBitmap_getHardwareBuffer. Call AHardwareBuffer_acquire on the
buffer so it will not be deleted while the client is using it.

Change-Id: I9240c1928c1478053ecf7c252443a33dbd6fd6db
---
 core/jni/android/graphics/Bitmap.cpp          |  6 +++-
 core/jni/android/graphics/GraphicsJNI.h       |  3 +-
 .../android/graphics/apex/android_bitmap.cpp  | 30 +++++++++++++++----
 .../apex/include/android/graphics/bitmap.h    | 15 ++++++++++
 native/graphics/jni/bitmap.cpp                | 15 ++++++++++
 native/graphics/jni/libjnigraphics.map.txt    |  1 +
 6 files changed, 62 insertions(+), 8 deletions(-)

diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 593728350037..32a7cf32bc0a 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -243,7 +243,8 @@ Bitmap* GraphicsJNI::getNativeBitmap(JNIEnv* env, jobject bitmap) {
     return localBitmap.valid() ? &localBitmap->bitmap() : nullptr;
 }
 
-SkImageInfo GraphicsJNI::getBitmapInfo(JNIEnv* env, jobject bitmap, uint32_t* outRowBytes) {
+SkImageInfo GraphicsJNI::getBitmapInfo(JNIEnv* env, jobject bitmap, uint32_t* outRowBytes,
+                                       bool* isHardware) {
     SkASSERT(env);
     SkASSERT(bitmap);
     SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
@@ -252,6 +253,9 @@ SkImageInfo GraphicsJNI::getBitmapInfo(JNIEnv* env, jobject bitmap, uint32_t* ou
     if (outRowBytes) {
         *outRowBytes = localBitmap->rowBytes();
     }
+    if (isHardware) {
+        *isHardware = localBitmap->isHardware();
+    }
     return localBitmap->info();
 }
 
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 99034edaadf7..1e497654f18d 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -62,7 +62,8 @@ public:
 
     static android::Canvas* getNativeCanvas(JNIEnv*, jobject canvas);
     static android::Bitmap* getNativeBitmap(JNIEnv*, jobject bitmap);
-    static SkImageInfo getBitmapInfo(JNIEnv*, jobject bitmap, uint32_t* outRowBytes);
+    static SkImageInfo getBitmapInfo(JNIEnv*, jobject bitmap, uint32_t* outRowBytes,
+                                     bool* isHardware);
     static SkRegion* getNativeRegion(JNIEnv*, jobject region);
 
     /*
diff --git a/core/jni/android/graphics/apex/android_bitmap.cpp b/core/jni/android/graphics/apex/android_bitmap.cpp
index b8e04a7e9a2b..01a4d9b12d8c 100644
--- a/core/jni/android/graphics/apex/android_bitmap.cpp
+++ b/core/jni/android/graphics/apex/android_bitmap.cpp
@@ -78,7 +78,7 @@ static SkColorType getColorType(AndroidBitmapFormat format) {
     }
 }
 
-static uint32_t getInfoFlags(const SkImageInfo& info) {
+static uint32_t getAlphaFlags(const SkImageInfo& info) {
     switch (info.alphaType()) {
         case kUnknown_SkAlphaType:
             LOG_ALWAYS_FATAL("Bitmap has no alpha type");
@@ -92,6 +92,14 @@ static uint32_t getInfoFlags(const SkImageInfo& info) {
     }
 }
 
+static uint32_t getInfoFlags(const SkImageInfo& info, bool isHardware) {
+    uint32_t flags = getAlphaFlags(info);
+    if (isHardware) {
+        flags |= ANDROID_BITMAP_FLAGS_IS_HARDWARE;
+    }
+    return flags;
+}
+
 ABitmap* ABitmap_copy(ABitmap* srcBitmapHandle, AndroidBitmapFormat dstFormat) {
     SkColorType dstColorType = getColorType(dstFormat);
     if (srcBitmapHandle && dstColorType != kUnknown_SkColorType) {
@@ -108,19 +116,19 @@ ABitmap* ABitmap_copy(ABitmap* srcBitmapHandle, AndroidBitmapFormat dstFormat) {
     return nullptr;
 }
 
-static AndroidBitmapInfo getInfo(const SkImageInfo& imageInfo, uint32_t rowBytes) {
+static AndroidBitmapInfo getInfo(const SkImageInfo& imageInfo, uint32_t rowBytes, bool isHardware) {
     AndroidBitmapInfo info;
     info.width = imageInfo.width();
     info.height = imageInfo.height();
     info.stride = rowBytes;
     info.format = getFormat(imageInfo);
-    info.flags = getInfoFlags(imageInfo);
+    info.flags = getInfoFlags(imageInfo, isHardware);
     return info;
 }
 
 AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmapHandle) {
     Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle);
-    return getInfo(bitmap->info(), bitmap->rowBytes());
+    return getInfo(bitmap->info(), bitmap->rowBytes(), bitmap->isHardware());
 }
 
 namespace {
@@ -219,8 +227,9 @@ ADataSpace ABitmap_getDataSpace(ABitmap* bitmapHandle) {
 
 AndroidBitmapInfo ABitmap_getInfoFromJava(JNIEnv* env, jobject bitmapObj) {
     uint32_t rowBytes = 0;
-    SkImageInfo imageInfo = GraphicsJNI::getBitmapInfo(env, bitmapObj, &rowBytes);
-    return getInfo(imageInfo, rowBytes);
+    bool isHardware = false;
+    SkImageInfo imageInfo = GraphicsJNI::getBitmapInfo(env, bitmapObj, &rowBytes, &isHardware);
+    return getInfo(imageInfo, rowBytes, isHardware);
 }
 
 void* ABitmap_getPixels(ABitmap* bitmapHandle) {
@@ -378,3 +387,12 @@ int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const
             return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
     }
 }
+
+AHardwareBuffer* ABitmap_getHardwareBuffer(ABitmap* bitmapHandle) {
+    Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle);
+    AHardwareBuffer* buffer = bitmap->hardwareBuffer();
+    if (buffer) {
+        AHardwareBuffer_acquire(buffer);
+    }
+    return buffer;
+}
diff --git a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
index 683851d09d93..02ec6554f522 100644
--- a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
+++ b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
@@ -21,6 +21,8 @@
 #include <jni.h>
 #include <sys/cdefs.h>
 
+struct AHardwareBuffer;
+
 __BEGIN_DECLS
 
 /**
@@ -62,6 +64,18 @@ jobject ABitmapConfig_getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat forma
 int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const void* pixels,
                      AndroidBitmapCompressFormat format, int32_t quality, void* userContext,
                      AndroidBitmap_compress_write_fn);
+/**
+ *  Retrieve the native object associated with a HARDWARE Bitmap.
+ *
+ *  Client must not modify it while a Bitmap is wrapping it.
+ *
+ *  @param bitmap Handle to an android.graphics.Bitmap.
+ *  @return on success, a pointer to the
+ *         AHardwareBuffer associated with bitmap. This acquires
+ *         a reference on the buffer, and the client must call
+ *         AHardwareBuffer_release when finished with it.
+ */
+AHardwareBuffer* ABitmap_getHardwareBuffer(ABitmap* bitmap);
 
 __END_DECLS
 
@@ -116,6 +130,7 @@ namespace graphics {
         ADataSpace getDataSpace() const { return ABitmap_getDataSpace(mBitmap); }
         void* getPixels() const { return ABitmap_getPixels(mBitmap); }
         void notifyPixelsChanged() const { ABitmap_notifyPixelsChanged(mBitmap); }
+        AHardwareBuffer* getHardwareBuffer() const { return ABitmap_getHardwareBuffer(mBitmap); }
 
     private:
         // takes ownership of the provided ABitmap
diff --git a/native/graphics/jni/bitmap.cpp b/native/graphics/jni/bitmap.cpp
index ea8a521c9d5f..4f21ccba2419 100644
--- a/native/graphics/jni/bitmap.cpp
+++ b/native/graphics/jni/bitmap.cpp
@@ -76,6 +76,21 @@ int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap) {
     return ANDROID_BITMAP_RESULT_SUCCESS;
 }
 
+int AndroidBitmap_getHardwareBuffer(JNIEnv* env, jobject jbitmap, AHardwareBuffer** outBuffer) {
+    if (NULL == env || NULL == jbitmap || NULL == outBuffer) {
+        return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
+    }
+
+    android::graphics::Bitmap bitmap(env, jbitmap);
+
+    if (!bitmap.isValid()) {
+        return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
+    }
+
+    *outBuffer = bitmap.getHardwareBuffer();
+    return *outBuffer == NULL ? ANDROID_BITMAP_RESULT_BAD_PARAMETER : ANDROID_BITMAP_RESULT_SUCCESS;
+}
+
 int AndroidBitmap_compress(const AndroidBitmapInfo* info,
                            int32_t dataSpace,
                            const void* pixels,
diff --git a/native/graphics/jni/libjnigraphics.map.txt b/native/graphics/jni/libjnigraphics.map.txt
index 6843e7a8552f..2e6c966b9d6b 100644
--- a/native/graphics/jni/libjnigraphics.map.txt
+++ b/native/graphics/jni/libjnigraphics.map.txt
@@ -22,6 +22,7 @@ LIBJNIGRAPHICS {
     AndroidBitmap_lockPixels;
     AndroidBitmap_unlockPixels;
     AndroidBitmap_compress; # introduced=30
+    AndroidBitmap_getHardwareBuffer; #introduced=30
   local:
     *;
 };
-- 
GitLab