Android 10 menambahkan dukungan untuk Android Interface Definition Language (AIDL) stabil, cara baru untuk memantau antarmuka program aplikasi (API) dan application biner interface (ABI) yang disediakan oleh antarmuka AIDL. AIDL stabil memiliki beberapa perbedaan utama berikut dengan AIDL:
- Antarmuka ditentukan dalam sistem build dengan
aidl_interfaces
. - Antarmuka hanya boleh berisi data terstruktur. Parcelable yang mewakili jenis pilihan dibuat secara otomatis berdasarkan definisi AIDL-nya dan secara otomatis disusun dan tidak disusun.
- Antarmuka dapat dideklarasikan sebagai stabil (kompatibel dengan versi lama). Jika hal ini terjadi, API-nya akan dilacak dan dibuat versi dalam file di samping antarmuka AIDL.
AIDL terstruktur versus stabil
AIDL terstruktur mengacu pada jenis yang ditentukan hanya dalam AIDL. Misalnya, deklarasi parcelable (parcelable kustom) bukan AIDL terstruktur. Parcelable dengan kolom yang ditentukan dalam AIDL disebut structured parcelable.
AIDL stabil memerlukan AIDL terstruktur agar sistem build dan compiler
dapat memahami apakah perubahan yang dibuat pada parcelable kompatibel dengan versi lama.
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 untukFoo
jenis AIDL yang ditentukan dalamcom.acme
paket harus berada di<base_path>/com/acme/Foo.aidl
, dengan<base_path>
dapat berupa direktori apa pun yang terkait dengan direktori tempatAndroid.bp
berada. Dalam contoh sebelumnya,<base_path>
adalahsrcs/aidl
.local_include_dir
: Jalur tempat nama paket dimulai. Hal ini sesuai dengan<base_path>
yang dijelaskan di atas.imports
: Daftar modulaidl_interface
yang digunakannya. Jika salah satu antarmuka AIDL Anda menggunakan antarmuka atau parcelable dariaidl_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 12versions
: Versi antarmuka sebelumnya yang dibekukan dalamapi_dir
. Mulai Android 11,versions
akan dibekukan di bawahaidl_api/name
. Jika tidak ada versi antarmuka yang dibekukan, hal ini tidak boleh ditentukan, dan tidak akan ada pemeriksaan kompatibilitas. Kolom ini telah diganti denganversions_with_info
untuk Android 13 dan yang lebih baru.versions_with_info
: Daftar tuple, yang masing-masing berisi nama versi yang dibekukan dan daftar dengan impor versi modul aidl_interface lainnya yang diimpor oleh versi aidl_interface ini. Definisi versi V dari antarmuka AIDL IFACE terletak diaidl_api/IFACE/V
. Kolom ini diperkenalkan di Android 13, dan tidak boleh diubah diAndroid.bp
secara langsung. Kolom ini ditambahkan atau diperbarui dengan memanggil*-update-api
atau*-freeze-api
. Selain itu, kolomversions
otomatis dimigrasikan keversions_with_info
saat pengguna memanggil*-update-api
atau*-freeze-api
.stability
: Flag opsional untuk janji stabilitas antarmuka ini. Ini hanya mendukung"vintf"
. Jikastability
tidak disetel, sistem build akan memeriksa apakah antarmuka tersebut kompatibel dengan versi lama kecuali jikaunstable
ditentukan. Jika kebijakan tidak disetel, antarmuka dengan stabilitas dalam konteks kompilasi ini (jadi, baik semua hal sistem, misalnya, hal-hal disystem.img
dan partisi terkait, atau semua hal vendor, misalnya, hal-hal divendor.img
dan partisi terkait). Jikastability
disetel ke"vintf"
, ini sesuai dengan promise stabilitas: antarmuka harus tetap stabil selama digunakan.gen_trace
: Flag opsional untuk mengaktifkan atau menonaktifkan pelacakan. Mulai Android 14, defaultnya adalahtrue
untuk backendcpp
danjava
.host_supported
: Flag opsional yang jika ditetapkan ketrue
akan membuat library yang dihasilkan tersedia untuk lingkungan host.unstable
: Flag opsional yang digunakan untuk menandai bahwa antarmuka ini tidak harus stabil. Jika disetel ketrue
, sistem build tidak akan membuat dump API untuk antarmuka atau mengharuskannya diupdate.frozen
: Flag opsional yang jika ditetapkan ketrue
berarti antarmuka tidak memiliki perubahan sejak versi antarmuka sebelumnya. Hal ini memungkinkan lebih banyak pemeriksaan waktu build. Jika ditetapkan kefalse
, ini berarti antarmuka sedang dalam pengembangan dan memiliki perubahan baru, sehingga menjalankanfoo-freeze-api
akan menghasilkan versi baru dan otomatis mengubah nilai menjaditrue
. Diperkenalkan di Android 14.backend.<type>.enabled
: Tanda ini mengalihkan setiap backend yang menghasilkan kode 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 harus dinonaktifkan secara eksplisit. Rust dinonaktifkan secara default hingga Android 15 (Eksperimental AOSP).backend.<type>.apex_available
: Daftar nama APEX yang menyediakan library stub yang dihasilkan.backend.[cpp|java].gen_log
: Flag opsional yang mengontrol apakah akan menghasilkan kode tambahan untuk mengumpulkan informasi tentang transaksi atau tidak.backend.[cpp|java].vndk.enabled
: Flag opsional untuk menjadikan antarmuka ini bagian dari VNDK. Defaultnya adalahfalse
.backend.[cpp|ndk].additional_shared_libraries
: Diperkenalkan di Android 14, flag ini menambahkan dependensi ke library native. Tanda ini berguna denganndk_header
dancpp_header
.backend.java.sdk_version
: Flag opsional untuk menentukan versi SDK yang menjadi dasar pembuatan library stub Java. Defaultnya adalah"system_current"
. Ini tidak boleh ditetapkan jikabackend.java.platform_apis
adalahtrue
.backend.java.platform_apis
: Flag opsional yang harus ditetapkan ketrue
saat library yang dihasilkan harus di-build dengan 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 di AIDL stabil mirip dengan antarmuka tradisional, tetapi tidak diizinkan 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 wajib) untuk boolean
, char
,
float
, double
, byte
, int
, long
, dan String
. Di Android
12, setelan default untuk enumerasi yang ditentukan pengguna juga
didukung. Jika nilai 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 dalam 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 dibuat, foo-freeze-api menambahkan definisi API baru di api_dir
atau aidl_api/name
, bergantung pada versi Android, dan menambahkan file .hash
, yang keduanya mewakili antarmuka yang baru dibekukan. foo-freeze-api juga mengupdate 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 menjaga stabilitas antarmuka, pemilik dapat menambahkan hal baru:
- Metode untuk akhir antarmuka (atau metode dengan serial baru yang ditentukan secara eksplisit)
- Elemen ke akhir parcelable (harus ditambahkan secara default untuk setiap elemen)
- Nilai konstanta
- Di Android 11, enumerator
- Di Android 12, kolom ke akhir union
Tidak ada tindakan lain yang diizinkan, dan tidak ada orang lain yang dapat memodifikasi antarmuka (jika tidak, mereka berisiko bentrok dengan perubahan yang dibuat oleh 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 stabil dibekukan yang tidak memiliki kolomowner:
yang ditentukan.AIDL_FROZEN_OWNERS="aosp test"
- build mengharuskan semua antarmuka AIDL stabil dibekukan dengan kolomowner:
yang ditentukan sebagai "AOSP" atau "test".
Stabilitas impor
Memperbarui versi impor untuk versi antarmuka yang dibekukan akan memiliki kompatibilitas mundur pada lapisan AIDL Stabil. Namun, mengupdate ini mengharuskan mengupdate semua server dan klien yang menggunakan versi antarmuka sebelumnya, dan beberapa aplikasi dapat membingungkan saat menggabungkan jenis versi yang berbeda. 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
mendapatkanSTATUS_UNKNOWN_TRANSACTION
. - Backend
java
mendapatkanandroid.os.RemoteException
dengan pesan yang menyatakan API tidak diimplementasikan.
Untuk mengetahui strategi guna menangani hal ini, lihat versi membuat kueri dan menggunakan default.
Parcelable
Saat kolom baru ditambahkan ke parcelable, klien dan server lama akan menghapusnya. Saat klien dan server baru menerima parcelable lama, nilai default untuk kolom baru akan otomatis diisi. Ini berarti bahwa {i>default<i} harus ditentukan untuk semua {i>field<i} baru di parcelable.
Klien seharusnya tidak mengharapkan server menggunakan kolom baru, kecuali jika mereka mengetahui bahwa server menerapkan versi yang memiliki kolom yang ditentukan (lihat versi membuat kueri).
Enum dan konstanta
Demikian pula, klien dan server harus menolak atau mengabaikan enumerator dan nilai konstanta yang tidak dikenal sesuai kebutuhan, karena mungkin akan ada penambahan nilai di masa mendatang. Misalnya, server tidak boleh membatalkan saat menerima enumerator yang tidak diketahuinya. Server harus mengabaikan enumerator, atau menampilkan sesuatu agar klien tahu bahwa hal tersebut 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 terjadi
transaksi satu arah; jika tidak, error-nya adalah BAD_VALUE
(untuk backend C++ atau NDK)
atau IllegalArgumentException
(untuk backend Java). Error ini diterima jika klien mengirimkan union yang ditetapkan ke kolom baru ke server lama, atau jika merupakan klien lama yang menerima union dari server baru.
Pengembangan berbasis bendera
Antarmuka dalam pengembangan (tidak dibekukan) tidak dapat digunakan pada perangkat rilis karena tidak dijamin akan kompatibel dengan versi lama.
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 lama serupa 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 runtime, dan false
berarti semua library
versi yang tidak dibekukan berperilaku seperti versi frozen terakhir.
Anda dapat mengganti tanda ini ke true
untuk
pengembangan lokal, tetapi harus mengembalikannya ke false
sebelum rilis. Biasanya
pengembangan dilakukan dengan konfigurasi yang menetapkan flag 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 pada 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 baru antarmuka yang tidak dibekukan ditambahkan ke matriks kompatibilitas, versi frozen sebelumnya harus tetap tersedia 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 dalam semua konfigurasi.
Misalnya, saat menambahkan versi 4 yang tidak dibekukan, gunakan <version>3-4</version>
.
Jika versi 4 dibekukan, Anda dapat menghapus versi 3 dari matriks kompatibilitas karena versi frozen 4 digunakan jika RELEASE_AIDL_USE_UNFROZEN
adalah false
.
Manifes
Di Android 15 (Eksperimental AOSP), perubahan pada libvintf
diperkenalkan untuk
mengubah file manifes pada waktu build berdasarkan nilai
RELEASE_AIDL_USE_UNFROZEN
.
Manifes dan fragmen manifes mendeklarasikan versi antarmuka
mana yang diimplementasikan oleh layanan. Saat menggunakan versi antarmuka yang tidak dibekukan terbaru,
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 ini
diubah dari versi yang tidak dibekukan, N
, menjadi
versi beku terakhir 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 frozen terakhir 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 memiliki kompatibilitas mundur
dengan versi tambahan sebelumnya, tetapi ini merupakan detail baru untuk
klien vendor dan klien antarmuka milik partner.
Perubahan implementasi HAL
Perbedaan terbesar dalam pengembangan HAL dengan pengembangan berbasis flag 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 sedikit perbedaan yang perlu Anda ketahui, karena Anda sekarang secara efektif menerapkan dua versi yang menggunakan kode sumber yang sama (versi saat ini, yang tidak dibekukan).
Contoh: Antarmuka memiliki tiga versi frozen. Antarmuka diupdate dengan
metode baru. Klien dan layanan diupdate untuk menggunakan library
versi 4 baru. Karena didasarkan pada versi antarmuka
yang tidak dibekukan, library ini akan berperilaku seperti versi frozen terakhir, yaitu versi 3, jika
RELEASE_AIDL_USE_UNFROZEN
adalah false
, sehingga akan 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 mengimplementasikan dua versi callback yang berbeda
berdasarkan konfigurasi rilis, sehingga Anda tidak dapat
berasumsi bahwa klien mengirimkan versi terbaru, dan metode baru mungkin
menampilkan versi ini. Hal ini mirip dengan cara klien AIDL 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 defaultnya jika RELEASE_AIDL_USE_UNFROZEN
adalah false
dan nilai kolom baru yang coba dikirim oleh layanan akan dihapus saat proses selesai.
Jenis baru yang ditambahkan dalam versi tidak beku 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 saat menggunakan enumerator baru hanya dengan versi yang diperkenalkan, bukan versi sebelumnya.
Biasanya, Anda menggunakan foo->getInterfaceVersion()
untuk melihat versi yang digunakan antarmuka
jarak jauh. 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 Membuat kueri versi antarmuka objek
jarak jauh
untuk mengetahui informasi selengkapnya.
Antarmuka stabil VINTF baru
Saat paket antarmuka AIDL baru ditambahkan, tidak akan ada versi frozen terakhir, sehingga
tidak ada perilaku yang dapat dikembalikan ketika RELEASE_AIDL_USE_UNFROZEN
adalah
false
. Jangan gunakan antarmuka ini. Jika RELEASE_AIDL_USE_UNFROZEN
adalah
false
, Pengelola Layanan tidak akan mengizinkan layanan untuk mendaftarkan antarmuka
dan klien tidak akan menemukannya.
Anda dapat menambahkan layanan secara bersyarat berdasarkan nilai flag RELEASE_AIDL_USE_UNFROZEN
dalam 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 bersyarat, Anda dapat memeriksa apakah layanan dideklarasikan dengan
IServiceManager::isDeclared()
. Jika sudah dideklarasikan dan gagal didaftarkan, batalkan proses. Jika tidak dideklarasikan, maka diperkirakan gagal didaftarkan.
Sotong 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 pada rilis tahun depan. Kami menyesuaikan
target-level
dan PRODUCT_SHIPPING_API_LEVEL
untuk memastikan ada beberapa
perangkat yang diluncurkan yang telah diuji dan memenuhi persyaratan baru untuk rilis
tahun depan.
Jika RELEASE_AIDL_USE_UNFROZEN
adalah true
, Cuttlefish
digunakan untuk pengembangan rilis Android mendatang. Rilis ini menargetkan level FCM dan PRODUCT_SHIPPING_API_LEVEL
rilis Android tahun depan, yang mengharuskannya 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 berbagai cabang Git yang tidak menerima perubahan ke FCM
target-level
, mengirimkan API level, 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 modulaidl_interface
version
adalah salah satu dariVversion-number
untuk versi bekuVlatest-frozen-version-number + 1
untuk versi ujung hierarki (belum beku)
backend
adalah salah satu darijava
untuk backend Java,cpp
untuk backend C++,ndk
ataundk_platform
untuk backend NDK. Yang pertama adalah untuk aplikasi, dan yang terakhir untuk penggunaan platform hingga Android 13. Di Android 13 dan yang lebih baru, hanya gunakanndk
.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 dirujuk ke versi stabil terbaru menjadifoo-V2-backend
foo-unstable-backend
, yang dirujuk ke versi ToT menjadifoo-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
Perlu diperhatikan bahwa compiler AIDL tidak membuat modul versi unstable
,
atau modul tanpa versi untuk antarmuka AIDL stabil.
Mulai Android 12, nama modul yang dihasilkan dari
antarmuka AIDL stabil selalu menyertakan versi.
Metode antarmuka meta baru
Android 10 menambahkan beberapa metode antarmuka meta untuk AIDL stabil.
Mengkueri versi antarmuka objek jarak jauh
Klien dapat mengkueri versi dan hash antarmuka yang diimplementasikan 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 akan ditautkan ke
class terbaru meskipun class mungkin telah di-build dengan versi
antarmuka yang lebih lama. Jika diimplementasikan di class
bersama, antarmuka meta ini akan selalu menampilkan versi terbaru. Namun, dengan menerapkan metode
seperti di atas, nomor versi antarmuka akan disematkan dalam kode server
(karena IFoo.VERSION
adalah static final int
yang menjadi inline saat direferensikan),
sehingga metode ini dapat menampilkan versi yang sama persis dengan yang digunakan untuk membangun server.
Menangani antarmuka yang lebih lama
Ada kemungkinan klien diupdate dengan versi antarmuka AIDL
yang lebih baru, tetapi server menggunakan antarmuka AIDL lama. Dalam kasus tersebut,
memanggil metode pada antarmuka lama akan menampilkan UNKNOWN_TRANSACTION
.
Dengan AIDL stabil, klien memiliki kontrol yang lebih besar. Di sisi klien, Anda dapat menetapkan implementasi default ke antarmuka AIDL. Metode dalam implementasi default hanya dipanggil jika metode tersebut tidak diimplementasikan di sisi jarak jauh (karena di-build dengan versi antarmuka yang lebih lama). Karena default ditetapkan secara global, nilai default tidak boleh digunakan dari konteks yang berpotensi bersama.
Contoh di 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 remote di-build saat metode berada dalam
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.
Identifikasi semua dependensi antarmuka Anda. Untuk setiap paket yang menjadi dependensi antarmuka, tentukan apakah paket didefinisikan dalam AIDL stabil. Jika tidak ditentukan, paket harus dikonversi.
Mengonversi semua parcelable di antarmuka Anda menjadi parcelable stabil (file antarmuka itu sendiri tetap tidak berubah). Lakukan hal ini dengan mengekspresikan strukturnya secara langsung dalam file AIDL. Kelas manajemen harus ditulis ulang untuk menggunakan tipe baru ini. Hal ini dapat dilakukan sebelum Anda membuat paket
aidl_interface
(di bawah).Buat paket
aidl_interface
(seperti dijelaskan di atas) yang berisi nama modul Anda, dependensinya, dan informasi lain yang Anda butuhkan. Untuk membuatnya stabil (tidak hanya terstruktur), model tersebut juga perlu dibuat versinya. Untuk mengetahui informasi selengkapnya, lihat Antarmuka pembuatan versi.