Ensure all fields of AutoBufferPointer are initialized

In the process of revising libnativehelper interface, the
initialization of the fArray field was dropped. This change fixes
this and adds regression tests.

In writing the tests, it became apparent that the AutoBufferPointer
destructor would crash if the underlying buffer was heap array backed
and the buffer position was non-zero. ReleasePrimitiveArrayCritical
was called with the element corresponding to the current position
rather than the first element.

Bug: b/130390512
Test: atest FrameworksCoreTests:android.graphics.BitmapTest
Change-Id: I319512aaede7ba8af5d013c9281417695abf9099
diff --git a/core/jni/android_nio_utils.cpp b/core/jni/android_nio_utils.cpp
index 19a1c72..a62dd7c 100644
--- a/core/jni/android_nio_utils.cpp
+++ b/core/jni/android_nio_utils.cpp
@@ -18,42 +18,51 @@
 
 #include "core_jni_helpers.h"
 
-void* android::nio_getPointer(JNIEnv *_env, jobject buffer, jarray *array) {
-    assert(array);
+namespace {
 
+void* getPointer(JNIEnv *_env, jobject buffer, jarray *array, void** elements) {
+    assert(array);
     jint position;
     jint limit;
     jint elementSizeShift;
     jlong pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift);
     if (pointer != 0L) {
+        *array = nullptr;
+        *elements = nullptr;
         pointer += position << elementSizeShift;
         return reinterpret_cast<void*>(pointer);
     }
-
     jint offset = jniGetNioBufferBaseArrayOffset(_env, buffer);
     *array = jniGetNioBufferBaseArray(_env, buffer);
-    void * data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-    return reinterpret_cast<void*>(reinterpret_cast<char*>(data) + offset);
+    *elements = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
+    return reinterpret_cast<void*>(reinterpret_cast<char*>(*elements) + offset);
 }
 
+void releasePointer(JNIEnv *_env, jarray array, void *elements, jboolean commit) {
+    _env->ReleasePrimitiveArrayCritical(array, elements, commit ? 0 : JNI_ABORT);
+}
 
-void android::nio_releasePointer(JNIEnv *_env, jarray array, void *data,
-                                jboolean commit) {
-    _env->ReleasePrimitiveArrayCritical(array, data,
-                                        commit ? 0 : JNI_ABORT);
+}  // namespace
+
+void* android::nio_getPointer(JNIEnv *_env, jobject buffer, jarray *array) {
+    void* elements;
+    return getPointer(_env, buffer, array, &elements);
+}
+
+void android::nio_releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) {
+    releasePointer(_env, array, data, commit);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
-android::AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer,
-                                              jboolean commit) {
+android::AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit) {
     fEnv = env;
     fCommit = commit;
-    fPointer = android::nio_getPointer(env, nioBuffer, &fArray);
+    fPointer = getPointer(env, nioBuffer, &fArray, &fElements);
 }
 
 android::AutoBufferPointer::~AutoBufferPointer() {
-    if (NULL != fArray) {
-        android::nio_releasePointer(fEnv, fArray, fPointer, fCommit);
+    if (nullptr != fArray) {
+        releasePointer(fEnv, fArray, fElements, fCommit);
     }
 }