Allow native methods to declare they don't need a JNIEnv*.

Bug: 3069458
Change-Id: Ic9a6c562c5abf9607dd4c8a71b0d1e389e6d340b
diff --git a/vm/Jni.cpp b/vm/Jni.cpp
index 7abe26e..7da1310 100644
--- a/vm/Jni.cpp
+++ b/vm/Jni.cpp
@@ -716,6 +716,15 @@
         return false;
     }
 
+    // If a signature starts with a '!', we take that as a sign that the native code doesn't
+    // need a JNIEnv* passed in.
+    bool needsJniEnv = true;
+    if (*signature == '!') {
+        needsJniEnv = false;
+        ++signature;
+        LOGV("fast JNI method %s.%s:%s detected", clazz->descriptor, methodName, signature);
+    }
+
     Method* method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
     if (method == NULL) {
         method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
@@ -730,11 +739,26 @@
         return false;
     }
 
+    if (!needsJniEnv) {
+        // In this case, we have extra constraints to check...
+        if (dvmIsSynchronizedMethod(method)) {
+            LOGE("fast JNI method %s.%s:%s cannot be synchronized",
+                    clazz->descriptor, methodName, signature);
+            return false;
+        }
+        if (!dvmIsStaticMethod(method)) {
+            LOGE("fast JNI method %s.%s:%s cannot be non-static",
+                    clazz->descriptor, methodName, signature);
+            return false;
+        }
+    }
+
     if (method->nativeFunc != dvmResolveNativeMethod) {
         /* this is allowed, but unusual */
         LOGV("Note: %s.%s:%s was already registered", clazz->descriptor, methodName, signature);
     }
 
+    method->needsJniEnv = needsJniEnv;
     dvmUseJNIBridge(method, fnPtr);
 
     LOGV("JNI-registered %s.%s:%s", clazz->descriptor, methodName, signature);
@@ -1059,9 +1083,10 @@
     assert(method->insns != NULL);
 
     COMPUTE_STACK_SUM(self);
-    dvmPlatformInvoke(env, (ClassObject*)staticMethodClass,
-        method->jniArgInfo, method->insSize, modArgs, method->shorty,
-        (void*)method->insns, pResult);
+    dvmPlatformInvoke(method->needsJniEnv ? env : NULL,
+            (ClassObject*)staticMethodClass,
+            method->jniArgInfo, method->insSize, modArgs, method->shorty,
+            (void*)method->insns, pResult);
     CHECK_STACK_SUM(self);
 
     dvmChangeStatus(self, oldStatus);
@@ -1117,9 +1142,9 @@
     ANDROID_MEMBAR_FULL();      /* guarantee ordering on method->insns */
 
     COMPUTE_STACK_SUM(self);
-    dvmPlatformInvoke(self->jniEnv, NULL,
-        method->jniArgInfo, method->insSize, modArgs, method->shorty,
-        (void*)method->insns, pResult);
+    dvmPlatformInvoke(method->needsJniEnv ? self->jniEnv : NULL, NULL,
+            method->jniArgInfo, method->insSize, modArgs, method->shorty,
+            (void*)method->insns, pResult);
     CHECK_STACK_SUM(self);
 
     dvmChangeStatus(self, oldStatus);
@@ -1146,9 +1171,10 @@
     ANDROID_MEMBAR_FULL();      /* guarantee ordering on method->insns */
 
     COMPUTE_STACK_SUM(self);
-    dvmPlatformInvoke(self->jniEnv, (ClassObject*)staticMethodClass,
-        method->jniArgInfo, method->insSize, args, method->shorty,
-        (void*)method->insns, pResult);
+    dvmPlatformInvoke(method->needsJniEnv ? self->jniEnv : NULL,
+            (ClassObject*)staticMethodClass,
+            method->jniArgInfo, method->insSize, args, method->shorty,
+            (void*)method->insns, pResult);
     CHECK_STACK_SUM(self);
 
     dvmChangeStatus(self, oldStatus);
diff --git a/vm/oo/Object.h b/vm/oo/Object.h
index 5858e86..d3c3f0a 100644
--- a/vm/oo/Object.h
+++ b/vm/oo/Object.h
@@ -533,6 +533,9 @@
      */
     DalvikBridgeFunc nativeFunc;
 
+    /* Whether this native method needs a JNIEnv*. */
+    bool needsJniEnv;
+
     /*
      * Register map data, if available.  This will point into the DEX file
      * if the data was computed during pre-verification, or into the