Loading core/jni/android/graphics/Bitmap.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -224,7 +224,7 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, SkBitmap bitmap; bitmap.setConfig(config, width, height); if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL)) { if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL, true)) { return NULL; } Loading @@ -240,7 +240,7 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src, SkBitmap::Config dstConfig, jboolean isMutable) { SkBitmap result; JavaPixelAllocator allocator(env); JavaPixelAllocator allocator(env, true); if (!src->copyTo(&result, dstConfig, &allocator)) { return NULL; Loading Loading @@ -356,7 +356,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { } } if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable)) { if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable, true)) { ctable->safeUnref(); delete bitmap; return NULL; Loading core/jni/android/graphics/BitmapFactory.cpp +9 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ static jfieldID gOptions_configFieldID; static jfieldID gOptions_ditherFieldID; static jfieldID gOptions_purgeableFieldID; static jfieldID gOptions_shareableFieldID; static jfieldID gOptions_nativeAllocFieldID; static jfieldID gOptions_widthFieldID; static jfieldID gOptions_heightFieldID; static jfieldID gOptions_mimeFieldID; Loading Loading @@ -300,6 +301,11 @@ static bool optionsShareable(JNIEnv* env, jobject options) { env->GetBooleanField(options, gOptions_shareableFieldID); } static bool optionsReportSizeToVM(JNIEnv* env, jobject options) { return NULL == options || !env->GetBooleanField(options, gOptions_nativeAllocFieldID); } static jobject nullObjectReturn(const char msg[]) { if (msg) { SkDebugf("--- %s\n", msg); Loading Loading @@ -330,6 +336,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, SkBitmap::Config prefConfig = SkBitmap::kNo_Config; bool doDither = true; bool isPurgeable = allowPurgeable && optionsPurgeable(env, options); bool reportSizeToVM = optionsReportSizeToVM(env, options); if (NULL != options) { sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID); Loading @@ -355,7 +362,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, decoder->setDitherImage(doDither); NinePatchPeeker peeker; JavaPixelAllocator javaAllocator(env); JavaPixelAllocator javaAllocator(env, reportSizeToVM); SkBitmap* bitmap = new SkBitmap; Res_png_9patch dummy9Patch; Loading Loading @@ -699,6 +706,7 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) { gOptions_ditherFieldID = getFieldIDCheck(env, gOptions_class, "inDither", "Z"); gOptions_purgeableFieldID = getFieldIDCheck(env, gOptions_class, "inPurgeable", "Z"); gOptions_shareableFieldID = getFieldIDCheck(env, gOptions_class, "inInputShareable", "Z"); gOptions_nativeAllocFieldID = getFieldIDCheck(env, gOptions_class, "inNativeAlloc", "Z"); gOptions_widthFieldID = getFieldIDCheck(env, gOptions_class, "outWidth", "I"); gOptions_heightFieldID = getFieldIDCheck(env, gOptions_class, "outHeight", "I"); gOptions_mimeFieldID = getFieldIDCheck(env, gOptions_class, "outMimeType", "Ljava/lang/String;"); Loading core/jni/android/graphics/Graphics.cpp +31 −25 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ #include "SkRegion.h" #include <android_runtime/AndroidRuntime.h> //#define REPORT_SIZE_TO_JVM //#define TRACK_LOCK_COUNT void doThrow(JNIEnv* env, const char* exc, const char* msg) { Loading Loading @@ -444,7 +445,7 @@ private: }; bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable) { SkColorTable* ctable, bool reportSizeToVM) { Sk64 size64 = bitmap->getSize64(); if (size64.isNeg() || !size64.is32()) { doThrow(env, "java/lang/IllegalArgumentException", Loading @@ -453,8 +454,9 @@ bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap, } size_t size = size64.get32(); // SkDebugf("-------------- inform VM we've allocated %d bytes\n", size); jlong jsize = size; // the VM wants longs for the size if (reportSizeToVM) { // SkDebugf("-------------- inform VM we've allocated %d bytes\n", size); bool r = env->CallBooleanMethod(gVMRuntime_singleton, gVMRuntime_trackExternalAllocationMethodID, jsize); Loading @@ -466,10 +468,11 @@ bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap, doThrowOOME(env, "bitmap size exceeds VM budget"); return false; } } // call the version of malloc that returns null on failure void* addr = sk_malloc_flags(size, 0); if (NULL == addr) { if (reportSizeToVM) { // SkDebugf("-------------- inform VM we're releasing %d bytes which we couldn't allocate\n", size); // we didn't actually allocate it, so inform the VM env->CallVoidMethod(gVMRuntime_singleton, Loading @@ -478,10 +481,14 @@ bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap, if (!GraphicsJNI::hasException(env)) { doThrowOOME(env, "bitmap size too large for malloc"); } } return false; } bitmap->setPixelRef(new AndroidPixelRef(env, addr, size, ctable))->unref(); SkPixelRef* pr = reportSizeToVM ? new AndroidPixelRef(env, addr, size, ctable) : new SkMallocPixelRef(addr, size, ctable); bitmap->setPixelRef(pr)->unref(); // since we're already allocated, we lockPixels right away // HeapAllocator behaves this way too bitmap->lockPixels(); Loading @@ -490,12 +497,11 @@ bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap, /////////////////////////////////////////////////////////////////////////////// JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env) : fEnv(env) { } JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env, bool reportSizeToVM) : fEnv(env), fReportSizeToVM(reportSizeToVM) {} bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { return GraphicsJNI::setJavaPixelRef(fEnv, bitmap, ctable); return GraphicsJNI::setJavaPixelRef(fEnv, bitmap, ctable, fReportSizeToVM); } //////////////////////////////////////////////////////////////////////////////// Loading core/jni/android/graphics/GraphicsJNI.h +4 −2 Original line number Diff line number Diff line Loading @@ -59,7 +59,8 @@ public: Returns true on success. If it returns false, then it failed, and the appropriate exception will have been raised. */ static bool setJavaPixelRef(JNIEnv*, SkBitmap*, SkColorTable* ctable); static bool setJavaPixelRef(JNIEnv*, SkBitmap*, SkColorTable* ctable, bool reportSizeToVM); /** Copy the colors in colors[] to the bitmap, convert to the correct format along the way. Loading @@ -71,12 +72,13 @@ public: class JavaPixelAllocator : public SkBitmap::Allocator { public: JavaPixelAllocator(JNIEnv* env); JavaPixelAllocator(JNIEnv* env, bool reportSizeToVM); // overrides virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable); private: JNIEnv* fEnv; bool fReportSizeToVM; }; class AutoJavaFloatArray { Loading graphics/java/android/graphics/BitmapFactory.java +13 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,19 @@ public class BitmapFactory { */ public boolean inInputShareable; /** * Normally bitmap allocations count against the dalvik heap, which * means they help trigger GCs when a lot have been allocated. However, * in rare cases, the caller may want to allocate the bitmap outside of * that heap. To request that, set inNativeAlloc to true. In these * rare instances, it is solely up to the caller to ensure that OOM is * managed explicitly by calling bitmap.recycle() as soon as such a * bitmap is no longer needed. * * @hide pending API council approval */ public boolean inNativeAlloc; /** * The resulting width of the bitmap, set independent of the state of * inJustDecodeBounds. However, if there is an error trying to decode, Loading Loading
core/jni/android/graphics/Bitmap.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -224,7 +224,7 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, SkBitmap bitmap; bitmap.setConfig(config, width, height); if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL)) { if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL, true)) { return NULL; } Loading @@ -240,7 +240,7 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src, SkBitmap::Config dstConfig, jboolean isMutable) { SkBitmap result; JavaPixelAllocator allocator(env); JavaPixelAllocator allocator(env, true); if (!src->copyTo(&result, dstConfig, &allocator)) { return NULL; Loading Loading @@ -356,7 +356,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { } } if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable)) { if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable, true)) { ctable->safeUnref(); delete bitmap; return NULL; Loading
core/jni/android/graphics/BitmapFactory.cpp +9 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ static jfieldID gOptions_configFieldID; static jfieldID gOptions_ditherFieldID; static jfieldID gOptions_purgeableFieldID; static jfieldID gOptions_shareableFieldID; static jfieldID gOptions_nativeAllocFieldID; static jfieldID gOptions_widthFieldID; static jfieldID gOptions_heightFieldID; static jfieldID gOptions_mimeFieldID; Loading Loading @@ -300,6 +301,11 @@ static bool optionsShareable(JNIEnv* env, jobject options) { env->GetBooleanField(options, gOptions_shareableFieldID); } static bool optionsReportSizeToVM(JNIEnv* env, jobject options) { return NULL == options || !env->GetBooleanField(options, gOptions_nativeAllocFieldID); } static jobject nullObjectReturn(const char msg[]) { if (msg) { SkDebugf("--- %s\n", msg); Loading Loading @@ -330,6 +336,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, SkBitmap::Config prefConfig = SkBitmap::kNo_Config; bool doDither = true; bool isPurgeable = allowPurgeable && optionsPurgeable(env, options); bool reportSizeToVM = optionsReportSizeToVM(env, options); if (NULL != options) { sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID); Loading @@ -355,7 +362,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, decoder->setDitherImage(doDither); NinePatchPeeker peeker; JavaPixelAllocator javaAllocator(env); JavaPixelAllocator javaAllocator(env, reportSizeToVM); SkBitmap* bitmap = new SkBitmap; Res_png_9patch dummy9Patch; Loading Loading @@ -699,6 +706,7 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) { gOptions_ditherFieldID = getFieldIDCheck(env, gOptions_class, "inDither", "Z"); gOptions_purgeableFieldID = getFieldIDCheck(env, gOptions_class, "inPurgeable", "Z"); gOptions_shareableFieldID = getFieldIDCheck(env, gOptions_class, "inInputShareable", "Z"); gOptions_nativeAllocFieldID = getFieldIDCheck(env, gOptions_class, "inNativeAlloc", "Z"); gOptions_widthFieldID = getFieldIDCheck(env, gOptions_class, "outWidth", "I"); gOptions_heightFieldID = getFieldIDCheck(env, gOptions_class, "outHeight", "I"); gOptions_mimeFieldID = getFieldIDCheck(env, gOptions_class, "outMimeType", "Ljava/lang/String;"); Loading
core/jni/android/graphics/Graphics.cpp +31 −25 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ #include "SkRegion.h" #include <android_runtime/AndroidRuntime.h> //#define REPORT_SIZE_TO_JVM //#define TRACK_LOCK_COUNT void doThrow(JNIEnv* env, const char* exc, const char* msg) { Loading Loading @@ -444,7 +445,7 @@ private: }; bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable) { SkColorTable* ctable, bool reportSizeToVM) { Sk64 size64 = bitmap->getSize64(); if (size64.isNeg() || !size64.is32()) { doThrow(env, "java/lang/IllegalArgumentException", Loading @@ -453,8 +454,9 @@ bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap, } size_t size = size64.get32(); // SkDebugf("-------------- inform VM we've allocated %d bytes\n", size); jlong jsize = size; // the VM wants longs for the size if (reportSizeToVM) { // SkDebugf("-------------- inform VM we've allocated %d bytes\n", size); bool r = env->CallBooleanMethod(gVMRuntime_singleton, gVMRuntime_trackExternalAllocationMethodID, jsize); Loading @@ -466,10 +468,11 @@ bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap, doThrowOOME(env, "bitmap size exceeds VM budget"); return false; } } // call the version of malloc that returns null on failure void* addr = sk_malloc_flags(size, 0); if (NULL == addr) { if (reportSizeToVM) { // SkDebugf("-------------- inform VM we're releasing %d bytes which we couldn't allocate\n", size); // we didn't actually allocate it, so inform the VM env->CallVoidMethod(gVMRuntime_singleton, Loading @@ -478,10 +481,14 @@ bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap, if (!GraphicsJNI::hasException(env)) { doThrowOOME(env, "bitmap size too large for malloc"); } } return false; } bitmap->setPixelRef(new AndroidPixelRef(env, addr, size, ctable))->unref(); SkPixelRef* pr = reportSizeToVM ? new AndroidPixelRef(env, addr, size, ctable) : new SkMallocPixelRef(addr, size, ctable); bitmap->setPixelRef(pr)->unref(); // since we're already allocated, we lockPixels right away // HeapAllocator behaves this way too bitmap->lockPixels(); Loading @@ -490,12 +497,11 @@ bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap, /////////////////////////////////////////////////////////////////////////////// JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env) : fEnv(env) { } JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env, bool reportSizeToVM) : fEnv(env), fReportSizeToVM(reportSizeToVM) {} bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { return GraphicsJNI::setJavaPixelRef(fEnv, bitmap, ctable); return GraphicsJNI::setJavaPixelRef(fEnv, bitmap, ctable, fReportSizeToVM); } //////////////////////////////////////////////////////////////////////////////// Loading
core/jni/android/graphics/GraphicsJNI.h +4 −2 Original line number Diff line number Diff line Loading @@ -59,7 +59,8 @@ public: Returns true on success. If it returns false, then it failed, and the appropriate exception will have been raised. */ static bool setJavaPixelRef(JNIEnv*, SkBitmap*, SkColorTable* ctable); static bool setJavaPixelRef(JNIEnv*, SkBitmap*, SkColorTable* ctable, bool reportSizeToVM); /** Copy the colors in colors[] to the bitmap, convert to the correct format along the way. Loading @@ -71,12 +72,13 @@ public: class JavaPixelAllocator : public SkBitmap::Allocator { public: JavaPixelAllocator(JNIEnv* env); JavaPixelAllocator(JNIEnv* env, bool reportSizeToVM); // overrides virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable); private: JNIEnv* fEnv; bool fReportSizeToVM; }; class AutoJavaFloatArray { Loading
graphics/java/android/graphics/BitmapFactory.java +13 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,19 @@ public class BitmapFactory { */ public boolean inInputShareable; /** * Normally bitmap allocations count against the dalvik heap, which * means they help trigger GCs when a lot have been allocated. However, * in rare cases, the caller may want to allocate the bitmap outside of * that heap. To request that, set inNativeAlloc to true. In these * rare instances, it is solely up to the caller to ensure that OOM is * managed explicitly by calling bitmap.recycle() as soon as such a * bitmap is no longer needed. * * @hide pending API council approval */ public boolean inNativeAlloc; /** * The resulting width of the bitmap, set independent of the state of * inJustDecodeBounds. However, if there is an error trying to decode, Loading