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;";