Use libandroid_runtime lazily

This is a part of cutting dependency from libmediandk to
libandroid_runtime.

By making a libandroid_runtime to be loaded lazily,
libmediandk won't load libandroid_runtime when it is used as a LL-NDK.

Bug: 124268753
Test: m -j
Change-Id: Ib040856c58d38e11a5f32cd5dd5519910573334b
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index 1abee93..0891f2a 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -23,9 +23,7 @@
 #include <jni.h>
 #include <unistd.h>
 
-#include <android_runtime/AndroidRuntime.h>
-#include <android_util_Binder.h>
-#include <binder/IServiceManager.h>
+#include <binder/IBinder.h>
 #include <cutils/properties.h>
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
@@ -41,8 +39,67 @@
 #include "../../libstagefright/include/NuCachedSource2.h"
 #include "NdkMediaDataSourceCallbacksPriv.h"
 
+#include <mutex> // std::call_once,once_flag
+#include <dlfcn.h> // dlopen
+
 using namespace android;
 
+// load libandroid_runtime.so lazily.
+// A vendor process may use libmediandk but should not depend on libandroid_runtime.
+// TODO(jooyung): remove duplicate (b/125550121)
+// frameworks/native/libs/binder/ndk/ibinder_jni.cpp
+namespace {
+
+typedef JNIEnv* (*getJNIEnv_t)();
+typedef sp<IBinder> (*ibinderForJavaObject_t)(JNIEnv* env, jobject obj);
+
+getJNIEnv_t getJNIEnv_;
+ibinderForJavaObject_t ibinderForJavaObject_;
+
+std::once_flag mLoadFlag;
+
+void load() {
+    std::call_once(mLoadFlag, []() {
+        void* handle = dlopen("libandroid_runtime.so", RTLD_LAZY);
+        if (handle == nullptr) {
+            ALOGE("Could not open libandroid_runtime.");
+            return;
+        }
+
+        getJNIEnv_ = reinterpret_cast<getJNIEnv_t>(
+                dlsym(handle, "_ZN7android14AndroidRuntime9getJNIEnvEv"));
+        if (getJNIEnv_ == nullptr) {
+            ALOGE("Could not find AndroidRuntime::getJNIEnv.");
+            // no return
+        }
+
+        ibinderForJavaObject_ = reinterpret_cast<ibinderForJavaObject_t>(
+                dlsym(handle, "_ZN7android20ibinderForJavaObjectEP7_JNIEnvP8_jobject"));
+        if (ibinderForJavaObject_ == nullptr) {
+            ALOGE("Could not find ibinderForJavaObject.");
+            // no return
+        }
+    });
+}
+
+JNIEnv* getJNIEnv() {
+    load();
+    if (getJNIEnv_ == nullptr) {
+        return nullptr;
+    }
+    return (getJNIEnv_)();
+}
+
+sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj) {
+    load();
+    if (ibinderForJavaObject_ == nullptr) {
+        return nullptr;
+    }
+    return (ibinderForJavaObject_)(env, obj);
+}
+
+} // namespace
+
 struct AMediaDataSource {
     void *userdata;
     AMediaDataSourceReadAt readAt;
@@ -124,9 +181,14 @@
     if (obj == NULL) {
         return NULL;
     }
+    sp<IBinder> binder;
     switch (version) {
         case 1:
-            return interface_cast<IMediaHTTPService>(ibinderForJavaObject(env, obj));
+            binder = ibinderForJavaObject(env, obj);
+            if (binder == NULL) {
+                return NULL;
+            }
+            return interface_cast<IMediaHTTPService>(binder);
         case 2:
             return new JMedia2HTTPService(env, obj);
         default:
@@ -179,7 +241,7 @@
 
     switch (version) {
         case 1:
-            env = AndroidRuntime::getJNIEnv();
+            env = getJNIEnv();
             clazz = "android/media/MediaHTTPService";
             method = "createHttpServiceBinderIfNecessary";
             signature = "(Ljava/lang/String;)Landroid/os/IBinder;";