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