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 AIDLFoo
yang ditentukan dalam paketcom.acme
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. Ini sesuai dengan<base_path>
yang dijelaskan di atas.imports
: Daftar modulaidl_interface
yang digunakan. 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 diapi_dir
. Mulai Android 11,versions
dibekukan diaidl_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 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 diaidl_api/IFACE/V
. Kolom ini diperkenalkan di Android 13, dan tidak boleh diubah diAndroid.bp
secara langsung. Kolom 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 ditetapkan, sistem build akan memeriksa apakah antarmuka kompatibel dengan versi sebelumnya, kecualiunstable
ditentukan. Tidak ditetapkan sesuai dengan antarmuka dengan stabilitas dalam konteks kompilasi ini (jadi semua hal sistem, misalnya, hal-hal disystem.img
dan partisi terkait, atau semua hal vendor, misalnya, hal-hal divendor.img
dan partisi terkait). Jikastability
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 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 perlu stabil. Jika ditetapkan ketrue
, sistem build tidak akan membuat dump API untuk antarmuka atau mengharuskannya diupdate.frozen
: Flag opsional yang jika ditetapkan ketrue
berarti antarmuka tidak mengalami perubahan sejak antarmuka versi 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 secara otomatis mengubah nilai menjaditrue
. 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 adalahfalse
.backend.[cpp|ndk].additional_shared_libraries
: Diperkenalkan di Android 14, flag ini menambahkan dependensi ke library native. Flag ini berguna denganndk_header
dancpp_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 jikabackend.java.platform_apis
adalahtrue
.backend.java.platform_apis
: Flag opsional yang harus ditetapkan ketrue
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 kolomowner:
yang ditentukan.AIDL_FROZEN_OWNERS="aosp test"
- build memerlukan semua antarmuka AIDL yang stabil untuk dibekukan dengan kolomowner:
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
mendapatkanSTATUS_UNKNOWN_TRANSACTION
. - Backend
java
mendapatkanandroid.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 modulaidl_interface
version
adalah salah satu dariVversion-number
untuk versi frozenVlatest-frozen-version-number + 1
untuk versi tip-of-tree (belum dibekukan)
backend
adalah salah satu darijava
untuk backend Java,cpp
untuk backend C++,ndk
ataundk_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 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 merujuk 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
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.
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.
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).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.