Add locking around AudioRecord release() function in JNI. Bug 2481952.

There is a potential threading issue where an app could call release()
on two threads. This hack adds a static lock object that serializes
access to the Java fields that contain the pointer to the native
AudioRecord object and weak reference to the Java object. Also
modifies finalize() to call release() so that both use the locking
scheme.

Change-Id: I09dcb19b7f501dc582e40e8718142b493eba2518
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index d7485ae..17f5daf 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -55,6 +55,8 @@
     jobject     audioRecord_ref;
  };
 
+Mutex sLock;
+
 // ----------------------------------------------------------------------------
 
 #define AUDIORECORD_SUCCESS                         0
@@ -255,12 +257,21 @@
 
 
 // ----------------------------------------------------------------------------
-static void android_media_AudioRecord_finalize(JNIEnv *env,  jobject thiz) {
-    
-    // delete the AudioRecord object
+static void android_media_AudioRecord_release(JNIEnv *env,  jobject thiz) {
+
+    // serialize access. Ugly, but functional.
+    Mutex::Autolock lock(&sLock);
     AudioRecord *lpRecorder = 
             (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+    audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetIntField(
+        thiz, javaAudioRecordFields.nativeCallbackCookie);
 
+    // reset the native resources in the Java object so any attempt to access
+    // them after a call to release fails.
+    env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, 0);
+    env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
+
+    // delete the AudioRecord object
     if (lpRecorder) {
         LOGV("About to delete lpRecorder: %x\n", (int)lpRecorder);
         lpRecorder->stop();
@@ -268,27 +279,18 @@
     }
     
     // delete the callback information
-    audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetIntField(
-        thiz, javaAudioRecordFields.nativeCallbackCookie);
     if (lpCookie) {
         LOGV("deleting lpCookie: %x\n", (int)lpCookie);
         env->DeleteGlobalRef(lpCookie->audioRecord_class);
         env->DeleteGlobalRef(lpCookie->audioRecord_ref);
         delete lpCookie;
     }
-
 }
 
 
 // ----------------------------------------------------------------------------
-static void android_media_AudioRecord_release(JNIEnv *env,  jobject thiz) {
-       
-    // do everything a call to finalize would
-    android_media_AudioRecord_finalize(env, thiz);
-    // + reset the native resources in the Java object so any attempt to access
-    // them after a call to release fails.
-    env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, 0);
-    env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
+static void android_media_AudioRecord_finalize(JNIEnv *env,  jobject thiz) {
+    android_media_AudioRecord_release(env, thiz);
 }