{"id":105,"date":"2020-09-15T15:22:50","date_gmt":"2020-09-15T07:22:50","guid":{"rendered":"http:\/\/pareto.fun\/?p=105"},"modified":"2020-12-31T11:35:17","modified_gmt":"2020-12-31T03:35:17","slug":"android-10-linker%ef%bc%88%e5%be%85%e4%bf%ae%e6%94%b9%ef%bc%89","status":"publish","type":"post","link":"http:\/\/pareto.fun\/?p=105","title":{"rendered":"Android  Linker \u89e3\u8bfb\u2014\u20141"},"content":{"rendered":"\n<p>Android \u7248\u672c\uff1aandroid-8.0.0_r4<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u76ee\u7684<\/h2>\n\n\n\n<ul><li>elf\u7684\u52a0\u8f7d\u8fc7\u7a0b<\/li><li>\u5728so\u52a0\u8f7d\u8fc7\u7a0b\u4e2d\u786e\u5b9a\u4f9d\u8d56\u5e93\u5148\u88ab\u8c03\u7528construct \u8fd8\u662f\u540e\u8c03\u7528\u3002<\/li><li>elf \u91cd\u5b9a\u4f4d\u8fc7\u7a0b\u505a\u4e86\u4ec0\u4e48\uff1f<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">\u8fc7\u7a0b<\/h2>\n\n\n\n<p>System.loadLibrary\u6e90\u7801\u4f4d\u4e8e\uff1a.\/libcore\/ojluni\/src\/main\/java\/java\/lang\/System.java<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">public static void loadLibrary(String libname) {<br> &nbsp;  Runtime.getRuntime().loadLibrary0(VMStack.getCallingClassLoader(), libname);<br>}<\/pre>\n\n\n\n<p>\u53ef\u4ee5\u770b\u5230\u7136\u540e\u53c8\u8c03\u7528\u4e86Runtime.java\u7684loadLibrary0\u65b9\u6cd5\uff1a.\/libcore\/ojluni\/src\/main\/java\/java\/lang\/Runtime.java<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> &nbsp; &nbsp;synchronized void loadLibrary0(ClassLoader loader, String libname) {<br> &nbsp; &nbsp; &nbsp; &nbsp;if (libname.indexOf((int)File.separatorChar) != -1) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new UnsatisfiedLinkError(<br> &nbsp; &nbsp;\"Directory separator should not appear in library name: \" + libname);<br> &nbsp; &nbsp; &nbsp;  }<br> &nbsp; &nbsp; &nbsp; &nbsp;String libraryName = libname;<br> &nbsp; &nbsp; &nbsp; &nbsp;if (loader != null) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;String filename = loader.findLibrary(libraryName);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (filename == null) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new UnsatisfiedLinkError(loader + \" couldn't find \\\"\" +<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.mapLibraryName(libraryName) + \"\\\"\");<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;String error = doLoad(filename, loader);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (error != null) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new UnsatisfiedLinkError(error);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return;<br> &nbsp; &nbsp; &nbsp;  }<br>\u200b<br> &nbsp; &nbsp; &nbsp; &nbsp;String filename = System.mapLibraryName(libraryName);<br> &nbsp; &nbsp; &nbsp; &nbsp;List&lt;String&gt; candidates = new ArrayList&lt;String&gt;();<br> &nbsp; &nbsp; &nbsp; &nbsp;String lastError = null;<br> &nbsp; &nbsp; &nbsp; &nbsp;for (String directory : getLibPaths()) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;String candidate = directory + filename;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;candidates.add(candidate);<br>\u200b<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (IoUtils.canOpenReadOnly(candidate)) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;String error = doLoad(candidate, loader);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (error == null) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return; \/\/ We successfully loaded the library. Job done.<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;lastError = error;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }<br> &nbsp; &nbsp; &nbsp;  }<br>\u200b<br> &nbsp; &nbsp; &nbsp; &nbsp;if (lastError != null) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new UnsatisfiedLinkError(lastError);<br> &nbsp; &nbsp; &nbsp;  }<br> &nbsp; &nbsp; &nbsp; &nbsp;throw new UnsatisfiedLinkError(\"Library \" + libraryName + \" not found; tried \" + candidates);<br> &nbsp;  }<\/pre>\n\n\n\n<p>\u8fd9\u4e2a\u65b9\u6cd5\u4e3b\u8981\u6709\u4e24\u4e2a\u4f5c\u7528\uff1a<\/p>\n\n\n\n<ol><li>\u627e\u5230lib\u7684\u5168\u79f0<\/li><li>\u8c03\u7528doLoad\u52a0\u8f7dlib\u5e93<\/li><\/ol>\n\n\n\n<p>\u9996\u5148\u4f1a\u5224\u65adloader \u4e0d\u4e3a\u7a7a\u6765\u6267\u884c\u4e0a\u9762\u4e24\u6b65\uff0c\u5982\u679c\u4e3a\u7a7a\uff0c\u5219\u6362\u4e2a\u65b9\u6cd5\u7ee7\u7eed\u6267\u884c\u4e0a\u9762\u4e24\u6b65\u3002<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> &nbsp; &nbsp;private String doLoad(String name, ClassLoader loader) {<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp;String librarySearchPath = null;<br> &nbsp; &nbsp; &nbsp; &nbsp;if (loader != null &amp;&amp; loader instanceof BaseDexClassLoader) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;BaseDexClassLoader dexClassLoader = (BaseDexClassLoader) loader;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;librarySearchPath = dexClassLoader.getLdLibraryPath();<br> &nbsp; &nbsp; &nbsp;  }<br>\u200b<br> &nbsp; &nbsp; &nbsp; &nbsp;synchronized (this) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return nativeLoad(name, loader, librarySearchPath);<br> &nbsp; &nbsp; &nbsp;  }<br> &nbsp;  }<\/pre>\n\n\n\n<p>\u62ff\u5230\u5e93\u7684\u641c\u7d22\u8def\u5f84\uff0c\u8c03\u7528\u4e86native \u7684nativeLoad\u65b9\u6cd5\u3002<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">private static native String nativeLoad(String filename, ClassLoader loader,String ibrarySearchPath);<\/pre>\n\n\n\n<p>native\u51fd\u6570\u5728libcore\/ojluni\/src\/main\/native\/register.cpp,\u7edf\u4e00\u6ce8\u518c\uff0c<\/p>\n\n\n\n<p>\u5176\u4e2d\u6211\u4eec\u9700\u8981\u7684nativeLoad\u51fd\u6570\u5728libcore\/ojluni\/src\/main\/native\/Runtime.c \u6587\u4ef6\u4e0b<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jstring javaFilename,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jobject javaLoader,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jstring javaLibrarySearchPath) {<br> &nbsp;ScopedUtfChars filename(env, javaFilename);<br> &nbsp;if (filename.c_str() == NULL) {<br> &nbsp; &nbsp;return NULL;<br>  }<br>\u200b<br> &nbsp;std::string error_msg;<br>  {<br> &nbsp; &nbsp;art::JavaVMExt* vm = art::Runtime::Current()-&gt;GetJavaVM();<br> &nbsp; &nbsp;bool success = vm-&gt;LoadNativeLibrary(env,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; filename.c_str(),<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; javaLoader,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; javaLibrarySearchPath,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &amp;error_msg);<br> &nbsp; &nbsp;if (success) {<br> &nbsp; &nbsp; &nbsp;return nullptr;<br> &nbsp;  }<br>  }<br>\u200b<br> &nbsp;\/\/ Don't let a pending exception from JNI_OnLoad cause a CheckJNI issue with NewStringUTF.<br> &nbsp;env-&gt;ExceptionClear();<br> &nbsp;return env-&gt;NewStringUTF(error_msg.c_str());<br>}<\/pre>\n\n\n\n<p>\u7ee7\u7eed\u8ddf\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">bool JavaVMExt::LoadNativeLibrary(JNIEnv* env,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;const std::string&amp; path,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;jobject class_loader,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;jstring library_path,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;std::string* error_msg) {<br> &nbsp;error_msg-&gt;clear();<br>\u200b<br> &nbsp;\/\/ See if we've already loaded this library.  If we have, and the class loader matches, return successfully without doing anything.<br>\u3002\u3002\u3002\u3002\u3002 \uff0c \u5df2\u7ecf\u52a0\u8f7d\u4e86so<br> &nbsp;if (library != nullptr) {<br> &nbsp; &nbsp;if (library-&gt;GetClassLoaderAllocator() != class_loader_allocator) {<br>\u200b<br> &nbsp; &nbsp; &nbsp;StringAppendF(error_msg, \"Shared library \\\"%s\\\" already opened by \"<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\"ClassLoader %p; can't open in ClassLoader %p\",<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;path.c_str(), library-&gt;GetClassLoader(), class_loader);<br> &nbsp; &nbsp; &nbsp;LOG(WARNING) &lt;&lt; error_msg;<br> &nbsp; &nbsp; &nbsp;return false;<br> &nbsp;  }<br> &nbsp; &nbsp;VLOG(jni) &lt;&lt; \"[Shared library \\\"\" &lt;&lt; path &lt;&lt; \"\\\" already loaded in \"<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;&lt; \" ClassLoader \" &lt;&lt; class_loader &lt;&lt; \"]\";<br> &nbsp; &nbsp;if (!library-&gt;CheckOnLoadResult()) {<br> &nbsp; &nbsp; &nbsp;StringAppendF(error_msg, \"JNI_OnLoad failed on a previous attempt \"<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\"to load \\\"%s\\\"\", path.c_str());<br> &nbsp; &nbsp; &nbsp;return false;<br> &nbsp;  }<br> &nbsp; &nbsp;return true;<br>  }<br>  .........<br>\/\/\u6ca1\u6709\u52a0\u8f7d\u8fc7so \uff0c \u5c31\u8c03\u7528OpenNativeLibrary\u6765\u52a0\u8f7dso\u3002<br> &nbsp;Locks::mutator_lock_-&gt;AssertNotHeld(self);<br> &nbsp;const char* path_str = path.empty() ? nullptr : path.c_str();<br> &nbsp;bool needs_native_bridge = false;<br> &nbsp;void* handle = android::OpenNativeLibrary(env,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;runtime_-&gt;GetTargetSdkVersion(),<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;path_str,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;class_loader,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;library_path,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp;needs_native_bridge,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;error_msg);<br>\u200b<br> &nbsp;VLOG(jni) &lt;&lt; \"[Call to dlopen(\\\"\" &lt;&lt; path &lt;&lt; \"\\\", RTLD_NOW) returned \" &lt;&lt; handle &lt;&lt; \"]\";<br>\u200b<br> &nbsp;if (handle == nullptr) {<br> &nbsp; &nbsp;VLOG(jni) &lt;&lt; \"dlopen(\\\"\" &lt;&lt; path &lt;&lt; \"\\\", RTLD_NOW) failed: \" &lt;&lt; *error_msg;<br> &nbsp; &nbsp;return false;<br>  }<br>\u200b<br>  ......... <br> &nbsp;\/\/\u8981\u662fso\u52a0\u8f7d\u6210\u529f\u540e\uff0c\u8fd8\u8981\u770b\u6709\u6ca1\u6709JNI_OnLoad\u51fd\u6570\uff0c\u6765\u5224\u65adnative\u51fd\u6570\u662f\u9759\u6001\u6ce8\u518c\u8fd8\u662fJni\u52a8\u6001\u6ce8\u518c\u3002<br> &nbsp;bool was_successful = false;<br> &nbsp;void* sym = library-&gt;FindSymbol(\"JNI_OnLoad\", nullptr);<br> &nbsp;if (sym == nullptr) {<br> &nbsp; &nbsp;VLOG(jni) &lt;&lt; \"[No JNI_OnLoad found in \\\"\" &lt;&lt; path &lt;&lt; \"\\\"]\";<br> &nbsp; &nbsp;was_successful = true;<br>  } else {<br> &nbsp; &nbsp;\/\/ Call JNI_OnLoad.  We have to override the current class<br> &nbsp; &nbsp;\/\/ loader, which will always be \"null\" since the stuff at the<br> &nbsp; &nbsp;\/\/ top of the stack is around Runtime.loadLibrary().  (See<br> &nbsp; &nbsp;\/\/ the comments in the JNI FindClass function.)<br> &nbsp; &nbsp;ScopedLocalRef&lt;jobject&gt; old_class_loader(env, env-&gt;NewLocalRef(self-&gt;GetClassLoaderOverride()));<br> &nbsp; &nbsp;self-&gt;SetClassLoaderOverride(class_loader);<br> &nbsp; &nbsp;VLOG(jni) &lt;&lt; \"[Calling JNI_OnLoad in \\\"\" &lt;&lt; path &lt;&lt; \"\\\"]\";<br> &nbsp; &nbsp;typedef int (*JNI_OnLoadFn)(JavaVM*, void*);<br> &nbsp; &nbsp;JNI_OnLoadFn jni_on_load = reinterpret_cast&lt;JNI_OnLoadFn&gt;(sym);<br> &nbsp; &nbsp;int version = (*jni_on_load)(this, nullptr);<br> &nbsp;  .......<br>}<\/pre>\n\n\n\n<p>\u7ee7\u7eed\u8ddfandroid::OpenNativeLibrary \uff0c system\/core\/libnativeloader\/native_loader.cpp<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void* OpenNativeLibrary(JNIEnv* env,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;int32_t target_sdk_version,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;const char* path,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;jobject class_loader,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;jstring library_path,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;bool* needs_native_bridge,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;std::string* error_msg) {<br>#if defined(__ANDROID__)<br> &nbsp;UNUSED(target_sdk_version);<br> &nbsp;if (class_loader == nullptr) {<br> &nbsp; &nbsp;*needs_native_bridge = false;<br> &nbsp; &nbsp;return dlopen(path, RTLD_NOW);<br>  }<br>\u200b<br> &nbsp;std::lock_guard&lt;std::mutex&gt; guard(g_namespaces_mutex);<br> &nbsp;NativeLoaderNamespace ns;<br>\u200b<br> &nbsp;if (!g_namespaces-&gt;FindNamespaceByClassLoader(env, class_loader, &amp;ns)) {<br> &nbsp; &nbsp;if (!g_namespaces-&gt;Create(env,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;target_sdk_version,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;class_loader,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;false \/* is_shared *\/,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;false \/* is_for_vendor *\/,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;library_path,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;nullptr,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp;ns,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;error_msg)) {<br> &nbsp; &nbsp; &nbsp;return nullptr;<br> &nbsp;  }<br>  }<br>\u200b<br> &nbsp;if (ns.is_android_namespace()) {<br> &nbsp; &nbsp;android_dlextinfo extinfo;<br> &nbsp; &nbsp;extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;<br> &nbsp; &nbsp;extinfo.library_namespace = ns.get_android_ns();<br>\u200b<br> &nbsp; &nbsp;void* handle = android_dlopen_ext(path, RTLD_NOW, &amp;extinfo);<br> &nbsp; &nbsp;if (handle == nullptr) {<br> &nbsp; &nbsp; &nbsp;*error_msg = dlerror();<br> &nbsp;  }<br> &nbsp; &nbsp;*needs_native_bridge = false;<br> &nbsp; &nbsp;return handle;<br>  } else {<br> &nbsp; &nbsp;void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns.get_native_bridge_ns());<br> &nbsp; &nbsp;if (handle == nullptr) {<br> &nbsp; &nbsp; &nbsp;*error_msg = NativeBridgeGetError();<br> &nbsp;  }<br> &nbsp; &nbsp;*needs_native_bridge = true;<br> &nbsp; &nbsp;return handle;<br>  }<br>#else<br> &nbsp;UNUSED(env, target_sdk_version, class_loader, library_path);<br> &nbsp;*needs_native_bridge = false;<br> &nbsp;void* handle = dlopen(path, RTLD_NOW);<br> &nbsp;if (handle == nullptr) {<br> &nbsp; &nbsp;if (NativeBridgeIsSupported(path)) {<br> &nbsp; &nbsp; &nbsp;*needs_native_bridge = true;<br> &nbsp; &nbsp; &nbsp;handle = NativeBridgeLoadLibrary(path, RTLD_NOW);<br> &nbsp; &nbsp; &nbsp;if (handle == nullptr) {<br> &nbsp; &nbsp; &nbsp; &nbsp;*error_msg = NativeBridgeGetError();<br> &nbsp; &nbsp;  }<br> &nbsp;  } else {<br> &nbsp; &nbsp; &nbsp;*needs_native_bridge = false;<br> &nbsp; &nbsp; &nbsp;*error_msg = dlerror();<br> &nbsp;  }<br>  }<br> &nbsp;return handle;<br>#endif<br>}<\/pre>\n\n\n\n<p>\u6709\u4e24\u4e2a\u70b9\uff0cclass_loader == NULL , \u548c\u975e\u7a7a\u7684\u60c5\u51b5\u3002<del>\u8fd9\u91cc\u731c\u6d4b\u5bf9\u5e94\u4e24\u79cd\u60c5\u51b5(\u672a\u52a0\u9a8c\u8bc1)class_loader\u4e3a\u7a7a\u65f6\uff0c\u5bf9\u5e94so\u4e2d\u51fd\u6570\u4e3b\u52a8\u8c03\u7528\u6253\u5f00so\uff0c\u4f46\u662fso\u95f4\u5f15\u7528\u76f4\u63a5\u4f7f\u7528dlopen\u5e94\u8be5\u4e0d\u8d70\u8fd9\u4e2a\u8fc7\u7a0b<\/del> \u3002\u4e0d\u6653\u5f97\u8fd9\u4e24\u79cd\u662f\u4ec0\u4e48\u60c5\u51b5\u3002\u3002\u3002\u3002\u5927\u795e\u53ef\u4ee5\u6307\u6559\u4e0b\u3002\u7b2c\u4e00\u4e2a\u8fc7\u7a0b\u76f4\u63a5\u8d70dlopen\u3002\u7b2c\u4e8c\u4e2a\u8fc7\u7a0b\uff0c\u8d70android_dlopen_ext \uff0c \u4e24\u4e2a\u51fd\u6570\u6700\u7ec8\u90fd\u4f1a\u8d70\u5230do_dlopen \u6765\u6253\u5f00so \u3002<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void* do_dlopen(const char* name, int flags,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;const android_dlextinfo* extinfo,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;const void* caller_addr) {<br>\u200b<br>\/\/ \u5728\u6b64\u4e4b\u524d\u90fd\u662f\u9488\u5bf9\uff0cflag \u548cextinfo flag\u7684\u5904\u7406\u3002<br> &nbsp;const char* translated_name = name;<br> &nbsp;if (g_is_asan &amp;&amp; translated_name != nullptr &amp;&amp; translated_name[0] == '\/') {<br> &nbsp; &nbsp;char original_path[PATH_MAX];<br> &nbsp; &nbsp;if (realpath(name, original_path) != nullptr) {<br> &nbsp; &nbsp; &nbsp;asan_name_holder = std::string(kAsanLibDirPrefix) + original_path;<br> &nbsp; &nbsp; &nbsp;LD_LOG(kLogDlopen,\"... pareto's here realpath =\\\"%s\\\"\",name);<br> &nbsp; &nbsp; &nbsp;if (file_exists(asan_name_holder.c_str())) {<br> &nbsp; &nbsp; &nbsp; &nbsp;soinfo* si = nullptr;<br> &nbsp; &nbsp; &nbsp; &nbsp;if (find_loaded_library_by_realpath(ns, original_path, true, &amp;si)) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;PRINT(\"linker_asan dlopen NOT translating \\\"%s\\\" -&gt; \\\"%s\\\": library already loaded\", name,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;asan_name_holder.c_str());<br> &nbsp; &nbsp; &nbsp;  } else {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;PRINT(\"linker_asan dlopen translating \\\"%s\\\" -&gt; \\\"%s\\\"\", name, translated_name);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;translated_name = asan_name_holder.c_str();<br> &nbsp; &nbsp; &nbsp;  }<br> &nbsp; &nbsp;  }<br> &nbsp;  }<br>  }<br>\u200b<br> &nbsp;ProtectedDataGuard guard;<br> &nbsp; &nbsp;\/\/\u5173\u6ce8\u70b9 find_library<br> &nbsp;soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);<br> &nbsp;loading_trace.End();<br>\u200b<br> &nbsp;if (si != nullptr) {<br> &nbsp; &nbsp;void* handle = si-&gt;to_handle();<br>    \/\/\u8c03\u7528init<br> &nbsp; &nbsp;si-&gt;call_constructors();<br> &nbsp; <br> &nbsp; &nbsp;return handle;<br>  }<br>\u200b<br> &nbsp;return nullptr;<br>}<\/pre>\n\n\n\n<p>find_library\u5185\u90e8\u8c03\u7528\u91cd\u8f7d\u51fd\u6570find_library \uff0c\u5185\u90e8\u7684\u91cd\u8f7d\u51fd\u6570\u5c31\u662f\u672c\u6b21\u5206\u6790\u7684\u91cd\u70b9\u3002<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">static soinfo* find_library(android_namespace_t* ns,\n                            const char* name, int rtld_flags,\n                            const android_dlextinfo* extinfo,\n                            soinfo* needed_by) {\n  soinfo* si;\n\n  \/\/ readers_map is shared across recursive calls to find_libraries.\n  \/\/ However, the map is not shared across different threads.\n  std::unordered_map&lt;const soinfo*, ElfReader&gt; readers_map;\n  if (name == nullptr) {\n    si = solist_get_somain();\n  } else if (!find_libraries(ns,\n                             needed_by,\n                             &amp;name,\n                             1,\n                             &amp;si,\n                             nullptr,\n                             0,\n                             rtld_flags,\n                             extinfo,\n                             false \/* add_as_children *\/,\n                             true \/* search_linked_namespaces *\/,\n                             readers_map)) {\n    return nullptr;\n  }\n\t\/\/  \u589e\u52a0so\u7684\u7d22\u5f15\u8ba1\u6570\n  si-&gt;increment_ref_count();\n\n  return si;\n}<\/pre>\n\n\n\n<p>\u5173\u952e\u51fd\u6570\u5230\u4f4d\u4e86<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">bool find_libraries(android_namespace_t* ns,\n                    soinfo* start_with,\n                    const char* const library_names[],\n                    size_t library_names_count,\n                    soinfo* soinfos[],\n                    std::vector&lt;soinfo*&gt;* ld_preloads,\n                    size_t ld_preloads_count,\n                    int rtld_flags,\n                    const android_dlextinfo* extinfo,\n                    bool add_as_children,\n                    bool search_linked_namespaces,\n                    std::unordered_map&lt;const soinfo*, ElfReader&gt;&amp; readers_map,\n                    std::vector&lt;android_namespace_t*&gt;* namespaces) {\n  \/\/ Step 0: prepare.\n  LoadTaskList load_tasks;\n\n  for (size_t i = 0; i &lt; library_names_count; ++i) {\n    const char* name = library_names[i];\n    LD_LOG(kLogDlopen,\"[linker.cpp] step 1 ,so_name\",name);\n\n    load_tasks.push_back(LoadTask::create(name, start_with, ns, &amp;readers_map));\n  }\n\n  \/\/ If soinfos array is null allocate one on stack.\n  \/\/ The array is needed in case of failure; for example\n  \/\/ when library_names[] = {libone.so, libtwo.so} and libone.so\n  \/\/ is loaded correctly but libtwo.so failed for some reason.\n  \/\/ In this case libone.so should be unloaded on return.\n  \/\/ See also implementation of failure_guard below.\n\n  if (soinfos == nullptr) {\n    size_t soinfos_size = sizeof(soinfo*)*library_names_count;\n    soinfos = reinterpret_cast&lt;soinfo**&gt;(alloca(soinfos_size));\n    memset(soinfos, 0, soinfos_size);\n  }\n\n  \/\/ list of libraries to link - see step 2.\n  size_t soinfos_count = 0;\n\n  auto scope_guard = android::base::make_scope_guard([&amp;]() {\n    for (LoadTask* t : load_tasks) {\n      LD_LOG(kLogDlopen,\"[linker.cpp] before call deleter %s\",t-&gt;get_name());\n      LoadTask::deleter(t);\n    }\n  });\n\n  auto failure_guard = android::base::make_scope_guard([&amp;]() {\n    \/\/ Housekeeping\n    soinfo_unload(soinfos, soinfos_count);\n  });\n\n  ZipArchiveCache zip_archive_cache;\n\n  \/\/ Step 1: expand the list of load_tasks to include\n  \/\/ all DT_NEEDED libraries (do not load them just yet)\n  for (size_t i = 0; i&lt;load_tasks.size(); ++i) {\n    LoadTask* task = load_tasks[i];\n    LD_LOG(kLogDlopen,\"[linker.cpp] traverse load_tasks %s\",task-&gt;get_name());\n    soinfo* needed_by = task-&gt;get_needed_by();\n    LD_LOG(kLogDlopen,\"[linker.cpp] print needed_by so_name %s ,add_as_children  %d \",needed_by-&gt;get_soname(),add_as_children);\n    bool is_dt_needed = needed_by != nullptr &amp;&amp; (needed_by != start_with || add_as_children);\n    LD_LOG(kLogDlopen,\"[linker.cpp] value of is_dt_needed %d\",is_dt_needed);\n    task-&gt;set_extinfo(is_dt_needed ? nullptr : extinfo);\n    task-&gt;set_dt_needed(is_dt_needed);\n\n    \/\/ try to find the load.\n    \/\/ Note: start from the namespace that is stored in the LoadTask. This namespace\n    \/\/ is different from the current namespace when the LoadTask is for a transitive\n    \/\/ dependency and the lib that created the LoadTask is not found in the\n    \/\/ current namespace but in one of the linked namespace.\n    if (!find_library_internal(const_cast&lt;android_namespace_t*&gt;(task-&gt;get_start_from()),\n                               task,\n                               &amp;zip_archive_cache,\n                               &amp;load_tasks,\n                               rtld_flags,\n                               search_linked_namespaces || is_dt_needed)) {\n      return false;\n    }\n\n    soinfo* si = task-&gt;get_soinfo();\n\n    if (is_dt_needed) {\n      needed_by-&gt;add_child(si);\n\n      if (si-&gt;is_linked()) {\n        si-&gt;increment_ref_count();\n      }\n    }\n\n    \/\/ When ld_preloads is not null, the first\n    \/\/ ld_preloads_count libs are in fact ld_preloads.\n    if (ld_preloads != nullptr &amp;&amp; soinfos_count &lt; ld_preloads_count) {\n      ld_preloads-&gt;push_back(si);\n    }\n\n    if (soinfos_count &lt; library_names_count) {\n      soinfos[soinfos_count++] = si;\n    }\n  }\n\n  \/\/ Step 2: Load libraries in random order (see b\/24047022)\n  LoadTaskList load_list;\n  for (auto&amp;&amp; task : load_tasks) {\n    soinfo* si = task-&gt;get_soinfo();\n    auto pred = [&amp;](const LoadTask* t) {\n      return t-&gt;get_soinfo() == si;\n    };\n\n    if (!si-&gt;is_linked() &amp;&amp;\n        std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {\n      load_list.push_back(task);\n    }\n  }\n  shuffle(&amp;load_list);\n\n  for (auto&amp;&amp; task : load_list) {\n    LD_LOG(kLogDlopen,\"[linker.cpp] Step2 list all task %s \",task-&gt;get_name());\n    if (!task-&gt;load()) {\n      return false;\n    }\n  }\n\n  \/\/ Step 3: pre-link all DT_NEEDED libraries in breadth first order.\n  for (auto&amp;&amp; task : load_tasks) {\n    soinfo* si = task-&gt;get_soinfo();\n    if (!si-&gt;is_linked() &amp;&amp; !si-&gt;prelink_image()) {\n      return false;\n    }\n  }\n\n  \/\/ Step 4: Construct the global group. Note: DF_1_GLOBAL bit of a library is\n  \/\/ determined at step 3.\n\n  \/\/ Step 4-1: DF_1_GLOBAL bit is force set for LD_PRELOADed libs because they\n  \/\/ must be added to the global group\n  if (ld_preloads != nullptr) {\n    for (auto&amp;&amp; si : *ld_preloads) {\n      si-&gt;set_dt_flags_1(si-&gt;get_dt_flags_1() | DF_1_GLOBAL);\n    }\n  }\n\n  \/\/ Step 4-2: Gather all DF_1_GLOBAL libs which were newly loaded during this\n  \/\/ run. These will be the new member of the global group\n  soinfo_list_t new_global_group_members;\n  for (auto&amp;&amp; task : load_tasks) {\n    soinfo* si = task-&gt;get_soinfo();\n    if (!si-&gt;is_linked() &amp;&amp; (si-&gt;get_dt_flags_1() &amp; DF_1_GLOBAL) != 0) {\n      new_global_group_members.push_back(si);\n    }\n  }\n\n  \/\/ Step 4-3: Add the new global group members to all the linked namespaces\n  for (auto si : new_global_group_members) {\n    for (auto linked_ns : *namespaces) {\n      if (si-&gt;get_primary_namespace() != linked_ns) {\n        linked_ns-&gt;add_soinfo(si);\n        si-&gt;add_secondary_namespace(linked_ns);\n      }\n    }\n  }\n\n  \/\/ Step 5: link libraries that are not destined to this namespace.\n  \/\/ Do this by recursively calling find_libraries on the namespace where the lib\n  \/\/ was found during Step 1.\n  for (auto&amp;&amp; task : load_tasks) {\n    soinfo* si = task-&gt;get_soinfo();\n    if (si-&gt;get_primary_namespace() != ns) {\n      const char* name = task-&gt;get_name();\n        \/\/\u8fd9\u91cc\u53ef\u4ee5\u770b\u51fa\u5148\u9012\u5f52needed_by\u3002\n      if (find_libraries(si-&gt;get_primary_namespace(), task-&gt;get_needed_by(), &amp;name, 1,\n                         nullptr \/* soinfos *\/, nullptr \/* ld_preloads *\/, 0 \/* ld_preload_count *\/,\n                         rtld_flags, nullptr \/* extinfo *\/, false \/* add_as_children *\/,\n                         false \/* search_linked_namespaces *\/, readers_map, namespaces)) {\n        \/\/ If this lib is directly needed by one of the libs in this namespace,\n        \/\/ then increment the count\n        soinfo* needed_by = task-&gt;get_needed_by();\n        if (needed_by != nullptr &amp;&amp; needed_by-&gt;get_primary_namespace() == ns &amp;&amp; si-&gt;is_linked()) {\n          si-&gt;increment_ref_count();\n        }\n      } else {\n        return false;\n      }\n    }\n  }\n\n  \/\/ Step 6: link libraries in this namespace\n  soinfo_list_t local_group;\n  walk_dependencies_tree(\n      (start_with != nullptr &amp;&amp; add_as_children) ? &amp;start_with : soinfos,\n      (start_with != nullptr &amp;&amp; add_as_children) ? 1 : soinfos_count,\n      [&amp;] (soinfo* si) {\n    if (ns-&gt;is_accessible(si)) {\n      local_group.push_back(si);\n      return kWalkContinue;\n    } else {\n      return kWalkSkip;\n    }\n  });\n  LD_LOG(kLogDlopen,\"[linker.cpp] link libraries in this namespace\");\n  soinfo_list_t global_group = ns-&gt;get_global_group();\n  bool linked = local_group.visit([&amp;](soinfo* si) {\n    if (!si-&gt;is_linked()) {\n      LD_LOG(kLogDlopen,\"so %s is not linked , now try to link \",si-&gt;get_soname());\n      if (!si-&gt;link_image(global_group, local_group, extinfo) ||\n          !get_cfi_shadow()-&gt;AfterLoad(si, solist_get_head())) {\n        return false;\n      }\n    }\n\n    return true;\n  });\n  LD_LOG(kLogDlopen,\"[linker.cpp] all link libraries in this namespace has linker\");\n  if (linked) {\n    local_group.for_each([](soinfo* si) {\n      LD_LOG(kLogDlopen,\"travser local_group list %s\" , si-&gt;get_soname());\n      if (!si-&gt;is_linked()) {\n        si-&gt;set_linked();\n      }\n    });\n\n    failure_guard.Disable();\n  }\n\n  return linked;\n}\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Android \u7248\u672c\uff1aandroid-8.0.0_r4 \u76ee\u7684 elf\u7684\u52a0\u8f7d\u8fc7\u7a0b \u5728so\u52a0\u8f7d\u8fc7\u7a0b\u4e2d\u786e\u5b9a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[9],"tags":[],"_links":{"self":[{"href":"http:\/\/pareto.fun\/index.php?rest_route=\/wp\/v2\/posts\/105"}],"collection":[{"href":"http:\/\/pareto.fun\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/pareto.fun\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/pareto.fun\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/pareto.fun\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=105"}],"version-history":[{"count":7,"href":"http:\/\/pareto.fun\/index.php?rest_route=\/wp\/v2\/posts\/105\/revisions"}],"predecessor-version":[{"id":216,"href":"http:\/\/pareto.fun\/index.php?rest_route=\/wp\/v2\/posts\/105\/revisions\/216"}],"wp:attachment":[{"href":"http:\/\/pareto.fun\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=105"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/pareto.fun\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=105"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/pareto.fun\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=105"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}