blob: 6d3c057b9d5faa3587abf36cc1d0f9ebb1c8debe [file] [log] [blame]
Orion Hodson9b16e342019-10-09 13:29:16 +01001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "nativeloader"
18
19#include "nativeloader/native_loader.h"
20
21#include <dlfcn.h>
22#include <sys/types.h>
23
24#include <memory>
25#include <mutex>
26#include <string>
27#include <vector>
28
29#include <android-base/file.h>
30#include <android-base/macros.h>
31#include <android-base/strings.h>
32#include <nativebridge/native_bridge.h>
33#include <nativehelper/ScopedUtfChars.h>
34
35#ifdef __ANDROID__
36#include <log/log.h>
37#include "library_namespaces.h"
38#include "nativeloader/dlext_namespaces.h"
39#endif
40
41namespace android {
42
43namespace {
44#if defined(__ANDROID__)
45using android::nativeloader::LibraryNamespaces;
46
47constexpr const char* kApexPath = "/apex/";
48
49std::mutex g_namespaces_mutex;
50LibraryNamespaces* g_namespaces = new LibraryNamespaces;
51
52android_namespace_t* FindExportedNamespace(const char* caller_location) {
53 std::string location = caller_location;
54 // Lots of implicit assumptions here: we expect `caller_location` to be of the form:
55 // /apex/com.android...modulename/...
56 //
57 // And we extract from it 'modulename', which is the name of the linker namespace.
58 if (android::base::StartsWith(location, kApexPath)) {
59 size_t slash_index = location.find_first_of('/', strlen(kApexPath));
60 LOG_ALWAYS_FATAL_IF((slash_index == std::string::npos),
61 "Error finding namespace of apex: no slash in path %s", caller_location);
62 size_t dot_index = location.find_last_of('.', slash_index);
63 LOG_ALWAYS_FATAL_IF((dot_index == std::string::npos),
64 "Error finding namespace of apex: no dot in apex name %s", caller_location);
65 std::string name = location.substr(dot_index + 1, slash_index - dot_index - 1);
66 android_namespace_t* boot_namespace = android_get_exported_namespace(name.c_str());
67 LOG_ALWAYS_FATAL_IF((boot_namespace == nullptr),
68 "Error finding namespace of apex: no namespace called %s", name.c_str());
69 return boot_namespace;
70 }
71 return nullptr;
72}
73#endif // #if defined(__ANDROID__)
74} // namespace
75
76void InitializeNativeLoader() {
77#if defined(__ANDROID__)
78 std::lock_guard<std::mutex> guard(g_namespaces_mutex);
79 g_namespaces->Initialize();
80#endif
81}
82
83void ResetNativeLoader() {
84#if defined(__ANDROID__)
85 std::lock_guard<std::mutex> guard(g_namespaces_mutex);
86 g_namespaces->Reset();
87#endif
88}
89
90jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobject class_loader,
91 bool is_shared, jstring dex_path, jstring library_path,
92 jstring permitted_path) {
93#if defined(__ANDROID__)
94 std::lock_guard<std::mutex> guard(g_namespaces_mutex);
95 auto ns = g_namespaces->Create(env, target_sdk_version, class_loader, is_shared, dex_path,
96 library_path, permitted_path);
97 if (!ns) {
98 return env->NewStringUTF(ns.error().message().c_str());
99 }
100#else
101 UNUSED(env, target_sdk_version, class_loader, is_shared, dex_path, library_path, permitted_path);
102#endif
103 return nullptr;
104}
105
106void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
107 jobject class_loader, const char* caller_location, jstring library_path,
108 bool* needs_native_bridge, char** error_msg) {
109#if defined(__ANDROID__)
110 UNUSED(target_sdk_version);
111 if (class_loader == nullptr) {
112 *needs_native_bridge = false;
113 if (caller_location != nullptr) {
114 android_namespace_t* boot_namespace = FindExportedNamespace(caller_location);
115 if (boot_namespace != nullptr) {
116 const android_dlextinfo dlextinfo = {
117 .flags = ANDROID_DLEXT_USE_NAMESPACE,
118 .library_namespace = boot_namespace,
119 };
120 void* handle = android_dlopen_ext(path, RTLD_NOW, &dlextinfo);
121 if (handle == nullptr) {
122 *error_msg = strdup(dlerror());
123 }
124 return handle;
125 }
126 }
127 void* handle = dlopen(path, RTLD_NOW);
128 if (handle == nullptr) {
129 *error_msg = strdup(dlerror());
130 }
131 return handle;
132 }
133
134 std::lock_guard<std::mutex> guard(g_namespaces_mutex);
135 NativeLoaderNamespace* ns;
136
137 if ((ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader)) == nullptr) {
138 // This is the case where the classloader was not created by ApplicationLoaders
139 // In this case we create an isolated not-shared namespace for it.
140 Result<NativeLoaderNamespace*> isolated_ns =
141 g_namespaces->Create(env, target_sdk_version, class_loader, false /* is_shared */, nullptr,
142 library_path, nullptr);
143 if (!isolated_ns) {
144 *error_msg = strdup(isolated_ns.error().message().c_str());
145 return nullptr;
146 } else {
147 ns = *isolated_ns;
148 }
149 }
150
151 return OpenNativeLibraryInNamespace(ns, path, needs_native_bridge, error_msg);
152#else
153 UNUSED(env, target_sdk_version, class_loader, caller_location);
154
155 // Do some best effort to emulate library-path support. It will not
156 // work for dependencies.
157 //
158 // Note: null has a special meaning and must be preserved.
159 std::string c_library_path; // Empty string by default.
160 if (library_path != nullptr && path != nullptr && path[0] != '/') {
161 ScopedUtfChars library_path_utf_chars(env, library_path);
162 c_library_path = library_path_utf_chars.c_str();
163 }
164
165 std::vector<std::string> library_paths = base::Split(c_library_path, ":");
166
167 for (const std::string& lib_path : library_paths) {
168 *needs_native_bridge = false;
169 const char* path_arg;
170 std::string complete_path;
171 if (path == nullptr) {
172 // Preserve null.
173 path_arg = nullptr;
174 } else {
175 complete_path = lib_path;
176 if (!complete_path.empty()) {
177 complete_path.append("/");
178 }
179 complete_path.append(path);
180 path_arg = complete_path.c_str();
181 }
182 void* handle = dlopen(path_arg, RTLD_NOW);
183 if (handle != nullptr) {
184 return handle;
185 }
186 if (NativeBridgeIsSupported(path_arg)) {
187 *needs_native_bridge = true;
188 handle = NativeBridgeLoadLibrary(path_arg, RTLD_NOW);
189 if (handle != nullptr) {
190 return handle;
191 }
192 *error_msg = strdup(NativeBridgeGetError());
193 } else {
194 *error_msg = strdup(dlerror());
195 }
196 }
197 return nullptr;
198#endif
199}
200
201bool CloseNativeLibrary(void* handle, const bool needs_native_bridge, char** error_msg) {
202 bool success;
203 if (needs_native_bridge) {
204 success = (NativeBridgeUnloadLibrary(handle) == 0);
205 if (!success) {
206 *error_msg = strdup(NativeBridgeGetError());
207 }
208 } else {
209 success = (dlclose(handle) == 0);
210 if (!success) {
211 *error_msg = strdup(dlerror());
212 }
213 }
214
215 return success;
216}
217
218void NativeLoaderFreeErrorMessage(char* msg) {
219 // The error messages get allocated through strdup, so we must call free on them.
220 free(msg);
221}
222
223#if defined(__ANDROID__)
224void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path,
225 bool* needs_native_bridge, char** error_msg) {
226 auto handle = ns->Load(path);
227 if (!handle && error_msg != nullptr) {
228 *error_msg = strdup(handle.error().message().c_str());
229 }
230 if (needs_native_bridge != nullptr) {
231 *needs_native_bridge = ns->IsBridged();
232 }
233 return handle ? *handle : nullptr;
234}
235
236// native_bridge_namespaces are not supported for callers of this function.
237// This function will return nullptr in the case when application is running
238// on native bridge.
239android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
240 std::lock_guard<std::mutex> guard(g_namespaces_mutex);
241 NativeLoaderNamespace* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
242 if (ns != nullptr && !ns->IsBridged()) {
243 return ns->ToRawAndroidNamespace();
244 }
245 return nullptr;
246}
247
248NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
249 std::lock_guard<std::mutex> guard(g_namespaces_mutex);
250 return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
251}
252#endif
253
254}; // namespace android