add hidden Options field for native allocations
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index af8ecf5..3fb07a7 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -224,7 +224,7 @@
     SkBitmap bitmap;

 

     bitmap.setConfig(config, width, height);

-    if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL)) {

+    if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL, true)) {

         return NULL;

     }

 

@@ -240,7 +240,7 @@
 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;

@@ -356,7 +356,7 @@
         }

     }

 

-    if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable)) {

+    if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable, true)) {

         ctable->safeUnref();

         delete bitmap;

         return NULL;

diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 137707f..0c84265 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -23,6 +23,7 @@
 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;
@@ -300,6 +301,11 @@
             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);
@@ -330,6 +336,7 @@
     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);
@@ -355,7 +362,7 @@
     decoder->setDitherImage(doDither);
 
     NinePatchPeeker     peeker;
-    JavaPixelAllocator  javaAllocator(env);
+    JavaPixelAllocator  javaAllocator(env, reportSizeToVM);
     SkBitmap*           bitmap = new SkBitmap;
     Res_png_9patch      dummy9Patch;
 
@@ -699,6 +706,7 @@
     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;");
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 6eebbdc..6e159a8 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -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) {
@@ -444,7 +445,7 @@
 };
 
 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",
@@ -453,35 +454,41 @@
     }
     
     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
-    bool r = env->CallBooleanMethod(gVMRuntime_singleton,
-                                     gVMRuntime_trackExternalAllocationMethodID,
-                                     jsize);
-    if (GraphicsJNI::hasException(env)) {
-        return false;
+    if (reportSizeToVM) {
+        //    SkDebugf("-------------- inform VM we've allocated %d bytes\n", size);
+        bool r = env->CallBooleanMethod(gVMRuntime_singleton,
+                                    gVMRuntime_trackExternalAllocationMethodID,
+                                    jsize);
+        if (GraphicsJNI::hasException(env)) {
+            return false;
+        }
+        if (!r) {
+            LOGE("VM won't let us allocate %zd bytes\n", size);
+            doThrowOOME(env, "bitmap size exceeds VM budget");
+            return false;
+        }
     }
-    if (!r) {
-        LOGE("VM won't let us allocate %zd bytes\n", size);
-        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) {
-        //        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,
-                             gVMRuntime_trackExternalFreeMethodID,
-                             jsize);
-        if (!GraphicsJNI::hasException(env)) {
-            doThrowOOME(env, "bitmap size too large for malloc");
+        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,
+                                 gVMRuntime_trackExternalFreeMethodID,
+                                 jsize);
+            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();
@@ -490,12 +497,11 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-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);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index e2dc9ac..16925e4 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -59,7 +59,8 @@
         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.
@@ -71,12 +72,13 @@
 
 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 {
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index e5a9aab..082e0c0 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -129,6 +129,19 @@
         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,
          * outWidth will be set to -1.