AIDL Stabil

Android 10 menambahkan dukungan untuk Android Interface Definition Language (AIDL) yang stabil, cara baru untuk melacak antarmuka program aplikasi (API) dan antarmuka biner aplikasi (ABI) yang disediakan oleh antarmuka AIDL. AIDL stabil berfungsi persis seperti AIDL, tetapi sistem build melacak kompatibilitas antarmuka, dan ada batasan pada hal yang dapat Anda lakukan:

  • Antarmuka ditentukan dalam sistem build dengan aidl_interfaces.
  • Antarmuka hanya dapat berisi data terstruktur. Parcelable yang mewakili jenis yang dipilih akan otomatis dibuat berdasarkan definisi AIDL-nya dan otomatis dimarshal dan diunmarshal.
  • Antarmuka dapat dideklarasikan sebagai stabil (kompatibel dengan versi sebelumnya). Jika hal ini terjadi, API-nya akan dilacak dan diberi versi dalam file di samping antarmuka AIDL.

AIDL terstruktur versus stabil

AIDL Terstruktur mengacu pada jenis yang ditentukan sepenuhnya di AIDL. Misalnya, deklarasi parcelable (parcelable kustom) bukan AIDL terstruktur. Parcelable dengan kolomnya yang ditentukan di AIDL disebut parcelable terstruktur.

AIDL Stabil memerlukan AIDL terstruktur sehingga sistem build dan compiler dapat memahami apakah perubahan yang dilakukan pada parcelable kompatibel dengan versi sebelumnya. Namun, tidak semua antarmuka terstruktur stabil. Agar stabil, antarmuka hanya boleh menggunakan jenis terstruktur, dan juga harus menggunakan fitur pembuatan versi berikut. Sebaliknya, antarmuka tidak stabil jika sistem build inti digunakan untuk membangunnya atau jika unstable:true disetel.

Menentukan antarmuka AIDL

Definisi aidl_interface akan terlihat seperti ini:

aidl_interface {
    name: "my-aidl",
    srcs: ["srcs/aidl/**/*.aidl"],
    local_include_dir: "srcs/aidl",
    imports: ["other-aidl"],
    versions_with_info: [
        {
            version: "1",
            imports: ["other-aidl-V1"],
        },
        {
            version: "2",
            imports: ["other-aidl-V3"],
        }
    ],
    stability: "vintf",
    backend: {
        java: {
            enabled: true,
            platform_apis: true,
        },
        cpp: {
            enabled: true,
        },
        ndk: {
            enabled: true,
        },
        rust: {
            enabled: true,
        },
    },

}
  • name: Nama modul antarmuka AIDL yang mengidentifikasi antarmuka AIDL secara unik.
  • srcs: Daftar file sumber AIDL yang menyusun antarmuka. Jalur untuk jenis AIDL Foo yang ditentukan dalam paket com.acme harus berada di <base_path>/com/acme/Foo.aidl, dengan <base_path> dapat berupa direktori apa pun yang terkait dengan direktori tempat Android.bp berada. Dalam contoh sebelumnya, <base_path> adalah srcs/aidl.
  • local_include_dir: Jalur tempat nama paket dimulai. Ini sesuai dengan <base_path> yang dijelaskan di atas.
  • imports: Daftar modul aidl_interface yang digunakan. Jika salah satu antarmuka AIDL Anda menggunakan antarmuka atau parcelable dari aidl_interface lain, masukkan namanya di sini. Nama dapat berupa nama itu sendiri, untuk merujuk ke versi terbaru, atau nama dengan akhiran versi (seperti -V1) untuk merujuk ke versi tertentu. Menentukan versi telah didukung sejak Android 12
  • versions: Versi antarmuka sebelumnya yang dibekukan di api_dir. Mulai Android 11, versions dibekukan di aidl_api/name. Jika tidak ada versi antarmuka yang dibekukan, hal ini tidak boleh ditentukan, dan tidak akan ada pemeriksaan kompatibilitas. Kolom ini telah diganti dengan versions_with_info untuk Android 13 dan yang lebih baru.
  • versions_with_info: Daftar tuple, yang masing-masing berisi nama versi beku dan daftar dengan impor versi modul aidl_interface lain yang diimpor oleh versi aidl_interface ini. Definisi versi V dari antarmuka AIDL IFACE terletak di aidl_api/IFACE/V. Kolom ini diperkenalkan di Android 13, dan tidak boleh diubah di Android.bp secara langsung. Kolom ditambahkan atau diperbarui dengan memanggil *-update-api atau *-freeze-api. Selain itu, kolom versions otomatis dimigrasikan ke versions_with_info saat pengguna memanggil *-update-api atau *-freeze-api.
  • stability: Flag opsional untuk janji stabilitas antarmuka ini. Ini hanya mendukung "vintf". Jika stability tidak ditetapkan, sistem build akan memeriksa apakah antarmuka kompatibel dengan versi sebelumnya, kecuali unstable ditentukan. Tidak ditetapkan sesuai dengan antarmuka dengan stabilitas dalam konteks kompilasi ini (jadi semua hal sistem, misalnya, hal-hal di system.img dan partisi terkait, atau semua hal vendor, misalnya, hal-hal di vendor.img dan partisi terkait). Jika stability ditetapkan ke "vintf", hal ini sesuai dengan janji stabilitas: antarmuka harus tetap stabil selama digunakan.
  • gen_trace: Flag opsional untuk mengaktifkan atau menonaktifkan pelacakan. Mulai Android 14, defaultnya adalah true untuk backend cpp dan java.
  • host_supported: Flag opsional yang jika ditetapkan ke true akan membuat library yang dihasilkan tersedia untuk lingkungan host.
  • unstable: Flag opsional yang digunakan untuk menandai bahwa antarmuka ini tidak perlu stabil. Jika ditetapkan ke true, sistem build tidak akan membuat dump API untuk antarmuka atau mengharuskannya diupdate.
  • frozen: Flag opsional yang jika ditetapkan ke true berarti antarmuka tidak mengalami perubahan sejak antarmuka versi sebelumnya. Hal ini memungkinkan lebih banyak pemeriksaan waktu build. Jika ditetapkan ke false, ini berarti antarmuka sedang dalam pengembangan dan memiliki perubahan baru sehingga menjalankan foo-freeze-api akan menghasilkan versi baru dan secara otomatis mengubah nilai menjadi true. Diperkenalkan di Android 14.
  • backend.<type>.enabled: Flag ini mengalihkan setiap backend yang dibuat kodenya oleh compiler AIDL. Empat backend didukung: Java, C++, NDK, dan Rust. Backend Java, C++, dan NDK diaktifkan secara default. Jika salah satu dari ketiga backend ini tidak diperlukan, backend tersebut harus dinonaktifkan secara eksplisit. Rust dinonaktifkan secara default hingga Android 15.
  • backend.<type>.apex_available: Daftar nama APEX yang tersedia untuk library stub yang dihasilkan.
  • backend.[cpp|java].gen_log: Flag opsional yang mengontrol apakah akan membuat kode tambahan untuk mengumpulkan informasi tentang transaksi.
  • backend.[cpp|java].vndk.enabled: Flag opsional untuk menjadikan antarmuka ini bagian dari VNDK. Default-nya adalah false.
  • backend.[cpp|ndk].additional_shared_libraries: Diperkenalkan di Android 14, flag ini menambahkan dependensi ke library native. Flag ini berguna dengan ndk_header dan cpp_header.
  • backend.java.sdk_version: Flag opsional untuk menentukan versi SDK yang digunakan untuk mem-build library stub Java. Defaultnya adalah "system_current". Ini tidak boleh ditetapkan jika backend.java.platform_apis adalah true.
  • backend.java.platform_apis: Flag opsional yang harus ditetapkan ke true saat library yang dihasilkan perlu di-build terhadap API platform, bukan SDK.

Untuk setiap kombinasi versi dan backend yang diaktifkan, library stub akan dibuat. Untuk mengetahui cara merujuk ke versi tertentu library stub untuk backend tertentu, lihat Aturan penamaan modul.

Menulis file AIDL

Antarmuka dalam AIDL stabil mirip dengan antarmuka tradisional, dengan pengecualian bahwa antarmuka tersebut tidak diizinkan untuk menggunakan parcelable yang tidak terstruktur (karena tidak stabil. lihat AIDL terstruktur versus stabil). Perbedaan utama dalam AIDL stabil adalah cara penentuan parcelable. Sebelumnya, parcelable dideklarasikan ke depan; dalam AIDL yang stabil (dan karenanya terstruktur), kolom dan variabel parcelable ditentukan secara eksplisit.

// in a file like 'some/package/Thing.aidl'
package some.package;

parcelable SubThing {
    String a = "foo";
    int b;
}

Default didukung (tetapi tidak diperlukan) untuk boolean, char, float, double, byte, int, long, dan String. Di Android 12, default untuk enumerasi yang ditentukan pengguna juga didukung. Jika default tidak ditentukan, nilai seperti 0 atau kosong akan digunakan. Enumerasi tanpa nilai default diinisialisasi ke 0 meskipun tidak ada enumerator nol.

Menggunakan library stub

Setelah menambahkan library stub sebagai dependensi ke modul, Anda dapat menyertakannya ke dalam file. Berikut adalah contoh library stub dalam sistem build (Android.mk juga dapat digunakan untuk definisi modul lama):

cc_... {
    name: ...,
    shared_libs: ["my-module-name-cpp"],
    ...
}
# or
java_... {
    name: ...,
    // can also be shared_libs if your preference is to load a library and share
    // it among multiple users or if you only need access to constants
    static_libs: ["my-module-name-java"],
    ...
}
# or
rust_... {
    name: ...,
    rustlibs: ["my-module-name-rust"],
    ...
}

Contoh dalam C++:

#include "some/package/IFoo.h"
#include "some/package/Thing.h"
...
    // use just like traditional AIDL

Contoh di Java:

import some.package.IFoo;
import some.package.Thing;
...
    // use just like traditional AIDL

Contoh di Rust:

use aidl_interface_name::aidl::some::package::{IFoo, Thing};
...
    // use just like traditional AIDL

Antarmuka pembuatan versi

Mendeklarasikan modul dengan nama foo juga akan membuat target dalam sistem build yang dapat Anda gunakan untuk mengelola API modul. Saat di-build, foo-freeze-api menambahkan definisi API baru di bagian api_dir atau aidl_api/name, bergantung pada versi Android, dan menambahkan file .hash, yang keduanya mewakili versi antarmuka yang baru dibekukan. foo-freeze-api juga memperbarui properti versions_with_info untuk mencerminkan versi tambahan dan imports untuk versi tersebut. Pada dasarnya, imports di versions_with_info disalin dari kolom imports. Namun, versi stabil terbaru ditentukan di imports di versions_with_info untuk impor, yang tidak memiliki versi eksplisit. Setelah properti versions_with_info ditentukan, sistem build akan menjalankan pemeriksaan kompatibilitas antara versi frozen serta antara Top of Tree (ToT) dan versi frozen terbaru.

Selain itu, Anda perlu mengelola definisi API versi ToT. Setiap kali API diupdate, jalankan foo-update-api untuk mengupdate aidl_api/name/current yang berisi definisi API versi ToT.

Untuk mempertahankan stabilitas antarmuka, pemilik dapat menambahkan:

  • Metode ke akhir antarmuka (atau metode dengan serial baru yang ditentukan secara eksplisit)
  • Elemen ke akhir parcelable (memerlukan default yang ditambahkan untuk setiap elemen)
  • Nilai konstan
  • Di Android 11, penghitung
  • Di Android 12, kolom ke akhir union

Tidak ada tindakan lain yang diizinkan, dan tidak ada orang lain yang dapat mengubah antarmuka (jika tidak, mereka berisiko mengalami konflik dengan perubahan yang dilakukan pemilik).

Untuk menguji apakah semua antarmuka dibekukan untuk dirilis, Anda dapat mem-build dengan kumpulan variabel lingkungan berikut:

  • AIDL_FROZEN_REL=true m ... - build mengharuskan semua antarmuka AIDL yang stabil dibekukan yang tidak memiliki kolom owner: yang ditentukan.
  • AIDL_FROZEN_OWNERS="aosp test" - build memerlukan semua antarmuka AIDL yang stabil untuk dibekukan dengan kolom owner: yang ditentukan sebagai "aosp" atau "test".

Stabilitas impor

Memperbarui versi impor untuk versi antarmuka yang dibekukan kompatibel dengan versi sebelumnya di lapisan AIDL Stabil. Namun, untuk mengupdatenya, Anda harus mengupdate semua server dan klien yang menggunakan antarmuka versi sebelumnya, dan beberapa aplikasi mungkin akan bingung saat menggabungkan berbagai versi jenis. Umumnya, untuk paket khusus jenis atau umum, hal ini aman karena kode harus sudah ditulis untuk menangani jenis yang tidak diketahui dari transaksi IPC.

Dalam kode platform Android, kode android.hardware.graphics.common adalah contoh terbesar dari jenis upgrade versi ini.

Menggunakan antarmuka berversi

Metode antarmuka

Saat runtime, ketika mencoba memanggil metode baru di server lama, klien baru akan mendapatkan error atau pengecualian, bergantung pada backend-nya.

  • Backend cpp mendapatkan ::android::UNKNOWN_TRANSACTION.
  • Backend ndk mendapatkan STATUS_UNKNOWN_TRANSACTION.
  • Backend java mendapatkan android.os.RemoteException dengan pesan yang menyatakan bahwa API tidak diterapkan.

Untuk strategi guna menangani hal ini, lihat membuat kueri versi dan menggunakan default.

Parcelable

Saat kolom baru ditambahkan ke parcelables, klien dan server lama akan menghapusnya. Saat klien dan server baru menerima parcelable lama, nilai default untuk kolom baru akan otomatis diisi. Artinya, default harus ditentukan untuk semua kolom baru dalam parcelable.

Klien tidak boleh mengharapkan server menggunakan kolom baru kecuali jika mereka tahu bahwa server menerapkan versi yang memiliki kolom yang ditentukan (lihat membuat kueri versi).

Enum dan konstanta

Demikian pula, klien dan server harus menolak atau mengabaikan nilai konstan dan enumerator yang tidak dikenal sesuai kebutuhan, karena lebih banyak nilai yang dapat ditambahkan di masa mendatang. Misalnya, server tidak boleh dibatalkan saat menerima enumerator yang tidak diketahui. Server harus mengabaikan enumerator, atau menampilkan sesuatu agar klien tahu bahwa enumerator tidak didukung dalam implementasi ini.

Serikat

Mencoba mengirim union dengan kolom baru akan gagal jika penerima sudah lama dan tidak mengetahui kolom tersebut. Implementasi tidak akan pernah melihat gabungan dengan kolom baru. Kegagalan akan diabaikan jika merupakan transaksi satu arah; jika tidak, error-nya adalah BAD_VALUE(untuk backend C++ atau NDK) atau IllegalArgumentException(untuk backend Java). Error akan diterima jika klien mengirim gabungan yang ditetapkan ke kolom baru ke server lama, atau jika klien lama menerima gabungan dari server baru.

Mengelola beberapa versi

Namespace penaut di Android hanya dapat memiliki 1 versi antarmuka aidl tertentu untuk menghindari situasi saat jenis aidl yang dihasilkan memiliki beberapa definisi. C++ memiliki Satu Aturan Definisi yang hanya memerlukan satu definisi dari setiap simbol.

Build Android akan menampilkan error jika modul bergantung pada versi yang berbeda dari library aidl_interface yang sama. Modul mungkin bergantung pada library ini secara langsung atau tidak langsung melalui dependensi dependensinya. Error ini menunjukkan grafik dependensi dari modul yang gagal ke versi library aidl_interface yang bertentangan. Semua dependensi perlu diupdate untuk menyertakan versi library yang sama (biasanya versi terbaru) dari library ini.

Jika library antarmuka digunakan oleh banyak modul yang berbeda, sebaiknya buat cc_defaults, java_defaults, dan rust_defaults untuk setiap grup library dan proses yang perlu menggunakan versi yang sama. Saat memperkenalkan versi antarmuka baru, default tersebut dapat diperbarui dan semua modul yang menggunakannya akan diperbarui bersama, sehingga memastikan modul tersebut tidak menggunakan versi antarmuka yang berbeda.

cc_defaults {
  name: "my.aidl.my-process-group-ndk-shared",
  shared_libs: ["my.aidl-V3-ndk"],
  ...
}

cc_library {
  name: "foo",
  defaults: ["my.aidl.my-process-group-ndk-shared"],
  ...
}

cc_binary {
  name: "bar",
  defaults: ["my.aidl.my-process-group-ndk-shared"],
  ...
}

Saat modul aidl_interface mengimpor modul aidl_interface lainnya, tindakan ini akan membuat dependensi tambahan yang memerlukan versi tertentu untuk digunakan bersama. Situasi ini dapat menjadi sulit dikelola jika ada modul aidl_interface umum yang diimpor dalam beberapa modul aidl_interface yang digunakan bersama dalam proses yang sama.

aidl_interfaces_defaults dapat digunakan untuk menyimpan satu definisi versi terbaru dependensi untuk aidl_interface yang dapat diperbarui di satu tempat, dan digunakan oleh semua modul aidl_interface yang ingin mengimpor antarmuka umum tersebut.

aidl_interface_defaults {
  name: "android.popular.common-latest-defaults",
  imports: ["android.popular.common-V3"],
  ...
}

aidl_interface {
  name: "android.foo",
  defaults: ["my.aidl.latest-ndk-shared"],
  ...
}

aidl_interface {
  name: "android.bar",
  defaults: ["my.aidl.latest-ndk-shared"],
  ...
}

Pengembangan berbasis flag

Antarmuka dalam pengembangan (tidak dibekukan) tidak dapat digunakan di perangkat rilis, karena tidak dijamin kompatibel dengan versi sebelumnya.

AIDL mendukung penggantian waktu proses untuk library antarmuka yang tidak dibekukan ini agar kode dapat ditulis terhadap versi terbaru yang tidak dibekukan dan masih digunakan pada perangkat rilis. Perilaku klien yang kompatibel dengan versi sebelumnya mirip dengan perilaku yang ada dan dengan penggantian, implementasi juga harus mengikuti perilaku tersebut. Lihat Menggunakan antarmuka berversi.

Flag build AIDL

Flag yang mengontrol perilaku ini adalah RELEASE_AIDL_USE_UNFROZEN yang ditentukan dalam build/release/build_flags.bzl. true berarti versi antarmuka yang tidak dibekukan digunakan pada waktu proses dan false berarti library versi yang tidak dibekukan semuanya berperilaku seperti versi terakhir yang dibekukan. Anda dapat mengganti tanda ke true untuk pengembangan lokal, tetapi harus mengembalikannya ke false sebelum rilis. Biasanya, pengembangan dilakukan dengan konfigurasi yang memiliki tanda yang ditetapkan ke true.

Matriks dan manifes kompatibilitas

Objek antarmuka vendor (objek VINTF) menentukan versi yang diharapkan, dan versi yang disediakan di kedua sisi antarmuka vendor.

Sebagian besar perangkat non-Cuttlefish menargetkan matriks kompatibilitas terbaru hanya setelah antarmuka dibekukan, sehingga tidak ada perbedaan dalam library AIDL berdasarkan RELEASE_AIDL_USE_UNFROZEN.

Matriks

Antarmuka milik partner ditambahkan ke matriks kompatibilitas khusus perangkat atau khusus produk yang ditargetkan perangkat selama pengembangan. Jadi, saat versi antarmuka baru yang tidak dibekukan ditambahkan ke matriks kompatibilitas, versi beku sebelumnya harus tetap ada untuk RELEASE_AIDL_USE_UNFROZEN=false. Anda dapat menangani hal ini dengan menggunakan file matriks kompatibilitas yang berbeda untuk konfigurasi RELEASE_AIDL_USE_UNFROZEN yang berbeda atau mengizinkan kedua versi dalam satu file matriks kompatibilitas yang digunakan di semua konfigurasi.

Misalnya, saat menambahkan versi 4 yang tidak dibekukan, gunakan <version>3-4</version>.

Saat versi 4 dibekukan, Anda dapat menghapus versi 3 dari matriks kompatibilitas karena versi 4 yang dibekukan digunakan saat RELEASE_AIDL_USE_UNFROZEN adalah false.

Manifes

Di Android 15, perubahan pada libvintf diperkenalkan untuk mengubah file manifes pada waktu build berdasarkan nilai RELEASE_AIDL_USE_UNFROZEN.

Manifes dan fragmen manifes mendeklarasikan versi antarmuka yang diimplementasikan layanan. Saat menggunakan versi antarmuka terbaru yang tidak dibekukan, manifes harus diupdate untuk mencerminkan versi baru ini. Saat RELEASE_AIDL_USE_UNFROZEN=false, entri manifes disesuaikan oleh libvintf untuk mencerminkan perubahan dalam library AIDL yang dihasilkan. Versi diubah dari versi yang tidak dibekukan, N, menjadi versi terakhir yang dibekukan N - 1. Oleh karena itu, pengguna tidak perlu mengelola beberapa manifes atau fragmen manifes untuk setiap layanan mereka.

Perubahan klien HAL

Kode klien HAL harus kompatibel dengan setiap versi frozen sebelumnya yang didukung. Jika RELEASE_AIDL_USE_UNFROZEN adalah false, layanan akan selalu terlihat seperti versi terakhir yang dibekukan atau yang lebih lama (misalnya, memanggil metode baru yang tidak dibekukan akan menampilkan UNKNOWN_TRANSACTION, atau kolom parcelable baru memiliki nilai defaultnya). Klien framework Android harus kompatibel dengan versi sebelumnya yang tambahan, tetapi ini adalah detail baru untuk klien vendor dan klien antarmuka milik partner.

Perubahan implementasi HAL

Perbedaan terbesar dalam pengembangan HAL dengan pengembangan berbasis tanda adalah persyaratan untuk implementasi HAL agar kompatibel dengan versi frozen terakhir agar berfungsi saat RELEASE_AIDL_USE_UNFROZEN adalah false. Mempertimbangkan kompatibilitas mundur dalam implementasi dan kode perangkat merupakan latihan baru. Lihat Menggunakan antarmuka berversi.

Pertimbangan kompatibilitas mundur umumnya sama untuk klien dan server, serta untuk kode framework dan kode vendor, tetapi ada perbedaan kecil yang perlu Anda perhatikan, karena sekarang Anda secara efektif menerapkan dua versi yang menggunakan kode sumber yang sama (versi saat ini yang tidak dibekukan ).

Contoh: Antarmuka memiliki tiga versi yang dibekukan. Antarmuka diperbarui dengan metode baru. Klien dan layanan diupdate untuk menggunakan library versi 4 baru. Karena library V4 didasarkan pada versi antarmuka yang tidak dibekukan, library ini berperilaku seperti versi beku terakhir, versi 3, saat RELEASE_AIDL_USE_UNFROZEN adalah false, dan mencegah penggunaan metode baru.

Saat antarmuka dibekukan, semua nilai RELEASE_AIDL_USE_UNFROZEN akan menggunakan versi yang dibekukan, dan kode yang menangani kompatibilitas mundur dapat dihapus.

Saat memanggil metode pada callback, Anda harus menangani kasus dengan baik ketika UNKNOWN_TRANSACTION ditampilkan. Klien mungkin menerapkan dua versi callback yang berbeda berdasarkan konfigurasi rilis, sehingga Anda tidak dapat mengasumsikan bahwa klien mengirim versi terbaru, dan metode baru mungkin menampilkannya. Hal ini mirip dengan cara klien AIDL yang stabil mempertahankan kompatibilitas mundur dengan server yang dijelaskan dalam Menggunakan antarmuka berversi.

// Get the callback along with the version of the callback
ScopedAStatus RegisterMyCallback(const std::shared_ptr<IMyCallback>& cb) override {
    mMyCallback = cb;
    // Get the version of the callback for later when we call methods on it
    auto status = mMyCallback->getInterfaceVersion(&mMyCallbackVersion);
    return status;
}

// Example of using the callback later
void NotifyCallbackLater() {
  // From the latest frozen version (V2)
  mMyCallback->foo();
  // Call this method from the unfrozen V3 only if the callback is at least V3
  if (mMyCallbackVersion >= 3) {
    mMyCallback->bar();
  }
}

Kolom baru dalam jenis yang ada (parcelable, enum, union) mungkin tidak ada atau berisi nilai default-nya saat RELEASE_AIDL_USE_UNFROZEN adalah false dan nilai kolom baru yang coba dikirim layanan akan dihapus saat keluar dari proses.

Jenis baru yang ditambahkan dalam versi yang tidak dibekukan ini tidak dapat dikirim atau diterima melalui antarmuka.

Implementasi tidak pernah mendapatkan panggilan untuk metode baru dari klien jika RELEASE_AIDL_USE_UNFROZEN adalah false.

Berhati-hatilah untuk menggunakan penghitung baru hanya dengan versi tempat penghitung tersebut diperkenalkan, dan bukan versi sebelumnya.

Biasanya, Anda menggunakan foo->getInterfaceVersion() untuk melihat versi antarmuka jarak jauh yang digunakan. Namun, dengan dukungan pembuatan versi berbasis tanda, Anda akan mengimplementasikan dua versi yang berbeda, sehingga Anda mungkin ingin mendapatkan versi antarmuka saat ini. Anda dapat melakukannya dengan mendapatkan versi antarmuka objek saat ini, misalnya, this->getInterfaceVersion() atau metode lainnya untuk my_ver. Lihat Mengkueri versi antarmuka objek jarak jauh untuk informasi selengkapnya.

Antarmuka VINTF baru yang stabil

Saat paket antarmuka AIDL baru ditambahkan, tidak akan ada versi frozen terakhir, sehingga tidak ada perilaku yang dapat dikembalikan saat RELEASE_AIDL_USE_UNFROZEN adalah false. Jangan gunakan antarmuka ini. Jika RELEASE_AIDL_USE_UNFROZEN adalah false, Pengelola Layanan tidak akan mengizinkan layanan mendaftarkan antarmuka dan klien tidak akan menemukannya.

Anda dapat menambahkan layanan secara kondisional berdasarkan nilai tanda RELEASE_AIDL_USE_UNFROZEN di makefile perangkat:

ifeq ($(RELEASE_AIDL_USE_UNFROZEN),true)
PRODUCT_PACKAGES += \
    android.hardware.health.storage-service
endif

Jika layanan adalah bagian dari proses yang lebih besar sehingga Anda tidak dapat menambahkannya ke perangkat secara kondisional, Anda dapat memeriksa apakah layanan dideklarasikan dengan IServiceManager::isDeclared(). Jika sudah dideklarasikan dan gagal didaftarkan, batalkan proses. Jika tidak dideklarasikan, pendaftaran akan gagal.

Cuttlefish sebagai alat pengembangan

Setiap tahun setelah VINTF dibekukan, kami menyesuaikan matriks kompatibilitas framework (FCM) target-level dan PRODUCT_SHIPPING_API_LEVEL Cuttlefish sehingga mencerminkan perangkat yang diluncurkan dengan rilis tahun depan. Kami menyesuaikan target-level dan PRODUCT_SHIPPING_API_LEVEL untuk memastikan ada beberapa perangkat peluncuran yang diuji dan memenuhi persyaratan baru untuk rilis tahun depan.

Jika RELEASE_AIDL_USE_UNFROZEN adalah true, Cuttlefish akan digunakan untuk pengembangan rilis Android mendatang. Versi ini menargetkan level FCM dan PRODUCT_SHIPPING_API_LEVEL rilis Android tahun depan, sehingga memerlukannya untuk memenuhi Persyaratan Software Vendor (VSR) rilis berikutnya.

Jika RELEASE_AIDL_USE_UNFROZEN adalah false, Cuttlefish memiliki target-level dan PRODUCT_SHIPPING_API_LEVEL sebelumnya untuk mencerminkan perangkat rilis. Di Android 14 dan yang lebih rendah, diferensiasi ini akan dilakukan dengan cabang Git yang berbeda yang tidak mengambil perubahan pada FCM target-level, API level pengiriman, atau kode lain yang menargetkan rilis berikutnya.

Aturan penamaan modul

Di Android 11, untuk setiap kombinasi versi dan backend yang diaktifkan, modul library stub akan otomatis dibuat. Untuk merujuk ke modul library stub tertentu untuk penautan, jangan gunakan nama modul aidl_interface, melainkan nama modul library stub, yaitu ifacename-version-backend, dengan

  • ifacename: nama modul aidl_interface
  • version adalah salah satu dari
    • Vversion-number untuk versi frozen
    • Vlatest-frozen-version-number + 1 untuk versi tip-of-tree (belum dibekukan)
  • backend adalah salah satu dari
    • java untuk backend Java,
    • cpp untuk backend C++,
    • ndk atau ndk_platform untuk backend NDK. Yang pertama ditujukan untuk aplikasi, dan yang kedua ditujukan untuk penggunaan platform hingga Android 13. Di Android 13 dan yang lebih baru, hanya gunakan ndk.
    • rust untuk backend Rust.

Asumsikan ada modul dengan nama foo dan versi terbarunya adalah 2, dan mendukung NDK dan C++. Dalam hal ini, AIDL akan menghasilkan modul berikut:

  • Berdasarkan versi 1
    • foo-V1-(java|cpp|ndk|ndk_platform|rust)
  • Berdasarkan versi 2 (versi stabil terbaru)
    • foo-V2-(java|cpp|ndk|ndk_platform|rust)
  • Berdasarkan versi ToT
    • foo-V3-(java|cpp|ndk|ndk_platform|rust)

Dibandingkan dengan Android 11:

  • foo-backend, yang merujuk ke versi stabil terbaru, menjadi foo-V2-backend
  • foo-unstable-backend, yang dirujuk ke versi ToT menjadi foo-V3-backend

Nama file output selalu sama dengan nama modul.

  • Berdasarkan versi 1: foo-V1-(cpp|ndk|ndk_platform|rust).so
  • Berdasarkan versi 2: foo-V2-(cpp|ndk|ndk_platform|rust).so
  • Berdasarkan versi ToT: foo-V3-(cpp|ndk|ndk_platform|rust).so

Perhatikan bahwa compiler AIDL tidak membuat modul versi unstable, atau modul tanpa versi untuk antarmuka AIDL yang stabil. Mulai Android 12, nama modul yang dihasilkan dari antarmuka AIDL yang stabil selalu menyertakan versinya.

Metode antarmuka meta baru

Android 10 menambahkan beberapa metode antarmuka meta untuk AIDL stabil.

Membuat kueri versi antarmuka objek jarak jauh

Klien dapat membuat kueri versi dan hash antarmuka yang diterapkan objek jarak jauh dan membandingkan nilai yang ditampilkan dengan nilai antarmuka yang digunakan klien.

Contoh dengan backend cpp:

sp<IFoo> foo = ... // the remote object
int32_t my_ver = IFoo::VERSION;
int32_t remote_ver = foo->getInterfaceVersion();
if (remote_ver < my_ver) {
  // the remote side is using an older interface
}

std::string my_hash = IFoo::HASH;
std::string remote_hash = foo->getInterfaceHash();

Contoh dengan backend ndk (dan ndk_platform):

IFoo* foo = ... // the remote object
int32_t my_ver = IFoo::version;
int32_t remote_ver = 0;
if (foo->getInterfaceVersion(&remote_ver).isOk() && remote_ver < my_ver) {
  // the remote side is using an older interface
}

std::string my_hash = IFoo::hash;
std::string remote_hash;
foo->getInterfaceHash(&remote_hash);

Contoh dengan backend java:

IFoo foo = ... // the remote object
int myVer = IFoo.VERSION;
int remoteVer = foo.getInterfaceVersion();
if (remoteVer < myVer) {
  // the remote side is using an older interface
}

String myHash = IFoo.HASH;
String remoteHash = foo.getInterfaceHash();

Untuk bahasa Java, sistem jarak jauh HARUS mengimplementasikan getInterfaceVersion() dan getInterfaceHash() sebagai berikut (super digunakan sebagai pengganti IFoo untuk menghindari kesalahan salin dan tempel. Anotasi @SuppressWarnings("static") mungkin diperlukan untuk menonaktifkan peringatan, bergantung pada konfigurasi javac):

class MyFoo extends IFoo.Stub {
    @Override
    public final int getInterfaceVersion() { return super.VERSION; }

    @Override
    public final String getInterfaceHash() { return super.HASH; }
}

Hal ini karena class yang dihasilkan (IFoo, IFoo.Stub, dll.) digunakan bersama antara klien dan server (misalnya, class dapat berada di classpath boot). Saat class dibagikan, server juga ditautkan ke versi class terbaru meskipun mungkin telah dibuat dengan antarmuka versi lama. Jika antarmuka meta ini diterapkan di class umum, antarmuka tersebut akan selalu menampilkan versi terbaru. Namun, dengan menerapkan metode seperti di atas, nomor versi antarmuka disematkan dalam kode server (karena IFoo.VERSION adalah static final int yang disisipkan saat direferensikan) sehingga metode dapat menampilkan versi persis yang digunakan untuk mem-build server.

Menangani antarmuka lama

Mungkin klien diupdate dengan antarmuka AIDL versi yang lebih baru, tetapi server menggunakan antarmuka AIDL lama. Dalam kasus tersebut, memanggil metode pada antarmuka lama akan menampilkan UNKNOWN_TRANSACTION.

Dengan AIDL yang stabil, klien memiliki kontrol lebih besar. Di sisi klien, Anda dapat menetapkan implementasi default ke antarmuka AIDL. Metode dalam penerapan default hanya dipanggil jika metode tidak diterapkan di sisi jarak jauh (karena dibuat dengan antarmuka versi lama). Karena default ditetapkan secara global, nilai default tidak boleh digunakan dari konteks yang berpotensi bersama.

Contoh dalam C++ di Android 13 dan yang lebih baru:

class MyDefault : public IFooDefault {
  Status anAddedMethod(...) {
   // do something default
  }
};

// once per an interface in a process
IFoo::setDefaultImpl(::android::sp<MyDefault>::make());

foo->anAddedMethod(...); // MyDefault::anAddedMethod() will be called if the
                         // remote side is not implementing it

Contoh di Java:

IFoo.Stub.setDefaultImpl(new IFoo.Default() {
    @Override
    public xxx anAddedMethod(...)  throws RemoteException {
        // do something default
    }
}); // once per an interface in a process

foo.anAddedMethod(...);

Anda tidak perlu menyediakan implementasi default untuk semua metode dalam antarmuka AIDL. Metode yang dijamin akan diimplementasikan di sisi jarak jauh (karena Anda yakin bahwa jarak jauh dibuat saat metode berada di deskripsi antarmuka AIDL) tidak perlu diganti di class impl default.

Mengonversi AIDL yang ada menjadi AIDL terstruktur atau stabil

Jika Anda sudah memiliki antarmuka AIDL dan kode yang menggunakannya, gunakan langkah-langkah berikut untuk mengonversi antarmuka menjadi antarmuka AIDL yang stabil.

  1. Identifikasi semua dependensi antarmuka Anda. Untuk setiap paket yang menjadi dependensi antarmuka, tentukan apakah paket tersebut ditentukan dalam AIDL yang stabil. Jika tidak ditentukan, paket harus dikonversi.

  2. Konversikan semua parcelable di antarmuka Anda menjadi parcelable yang stabil (file antarmuka itu sendiri dapat tetap tidak berubah). Lakukan hal ini dengan mengekspresikan strukturnya langsung dalam file AIDL. Class pengelolaan harus ditulis ulang untuk menggunakan jenis baru ini. Hal ini dapat dilakukan sebelum Anda membuat paket aidl_interface (di bawah).

  3. Buat paket aidl_interface (seperti yang dijelaskan di atas) yang berisi nama modul, dependensinya, dan informasi lain yang Anda perlukan. Agar stabil (tidak hanya terstruktur), data juga perlu diberi versi. Untuk mengetahui informasi selengkapnya, lihat Membuat versi antarmuka.