Click here to Skip to main content
15,868,066 members
Articles / Mobile Apps / Android
Article

Native Library Compression SDK for Android* Apps

Rate me:
Please Sign up or sign in to vote.
4.20/5 (2 votes)
18 Sep 2014CPOL5 min read 11.3K   5  
To solve the FAT APK size problem, the author has developed a native library compression SDK.

This article is for our sponsors at CodeProject. These articles are intended to provide you with information on products and services that we consider useful and of value to developers

Introduction

Android apps are typically written in Java* because of its elegant object-oriented design and the fact that the Android Software Development Kit (Android SDK) provides cross-platform features in Java. At times, however, developers need to use Android’s native interface, especially if memory management and performance are critical issues. Android’s native interface is provided through the Native Development Kit (NDK), which supports native development in C/C++.

There are many NDK apps on the Google software market. To reduce package size, some ISVs release a single APK but not a FAT APK (a single APK contains either an ARM* or an x86 library, while a FAT APK has both). FAT APKs have advantages over single APKs. They are easier for end users to access and the libraries aren’t overlapped during application updating. Developers are, therefore, encouraged to make FAT APKs for the x86 Android software ecosystem. But how can developers mitigate large FAT APK file sizes?

Zip* vs. LZMA

To solve the FAT APK size problem, the author has developed a native library compression SDK. The basic idea uses the Lempel–Ziv–Markov chain algorithm (LZMA) (http://www.7-zip.org/sdk.html) to compress native libraries. Google uses Zip to compress all of the content, and while Zip is fast, its compression rate is lower than LZMA. LZMA is especially good for compressing the large dictionary files found in native libraries. The following graph shows the difference in file sizes after performing compressions with Zip and LZMA.

Image 1

Figure 1: Size comparison of a file after being compressed with Zip* and LZMA1

Image 2

Figure 2: Size comparison of multiple files (same CPU architecture) after being compressed with Zip* and LZMA1

Image 3

Figure 3: Size comparison of multiple files (different CPU architecture) after being compressed with Zip* and LZMA1

Image 4

Figure 4: Size comparison of three identical files after being compressed with Zip* and LZMA1

From the four charts above, we may conclude that LZMA can reduce the redundancy between the files. In the extreme (three identical files), LZMA can get a higher compression rate than Zip. This feature is particularly suitable for compressing native libraries. Generally, a native library will use the same code to get "armeabi","armeabi-v7a","x86" or even "mips" libraries, and for "armeabi-v7a" there is ARM NEON* and non-NEON code as well. These libraries have redundancies due to the same source code. Even with different architecture, for example, libffmpeg_armv7_vfpv3.so and libffmpeg_x86.so, when one is ARMEABI and the other is x86, the compression rate is 40%, while for a single file, the rate is only 20%.

Native Library Compression SDK

The native library compression SDK, the author developed, can help app developer to integrate the LZMA native library compression to obtain smaller files. The core idea of this SDK is to compress the entire native library into the asserts folder as follows.

The API in this SDK is very simple. On the first run of this application, the code extracts the entire native library from the asserts folder.

static boolean NewInstance(Context cont,Handler hdl,boolean showProgress)
	static DecRawso GetInstance()
	String GetPath(String libname)

It is recommended that app developers should modify the source code and add only NewInstance when the application starts, then change system.loadlibrary(***) to system.load(DecRawso . GetInstance ().GetPath(***)). After these minor changes, the APK will be smaller yet run the same as before.

If developers can ensure enough delay from the calling of NewInstance to the first loading of native library, they should call (NewInstance (cont,null,false)) without the Handler. Otherwise, a Handler should be passed to receive the "decode end" asynchronous message.

The author integrated this SDK into MoboPlayer* on an Intel® Atom™ Z2760 processor-based tablet (codenamed Clover Trail). The code calls NewInstance in the synchronization method when users start the app and the splash screen is displayed. Calling NewInsance is transparent to the end user since the decoding is done in the background. The following chart shows the compression result.

Image 5

Table 5: MoboPlayer* FAT APK size compression1

Enhanced Functions of Native Library Compression SDK

Besides the LZMA compression, this SDK provides additional functions to encourage developers to include an x86 native library with the following:

  1. Cloud Storage: ISVs can store the x86 libraries on the cloud server, and these libraries can be downloaded from the server after installation. This action is automatically done on x86 devices and is only enabled when Wi-Fi* is connected.
  2. Missing Library Detection: If x86 libraries are missing, the SDK will automatically re-extract ARM libraries. An ISV can copy the ARM library to the x86 folder to avoid this issue, but it must make sure there is no cross-reference between ARM and x86 libraries.
  3. Java Tool for Packaging: A Java Package Tool is provided to convert normal APKs to LZMA-compressed APKs. This tool supports Windows*, Linux*, and Mac* systems. You can use it as: ComPressApk.jar -a C:/my/test.APK -k c:/key *** ### alias, if "-k" is missing (that is to say, you can just call ComPressApk.jar -a C:/my/test.APK), the Eclipse* default test key will be used to sign this APK. This tool can be integrated into an ants build script to support automatically compiling and publishing.
  4. Filter: The ConfigureFilter function allows you to only extract the necessary libraries. For example, entering ConfigureFilter("libffmpeg", "libffmpeg_armv7_neon.so") means only extract libffmpeg_armv7_neon.so among all of the libraries that start with "libffmpeg". This is useful to decrease the post-install size.

Conclusion

Using the Native Library Compression SDK for your Android apps can significantly decrease the native library package size and benefit applications with large native libraries (generally these applications are video players, browsers, and 3D games). For the source and technical support, please contact the author.

About the Author

Yuming Li (Yuming.li@intel.com) is a software apps engineer in the Intel Software and Services Group. He currently focuses on multimedia-related applications enabling and performance optimization, in particular on Android mobile platforms.

1Results have been estimated based on internal Intel® analysis and are provided for informational purposes only. Any difference in system hardware or software design or configuration may affect actual performance.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Intel is inside more and more Android devices, and we have tools and resources to make your app development faster and easier.


Comments and Discussions