Native loader as a separate library
Extracted native loader to separate library in order to
be able to reuse it for NativeActivities related native code
in libandroid_runtime.so
Bug: http://b/22548808
Change-Id: Ibcf5ddcdc5aba22e32e4b72887840e9c171c1986
diff --git a/include/nativeloader/native_loader.h b/include/nativeloader/native_loader.h
new file mode 100644
index 0000000..18b7ba4
--- /dev/null
+++ b/include/nativeloader/native_loader.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef NATIVE_LOADER_H_
+#define NATIVE_LOADER_H_
+
+#include "jni.h"
+#include <stdint.h>
+
+namespace android {
+
+__attribute__((visibility("default")))
+void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
+ jobject class_loader, jstring library_path);
+
+}; // namespace android
+
+#endif // NATIVE_BRIDGE_H_
diff --git a/libnativeloader/Android.mk b/libnativeloader/Android.mk
new file mode 100644
index 0000000..5e65c4c
--- /dev/null
+++ b/libnativeloader/Android.mk
@@ -0,0 +1,54 @@
+LOCAL_PATH:= $(call my-dir)
+
+NATIVE_LOADER_COMMON_SRC_FILES := \
+ native_loader.cpp
+
+# Shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativeloader
+
+LOCAL_SRC_FILES:= $(NATIVE_LOADER_COMMON_SRC_FILES)
+LOCAL_SHARED_LIBRARIES := libnativehelper liblog libcutils
+LOCAL_STATIC_LIBRARIES := libbase
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Shared library for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativeloader
+
+LOCAL_SRC_FILES:= $(NATIVE_LOADER_COMMON_SRC_FILES)
+LOCAL_SHARED_LIBRARIES := libnativehelper liblog libcutils
+LOCAL_STATIC_LIBRARIES := libbase
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+# Static library for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativeloader
+
+LOCAL_SRC_FILES:= $(NATIVE_LOADER_COMMON_SRC_FILES)
+LOCAL_STATIC_LIBRARIES := libnativehelper libcutils liblog libbase
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
new file mode 100644
index 0000000..33870e2
--- /dev/null
+++ b/libnativeloader/native_loader.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include "nativeloader/native_loader.h"
+#include "ScopedUtfChars.h"
+
+#include <dlfcn.h>
+#ifdef __ANDROID__
+#include <android/dlext.h>
+#include "cutils/properties.h"
+#endif
+
+#include <algorithm>
+#include <vector>
+#include <string>
+#include <mutex>
+
+#include "base/macros.h"
+#include "base/strings.h"
+
+namespace android {
+
+#ifdef __ANDROID__
+// TODO(dimitry): move this to system properties.
+static const char* kPublicNativeLibraries = "libandroid.so:"
+ "libc.so:"
+ "libdl.so:"
+ "libEGL.so:"
+ "libGLESv1_CM.so:"
+ "libGLESv2.so:"
+ "libGLESv3.so:"
+ "libjnigraphics.so:"
+ "liblog.so:"
+ "libmediandk.so:"
+ "libm.so:"
+ "libOpenMAXAL.so:"
+ "libOpenSLES.so:"
+ "libstdc++.so:"
+ "libz.so";
+
+class LibraryNamespaces {
+ public:
+ LibraryNamespaces() : initialized_(false) { }
+
+ android_namespace_t* GetOrCreate(JNIEnv* env, jobject class_loader, jstring library_path) {
+ ScopedUtfChars libraryPath(env, library_path);
+
+ if (!initialized_ && !InitPublicNamespace(libraryPath.c_str())) {
+ return nullptr;
+ }
+
+ std::lock_guard<std::mutex> guard(mutex_);
+
+ auto it = FindNamespaceByClassLoader(env, class_loader);
+
+ if (it != namespaces_.end()) {
+ return it->second;
+ }
+
+ android_namespace_t* ns =
+ android_create_namespace("classloader-namespace",
+ nullptr,
+ libraryPath.c_str(),
+ true);
+
+ namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));
+
+ return ns;
+ }
+
+ private:
+ bool InitPublicNamespace(const char* library_path) {
+ // Make sure all the public libraries are loaded
+ std::vector<std::string> sonames = android::base::Split(kPublicNativeLibraries, ":");
+ for (const auto& soname : sonames) {
+ if (dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr) {
+ return false;
+ }
+ }
+
+ // Some apps call dlopen from generated code unknown to linker in which
+ // case linker uses anonymous namespace. See b/25844435 for details.
+ initialized_ = android_init_namespaces(kPublicNativeLibraries, library_path);
+
+ return initialized_;
+ }
+
+ std::vector<std::pair<jweak, android_namespace_t*>>::const_iterator
+ FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+ return std::find_if(namespaces_.begin(), namespaces_.end(),
+ [&](const std::pair<jweak, android_namespace_t*>& value) {
+ return env->IsSameObject(value.first, class_loader);
+ });
+ }
+
+ bool initialized_;
+ std::mutex mutex_;
+ std::vector<std::pair<jweak, android_namespace_t*>> namespaces_;
+
+ DISALLOW_COPY_AND_ASSIGN(LibraryNamespaces);
+};
+
+static LibraryNamespaces* g_namespaces = new LibraryNamespaces;
+#endif
+
+
+void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
+ jobject class_loader, jstring library_path) {
+#if defined(__ANDROID__)
+ if (target_sdk_version == 0 || class_loader == nullptr) {
+ return dlopen(path, RTLD_NOW);
+ }
+
+ android_namespace_t* ns = g_namespaces->GetOrCreate(env, class_loader, library_path);
+
+ if (ns == nullptr) {
+ return nullptr;
+ }
+
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns;
+
+ return android_dlopen_ext(path, RTLD_NOW, &extinfo);
+#else
+ UNUSED(env, target_sdk_version, class_loader, library_path);
+ return dlopen(path, RTLD_NOW);
+#endif
+}
+
+}; // android namespace