[M85 Migration] Add an evas gl option for rotation
[platform/framework/web/chromium-efl.git] / docs / android_native_libraries.md
1 # Shared Libraries on Android
2 This doc outlines some tricks / gotchas / features of how we ship native code in
3 Chrome on Android.
4
5 [TOC]
6
7 ## Library Packaging
8  * Android J & K (ChromePublic.apk):
9    * `libchrome.so` is stored compressed and extracted by Android during installation.
10  * Android L & M (ChromeModernPublic.apk):
11    * `libchrome.so` is stored uncompressed within the apk (with the name `crazy.libchrome.so` to avoid extraction).
12    * It is loaded directly from the apk (without extracting) by `mmap()`'ing it.
13  * Android N, O & P (MonochromePublic.apk):
14    * `libmonochrome.so` is stored uncompressed (AndroidManifest.xml attribute disables extraction) and loaded directly from the apk (functionality now supported by the system linker).
15  * Android Q (TrichromeChrome.aab+TrichromeLibrary.apk):
16    * `libmonochrome.so` is stored in the shared library apk (TrichromeLibrary.apk) instead of in the Chrome apk, so that it can be shared with TrichromeWebView. It's stored uncompressed and loaded directly from the apk the same way as on N-P. Trichrome uses the same native library as Monochrome, so it's still called `libmonochrome.so`.
17
18 ## Build Variants (eg. monochrome_64_32_apk)
19 The packaging above extends to cover both 32-bit and 64-bit device
20 configurations.
21
22 Chrome and ChromeModern support 64-bit builds, but these do not ship to Stable.
23 The system Webview APK that ships to those devices contains a 32-bit library,
24 and for 64-bit devices, a 64-bit library as well (32-bit Webview client apps
25 will use the 32-bit library, and vice-versa).
26
27 ### Monochrome
28 Monochrome's intent was to eliminate the duplication between the 32-bit Chrome
29 and Webview libraries (most of the library is identical). In 32-bit Monochrome,
30 a single combined library serves both Chrome and Webview needs. The 64-bit
31 version adds an extra Webview-only library.
32
33 More recently, additional Monochrome permutations have arrived. First, Google
34 Play will eventually require that apps offer a 64-bit version to compatible
35 devices. In Monochrome, this implies swapping the architecture of the Chrome and
36 Webview libraries (64-bit combined lib, and extra 32-bit Webview lib). Further
37 down the road, silicon vendors may drop 32-bit support from their chips, after
38 which a pure 64-bit version of Monochrome will apply. In each of these cases,
39 the library name of the combined and Webview-only libraries must match (an
40 Android platform requirement), so both libs are named libmonochrome.so (or
41 libmonochrome_64.so in the 64-bit browser case).
42
43 Since 3 of these variations require a 64-bit build config, it makes sense to
44 also support the 4th variant on 64-bit, thus allowing a single builder to build
45 all variants (if desired). Further, a naming scheme must exist to disambiguate
46 the various targets:
47
48 **monochrome_(browser ABI)_(extra_webview ABI)**
49
50 For example, the 64-bit browser version with extra 32-bit Webview is
51 **monochrome_64_32_apk**. The combinations are as follows:
52
53 Builds on | Variant | Description
54 --- | --- | ---
55 32-bit | monochrome | The original 32-bit-only version
56 64-bit | monochrome | The original 64-bit version, with 32-bit combined lib and 64-bit Webview. This would be named monochrome_32_64_apk if not for legacy naming.
57 64-bit | monochrome_64_32 | 64-bit combined lib with 32-bit Webview library.
58 64-bit | monochrome_64 | 64-bit combined lib only, for eventual pure 64-bit hardware.
59 64-bit | monochrome_32 | A mirror of the original 32-bit-only version on 64-bit, to allow building all products on one builder. The result won't be bit-identical to the original, since there are subtle compilation differences.
60
61 ### Trichrome
62 Trichrome has the same 4 permutations as Monochrome, but adds another dimension.
63 Trichrome returns to separate apps for Chrome and Webview, but places shared
64 resources in a third shared-library APK. The table below shows which native
65 libraries are packaged where. Note that **dummy** placeholder libraries are
66 inserted where needed, since Android determines supported ABIs from the presence
67 of native libraries, and the ABIs of a shared library APK must match its client
68 app.
69
70 Builds on | Variant | Chrome | Library | Webview
71 --- | --- | --- | --- | ---
72 32-bit | trichrome | `32/dummy` | `32/combined` | `32/dummy`
73 64-bit | trichrome | `32/dummy`, `64/dummy` | `32/combined`, `64/dummy` | `32/dummy`, `64/webview`
74 64-bit | trichrome_64_32 | `32/dummy`, `64/dummy` | `32/dummy`, `64/combined` | `32/webview`, `64/dummy`
75 64-bit | trichrome_64 | `64/dummy` | `64/combined` | `64/dummy`
76 64-bit | trichrome_32 | `32/dummy` | `32/combined` | `32/dummy`
77
78 ## Crashpad Packaging
79  * Crashpad is a native library providing out-of-process crash dumping. When a
80    dump is requested (e.g. after a crash), a Crashpad handler process is started
81    to produce a dump.
82  * Chrome and ChromeModern (Android J through M):
83    * libchrome_crashpad_handler.so is a standalone executable containing all of
84      the crash dumping code. It is stored compressed and extracted automatically
85      by the system, allowing it to be directly executed to produce a crash dump.
86  * Monochrome (N through P) and SystemWebView (L through P):
87     * All of the Crashpad code is linked into the package's main native library
88       (e.g. libmonochrome.so). When a dump is requested, /system/bin/app_process
89       is executed, loading CrashpadMain.java which in turn uses JNI to call into
90       the native crash dumping code. This approach requires building CLASSPATH
91       and LD_LIBRARY_PATH variables to ensure app_process can locate
92       CrashpadMain.java and any native libraries (e.g. system libraries, shared
93       libraries, split apks, etc.) the package's main native library depends on.
94  * Monochrome, Trichrome, and SystemWebView (Q+):
95     * All of the Crashpad handler code is linked into the package's native
96       library. libcrashpad_handler_trampoline.so is a minimal executable
97       packaged with the main native library, stored uncompressed and left
98       unextracted. When a dump is requested, /system/bin/linker is executed to
99       load the trampoline from the APK, which in turn `dlopen()`s the main
100       native library to load the remaining Crashpad handler code. A trampoline
101       is used to de-duplicate shared code between Crashpad and the main native
102       library packaged with it. This approach isn't used for P- because the
103       linker doesn't support loading executables on its command line until Q.
104       This approach also requires building a suitable LD_LIBRARY_PATH to locate
105       any shared libraries Chrome/WebView depends on.
106
107 ## Debug Information
108 **What is it?**
109  * Sections of an ELF that provide debugging and symbolization information (e.g. ability convert addresses to function & line numbers).
110
111 **How we use it:**
112  * ELF debug information is too big to push to devices, even for local development.
113  * All of our APKs include `.so` files with debug information removed via `strip`.
114  * Unstripped libraries are stored at `out/Default/lib.unstripped`.
115    * Many of our scripts are hardcoded to look for them there.
116
117 ## Unwind Info & Frame Pointers
118 **What are they:**
119  * Unwind info is data that describes how to unwind the stack. It is:
120    * It is required to support C++ exceptions (which Chrome doesn't use).
121    * It can also be used to produce stack traces.
122    * It is generally stored in an ELF section called `.eh_frame` & `.eh_frame_hdr`, but arm32 stores it in `.ARM.exidx` and `.ARM.extab`.
123      * You can see these sections via: `readelf -S libchrome.so`
124  * "Frame Pointers" is a calling convention that ensures every function call has the return address pushed onto the stack.
125    * Frame Pointers can also be used to produce stack traces (but without entries for inlined functions).
126
127 **How we use them:**
128  * We disable unwind information (search for [`exclude_unwind_tables`](https://cs.chromium.org/search/?q=exclude_unwind_tables+file:%5C.gn&type=cs)).
129  * For all architectures except arm64, we disable frame pointers in order to reduce binary size (search for [`enable_frame_pointers`](https://cs.chromium.org/search/?q=enable_frame_pointers+file:%5C.gn&type=cs)).
130  * Crashes are unwound offline using `minidump_stackwalk`, which can create a stack trace given a snapshot of stack memory and the unstripped library (see [//docs/testing/using_breakpad_with_content_shell.md](testing/using_breakpad_with_content_shell.md))
131  * To facilitate heap profiling, we ship unwind information to arm32 canary & dev channels as a separate file: `assets/unwind_cfi_32`
132
133 ## JNI Native Methods Resolution
134  * For ChromePublic.apk and ChromeModernPublic.apk:
135    * `JNI_OnLoad()` is the only exported symbol (enforced by a linker script).
136    * Native methods registered explicitly during start-up by generated code.
137      * Explicit generation is required because the Android runtime uses the system's `dlsym()`, which doesn't know about Crazy-Linker-opened libraries.
138  * For MonochromePublic.apk and TrichromeChrome.aab:
139    * `JNI_OnLoad()` and `Java_*` symbols are exported by linker script.
140    * No manual JNI registration is done. Symbols are resolved lazily by the runtime.
141
142 ## Packed Relocations
143  * All flavors of `lib(mono)chrome.so` enable "packed relocations", or "APS2 relocations" in order to save binary size.
144    * Refer to [this source file](https://android.googlesource.com/platform/bionic/+/refs/heads/master/tools/relocation_packer/src/delta_encoder.h) for an explanation of the format.
145  * To process these relocations:
146    * Pre-M Android: Our custom linker must be used.
147    * M+ Android: The system linker understands the format.
148  * To see if relocations are packed, look for `LOOS+#` when running: `readelf -S libchrome.so`
149  * Android P+ [supports an even better format](https://android.googlesource.com/platform/bionic/+/8b14256/linker/linker.cpp#2620) known as RELR.
150    * We'll likely switch non-Monochrome apks over to using it once it is implemented in `lld`.
151
152 ## RELRO Sharing
153 **What is it?**
154  * RELRO refers to the ELF segment `GNU_RELRO`. It contains data that the linker marks as read-only after it applies relocations.
155    * To inspect the size of the segment: `readelf --segments libchrome.so`
156    * For `lib(mono)chrome.so` on arm32, it's about 2mb.
157  * If two processes map this segment to the same virtual address space, then pages of memory within the segment which contain only relative relocations (99% of them) will be byte-for-byte identical.
158    * Note: For `fork()`ed processes, all pages are already shared (via `fork()`'s copy-on-write semantics), so RELRO sharing does not apply to them.
159  * "RELRO sharing" is when this segment is copied into shared memory and shared by multiple processes.
160
161 **How does it work?**
162  * For Android < N (crazy linker):
163    1. Browser Process: `libchrome.so` loaded normally.
164    2. Browser Process: `GNU_RELRO` segment copied into `ashmem` (shared memory).
165    3. Browser Process (low-end only): RELRO private memory pages swapped out for ashmem ones (using `munmap()` & `mmap()`).
166    4. Browser Process: Load address and shared memory fd passed to renderers / gpu process.
167    5. Renderer Process: Crazy linker tries to load to the given load address.
168       * Loading can fail due to address space randomization causing something else to already by loaded at the address.
169    6. Renderer Process: If loading to the desired address succeeds:
170       * Linker puts `GNU_RELRO` into private memory and applies relocations as per normal.
171       * Afterwards, memory pages are compared against the shared memory and all identical pages are swapped out for ashmem ones (using `munmap()` & `mmap()`).
172  * For a more detailed description, refer to comments in [Linker.java](https://cs.chromium.org/chromium/src/base/android/java/src/org/chromium/base/library_loader/Linker.java).
173  * For Android N-P:
174    * The OS maintains a RELRO file on disk with the contents of the GNU_RELRO segment.
175    * All Android apps that contain a WebView load `libmonochrome.so` at the same virtual address and apply RELRO sharing against the memory-mapped RELRO file.
176    * Chrome uses `MonochromeLibraryPreloader` to call into the same WebView library loading code.
177      * When Monochrome is the WebView provider, `libmonochrome.so` is loaded with the system's cached RELRO's applied.
178    * `System.loadLibrary()` is called afterwards.
179      * When Monochrome is the WebView provider, this only calls JNI_OnLoad, since the library is already loaded. Otherwise, this loads the library and no RELRO sharing occurs.
180  * For non-low-end Android O-P (where there's a WebView zygote):
181    * For non-renderer processes, the above Android N+ logic applies.
182    * For renderer processes, the OS starts all Monochrome renderer processes by `fork()`ing the WebView zygote rather than the normal application zygote.
183      * In this case, RELRO sharing would be redundant since the entire process' memory is shared with the zygote with copy-on-write semantics.
184  * For Android Q+ (Trichrome):
185    * For non-renderer processes, TrichromeChrome no longer shares its RELRO data with WebView and no RELRO sharing occurs. TrichromeWebView works the same way as on Android N-P.
186    * For renderer processes, TrichromeChrome `fork()`s from a chrome-specific app zygote. `libmonochrome.so` is loaded in the zygote before `fork()`.
187      * Similar to O-P, app zygote provides copy-on-write memory semantics so RELRO sharing is redundant.
188    * For renderer processes, TrichromeWebView works the same way as on Android N-P.
189
190 ## Partitioned libraries
191 Some Chrome code is placed in feature-specific libraries and delivered via
192 [Dynamic Feature Modules](android_dynamic_feature_modules.md).
193
194 A linker-assisted partitioning system automates the placement of code into
195 either the main Chrome library or feature-specific .so libraries. Feature code
196 may continue to make use of core Chrome code (eg. base::) without modification,
197 but Chrome must call feature code through a virtual interface.
198
199 **How partitioning works**
200
201 The lld linker is now capable of producing a [partitioned
202 library](https://lld.llvm.org/Partitions.html), which is effectively an
203 intermediate single file containing multiple libraries. A separate tool
204 *(llvm-objcopy)* then splits the file into standalone .so files, invoked through
205 a [partitioned shared library](https://cs.chromium.org/chromium/src/build/partitioned_shared_library.gni)
206 GN template.
207
208 The primary partition is Chrome's main library (eg. libchrome.so), and other
209 partitions may contain feature code (eg. libvr.so). By specifying a list of
210 C/C++ symbols to use as entrypoints, the linker can collect all code used only
211 through these entrypoints, and place it in a particular partition.
212
213 To facilitate partitioning, all references from Chrome to the feature
214 entrypoints must be indirect. That is, Chrome must obtain a symbol from the
215 feature library through dlsym(), cast the pointer to its actual type, and call
216 through the resulting pointer.
217
218 Feature code retains the ability to freely call back into Chrome's core code.
219 When loading the library, the feature module system uses the feature name to
220 look up a partition name *(libfoo.so)* in an address offset table built into the
221 main library. The resulting offset is supplied to android_dlopen_ext(), which
222 instructs Android to load the library in a particular reserved address region.
223 This allows the feature library's relative references back to the main library
224 to work, as if the feature code had been linked into the main library
225 originally. No dynamic symbol resolution is required here.
226
227 **Implications on code placement**
228
229 * Any symbol referenced by multiple partitions ends up in the main library (even
230   if all calling libraries are feature partitions).
231 * Symbols that aren't feature code (eg. base::) will be pulled into the
232   feature's library if only that feature uses the code. This is a benefit, but
233   can be unexpected.
234
235 **Builds that support partitioned libraries**
236
237 Partitioned libraries are usable when all of the following are true:
238 * Component build is disabled (component build splits code across GN component
239   target boundaries instead).
240 * The compiler is Clang.
241 * The linker is lld.
242
243 ## Library Prefetching
244  * During start-up, we `fork()` a process that reads a byte from each page of the library's memory (or just the ordered range of the library).
245    * See [//base/android/library_loader/](../base/android/library_loader/).
246
247 ## Historical Tidbits
248  * We used to use the system linker on M (`ModernLinker.java`).
249    * This was removed due to [poor performance](https://bugs.chromium.org/p/chromium/issues/detail?id=719977).
250  * We used to use `relocation_packer` to pack relocations after linking, which complicated our build system and caused many problems for our tools because it caused logical addresses to differ from physical addresses.
251    * We now link with `lld`, which supports packed relocations natively and doesn't have these problems.
252
253 ## See Also
254  * [//docs/android_build_instructions.md#Multiple-Chrome-APK-Targets](android_build_instructions.md#Multiple-Chrome-APK-Targets)
255  * [//third_party/android_crazy_linker/README.chromium](../third_party/android_crazy_linker/README.chromium)
256  * [//base/android/linker/BUILD.gn](../base/android/linker/BUILD.gn)