AIDL stil kılavuzu

Burada özetlenen en iyi uygulamalar, özellikle AIDL bir API 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 bir API tanımlamak için kullanılabilir. AIDL ile 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. AIDL'nin uygulamadaki örnekleri için HAL'ler için AIDL ve Kararlı AIDL başlıklı makaleleri inceleyin.

Sürüm oluşturma

Bir AIDL API'sinin geriye dönük uyumlu her anlık görüntüsü bir sürüme karşılık gelir. Anlık görüntü almak için m <module-name>-freeze-api komutunu çalıştırın. API'nin bir istemcisi veya sunucusu her yayınlandığında (ör. Mainline treninde) anlık görüntü almanız ve yeni bir sürüm oluşturmanız gerekir. Sistemden tedarikçiye API'leri için bu işlem, yıllık platform revizyonuyla birlikte yapılmalıdır.

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

API tasarım kuralları

Genel

1. Her şeyi belgeleyin

  • Her yöntemi semantiği, bağımsız değişkenleri, yerleşik istisnaların kullanımı, hizmete özel istisnalar ve dönüş değeri açısından belgeleyin.
  • Her arayüzü semantiği için belgeleyin.
  • Numaralandırılmış türlerin ve sabitlerin semantik anlamını belgeleme.
  • Uygulayıcı için net olmayan her şeyi belgeleyin.
  • Uygun yerlerde örnekler verin.

2. Dış Lastik

Türler için büyük harf içeren camel case, yöntemler, alanlar ve bağımsız değişkenler için ise küçük harf içeren camel case kullanın. Örneğin, paketlenebilir bir tür için MyParcelable, bağımsız değişken için anArgument. Kısaltmalar için kısaltmayı bir kelime olarak değerlendirin (NFC -> Nfc).

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

Arayüzler

1. Adlandırma

[-Winterface-name] Arayüz adı I ile başlamalıdır (ör. IFoo).

2. Kimliğe dayalı "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 sahtesinin yapılamamasından yararlanır.

Önerilmez: Kimliğe dayalı nesneler içeren 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öntemlerle çift yönlü yöntemleri karıştırmayın

[-Wmixed-oneway] Tek yönlü yöntemleri tek yönlü olmayan yöntemlerle karıştırmayın. Bu durum, istemciler ve sunucular için iş parçacığı modelini anlamayı zorlaştırır. Özellikle belirli bir arayüzün istemci kodunu okurken her yöntemin engelleyip engellemeyeceğini aramanız gerekir.

4. Dönüş durum kodlarından kaçının

Tüm AIDL yöntemlerinde örtülü bir durum döndürme kodu olduğundan, yöntemler döndürülen değerler olarak durum kodlarını kullanmamalıdır. ServiceSpecificException veya EX_SERVICE_SPECIFIC sayfasına bakın. Bu değerler, bir AIDL arayüzünde sabitler olarak tanımlanır. Daha ayrıntılı bilgiyi AIDL arka uçlarının hata işleme bölümünde bulabilirsiniz.

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

[-Wout-array] void foo(out String[] ret) gibi dizi çıkış parametrelerine sahip yöntemler genellikle kötüdür. Çünkü çıkış dizisinin boyutu Java'da istemci tarafından bildirilip ayrılmalıdır. Bu nedenle, dizi çıkışının boyutu sunucu tarafından seçilemez. Bu istenmeyen davranış, Java'da dizilerin çalışma şeklinden (yeniden tahsis edilemezler) kaynaklanır. Bunun yerine String[] foo() gibi API'leri tercih edin.

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

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

7. Çıkış ve giriş/çıkış @nullable olmayan dizi dışı parametrelerden kaçının

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

Yapılandırılmış parcelable'lar

1. Ne zaman kullanılır?

Gönderilecek birden fazla veri türü olduğunda yapılandırılmış paketlenebilirler kullanın.

Veya tek bir veri türünüz olduğunda ancak gelecekte bunu genişletmeniz gerekeceğini düşündüğünüzde. Örneğin, String username kullanmayın. Aşağıdaki gibi genişletilebilir bir paketlenebilir nesne kullanın:

parcelable User {
    String username;
}

Böylece gelecekte aşağıdaki şekilde uzatabilirsiniz:

parcelable User {
    String username;
    int id;
}

2. Varsayılanları açıkça sağlama

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

Yapılandırılmamış Parcelable'lar

1. Ne zaman kullanılır?

Yapılandırılmamış Parcelable'lar, Java'da @JavaOnlyStableParcelable ile, NDK arka ucunda ise @NdkOnlyStableParcelable ile kullanılabilir. Bunlar genellikle yapılandırılamayan eski ve mevcut paketlenebilirlerdir.

Sabitler ve sıralamalar

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

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

2. Numaralandırmalar kapalı kümeler olmalıdır.

Numaralandırmalar kapalı kümeler olmalıdır. Not: Yalnızca arayüz sahibi enum öğeleri ekleyebilir. Tedarikçilerin veya OEM'lerin bu alanları genişletmesi gerekiyorsa alternatif bir mekanizma gerekir. Mümkün olduğunda, tedarikçi işlevselliğinin upstreaming'i tercih edilmelidir. Ancak bazı durumlarda, özel tedarikçi değerlerine izin verilebilir (Bununla birlikte, tedarikçilerin bunu sürüm oluşturmak için bir mekanizmaya sahip olması gerekir. Belki de AIDL'nin kendisi, birbirleriyle çakışmamalı ve bu değerler üçüncü taraf uygulamalarına gösterilmemelidir).

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

Numaralandırılmış türler sürümlendirildiğinden kaç değerin mevcut olduğunu belirten değerlerden kaçınılmalıdır. C++'ta bu durum enum_range<> ile çözülebilir. Rust için enum_values() kullanın. Java'da henüz bir çözüm bulunmamaktadır.

Önerilmez: Numaralandırılmış değerler kullanmayın.

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

4. Gereksiz önek ve soneklerden kaçının

[-Wredundant-name] Sabitlerde ve numaralandırıcılarda gereksiz veya tekrar eden önek ve soneklerden kaçının.

Önerilmez: Gereksiz bir önek kullanma

enum MyStatus {
    STATUS_GOOD,
    STATUS_BAD // BAD
}

Önerilen: Enum'u doğrudan adlandırma

enum MyStatus {
    GOOD,
    BAD
}

FileDescriptor

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

Yerel arka uçlarda, FileDescriptor, otomatik olarak kapatılabilen unique_fd ile eşlendiği için güvendesiniz. Ancak kullanacağınız arka uç dilinden bağımsız olarak, gelecekte arka uç dilini değiştirme özgürlüğünüzü sınırlayacağından FileDescriptor kullanmamanız önerilir.

Bunun yerine, otomatik olarak kapatılabilen ParcelFileDescriptor özelliğini kullanın.

Değişken birimler

Değişken birimlerin, belgelere başvurmaya gerek kalmadan iyi tanımlanıp anlaşılabilmesi için ada dahil edildiğinden emin olun.

Ö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ı referanslarını belirtmelidir

Zaman damgaları (aslında tüm birimler!) birimlerini ve referans noktalarını net bir şekilde 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;