Fix a bug, where one thread is using JNIEnv associated with another thread.

We see abort messages like this when using JavaPixelAllocator and JavaMemoryUsageReporter.
W/dalvikvm(  680): JNI WARNING: threadid=2 using env from threadid=10
W/dalvikvm(  680):              in Landroid/graphics/LargeBitmap;.nativeClean (I)V (CallVoidMethodV)

To fix it, we keep JavaVM, rather than JNIEnv, in JavaPixelAllocator and JavaMemoryUsageReporter,
because JavaVM allows us to get the JNIEnv corresponds to the current thread.

Change-Id: Ibd4b394a53dd3fdccc5a442eeb0dedf836479575
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 204bb74..578de6f 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -518,35 +518,48 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env, bool reportSizeToVM)
-    : fEnv(env), fReportSizeToVM(reportSizeToVM) {}
+    : fReportSizeToVM(reportSizeToVM) {
+    if (env->GetJavaVM(&fVM) != JNI_OK) {
+        SkDebugf("------ [%p] env->GetJavaVM failed\n", env);
+        sk_throw();
+    }
+}
     
 bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
-    return GraphicsJNI::setJavaPixelRef(fEnv, bitmap, ctable, fReportSizeToVM);
+    JNIEnv* env = vm2env(fVM);
+    return GraphicsJNI::setJavaPixelRef(env, bitmap, ctable, fReportSizeToVM);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 JavaMemoryUsageReporter::JavaMemoryUsageReporter(JNIEnv* env)
-    : fEnv(env), fTotalSize(0) {}
+    : fTotalSize(0) {
+    if (env->GetJavaVM(&fVM) != JNI_OK) {
+        SkDebugf("------ [%p] env->GetJavaVM failed\n", env);
+        sk_throw();
+    }
+}
 
 JavaMemoryUsageReporter::~JavaMemoryUsageReporter() {
+    JNIEnv* env = vm2env(fVM);
     jlong jtotalSize = fTotalSize;
-    fEnv->CallVoidMethod(gVMRuntime_singleton,
+    env->CallVoidMethod(gVMRuntime_singleton,
             gVMRuntime_trackExternalFreeMethodID,
             jtotalSize);
 }
 
 bool JavaMemoryUsageReporter::reportMemory(size_t memorySize) {
     jlong jsize = memorySize;  // the VM wants longs for the size
-    bool r = fEnv->CallBooleanMethod(gVMRuntime_singleton,
+    JNIEnv* env = vm2env(fVM);
+    bool r = env->CallBooleanMethod(gVMRuntime_singleton,
             gVMRuntime_trackExternalAllocationMethodID,
             jsize);
-    if (GraphicsJNI::hasException(fEnv)) {
+    if (GraphicsJNI::hasException(env)) {
         return false;
     }
     if (!r) {
         LOGE("VM won't let us allocate %zd bytes\n", memorySize);
-        doThrowOOME(fEnv, "bitmap size exceeds VM budget");
+        doThrowOOME(env, "bitmap size exceeds VM budget");
         return false;
     }
     fTotalSize += memorySize;
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 8d6528b..1a43a3e 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -80,7 +80,7 @@
     virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable);
     
 private:
-    JNIEnv* fEnv;
+    JavaVM* fVM;
     bool fReportSizeToVM;
 };
 
@@ -92,7 +92,7 @@
     virtual bool reportMemory(size_t memorySize);
 
 private:
-    JNIEnv* fEnv;
+    JavaVM* fVM;
     size_t fTotalSize;
 };