native_loader.cpp revision 5f28b8460d9e53c5ccbe154ec244c9ae56b4a97c
1/* 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#include "nativeloader/native_loader.h" 18#include "ScopedUtfChars.h" 19 20#include <dlfcn.h> 21#ifdef __ANDROID__ 22#include <android/dlext.h> 23#include "cutils/properties.h" 24#include "log/log.h" 25#endif 26 27#include <algorithm> 28#include <vector> 29#include <string> 30#include <mutex> 31 32#include "android-base/macros.h" 33#include "android-base/strings.h" 34 35namespace android { 36 37#ifdef __ANDROID__ 38// TODO(dimitry): move this to system properties. 39static const char* kPublicNativeLibraries = "libandroid.so:" 40 "libc.so:" 41 "libcamera2ndk.so:" 42 "libdl.so:" 43 "libEGL.so:" 44 "libGLESv1_CM.so:" 45 "libGLESv2.so:" 46 "libGLESv3.so:" 47 "libicui18n.so:" 48 "libicuuc.so:" 49 "libjnigraphics.so:" 50 "liblog.so:" 51 "libmediandk.so:" 52 "libm.so:" 53 "libOpenMAXAL.so:" 54 "libOpenSLES.so:" 55 "libRS.so:" 56 "libstdc++.so:" 57 "libvulkan.so:" 58 "libwebviewchromium_plat_support.so:" 59 "libz.so"; 60 61class LibraryNamespaces { 62 public: 63 LibraryNamespaces() : initialized_(false) { } 64 65 android_namespace_t* Create(JNIEnv* env, 66 jobject class_loader, 67 bool is_shared, 68 jstring java_library_path, 69 jstring java_permitted_path, 70 int32_t target_sdk_version) { 71 ScopedUtfChars library_path(env, java_library_path); 72 73 std::string permitted_path; 74 if (java_permitted_path != nullptr) { 75 ScopedUtfChars path(env, java_permitted_path); 76 permitted_path = path.c_str(); 77 } 78 79 if (!initialized_ && !InitPublicNamespace(library_path.c_str(), target_sdk_version)) { 80 return nullptr; 81 } 82 83 android_namespace_t* ns = FindNamespaceByClassLoader(env, class_loader); 84 85 LOG_FATAL_IF(ns != nullptr, "There is already a namespace associated with this classloader"); 86 87 uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED; 88 if (is_shared) { 89 namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED; 90 } 91 92 ns = android_create_namespace("classloader-namespace", 93 nullptr, 94 library_path.c_str(), 95 namespace_type, 96 java_permitted_path != nullptr ? 97 permitted_path.c_str() : 98 nullptr); 99 100 if (ns != nullptr) { 101 namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns)); 102 } 103 104 return ns; 105 } 106 107 android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) { 108 auto it = std::find_if(namespaces_.begin(), namespaces_.end(), 109 [&](const std::pair<jweak, android_namespace_t*>& value) { 110 return env->IsSameObject(value.first, class_loader); 111 }); 112 return it != namespaces_.end() ? it->second : nullptr; 113 } 114 115 void PreloadPublicLibraries() { 116 // android_init_namespaces() expects all the public libraries 117 // to be loaded so that they can be found by soname alone. 118 std::vector<std::string> sonames = android::base::Split(kPublicNativeLibraries, ":"); 119 for (const auto& soname : sonames) { 120 dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE); 121 } 122 } 123 124 private: 125 bool InitPublicNamespace(const char* library_path, int32_t target_sdk_version) { 126 // Some apps call dlopen from generated code unknown to linker in which 127 // case linker uses anonymous namespace. See b/25844435 for details. 128 std::string publicNativeLibraries = kPublicNativeLibraries; 129 130 // TODO (dimitry): This is a workaround for http://b/26436837 131 // will be removed before the release. 132 if (target_sdk_version <= 23) { 133 // check if libart.so is loaded. 134 void* handle = dlopen("libart.so", RTLD_NOW | RTLD_NOLOAD); 135 if (handle != nullptr) { 136 publicNativeLibraries += ":libart.so"; 137 dlclose(handle); 138 } 139 } 140 // END OF WORKAROUND 141 142 initialized_ = android_init_namespaces(publicNativeLibraries.c_str(), library_path); 143 144 return initialized_; 145 } 146 147 bool initialized_; 148 std::vector<std::pair<jweak, android_namespace_t*>> namespaces_; 149 150 DISALLOW_COPY_AND_ASSIGN(LibraryNamespaces); 151}; 152 153static std::mutex g_namespaces_mutex; 154static LibraryNamespaces* g_namespaces = new LibraryNamespaces; 155 156static bool namespaces_enabled(uint32_t target_sdk_version) { 157 return target_sdk_version > 0; 158} 159#endif 160 161void PreloadPublicNativeLibraries() { 162#if defined(__ANDROID__) 163 std::lock_guard<std::mutex> guard(g_namespaces_mutex); 164 g_namespaces->PreloadPublicLibraries(); 165#endif 166} 167 168 169jstring CreateClassLoaderNamespace(JNIEnv* env, 170 int32_t target_sdk_version, 171 jobject class_loader, 172 bool is_shared, 173 jstring library_path, 174 jstring permitted_path) { 175#if defined(__ANDROID__) 176 if (!namespaces_enabled(target_sdk_version)) { 177 return nullptr; 178 } 179 180 std::lock_guard<std::mutex> guard(g_namespaces_mutex); 181 android_namespace_t* ns = g_namespaces->Create(env, 182 class_loader, 183 is_shared, 184 library_path, 185 permitted_path, 186 target_sdk_version); 187 if (ns == nullptr) { 188 return env->NewStringUTF(dlerror()); 189 } 190#else 191 UNUSED(env, target_sdk_version, class_loader, is_shared, 192 library_path, permitted_path); 193#endif 194 return nullptr; 195} 196 197void* OpenNativeLibrary(JNIEnv* env, 198 int32_t target_sdk_version, 199 const char* path, 200 jobject class_loader, 201 jstring library_path) { 202#if defined(__ANDROID__) 203 if (!namespaces_enabled(target_sdk_version) || class_loader == nullptr) { 204 return dlopen(path, RTLD_NOW); 205 } 206 207 std::lock_guard<std::mutex> guard(g_namespaces_mutex); 208 android_namespace_t* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader); 209 210 if (ns == nullptr) { 211 // This is the case where the classloader was not created by ApplicationLoaders 212 // In this case we create an isolated not-shared namespace for it. 213 ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr, target_sdk_version); 214 if (ns == nullptr) { 215 return nullptr; 216 } 217 } 218 219 android_dlextinfo extinfo; 220 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; 221 extinfo.library_namespace = ns; 222 223 return android_dlopen_ext(path, RTLD_NOW, &extinfo); 224#else 225 UNUSED(env, target_sdk_version, class_loader, library_path); 226 return dlopen(path, RTLD_NOW); 227#endif 228} 229 230#if defined(__ANDROID__) 231android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) { 232 std::lock_guard<std::mutex> guard(g_namespaces_mutex); 233 return g_namespaces->FindNamespaceByClassLoader(env, class_loader); 234} 235#endif 236 237}; // android namespace 238