AIDL stil kılavuzu

Burada açıklanan en iyi uygulamalar, özellikle AIDL bir API'yi tanımlamak veya API yüzeyleriyle etkileşim kurmak için kullanıldığında, AIDL arayüzlerini etkili bir şekilde ve arayüzün esnekliğine dikkat ederek geliştirmek için bir kılavuz görevi görür.

AIDL, uygulamaların arka plan işleminde birbirleriyle veya sistemle arayüz oluşturması gerektiğinde API tanımlamak için kullanılabilir. AIDL içeren uygulamalarda programlama arayüzleri geliştirme hakkında daha fazla bilgi için Android Arayüz Tanımlama Dili (AIDL) başlıklı makaleyi inceleyin. Uygulamadaki AIDL örnekleri için HAL'ler için AIDL ve Kararlı AIDL'ye bakın.

Sürüm oluşturma

Bir AIDL API'nin geriye dönük uyumlu her anlık görüntüsü bir sürüme karşılık gelir. Ekran görüntüsü almak için m <module-name>-freeze-api komutunu çalıştırın. API'nin bir istemcisi veya sunucusu her yayınlandığında (ör. ana hat treninde) anlık görüntü almanız ve yeni bir sürüm oluşturmanız gerekir. Sistemden tedarikçiye API'ler için bu işlem yıllık platform revizyonunda gerçekleşir.

İzin verilen değişiklik türleri hakkında daha fazla bilgi için Arayüz sürümlendirme başlıklı makaleyi inceleyin.

API tasarımı yönergeleri

Genel

1. Her şeyi belgeleyin

  • Her yöntemin anlamsal özelliklerini, bağımsız değişkenlerini, yerleşik istisnaların kullanımını, hizmete özgü istisnaları ve döndürülen değeri belgeleyin.
  • Her arayüzün anlamsallığını belgeleyin.
  • Listelemelerin ve sabitlerin anlamsal anlamını açıklayın.
  • Uygulamacı için net olmayan her şeyi belgeleyin.
  • Uygun durumlarda örnek verin.

2. Dış lastik

Türler için büyük harfle, yöntemler, alanlar ve bağımsız değişkenler için küçük harfle başlayın. Örneğin, ayrıştırılabilir tür için MyParcelable, bağımsız değişken için anArgument. Kısaltmalar için kelime kısaltmasını kullanabilirsiniz (NFC -> Nfc).

[-Wconst-name] Enum değerleri ve sabitler ENUM_VALUE ve CONSTANT_NAME olmalıdır

Arayüzler

1. Adlandırma

[-Winterface-name] Arayüz adı, IFoo gibi I ile başlamalıdır.

2. Kimlik tabanlı "nesneler" içeren büyük arayüzlerden kaçının

Belirli bir API ile ilgili çok sayıda çağrı olduğunda alt arayüzleri tercih edin. Bu durum, aşağıdaki avantajları sağlar:

  • İstemci veya sunucu kodunun anlaşılmasını kolaylaştırır
  • Nesnelerin yaşam döngüsünü basitleştirir
  • Bağlayıcıların dövülemez olmasından faydalanır.

Önerilmez: Kimlik tabanlı nesnelerin bulunduğu tek ve büyük bir arayüz

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
}

Önerilen: Ayrı arayüzler

interface IManager {
    IFoo getFoo();
}

interface IFoo {
    void begin(); // clients in other processes can't guess a binder
    void op();
}

3. Tek yönlü yöntemleri iki yönlü yöntemlerle karıştırmayın

[-Wmixed-oneway] Tek yönlü yöntemlerle tek yönlü olmayan yöntemleri karıştırmayın. Aksi takdirde, istemciler ve sunucular için mesaj dizileri modelini anlama işlemi karmaşık hale gelir. Daha açık belirtmek gerekirse, belirli bir arayüzün istemci kodunu okurken her yöntemin engelleyip engellemeyeceğini kontrol etmeniz gerekir.

4. Durum kodları döndürmekten kaçının

Tüm AIDL yöntemlerinin gizli bir durum döndürme kodu olduğundan, yöntemler dönüş değeri olarak durum kodlarından kaçınmalıdır. ServiceSpecificException veya EX_SERVICE_SPECIFIC başlıklı makaleyi inceleyin. Bu değerler, kural olarak bir AIDL arayüzünde sabit olarak tanımlanır. Daha ayrıntılı bilgi için AIDL arka uçlarının hata işleme bölümüne bakın.

5. Çıkış parametresi olarak kullanılan diziler zararlı olarak kabul edilir

[-Wout-array] void foo(out String[] ret) gibi dizi çıkış parametreleri olan yöntemler genellikle kötüdür çünkü çıkış dizisi boyutu Java'da istemci tarafından tanımlanmalı ve ayrılmalıdır. Bu nedenle, dizi çıkışının boyutu sunucu tarafından seçilemez. Bu istenmeyen davranış, dizilerin Java'da işleyiş şekli nedeniyle (yeniden ayrılamazlar) ortaya çıkar. Bunun yerine String[] foo() gibi API'leri tercih edin.

6. Giriş/çıkış parametrelerinden kaçının

[-Winout-parameter] in parametreleri bile out parametrelerine benzediği için bu durum müşterilerin kafasını karıştırabilir.

7. out ve inout @nullable olmayan dizi dışı parametrelerden kaçının

[-Wout-nullable] Java arka ucu, diğer arka uçlar @nullable ek açıklamasını işlemediği için out/inout @nullable T arka uçlar arasında tutarsız davranışlara neden olabilir. Örneğin, Java olmayan arka uçlar @nullable parametresini null olarak ayarlayabilir (C++'ta std::nullopt olarak ayarlayabilir) ancak Java istemcisi bunu null olarak okuyamaz.

Yapılandırılmış paketlenebilir öğeler

1. Ne zaman kullanılır?

Gönderilecek birden fazla veri türünün olduğu yapılandırılmış ayrıştırıcıları kullanın.

Tek bir veri türünü kullanırken gelecekte bu türü genişletmeniz gerekebileceğini düşünüyorsanız da bu yöntemi kullanabilirsiniz. Örneğin, String username kullanmayın. Aşağıdaki gibi genişletilebilir bir paketlenebilir öğe kullanın:

parcelable User {
    String username;
}

Böylece, gelecekte aşağıdaki gibi genişletebilirsiniz:

parcelable User {
    String username;
    int id;
}

2. Varsayılanları açıkça belirtin

[-Wexplicit-default, -Wenum-explicit-default] Alanlar için açık varsayılanlar sağlayın.

Yapılandırılmamış paketlenebilir öğeler

1. Ne zaman kullanılır?

Yapılandırılmamış paketlenebilirler, Java'da @JavaOnlyStableParcelable ile ve NDK arka ucunda @NdkOnlyStableParcelable ile kullanılabilir. Bunlar genellikle yapılandırılamayan eski ve mevcut paketlenebilir öğelerdir.

Sabitler ve sıralamalar

1. Bit alanları sabit alanlar kullanmalıdır

Bit alanları sabit alanlar (ör. bir arayüzde const int FOO = 3;) kullanmalıdır.

2. Listeler kapalı kümeler olmalıdır.

Listeler kapalı kümeler olmalıdır. Not: Yalnızca arayüz sahibi, enum öğeleri ekleyebilir. Tedarikçi firmaların veya OEM'lerin bu alanları genişletmesi gerekiyorsa alternatif bir mekanizmaya ihtiyaç vardır. Mümkün olduğunda tedarikçi işlevini yayına aktarma tercih edilmelidir. Ancak bazı durumlarda özel tedarikçi değerlerine izin verilebilir (ancak tedarikçilerin bunu sürümlendirecek bir mekanizması olmalıdır, belki de AIDL'nin kendisi, birbirleriyle çakışamaz ve bu değerler üçüncü taraf uygulamalarına gösterilmemelidir).

3. "NUM_ELEMENTS" gibi değerlerden kaçının

Listeler sürüm içerdiğinden, kaç tane değer olduğunu belirten değerlerden kaçınılmalıdır. C++'ta bu sorun enum_range<> ile çözülebilir. Rust için enum_values() kullanın. Java'da henüz bir çözüm bulunmuyor.

Önerilmez: Numaralı değerler kullanma

@Backing(type="int")
enum FruitType {
    APPLE = 0,
    BANANA = 1,
    MANGO = 2,
    NUM_TYPES, // BAD
}

4. Gereksiz ön eklerden ve son eklerden kaçının

[-Wredundant-name] Sabitler ve sayılandırıcılarda gereksiz veya yinelenen ön eklerden ve son eklerden kaçının.

Önerilmez: Gereksiz bir önek kullanılması

enum MyStatus {
    STATUS_GOOD,
    STATUS_BAD // BAD
}

Önerilen: Sıralamayı doğrudan adlandırma

enum MyStatus {
    GOOD,
    BAD
}

FileDescriptor

[-Wfile-descriptor] FileDescriptor değerinin bir bağımsız değişken veya AIDL arayüz yönteminin döndürdüğü değer olarak kullanılması önerilmez. Bu durum, özellikle AIDL Java'da uygulandığında, dikkatli bir şekilde ele alınmadığı takdirde dosya tanımlayıcısı sızıntısına neden olabilir. Özetle, bir FileDescriptor'yi kabul ederseniz artık kullanılmadığında manuel olarak kapatmanız gerekir.

Doğal arka uçlarda FileDescriptor, otomatik olarak kapatılabilen unique_fd ile eşlendiğinden güvendesiniz. Ancak kullanacağınız arka uç dilinden bağımsız olarak, FileDescriptor kullanmamak akıllıca bir seçimdir. Aksi takdirde, gelecekte arka uç dilini değiştirme özgürlüğünüz sınırlanır.

Bunun yerine, otomatik olarak kapatılabilen ParcelFileDescriptor seçeneğini kullanın.

Değişken birimler

Değişken birimlerinin ada eklendiğinden emin olun. Böylece, birimlerin belgelere referansta bulunmaya gerek kalmadan iyi tanımlanmasını ve anlaşılmasını sağlayabilirsiniz.

Örnekler

long duration; // Bad
long durationNsec; // Good
long durationNanos; // Also good

double energy; // Bad
double energyMilliJoules; // Good

int frequency; // Bad
int frequencyHz; // Good

Zaman damgalarında referans belirtilmelidir.

Zaman damgaları, birimlerini ve referans noktalarını açıkça belirtmelidir.

Örnekler

/**
 * 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;