Reprinted - CPU architecture supported by Android system

Original link

The early Android system almost only supported the ARMv5 CPU architecture. Do you know how many kinds it supports now? 7 kinds!

The Android system currently supports the following seven different CPU architectures: ARMv5, ARMv7 (from 2010), x86 (from 2011), MIPS (from 2012), ARMv8, MIPS64 and x86_64 (from 2014), Each is associated with a corresponding ABI.

Application Binary Interface (Application Binary Interface) defines how binary files (especially .so files) run on the corresponding system platform, from the instruction set used, memory alignment to available system function libraries. On the Android system, each CPU architecture corresponds to an ABI: armeabi, armeabi-v7a, x86, mips, arm64-v8a, mips64, x86_64.

Why you need to focus on .so files

If the NDK is used in the project, it will generate .so files, so obviously you are already paying attention to it. If you're just coding in Java, you might be thinking that you don't need to pay attention to .so files, because Java is cross-platform. But in fact, even if you only use the Java language in the project, in many cases, you may not realize that the function library or engine library that the project depends on has embedded .so files and depends on different ABIs.

For example, if the project uses RenderScript support library, OpenCV, Unity, android-gif-drawable, SQLCipher, etc., you already include .so files in the generated APK file, and you need to pay attention to the .so files.

The ABI supported by an Android application depends on the .so file located in the lib/ABI directory in the APK, where the ABI may be one of the seven ABIs mentioned above.

 

The Native Libs Monitor application can help us understand which .so files are used in the APK installed on the phone, and which function libraries or frameworks the .so files come from.

Of course, we can also decompile the app to obtain this information, but it is relatively troublesome.

Many devices support more than one ABI. For example ARM64 and x86 devices can also run both armeabi-v7a and armeabi binaries. But it's better to provide a platform-specific binary package for a specific platform, in which case there is one less emulation layer at runtime (such as the virtual layer that emulates arm on x86 devices), resulting in better performance (thanks to recent architectures Updates, e.g. hardware fpu, more registers, better vectorization, etc).

We can get a list of ABIs supported by the device sorted by preference through Build.SUPPORTED_ABIS. But you should not read it from your application, because when the Android package manager installs the APK, it will automatically select the .so file precompiled for the corresponding system ABI in the APK package, if it is in the corresponding lib/ABI directory If there is a .so file.

Where things can go wrong in the app

There is a simple but not well known important rule when dealing with .so files.

You should try to provide .so files optimized for each ABI, but either all or none: you shouldn't mix them. You should provide corresponding .so files for each ABI directory.

When an application is installed on a device, only the .so files corresponding to the CPU architecture supported by the device will be installed. On x86 devices, if there is a .so file in the libs/x86 directory, it will be installed. If it does not exist, the .so file in armeabi-v7a will be selected. If it does not exist, the .so file in the armeabi directory will be selected. file (since x86 devices also support armeabi-v7a and armeabi).

Could go wrong elsewhere

When you import a .so file, it doesn't just affect the CPU architecture. I can see a series of common errors from other developers, most of which are "UnsatisfiedLinkError", "dlopen: failed" and other types of crashes or poor performance:

.so files compiled with android-21 platform version run on android-15 devices

When using the NDK, you may be inclined to use the latest compilation platform, but in fact this is wrong because the NDK platform is not backward compatible, but forward compatible. It is recommended to use the compilation platform corresponding to the app's minSdkVersion.

This also means that when you import a precompiled .so file, you need to check the platform version it was compiled on.

Mixing .so files compiled with different C++ runtimes

.so files can depend on different C++ runtimes, either statically compiled or dynamically loaded. Mixing different versions of the C++ runtime can lead to a lot of weird crashes and should be avoided. As a rule of thumb, statically compiling the C++ runtime is fine when there is only one .so file, otherwise when there are multiple .so files, you should have all the .so files dynamically link against the same C++ runtime.

This means that when a new precompiled .so file is introduced and other .so files exist in the project, we need to first confirm whether the C++ runtime used by the newly introduced .so file is the same as the existing .so file .

There is no corresponding .so file provided for each supported CPU architecture

This has been mentioned before, but you should really pay attention to it because it can happen without even realizing it.

For example: your app supports armeabi-v7a and x86 architecture, and then use Android Studio to add a function library dependency, this function library contains .so files and supports more CPU architectures, such as adding android-gif-drawable function library :

compilepl.droidsonroids.gif:android-gif-drawable:1.1.+’

After publishing our app, we will find that it will crash on some devices, such as Galaxy S6, and finally we can find that only the .so files in the 64-bit directory are installed into the phone.

Solution: Recompile our .so file to support missing ABIs, or set

ndk.abiFilters

Displays the specified supported ABIs.

One final note: if you are an SDK provider and provide a library that doesn't support all ABIs, you're going to screw up your users because they'll have to support fewer ABIs than you provide.

Put the .so file in the wrong place

It is often easy to get confused about where the .so file should be placed or generated. Here is a summary:

  • The Android Studio project is placed in the jniLibs/ABI directory (of course, it can also be specified by setting the jniLibs.srcDir property in the build.gradle file)
  • The Eclipse project is placed in the libs/ABI directory (this is also the directory where the ndk-build command generates .so files by default)
  • The AAR archive is located in the jni/ABI directory (.so files are automatically included in the APK that references the AAR archive)
  • In the lib/ABI directory in the final APK file
  • After installing through PackageManager, in systems smaller than Android 5.0, the .so file is located in the app's nativeLibraryPath directory; in systems greater than or equal to Android 5.0, the .so file is located in the app's nativeLibraryRootDir/CPU_ARCH directory.

Only provide .so files for armeabi architecture and ignore other ABIs

All x86/x86_64/armeabi-v7a/arm64-v8a devices support armeabi .so files, so it seems that removing .so files for other ABIs is a good trick to reduce APK size. But it's not: it doesn't just affect the performance and compatibility of the library.

x86 devices can run ARM-type function libraries well, but there is no guarantee that crashes will not occur 100%, especially for older devices. 64-bit devices (arm64-v8a, x86_64, mips64) can run 32-bit libraries, but running in 32-bit mode, running 32-bit versions of ART and Android components on 64-bit platforms, will lose 64-bit optimizations performance (ART, webview, media, etc.).

It is a wrong excuse to reduce the size of the APK package, because you can also choose to upload the APK of the specified ABI version in the application market to generate different ABI versions

 This APK can be configured as follows in build.gradle:

android {
   ...
   splits {
     help {
       enable true
       reset()
       include 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' //select ABIs to build APKs for
       universalApk true //generate an additional APK that contains all the ABIs
     }
   }
   // map for the version code
   project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]
   android.applicationVariants.all { variant ->
     // assign different version code for each output
     variant.outputs.each { output ->
       output.versionCodeOverride =
           project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0) * 1000000 + android.defaultConfig.versionCode
     }
   }
}

 

 

Guess you like

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