Provide access to the bitmap's SharedMemory.

The shared memory object can then be passed through HIDL
to avoid unecessary copying of pixel data.

Test: WearOS DisplayOffload
Bug: 260872900
Change-Id: I7f78d2940a295190bd1f1076a01419481dd0d15c
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 3c654d6..e60506f 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -26,7 +26,9 @@
 import android.hardware.HardwareBuffer;
 import android.os.Build;
 import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
+import android.os.SharedMemory;
 import android.os.StrictMode;
 import android.os.Trace;
 import android.util.DisplayMetrics;
@@ -38,6 +40,7 @@
 
 import libcore.util.NativeAllocationRegistry;
 
+import java.io.IOException;
 import java.io.OutputStream;
 import java.lang.ref.WeakReference;
 import java.nio.Buffer;
@@ -738,6 +741,26 @@
     }
 
     /**
+     * Returns the shared memory handle to the pixel storage if the bitmap is already using
+     * shared memory and null if it is not.  The SharedMemory object is then useful to then pass
+     * through HIDL APIs (e.g. WearOS's DisplayOffload service).
+     *
+     * @hide
+     */
+    public SharedMemory getSharedMemory() {
+        checkRecycled("Cannot access shared memory of a recycled bitmap");
+        if (nativeIsBackedByAshmem(mNativePtr)) {
+            try {
+                int fd = nativeGetAshmemFD(mNativePtr);
+                return SharedMemory.fromFileDescriptor(ParcelFileDescriptor.fromFd(fd));
+            } catch (IOException e) {
+                Log.e(TAG, "Unable to create dup'd file descriptor for shared bitmap memory");
+            }
+        }
+        return null;
+    }
+
+    /**
      * Create a hardware bitmap backed by a {@link HardwareBuffer}.
      *
      * <p>The passed HardwareBuffer's usage flags must contain
@@ -2294,6 +2317,7 @@
                                             boolean isMutable);
     private static native Bitmap nativeCopyAshmem(long nativeSrcBitmap);
     private static native Bitmap nativeCopyAshmemConfig(long nativeSrcBitmap, int nativeConfig);
+    private static native int nativeGetAshmemFD(long nativeBitmap);
     private static native long nativeGetNativeFinalizer();
     private static native void nativeRecycle(long nativeBitmap);
     @UnsupportedAppUsage
diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp
index 540abec..c68a6b9 100755
--- a/libs/hwui/jni/Bitmap.cpp
+++ b/libs/hwui/jni/Bitmap.cpp
@@ -422,6 +422,11 @@
     return ret;
 }
 
+static jint Bitmap_getAshmemFd(JNIEnv* env, jobject, jlong bitmapHandle) {
+    LocalScopedBitmap bitmap(bitmapHandle);
+    return (bitmap.valid()) ? bitmap->bitmap().getAshmemFd() : -1;
+}
+
 static void Bitmap_destruct(BitmapWrapper* bitmap) {
     delete bitmap;
 }
@@ -1257,6 +1262,7 @@
         (void*)Bitmap_copyAshmem },
     {   "nativeCopyAshmemConfig",   "(JI)Landroid/graphics/Bitmap;",
         (void*)Bitmap_copyAshmemConfig },
+    {   "nativeGetAshmemFD",        "(J)I", (void*)Bitmap_getAshmemFd },
     {   "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
     {   "nativeRecycle",            "(J)V", (void*)Bitmap_recycle },
     {   "nativeReconfigure",        "(JIIIZ)V", (void*)Bitmap_reconfigure },