AIDL yang stabil

Android 10 menambahkan dukungan untuk Android Interface Definition Language (AIDL) yang stabil, sebuah cara baru untuk melacak antarmuka program aplikasi (API)/antarmuka biner aplikasi (ABI) yang disediakan oleh antarmuka AIDL. AIDL yang stabil memiliki perbedaan utama berikut dari AIDL:

  • Antarmuka didefinisikan dalam sistem build dengan aidl_interfaces .
  • Antarmuka hanya dapat berisi data terstruktur. Parcelable yang mewakili tipe yang diinginkan secara otomatis dibuat berdasarkan definisi AIDL-nya dan secara otomatis disusun dan tidak disusun.
  • Antarmuka dapat dinyatakan stabil (kompatibel ke belakang). Ketika ini terjadi, API mereka dilacak dan dibuat versinya dalam file di sebelah antarmuka AIDL.

AIDL terstruktur versus stabil

AIDL terstruktur mengacu pada tipe yang didefinisikan murni dalam AIDL. Misalnya, deklarasi parsel (parsial khusus) bukanlah AIDL yang terstruktur. Paket yang bidangnya ditentukan dalam AIDL disebut paket terstruktur .

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

Mendefinisikan antarmuka AIDL

Definisi aidl_interface 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 secara unik mengidentifikasi antarmuka AIDL.
  • srcs : Daftar file sumber AIDL yang menyusun antarmuka. Jalur untuk tipe AIDL Foo yang didefinisikan 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. Pada contoh di atas, <base_path> adalah srcs/aidl .
  • local_include_dir : Jalur dari mana 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 paket dari aidl_interface lain, masukkan namanya di sini. Ini bisa 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 dibekukan di bawah api_dir , Mulai Android 11, versions dibekukan di bawah aidl_api/ name . Jika tidak ada versi antarmuka yang dibekukan, versi ini tidak akan ditentukan, dan tidak akan ada pemeriksaan kompatibilitas. Bidang ini telah diganti dengan versions_with_info untuk versi 13 dan lebih tinggi.
  • versions_with_info : Daftar tupel, yang masing-masing berisi nama versi yang dibekukan 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 . Bidang ini diperkenalkan di Android 13, dan tidak seharusnya diubah secara langsung di Android.bp. Bidang ini ditambahkan atau diperbarui dengan memanggil *-update-api atau *-freeze-api . Selain itu, bidang versions secara otomatis dimigrasikan ke versions_with_info ketika pengguna memanggil *-update-api atau *-freeze-api .
  • stability : Bendera opsional untuk janji stabilitas antarmuka ini. Saat ini hanya mendukung "vintf" . Jika ini tidak disetel, ini berhubungan dengan antarmuka dengan stabilitas dalam konteks kompilasi ini (jadi antarmuka yang dimuat di sini hanya dapat digunakan dengan hal-hal yang dikompilasi bersama, misalnya pada system.img). Jika ini disetel ke "vintf" , ini sesuai dengan janji stabilitas: antarmuka harus tetap stabil selama digunakan.
  • gen_trace : Tanda opsional untuk mengaktifkan atau menonaktifkan pelacakan. Mulai Android 14, defaultnya true untuk backend cpp dan java .
  • host_supported : Bendera opsional yang jika disetel ke true membuat perpustakaan yang dihasilkan tersedia untuk lingkungan host.
  • unstable : Bendera opsional yang digunakan untuk menandai bahwa antarmuka ini tidak perlu stabil. Jika ini disetel ke true , sistem pembangunan tidak membuat dump API untuk antarmuka atau mengharuskannya diperbarui.
  • frozen : Bendera opsional yang jika disetel ke true berarti antarmuka tidak mengalami perubahan sejak versi antarmuka sebelumnya. Hal ini memungkinkan lebih banyak pemeriksaan waktu pembangunan. Jika disetel ke false ini berarti antarmuka sedang dalam pengembangan dan ada perubahan baru sehingga menjalankan foo-freeze-api akan menghasilkan versi baru dan secara otomatis mengubah nilainya menjadi true . Diperkenalkan di Android 14.
  • backend.<type>.enabled : Flag ini mengaktifkan masing-masing backend yang kodenya dibuat oleh compiler AIDL. Saat ini, 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. Karat dinonaktifkan secara default.
  • backend.<type>.apex_available : Daftar nama APEX yang tersedia untuk perpustakaan stub yang dihasilkan.
  • backend.[cpp|java].gen_log : Bendera opsional yang mengontrol apakah akan menghasilkan kode tambahan untuk mengumpulkan informasi tentang transaksi.
  • backend.[cpp|java].vndk.enabled : Bendera opsional untuk menjadikan antarmuka ini bagian dari VNDK. Standarnya false .
  • backend.[cpp|ndk].additional_shared_libraries : Diperkenalkan di Android 14, tanda ini menambahkan dependensi ke perpustakaan asli. Tanda ini berguna dengan ndk_header dan cpp_header .
  • backend.java.sdk_version : Tanda opsional untuk menentukan versi SDK yang digunakan untuk membuat pustaka stub Java. Standarnya adalah "system_current" . Ini tidak boleh disetel jika backend.java.platform_apis benar.
  • backend.java.platform_apis : Tanda opsional yang harus disetel ke true ketika perpustakaan yang dihasilkan perlu dibuat berdasarkan API platform, bukan SDK.

Untuk setiap kombinasi versi dan backend yang diaktifkan, pustaka rintisan dibuat. Untuk mengetahui cara merujuk ke versi spesifik perpustakaan 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 diperbolehkan menggunakan paket yang tidak terstruktur (karena ini tidak stabil! lihat AIDL Terstruktur versus stabil ). Perbedaan utama dalam AIDL stabil adalah bagaimana parsel didefinisikan. Sebelumnya, barang parsel diumumkan ke depan ; dalam AIDL yang stabil (dan karenanya terstruktur), bidang dan variabel yang dapat dibagi-bagi didefinisikan secara eksplisit.

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

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

Default saat ini didukung (tetapi tidak wajib) 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. Pencacahan tanpa nilai default diinisialisasi ke 0 meskipun tidak ada pencacah nol.

Menggunakan perpustakaan rintisan

Setelah menambahkan pustaka rintisan sebagai dependensi ke modul, Anda bisa memasukkannya ke dalam file Anda. Berikut adalah contoh pustaka stub di 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 desire 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 di C++:

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

Contoh di Jawa:

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 membuat target di sistem build yang dapat Anda gunakan untuk mengelola API modul. Saat dibuat, foo-freeze-api menambahkan definisi API baru pada api_dir atau aidl_api/ name , bergantung pada versi Android, dan menambahkan file .hash , keduanya mewakili versi antarmuka yang baru dibekukan. foo-freeze-api juga memperbarui properti versions_with_info untuk mencerminkan versi tambahan dan imports versi tersebut. Pada dasarnya, imports di versions_with_info disalin dari bidang imports . Namun versi stabil terbaru ditentukan dalam imports di versions_with_info untuk impor yang tidak memiliki versi eksplisit. Setelah properti versions_with_info ditentukan, sistem build menjalankan pemeriksaan kompatibilitas antara versi yang dibekukan dan juga antara Top of Tree (ToT) dan versi beku terbaru.

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

Untuk menjaga stabilitas antarmuka, pemilik dapat menambahkan yang baru:

  • Metode di akhir antarmuka (atau metode dengan serial baru yang didefinisikan secara eksplisit)
  • Elemen di akhir paket (membutuhkan penambahan default untuk setiap elemen)
  • Nilai konstan
  • Di Android 11, enumerator
  • Di Android 12, kolom di akhir gabungan

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

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

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

Stabilitas impor

Memperbarui versi impor untuk versi antarmuka yang dibekukan kompatibel dengan lapisan AIDL Stabil. Namun, memperbarui ini memerlukan pembaruan semua server dan klien yang menggunakan antarmuka versi lama, dan beberapa aplikasi mungkin bingung saat mencampur jenis versi yang berbeda. Secara umum, untuk paket tipe saja atau umum, ini aman karena kode harus sudah ditulis untuk menangani tipe yang tidak diketahui dari transaksi IPC.

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

Menggunakan antarmuka berversi

Metode antarmuka

Saat runtime, ketika mencoba memanggil metode baru di server lama, klien baru mendapatkan kesalahan atau pengecualian, bergantung pada backend.

  • backend cpp mendapat ::android::UNKNOWN_TRANSACTION .
  • dan backend ndk mendapat STATUS_UNKNOWN_TRANSACTION .
  • backend java mendapat android.os.RemoteException dengan pesan yang mengatakan API tidak diterapkan.

Untuk mengetahui strategi menangani hal ini, lihat versi kueri dan penggunaan defaults .

Parcelable

Saat bidang baru ditambahkan ke paket, klien dan server lama akan menghapusnya. Ketika klien dan server baru menerima parsel lama, nilai default untuk kolom baru akan terisi secara otomatis. Ini berarti bahwa default harus ditentukan untuk semua kolom baru dalam parsel.

Klien tidak boleh mengharapkan server untuk menggunakan bidang baru kecuali mereka mengetahui server mengimplementasikan versi yang bidangnya telah ditentukan (lihat versi kueri ).

Enum dan konstanta

Demikian pula, klien dan server harus menolak atau mengabaikan nilai konstanta dan enumerator yang tidak dikenali sebagaimana mestinya, karena mungkin akan ditambahkan lebih banyak lagi di masa mendatang. Misalnya, server tidak boleh dibatalkan ketika menerima enumerator yang tidak diketahuinya. Itu harus mengabaikannya, atau mengembalikan sesuatu sehingga klien tahu itu tidak didukung dalam implementasi ini.

Serikat pekerja

Mencoba mengirim gabungan dengan bidang baru gagal jika penerima sudah lama dan tidak mengetahui tentang bidang tersebut. Implementasinya tidak akan pernah melihat penyatuan dengan bidang baru. Kegagalan diabaikan jika transaksi satu arah; jika tidak, kesalahannya adalah BAD_VALUE (untuk backend C++ atau NDK) atau IllegalArgumentException (untuk backend Java). Kesalahan diterima jika klien mengirimkan kumpulan gabungan ke bidang baru ke server lama, atau saat klien lama menerima gabungan dari server baru.

Pembangunan berbasis bendera

Antarmuka dalam pengembangan (yang tidak dibekukan) tidak dapat digunakan pada perangkat rilis, karena tidak ada jaminan kompatibilitas ke belakang.

AIDL mendukung fallback run time untuk pustaka antarmuka yang tidak dibekukan ini agar kode dapat ditulis terhadap versi terbaru yang tidak dibekukan dan tetap dapat digunakan pada perangkat rilis. Perilaku klien yang kompatibel ke belakang serupa dengan perilaku yang ada dan dengan fallback, implementasinya juga harus mengikuti perilaku tersebut. Lihat Menggunakan antarmuka berversi .

Bendera pembuatan AIDL

Bendera yang mengontrol perilaku ini adalah RELEASE_AIDL_USE_UNFROZEN yang didefinisikan dalam build/release/build_flags.bzl . true berarti versi antarmuka yang tidak dibekukan digunakan pada saat dijalankan dan false berarti pustaka dari versi yang tidak dibekukan semuanya berperilaku seperti versi terakhir yang dibekukan. Anda dapat mengganti tanda menjadi true untuk pengembangan lokal, namun harus mengembalikannya ke false sebelum dirilis. Biasanya pengembangan dilakukan dengan konfigurasi yang flagnya disetel ke true .

Matriks dan manifes kompatibilitas

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

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

Matriks

Antarmuka milik mitra ditambahkan ke matriks kompatibilitas khusus perangkat atau produk tertentu yang ditargetkan perangkat selama pengembangan. Jadi, ketika versi antarmuka baru yang tidak dibekukan ditambahkan ke matriks kompatibilitas, versi sebelumnya yang dibekukan harus tetap ada selama RELEASE_AIDL_USE_UNFROZEN=false . Anda dapat mengatasinya 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> .

Ketika versi 4 dibekukan, Anda dapat menghapus versi 3 dari matriks kompatibilitas karena versi 4 yang dibekukan digunakan ketika RELEASE_AIDL_USE_UNFROZEN bernilai false .

Mewujud

Di Android 15 (eksperimen 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 suatu layanan. Saat menggunakan versi antarmuka terbaru yang tidak dibekukan, manifes harus diperbarui untuk mencerminkan versi baru ini. Ketika RELEASE_AIDL_USE_UNFROZEN=false entri manifes disesuaikan oleh libvintf untuk mencerminkan perubahan di perpustakaan AIDL yang dihasilkan. Versi tersebut dimodifikasi dari versi yang tidak dibekukan, N , hingga versi terakhir yang dibekukan N - 1 . Oleh karena itu, pengguna tidak perlu mengelola beberapa manifes atau fragmen manifes untuk setiap layanannya.

Perubahan klien HAL

Kode klien HAL harus kompatibel dengan setiap versi beku yang didukung sebelumnya. Ketika RELEASE_AIDL_USE_UNFROZEN false , layanan selalu terlihat seperti versi terakhir yang dibekukan atau yang lebih lama (misalnya, memanggil metode baru yang tidak dibekukan akan mengembalikan UNKNOWN_TRANSACTION , atau bidang baru parcelable memiliki nilai defaultnya). Klien kerangka kerja Android harus kompatibel dengan versi tambahan sebelumnya, namun ini adalah detail baru untuk klien vendor dan klien antarmuka milik mitra.

Perubahan implementasi HAL

Perbedaan terbesar dalam pengembangan HAL dengan pengembangan berbasis flag adalah persyaratan agar implementasi HAL kompatibel dengan versi terakhir yang dibekukan agar dapat berfungsi ketika RELEASE_AIDL_USE_UNFROZEN bernilai false . Mempertimbangkan kompatibilitas ke belakang dalam implementasi dan kode perangkat adalah sebuah latihan baru. Lihat Menggunakan antarmuka berversi .

Pertimbangan kompatibilitas mundur umumnya sama untuk klien dan server, dan untuk kode kerangka kerja dan kode vendor, namun ada perbedaan halus yang perlu Anda waspadai, karena Anda sekarang secara efektif mengimplementasikan dua versi yang menggunakan kode sumber yang sama. (versi saat ini yang tidak dibekukan).

Contoh: Sebuah antarmuka memiliki tiga versi yang dibekukan. Antarmuka diperbarui dengan metode baru. Klien dan layanan keduanya diperbarui untuk menggunakan perpustakaan versi 4 yang baru. Karena pustaka V4 didasarkan pada versi antarmuka yang tidak dibekukan, ia berperilaku seperti versi terakhir yang dibekukan, versi 3, ketika RELEASE_AIDL_USE_UNFROZEN bernilai false , dan mencegah penggunaan metode baru.

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

Saat memanggil metode pada callback, Anda harus menangani kasus dengan baik ketika UNKNOWN_TRANSACTION dikembalikan. Klien mungkin menerapkan dua versi panggilan balik yang berbeda berdasarkan konfigurasi rilis, sehingga Anda tidak dapat berasumsi klien akan mengirimkan versi terbaru, dan metode baru mungkin mengembalikan versi ini. Hal ini mirip dengan bagaimana klien AIDL yang stabil menjaga kompatibilitas 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();
  }
}

Bidang baru dalam tipe yang sudah ada ( parcelable , enum , union ) mungkin tidak ada atau berisi nilai defaultnya ketika RELEASE_AIDL_USE_UNFROZEN false dan nilai bidang baru yang coba dikirim oleh layanan akan dihapus saat proses keluar.

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

Implementasinya tidak pernah mendapat panggilan untuk metode baru dari klien mana pun ketika RELEASE_AIDL_USE_UNFROZEN bernilai false .

Berhati-hatilah saat menggunakan enumerator baru hanya dengan versi yang diperkenalkan, dan bukan versi sebelumnya.

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

Antarmuka stabil VINTF baru

Ketika paket antarmuka AIDL baru ditambahkan, tidak ada versi terakhir yang dibekukan, sehingga tidak ada perilaku yang dapat digunakan kembali ketika RELEASE_AIDL_USE_UNFROZEN bernilai false . Jangan gunakan antarmuka ini. Jika RELEASE_AIDL_USE_UNFROZEN bernilai false , Manajer Layanan tidak akan mengizinkan layanan mendaftarkan antarmuka dan klien tidak akan menemukannya.

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

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

Jika layanan merupakan bagian dari proses yang lebih besar sehingga Anda tidak dapat menambahkannya ke perangkat secara kondisional, Anda dapat memeriksa apakah layanan tersebut dideklarasikan dengan IServiceManager::isDeclared() . Jika sudah dideklarasikan dan gagal mendaftar, maka batalkan prosesnya. Jika tidak dideklarasikan maka diperkirakan gagal mendaftar.

Sotong sebagai alat pengembangan

Setiap tahun setelah VINTF dibekukan, kami menyesuaikan target-level matriks kompatibilitas kerangka kerja (FCM) 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 peluncuran yang diuji dan memenuhi persyaratan baru untuk rilis tahun depan.

Jika RELEASE_AIDL_USE_UNFROZEN true , Cuttlefish digunakan untuk pengembangan rilis Android mendatang. Ini menargetkan level FCM dan PRODUCT_SHIPPING_API_LEVEL rilis Android tahun depan, yang mengharuskannya memenuhi Persyaratan Perangkat Lunak Vendor (VSR) rilis berikutnya.

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

Aturan penamaan modul

Di Android 11, untuk setiap kombinasi versi dan backend yang diaktifkan, modul perpustakaan stub dibuat secara otomatis. Untuk merujuk ke modul perpustakaan stub tertentu untuk ditautkan, jangan gunakan nama modul aidl_interface , tetapi nama modul perpustakaan stub, yaitu ifacename - version - backend , di mana

  • ifacename : nama modul aidl_interface
  • version adalah salah satu dari
    • V version-number untuk versi yang dibekukan
    • V latest-frozen-version-number + 1 untuk versi ujung pohon (yang belum dibekukan)
  • backend adalah salah satunya
    • java untuk backend Java,
    • cpp untuk backend C++,
    • ndk atau ndk_platform untuk backend NDK. Yang pertama untuk aplikasi, dan yang terakhir untuk penggunaan platform,
    • rust untuk backend Rust.

Asumsikan ada modul dengan nama foo dan versi terbarunya adalah 2 , dan mendukung NDK dan C++. Dalam hal ini, AIDL menghasilkan modul-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 mengacu pada versi stabil terbaru menjadi foo- V2 - backend
  • foo-unstable- backend , yang mengacu pada versi ToT menjadi foo- V3 - backend

Nama file keluaran 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 kompiler AIDL tidak membuat modul versi unstable , atau modul non-versi untuk antarmuka AIDL 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 yang stabil.

Menanyakan versi antarmuka objek jarak jauh

Klien dapat menanyakan versi dan hash antarmuka yang diimplementasikan oleh objek jarak jauh dan membandingkan nilai yang dikembalikan 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, sisi jarak jauh HARUS mengimplementasikan getInterfaceVersion() dan getInterfaceHash() sebagai berikut ( super digunakan sebagai pengganti IFoo untuk menghindari kesalahan salin/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 kelas yang dihasilkan ( IFoo , IFoo.Stub , dll.) dibagikan antara klien dan server (misalnya, kelas dapat berada di jalur kelas boot). Ketika kelas dibagikan, server juga ditautkan ke versi kelas terbaru meskipun mungkin dibuat dengan versi antarmuka yang lebih lama. Jika antarmuka meta ini diimplementasikan di kelas bersama, versi terbaru selalu dikembalikan. Namun, dengan mengimplementasikan metode seperti di atas, nomor versi antarmuka tertanam dalam kode server (karena IFoo.VERSION adalah static final int yang disejajarkan ketika direferensikan) dan dengan demikian metode tersebut dapat mengembalikan versi persis server tersebut dibangun. dengan.

Berurusan dengan antarmuka lama

Ada kemungkinan bahwa klien diperbarui dengan versi antarmuka AIDL yang lebih baru tetapi server menggunakan antarmuka AIDL yang lama. Dalam kasus seperti itu, memanggil metode pada antarmuka lama akan mengembalikan UNKNOWN_TRANSACTION .

Dengan AIDL yang stabil, klien memiliki kontrol lebih besar. Di sisi klien, Anda dapat menyetel implementasi default ke antarmuka AIDL. Sebuah metode dalam implementasi default dipanggil hanya ketika metode tersebut tidak diimplementasikan di sisi jarak jauh (karena metode tersebut dibangun dengan versi antarmuka yang lebih lama). Karena defaultnya ditetapkan secara global, maka default tersebut tidak boleh digunakan dalam konteks yang berpotensi digunakan 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 Jawa:

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 semua metode di antarmuka AIDL. Metode yang dijamin dapat diimplementasikan di sisi jarak jauh (karena Anda yakin bahwa jarak jauh dibuat ketika metode tersebut ada dalam deskripsi antarmuka AIDL) tidak perlu ditimpa di kelas impl default.

Mengubah AIDL yang ada menjadi AIDL terstruktur/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 bergantung pada antarmuka, tentukan apakah paket tersebut didefinisikan dalam AIDL yang stabil. Jika tidak ditentukan, paket harus dikonversi.

  2. Konversikan semua paket di antarmuka Anda menjadi paket yang stabil (file antarmuka itu sendiri tidak dapat diubah). Lakukan 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).

  3. Buat paket aidl_interface (seperti dijelaskan di atas) yang berisi nama modul Anda, dependensinya, dan informasi lain yang Anda perlukan. Untuk membuatnya stabil (tidak hanya terstruktur), ia juga perlu dibuat versinya. Untuk informasi lebih lanjut, lihat Pembuatan versi antarmuka .