Android native library merging

Visit the post for more.

David Reiss
9 min readintermediate
--
View Original

Overview

The article discusses a scalable solution developed by Facebook for merging native libraries in Android applications to overcome the native library limit in older Android versions. It details the challenges faced and the techniques implemented, such as renaming symbols and using custom ELF sections, to ensure performance is maintained while reducing app size.

What You'll Learn

1

How to merge native libraries in Android applications

2

Why managing JNI_OnLoad symbols is crucial for library merging

3

How to utilize Buck for custom library linking

Prerequisites & Requirements

  • Understanding of C++ and JNI
  • Familiarity with Buck build system(optional)

Key Questions Answered

How does Facebook merge native libraries in Android apps?
Facebook merges native libraries by integrating a feature into their Buck build system that allows apps to specify which libraries to merge. This process involves renaming JNI_OnLoad functions to avoid symbol conflicts and using custom ELF sections to register these functions for proper loading.
What challenges arise when merging JNI_OnLoad functions?
The main challenge is the duplication of the JNI_OnLoad symbol across multiple libraries. Facebook addresses this by renaming each library's JNI_OnLoad function and using custom ELF sections to manage the loading of these renamed functions without conflicts.
What is the impact of merging native libraries on app performance?
Merging native libraries allows Facebook to avoid the native library limit on older Android devices without harming performance or increasing app size. This optimization enables better inter-library optimizations during the linking process.
How can developers determine which libraries to merge?
Developers can use a script provided by Facebook that analyzes the APK to visualize library dependencies and identify which libraries are suitable for merging, particularly those loaded during app startup or those with similar names.

Technologies & Tools

Build System
Buck
Used for managing the build process and linking libraries in the Android applications.
Library Loading
Soloader
Facilitates the loading of native libraries and helps manage the mapping of original library names to merged names.

Key Actionable Insights

1
Implement a library merging strategy to optimize your Android applications.
By merging libraries, you can reduce the number of native libraries your app uses, which is particularly beneficial for older Android versions that have a library limit. This can lead to improved performance and reduced app size.
2
Utilize custom ELF sections for managing JNI_OnLoad functions effectively.
This technique allows you to avoid symbol conflicts when merging libraries, ensuring that each library's JNI_OnLoad function is registered correctly without causing issues during the loading process.
3
Leverage the Buck build system for custom library linking.
Integrating library merging into your build system can streamline the process and help manage dependencies more effectively, particularly in large codebases with multiple applications.

Common Pitfalls

1
Failing to manage symbol conflicts when merging libraries can lead to runtime errors.
This issue arises when multiple libraries define the same symbol, such as JNI_OnLoad. Properly renaming these symbols and using custom ELF sections can help avoid this problem.
2
Not analyzing library dependencies before merging can result in unnecessary code being loaded.
Merging libraries without understanding their interdependencies can lead to larger APK sizes and slower performance. Using analysis tools to visualize dependencies is essential.

Related Concepts

Jni
C++
Android Development
Library Management
Build Systems