Praktik terbaik yang diuraikan di sini berfungsi sebagai panduan untuk mengembangkan antarmuka AIDL secara efektif dan dengan memperhatikan fleksibilitas antarmuka, terutama ketika AIDL digunakan untuk mendefinisikan API atau berinteraksi dengan permukaan API.
AIDL dapat digunakan untuk mendefinisikan API ketika aplikasi perlu berinteraksi satu sama lain dalam proses latar belakang atau perlu berinteraksi dengan sistem. Untuk informasi selengkapnya tentang mengembangkan antarmuka pemrograman dalam aplikasi dengan AIDL, lihat Android Interface Definition Language (AIDL) . Untuk contoh AIDL dalam praktiknya, lihat AIDL untuk HAL dan AIDL Stabil .
Pembuatan versi
Setiap snapshot API AIDL yang kompatibel dengan versi sebelumnya. Untuk mengambil snapshot, jalankan m <module-name>-freeze-api
. Setiap kali klien atau server API dirilis (misalnya di kereta jalur utama), Anda perlu mengambil snapshot dan membuat versi baru. Untuk API sistem-ke-vendor, hal ini harus dilakukan dengan revisi platform tahunan.
Untuk detail dan informasi selengkapnya tentang jenis perubahan yang diperbolehkan, lihat Antarmuka pembuatan versi .
Pedoman desain API
Umum
1. Dokumentasikan semuanya
- Dokumentasikan setiap metode untuk semantik, argumen, penggunaan pengecualian bawaan, pengecualian khusus layanan, dan nilai kembalian.
- Dokumentasikan setiap antarmuka untuk semantiknya.
- Dokumentasikan makna semantik enum dan konstanta.
- Dokumentasikan apa pun yang mungkin tidak jelas bagi pelaksana.
- Berikan contoh jika relevan.
2. Selongsong
Gunakan huruf besar unta untuk tipe dan huruf besar unta bawah untuk metode, bidang, dan argumen. Misalnya, MyParcelable
untuk tipe parsel dan anArgument
untuk argumen. Untuk akronim, pertimbangkan akronim sebuah kata ( NFC
-> Nfc
).
[-Wconst-name] Nilai dan konstanta enum harus ENUM_VALUE
dan CONSTANT_NAME
Antarmuka
1. Penamaan
[-Winterface-name] Nama antarmuka harus dimulai dengan I
like IFoo
.
2. Hindari antarmuka besar dengan "objek" berbasis id
Lebih memilih sub-antarmuka ketika ada banyak panggilan yang terkait dengan API tertentu. Hal ini memberikan keuntungan sebagai berikut: - Membuat kode klien/server lebih mudah dipahami - Membuat siklus hidup objek menjadi lebih sederhana - Memanfaatkan pengikat yang tidak dapat diubah.
Tidak disarankan: Antarmuka tunggal dan besar dengan objek berbasis id
interface IManager {
int getFooId();
void beginFoo(int id); // clients in other processes can guess an ID
void opFoo(int id);
void recycleFoo(int id); // ownership not handled by type
}
Direkomendasikan: Sub-antarmuka individual
interface IManager {
IFoo getFoo();
}
interface IFoo {
void begin(); // clients in other processes can't guess a binder
void op();
}
3. Jangan mencampuradukkan metode satu arah dengan dua arah
[-Wmixed-oneway] Jangan mencampurkan metode oneway dengan metode non-oneway, karena akan membuat pemahaman model threading menjadi rumit bagi klien dan server. Khususnya, saat membaca kode klien dari antarmuka tertentu, Anda perlu mencari setiap metode apakah metode tersebut akan memblokir atau tidak.
4. Hindari mengembalikan kode status
Metode harus menghindari kode status sebagai nilai kembalian, karena semua metode AIDL memiliki kode pengembalian status implisit. Lihat ServiceSpecificException
atau EX_SERVICE_SPECIFIC
. Berdasarkan konvensi, nilai-nilai ini didefinisikan sebagai konstanta dalam antarmuka AIDL. Informasi lebih detail ada di bagian Penanganan kesalahan pada AIDL Backends .
5. Array sebagai parameter keluaran dianggap berbahaya
[-Wout-array] Metode yang memiliki parameter keluaran larik, seperti void foo(out String[] ret)
biasanya buruk karena ukuran larik keluaran harus dideklarasikan dan dialokasikan oleh klien di Java, sehingga ukuran keluaran larik tidak bisa dipilih oleh server. Perilaku yang tidak diinginkan ini terjadi karena cara kerja array di Java (tidak dapat dialokasikan kembali). Daripada memilih API seperti String[] foo()
.
6. Hindari parameter masuk
[-Winout-parameter] Ini dapat membingungkan klien karena parameter in
pun terlihat seperti parameter out
.
7. Hindari parameter non-array keluar/masuk @nullable
[-Wout-nullable] Karena backend Java tidak menangani anotasi @nullable
sementara backend lain menanganinya, out/inout @nullable T
dapat menyebabkan perilaku tidak konsisten di seluruh backend. Misalnya, backend non-Java dapat menyetel parameter out @nullable
ke null (di C++, menyetelnya sebagai std::nullopt
) tetapi klien Java tidak dapat membacanya sebagai null.
Paket terstruktur
1. Kapan digunakan
Gunakan paket terstruktur di mana Anda memiliki beberapa tipe data untuk dikirim.
Atau, saat Anda saat ini memiliki satu tipe data tetapi Anda berharap perlu memperluasnya di masa mendatang. Misalnya, jangan gunakan String username
. Gunakan parsel yang dapat diperpanjang, seperti berikut:
parcelable User {
String username;
}
Sehingga kedepannya dapat diperpanjang sebagai berikut:
parcelable User {
String username;
int id;
}
2. Berikan default secara eksplisit
[-Wexplicit-default, -Wenum-explicit-default] Memberikan default eksplisit untuk bidang.
Parcelable tidak terstruktur
1. Kapan digunakan
Parcelable tidak terstruktur saat ini tersedia di Java dengan @JavaOnlyStableParcelable
dan di backend NDK dengan @NdkOnlyStableParcelable
. Biasanya, ini adalah parsel lama dan sudah ada yang tidak dapat disusun dengan mudah.
Konstanta dan Enum
1. Bitfield harus menggunakan kolom konstan
Bitfields harus menggunakan bidang konstan (misalnya const int FOO = 3;
dalam antarmuka).
2. Enum harus berupa himpunan tertutup.
Enum harus berupa set tertutup. Catatan: hanya pemilik antarmuka yang dapat menambahkan elemen enum. Jika vendor atau OEM perlu memperluas bidang ini, diperlukan mekanisme alternatif. Jika memungkinkan, fungsionalitas vendor hulu harus diutamakan. Namun, dalam beberapa kasus, nilai vendor khusus mungkin diizinkan (walaupun, vendor harus memiliki mekanisme untuk membuat versi ini, mungkin AIDL itu sendiri, nilai tersebut tidak boleh bertentangan satu sama lain, dan nilai ini tidak boleh bertentangan terkena aplikasi pihak ketiga).
3. Hindari nilai seperti "NUM_ELEMENTS"
Karena enum memiliki versi, nilai yang menunjukkan berapa banyak nilai yang ada harus dihindari. Di C++, ini bisa diatasi dengan, enum_range<>
. Untuk Rust, gunakan enum_values()
. Di Jawa, belum ada solusi.
Tidak disarankan: Menggunakan nilai bernomor
@Backing(type="int")
enum FruitType {
APPLE = 0,
BANANA = 1,
MANGO = 2,
NUM_TYPES, // BAD
}
4. Hindari prefiks dan sufiks yang berlebihan
[-Wredundant-name] Hindari awalan dan sufiks yang berlebihan atau berulang dalam konstanta dan enumerator.
Tidak disarankan: Menggunakan awalan yang berlebihan
enum MyStatus {
STATUS_GOOD,
STATUS_BAD // BAD
}
Direkomendasikan: Memberi nama enum secara langsung
enum MyStatus {
GOOD,
BAD
}
Deskripsi File
[-Wfile-descriptor] Penggunaan FileDescriptor
sebagai argumen atau nilai kembalian metode antarmuka AIDL sangat tidak disarankan. Terutama, ketika AIDL diimplementasikan di Java, hal ini mungkin menyebabkan kebocoran deskriptor file kecuali ditangani dengan hati-hati. Pada dasarnya, jika Anda menerima FileDescriptor
, Anda harus menutupnya secara manual ketika tidak lagi digunakan.
Untuk backend asli, Anda aman karena FileDescriptor
dipetakan ke unique_fd
yang dapat ditutup secara otomatis. Namun apa pun bahasa backend yang akan Anda gunakan, sebaiknya JANGAN gunakan FileDescriptor
sama sekali karena ini akan membatasi kebebasan Anda untuk mengubah bahasa backend di masa mendatang.
Sebagai gantinya, gunakan ParcelFileDescriptor
, yang dapat ditutup secara otomatis.
Unit variabel
Pastikan unit variabel disertakan dalam nama sehingga unitnya terdefinisi dengan baik dan dipahami tanpa memerlukan dokumentasi referensi
Contoh
long duration; // Bad
long durationNsec; // Good
long durationNanos; // Also good
double energy; // Bad
double energyMilliJoules; // Good
int frequency; // Bad
int frequencyHz; // Good
Stempel waktu harus menunjukkan referensinya
Stempel waktu (pada kenyataannya, semua unit!) harus dengan jelas menunjukkan unit dan titik referensinya.
Contoh
/**
* Time since device boot in milliseconds
*/
long timestampMs;
/**
* UTC time received from the NTP server in units of milliseconds
* since January 1, 1970
*/
long utcTimeMs;