native_loader.cpp revision d047c925af62e1fe28fcd1c1940df4afe18d458a
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 std::lock_guard<std::mutex> guard(mutex_); 84 85 android_namespace_t* ns = FindNamespaceByClassLoader(env, class_loader); 86 87 LOG_FATAL_IF(ns != nullptr, "There is already a namespace associated with this classloader"); 88 89 uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED; 90 if (is_shared) { 91 namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED; 92 } 93 94 ns = android_create_namespace("classloader-namespace", 95 nullptr, 96 library_path.c_str(), 97 namespace_type, 98 java_permitted_path != nullptr ? 99 permitted_path.c_str() : 100 nullptr); 101 102 if (ns != nullptr) { 103 namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns)); 104 } 105 106 return ns; 107 } 108 109 android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) { 110 auto it = std::find_if(namespaces_.begin(), namespaces_.end(), 111 [&](const std::pair<jweak, android_namespace_t*>& value) { 112 return env->IsSameObject(value.first, class_loader); 113 }); 114 return it != namespaces_.end() ? it->second : nullptr; 115 } 116 117 void PreloadPublicLibraries() { 118 // android_init_namespaces() expects all the public libraries 119 // to be loaded so that they can be found by soname alone. 120 std::vector<std::string> sonames = android::base::Split(kPublicNativeLibraries, ":"); 121 for (const auto& soname : sonames) { 122 dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE); 123 } 124 } 125 126 private: 127 bool InitPublicNamespace(const char* library_path, int32_t target_sdk_version) { 128 // Some apps call dlopen from generated code unknown to linker in which 129 // case linker uses anonymous namespace. See b/25844435 for details. 130 std::string publicNativeLibraries = kPublicNativeLibraries; 131 132 // TODO (dimitry): This is a workaround for http://b/26436837 133 // will be removed before the release. 134 if (target_sdk_version <= 23) { 135 publicNativeLibraries += ":libart.so"; 136 } 137 // END OF WORKAROUND 138 139 initialized_ = android_init_namespaces(publicNativeLibraries.c_str(), library_path); 140 141 return initialized_; 142 } 143 144 bool initialized_; 145 std::mutex mutex_; 146 std::vector<std::pair<jweak, android_namespace_t*>> namespaces_; 147 148 DISALLOW_COPY_AND_ASSIGN(LibraryNamespaces); 149}; 150 151static LibraryNamespaces* g_namespaces = new LibraryNamespaces; 152 153static bool namespaces_enabled(uint32_t target_sdk_version) { 154 return target_sdk_version > 0; 155} 156#endif 157 158void PreloadPublicNativeLibraries() { 159#if defined(__ANDROID__) 160 g_namespaces->PreloadPublicLibraries(); 161#endif 162} 163 164 165jstring CreateClassLoaderNamespace(JNIEnv* env, 166 int32_t target_sdk_version, 167 jobject class_loader, 168 bool is_shared, 169 jstring library_path, 170 jstring permitted_path) { 171#if defined(__ANDROID__) 172 if (!namespaces_enabled(target_sdk_version)) { 173 return nullptr; 174 } 175 176 android_namespace_t* ns = g_namespaces->Create(env, 177 class_loader, 178 is_shared, 179 library_path, 180 permitted_path, 181 target_sdk_version); 182 if (ns == nullptr) { 183 return env->NewStringUTF(dlerror()); 184 } 185#else 186 UNUSED(env, target_sdk_version, class_loader, is_shared, 187 library_path, permitted_path); 188#endif 189 return nullptr; 190} 191 192void* OpenNativeLibrary(JNIEnv* env, 193 int32_t target_sdk_version, 194 const char* path, 195 jobject class_loader, 196 jstring library_path) { 197#if defined(__ANDROID__) 198 if (!namespaces_enabled(target_sdk_version) || class_loader == nullptr) { 199 return dlopen(path, RTLD_NOW); 200 } 201 202 android_namespace_t* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader); 203 204 if (ns == nullptr) { 205 // This is the case where the classloader was not created by ApplicationLoaders 206 // In this case we create an isolated not-shared namespace for it. 207 ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr, target_sdk_version); 208 if (ns == nullptr) { 209 return nullptr; 210 } 211 } 212 213 android_dlextinfo extinfo; 214 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; 215 extinfo.library_namespace = ns; 216 217 return android_dlopen_ext(path, RTLD_NOW, &extinfo); 218#else 219 UNUSED(env, target_sdk_version, class_loader, library_path); 220 return dlopen(path, RTLD_NOW); 221#endif 222} 223 224#if defined(__ANDROID__) 225android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) { 226 return g_namespaces->FindNamespaceByClassLoader(env, class_loader); 227} 228#endif 229 230}; // android namespace 231