Merge "AndroidRuntime: Expose javaAttachThread / javaDetachThread."
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index b236385..aae727d 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -297,6 +297,7 @@
             header_libs: [
                 "bionic_libc_platform_headers",
                 "dnsproxyd_protocol_headers",
+                "libandroid_runtime_threads_headers",
             ],
         },
         host: {
@@ -338,3 +339,18 @@
         never: true,
     },
 }
+
+cc_library_headers {
+    name: "libandroid_runtime_threads_headers",
+    host_supported: true,
+    vendor_available: true,
+    // TODO(b/153609531): remove when libbinder is not native_bridge_supported
+    native_bridge_supported: true,
+    // Allow only modules from the following list to create threads that can be
+    // attached to the JVM. This list should be a subset of the dependencies of
+    // libandroid_runtime.
+    visibility: [
+        "//frameworks/native/libs/binder",
+    ],
+    export_include_dirs: ["include_threads"],
+}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f4a10ef..79038b0 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -22,6 +22,7 @@
 #include <android-base/properties.h>
 #include <android/graphics/jni_runtime.h>
 #include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/threads.h>
 #include <assert.h>
 #include <binder/IBinder.h>
 #include <binder/IPCThreadState.h>
@@ -1338,14 +1339,15 @@
     return env;
 }
 
+extern "C" {
+
 /*
  * Makes the current thread visible to the VM.
  *
  * The JNIEnv pointer returned is only valid for the current thread, and
  * thus must be tucked into thread-local storage.
  */
-static int javaAttachThread(const char* threadName, JNIEnv** pEnv)
-{
+bool androidJavaAttachThread(const char* threadName) {
     JavaVMAttachArgs args;
     JavaVM* vm;
     jint result;
@@ -1357,18 +1359,17 @@
     args.name = (char*) threadName;
     args.group = NULL;
 
-    result = vm->AttachCurrentThread(pEnv, (void*) &args);
-    if (result != JNI_OK)
-        ALOGI("NOTE: attach of thread '%s' failed\n", threadName);
+    JNIEnv* env;
+    result = vm->AttachCurrentThread(&env, (void*)&args);
+    if (result != JNI_OK) ALOGI("NOTE: attach of thread '%s' failed\n", threadName);
 
-    return result;
+    return result == JNI_OK;
 }
 
 /*
  * Detach the current thread from the set visible to the VM.
  */
-static int javaDetachThread(void)
-{
+bool androidJavaDetachThread(void) {
     JavaVM* vm;
     jint result;
 
@@ -1376,11 +1377,12 @@
     assert(vm != NULL);
 
     result = vm->DetachCurrentThread();
-    if (result != JNI_OK)
-        ALOGE("ERROR: thread detach failed\n");
-    return result;
+    if (result != JNI_OK) ALOGE("ERROR: thread detach failed\n");
+    return result == JNI_OK;
 }
 
+} // extern "C"
+
 /*
  * When starting a native thread that will be visible from the VM, we
  * bounce through this to get the right attach/detach action.
@@ -1391,18 +1393,16 @@
     void* userData = ((void **)args)[1];
     char* name = (char*) ((void **)args)[2];        // we own this storage
     free(args);
-    JNIEnv* env;
     int result;
 
     /* hook us into the VM */
-    if (javaAttachThread(name, &env) != JNI_OK)
-        return -1;
+    if (!androidJavaAttachThread(name)) return -1;
 
     /* start the thread running */
     result = (*(android_thread_func_t)start)(userData);
 
     /* unhook us */
-    javaDetachThread();
+    (void)androidJavaDetachThread();
     free(name);
 
     return result;
diff --git a/core/jni/include_threads/android_runtime/threads.h b/core/jni/include_threads/android_runtime/threads.h
new file mode 100644
index 0000000..a410529
--- /dev/null
+++ b/core/jni/include_threads/android_runtime/threads.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Manages the interaction between threads and the Android Runtime. If these symbols do not exist
+// at runtime, it means the current process does not link to libandroid_runtime.
+
+#pragma once
+
+extern "C" {
+
+// Attach current thread to JVM. Return true if successful, false otherwise.
+bool androidJavaAttachThread(const char* threadName);
+
+// Detach current thread to JVM. Return true if successful, false otherwise.
+bool androidJavaDetachThread();
+
+} // extern "C"