The foreword 0.

A few days ago, I posted an article titled “Optimizing ApK size ABI Filters and ApK Split” on my official account. I received some comments in the comment section saying that the article didn’t go far enough. I asked how the system chooses so libraries under different ABI. How does the current APP fit? What to leave out and what to keep? There are some questions.


Therefore, I decided to write a more article in person to systematically talk about some things about Android CPU architecture, and combined with the adaptation of Dachang apps such as wechat, Alipay, Taobao and other apps, analyze how to adapt our APP development. This paper involves the following issues:

  • What is the ABI?
  • What does the ABI do?
  • How does Dachang APP adapt to different CPU architectures?
  • How does the ABI work?
  • How do we fit in our own apps?
  • ABI split- performance + compatibility is all

In this article, we will answer those questions one by one.

1. What is ABI?

ABI stands for Application Binary Interface.

Different Android devices may use different CPU architectures and therefore support different instruction sets. Each combination of CPU and instruction set has its own application binary interface (or ABI), which defines very precisely how the application’s machine code should interact with the system at run time. You must specify an ABI (Application Binary Interface) for each CPU architecture to be used with your Application.

The ABI contains the following information:

  • Available CPU instruction set (and extended instruction set).
  • Byte order for runtime memory storage and loading. Android is always little-endian.
  • Specifications for passing data between applications and systems (including alignment restrictions), and how stacks and registers are used when the system calls functions.
  • The format of executable binaries, such as programs and shared libraries, and the types of content they support. Android always uses ELF.
  • How to reorder C++ names.

Android currently supports the following 7 ABIs:

MIPS, MIPS64, X86, x86-64, ARM64-V8A, Armeabi, Armeabi-V7ACopy the code

2. What does the ABI do?

When we want to use the Native (C/C++) library in a project, we must provide a compilation package for the processor architecture we want to support. Each processor architecture requires us to provide one or more.so files containing native code.

By default, all architectures are supported by Android Studio or command packaging in order to make the APP more compatible, but the corresponding APK size increases crazily. For the user, the target device only needs one of these versions, but when the user downloads APK, they download all of them (which is pretty user unfriendly).


What to do? Abifilters provides us with a solution. Abifilters provides us with the ability to select and match specific CPU architectures by adding the following configuration to build.gradle in app:

android {
        defaultConfig {
            ndk {
                abiFilters 'arm64-v8a', 'x86_64'
            }
        }
Copy the code

}

You may not be able to understand the ABI from the above text, so let’s use a simple example to illustrate.


2.1 Illustrate the functions of ABI

First, we create a simple Hello World application with just one Activity and a launch icon. Let’s look at the following typed APK:


There are no native libraries in use and the size is 2.1MB. Now we add multi-ABI native library support, we integrate Realm into the project and then package it.


The size of apK has been increased from 2.1MB to 11.2MB, and there is a new native so library folder with a size of 8.8MB.


As you can see above, Realm generates.so libraries for five CPU architectures: MIPS, x86, X86_64, ARM64-V8A, and ArmeabI-V7A. Increased package size by 8.8MB. But this is not what we want, we just want to fit the CPU architecture we specify, so we need to add the Abifilters configuration in gralde.build to achieve the desired effect:

Android 28 / / compile the SDK version defaultConfig {{compileSdkVersion applicationId "com. Example, zhouwei helloworld" minSdkVersion 15 targetSdkVersion 28 versionCode 1 versionName testInstrumentationRunner "1.0" "Android. Support. The test. The runner. AndroidJUnitRunner" / / specifies a CPU architecture the NDK {abiFilters' arm64 - v8a ', 'x86_64'}}}Copy the code

The effect is as follows:


As you can see, only the SO files we specified for the CPU architecture were generated and the package size was reduced by 5.3MB.

At this point, you may have a question: Android supports seven CPU architectures, so which CPU architectures should we adapt to ensure the best compatibility while minimizing the size of APK in our actual projects?

Before we answer that question, let’s take a look at how these top giants fit in.

3. How does Dachang APP adapt to different CPU architectures?

First of all, we download some APK from big factories to see their adaptation. Here I analyze the adaptation of wechat, mobile QQ, Alipay and Taobao apps:


As you can see, wechat is arm64-V8A (wechat was recently arm64-V8A, formerly Armeabi), Alipay and Handq are Armeabi, and Taobao are Armeabi-V7A. Different apps adapt to different platforms, but one thing they have in common is that they only specify one platform.

Wait, these apps are only compatible with one CPU architecture. For example, armeabi-V7A is only compatible with one CPU architecture. Will these apps work when installed on other architectures, such as ARM64-V8A?

To understand this, we need to understand how the ABI works.

How does the ABI work?

The official documentation explains as follows:

The Android system knows at runtime which ABI it supports because version-specific system attributes indicate:

  • The main ABI of the device corresponds to the machine code used by the system image itself.
  • (Optional) Secondary ABI corresponding to other ABI also supported by the system image.

This mechanism ensures that the system extracts the best machine code from the package at installation time.

For best performance, compile directly against the main ABI. For example, a typical device based on ARMv5TE defines only the main ABI: armeABI. In contrast, a typical ARMV7-based device defines the primary ABI as ArmeABI-V7A and the secondary ABI as armeABI because it can run the application native binaries generated for each ABI.

32-bit variants are also supported on 64-bit devices. Take an ARM64-V8A device for example, which can also run Armeabi and ArmeabI-V7A code. Note, however, that applications perform much better on 64-bit devices if they target ARM64-V8A rather than rely on devices running armeabI-V7A version of the application.

Many x86-based devices can also run Armeabi-V7A and Armeabi NDK binaries. For these devices, the primary ABI will be x86 and the secondary ABI will be ArmeabI-V7A.

If the above paragraph is a bit confusing, let me explain it briefly. In general, an Android device can support multiple ABI’s, including the primary and secondary ABI’s, arm64-V8A’s, Armeabi-V7A’s and ArmeABI’s, and Armeabi-V7A’s. The secondary ABI is armeabi.

In addition, x86 phones will contain the instruction set dynamic transcoding tool called Houdini provided by Intel, which is compatible with ARM. So, that is to say, apps adapted to Armeabi platform can run on x86 phones.

3.1 Specific adaptation process of the main and auxiliary ABI

Given how the ABI works, an Android device supports the primary and secondary ABI, so how do they work? Take arm64-V8A as an example:


For a phone whose CPU is arm64-V8A, when running app, enter JNilibs to read library files, first look for arm64-v8A folder, if not, go to armeabi-v7a folder, if not, go to Armeabi folder. If not, throw an exception;

If you have the arm64-v8a folder, look for the.so file with the specific name. Note: if you do not find the desired.so file, you do not look down (armeabi-v7a folder) and throw an exception.

Exception: Java. Lang. UnsatisfiedLinkError: dlopen failed: library "/ * * *. So" not foundCopy the code

A special case to note is the case where a folder is hit but the so file is not hit:

  • For example, if the arm64-V8a folder is hit and no so file is found, the armeabi-v7a folder will not be searched, but will throw an exception.

  • If your project uses third-party dependencies, it is recommended to include ndK. abiFilters in your Build if you only have one ABI

  • Such as: Third party AAR files, if the SDK fully supports the ABI, may include armeabi, ArmeabI-v7A, x86, ARM64-V8A, and x86_64, while the other SO in your application only supports armeABI, Armeabi-v7A, and x86. An AAR that directly references the SDK automatically compiles packages that support the five ABI’s. However, the other SO of the application lacks support for the other two ABI’s, so if the application runs on devices with arm64-V8A and x86_64 as the preferred ABI, it will crash==.

Therefore, we need to configure the abiFilter configuration in our app to avoid some unknown errors.

DefaultConfig {NDK {abiFilters "armeabi"}}Copy the code
3.2 Share of 7 Android CPU architectures in the current market
  • Arm64-v8a: Current mainstream version

  • Armeabi-v7a: Some old phones

  • X86 / X86_64: X86 mobile phones will include an instruction set dynamic transcoding tool called Houdini provided by Intel, which is compatible with ARM. So. Considering the market share of x86 is less than 1%, the two x86 related

  • Armeabi/MIPS/MIPS64: The NDK previously supported ARMv5 (ArmeABI) as well as 32-bit and 64-bit MIPS, but the NDK R17 is no longer supported and is rarely used on mobile phones.

Currently in the mobile phone market, x86 / X86_64 / Armeabi/MIPS/MIPS6 architecture can not be ignored, their share should be very few, ARM64-V8A as the latest generation of architecture, should be the current mainstream, Armeabi-V7A only exist a few old phones.

I tried to find the specific market share data on Google, but could not find it. However, it can be seen from the fact that the national wechat app only matches ARM64-V8A, arm64-V8A is the mainstream at present, and there is another point that Google Play started from August 2019. Force APP to adapt arm64-V8A to slowly eliminate 32-bit Armeabi-V7A.


4. How should we fit into our project?

This is the answer to the first two questions.

Q1: Armeabi-V7A is only available. Will the APP bounce when installed on other architectures, such as ARM64-V8A?

A: No, but the other way around.

Because armeabI-V7A and ARM64-V8A are backward compatible:

  • Only fitarmeabiThe APP can run onarmeabi.x86.x86_64.armeabi-v7a.arm64-v8on
  • Only fitarmeabi-v7aCan run onarmeabi-v7aandarm64-v8a
  • Only fitarm64-v8aCan run onarm64-v8aon

So how do we fit in? The following schemes are given:

Plan 1: Only use Armeabi

  • Advantages: Almost all CPU architectures (except obsolete MIPS and MIPS_64)

  • Cons: Low performance, equivalent to requiring auxiliary ABI or dynamic transcoding for compatibility on most phones

Option two: Only armeabi-V7A

The first scheme is the same, but part of the old equipment is screened out, which is more balanced in performance and compatibility

Plan 3: only arm64-V8

  • Advantages: The best performance

  • Cons: Only runs on ARM64-V8, some older device users will be abandoned

All the three schemes are ok. In the current Dachang APP adaptation, all of them are available, and most of them are the first two schemes. It’s up to you to decide which one to choose: arm64-V8 for performance, Armeabi for compatibility, and armeabI-V7A for balance.

At the moment, most of the dachang apps use Armeabi or Armeabi-V7A. Only the awesome ones like wechat give up a few devices for the sake of performance and user experience, which makes sense because wechat doesn’t care about flies.

5. Can you have both performance and compatibility?

In fact, this article should have ended in the last section, but I still feel that the advantages are not enough. In addition to accommodating all CPU architectures, why can’t performance and compatibility be achieved at the same time? In fact, Google has already thought about this. It is also possible to implement abi split and subcontract. The implementation is also very simple. Add the following configuration to Gradle:

 android {
      ...
      splits {
// Configures multiple APKs based on ABI. abi { // Enables building multiple APKs per ABI. enable true // By default all  ABIs are included, so use reset() and include to specify that we only // want APKs for x86 and x86_64. // Resets the list of ABIs that Gradle should create APKs for to none. reset() // Specifies a list of ABIs that Gradle should create APKs for. include "x86", "x86_64", "arm64-v8a", "armeabi", "armeabi-v7a" // Specifies that we do not want to also generate a universal APK that includes all ABIs. universalApk false } } }Copy the code

Copy the code

Then, a separate APK can be created for each CPU architecture, which contains only one platform, as follows:



In this way, performance is guaranteed without increasing the size of APK, and compatibility is perfect because you can pack all architectures in a single package, killing multiple birds with one stone.

Also, Google Play supports uploading multiple APKs:


In this way, different packages can be downloaded according to different CPU architectures.

But, but, but, unfortunately, domestic app stores do not support it yet!

Refer to the article

  • https://www.diycode.cc/topics/691
  • https://developer.android.com/ndk/guides/abis
  • https://android.jlelse.eu/controlling-apk-size-when-using-native-libraries-45c6c0e5b70a

That’s all for this article, please feel free to point out any mistakes in the comments section. Original is not easy, if you like this article, welcome to like, forward, collect three even once.

In addition, welcome to pay attention to my public account “technology TOP”, there are high-quality technical articles pushed every day.

Every day there are dried articles continue to update, you can search wechat “technology TOP” the first time to read, reply [mind map] [interview] [resume] Yes, I prepare some Android advanced route, interview guidance and resume template for you