A big pit related to so in Android

It is inevitable to introduce third-party code in Android application development. If it is an open source project, the risk is relatively controllable. If you introduce a commercial SDK, you must be cautious. It is inevitable that there will be problems of one kind or another. Like this one we are going to talk about today.

write picture description here

For students who have integrated third-party SDKs, the directory structure in the above figure should be familiar. Under normal circumstances, we only need to place the so files of different versions separately. But what if the third-party SDK we want to integrate doesn't have the arm-v7a version? Is deleting the armeabi-v7a directory to keep only armeabi? Or does it matter that the number of .so files in the two directories is different? Which .so will the system load?

If you are only interested in the conclusion, you can skip to the end

For the convenience of explanation, we first introduce   the concept of FAT Binary . We know that different CPUs support different instruction sets, so what if we need to make the app run normally on as many CPUs as possible? It's simple, just put different versions of Binary in a file, and you can use it as needed at runtime. This is a typical implementation of FAT Binary. The way Android implements FAT is somewhat different, that is, placing the .so file in the corresponding folder mentioned above. In the Android system, ndk will generate the following 7 so by default.

write picture description here

It is uneconomical to have so many versions of .so in the apk file:

  • mips / mips64: Rarely used for mobile phones and can be ignored
  • x86 / x86_64: Mobile phones with x86 architecture will include an instruction set dynamic transcoding tool called Houdini provided by Intel to achieve compatibility with arm .so, and then consider the market share of x86 below 1%, and the two related to x86. so can also be ignored
  • armeabi: ARM v5 This is quite an old version, lacks hardware support for floating point calculations, and has performance bottlenecks when a large number of calculations are required
  • armeabi-v7a: The current mainstream version of ARM v7
  • arm64-v8a: 64-bit support

In this way, we can make it clear that mips, mips64, x86, x86_64 these 4 .so we do not need.

Let's go back to the question we mentioned at the beginning:

Suppose our current situation is like this (b.so is the third-party so that only has the armeabi version):

write picture description here

If so, which so will be executed when running the apk on both ARM / ARM v7 devices?

The answer is: not sure...

How did such a foolish answer come about?

Since the design of the FAT binrary on Android is so exciting, it is necessary to perform a copy of the corresponding version so according to the CPU situation when the apk is installed. The most reasonable approach for the above situation would be to use the two files armeabi-v7a/a.so and armeabi/b.so. Google thought the same thing at first, and then introduced the bug...

Native library copy issue when install apk with different abi native libraries on device

write picture description here

The above picture is the so file copy logic that is still in use in Android 4.4. It seems that there is no problem?

The pit father is that  Android does not guarantee the scanning order of the zip entry when installing the apk file , so the same file placement will bring two different installation results:

write picture description here

write picture description here

Looking a little dizzy? In short, if we put it in the way we put it above, the system may only copy armeabi-v7a/a.so after installation. If the logic of b.so is executed, the program will obviously crash .

There is also a small episode here. The finder of this bug has actually given a complete solution when submitting it, but after going through a code review for almost a year, the Android official said: We have repaired it by ourselves =_ =.

write picture description here

This problem is indeed "fixed" in Android 5.0. The "repair" method is simple and rude, no longer match the abi with the file as the granularity, and directly copy the entire folder =_=. So if we follow our previous placement method, in Android 5.0+, if b.so is executed, it will definitely crash.

As mentioned above, keeping only the armeabi folder is unwise from a performance perspective. The correct way is to copy armeabi/b.so to armeabi-v7a/b.so. This is because ARM v7 is forward compatible with ARM v5.

  • In order to reduce the size of the apk, only keep two folders, armeabi and armeabi-v7a, and ensure that the number of so in these two folders is the same
  • For the third-party so that only provides the armeabi version, copy a copy to the armeabi-v7a folder

Original address: https://zhuanlan.zhihu.com/p/21359984

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326833869&siteId=291194637