沉舟侧畔千帆进,病树前头万木春。这篇文章主要讲述android 加载so的流程相关的知识,希望能为你提供帮助。
源码版本:android-4.4.4_r1
以
[java.lang.Runtime ->
load()]
为例来说明(loadLiabrary() 最后和 load() 殊途同归,有兴趣的可以自行分析),对应的 Android 源码在
[srcAndroid/libcore/luni/src/main/java/java/lang/Runtime.java/home/shanyu/srcAndroid/libcore/luni/src/main/java/java/lang/Runtime.java],
从 320 行开始。
/** * Loads and links the dynamic library that is identified through the * specified path. This method is similar to {@link #loadLibrary(String)}, * but it accepts a full path specification whereas {@code loadLibrary} just * accepts the name of the library to load. * * @param pathName *the absolute (platform dependent) path to the library to load. * @throws UnsatisfiedLinkError *if the library can not be loaded. */ public void load(String pathName) { load(pathName, VMStack.getCallingClassLoader()); }/* * Loads and links the given library without security checks. */ void load(String pathName, ClassLoader loader) { if (pathName == null) { throw new NullPointerException("pathName == null"); } String error = doLoad(pathName, loader); if (error != null) { throw new UnsatisfiedLinkError(error); } }
【android 加载so的流程】最终调用了doLoad(String name, ClassLoader loader)函数,这个函数仍然在Runtime.java文件中:
private String doLoad(String name, ClassLoader loader) { // Android apps are forked from the zygote, so they can‘t have a custom LD_LIBRARY_PATH, // which means that by default an app‘s shared library directory isn‘t on LD_LIBRARY_PATH.// The PathClassLoader set up by frameworks/base knows the appropriate path, so we can load // libraries with no dependencies just fine, but an app that has multiple libraries that // depend on each other needed to load them in most-dependent-first order.// We added API to Android‘s dynamic linker so we can update the library path used for // the currently-running process. We pull the desired path out of the ClassLoader here // and pass it to nativeLoad so that it can call the private dynamic linker API.// We didn‘t just change frameworks/base to update the LD_LIBRARY_PATH once at the // beginning because multiple apks can run in the same process and third party code can // use its own BaseDexClassLoader.// We didn‘t just add a dlopen_with_custom_LD_LIBRARY_PATH call because we wanted any // dlopen(3) calls made from a .so‘s JNI_OnLoad to work too.// So, find out what the native library search path is for the ClassLoader in question... String ldLibraryPath = null; if (loader != null & & loader instanceof BaseDexClassLoader) { ldLibraryPath = ((BaseDexClassLoader) loader).getLdLibraryPath(); } // nativeLoad should be synchronized so there‘s only one LD_LIBRARY_PATH in use regardless // of how many ClassLoaders are in the system, but dalvik doesn‘t support synchronized // internal natives. synchronized (this) { return nativeLoad(name, loader, ldLibraryPath); } }// TODO: should be synchronized, but dalvik doesn‘t support synchronized internal natives. private static native String nativeLoad(String filename, ClassLoader loader, String ldLibraryPath);
最终调用到了"String nativeLoad(String filename, ClassLoader loader, String ldLibraryPath)"函数,这个一个native函数,定义位于[srcAndroid/dalvik/vm/native/java_lang_Runtime.cpp]文件中。从64行开始:
/* * static String nativeLoad(String filename, ClassLoader loader, String ldLibraryPath) * * Load the specified full path as a dynamic library filled with * JNI-compatible methods. Returns null on success, or a failure * message on failure. */ static void Dalvik_java_lang_Runtime_nativeLoad(const u4* args, JValue* pResult) { StringObject* fileNameObj = (StringObject*) args[0]; Object* classLoader = (Object*) args[1]; StringObject* ldLibraryPathObj = (StringObject*) args[2]; assert(fileNameObj != NULL); char* fileName = dvmCreateCstrFromString(fileNameObj); if (ldLibraryPathObj != NULL) { char* ldLibraryPath = dvmCreateCstrFromString(ldLibraryPathObj); void* sym = dlsym(RTLD_DEFAULT, "android_update_LD_LIBRARY_PATH"); if (sym != NULL) { typedef void (*Fn)(const char*); Fn android_update_LD_LIBRARY_PATH = reinterpret_cast< Fn> (sym); (*android_update_LD_LIBRARY_PATH)(ldLibraryPath); } else { ALOGE("android_update_LD_LIBRARY_PATH not found; .so dependencies will not work!"); } free(ldLibraryPath); }StringObject* result = NULL; char* reason = NULL; bool success = dvmLoadNativeCode(fileName, classLoader, & reason); if (!success) { const char* msg = (reason != NULL) ? reason : "unknown failure"; result = dvmCreateStringFromCstr(msg); dvmReleaseTrackedAlloc((Object*) result, NULL); }free(reason); free(fileName); RETURN_PTR(result); }
还是传值 + 检查,然后执行 [bool success = dvmLoadNativeCode(fileName, classLoader, & reason); ] ,看下 dvmLoadNativeCode(...) 的代码,位于 vm/Native.cpp # 301 行。
推荐阅读
- Android关于Task的一些实践之SingleTask, SingleInstance和TaskAffinity
- android从IIS/asp.net下载apk文件
- Android全屏(包含3种隐藏顶部状态栏及标题栏和一种隐藏Android 4.0平板底部状态栏的方法)
- 在Android设备上不支持requestAnimationFrame
- 关于android中线程,进程,组件,app的理解
- apple Swift语言新手教程
- Android TextView : “Do not concatenate text displayed with setText”
- android 常见分辨率与DPI对照表
- Android如何改变TextView字体间距