Pengelolaan ABI

Handset Android berbeda menggunakan CPU berbeda, yang pada akhirnya mendukung set instruksi berbeda pula. Setiap kombinasi CPU dan set instruksi memiliki Application Binary Interface, atau ABI sendiri. ABI menentukan, dengan presisi yang tinggi, bagaimana kode mesin suatu aplikasi seharusnya berinteraksi dengan sistem pada pada waktu proses. Anda harus menentukan ABI untuk setiap arsitektur CPU agar dapat berfungsi dengan aplikasi yang diinginkan.

Umumnya ABI menyertakan informasi berikut:

  • Set instruksi CPU yang harus digunakan oleh kode mesin.
  • Endianess penyimpanan dan pemuatan memori pada waktu proses.
  • Format biner executable, seperti program dan library bersama, dan jenis konten yang didukungnya.
  • Berbagai konvensi untuk meneruskan data di antara kode dan sistem. Konvensi ini mencakup kendala penyelarasan, beserta cara sistem menggunakan tumpukan dan register ketika memanggil fungsi.
  • Daftar simbol fungsi yang tersedia untuk kode mesin Anda pada waktu proses, umumnya dari kumpulan library yang sangat spesifik.

Halaman ini mengenumerasi ABI yang didukung NDK, dan memberikan informasi tentang cara kerja masing-masing ABI. Untuk daftar masalah ABI pada sistem 32-bit, lihat bug ABI 32-bit

ABI yang Didukung

Setiap ABI mendukung satu atau beberapa set instruksi. Tabel 1 memberikan gambaran sekilas set instruksi yang didukung masing-masing ABI.

Tabel 1. ABI dan set instruksi yang didukung.

ABI Set Instruksi yang Didukung Catatan
armeabi
  • ARMV5TE dan yang lebih baru
  • Thumb-1
  • Tidak digunakan lagi di r16. Dihapus dalam r17. Tidak ada hard float.
    armeabi-v7a
  • armeabi
  • Thumb-2
  • VFPv3-D16
  • Lainnya, opsional
  • Tidak kompatibel dengan perangkat ARMv5, v6.
    arm64-v8a
  • AArch64
  • x86
  • x86 (IA-32)
  • MMX
  • SSE/2/3
  • SSSE3
  • Tidak ada dukungan untuk MOVBE atau SSE4.
    x86_64
  • x86-64
  • MMX
  • SSE/2/3
  • SSSE3
  • SSE4.1, 4.2
  • POPCNT
  • Catatan: Secara historis, NDK mendukung MIPS 32-bit dan 64-bit, tetapi dukungan tersebut dihapus pada NDK r17.

    Informasi lebih detail tentang setiap ABI ditampilkan di bawah ini.

    armeabi

    Catatan: ABI ini telah dihapus pada NDK r17.

    ABI ini ditujukan untuk CPU berbasis ARM yang mendukung setidaknya set instruksi ARMv5TE. Silakan lihat dokumentasi berikut untuk detail lebih lanjut:

    Standar AAPCS menentukan EABI sebagai kumpulan ABI yang serupa tetapi berbeda. Selain itu, Android mengikuti ARM GNU/Linux ABI little-endian.

    ABI ini tidak mendukung komputasi bilangan titik mengambang yang dibantu hardware. Sebagai gantinya, semua operasi bilangan titik mengambang menggunakan fungsi pembantu software dari library statis libgcc.a compiler.

    armeabi ABI mendukung set instruksi Thumb (alias Thumb-1) ARM. NDK menghasilkan kode Thumb secara default kecuali jika Anda menentukan perilaku yang berbeda menggunakan variabel LOCAL_ARM_MODE dalam file Android.mk Anda.

    armeabi-v7a

    ABI ini memperluas armeabi untuk mencakup beberapa ekstensi set instruksi CPU. Ekstensi instruksi yang didukung ABI khusus Android ini adalah:

    • Ekstensi set instruksi Thumb-2, yang memberikan performa yang sebanding dengan instruksi ARM 32-bit dengan keringkasan yang serupa dengan Thumb-1.
    • Instruksi FPU hardware VFP. Lebih spesifiknya, VFPv3-D16, yang mencakup 16 register bilangan titik mengambang 64-bit khusus, selain 16 register 32-bit lainnya dari inti ARM.

    Ekstensi lain yang dideskripsikan oleh spesifikasi ARM v7-a, termasuk Advanced SIMD (alias NEON), VFPv3-D32, dan ThumbEE, bersifat opsional untuk ABI ini. Karena keberadaannya tidak dijamin, sistem harus memeriksa pada waktu proses apakah ekstensi tersebut tersedia. Jika tidak ada, Anda harus menggunakan jalur kode alternatif. Pemeriksaan ini mirip dengan yang biasanya dilakukan sistem untuk memeriksa atau menggunakan MMX, SSE2, dan set instruksi khusus lainnya pada CPU x86.

    Untuk informasi tentang cara menjalankan pemeriksaan waktu proses ini, lihat Library cpufeatures. Selain itu, untuk informasi dukungan NDK dalam membuat kode mesin untuk NEON, lihat Dukungan NEON.

    armeabi-v7a ABI menggunakan switch -mfloat-abi=softfp untuk menerapkan aturan bahwa compiler harus meneruskan semua nilai ganda dalam pasangan register inti selama pemanggilan fungsi, bukan nilai titik mengambang khusus. Sistem dapat menjalankan semua komputasi internal menggunakan register FP. Hal itu akan sangat mempercepat komputasi.

    arm64-v8a

    ABI ini adalah untuk CPU berbasis ARMv8 yang mendukung AArch64. ABI tersebut juga menyertakan set instruksi NEON dan VFPv4.

    Untuk informasi lebih lanjut, lihat Pratinjau Teknologi ARMv8, dan hubungi ARM untuk mendapatkan informasi selengkapnya.

    x86

    ABI ini adalah untuk CPU yang mendukung set instruksi yang biasanya disebut "x86" atau "IA-32". Karakteristik ABI ini antara lain:

    • Instruksi biasanya dihasilkan oleh GCC dengan tanda compiler seperti berikut:
          -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32
          

      Tanda ini menargetkan set instruksi Pentium Pro, beserta ekstensi set instruksi MMX, SSE, SSE2, SSE3, dan SSSE3. Kode yang dihasilkan adalah pengoptimalan yang diseimbangkan ke seluruh CPU 32-bit Intel teratas.

      Untuk informasi lebih lanjut tentang tanda compiler, khususnya yang berkaitan dengan pengoptimalan performa, lihat Petunjuk performa GCC x86.

    • Gunakan konvensi pemanggilan 32-bit x86 Linux standar, bukan yang ditujukan untuk SVR. Untuk informasi selengkapnya, lihat bagian 6, "Penggunaan Register" pada Konvensi pemanggilan untuk berbagai compiler C++ dan sistem operasi.

    ABI ini tidak mencakup ekstensi set instruksi IA-32 opsional lainnya, seperti:

    • MOVBE
    • Semua varian SSE4.

    Anda masih dapat menggunakan ekstensi ini, selama Anda menggunakan pendeteksian fitur waktu proses untuk mengaktifkannya, dan menyediakan fallback untuk perangkat yang tidak mendukungnya.

    Toolchain NDK mengasumsikan penyelarasan tumpukan 16-byte sebelum panggilan fungsi. Fitur dan opsi default menerapkan aturan ini. Jika menulis kode assembly, Anda harus memastikan untuk mempertahankan keselarasan tumpukan, dan memastikan bahwa compiler lain juga mematuhi aturan ini.

    Lihat dokumen berikut untuk detail selengkapnya:

    x86_64

    ABI ini adalah untuk CPU yang mendukung set instruksi yang biasanya disebut "x86-64". ABI ini mendukung instruksi yang biasanya dihasilkan GCC dengan tanda compiler berikut:

        -march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=intel
        

    Tanda ini menargetkan set instruksi x86-64, menurut dokumentasi GCC, beserta ekstensi set instruksi MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, dan POPCNT. Kode yang dihasilkan adalah pengoptimalan yang diseimbangkan ke seluruh CPU 64-bit Intel teratas.

    Untuk informasi lebih lanjut tentang tanda compiler, khususnya yang berkaitan dengan optimisasi performa, lihat Performa GCC x86.

    ABI ini tidak mencakup ekstensi set instruksi x86-64 opsional lainnya, seperti:

    • MOVBE
    • SHA
    • AVX
    • AVX2

    Anda masih dapat menggunakan ekstensi ini, selama Anda menggunakan pendeteksian fitur waktu proses untuk mengaktifkannya, dan menyediakan fallback untuk perangkat yang tidak mendukungnya.

    Lihat dokumen berikut untuk detail selengkapnya:

    Menghasilkan Kode untuk ABI Tertentu

    Secara default, NDK menargetkan semua ABI yang masih digunakan. Anda dapat menargetkan ABI tunggal dengan menetapkan APP_ABI pada file Application.mk Anda. Cuplikan berikut menampilkan beberapa contoh penggunaan APP_ABI

        APP_ABI := arm64-v8a  # Target only arm64-v8a
        APP_ABI := all  # Target all ABIs, including those that are deprecated.
        APP_ABI := armeabi-v7a x86_64  # Target only armeabi-v7a and x86_64.
        

    Untuk informasi selengkapnya tentang nilai yang dapat Anda tetapkan untuk APP_ABI, lihat Application.mk.

    Perilaku default sistem build adalah memasukkan semua biner untuk setiap ABI ke dalam sebuah APK, yang disebut juga APK gemuk. APK gemuk jauh lebih besar daripada APK yang hanya memuat biner untuk satu ABI tunggal. Hasilnya adalah kompatibilitas yang lebih luas, tetapi dengan ukuran APK yang lebih besar. Sebaiknya Anda memanfaatkan APK terpisah untuk mengurangi ukuran APK sambil tetap mempertahankan kompatibilitas perangkat secara maksimum.

    Pada waktu penginstalan, pengelola paket hanya mengekstrak kode mesin yang paling sesuai untuk perangkat target. Untuk detailnya, lihat Ekstraksi otomatis kode native pada waktu penginstalan.

    Pengelolaan ABI pada Platform Android

    Bagian ini menjelaskan tentang bagaimana platform Android mengelola kode native di APK.

    Kode native dalam paket aplikasi

    Baik Play Store maupun Package Manager berharap untuk menemukan library yang dihasilkan NDK pada jalur file di dalam APK yang cocok dengan pola berikut:

        /lib/<abi>/lib<name>.so
        

    Di sini, <abi> adalah salah satu nama ABI yang tercantum di bagian ABI yang Didukung, dan <name> adalah nama library yang Anda tentukan untuk variabel LOCAL_MODULE dalam file Android.mk. Karena hanya berupa file zip, file APK mudah dibuka untuk mengonfirmasi bahwa library native bersama berada di tempat yang seharusnya.

    Jika sistem tidak menemukan library native bersama di tempat yang seharusnya, maka sistem tidak akan dapat menggunakannya. Dalam kasus semacam ini, aplikasi itu sendiri harus menyalin library, dan kemudian menjalankan dlopen().

    Dalam APK gemuk, setiap library berada di bagian direktori yang namanya cocok dengan ABI yang terkait. Misalnya, APK gemuk dapat memuat:

        /lib/armeabi/libfoo.so
        /lib/armeabi-v7a/libfoo.so
        /lib/arm64-v8a/libfoo.so
        /lib/x86/libfoo.so
        /lib/x86_64/libfoo.so
        

    Catatan: Perangkat Android berbasis ARMv7 yang menjalankan 4.0.3 atau yang lebih lama menginstal library native dari direktori armeabi, bukan dari armeabi-v7a, jika kedua direktori tersebut ada. Hal ini karena /lib/armeabi/ muncul setelah /lib/armeabi-v7a/ di APK. Masalah ini diperbaiki mulai 4.0.4.

    Dukungan ABI Platform Android

    Sistem Android mengetahui pada pada waktu proses ABI mana yang didukungnya, karena properti sistem khusus build menunjukkan:

    • ABI primer untuk perangkat, yang sesuai dengan kode mesin yang digunakan dalam gambar sistem itu sendiri.
    • ABI sekunder (opsional), yang sesuai dengan ABI lain yang juga didukung gambar sistem.

    Mekanisme ini memastikan bahwa sistem mengekstrak kode mesin terbaik dari paket pada waktu penginstalan.

    Untuk performa terbaik, sebaiknya Anda membuat kompilasi langsung untuk ABI primer. Misalnya, perangkat berbasis ARMv5TE standar hanya akan menentukan ABI primer: armeabi. Sebaliknya, perangkat berbasis ARMv7 standar akan menentukan ABI primer sebagai armeabi-v7a dan ABI sekunder sebagai armeabi, karena perangkat ini dapat menjalankan biner native aplikasi yang dihasilkan untuk setiap ABI.

    Perangkat 64-bit juga mendukung varian 32-bit. Menggunakan perangkat arm64-v8a sebagai contoh, perangkat ini juga dapat menjalankan kode armeabi dan armeabi-v7a. Namun, perlu diketahui bahwa aplikasi Anda akan berperforma jauh lebih baik pada perangkat 64-bit jika menargetkan arm64-v8a daripada mengandalkan perangkat yang menjalankan versi armeabi-v7a untuk aplikasi Anda.

    Banyak perangkat berbasis x86 juga dapat menjalankan biner NDK armeabi-v7a dan armeabi. Untuk perangkat semacam itu, ABI primer adalah x86, dan sekundernya adalah armeabi-v7a.

    Ekstraksi otomatis kode native pada waktu penginstalan

    Saat menginstal aplikasi, layanan pengelola paket memindai APK, dan mencari setiap library bersama yang berformat:

        lib/<primary-abi>/lib<name>.so
        

    Jika tidak ada yang ditemukan, dan Anda telah menentukan ABI sekunder, layanan akan mencari library bersama yang berformat:

        lib/<secondary-abi>/lib<name>.so
        

    Setelah menemukan library yang dicari, pengelola paket akan menyalinnya ke /lib/lib<name>.so, di bagian direktori data aplikasi (data/data/<package_name>/lib/).

    Jika tidak ada file objek bersama, aplikasi akan membuat dan menginstalnya, tetapi akan mengalami error pada waktu proses.