Add internal bitmap api for creating immutable ashmem backed bitmaps.

Bug 21037890
Change-Id: I827e83dd75e301e7d93ead5efdd744f0d8435ae5
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 7bd5af1..04b9a95 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -719,6 +719,21 @@
             getPremulBitmapCreateFlags(isMutable));
 }
 
+static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
+    SkBitmap src;
+    reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
+    SkBitmap result;
+
+    AshmemPixelAllocator allocator(env);
+    if (!src.copyTo(&result, &allocator)) {
+        return NULL;
+    }
+    Bitmap* bitmap = allocator.getStorageObjAndReset();
+    bitmap->peekAtPixelRef()->setImmutable();
+    jobject ret = GraphicsJNI::createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
+    return ret;
+}
+
 static void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) {
     LocalScopedBitmap bitmap(bitmapHandle);
     bitmap->detachFromJava();
@@ -1267,6 +1282,8 @@
         (void*)Bitmap_creator },
     {   "nativeCopy",               "(JIZ)Landroid/graphics/Bitmap;",
         (void*)Bitmap_copy },
+    {   "nativeCopyAshmem",         "(J)Landroid/graphics/Bitmap;",
+        (void*)Bitmap_copyAshmem },
     {   "nativeDestructor",         "(J)V", (void*)Bitmap_destructor },
     {   "nativeRecycle",            "(J)Z", (void*)Bitmap_recycle },
     {   "nativeReconfigure",        "(JIIIIZ)V", (void*)Bitmap_reconfigure },
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 028a385..ff22ef3 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -674,6 +674,25 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+AshmemPixelAllocator::AshmemPixelAllocator(JNIEnv *env) {
+    LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mJavaVM) != JNI_OK,
+            "env->GetJavaVM failed");
+}
+
+AshmemPixelAllocator::~AshmemPixelAllocator() {
+    if (mStorage) {
+        mStorage->detachFromJava();
+    }
+}
+
+bool AshmemPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
+    JNIEnv* env = vm2env(mJavaVM);
+    mStorage = GraphicsJNI::allocateAshmemPixelRef(env, bitmap, ctable);
+    return mStorage != nullptr;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
 static jclass make_globalref(JNIEnv* env, const char classname[])
 {
     jclass c = env->FindClass(classname);
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 4f72118..1938e85 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -144,6 +144,23 @@
     android::Bitmap* mStorage = nullptr;
 };
 
+class AshmemPixelAllocator : public SkBitmap::Allocator {
+public:
+    AshmemPixelAllocator(JNIEnv* env);
+    ~AshmemPixelAllocator();
+    virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable);
+    android::Bitmap* getStorageObjAndReset() {
+        android::Bitmap* result = mStorage;
+        mStorage = NULL;
+        return result;
+    };
+
+private:
+    JavaVM* mJavaVM;
+    android::Bitmap* mStorage = nullptr;
+};
+
+
 enum JNIAccess {
     kRO_JNIAccess,
     kRW_JNIAccess
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 2d8b0b2..a999b71 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -558,6 +558,22 @@
     }
 
     /**
+     * Creates a new immutable bitmap backed by ashmem which can efficiently
+     * be passed between processes.
+     *
+     * @hide
+     */
+    public Bitmap createAshmemBitmap() {
+        checkRecycled("Can't copy a recycled bitmap");
+        Bitmap b = nativeCopyAshmem(mFinalizer.mNativeBitmap);
+        if (b != null) {
+            b.setPremultiplied(mRequestPremultiplied);
+            b.mDensity = mDensity;
+        }
+        return b;
+    }
+
+    /**
      * Creates a new bitmap, scaled from an existing bitmap, when possible. If the
      * specified width and height are the same as the current width and height of
      * the source bitmap, the source bitmap is returned and no new bitmap is
@@ -1636,6 +1652,7 @@
                                               int nativeConfig, boolean mutable);
     private static native Bitmap nativeCopy(long nativeSrcBitmap, int nativeConfig,
                                             boolean isMutable);
+    private static native Bitmap nativeCopyAshmem(long nativeSrcBitmap);
     private static native void nativeDestructor(long nativeBitmap);
     private static native boolean nativeRecycle(long nativeBitmap);
     private static native void nativeReconfigure(long nativeBitmap, int width, int height,