Use ashmem to optimize all bitmap copies.

Bug 21037890
Change-Id: Ie32ca3a0c527755f1a1b77db7548cb9629e2001b
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 1c6f7de..028a385 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -1,5 +1,8 @@
 #define LOG_TAG "GraphicsJNI"
 
+#include <unistd.h>
+#include <sys/mman.h>
+
 #include "jni.h"
 #include "JNIHelp.h"
 #include "GraphicsJNI.h"
@@ -10,6 +13,7 @@
 #include "SkMath.h"
 #include "SkRegion.h"
 #include <android_runtime/AndroidRuntime.h>
+#include <cutils/ashmem.h>
 
 #include <Caches.h>
 #include <TextureCache.h>
@@ -572,6 +576,82 @@
     return true;
 }
 
+android::Bitmap* GraphicsJNI::allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
+                                                     SkColorTable* ctable) {
+    int fd;
+
+    const SkImageInfo& info = bitmap->info();
+    if (info.fColorType == kUnknown_SkColorType) {
+        doThrowIAE(env, "unknown bitmap configuration");
+        return nullptr;
+    }
+
+    size_t size;
+    if (!computeAllocationSize(*bitmap, &size)) {
+        return nullptr;
+    }
+
+    // we must respect the rowBytes value already set on the bitmap instead of
+    // attempting to compute our own.
+    const size_t rowBytes = bitmap->rowBytes();
+
+    // Create new ashmem region with read/write priv
+    fd = ashmem_create_region("bitmap", size);
+    if (fd < 0) {
+        return nullptr;
+    }
+
+    void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    if (addr == MAP_FAILED) {
+        close(fd);
+        return nullptr;
+    }
+
+    if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
+        munmap(addr, size);
+        close(fd);
+        return nullptr;
+    }
+
+    android::Bitmap* wrapper = new android::Bitmap(addr, fd, info, rowBytes, ctable);
+    wrapper->getSkBitmap(bitmap);
+    // since we're already allocated, we lockPixels right away
+    // HeapAllocator behaves this way too
+    bitmap->lockPixels();
+
+    return wrapper;
+}
+
+android::Bitmap* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
+                                                SkColorTable* ctable, int fd, bool readOnly) {
+    int flags;
+
+    const SkImageInfo& info = bitmap->info();
+    if (info.fColorType == kUnknown_SkColorType) {
+        doThrowIAE(env, "unknown bitmap configuration");
+        return nullptr;
+    }
+
+    // Create new ashmem region with read/write priv
+    flags = readOnly ? (PROT_READ) : (PROT_READ | PROT_WRITE);
+    void* addr = mmap(NULL, ashmem_get_size_region(fd), flags, MAP_SHARED, fd, 0);
+    if (addr == MAP_FAILED) {
+        return nullptr;
+    }
+
+    // we must respect the rowBytes value already set on the bitmap instead of
+    // attempting to compute our own.
+    const size_t rowBytes = bitmap->rowBytes();
+
+    android::Bitmap* wrapper = new android::Bitmap(addr, fd, info, rowBytes, ctable);
+    wrapper->getSkBitmap(bitmap);
+    // since we're already allocated, we lockPixels right away
+    // HeapAllocator behaves this way too
+    bitmap->lockPixels();
+
+    return wrapper;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env) {