1. 程式人生 > >Device supports x86_64,but APK only supports armeabi

Device supports x86_64,but APK only supports armeabi

Device supports x86_64,but APK only supports armeabi

今天在建立虛擬機器的時候發現這麼一句話,於是我就開始思考,這話什麼意思?為什麼我在真機上沒有看到過這樣的意思。於是我就開始google之。現在將我的調查結果記錄如下

第一篇-記錄so檔案一些問題

簡介:做專案的時候經常會使用到so檔案。例如使用高德地圖,其SDK中就包含了armeabi、armeabi-v7a、arm64-v8a、x86等其他資料夾,裡面通常放著同樣名稱、同樣數量的so檔案。實際使用過程中,關於這些so檔案引發的問題確實不少,也不好解決。寫下此文,希望以後遇到相關的問題,能有個大概的思路。

名詞解析:
NDK:Native Development Kit
JNI:Java Native Interface
ABI: Application Binary Interface 應用二進位制介面

Android Studio使用so庫
1、使用和eclipse一樣在libs目錄下新建armeabi目錄的方式
需要在build.gradle中新增指定jni庫目錄的語句
sourceSets {
main.jniLibs.srcDirs = ['libs'] //指定libs為jni的存放目錄
}
2、使用AS預設的位置:src/main/jniLibs
直接在src/main/下新建jniLibs目錄,將armeabi等目錄放到該目錄下即可
備註:AS可以直接右鍵新建同目錄下的jniLibs目錄,但該目錄不是編譯好的庫檔案目錄,而是未編譯的原生代碼檔案的目錄(這裡指的是與java同級的jni目錄,放置cpp程式碼的)

android支援的cpu架構(目前是七種)
| 架構 | 說明 |
| :---------- | :--------------------------------------- |
| armeabi | 第5代 ARM v5TE,使用軟體浮點運算,相容所有ARM裝置,通用性強,速度慢 |
| armeabi-v7a | 第7代 ARM v7,使用硬體浮點運算,具有高階擴充套件功能 |
| arm64-v8a | 第8代,64位,包含AArch32、AArch64兩個執行狀態對應32、64bit |
| x86 | intel 32位,一般用於平板 |
| x86_64 | intel 64位,一般用於平板 |
| mips | 少接觸 |
| mips64 | 少接觸 |

安裝時的相容性檢查:
安裝到系統中後,so檔案會被提取在:data/app/com.xxxxxxxx.app-x/lib/目錄下(5.0版本)、/data/app-lib/目錄下(4.2版本),其中armeabi和armeabi-v7a會生成arm目錄,arm64-v8a會生成arm64目錄。
安裝app的時候,如果app使用了so檔案,而不存在適合本機cpu架構的so檔案,會報如下錯誤:
Installation failed with message INSTALL_FAILED_NO_MATCHING_ABIS.
例如:在x86模擬器上就必須有x86版本的so資料夾。不然無法安裝成功。

執行時的相容性檢查:
1、檢查目標目錄下是否存在的so庫檔案
2、檢查存在的so檔案是否符合當前cpu架構。
對於情況一,一般規避的做法是:保證jnilibs目錄下x86、x84_64、armeabi、armeabi-v7a、arm64-v8a等目錄下的檔名稱數量是一致的。
例如:專案中使用了A、B、C三個第三方庫。其中A、B提供了armebi以及arm64-v8a版本的庫檔案,而C只提供了armebi、armebi-v7a版本的庫檔案。這時候只能夠刪除原有的arm64-v8a目錄,保留armeabi目錄,一般arm64的手機都能相容使用armeabi版本的庫。或者複製一份armeabi的so檔案到缺少的目錄中(推薦)。

生成so檔案:
NDK交叉編譯時選定APP_ABI := armeabi x86 ...可以生成支援相應晶片的so檔案。APP_ABI := all生成支援所有晶片指令集(目前七種)so檔案。

Android載入so檔案規則:
當你只提供了armeabi目錄時,armeabi-v7a、arm64-v8a架構的程式都會去armeabi裡尋找,而當你同時也提供了armeabi-v7a、armeabi-v8a目錄,而裡面又不存在對應的so庫時,系統就不會再去armeabi裡面尋找了,直接找不到報錯。其他平臺也是如此。這裡我踩了不少的坑,切記。
一般來說,一些比較有名的第三方庫都會提供armeabi、armeabi-v7a、x86這三種類型的so檔案,同時擁有這三種版本的app可以在所有機型上執行。另外,越來越多的SDK會同時提供arm64-v8a版本。只包含armeabi的專案也可以在所有裝置上執行。

現實案例:
我的專案中使用了armeabi、arm64-v8a兩種型別,而當我需要使用某語音第三方庫的時候,發現只提供了armeabi、armeabi-v7a兩種型別的so檔案,而我的手機是arm64-v8a的。所以只會使用arm64-v8a裡面的so檔案,當使用到該語音庫時找不到對應的so庫,就會報錯。理論上有以下兩種解決方法:
一、刪除所有arm64-v8a,只保留armeabi,全部使用相容性最高的版本,但也執行速度最慢。
二、將該語音庫的armeabi版本的so複製到arm64-v8a中。單一so檔案使用armeabi相容版本。

總結:
當你使用到so檔案時,保證每個子資料夾中檔名稱數量都是一致的。
對於只提供armeabi的第三方庫,複製一份armeabi的so檔案到缺失的其他目錄中;或者只保留armeabi目錄(不推薦)

第二篇-標題問題解析

Android 的 so 庫和 ABI 配置我原先也是沒有什麼概念的,直到上個周,在我嘗試跑一個程式的時候,真機執行沒問題,但是用偉大的模擬機的時候,遇到了這麼一個錯誤:

模擬機的下面顯示:
Device supports x86,but APK only supports armeabi-v7a,armeabi,x86_64;
模擬機的裝置是 x86,但是執行的這個程式的 apk 卻只支援 armeabi-v7a,armeabi 和 x86_64 三種。
這個問題不僅僅是一個問題,它是很多個問題

是的,那麼問題來了
x86,armeabi-v7a,armeabi,x86_64 到底是什麼玩意?
我們的程式碼是在哪裡設定apk對它們支援的?
怎麼檢視和設定模擬機的支援型別?
為什麼我連線的真機大華為 HUAWEI PE-TL20 沒有顯示這樣的錯誤?

寶寶發現了真相,快來誇我

為了弄明白上面的幾個疑問,我 google 了很多相關方面的內容,終於召喚真相~~下面一個個來解釋~
1.x86,armeabi-v7a,armeabi,x86_64 到底是什麼玩意?
這四個玩意都是 CPU 架構型別的名稱。 目前 android 支援的 CPU 架構有有以下幾種:

CPU架構 描述
armeabi 第5代 ARM v5TE,使用軟體浮點運算,相容所有ARM裝置,通用性強,速度慢
armeabi-v7a 第7代 ARM v7,使用硬體浮點運算,具有高階擴充套件功能
arm64-v8a 第8代,64位,包含AArch32、AArch64兩個執行狀態對應32、64bit
x86 intel 32位,一般用於平板
x86_64 intel 64位,一般用於平板
mips 少接觸
mips64 少接觸

2.我們的程式碼是在哪裡設定apk對它們支援的?
如果你和我用的開發工具都是 Android Studio 的話,那麼在程式的主module 的 build.gradle中你會發現有這麼個程式碼:

defaultConfig { ndk { abiFilters "armeabi", "armeabi-v7a", "x86_64" } }

就是這裡設定了支援的 CPU 的型別, 和剛才提示的 apk 支援的 CPU的型別是一模一樣的. 但是,在這裡,我也發現了一個不認識的標籤屬性 abiFiliter
硬翻過來是 abi 過濾器, abi 是什麼?
ABI, (application binary interface,縮寫為ABI),應用二進位制介面。在計算機中,ABI 描述了應用程式(或者其他型別)和作業系統之間或其他應用程式的低階介面

3.怎麼檢視和設定模擬機的支援型別?
這個問題非常簡單,我們在建立一個模擬機的時候,就有 ABI 的選擇,因為粗心,之前一直都沒有發現,看下圖:

4.為什麼我連線的真機大華為 HUAWEI PE-TL20 沒有顯示這樣的錯誤?
問題解決到這裡,我們幾乎都猜到了答案,就是大華為 HUAWEI PE-TL20 這個裝置支援的CPU 架構 ,肯定是 程式碼中支援的 armeabi-v7a,armeabi,x86_64 中的一種。
到底是其中的哪一個呢?我們可以通過adb命令列的方式檢視。
具體步驟: 1.連線手機到電腦上 2.開啟 cmd 命令視窗,輸入命令 adb shell
3.然後輸入命令 cat /proc/cpuinfo

如果你使用adb的過程中,出現了adb錯誤“'adb' 不是內部或外部命令,也不是可執行的程式或批處理檔案
,不要慌,這是因為沒有配置 adb 的環境變數,配置一下,就好了。具體配置步驟,可以移步這裡 adb錯誤“’adb’ 不是內部或外部命令,也不是可執行的程式或批處理檔案
大華為 HUAWEI PE-TL20 的結果如下:

顯示是ARMv7, 對應的應該是armeabi-v7a,看來我們的猜測果然是對的。

第三篇

Android can run on several different computer architectures. This document discusses the different CPU architectures that may be employed for a Xamarin.Android application. This document will also explain how Android applications are packaged to support different CPU architectures. The Application Binary Interface (ABI) will be introduced, and guidance will be provided regarding which ABIs to use in a Xamarin.Android application.

Overview

Android allows for the creation of "fat binaries," a single .apk file that contains machine code that will support multiple, different CPU architectures. This is accomplished by associating each piece of machine code with an Application Binary Interface. The ABI is used to control which machine code will run on a given hardware device. For example, for an Android application to run on an x86 device, it is necessary to include x86 ABI support when compiling the application.

Specifically, each Android application will support at least one embedded-application binary interface (EABI). EABI are conventions specific to embedded software programs. A typical EABI will describe things such as:

  • The CPU instruction set.
  • The endianness of memory stores and loads at run time.
  • The binary format of object files and program libraries, as well as which type of content is allowed or supported in these files and libraries.
  • The various conventions used to pass data between application code and the system (for example: how registers and/or the stack are used when functions are called, alignment constraints, etc.)
  • Alignment and size constraints for enum types, structures, fields, and arrays.
  • The list of function symbols available to your machine code at run time, generally from a very specific selected set of libraries.

armeabi and Thread Safety

The Application Binary Interface will be discussed in detail below, but it is important to remember that the armeabi runtime used by Xamarin.Android is not thread safe. If an application that has armeabi support is deployed to an armeabi-v7a device, many strange and unexplainable exceptions will occur.

Due to a bug in Android 4.0.0, 4.0.1, 4.0.2, and 4.0.3, the native libraries will be picked up from the armeabi directory even though there is an armeabi-v7a directory present and the device is an armeabi-v7a device.

Note: Xamarin.Android will ensure that .so are added to the APK in the correct order. This bug should not be an issue for users of Xamarin.Android.

ABI Descriptions

Each ABI supported by Android is identified by a unique name.

armeabi

This is the name of an EABI for ARM-based CPUs that support at least the ARMv5TE instruction set. Android follows the little-endian ARM GNU/Linux ABI. This ABI does not support hardware-assisted floating-point computations. All FP operations are performed by software helper functions that come from the compiler's libgcc.a static library. SMP devices are not supported by armeabi.

Note: Xamarin.Android's armeabi code is not thread safe and should not be used on multi-CPU armeabi-v7a devices (described below). Using aremabi code on a single-core armeabi-v7a device is safe.

armeabi-v7a

This is another ARM-based CPU instruction set that extends the armeabi EABI described above. The armeabi-v7a EABI has support for hardware floating-point operations and multiple CPU (SMP) devices. An application that uses the armeabi-v7a EABI can expect substantial performance improvements over an application that uses armeabi.
Note: armeabi-v7a
machine code will not run on ARMv5 devices.

arm64-v8a

This is a 64-bit instruction set that is based on the ARMv8 CPU architecture. This architecture is used in the Nexus 9. Xamarin.Android 5.1 provides experimental support for this architecture (for more information, see Experimental Features).

x86

This is the name of an ABI for CPUs that support the instruction set commonly named x86 or IA-32. This ABI corresponds to instructions for the Pentium Pro instruction set, including the MMX, SSE, SSE2, and SSE3 instruction sets. It does not include any other optional IA-32 instruction set extensions such as:

  • the MOVBE instruction.
  • Supplemental SSE3 extension (SSSE3).
  • any variant of SSE4.

Note: Google TV, although it runs on x86, is not supported by Android's NDK or by Xamarin.Android.

x86_64

This is the name of an ABI for CPUs that support the 64-bit x86 instruction set (also referred to as x64 or AMD64). Xamarin.Android 5.1 provides experimental support for this architecture (for more information, see Experimental Features).

mips

This is the name of an ABI for MIPS-based CPUs that support at least the MIPS32r1 instruction set. Neither MIPS 16 nor micromips are supported by Android.

Note: MIPS devices are not currently supported by Xamarin.Android, but will be in a future release.

APK File Format

The Android Application Package is the file format that holds all of the code, assets,resources, and certificates necessary for an Android application. It is a .zip file, but uses the .apk file name extension. When expanded, the contents of an .apk created by Xamarin.Android can be seen in the screenshot below:
Contents of the .apk
A quick description of the contents of the .apk file:

  • AndroidManifest.xml – This is the AndroidManifest.xml file, in binary XML format.
  • classes.dex – This contains the application code, compiled into the dex file format that is used by the Android runtime VM.
  • resources.arsc – This file contains all of the precompiled resources for the application.
  • lib – This directory holds the compiled code for each ABI. It will contain one subfolder for each ABI that was described in the previous section. In the screenshot above, the .apk
    in question has native libraries for both armeabi-v7a and for x86.
  • META-INF – This directory (if present) is used to store signing information, package, and extension configuration data.
  • res – This directory holds the resources that were not compiled into resources.arsc.

    Note: The file libmonodroid.so is the native library required by all Xamarin.Android applications.

Android Device ABI Support

Each Android device supports executing native code in up to two ABIs:

  • The "primary" ABI – This corresponds to the machine code used in the system image.
  • A "secondary" ABI – This is an optional ABI that is also supported by the system image.
    For example, a typical ARMv5TE device will only have a primary ABI of armeabi, while an ARMv7 device would specify a primary ABI of armeabi-v7a and a secondary ABI of armeabi. A typical x86 device would only specify a primary ABI of x86.

Android Native Library Installation

At package installation time, native libraries within the .apk are extracted into the app's native library directory, typically /data/data/

Android's native library installation behavior varies dramatically between Android versions.

Installing Native Libraries: Pre-Android 4.0

Android prior to 4.0 Ice Cream Sandwich will only extract native libraries from a single ABI within the .apk. Android apps of this vintage will first try to extract all native libraries for the primary ABI, and if no such libraries exist, Android will then extract all native libraries for the secondary ABI. No "merging" is done.

For example, consider a situation where an application is installed on an armeabi-v7a device. The .apk, which supports both armeabi and armeabi-v7a, has the following ABI lib directories and files in it:

lib/armeabi/libone.so
lib/armeabi/libtwo.so
lib/armeabi-v7a/libtwo.so

After installation, the native library directory will contain:

$APP/lib/libtwo.so # from the armeabi-v7a directory in the apk

In other words, no libone.so is installed. This will cause problems, as libone.so is not present for the application to load at run time. This behavior, while unexpected, has been logged as a bug and reclassified as "working as intended."

Consequently, when targeting Android versions prior to 4.0, it is necessary to provide all native libraries for each ABI that the application will support, that is, the .apk
should contain:

lib/armeabi/libone.so
lib/armeabi/libtwo.so
lib/armeabi-v7a/libone.so
lib/armeabi-v7a/libtwo.so

Installing Native Libraries: Android 4.0 – Android 4.0.3

Android 4.0 Ice Cream Sandwich changes the extraction logic. It will enumerate all native libraries, see if the file's basename has already been extracted, and if both of the following conditions are met, then the library will be extracted:

  • It hasn't already been extracted.
  • The native library's ABI matches the target's primary or secondary ABI.
    Meeting these conditions allows "merging" behavior; that is, if we have an .apk
    with the following contents:
lib/armeabi/libone.so
lib/armeabi/libtwo.so
lib/armeabi-v7a/libtwo.so

Then after installation, the native library directory will contain:

$APP/lib/libone.so
$APP/lib/libtwo.so

Unfortunately, this behavior is order dependent, as described in the following document - Issue 24321: Galaxy Nexus 4.0.2 uses armeabi native code when both armeabi and armeabi-v7a is included in apk.

The native libraries are processed "in order" (as listed by, for example, unzip), and the first match is extracted. Since the .apk contains armeabi and armeabi-v7a versions of libtwo.so, and the armeabi is listed first, it's the armeabi version that is extracted, not the armeabi-v7a version:

$APP/lib/libone.so # armeabi$APP/lib/libtwo.so # armeabi, NOT armeabi-v7a!

Furthermore, even if both armeabi and armeabi-v7a ABIs are specified (as described below in the section Declaring Supported ABIs), Xamarin.Android will create the following element in the . csproj:

<AndroidSupportedAbis>armeabi,armeabi-v7a</AndroidSupportedAbis>

Consequently, the armeabi libmonodroid.so will be found first within the .apk, and the armeabi libmonodroid.so will be the one that is extracted, even though the armeabi-v7a libmonodroid.so is present and optimized for the target. This can also result in obscure run-time errors,as armeabi is not SMP safe.

Installing Native Libraries: Android 4.0.4 and later

Android 4.0.4 changes the extraction logic: it will enumerate all native libraries, read the file's basename, then extract the primary ABI version (if present), or the secondary ABI (if present). This allows "merging" behavior; that is, if we have an .apk
with the following contents:

lib/armeabi/libone.so
lib/armeabi/libtwo.so
lib/armeabi-v7a/libtwo.so

Then after installation, the native library directory will contain:

$APP/lib/libone.so # from armeabi
$APP/lib/libtwo.so # from armeabi-v7a

Xamarin.Android and ABIs

Xamarin.Android supports the following architectures:

  • armeabi
  • armeabi-v7a
  • x86
    Xamarin.Android provides experimental support for the following architectures:
  • arm64-v8a
  • x86_64

Note that 64-bit runtimes are not required in order to run your app on 64-bit devices. For more information about experimental features in Xamarin.Android 5.1, see Experimental Features.
Xamarin.Android does not currently provide support for mips.

Declaring Supported ABI's

By default, Xamarin.Android will default to armeabi-v7a for Release builds, and to armeabi-v7a and x86 for Debug builds. Support for different ABIs can be set through the Project Options for a Xamarin.Android project. In Visual Studio, this can be set in the Android Options page of project Properties, under the Advanced tab, as shown in the following screenshot:
Android Options Advanced properties
In Xamarin Studio, the supported architectures may be selected on the Android Build page of Project Options, under the Advanced tab, as shown in the following screenshot:
Android Build Supported ABIs
There are some situations when it may be necessary to declare additional ABI support such as when:

  • Deploying the application to an x86 device.
  • Deploying the application to an armeabi-v7a device to ensure thread safety.

Summary

This document discussed the different CPU architectures that an Android application may run on. It introduced the Application Binary Interface and how it is used by Android to support disparate CPU architectures. It then went on to discuss how to specify ABI support in a Xamarin.Android application and highlighted the issues that arise when using Xamarin.Android applications on an armeabi-v7a
device that are intended only for armeabi.