Change NewDirectByteBuffer to allow NULL if capacity == 0.

Also make the diagnostics more uniform.

Bug: 7892060
Change-Id: Ib3ca0d6241a5958d2c8681337b1883fc3d74cb54
diff --git a/vm/CheckJni.cpp b/vm/CheckJni.cpp
index ccb5836..8886ea2 100644
--- a/vm/CheckJni.cpp
+++ b/vm/CheckJni.cpp
@@ -1985,12 +1985,6 @@
 
 static jobject Check_NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
     CHECK_JNI_ENTRY(kFlag_Default, "EpJ", env, address, capacity);
-    if (address == NULL || capacity < 0) {
-        ALOGW("JNI WARNING: invalid values for address (%p) or capacity (%ld)",
-            address, (long) capacity);
-        abortMaybe();
-        return NULL;
-    }
     return CHECK_JNI_EXIT("L", baseEnv(env)->NewDirectByteBuffer(env, address, capacity));
 }
 
diff --git a/vm/Jni.cpp b/vm/Jni.cpp
index 6decaed..29badb7 100644
--- a/vm/Jni.cpp
+++ b/vm/Jni.cpp
@@ -134,6 +134,11 @@
 
 */
 
+static void ReportJniError() {
+    dvmDumpThread(dvmThreadSelf(), false);
+    dvmAbort();
+}
+
 #ifdef WITH_JNI_STACK_CHECK
 # define COMPUTE_STACK_SUM(_self)   computeStackSum(_self);
 # define CHECK_STACK_SUM(_self)     checkStackSum(_self);
@@ -177,7 +182,7 @@
             ALOGD("JNI: bad stack CRC (0x%08x) -- okay during JNI_OnLoad", stackCrc);
         } else {
             ALOGW("JNI: bad stack CRC (%08x vs %08x)", crc, stackCrc);
-            dvmAbort();
+            ReportJniError();
         }
     }
     self->stackCrc = (u4) -1;       /* make logic errors more noticeable */
@@ -318,7 +323,7 @@
             Object* result = self->jniLocalRefTable.get(jobj);
             if (UNLIKELY(result == NULL)) {
                 ALOGE("JNI ERROR (app bug): use of deleted local reference (%p)", jobj);
-                dvmAbort();
+                ReportJniError();
             }
             return result;
         }
@@ -330,7 +335,7 @@
             Object* result = pRefTable->get(jobj);
             if (UNLIKELY(result == NULL)) {
                 ALOGE("JNI ERROR (app bug): use of deleted global reference (%p)", jobj);
-                dvmAbort();
+                ReportJniError();
             }
             return result;
         }
@@ -344,7 +349,7 @@
                 result = NULL;
             } else if (UNLIKELY(result == NULL)) {
                 ALOGE("JNI ERROR (app bug): use of deleted weak global reference (%p)", jobj);
-                dvmAbort();
+                ReportJniError();
             }
             return result;
         }
@@ -355,7 +360,7 @@
             return reinterpret_cast<Object*>(jobj);
         }
         ALOGW("Invalid indirect reference %p in decodeIndirectRef", jobj);
-        dvmAbort();
+        ReportJniError();
         return kInvalidIndirectRefObject;
     }
 }
@@ -363,8 +368,7 @@
 static void AddLocalReferenceFailure(IndirectRefTable* pRefTable) {
     pRefTable->dump("JNI local");
     ALOGE("Failed adding to JNI local ref table (has %zd entries)", pRefTable->capacity());
-    dvmDumpThread(dvmThreadSelf(), false);
-    dvmAbort();     // spec says call FatalError; this is equivalent
+    ReportJniError(); // spec says call FatalError; this is equivalent
 }
 
 /*
@@ -388,6 +392,7 @@
     if (UNLIKELY(jobj == NULL)) {
         AddLocalReferenceFailure(pRefTable);
     }
+
     if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
         // Hand out direct pointers to support broken old apps.
         return reinterpret_cast<jobject>(obj);
@@ -486,7 +491,7 @@
         gDvm.jniGlobalRefTable.dump("JNI global");
         ALOGE("Failed adding to JNI global ref table (%zd entries)",
                 gDvm.jniGlobalRefTable.capacity());
-        dvmAbort();
+        ReportJniError();
     }
 
     LOGVV("GREF add %p  (%s.%s)", obj,
@@ -509,7 +514,7 @@
                 } else {
                     gDvm.jniGlobalRefTable.dump("JNI global");
                     ALOGE("Excessive JNI global references (%d)", count);
-                    dvmAbort();
+                    ReportJniError();
                 }
             }
         }
@@ -528,7 +533,7 @@
     if (jobj == NULL) {
         gDvm.jniWeakGlobalRefTable.dump("JNI weak global");
         ALOGE("Failed adding to JNI weak global ref table (%zd entries)", table->capacity());
-        dvmAbort();
+        ReportJniError();
     }
     return jobj;
 }
@@ -591,8 +596,7 @@
         dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
         ALOGE("Failed adding to JNI pinned array ref table (%d entries)",
            (int) dvmReferenceTableEntries(&gDvm.jniPinRefTable));
-        dvmDumpThread(dvmThreadSelf(), false);
-        dvmAbort();
+        ReportJniError();
     }
 
     /*
@@ -958,14 +962,14 @@
 
         if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) {
             ALOGE("Unable to initialize monitor tracking table");
-            dvmAbort();
+            ReportJniError();
         }
     }
 
     if (!dvmAddToReferenceTable(refTable, obj)) {
         /* ran out of memory? could throw exception instead */
         ALOGE("Unable to add entry to monitor tracking table");
-        dvmAbort();
+        ReportJniError();
     } else {
         LOGVV("--- added monitor %p", obj);
     }
@@ -1402,7 +1406,7 @@
 static void FatalError(JNIEnv* env, const char* msg) {
     //dvmChangeStatus(NULL, THREAD_RUNNING);
     ALOGE("JNI posting fatal error: %s", msg);
-    dvmAbort();
+    ReportJniError();
 }
 
 /*
@@ -2683,13 +2687,19 @@
 
 /*
  * Allocate and return a new java.nio.ByteBuffer for this block of memory.
- *
- * "address" may not be NULL, and "capacity" must be > 0.  (These are only
- * verified when CheckJNI is enabled.)
  */
 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
     ScopedJniThreadState ts(env);
 
+    if (capacity < 0) {
+        ALOGE("JNI ERROR (app bug): negative buffer capacity: %lld", capacity);
+        ReportJniError();
+    }
+    if (address == NULL && capacity != 0) {
+        ALOGE("JNI ERROR (app bug): non-zero capacity for NULL pointer: %lld", capacity);
+        ReportJniError();
+    }
+
     /* create an instance of java.nio.ReadWriteDirectByteBuffer */
     ClassObject* bufferClazz = gDvm.classJavaNioReadWriteDirectByteBuffer;
     if (!dvmIsClassInitialized(bufferClazz) && !dvmInitClass(bufferClazz)) {