React-native series Android--soloader load dynamic link library

Source: Internet
Author: User

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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.