Android 10, AIDL arabirimleri tarafından sağlanan uygulama program arabirimini (API)/uygulama ikili arabirimini (ABI) takip etmenin yeni bir yolu olan kararlı Android Arabirim Tanımlama Dili (AIDL) için destek ekler. Kararlı AIDL, AIDL'den aşağıdaki temel farklılıklara sahiptir:
- Arayüzler, yapı sisteminde
aidl_interfaces
ile tanımlanır. - Arayüzler yalnızca yapılandırılmış veriler içerebilir. İstenen türleri temsil eden parseller, AIDL tanımlarına göre otomatik olarak oluşturulur ve otomatik olarak sıralanır ve sıralanmaz.
- Arabirimler kararlı (geriye dönük uyumlu) olarak bildirilebilir. Bu olduğunda, API'leri AIDL arayüzünün yanındaki bir dosyada izlenir ve sürümlenir.
Bir AIDL arayüzü tanımlama
aidl_interface
tanımı şöyle görünür:
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
: Bir AIDL arabirimini benzersiz şekilde tanımlayan AIDL arabirim modülünün adı. -
srcs
: Arayüzü oluşturan AIDL kaynak dosyalarının listesi.com.acme
paketinde tanımlanan AIDL türüFoo
yolu,<base_path>/com/acme/Foo.aidl
konumunda olmalıdır; burada<base_path>
,Android.bp
bulunduğu dizinle ilgili herhangi bir dizin olabilir. Yukarıdaki örnekte,<base_path>
srcs/aidl
. -
local_include_dir
: Paket adının başladığı yol. Yukarıda açıklanan<base_path>
öğesine karşılık gelir. -
imports
: Bunun kullandığıaidl_interface
modüllerinin listesi. AIDL arabirimlerinizden biri başka biraidl_interface
bir arabirim veya ayrıştırılabilir kullanıyorsa, adını buraya yazın. Bu, en son sürüme atıfta bulunmak için tek başına ad veya belirli bir sürüme atıfta bulunmak için sürüm sonekine sahip ad (örneğin-V1
) olabilir. Sürüm belirleme, Android 12'den beri desteklenmektedir -
versions
: Arayüzünapi_dir
altında dondurulmuş önceki sürümleri, Android 11'den başlayarak,versions
aidl_api/ name
altında dondurulmuştur. Bir arayüzün donmuş versiyonu yoksa, bu belirtilmemeli ve uyumluluk kontrolleri yapılmayacaktır. Bu alan, 13 ve üstü içinversions_with_info
ile değiştirilmiştir. -
versions_with_info
: Her biri donmuş bir sürümün adını ve bu aidl_interface sürümünün içe aktardığı diğer aidl_interface modüllerinin içe aktarılan sürümlerini içeren bir liste içeren demetlerin listesi. Bir AIDL arabirimi IFACE'nin V sürümünün tanımıaidl_api/ IFACE / V
konumunda bulunur. Bu alan Android 13'te tanıtıldı ve doğrudan Android.bp'de değiştirilmesi gerekmiyor. Alan*-update-api
veya*-freeze-api
çağrılarak eklenir veya güncellenir. Ayrıca, bir kullanıcı*-update-api
veya*-freeze-api
çağırdığındaversions
alanları otomatik olarakversions_with_info
taşınır. -
stability
: Bu arayüzün kararlılık taahhüdü için isteğe bağlı bayrak. Şu anda yalnızca"vintf"
desteklemektedir. Bu ayarlanmazsa, bu derleme bağlamı içinde kararlı bir arabirime karşılık gelir (bu nedenle buraya yüklenen bir arabirim yalnızca birlikte derlenen şeylerle kullanılabilir, örneğin system.img'de). Bu,"vintf"
olarak ayarlanırsa, bu bir kararlılık taahhüdüne karşılık gelir: arabirim, kullanıldığı sürece sabit tutulmalıdır. -
gen_trace
: İzlemeyi açmak veya kapatmak için isteğe bağlı bayrak. Varsayılanfalse
. -
host_supported
:true
olarak ayarlandığında, oluşturulan kitaplıkları ana bilgisayar ortamı için kullanılabilir kılan isteğe bağlı bayrak. -
unstable
: Bu arabirimin kararlı olması gerekmediğini belirtmek için kullanılan isteğe bağlı bayrak. Bu,true
olarak ayarlandığında, derleme sistemi arayüz için API dökümü oluşturmaz ve güncellenmesini gerektirmez. -
frozen
:true
olarak ayarlandığında arabirimin önceki arabirim sürümünden bu yana hiçbir değişiklik yapmadığı anlamına gelen isteğe bağlı bayrak. Bu, daha fazla derleme zamanı denetimi sağlar.false
olarak ayarlandığında bu, arayüzün geliştirilmekte olduğu ve yeni değişikliklere sahip olduğu anlamına gelir; bu nedenlefoo-freeze-api
çalıştırılması yeni bir sürüm oluşturacak ve değeri otomatik olaraktrue
olarak değiştirecektir. Android 14'te tanıtıldı (AOSP deneysel). -
backend.<type>.enabled
: Bu bayraklar, AIDL derleyicisinin kod oluşturduğu arka uçların her birini değiştirir. Şu anda dört arka uç desteklenmektedir: 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 varsayılan olarak devre dışıdır. -
backend.<type>.apex_available
: Oluşturulan saplama kitaplığının kullanılabilir olduğu APEX adlarının listesi. -
backend.[cpp|java].gen_log
: İşlem hakkında bilgi toplamak için ek kod oluşturulup oluşturulmayacağını kontrol eden isteğe bağlı bayrak. -
backend.[cpp|java].vndk.enabled
: Bu arabirimi VNDK'nın bir parçası yapmak için isteğe bağlı bayrak. Varsayılanfalse
. -
backend.java.sdk_version
: Java saplama kitaplığının dayandığı SDK sürümünü belirtmek için isteğe bağlı bayrak. Varsayılan"system_current"
şeklindedir. Bu,backend.java.platform_apis
doğru olduğunda ayarlanmamalıdır. -
backend.java.platform_apis
: Oluşturulan kitaplıkların SDK yerine platform API'sine göre oluşturulması gerektiğindetrue
olarak ayarlanması gereken isteğe bağlı bayrak.
Sürümlerin ve etkinleştirilmiş arka uçların her bir kombinasyonu için bir saplama kitaplığı oluşturulur. Belirli bir arka uç için saplama kitaplığının belirli sürümüne nasıl başvurulacağını öğrenmek için bkz . Modül adlandırma kuralları .
AIDL dosyalarını yazma
Kararlı AIDL'deki arabirimler, yapılandırılmamış parsellenebilirleri kullanmalarına izin verilmemesi dışında (çünkü bunlar kararlı değildir!) geleneksel arabirimlere benzer. Kararlı AIDL'deki birincil fark, parsellenebilirlerin nasıl tanımlandığıdır. Daha önce, parseller ileriye dönük olarak beyan ediliyordu ; kararlı AIDL'de, parsellenebilir alanlar ve değişkenler açıkça tanımlanır.
// in a file like 'some/package/Thing.aidl'
package some.package;
parcelable SubThing {
String a = "foo";
int b;
}
Şu anda boolean
, char
, float
, double
, byte
, int
, long
ve String
için bir varsayılan desteklenmektedir (ancak gerekli değildir). Android 12'de, kullanıcı tanımlı numaralandırmalar için varsayılanlar da desteklenir. Bir varsayılan belirtilmediğinde, 0 benzeri veya boş bir değer kullanılır. Varsayılan değeri olmayan numaralandırmalar, sıfır numaralandırıcı olmasa bile 0 olarak başlatılır.
Saplama kitaplıklarını kullanma
Saplama kitaplıklarını modülünüze bağımlılık olarak ekledikten sonra bunları dosyalarınıza dahil edebilirsiniz. Derleme sistemindeki saplama kitaplıklarının örnekleri aşağıda verilmiştir ( Android.mk
, eski modül tanımları için de kullanılabilir):
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: ...,
rust_libs: ["my-module-name-rust"],
...
}
C++'da ö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
Sürüm arayüzleri
Foo adlı bir modülün bildirilmesi, derleme sisteminde modülün API'sini yönetmek için kullanabileceğiniz bir hedef de oluşturur. foo-freeze-api oluşturulduğunda, Android sürümüne bağlı olarak api_dir
veya aidl_api/ name
altına yeni bir API tanımı ekler ve her ikisi de arayüzün yeni dondurulmuş sürümünü temsil eden bir .hash
dosyası ekler. foo-freeze-api ayrıca, ek sürümü ve sürüm için imports
yansıtacak şekilde versions_with_info
özelliğini günceller. Temel olarak, versions_with_info
içindeki imports
imports
alanından kopyalanır. Ancak en son kararlı sürüm, açık bir sürümü olmayan içe aktarma için versions_with_info
imports
belirtilir. versions_with_info
özelliği belirtildikten sonra, yapı sistemi donmuş sürümler arasında ve ayrıca Ağacın Tepesi (ToT) ile en son donmuş sürüm arasında uyumluluk kontrolleri gerçekleştirir.
Ek olarak, ToT sürümünün API tanımını yönetmeniz gerekir. Bir API her güncellendiğinde, ToT sürümünün API tanımını içeren aidl_api/ name /current
güncellemek için foo-update-api'yi çalıştırın.
Bir arabirimin kararlılığını korumak için sahipler yenilerini ekleyebilir:
- Bir arabirimin sonuna kadar olan yöntemler (veya açıkça tanımlanmış yeni serilere sahip yöntemler)
- Bir parsellenebilirin sonuna kadar olan öğeler (her öğe için bir varsayılanın eklenmesini gerektirir)
- sabit değerler
- Android 11'de numaralandırıcılar
- Android 12'de, bir birliğin sonuna kadar olan alanlar
Başka hiçbir eyleme izin verilmez ve başka hiç kimse bir arabirimi değiştiremez (aksi takdirde, sahibin yaptığı değişikliklerle çakışma riskiyle karşı karşıya kalırlar).
Tüm arayüzlerin serbest bırakılmak üzere dondurulduğunu test etmek için, aşağıdaki çevresel değişkenleri ayarlayarak oluşturabilirsiniz:
-
AIDL_FROZEN_REL=true m ...
- yapı,owner:
alanı. -
AIDL_FROZEN_OWNERS="aosp test"
- derleme, tüm kararlı AIDL arabirimlerininowner:
"aosp" veya "test" olarak belirtilen alan.
İthalatın istikrarı
Bir arabirimin donmuş sürümleri için içe aktarma sürümlerinin güncellenmesi, Kararlı AIDL katmanında geriye doğru uyumludur. Ancak bunların güncellenmesi, arayüzün eski sürümünü kullanan tüm sunucuların ve istemcilerin güncellenmesini gerektirir ve bazı uygulamalar, farklı tür sürümlerini karıştırırken karıştırılabilir. Genel olarak, yalnızca türler veya ortak paketler için bu güvenlidir, çünkü IPC işlemlerinden bilinmeyen türleri işlemek için kodun zaten yazılması gerekir.
Android platform kodunda android.hardware.graphics.common
bu tür sürüm yükseltmenin en büyük örneğidir.
Sürümlü arayüzleri kullanma
Arayüz yöntemleri
Çalışma zamanında, eski bir sunucuda yeni yöntemler çağırmaya çalışırken, yeni istemciler arka uca bağlı olarak bir hata veya istisna alır.
-
cpp
arka ucu::android::UNKNOWN_TRANSACTION
alır. -
ndk
arka ucuSTATUS_UNKNOWN_TRANSACTION
alır. -
java
arka ucu, API'nin uygulanmadığını belirten bir mesajlaandroid.os.RemoteException
alır.
Bununla başa çıkma stratejileri için bkz . sürümleri sorgulama ve varsayılanları kullanma .
parseller
Parsellere yeni alanlar eklendiğinde, eski istemciler ve sunucular bunları bırakır. Yeni istemciler ve sunucular eski parsellenebilirleri aldığında, yeni alanlar için varsayılan değerler otomatik olarak doldurulur. Bu, bir parsellenebilirdeki tüm yeni alanlar için varsayılanların belirtilmesi gerektiği anlamına gelir.
İstemciler, sunucunun tanımlanmış alana sahip sürümü uyguladığını bilmedikleri sürece sunucuların yeni alanları kullanmasını beklememelidir ( sürümleri sorgulamaya bakın).
Numaralandırmalar ve sabitler
Benzer şekilde, istemciler ve sunucular, gelecekte daha fazlası eklenebileceğinden, tanınmayan sabit değerleri ve numaralandırıcıları uygun şekilde reddetmeli veya yok saymalıdır. Örneğin, bir sunucu bilmediği bir numaralandırıcı aldığında iptal etmemelidir. Ya görmezden gelmeli ya da müşterinin bu uygulamada desteklenmediğini bilmesi için bir şey döndürmeli.
sendikalar
Alıcı eskiyse ve alan hakkında bilgisi yoksa, yeni bir alanla bir birleşim göndermeye çalışmak başarısız olur. Uygulama, yeni alanla birliği asla görmeyecektir. Tek yönlü bir işlem ise başarısızlık yok sayılır; aksi halde hata BAD_VALUE
(C++ veya NDK arka ucu için) veya IllegalArgumentException
(Java arka ucu için) olur. İstemci yeni alana bir birleşim kümesini eski bir sunucuya gönderiyorsa veya yeni bir sunucudan birliği alan eski bir istemci ise hata alınır.
Modül adlandırma kuralları
Android 11'de, etkinleştirilen sürümlerin ve arka uçların her kombinasyonu için otomatik olarak bir saplama kitaplığı modülü oluşturulur. Bağlanmak üzere belirli bir saplama kitaplığı modülüne başvurmak için aidl_interface
modülünün adını değil, saplama kitaplığı modülünün adını kullanın; ifacename - version - backend burada
-
ifacename
:aidl_interface
modülünün adı -
version
aşağıdakilerden biridir- Dondurulmuş sürümler için
V version-number
- Ağacın ucu (henüz dondurulmamış) sürüm için
V latest-frozen-version-number + 1
- Dondurulmuş sürümler için
-
backend
aşağıdakilerden biridir- Java arka ucu için
java
, - C++ arka ucu için
cpp
, - NDK arka ucu için
ndk
veyandk_platform
. İlki uygulamalar içindir ve ikincisi platform kullanımı içindir, - Rust arka ucu için
rust
.
- Java arka ucu için
foo adında bir modül olduğunu ve en son sürümünün 2 olduğunu ve hem NDK hem de C++'yı desteklediğini varsayalım. Bu durumda, AIDL şu modülleri üretir:
- Versiyon 1'e göre
-
foo-V1-(java|cpp|ndk|ndk_platform|rust)
-
- Sürüm 2'ye göre (en son kararlı sürüm)
-
foo-V2-(java|cpp|ndk|ndk_platform|rust)
-
- ToT versiyonuna göre
-
foo-V3-(java|cpp|ndk|ndk_platform|rust)
-
Android 11 ile karşılaştırıldığında,
- en son kararlı sürüme atıfta bulunan
foo- backend
,foo- V2 - backend
olur - ToT sürümüne atıfta bulunan
foo-unstable- backend
,foo- V3 - backend
olur
Çıktı dosyası adları her zaman modül adlarıyla aynıdır.
- Sürüm 1'e göre:
foo-V1-(cpp|ndk|ndk_platform|rust).so
- Sürüm 2'ye göre:
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, kararlı bir AIDL arabirimi için unstable
bir sürüm modülü veya sürüm bilgisi olmayan 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 birkaç meta arayüz yöntemi ekler.
Uzak nesnenin arabirim sürümünü sorgulama
İstemciler, uzak nesnenin uyguladığı arabirimin sürümünü ve karmasını sorgulayabilir ve döndürülen değerleri, istemcinin kullandığı arabirimin değerleriyle karşılaştırabilir.
cpp
arka ucu ile örnek:
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 ucuyla ilgili ö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 ucu ile örnek:
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 dili için, uzak taraf getInterfaceVersion()
ve getInterfaceHash()
işlevini aşağıdaki gibi UYGULAMALIDIR (kopyalama/yapıştırma hatalarını önlemek için IFoo
yerine super
kullanılır. @SuppressWarnings("static")
ek açıklaması, bağlı olarak uyarıları devre dışı bırakmak için gerekli olabilir. javac
yapılandırması):
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 ve sunucu arasında paylaşılmasıdır (örneğin, sınıflar önyükleme sınıf yolunda olabilir). Sınıflar paylaşıldığında, arayüzün daha eski bir sürümüyle oluşturulmuş olsa bile sunucu, sınıfların en yeni sürümüyle de bağlantılıdır. Bu meta arabirim, paylaşılan sınıfta uygulanırsa, her zaman en yeni sürümü döndürür. Bununla birlikte, yukarıdaki yöntemi uygulayarak, arabirimin sürüm numarası sunucunun koduna gömülür (çünkü IFoo.VERSION
başvurulduğu zaman satır içine alınan static final int
) ve bu nedenle yöntem, sunucunun oluşturulduğu tam sürümü döndürebilir ile.
Eski arayüzlerle ilgilenmek
Bir istemcinin bir AIDL arabiriminin daha yeni sürümüyle güncellenmesi, ancak sunucunun eski AIDL arabirimini kullanması mümkündür. Bu gibi durumlarda, eski bir arabirimde bir yöntemin çağrılması UNKNOWN_TRANSACTION
döndürür.
İstikrarlı AIDL ile istemciler daha fazla kontrole sahip olur. İstemci tarafında, bir AIDL arabirimine varsayılan bir uygulama ayarlayabilirsiniz. Varsayılan uygulamadaki bir yöntem, yalnızca yöntem uzak tarafta uygulanmadığında çağrılır (çünkü arabirimin eski bir sürümüyle oluşturulmuştur). Varsayılanlar genel olarak ayarlandığından, potansiyel olarak paylaşılan bağlamlardan kullanılmamalıdır.
Android 13 ve sonrasında C++ örneği:
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 arabirimindeki tüm yöntemlerin varsayılan uygulamasını sağlamanız gerekmez. Uzak tarafta uygulanması garanti edilen yöntemlerin (çünkü uzaktan kumandanın, yöntemler AIDL arabirim açıklamasındayken oluşturulduğundan eminsiniz) varsayılan impl
sınıfında geçersiz kılınması gerekmez.
Mevcut AIDL'yi yapılandırılmış/kararlı AIDL'ye dönüştürme
Mevcut bir AIDL arayüzünüz ve onu kullanan kodunuz varsa, arayüzü kararlı bir AIDL arayüzüne dönüştürmek için aşağıdaki adımları kullanı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 ayrıştırılabilirleri kararlı ayrıştırılabilir parçalara dönüştürün (arayüz dosyalarının kendileri değişmeden kalabilir). Bunu, yapılarını doğrudan AIDL dosyalarında ifade ederek yapın. Bu yeni türleri kullanmak için yönetim sınıflarının yeniden yazılması gerekir. Bu, bir
aidl_interface
paketi oluşturmadan önce yapılabilir (aşağıda).Modülünüzün adını, bağımlılıklarını ve ihtiyacınız olan diğer bilgileri içeren bir
aidl_interface
paketi (yukarıda açıklandığı gibi) oluşturun. Dengeli hale getirmek için (sadece yapılandırılmış değil), aynı zamanda versiyonlanması gerekir. Daha fazla bilgi için bkz . Sürüm oluşturma arabirimleri .