Soloader is a small, open-source project for loading so library files from Facebook , with the primary role of automatically checking and loading multiple dependent so library files. In the Android platform, react-native projects use a large number of dynamic link libraries, the JNI technology, as Java and Javascript Communication bridge between the two programming languages.
Unzip the installer package for a react-native project apk file, and we can see a total of one so library file, where Libreactnativejni.so is the entrance to the JNI Bridge.
and libreactnativejni.so relies on the following two so files:
libfb.so
libfbjni.so
libfolly_json.so
libjsc.so
libglog.so
libgnustl_shared.so
libandroid.so
liblog.so
libstdc++.so
libm.so
libc.so
Libdl.so
Among them, the first 6 are react-native 's own dynamic link library, the latter 6 is the Android system dynamic link library, so if you want to load libreactnativejni.so Library, you must first load the two library files on which it depends. The last 6 system library files are preloaded by the system into the Dalvik virtual machine inside, can not be processed, but the first 6 must be manually preloaded! However, if a library file is dependent on another library file, it must load its dependent library files before loading itself.
This, in fact, is a recursive load dependent process, if it is by artificial to maintain this dependency, first extremely cumbersome, and then the maintainability of the code is greatly reduced. Fortunately, the dependent libraries are automatically checked and loaded after the android 4.3 version (including), but react-native is compatible with the android 4.1 version, So Soloader is a technology solution that is compatible with the following versions of 4.3 .
Soloader is a lightweight, less than 20 files that can be used directly in any Android project, not limited to react-native.
GitHub Open Source Address: Https://github.com/facebook/SoLoader
Let us examine the implementation principles of the following Soloader .
First, the Soloader needs to be initialized before loading the library file, and the main purpose is to collect all of the so library files (the System + Project itself) in advance, and look for them after loading.
Take a look at the init method of Com.facebook.soloader.SoLoader .
First step: Collect System Library files
Arraylist<sosource> sosources =NewArraylist<> ();StringLd_library_path = System.getenv ("Ld_library_path");if(Ld_library_path = =NULL) {Ld_library_path ="/vendor/lib:/system/lib"; }String[] systemlibrarydirectories = Ld_library_path.Split(":"); for(inti =0; i < systemlibrarydirectories.length; ++i) {File systemsodirectory =NewFile (Systemlibrarydirectories[i]); Sosources.add (NewDirectorysosource (Systemsodirectory,directorysosource.on_ld_library_path)); }
The system library file is mainly under two directories, the/vendor/lib directory and /system/lib directory, the first collection of these two Directorysosource .
Step two: Collect the current app's library file
int oursosourceflags = 0 ; //on old versions of Android, Bionic doesn ' t add our library directory to its internal Span class= "hljs-comment" >//search path, and the system doesn ' t resolve dependencies between modules we ship. On //these systems, we resolve dependencies ourselves. On other systems, Bionic ' s built-in //resolver suffices. if (Build.VERSION.SDK_INT <= build.version_codes. JELLY_BEAN_MR1) {oursosourceflags |= directorysosource.resolve_dependencies;} Sosource Oursosource = new directorysosource (new File (Applicationinfo.nativelibrarydir), oursosourceflags), Sosources.add (0 , Oursosource);
Nativelibrarydir points to the /data/app-lib/[package-name]-n directory. Because of the Android 4.2 version and above, the dependency is automatically processed, so add a flag resolve_dependencieshere, which means that loading the library file is loaded directly and does not need to find dependencies.
Step three: Resolve dependencies before loading library files
This process is the most complex step, involving the decoding of ELF files. The ELF file, formerly known as executable and linking Format, consists of roughly three types: relocatable files, dynamic link library files, executables. The so extension file, commonly used in Android , refers to the dynamic link library file in the system.
ELF File related information, detailed can refer to the following two articles:
Http://blog.chinaunix.net/uid-21273878-id-1828736.html
Http://blog.chinaunix.net/uid-72446-id-2060531.html
The following is an ELF file decoding, the main purpose is to find the dynamic link library of the dependent Library. Code is located in the com.facebook.soloader.MinElf extract_dt_needed method, the code is longer, we step by step to see:
ByteBuffer bb = ByteBuffer.allocate(8/* largest read unit */); // Read ELF header. bb.order(ByteOrder.LITTLE_ENDIAN); if (getu32(fc, bb, Elf32_Ehdr.e_ident) != ELF_MAGIC) { thrownew ElfError("file is not ELF"); }
First read the elf file header information, the value ofelf_magic is 0x464c457f, indicating that this is an elf format file , where the character E , the4c represents the character L, and the string represents the character F.
boolean is32 = (getu8(fc, bb, Elf32_Ehdr.e0x41);if (getu8(fc, bb, Elf32_Ehdr.e0x52) { bb.order(ByteOrder.BIG_ENDIAN);}
The 5 bytes represent the file type, with a value of 0(illegal target file),1(32-bit target file),2(64-bit target file).
The 6 bytes represent the encoding format, with a value of 0(illegal encoding format),1(Low-end encoding format), and2(big-endian encoding format).
Long E_phoff = is32? Getu32 (FC, BB, ELF32_EHDR. E_phoff): Get64 (FC, BB, ELF64_EHDR. E_phoff);Long E_phnum = is32? Getu16 (FC, BB, ELF32_EHDR. E_phnum): getu16 (FC, BB, ELF64_EHDR. E_phnum);int e_phentsize = is32? Getu16 (FC, BB, ELF32_EHDR. E_phentsize): getu16 (FC, BB, ELF64_EHDR. E_phentsize);if (E_phnum = = Pn_xnum) {//overflowed into section[0]. SH_info long E_shoff = is32? Getu32 (FC, BB, ELF32_EHDR. E_shoff): Get64 (FC, BB, ELF64_EHDR. E_shoff);Long Sh_info = is32? Getu32 (FC, BB, E_shoff + ELF32_SHDR. SH_info): getu32 (FC, BB, E_shoff + ELF64_SHDR. SH_info);E_phnum = Sh_info;}
The purpose of this step is to get the number of the head table of the program E_phnum, then iterate through each Header table information and find the starting position of the area where the dynamic link library dependency is located by its p_type value.
long dynstart = 0 ; long phdr = E_phoff; for (long i = 0 ; i < e_phnum; ++i) {long p_type = is32? getu32 (FC, BB, PhDr + elf32_phdr.p_type): Getu32 (FC, BB, PhDr + elf64_phdr.p_type); if (P_type = = pt_dynamic) {long p_offset = is32? getu32 (FC, BB, PhDr + elf32_phdr.p_offset) : Get64 (FC, BB, PhDr + elf64_phdr.p_offset); Dynstart = P_offset; break ; } PhDr + = E_phentsize; }
The p_type value of the Program Header table describing the dynamic link library is pt_dynamic, which is immediately following its 4 bytes relative to the file offset p_offset.
The next step is to calculate the number of dynamically-linked libraries it relies on , mainly by parsing the dynamic section, which contains an array:
typedefstructunion
The value of D_tag is dt_needed , which is 1, which indicates that there is a dynamic link library dependency. The value of D_tag is dt_strtab , which is 5, which indicates that this is the offset index of the table that describes the dynamic link library information.
LongD_tag;intnr_dt_needed =0;Longdyn = Dynstart;LongPtr_dt_strtab =0; Do{D_tag = is32? getu32 (FC, BB, Dyn + Elf32_dyn.d_tag): Get64 (FC, BB, Dyn + Elf64_dyn.d_tag);if(D_tag = = dt_needed) {if(nr_dt_needed = = Integer.max_value) {Throw NewElferror ("Malformed dt_needed section"); } nr_dt_needed + =1; }Else if(D_tag = = Dt_strtab) {ptr_dt_strtab = is32? getu32 (FC, BB, Dyn + Elf32_dyn.d_un): Get64 (FC, BB, Dyn + Elf64_dyn . D_un); } dyn + = Is32?8: -; } while(D_tag! = dt_null);
With the number of dynamic link dependent libraries and the offset index describing this dynamic link library information table, you can read the name of the library to which it depends.
Fourth Step: Loading the library file
Soloader 's loadLibrary method loads a dynamic-link library, such as:
SoLoader.loadLibrary("reactnativejni");
The final call is Directorysosource 's loadLibrary, because libreactnativejni.so is the dynamic link library of the current application, so Directorysosource 's sodirectory is pointing to /data/app-lib/[package-name]-n.
Public int loadLibrary(String SoName,intLoadflags)throwsIOException {File Sofile =NewFile (Sodirectory, soName);if(!sofile.exists ()) {returnLoad_result_not_found; }if((Loadflags & load_flag_allow_implicit_provision)! =0&& (Flags & on_ld_library_path)! =0) {returnload_result_implicitly_provided; }if((Flags & resolve_dependencies)! =0) {String dependencies[] = minelf.extract_dt_needed (sofile); for(inti =0; i < dependencies.length; ++i) {String dependency = dependencies[i];if(Dependency.startswith ("/")) {Continue; } Soloader.loadlibrarybysoname (Dependency, (Loadflags | load_flag_allow_implicit_provision)); }} system.load (Sofile.getabsolutepath ());returnload_result_loaded; }
The dependent library file is parsed by the minelf.extract_dt_needed method and then recursively called the soloader.loadlibrarybysoname method to load the dependent libraries.
If the dependent library file is a dynamic link library of the system, such as libandroid.so, because it is under /system/lib , the corresponding Directorysosource is called to load, In this scenario, the load_result_implicitly_providedis returned automatically because the library is already loaded by the system.
If the dependent library file is also the currently applied dynamic link library, such as libfb.so, first to parse the libfb.so dependent library file, repeat the above process. Until the last dependent dynamic link insecure library load is completed, the last call to the system's system.load method loads itself.
Summarize
Domestic Android applications rarely have more than 5 dynamic link libraries, even if the dynamic link libraries are independent of each other (from the major domestic service providers, such as Baidu maps, etc.), and like react-native This is rare for applications that rely heavily on JNI technology, but if so, using Soloader can greatly improve the code quality of the program!
This blog is not regularly updated continuously, welcome attention and Exchange:
Http://blog.csdn.net/megatronkings
React-native series Android--soloader load dynamic link library