Android 10, kararlı Android Arayüz Tanımlama Dili (AIDL) desteği ekler. Bu, AIDL arayüzleri tarafından sağlanan uygulama programlama arayüzünü (API) ve uygulama ikili arayüzünü (ABI) takip etmenin yeni bir yoludur. Kararlı AIDL, AIDL ile aynı şekilde çalışır ancak derleme sistemi arayüz uyumluluğunu izler ve yapabileceğiniz işlemler konusunda kısıtlamalar vardır:
- Arayüzler, derleme sisteminde
aidl_interfaces
ile tanımlanır. - Arayüzler yalnızca yapılandırılmış veriler içerebilir. Tercih edilen türleri temsil eden Parcelables, AIDL tanımlarına göre otomatik olarak oluşturulur ve otomatik olarak marshallenir ve unmarshallenir.
- Arayüzler kararlı (geriye dönük uyumlu) olarak tanımlanabilir. Bu durumda, API'leri AIDL arayüzünün yanındaki bir dosyada izlenir ve sürümleri belirlenir.
Yapılandırılmış ve kararlı AIDL
Yapılandırılmış AIDL, yalnızca AIDL'de tanımlanan türleri ifade eder. Örneğin, paketlenebilir bildirim (özel paketlenebilir) yapılandırılmış AIDL değildir. AIDL'de tanımlanan alanları olan Parcelables'lara yapılandırılmış Parcelables denir.
Kararlı AIDL, derleme sisteminin ve derleyicinin, paketlenebilir öğelerde yapılan değişikliklerin geriye dönük uyumlu olup olmadığını anlayabilmesi için yapılandırılmış AIDL gerektirir.
Ancak tüm yapılandırılmış arayüzler kararlıdır. Bir arayüzün kararlı olması için yalnızca yapılandırılmış türlerin yanı sıra aşağıdaki sürüm oluşturma özelliklerini de kullanması gerekir. Buna karşılık, bir arayüz oluşturmak için temel derleme sistemi kullanılırsa veya unstable:true
ayarlanırsa arayüz kararlı olmaz.
AIDL arayüzü tanımlama
aidl_interface
tanımı şu şekildedir:
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
: AIDL arayüzünü benzersiz şekilde tanımlayan AIDL arayüz modülünün adı.srcs
: Arayüzü oluşturan AIDL kaynak dosyalarının listesi.com.acme
paketinde tanımlananFoo
adlı bir AIDL türü için yol<base_path>/com/acme/Foo.aidl
olmalıdır. Burada<base_path>
,Android.bp
'ın bulunduğu dizinle ilgili herhangi bir dizin olabilir. Önceki örnekte<base_path>
,srcs/aidl
'tir.local_include_dir
: Paket adının başladığı yol. Yukarıda açıklanan<base_path>
ile aynıdır.imports
: Bu öğenin kullandığıaidl_interface
modüllerinin listesi. AIDL arayüzlerinizden biri başka biraidl_interface
'den bir arayüz veya paketlenebilir öğe kullanıyorsa adını buraya yazın. Bu, en son sürümü belirtmek için adın kendisi veya belirli bir sürümü belirtmek için sürüm son eki (-V1
gibi) içeren ad olabilir. Sürüm belirtme özelliği Android 12'den beri desteklenmektedir.versions
: Arayüzünapi_dir
altında dondurulmuş önceki sürümleri. Android 11'den itibarenversions
,aidl_api/name
altında dondurulur. Bir arayüzün dondurulmuş sürümü yoksa bu belirtilmemelidir ve uyumluluk kontrolleri yapılmaz. Bu alan, Android 13 ve sonraki sürümler içinversions_with_info
ile değiştirilmiştir.versions_with_info
: Her biri dondurulmuş bir sürümün adını ve aidl_interface'ın bu sürümünün içe aktardığı diğer aidl_interface modüllerinin sürüm içe aktarma işlemlerini içeren bir liste. IFACE adlı bir AIDL arayüzünün V sürümünün tanımıaidl_api/IFACE/V
adresinde yer alır. Bu alan Android 13'te kullanıma sunulmuştur ve doğrudanAndroid.bp
'te değiştirilmesi gerekmez. Alan,*-update-api
veya*-freeze-api
çağrılarak eklenir ya da güncellenir. Ayrıca, kullanıcı*-update-api
veya*-freeze-api
'i çağrdığındaversions
alanları otomatik olarakversions_with_info
alanına taşınır.stability
: Bu arayüzün istikrar vaadi için isteğe bağlı işaret. Bu yalnızca"vintf"
desteklenir.stability
ayarlanmamışsa derleme sistemi,unstable
belirtilmediği sürece arayüzün geriye dönük uyumlu olup olmadığını kontrol eder. Ayarlanmamış olma durumu, bu derleme bağlamında kararlılığa sahip bir arayüze karşılık gelir (yani tüm sistem öğeleri (ör.system.img
ve ilgili bölümlerdeki öğeler) veya tüm tedarikçi öğeleri (ör.vendor.img
ve ilgili bölümlerdeki öğeler)).stability
,"vintf"
olarak ayarlanırsa bu, kararlılık vaadiyle ilişkilidir: Arayüz, kullanıldığı sürece kararlı tutulmalıdır.gen_trace
: İzlemeyi etkinleştirmek veya devre dışı bırakmak için isteğe bağlı işaret. Android 14'ten itibarencpp
vejava
arka uçları için varsayılan değertrue
'tir.host_supported
:true
olarak ayarlandığında oluşturulan kitaplıkların ana makine ortamına sunulmasını sağlayan isteğe bağlı işaret.unstable
: Bu arayüzün kararlı olması gerekmediğini belirtmek için kullanılan isteğe bağlı işaret. Bu değertrue
olarak ayarlandığında derleme sistemi, arayüz için API dökümünü oluşturmaz ve güncellenmesini gerektirmez.frozen
:true
olarak ayarlandığında arayüzün önceki sürümünden bu yana herhangi bir değişiklik olmadığını belirten isteğe bağlı işaret. Bu sayede daha fazla derleme zamanı kontrolü yapılabilir.false
olarak ayarlandığında arayüzün geliştirme aşamasında olduğu ve yeni değişiklikler içerdiği anlamına gelir. Bu nedenle,foo-freeze-api
çalıştırıldığında yeni bir sürüm oluşturulur ve değer otomatik olaraktrue
olarak değiştirilir. Android 14'te kullanıma sunulmuştur.backend.<type>.enabled
: Bu işaretler, AIDL derleyicisinin kod oluşturduğu arka uçların her birini açar veya kapatır. Dört arka uç desteklenir: Java, C++, NDK ve Rust. Java, C++ ve NDK arka uçları varsayılan olarak etkindir. Bu üç arka uçtan herhangi birine ihtiyaç yoksa açıkça devre dışı bırakılması gerekir. Rust, Android 15'e kadar varsayılan olarak devre dışıdır.backend.<type>.apex_available
: Oluşturulan stub kitaplığının kullanılabildiği APEX adlarının listesi.backend.[cpp|java].gen_log
: İşlemle ilgili bilgi toplamak için ek kod oluşturulup oluşturulmayacağını kontrol eden isteğe bağlı işaret.backend.[cpp|java].vndk.enabled
: Bu arayüzü VNDK'nın bir parçası haline getirmek için isteğe bağlı işaret. Varsayılan değerfalse
'tir.backend.[cpp|ndk].additional_shared_libraries
: Android 14'te kullanıma sunulan bu işaret, yerel kitaplıklara bağımlılık ekler. Bu işaret,ndk_header
vecpp_header
ile birlikte kullanıldığında işe yarar.backend.java.sdk_version
: Java stub kitaplığının derlendiği SDK sürümünü belirtmek için isteğe bağlı işaret. Varsayılan değer"system_current"
'tir.backend.java.platform_apis
true
olduğunda bu ayarlanmamalıdır.backend.java.platform_apis
: Oluşturulan kitaplıkların SDK yerine platform API'sine göre derlenmesi gerektiğindetrue
olarak ayarlanması gereken isteğe bağlı işaret.
Sürümlerin ve etkin arka uçların her kombinasyonu için bir stub kitaplığı oluşturulur. Belirli bir arka uç için stub kitaplığının belirli bir sürümüne nasıl referans verileceği hakkında bilgi edinmek için Modül adlandırma kuralları başlıklı makaleyi inceleyin.
AIDL dosyaları yazma
Kararlı AIDL'deki arayüzler, geleneksel arayüzlere benzer. Bununla birlikte, yapılandırılmamış parcelable'ların kullanılmasına izin verilmez (çünkü bunlar kararlı değildir. Yapılandırılmış ve kararlı AIDL bölümüne bakın). Kararlı AIDL'deki birincil fark, paketlenebilir öğelerin nasıl tanımlandığıdır. Daha önce, parcelable'lar ileriye dönük olarak tanımlanıyordu. Kararlı (ve dolayısıyla yapılandırılmış) AIDL'de parcelable alanları ve değişkenleri açıkça tanımlanır.
// in a file like 'some/package/Thing.aidl'
package some.package;
parcelable SubThing {
String a = "foo";
int b;
}
boolean
, char
, float
, double
, byte
, int
, long
ve String
için varsayılan değer desteklenir (ancak zorunlu değildir). Android 12'de kullanıcı tanımlı listelemelerin varsayılan değerleri de desteklenir. Varsayılan değer belirtilmediğinde 0'a benzer veya boş bir değer kullanılır.
Varsayılan değeri olmayan listelemelerde, sıfır listeleyici olmasa bile 0 değeri kullanılır.
Kütüphane taslağı kullanma
Modülünüze bağımlı olarak stub kitaplıklarını ekledikten sonra bunları dosyalarınıza dahil edebilirsiniz. Aşağıda, derleme sistemindeki stub kitaplıklarının örnekleri verilmiştir (Android.mk
eski modül tanımları için de kullanılabilir).
Bu örneklerde sürüm bulunmadığından kararsız bir arayüz kullanıldığını gösterir. Ancak sürüm içeren arayüz adları ek bilgiler içerir. Arayüz sürümleri bölümüne bakın.
cc_... {
name: ...,
// use `shared_libs:` to load your library and its transitive dependencies
// dynamically
shared_libs: ["my-module-name-cpp"],
// use `static_libs:` to include the library in this binary and drop
// transitive dependencies
static_libs: ["my-module-name-cpp"],
...
}
# or
java_... {
name: ...,
// use `static_libs:` to add all jars and classes to this jar
static_libs: ["my-module-name-java"],
// use `libs:` to make these classes available during build time, but
// not add them to the jar, in case the classes are already present on the
// boot classpath (such as if it's in framework.jar) or another jar.
libs: ["my-module-name-java"],
// use `srcs:` with `-java-sources` if you want to add classes in this
// library jar directly, but you get transitive dependencies from
// somewhere else, such as the boot classpath or another jar.
srcs: ["my-module-name-java-source", ...],
...
}
# or
rust_... {
name: ...,
rustlibs: ["my-module-name-rust"],
...
}
C++'ta örnek:
#include "some/package/IFoo.h"
#include "some/package/Thing.h"
...
// use just like traditional AIDL
Java'da örnek:
import some.package.IFoo;
import some.package.Thing;
...
// use just like traditional AIDL
Rust'ta örnek:
use aidl_interface_name::aidl::some::package::{IFoo, Thing};
...
// use just like traditional AIDL
Arayüzlerin sürümlerini oluşturma
foo adlı bir modül tanımladığınızda, derleme sisteminde modülün API'sini yönetmek için kullanabileceğiniz bir hedef de oluşturulur. Derlendiğinde foo-freeze-api, Android sürümüne bağlı olarak api_dir
veya aidl_api/name
altında yeni bir API tanımı ve her ikisi de arayüzün yeni dondurulmuş sürümünü temsil eden bir .hash
dosyası ekler. foo-freeze-api, versions_with_info
mülkünü ek sürümü ve sürüm için imports
'i yansıtacak şekilde de günceller. Temel olarak, versions_with_info
alanındaki imports
, imports
alanından kopyalanır. Ancak açık bir sürümü olmayan içe aktarma işlemi için versions_with_info
içindeki imports
alanında en son kararlı sürüm belirtilmiştir.
versions_with_info
mülkü belirtildikten sonra derleme sistemi, dondurulmuş sürümler arasında ve ayrıca ağaç üst kısmı (ToT) ile en son dondurulmuş sürüm arasında uyumluluk kontrolleri yapar.
Ayrıca, ToT sürümünün API tanımını yönetmeniz gerekir. Bir API güncellendiğinde, ToT sürümünün API tanımını içeren aidl_api/name/current
dosyasını güncellemek için foo-update-api komutunu çalıştırın.
Sahipler, arayüzün kararlılığını korumak için yeni öğeler ekleyebilir:
- Bir arayüzün sonundaki yöntemler (veya açıkça tanımlanmış yeni serilere sahip yöntemler)
- Paketlenebilir öğelerin sonuna eklenen öğeler (her öğe için varsayılan bir değer eklenmesini gerektirir)
- Sabit değerler
- Android 11'de dize dizenler
- Android 12'de bir birleştirme işleminin sonuna kadar olan alanlar
Başka işlemlere izin verilmez ve başka hiç kimse arayüzde değişiklik yapamaz (aksi takdirde, sahibin yaptığı değişikliklerle çakışabilir).
Tüm arayüzlerin sürüm için dondurulduğunu test etmek üzere aşağıdaki ortam değişkenlerini ayarlayarak derleme yapabilirsiniz:
AIDL_FROZEN_REL=true m ...
: Derleme,owner:
alanı belirtilmeyen tüm kararlı AIDL arayüzlerinin dondurulmasını gerektirir.AIDL_FROZEN_OWNERS="aosp test"
: Derleme işlemi, tüm kararlı AIDL arayüzlerininowner:
alanı "aosp" veya "test" olarak belirtilmiş şekilde dondurulmasını gerektirir.
İçe aktarma işlemlerinin kararlılığı
Bir arayüzün dondurulmuş sürümleri için içe aktarma sürümlerini güncellemek, kararlı AIDL katmanında geriye dönük uyumludur. Ancak bunların güncellenmesi, arayüzün önceki bir sürümünü kullanan tüm sunucuların ve istemcilerin güncellenmesini gerektirir. Ayrıca bazı uygulamalar, türlerin farklı sürümlerini karıştırırken karışıklık yaşayabilir. Genellikle, yalnızca tür veya ortak paketler için bu güvenlidir çünkü IPC işlemlerinden gelen bilinmeyen türleri işlemek için kodun zaten yazılmış olması gerekir.
Android platform kodunda android.hardware.graphics.common
, bu tür sürüm yükseltmelerinin en büyük örneğidir.
Sürümlü arayüzleri kullanma
Arayüz yöntemleri
Eski bir sunucuda yeni yöntemler çağrılmaya çalışıldığında, yeni istemciler arka uçta bir hata veya istisna alır.
cpp
arka ucu::android::UNKNOWN_TRANSACTION
alır.ndk
arka ucuSTATUS_UNKNOWN_TRANSACTION
alır.java
arka uç, API'nin uygulanmadığını belirten bir mesajlaandroid.os.RemoteException
alır.
Bu sorunu gidermek için kullanılabilecek stratejiler için sürümleri sorgulama ve varsayılanları kullanma başlıklı makalelere bakın.
Ayrıştırılabilir öğeler
Paketlenebilir öğelere yeni alanlar eklendiğinde eski istemciler ve sunucular bunları düşürür. Yeni istemciler ve sunucular eski paketlenebilir öğeleri aldığında yeni alanlar için varsayılan değerler otomatik olarak doldurulur. Bu nedenle, paketlenebilir bir öğedeki tüm yeni alanlar için varsayılan değerlerin belirtilmesi gerekir.
İstemciler, sunucunun alanı tanımlanmış sürümü uyguladığını bilmedikçe sunucuların yeni alanları kullanmasını beklememelidir (sürümleri sorgulamaya bakın).
Sıralamalar ve sabitler
Benzer şekilde, istemciler ve sunucular, gelecekte daha fazlası eklenebilir olduğundan tanınmayan sabit değerleri ve dize dizinlerini uygun şekilde reddetmeli veya yok saymalıdır. Örneğin, bir sunucu, bilmediği bir dizine ekleme işlevi aldığında işlemi iptal etmemelidir. Sunucu, dizini yok saymalı veya istemcinin bu uygulamada desteklenmediğini bilmesi için bir şey döndürmelidir.
Birlikler
Alıcı eskiyse ve alan hakkında bilgi sahibi değilse yeni bir alan içeren bir birleştirme göndermeye çalışmak başarısız olur. Uygulama, yeni alanla birleşme işlemini hiçbir zaman görmez. Tek yönlü bir işlemse hata yoksayılır. Aksi takdirde hata BAD_VALUE
(C++ veya NDK arka uç için) ya da IllegalArgumentException
(Java arka uç için) olur. Müşteri yeni alana ayarlanmış bir birleştirme gönderiyorsa veya eski bir müşteri yeni bir sunucudan birleştirme aldığında bu hata alınır.
Birden fazla sürümü yönetme
Oluşturulan aidl
türlerinin birden fazla tanımı olduğu durumları önlemek için Android'deki bir bağlayıcı ad alanının belirli bir aidl
arayüzünün yalnızca 1 sürümü olabilir. C++, her sembol için yalnızca bir tanımın gerekli olduğu Tek Tanım Kuralı'na sahiptir.
Bir modül aynı aidl_interface
kitaplığının farklı sürümlerine bağlı olduğunda Android derlemesi hata verir. Modül, bu kitaplıklara doğrudan veya bağımlılarının bağımlılıkları aracılığıyla dolaylı olarak bağlı olabilir. Bu hatalar, başarısız modülden aidl_interface
kitaplığının çakışan sürümlerine kadar olan bağımlılık grafiğini gösterir. Tüm bağımlılıkların, bu kitaplıkların aynı (genellikle en son) sürümünü içerecek şekilde güncellenmesi gerekir.
Arayüz kitaplığı birçok farklı modül tarafından kullanılıyorsa aynı sürümü kullanması gereken kitaplık ve işlem grupları için cc_defaults
, java_defaults
ve rust_defaults
oluşturmak yararlı olabilir. Arayüzün yeni bir sürümü kullanıma sunulduğunda bu varsayılanlar güncellenebilir ve bunları kullanan tüm modüller birlikte güncellenerek arayüzün farklı sürümlerini kullanmamaları sağlanır.
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"],
...
}
aidl_interface
modülleri diğer aidl_interface
modüllerini içe aktardığında, belirli sürümlerin birlikte kullanılmasını gerektiren ek bağımlılıklar oluşur. Aynı işlemlerde birlikte kullanılan birden fazla aidl_interface
modülüne içe aktarılan ortak aidl_interface
modülleri olduğunda bu durumun yönetimi zor olabilir.
aidl_interfaces_defaults
, bir aidl_interface
için bağımlılıkların en son sürümlerinin tek bir yerde güncellenebilen ve bu ortak arayüzü içe aktarmak isteyen tüm aidl_interface
modülleri tarafından kullanılabilen tek bir tanımını tutmak için kullanılabilir.
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"],
...
}
İşaret tabanlı geliştirme
Geliştirme aşamasındaki (dondurulmamış) arayüzlerin geriye dönük uyumlu olması garanti edilmediğinden, bu arayüzler yayın cihazlarında kullanılamaz.
AIDL, kodun dondurulmamış en son sürüme göre yazılabilmesi ve yine de yayın cihazlarında kullanılabilmesi için bu dondurulmamış arayüz kitaplıkları için çalışma zamanında yedekleme desteği sunar. İstemcilerin geriye dönük uyumlu davranışı mevcut davranışa benzer. Yedekleme ile birlikte, uygulamaların da bu davranışları uygulaması gerekir. Sürümlü arayüzleri kullanma başlıklı makaleyi inceleyin.
AIDL derleme işareti
Bu davranışı kontrol eden işaret, build/release/build_flags.bzl
içinde RELEASE_AIDL_USE_UNFROZEN
tanımlanır. true
, arayüzün dondurulmamış sürümünün çalışma zamanında kullanıldığı anlamına gelir. false
ise dondurulmamış sürümlerin kitaplıklarının tümü, son dondurulmuş sürümleri gibi davranır.
Yerel geliştirme için işareti true
olarak geçersiz kılabilirsiniz ancak yayınlamadan önce false
olarak geri döndürmeniz gerekir. Geliştirme genellikle işareti true
olarak ayarlanmış bir yapılandırmayla yapılır.
Uyumluluk matrisi ve manifestler
Tedarikçi arayüzü nesneleri (VINTF nesneleri), tedarikçi arayüzünün her iki tarafında hangi sürümlerin beklendiğini ve hangi sürümlerin sağlandığını tanımlar.
Cuttlefish dışındaki cihazların çoğu, en son uyumluluk matrisini yalnızca arayüzler dondurulduktan sonra hedefler. Bu nedenle, RELEASE_AIDL_USE_UNFROZEN
'e dayalı AIDL kitaplıklarında fark yoktur.
Matrisler
İş ortağına ait arayüzler, cihazın geliştirme sırasında hedeflediği cihaza veya ürüne özel uyumluluk matrislerine eklenir. Bu nedenle, bir arayüzün dondurulmamış yeni bir sürümü uyumluluk matrisine eklendiğinde, önceki dondurulmuş sürümlerin RELEASE_AIDL_USE_UNFROZEN=false
için kalmasının Bu sorunu, farklı RELEASE_AIDL_USE_UNFROZEN
konfigürasyonlar için farklı uyumluluk matrisi dosyaları kullanarak veya tüm yapılandırmalarda kullanılan tek bir uyumluluk matrisi dosyasında her iki sürüme de izin vererek çözebilirsiniz.
Örneğin, dondurulmamış bir 4. sürüm eklerken <version>3-4</version>
kullanın.
4. sürüm dondurulduğunda 3. sürümü uyumluluk matrisinden kaldırabilirsiniz. Bunun nedeni, dondurulmuş 4. sürümün RELEASE_AIDL_USE_UNFROZEN
false
olduğunda kullanılmasıdır.
Manifestler
Android 15'te, derleme sırasında manifest dosyalarını RELEASE_AIDL_USE_UNFROZEN
değerine göre değiştirmek için libvintf
'te bir değişiklik yapıldı.
Manifestler ve manifest parçaları, bir hizmetin hangi arayüz sürümünü uyguladığını belirtir. Bir arayüzün dondurulmamış en son sürümü kullanıldığında manifest, bu yeni sürümü yansıtacak şekilde güncellenmelidir. RELEASE_AIDL_USE_UNFROZEN=false
olduğunda, manifest girişleri, oluşturulan AIDL kitaplığındaki değişikliği yansıtacak şekilde libvintf
tarafından ayarlanır. Sürüm, dondurulmamış sürüm N
'ten son dondurulmuş sürüm N - 1
'e değiştirilir. Bu nedenle, kullanıcıların her hizmeti için birden fazla manifest veya manifest parçası yönetmesi gerekmez.
HAL istemci değişiklikleri
HAL istemci kodu, desteklenen önceki her dondurulmuş sürümle geriye dönük uyumlu olmalıdır. RELEASE_AIDL_USE_UNFROZEN
false
olduğunda hizmetler her zaman son dondurulmuş sürüm veya önceki sürümler gibi görünür (örneğin, dondurulmamış yeni yöntemlerin çağrılması UNKNOWN_TRANSACTION
değerini döndürür veya yeni parcelable
alanlarının varsayılan değerleri olur). Android çerçeve istemcilerinin önceki sürümlerle geriye dönük uyumlu olması gerekir ancak bu, tedarikçi istemcileri ve iş ortağına ait arayüz istemcileri için yeni bir ayrıntıdır.
HAL uygulama değişiklikleri
İşaretçi tabanlı geliştirmeyle HAL geliştirme arasındaki en büyük fark, HAL uygulamalarının RELEASE_AIDL_USE_UNFROZEN
false
olduğunda çalışmak için son dondurulmuş sürümle geriye dönük uyumlu olması şartıdır.
Uygulamalarda ve cihaz kodunda geriye dönük uyumluluğu göz önünde bulundurmak yeni bir çalışmadır. Sürümlü arayüzleri kullanma başlıklı makaleyi inceleyin.
Geriye dönük uyumlulukla ilgili hususlar genellikle istemciler ve sunucular ile çerçeve kodu ve tedarikçi kodu için aynıdır. Ancak artık aynı kaynak kodunu (mevcut, dondurulmamış sürüm) kullanan iki sürümü etkili bir şekilde uyguladığınız için dikkat etmeniz gereken ince farklılıklar vardır.
Örnek: Bir arayüzün üç dondurulmuş sürümü vardır. Arayüz yeni bir yöntemle güncellenir. Hem istemci hem de hizmet, yeni 4. sürüm kitaplığı kullanacak şekilde güncellenir. V4 kitaplığı, arayüzün dondurulmamış bir sürümünü temel aldığından, RELEASE_AIDL_USE_UNFROZEN
false
olduğunda son dondurulmuş sürüm (3. sürüm) gibi davranır ve yeni yöntemin kullanılmasını engeller.
Arayüz dondurulduğunda RELEASE_AIDL_USE_UNFROZEN
değerinin tümünde dondurulmuş sürüm kullanılır ve geriye dönük uyumluluğu yöneten kod kaldırılabilir.
Geri aramalarda yöntemleri çağırırken UNKNOWN_TRANSACTION
döndürüldüğünde durumu düzgün bir şekilde ele almanız gerekir. İstemciler, sürüm yapılandırmasına bağlı olarak geri çağırma işlevinin iki farklı sürümünü uygulayabilir. Bu nedenle, istemcinin en yeni sürümü gönderdiğini varsayamazsınız ve yeni yöntemler bunu döndürebilir. Bu, Sürüm numaralı arayüzleri kullanma bölümünde açıklanan, kararlı AIDL istemcilerinin sunucularla geriye dönük uyumluluğu nasıl sağladığına benzer.
// 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();
}
}
Mevcut türlerdeki (parcelable
, enum
, union
) yeni alanlar, RELEASE_AIDL_USE_UNFROZEN
false
olduğunda var olmayabilir veya varsayılan değerlerini içermeyebilir. Ayrıca, bir hizmetin göndermeye çalıştığı yeni alanların değerleri, işlemden çıkarken bırakılır.
Dondurulmamış bu sürüme eklenen yeni türler arayüz üzerinden gönderilemez veya alınamaz.
RELEASE_AIDL_USE_UNFROZEN
false
olduğunda uygulama hiçbir müşteriden yeni yöntem çağrısı almaz.
Yeni dize dizili listeleyicileri yalnızca kullanıma sunulduğu sürümde kullanın. Önceki sürümde kullanmayın.
Uzak arayüzün hangi sürümü kullandığını görmek için normalde foo->getInterfaceVersion()
'ü kullanırsınız. Ancak işarete dayalı sürüm desteğiyle iki farklı sürüm uyguladığınız için mevcut arayüzün sürümünü almak isteyebilirsiniz. Bunu, geçerli nesnenin arayüz sürümünü (ör. this->getInterfaceVersion()
) veya my_ver
için diğer yöntemleri alarak yapabilirsiniz. Daha fazla bilgi için Uzak nesnenin arayüz sürümünü sorgulama başlıklı makaleyi inceleyin.
Yeni VINTF kararlı arayüzleri
Yeni bir AIDL arayüz paketi eklendiğinde son dondurulmuş sürüm olmadığından RELEASE_AIDL_USE_UNFROZEN
false
olduğunda geri dönülecek bir davranış yoktur. Bu arayüzleri kullanmayın. RELEASE_AIDL_USE_UNFROZEN
false
olduğunda Hizmet Yöneticisi, hizmetin arayüzü kaydettirmesine izin vermez ve istemciler arayüzü bulamaz.
Hizmetleri, cihaz makefile'indeki RELEASE_AIDL_USE_UNFROZEN
işaretinin değerine göre koşullu olarak ekleyebilirsiniz:
ifeq ($(RELEASE_AIDL_USE_UNFROZEN),true)
PRODUCT_PACKAGES += \
android.hardware.health.storage-service
endif
Hizmet daha büyük bir sürecin parçasıysa ve bu nedenle cihaza koşullu olarak ekleyemiyorsanız hizmetin IServiceManager::isDeclared()
ile tanımlanıp tanımlanmadığını kontrol edebilirsiniz. Tanımlanmışsa ve kaydedilmediyse işlemi iptal edin. Beyan edilmezse kaydının başarısız olması beklenir.
Geliştirme aracı olarak Cuttlefish
VINTF dondurulduktan sonra her yıl, çerçeve uyumluluk matrisini (FCM) target-level
ve Cuttlefish'in PRODUCT_SHIPPING_API_LEVEL
değerini gelecek yılın sürümüyle kullanıma sunulan cihazları yansıtacak şekilde ayarlarız. Test edilmiş ve gelecek yılki sürüm için yeni koşulları karşılayan bir lansman cihazı olduğundan emin olmak amacıyla target-level
ve PRODUCT_SHIPPING_API_LEVEL
değerlerini ayarlarız.
RELEASE_AIDL_USE_UNFROZEN
true
olduğunda Cuttlefish, gelecekteki Android sürümlerinin geliştirilmesi için kullanılır. Gelecek yılın Android sürümünün FCM düzeyini ve PRODUCT_SHIPPING_API_LEVEL
'ü hedefler. Bu nedenle, sonraki sürümün Tedarikçi Yazılım Şartları'nı (VSR) karşılaması gerekir.
RELEASE_AIDL_USE_UNFROZEN
false
olduğunda Cuttlefish, sürüm cihazını yansıtmak için önceki target-level
ve PRODUCT_SHIPPING_API_LEVEL
değerine sahiptir.
Android 14 ve önceki sürümlerde bu ayrım, FCM target-level
, gönderim API seviyesi veya sonraki sürümü hedefleyen başka bir kodda yapılan değişikliği kullanmayan farklı Git dallarıyla gerçekleştirilir.
Modül adlandırma kuralları
Android 11'de, etkinleştirilen sürüm ve arka uçların her kombinasyonu için otomatik olarak bir taslak kitaplık modülü oluşturulur. Bağlantı oluşturmak için belirli bir stub kitaplık modülüne atıfta bulunmak üzere aidl_interface
modülünün adını değil, stub kitaplık modülünün adını kullanın. Bu ad ifacename-version-backend şeklindedir.
ifacename
:aidl_interface
modülünün adıversion
şu değerlerden biri olmalıdır:- Artık güncellenmeyen sürümler için
Vversion-number
- Ağacın tepesindeki (henüz dondurulmamış) sürüm için
Vlatest-frozen-version-number + 1
- Artık güncellenmeyen sürümler için
backend
şu değerlerden biri olmalıdır:- Java arka ucu için
java
, - C++ arka ucu için
cpp
- NDK arka ucu için
ndk
veyandk_platform
. İlki uygulamalar için, ikincisi ise Android 13'e kadar platform kullanımı içindir. Android 13 ve sonraki sürümlerde yalnızcandk
kullanın. - Rust arka uç için
rust
.
- Java arka ucu için
foo adlı bir modülün olduğunu, en son sürümünün 2 olduğunu ve hem NDK hem de C++'yu desteklediğini varsayalım. Bu durumda AIDL aşağıdaki modülleri oluşturur:
- 1. sürüme göre
foo-V1-(java|cpp|ndk|ndk_platform|rust)
- 2. sürüme (en son kararlı sürüm) dayalı
foo-V2-(java|cpp|ndk|ndk_platform|rust)
- ToT sürümüne göre
foo-V3-(java|cpp|ndk|ndk_platform|rust)
Android 11 ile karşılaştırıldığında:
- En son kararlı sürümü belirten
foo-backend
,foo-V2-backend
olur. - ToT sürümünü belirten
foo-unstable-backend
,foo-V3-backend
olur.
Çıkış dosyası adları her zaman modül adlarıyla aynıdır.
- 1. sürüme dayalı:
foo-V1-(cpp|ndk|ndk_platform|rust).so
- 2. sürüme dayalı:
foo-V2-(cpp|ndk|ndk_platform|rust).so
- ToT sürümüne göre:
foo-V3-(cpp|ndk|ndk_platform|rust).so
AIDL derleyicisinin, istikrarlı bir AIDL arayüzü için unstable
sürüm modülü veya sürüm içermeyen bir modül oluşturmadığını unutmayın.
Android 12'den itibaren, kararlı bir AIDL arayüzünden oluşturulan modül adı her zaman sürümünü içerir.
Yeni meta arayüz yöntemleri
Android 10, kararlı AIDL için çeşitli meta arayüz yöntemleri ekler.
Uzak nesnenin arayüz sürümünü sorgulayın
İstemciler, uzak nesnenin uyguladığı arayüzün sürümünü ve karmasını sorgulayabilir ve döndürülen değerleri istemcinin kullandığı arayüzün değerleriyle karşılaştırabilir.
cpp
arka uç örneği:
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();
ndk
(ve ndk_platform
) arka ucu içeren örnek:
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);
java
arka uç örneği:
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();
Java dilinde uzak taraf, getInterfaceVersion()
ve getInterfaceHash()
'yi aşağıdaki gibi uygulamalıdır (kopyala ve yapıştırma hatalarını önlemek için IFoo
yerine super
kullanılır). javac
yapılandırmasına bağlı olarak uyarıları devre dışı bırakmak için @SuppressWarnings("static")
ek açıklama gerekebilir):
class MyFoo extends IFoo.Stub {
@Override
public final int getInterfaceVersion() { return super.VERSION; }
@Override
public final String getInterfaceHash() { return super.HASH; }
}
Bunun nedeni, oluşturulan sınıfların (IFoo
, IFoo.Stub
vb.) istemci ile sunucu arasında paylaşılmasıdır (örneğin, sınıflar önyükleme sınıf yolu içinde olabilir). Sınıflar paylaşıldığında sunucu, arayüzün eski bir sürümüyle oluşturulmuş olsa bile sınıfların en yeni sürümüne de bağlanır. Bu meta arayüz paylaşılan sınıfta uygulanırsa her zaman en yeni sürümü döndürür. Ancak yöntem yukarıdaki gibi uygulandığında arayüzün sürüm numarası sunucunun koduna yerleştirilir (IFoo.VERSION
, referans verildiğinde satır içi bir static final int
olduğundan) ve böylece yöntem, sunucunun derlendiği tam sürümü döndürebilir.
Eski arayüzlerle çalışma
Bir istemcinin, AIDL arayüzünün daha yeni bir sürümüyle güncellenmesi ancak sunucunun eski AIDL arayüzünü kullanması mümkündür. Bu tür durumlarda, eski bir arayüzde bir yöntem çağrıldığında UNKNOWN_TRANSACTION
döndürülür.
İstemciler, kararlı AIDL ile daha fazla kontrole sahip olur. İstemci tarafında, bir AIDL arayüzüne varsayılan bir uygulama ayarlayabilirsiniz. Varsayılan uygulamadaki bir yöntem yalnızca uzak tarafta uygulanmadığında (arayüzün eski bir sürümüyle oluşturulduğu için) çağrılır. Varsayılanlar global olarak ayarlandığından, paylaşılabilir bağlamlarda kullanılmamalıdır.
Android 13 ve sonraki sürümlerde C++ dilinde örnek:
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
Java'da örnek:
IFoo.Stub.setDefaultImpl(new IFoo.Default() {
@Override
public xxx anAddedMethod(...) throws RemoteException {
// do something default
}
}); // once per an interface in a process
foo.anAddedMethod(...);
Bir AIDL arayüzündeki tüm yöntemlerin varsayılan uygulamasını sağlamanız gerekmez. Uzak tarafta uygulanacağı garanti edilen yöntemlerin (yöntemler AIDL arayüz açıklamasındayken uzak cihazın derlendiğinden emin olduğunuz için) varsayılan impl
sınıfında geçersiz kılınmasına gerek yoktur.
Mevcut AIDL'yi yapılandırılmış veya kararlı AIDL'ye dönüştürme
Mevcut bir AIDL arayüzünüz ve bu arayüzü kullanan kodunuz varsa arayüzü kararlı bir AIDL arayüzüne dönüştürmek için aşağıdaki adımları uygulayın.
Arayüzünüzün tüm bağımlılıklarını tanımlayın. Arayüzün bağlı olduğu her paket için paketin kararlı AIDL'de tanımlanıp tanımlanmadığını belirleyin. Tanımlanmamışsa paket dönüştürülmelidir.
Arayüzünüzdeki tüm paketlenebilir öğeleri kararlı paketlenebilir öğelere dönüştürün (arayüz dosyalarının kendisi değişmeden kalabilir). Bunu, yapılarını doğrudan AIDL dosyalarında ifade ederek yapabilirsiniz. Yönetim sınıfları, bu yeni türleri kullanacak şekilde yeniden yazılmalıdır. Bu işlem,
aidl_interface
paketi oluşturmadan önce (aşağıda) yapılabilir.Modülünüzün adını, bağımlılıkları ve ihtiyacınız olan diğer bilgileri içeren bir
aidl_interface
paketi (yukarıda açıklandığı gibi) oluşturun. Verilerin sabitlenmesi için (yalnızca yapılandırılmış olması değil) sürümlendirilmesi de gerekir. Daha fazla bilgi için Arayüzlerde sürüm oluşturma bölümüne bakın.