Loading core/jni/android/graphics/Bitmap.cpp +110 −76 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ #include <sys/mman.h> #include <cutils/ashmem.h> #define DEBUG_PARCEL 0 namespace android { class WrappedPixelRef : public SkPixelRef { Loading Loading @@ -959,75 +961,82 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { } } int fd = p->readFileDescriptor(); int dupFd = dup(fd); // Read the bitmap blob. size_t size = bitmap->getSize(); android::Parcel::ReadableBlob blob; android::status_t status = p->readBlob(size, &blob); if (status) { SkSafeUnref(ctable); doThrowRE(env, "Could not read bitmap blob."); return NULL; } // Map the bitmap in place from the ashmem region if possible otherwise copy. Bitmap* nativeBitmap; if (blob.fd() >= 0 && (blob.isMutable() || !isMutable)) { #if DEBUG_PARCEL ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob " "(fds %s)", isMutable ? "mutable" : "immutable", blob.isMutable() ? "mutable" : "immutable", p->allowFds() ? "allowed" : "forbidden"); #endif // Dup the file descriptor so we can keep a reference to it after the Parcel // is disposed. int dupFd = dup(blob.fd()); if (dupFd < 0) { blob.release(); SkSafeUnref(ctable); doThrowRE(env, "Could not dup parcel fd."); doThrowRE(env, "Could not allocate dup blob fd."); return NULL; } bool readOnlyMapping = !isMutable; Bitmap* nativeBitmap = GraphicsJNI::mapAshmemPixelRef(env, bitmap.get(), ctable, dupFd, readOnlyMapping); // Map the pixels in place and take ownership of the ashmem region. nativeBitmap = GraphicsJNI::mapAshmemPixelRef(env, bitmap.get(), ctable, dupFd, const_cast<void*>(blob.data()), !isMutable); SkSafeUnref(ctable); if (!nativeBitmap) { close(dupFd); blob.release(); doThrowRE(env, "Could not allocate ashmem pixel ref."); return NULL; } bitmap->pixelRef()->setImmutable(); return GraphicsJNI::createBitmap(env, nativeBitmap, getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); // Clear the blob handle, don't release it. blob.clear(); } else { #if DEBUG_PARCEL if (blob.fd() >= 0) { ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap " "from immutable blob (fds %s)", p->allowFds() ? "allowed" : "forbidden"); } else { ALOGD("Bitmap.createFromParcel: copied contents from %s blob " "(fds %s)", blob.isMutable() ? "mutable" : "immutable", p->allowFds() ? "allowed" : "forbidden"); } #endif class Ashmem { public: Ashmem(size_t sz, bool removeWritePerm) : mSize(sz) { int fd = -1; void *addr = nullptr; // Create new ashmem region with read/write priv fd = ashmem_create_region("bitmap", sz); if (fd < 0) { goto error; } addr = mmap(nullptr, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { goto error; } // If requested, remove the ability to make additional writeable to // this memory. if (removeWritePerm) { if (ashmem_set_prot_region(fd, PROT_READ) < 0) { goto error; } } mFd = fd; mPtr = addr; return; error: if (fd >= 0) { close(fd); } if (addr) { munmap(addr, sz); } // Copy the pixels into a new buffer. nativeBitmap = GraphicsJNI::allocateJavaPixelRef(env, bitmap.get(), ctable); SkSafeUnref(ctable); if (!nativeBitmap) { blob.release(); doThrowRE(env, "Could not allocate java pixel ref."); return NULL; } ~Ashmem() { if (mPtr) { close(mFd); munmap(mPtr, mSize); bitmap->lockPixels(); memcpy(bitmap->getPixels(), blob.data(), size); bitmap->unlockPixels(); // Release the blob handle. blob.release(); } return GraphicsJNI::createBitmap(env, nativeBitmap, getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); } void *getPtr() const { return mPtr; } int getFd() const { return mFd; } private: int mFd = -1; int mSize; void* mPtr = nullptr; }; static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, jlong bitmapHandle, Loading Loading @@ -1064,26 +1073,51 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, } } bool ashmemSrc = androidBitmap->getAshmemFd() >= 0; if (ashmemSrc && !isMutable) { p->writeDupFileDescriptor(androidBitmap->getAshmemFd()); } else { Ashmem dstAshmem(bitmap.getSize(), !isMutable); if (!dstAshmem.getPtr()) { doThrowRE(env, "Could not allocate ashmem for new bitmap."); // Transfer the underlying ashmem region if we have one and it's immutable. android::status_t status; int fd = androidBitmap->getAshmemFd(); if (fd >= 0 && !isMutable && p->allowFds()) { #if DEBUG_PARCEL ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as " "immutable blob (fds %s)", p->allowFds() ? "allowed" : "forbidden"); #endif status = p->writeDupImmutableBlobFileDescriptor(fd); if (status) { doThrowRE(env, "Could not write bitmap blob file descriptor."); return JNI_FALSE; } return JNI_TRUE; } // Copy the bitmap to a new blob. bool mutableCopy = isMutable; #if DEBUG_PARCEL ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)", isMutable ? "mutable" : "immutable", mutableCopy ? "mutable" : "immutable", p->allowFds() ? "allowed" : "forbidden"); #endif size_t size = bitmap.getSize(); android::Parcel::WritableBlob blob; status = p->writeBlob(size, mutableCopy, &blob); if (status) { doThrowRE(env, "Could not copy bitmap to parcel blob."); return JNI_FALSE; } bitmap.lockPixels(); const void* pSrc = bitmap.getPixels(); if (pSrc == NULL) { memset(dstAshmem.getPtr(), 0, bitmap.getSize()); memset(blob.data(), 0, size); } else { memcpy(dstAshmem.getPtr(), pSrc, bitmap.getSize()); memcpy(blob.data(), pSrc, size); } bitmap.unlockPixels(); p->writeDupFileDescriptor(dstAshmem.getFd()); } blob.release(); return JNI_TRUE; } Loading core/jni/android/graphics/Graphics.cpp +11 −8 Original line number Diff line number Diff line Loading @@ -623,21 +623,21 @@ android::Bitmap* GraphicsJNI::allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitm } android::Bitmap* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable, int fd, bool readOnly) { int flags; SkColorTable* ctable, int fd, void* addr, bool readOnly) { 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 existing ashmem region if not already mapped. int flags = readOnly ? (PROT_READ) : (PROT_READ | PROT_WRITE); 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. Loading @@ -645,6 +645,9 @@ android::Bitmap* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, android::Bitmap* wrapper = new android::Bitmap(addr, fd, info, rowBytes, ctable); wrapper->getSkBitmap(bitmap); if (readOnly) { bitmap->pixelRef()->setImmutable(); } // since we're already allocated, we lockPixels right away // HeapAllocator behaves this way too bitmap->lockPixels(); Loading core/jni/android/graphics/GraphicsJNI.h +1 −1 Original line number Diff line number Diff line Loading @@ -99,7 +99,7 @@ public: SkColorTable* ctable); static android::Bitmap* mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable, int fd, bool readOnly); SkColorTable* ctable, int fd, void* addr, bool readOnly); /** * Given a bitmap we natively allocate a memory block to store the contents Loading core/jni/android_os_Parcel.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -211,7 +211,7 @@ static void android_os_Parcel_writeBlob(JNIEnv* env, jclass clazz, jlong nativeP } android::Parcel::WritableBlob blob; android::status_t err2 = parcel->writeBlob(length, &blob); android::status_t err2 = parcel->writeBlob(length, false, &blob); if (err2 != NO_ERROR) { signalExceptionForError(env, clazz, err2); return; Loading Loading
core/jni/android/graphics/Bitmap.cpp +110 −76 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ #include <sys/mman.h> #include <cutils/ashmem.h> #define DEBUG_PARCEL 0 namespace android { class WrappedPixelRef : public SkPixelRef { Loading Loading @@ -959,75 +961,82 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { } } int fd = p->readFileDescriptor(); int dupFd = dup(fd); // Read the bitmap blob. size_t size = bitmap->getSize(); android::Parcel::ReadableBlob blob; android::status_t status = p->readBlob(size, &blob); if (status) { SkSafeUnref(ctable); doThrowRE(env, "Could not read bitmap blob."); return NULL; } // Map the bitmap in place from the ashmem region if possible otherwise copy. Bitmap* nativeBitmap; if (blob.fd() >= 0 && (blob.isMutable() || !isMutable)) { #if DEBUG_PARCEL ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob " "(fds %s)", isMutable ? "mutable" : "immutable", blob.isMutable() ? "mutable" : "immutable", p->allowFds() ? "allowed" : "forbidden"); #endif // Dup the file descriptor so we can keep a reference to it after the Parcel // is disposed. int dupFd = dup(blob.fd()); if (dupFd < 0) { blob.release(); SkSafeUnref(ctable); doThrowRE(env, "Could not dup parcel fd."); doThrowRE(env, "Could not allocate dup blob fd."); return NULL; } bool readOnlyMapping = !isMutable; Bitmap* nativeBitmap = GraphicsJNI::mapAshmemPixelRef(env, bitmap.get(), ctable, dupFd, readOnlyMapping); // Map the pixels in place and take ownership of the ashmem region. nativeBitmap = GraphicsJNI::mapAshmemPixelRef(env, bitmap.get(), ctable, dupFd, const_cast<void*>(blob.data()), !isMutable); SkSafeUnref(ctable); if (!nativeBitmap) { close(dupFd); blob.release(); doThrowRE(env, "Could not allocate ashmem pixel ref."); return NULL; } bitmap->pixelRef()->setImmutable(); return GraphicsJNI::createBitmap(env, nativeBitmap, getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); // Clear the blob handle, don't release it. blob.clear(); } else { #if DEBUG_PARCEL if (blob.fd() >= 0) { ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap " "from immutable blob (fds %s)", p->allowFds() ? "allowed" : "forbidden"); } else { ALOGD("Bitmap.createFromParcel: copied contents from %s blob " "(fds %s)", blob.isMutable() ? "mutable" : "immutable", p->allowFds() ? "allowed" : "forbidden"); } #endif class Ashmem { public: Ashmem(size_t sz, bool removeWritePerm) : mSize(sz) { int fd = -1; void *addr = nullptr; // Create new ashmem region with read/write priv fd = ashmem_create_region("bitmap", sz); if (fd < 0) { goto error; } addr = mmap(nullptr, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { goto error; } // If requested, remove the ability to make additional writeable to // this memory. if (removeWritePerm) { if (ashmem_set_prot_region(fd, PROT_READ) < 0) { goto error; } } mFd = fd; mPtr = addr; return; error: if (fd >= 0) { close(fd); } if (addr) { munmap(addr, sz); } // Copy the pixels into a new buffer. nativeBitmap = GraphicsJNI::allocateJavaPixelRef(env, bitmap.get(), ctable); SkSafeUnref(ctable); if (!nativeBitmap) { blob.release(); doThrowRE(env, "Could not allocate java pixel ref."); return NULL; } ~Ashmem() { if (mPtr) { close(mFd); munmap(mPtr, mSize); bitmap->lockPixels(); memcpy(bitmap->getPixels(), blob.data(), size); bitmap->unlockPixels(); // Release the blob handle. blob.release(); } return GraphicsJNI::createBitmap(env, nativeBitmap, getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); } void *getPtr() const { return mPtr; } int getFd() const { return mFd; } private: int mFd = -1; int mSize; void* mPtr = nullptr; }; static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, jlong bitmapHandle, Loading Loading @@ -1064,26 +1073,51 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, } } bool ashmemSrc = androidBitmap->getAshmemFd() >= 0; if (ashmemSrc && !isMutable) { p->writeDupFileDescriptor(androidBitmap->getAshmemFd()); } else { Ashmem dstAshmem(bitmap.getSize(), !isMutable); if (!dstAshmem.getPtr()) { doThrowRE(env, "Could not allocate ashmem for new bitmap."); // Transfer the underlying ashmem region if we have one and it's immutable. android::status_t status; int fd = androidBitmap->getAshmemFd(); if (fd >= 0 && !isMutable && p->allowFds()) { #if DEBUG_PARCEL ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as " "immutable blob (fds %s)", p->allowFds() ? "allowed" : "forbidden"); #endif status = p->writeDupImmutableBlobFileDescriptor(fd); if (status) { doThrowRE(env, "Could not write bitmap blob file descriptor."); return JNI_FALSE; } return JNI_TRUE; } // Copy the bitmap to a new blob. bool mutableCopy = isMutable; #if DEBUG_PARCEL ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)", isMutable ? "mutable" : "immutable", mutableCopy ? "mutable" : "immutable", p->allowFds() ? "allowed" : "forbidden"); #endif size_t size = bitmap.getSize(); android::Parcel::WritableBlob blob; status = p->writeBlob(size, mutableCopy, &blob); if (status) { doThrowRE(env, "Could not copy bitmap to parcel blob."); return JNI_FALSE; } bitmap.lockPixels(); const void* pSrc = bitmap.getPixels(); if (pSrc == NULL) { memset(dstAshmem.getPtr(), 0, bitmap.getSize()); memset(blob.data(), 0, size); } else { memcpy(dstAshmem.getPtr(), pSrc, bitmap.getSize()); memcpy(blob.data(), pSrc, size); } bitmap.unlockPixels(); p->writeDupFileDescriptor(dstAshmem.getFd()); } blob.release(); return JNI_TRUE; } Loading
core/jni/android/graphics/Graphics.cpp +11 −8 Original line number Diff line number Diff line Loading @@ -623,21 +623,21 @@ android::Bitmap* GraphicsJNI::allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitm } android::Bitmap* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable, int fd, bool readOnly) { int flags; SkColorTable* ctable, int fd, void* addr, bool readOnly) { 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 existing ashmem region if not already mapped. int flags = readOnly ? (PROT_READ) : (PROT_READ | PROT_WRITE); 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. Loading @@ -645,6 +645,9 @@ android::Bitmap* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, android::Bitmap* wrapper = new android::Bitmap(addr, fd, info, rowBytes, ctable); wrapper->getSkBitmap(bitmap); if (readOnly) { bitmap->pixelRef()->setImmutable(); } // since we're already allocated, we lockPixels right away // HeapAllocator behaves this way too bitmap->lockPixels(); Loading
core/jni/android/graphics/GraphicsJNI.h +1 −1 Original line number Diff line number Diff line Loading @@ -99,7 +99,7 @@ public: SkColorTable* ctable); static android::Bitmap* mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable, int fd, bool readOnly); SkColorTable* ctable, int fd, void* addr, bool readOnly); /** * Given a bitmap we natively allocate a memory block to store the contents Loading
core/jni/android_os_Parcel.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -211,7 +211,7 @@ static void android_os_Parcel_writeBlob(JNIEnv* env, jclass clazz, jlong nativeP } android::Parcel::WritableBlob blob; android::status_t err2 = parcel->writeBlob(length, &blob); android::status_t err2 = parcel->writeBlob(length, false, &blob); if (err2 != NO_ERROR) { signalExceptionForError(env, clazz, err2); return; Loading