Theoretical basis
We are bound to deal with more SO loading in the process of Android development projects, so what is the order and process of so loading in the system, we need to be familiar with this loading process. The loading of SO is an analytical loading, which is different from dex to some extent. Dex is loaded for optimization verification to generate Odex, and then the odex file is parsed, while SO is more like loading while parsing, and the load segment is mainly parsed during the loading process. The following is mainly based on the Java layer so load from the source code to parse the load process.
Analysis of Java layer SO loading process
System. LoadLibrary entry point
In the Java layer, we know that loading the so file is realized through the System. LoadLibrary function. The following will be used as the entry point to analyze its call relationship and implementation. System.loadlibrary is defined in the source/libcore/luni/SRC/main/Java/Java/lang/System.
The following is an implementation of its function definition.
// The argument is the name of the so file to load
public static void loadLibrary(String libName) {
// This is done by calling the loadLibrary function under Runtime
// The function takes two arguments, argument 1 is the file name of the loaded so, and argument 2 is the class loader.
Runtime.getRuntime().loadLibrary(libName, VMStack.getCallingClassLoader());
}
Copy the code
The Runtime loadLibray
The loadLibray function is defined in the Runtime. Java file. The loadLibrary function of Runtime is located in the Android file source\libcore\luni\ SRC \main\ Java \ Java \lang\ runtime. Java.
The loadLibrary function of Runtime is defined below.
/* * Searches for and loads the given shared library using the given ClassLoader. */
void loadLibrary(String libraryName, ClassLoader loader) {
if(loader ! =null) {
// Use the loader to find the name of the so file to load
String filename = loader.findLibrary(libraryName);
// Failed to find
if (filename == null) {
// It's not necessarily true that the ClassLoader used
// System.mapLibraryName, but the default setup does, and it's
// misleading to say we didn't find "libMyLibrary.so" when we
// actually searched for "liblibMyLibrary.so.so".
throw new UnsatisfiedLinkError(loader + " couldn't find \"" +
System.mapLibraryName(libraryName) + "\" ");
}
// Load the so file name
String error = doLoad(filename, loader);
if(error ! =null) {
throw new UnsatisfiedLinkError(error);
}
return;
}
String filename = System.mapLibraryName(libraryName);
List<String> candidates = new ArrayList<String>();
String lastError = null;
// Loop over the file path
for (String directory : mLibPaths) {
// Concatenate the file path and file name
String candidate = directory + filename;
candidates.add(candidate);
if (IoUtils.canOpenReadOnly(candidate)) {
String error = doLoad(candidate, loader);
if (error == null) {
return; // We successfully loaded the library. Job done.} lastError = error; }}if(lastError ! =null) {
throw new UnsatisfiedLinkError(lastError);
}
throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
}
Copy the code
The Runtime doLoad
DoLoad: loadLibrary: doLoad: doLoad: loadLibrary: doLoad: doLoad: doLoad: doLoad: doLoad: doLoad: doLoad: doLoad: doLoad: doLoad: doLoad: The doload function under Rutime is in the source\libcore\luni\ SRC \main\ Java \ Java \lang\ runtime. Java file on the system.
The following code is a defined implementation of the Runtime doload function.
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) {
returnnativeLoad(name, loader, ldLibraryPath); }}Copy the code
conclusion
From the above source code implementation process analysis, we can see that Android loading so in the Java layer interface is system.loadLibrary (), through the hierarchical relationship to realize the Java layer loading so.
Below is a detailed Java layer-loaded so call.