Fix media server restart detection mechanism

There is a flaw in the mechanism used by AudioService
to detect the fact that mediaserver process did crash and restart.
It relies on polling AudioFlinger service until a successful
connection triggers a callback into AudioSystem JNI and then into AudioService.
But if another thread in system_server process, not attached to the
JNI environment, reconnects before AudioService, the callback is called in
a detached context and dropped.

The fix consists in attaching the thread executing the callback
and detaching it if needed.

Bug: 9693068.
Change-Id: I184308b12a3f87653bf818abf0159e0e45a66ef0
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 67c2cfd..45561d3 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -117,10 +117,36 @@
     return env->NewStringUTF(AudioSystem::getParameters(0, c_keys8).string());
 }
 
+static JNIEnv* AudioSystem_getJNIEnv(bool* needsDetach) {
+    *needsDetach = false;
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (env == NULL) {
+        JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
+        JavaVM* vm = AndroidRuntime::getJavaVM();
+        int result = vm->AttachCurrentThread(&env, (void*) &args);
+        if (result != JNI_OK) {
+            ALOGE("thread attach failed: %#x", result);
+            return NULL;
+        }
+        *needsDetach = true;
+    }
+    return env;
+}
+
+static void AudioSystem_detachJNI() {
+    JavaVM* vm = AndroidRuntime::getJavaVM();
+    int result = vm->DetachCurrentThread();
+    if (result != JNI_OK) {
+        ALOGE("thread detach failed: %#x", result);
+    }
+}
+
 static void
 android_media_AudioSystem_error_callback(status_t err)
 {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    bool needsDetach = false;
+    JNIEnv *env = AudioSystem_getJNIEnv(&needsDetach);
+
     if (env == NULL) {
         return;
     }
@@ -142,6 +168,10 @@
     }
 
     env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz, "errorCallbackFromNative","(I)V"), error);
+
+    if (needsDetach) {
+        AudioSystem_detachJNI();
+    }
 }
 
 static int