AIDL arka ucu, saplama kodu oluşturma hedefidir. AIDL dosyalarını kullanırken her zaman belirli bir çalışma zamanında belirli bir dilde kullanın. Şuna bağlı olarak: farklı AIDL arka uçları kullanmanız gerekir.
Aşağıdaki tabloda, API yüzeyinin kararlılığı, müşterinin
Böylece, bu API yüzeyinde kodun gerçekten daha iyi
system.img
libbinder.so
ikili programından bağımsız olarak teslim edilir.
AIDL aşağıdaki arka uçlara sahiptir:
Arka Uç | Dil | API yüzeyi | Bina sistemi |
---|---|---|---|
Java | Java | SDK/SystemApi (kararlı*) | tümü |
NDK | C++ | libbinder_ndk (kararlı*) | aidl_arayüz |
ABM | C++ | libbinder (kararsız) | tümü |
Rust | Rust | libbinder_rs (kararlı*) | aidl_arayüz |
- Bu API yüzeyleri sabittir ancak hizmet için olanlar gibi API'lerin çoğu kullanılabilir. dahili platform kullanımına ayrılmıştır ve kullanıcılar tarafından Uygulamalarda AIDL'yi kullanma hakkında daha fazla bilgi için bkz. geliştirici belgelerini inceleyin.
- Rust arka ucu, Android 12'de kullanıma sunuldu. "the" NDK arka ucu, Android 10 itibarıyla kullanıma sunulmuştur.
- Paslı kasa,
libbinder_ndk
adlı binanın üzerine inşa edilmiştir. Bu da sabit ve taşınabilir olması gerekir. APEX'ler, bağlayıcı kasayı herkes ile aynı şekilde kullanır. olması gerekir. Paslı kısım bir APEX'e paket halinde sunulur ve inceleyeceğiz. Bu, sistem bölümündekilibbinder_ndk.so
değerine bağlıdır.
Bina sistemi
Arka uca bağlı olarak AIDL'yi saplama olarak derlemenin iki yolu vardır girin. Derleme sistemleriyle ilgili daha fazla bilgi için Soong Modülü Referansı.
Çekirdek derleme sistemi
Herhangi bir cc_
veya java_
Android.bp modülünde (veya Android.mk
eşdeğerlerinde)
.aidl
dosyaları kaynak dosya olarak belirtilebilir. Bu örnekte, Java/PBM
AIDL'nin arka uçları kullanılır (NDK arka ucu değil) ve
ilgili AIDL dosyaları modüle otomatik olarak eklenir. Seçenekler
Örneğin local_include_dirs
, derleme sistemine kök yolunu
Söz konusu modüldeki AIDL dosyaları bu modüllerde aidl:
grubu. Rust arka ucunun yalnızca Rust ile kullanıldığını unutmayın. rust_
modül
farklı şekilde işlenir.
Bunun yerine, aidl_interface
modül rustlib
Bağlantı kurulabilecek <aidl_interface name>-rust
. Daha fazla bilgi için bkz.
Rust AIDL örneği.
aidl_arayüz
Bu derleme sistemiyle kullanılan türler yapılandırılmış olmalıdır. Yapılandırılmış olması için parseller doğrudan alanları içermeli ve tür bildirimleri olmamalıdır hedef dillerde tanımlandığını gösterir. Yapılandırılmış AIDL'nin AIDL'nin kararlı çalışması için Yapılandırılmış ve kararlı AIDL başlıklı makaleyi inceleyin.
Türler
aidl
derleyicisini, türler için bir referans uygulaması olarak düşünebilirsiniz.
Arayüz oluşturduğunuzda aidl --lang=<backend> ...
komutunu çağırarak
dosya oluşturma işlemi dahildir. aidl_interface
modülünü kullandığınızda şunları görüntüleyebilirsiniz:
out/soong/.intermediates/<path to module>/
çıktı.
Java/AIDL Türü | C++ Türü | NDK Türü | Pas Türü |
---|---|---|---|
Boole | Bool | Bool | Bool |
bayt | int8_t | int8_t | i8 |
karakter | karakter16_t | karakter16_t | u16 |
int | tam32_t | tam32_t | i32 |
uzun | int64_t | int64_t | i64 |
kayan | kayan | kayan | "f32" |
çift | çift | çift | "f64" |
Dize | android::Dize16 | std::string | Dize |
android.os.Parcelable | android::Parcelable | Yok | Yok |
Bağlayıcı | android::IBinder | ndk::SpAIBinder | binder::SpIBinder |
Tr[] | std::vector<T> | std::vector<T> | Giriş: &[T] Çıkış: Vec<T> |
bayt[] | std::vektör<uint8_t> | std::vector<int8_t>1 | In: &[u8] Dışarıda: Vec<u8> |
Liste<T> | std::vector<T>2 | std::vector<T>3 | İçinde: &[T]4 Dışarıda: Vec<T> |
Dosya Açıklayıcı | android::base::benzersiz_fd | Yok | binder::parcel::ParcelFileDescriptor |
ParcelFileAçıklayıcı | android::os::ParcelFileAçıklayıcı | ndk::ScopedFileDescriptor | binder::parcel::ParcelFileDescriptor |
arayüz türü (T) | android::sp<T> | std::shared_ptr<T>7 | binder::Güçlü |
ayrıştırılabilir türü (T) | T | T | T |
birlik türü (T)5 | T | T | T |
T[N] 6 | std::dizi<T, N> | std::dizi<T, N> | [T; K] |
1. Android 12 veya sonraki sürümlerde bayt dizileri, uint8_t yerine int8_t kullanmanızı öneririz. ziyaret edin.
2. C++ arka ucu List<T>
değerini destekler. T
, String
değerlerinden biridir.
IBinder
, ParcelFileDescriptor
veya ayrıştırılabilir. Android'de
13 veya sonraki bir değer için T
, temel olmayan herhangi bir tür olabilir
(arayüz türleri dahil) içerir. AOSP,
Tüm arka uçlarda çalıştıkları için T[]
gibi dizi türlerini kullanmalıdır.
'nı inceleyin.
3. NDK arka ucu List<T>
destekler. Burada T
, String
değerlerinden biridir.
ParcelFileDescriptor
veya ayrıştırılabilir. Android 13'te
veya daha yüksek değerler T
, diziler hariç herhangi bir primitif olmayan tür olabilir.
'nı inceleyin.
4. Rust kodu için türler, giriş (bağımsız değişken) veya çıkış (döndürülen değer) olabilir.
5. Birlik türleri Android 12 ve sonraki sürümlerde desteklenir daha yüksek olabilir. ziyaret edin.
6. Android 13 veya sonraki sürümlerde sabit boyutlu diziler
desteklenir. Sabit boyutlu dizilerin birden fazla boyutu olabilir (ör. int[3][4]
).
Java arka ucunda, sabit boyutlu diziler, dizi türleri olarak temsil edilir.
'nı inceleyin.
7. SharedRefBase
bağlayıcı nesnesini örneklendirmek için şunu kullanın:
SharedRefBase::make\<My\>(... args ...)
. Bu fonksiyon,
std::shared_ptr\<T\>
nesne
Bağlayıcının başka bir dosyaya ait olması ihtimaline karşı dahili olarak da yönetilir
bahsedeceğim. Nesnenin başka şekillerde oluşturulması iki kat sahipliğe neden olur.
ziyaret edin.
Yön (giriş/çıkış/çıkış)
Fonksiyonların bağımsız değişkenlerini belirtirken,
Bunları in
, out
veya inout
olarak düzenleyebilirsiniz. Bu, yönün bilgisinin hangi yönde
iletilmelidir. in
, varsayılan yöndür ve verilerin doğru yönde
arayandan aranan kişiye aktarılır. out
, verilerin
ona göstermeniz gerekir. inout
, bu ikisinin kombinasyonudur. Ancak
Android ekibi, inout
bağımsız değişken tanımlayıcısını kullanmaktan kaçınmanızı önerir.
inout
öğesini sürümlü bir arayüzle ve daha eski bir çağrıyla kullanıyorsanız
yalnızca arayanda bulunan ek alanlar varsayılan değerlerine sıfırlanır
değerler. Rust ile ilgili olarak normal bir inout
türü &mut Vec<T>
alır ve
inout
türündeki bir liste &mut Vec<T>
alır.
interface IRepeatExamples {
MyParcelable RepeatParcelable(MyParcelable token); // implicitly 'in'
MyParcelable RepeatParcelableWithIn(in MyParcelable token);
void RepeatParcelableWithInAndOut(in MyParcelable param, out MyParcelable result);
void RepeatParcelableWithInOut(inout MyParcelable param);
}
UTF8/UTF16
PBM arka ucuyla dizelerin utf-8 veya utf-16 olmasını seçebilirsiniz. Bildir
dizeleri otomatik olarak utf-8'e dönüştürmek için AIDL'de @utf8InCpp String
olarak kullanın.
NDK ve Rust arka uçları her zaman utf-8 dizelerini kullanır. Daha fazla bilgi için
utf8InCpp
ek açıklaması için AIDL'deki ek açıklamalar bölümüne bakın.
Boş değer atanabilirliği
Java arka ucunda boş olabilecek türlere @nullable
ile not ekleyebilirsiniz
API'yi kullanabilirsiniz. Rust arka ucunda bu
@nullable
tür, Option<T>
olarak gösterilir. Yerel sunucular boş değerleri reddeder
varsayılan olarak. Bunun tek istisnası interface
ve IBinder
türleridir.
Bu değer, NDK okumaları ve CPP/NDK yazmaları için her zaman null olabilir. Okuyucu Gelirleri Yöneticisi'ni
nullable
ek açıklaması hakkında daha fazla bilgi için bkz.
AIDL'deki ek açıklamalar.
Özel parseller
Özel ayrıştırılabilir, hedefte manuel olarak uygulanan bir ayrıştırılabilir öğedir. arka uçta olması gerekir. Özel ayrıştırıcıları yalnızca diğer ürünlere destek eklemeye çalışırken veya değiştirilemeyen mevcut bir özel ayrıştırıcının dilleridir.
AIDL'nin, özel bir parsel hakkında bilgi sahibi olması için ayrıştırılabilir beyannamesi aşağıdaki gibi görünür:
package my.pack.age;
parcelable Foo;
Varsayılan olarak bu, my.pack.age.Foo
değerinin bir Java olduğu bir Java paketi bildirir
Parcelable
arayüzünü uygulayan sınıftır.
AIDL'de ayrıştırılabilir özel PBM arka uç beyanı için cpp_header
kullanın:
package my.pack.age;
parcelable Foo cpp_header "my/pack/age/Foo.h";
my/pack/age/Foo.h
ürünündeki C++ uygulaması şu şekilde görünür:
#include <binder/Parcelable.h>
class MyCustomParcelable : public android::Parcelable {
public:
status_t writeToParcel(Parcel* parcel) const override;
status_t readFromParcel(const Parcel* parcel) override;
std::string toString() const;
friend bool operator==(const MyCustomParcelable& lhs, const MyCustomParcelable& rhs);
friend bool operator!=(const MyCustomParcelable& lhs, const MyCustomParcelable& rhs);
};
AIDL'de özel NDK parsel beyanı için ndk_header
kullanın:
package my.pack.age;
parcelable Foo ndk_header "android/pack/age/Foo.h";
android/pack/age/Foo.h
içindeki NDK uygulaması şöyle görünür:
#include <android/binder_parcel.h>
class MyCustomParcelable {
public:
binder_status_t writeToParcel(AParcel* _Nonnull parcel) const;
binder_status_t readFromParcel(const AParcel* _Nonnull parcel);
std::string toString() const;
friend bool operator==(const MyCustomParcelable& lhs, const MyCustomParcelable& rhs);
friend bool operator!=(const MyCustomParcelable& lhs, const MyCustomParcelable& rhs);
};
Android 15'te (AOSP deneysel), özel Pas beyanı için
AIDL'de ayrıştırılabilir, rust_type
kullanın:
package my.pack.age;
@RustOnlyStableParcelable parcelable Foo rust_type "rust_crate::Foo";
rust_crate/src/lib.rs
için Rust uygulaması aşağıdaki gibi görünür:
use binder::{
binder_impl::{BorrowedParcel, UnstructuredParcelable},
impl_deserialize_for_unstructured_parcelable, impl_serialize_for_unstructured_parcelable,
StatusCode,
};
#[derive(Clone, Debug, Eq, PartialEq)]
struct Foo {
pub bar: String,
}
impl UnstructuredParcelable for Foo {
fn write_to_parcel(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> {
parcel.write(&self.bar)?;
Ok(())
}
fn from_parcel(parcel: &BorrowedParcel) -> Result<Self, StatusCode> {
let bar = parcel.read()?;
Ok(Self { bar })
}
}
impl_deserialize_for_unstructured_parcelable!(Foo);
impl_serialize_for_unstructured_parcelable!(Foo);
Bu ayrıştırıcıyı AIDL dosyalarında bir tür olarak kullanabilirsiniz, ancak
(AIDL tarafından üretilen) PPP/NDK arka ucu için <
ve ==
operatörleri sağlayın
union
içinde kullanmak üzere özel parseller gönderebilirsiniz.
Varsayılan değerler
Yapılandırılmış ayrıştırılabilirler, temel öğeler için alan başına varsayılan değerleri bildirebilir,
String
öğeleri ve bu türlerdeki diziler.
parcelable Foo {
int numField = 42;
String stringField = "string value";
char charValue = 'a';
...
}
Java arka ucunda varsayılan değerler eksik olduğunda alanlar şu şekilde başlatılır:
temel türler için sıfır, primitif olmayan türler için null
değerleri.
Diğer arka uçlarda, alanlar aşağıdaki durumlarda varsayılan ilk kullanıma hazır değerlerle başlatılır:
varsayılan değerler tanımlanmamıştır. Örneğin, C++ arka ucunda String
alanları
boş dize olarak başlatılır, List<T>
alanları ise
boş vector<T>
. @nullable
alanları, boş değer alanları olarak başlatılır.
Hata işleme
Android OS, hizmetlerin raporlama sırasında kullanılacak yerleşik hata türleri sağlar hatalar. Bunlar bağlayıcı tarafından kullanılır ve bir bağlayıcı arayüzüdür. Kullanımları AIDL tanımında açıkça belirtilmiştir ve kullanıcı tanımlı bir durum veya dönüş türü gerektirmez.
Hatalı çıkış parametreleri
AIDL işlevi hata bildirdiğinde işlev başlatılamayabilir veya
çıkış parametrelerini değiştirebilir. Özellikle, çıkış parametreleri
hata, işleme sırasında değil, ayrıştırma sırasında ortaya çıkarken ortaya çıkar
ilişkilidir. Genel olarak, AIDL'den hata alınırken
fonksiyonunun yanı sıra tüm inout
ve out
parametrelerinin yanı sıra döndürülen değeri (yani,
bazı arka uçlarda out
parametresi gibi davranır) normal koşullarda,
süresizdir.
Kullanılacak hata değerleri
Yerleşik hata değerlerinin çoğu tüm AIDL arayüzlerinde kullanılabilir, ancak
özel bir şekilde ele alınıyor. Örneğin, EX_UNSUPPORTED_OPERATION
ve
Hata durumunu açıklarken EX_ILLEGAL_ARGUMENT
kullanılabilir ancak
EX_TRANSACTION_FAILED
,
geliştirmenize yardımcı olur. Daha fazla bilgi için arka uca özgü tanımları kontrol edin
bilgileri gözden geçirin.
AIDL arayüzü,
yerleşik hata türleri varsa onlar, hizmete özgü özel yerleşik hata mesajını
dahil edilmesine olanak tanıyan bir hata
Kullanıcı tarafından tanımlanan. Bu hizmete özgü hatalar genellikle
AIDL arayüzü const int
veya int
destekli enum
olarak ve ayrıştırılmamış
bağlayıcı.
Java'da hatalar, android.os.RemoteException
gibi istisnalarla eşlenir. Örneğin,
hizmete özgü istisnalar, Java, android.os.ServiceSpecificException
kullanıcı tanımlı hatayla birlikte gösterilir.
Android'deki yerel kodda istisnalar kullanılmaz. PBM arka ucu,
android::binder::Status
NDK arka ucu ndk::ScopedAStatus
kullanır. Hepsini
yöntemi, AIDL tarafından oluşturulan bu yapılandırmanın durumunu temsil eden
yöntemidir. Rust arka ucu, NDK ile aynı istisna kodu değerlerini kullanır ancak
önce bu dosyaları yerel Paslanma hatalarına (StatusCode
, ExceptionCode
) dönüştürür
kullanıcıya teslim etmek anlamına gelir. Hizmete özgü hatalar için,
Status
veya ScopedAStatus
, EX_SERVICE_SPECIFIC
ile birlikte
kullanıcı tanımlı hata.
Yerleşik hata türleri aşağıdaki dosyalarda bulunabilir:
Arka Uç | Tanım |
---|---|
Java | android/os/Parcel.java |
ABM | binder/Status.h |
NDK | android/binder_status.h |
Rust | android/binder_status.h |
Çeşitli arka uçları kullanma
Bu talimatlar Android platform koduna özeldir. Bu örneklerde
tanımlanmış tür, my.package.IFoo
. Rust arka ucunun nasıl kullanılacağıyla ilgili talimatlar için
Rust AIDL örneğini inceleyin
Android Rust Desenleri'nde
sayfasını ziyaret edin.
İçe aktarma türleri
Tanımlanan türün arayüz, ayrıştırılabilir veya birleşik olması fark etmeksizin tüm aynısını kullanın:
import my.package.IFoo;
Veya PBM arka ucunda:
#include <my/package/IFoo.h>
Alternatif olarak NDK arka ucunda (ek aidl
ad alanına dikkat edin):
#include <aidl/my/package/IFoo.h>
Veya Rust arka ucunda:
use my_package::aidl::my::package::IFoo;
Java'da iç içe yerleştirilmiş bir türü içe aktarabilseniz de, CPP/NDK arka uçlarında
kök türüne ait üstbilgiyi dahil edin. Örneğin, iç içe yerleştirilmiş bir türü içe aktarırken
my/package/IFoo.aidl
içinde tanımlanan Bar
(IFoo
,
dosyası) kullanıyorsanız PBM arka ucu için <my/package/IFoo.h>
(veya
NDK arka ucu için <aidl/my/package/IFoo.h>
).
Hizmetleri uygulama
Bir hizmeti uygulamak için yerel saplama sınıfından devralmanız gerekir. Bu sınıf bağlayıcı sürücüsünden komutları okur ve kullandığınız yöntemleri yürütür yardımcı olur. Şu şekilde bir AIDL dosyanızın olduğunu düşünün:
package my.package;
interface IFoo {
int doFoo();
}
Java'da şu sınıfı genişletmeniz gerekir:
import my.package.IFoo;
public class MyFoo extends IFoo.Stub {
@Override
int doFoo() { ... }
}
PBM arka ucunda:
#include <my/package/BnFoo.h>
class MyFoo : public my::package::BnFoo {
android::binder::Status doFoo(int32_t* out) override;
}
NDK arka ucunda (ek aidl
ad alanına dikkat edin):
#include <aidl/my/package/BnFoo.h>
class MyFoo : public aidl::my::package::BnFoo {
ndk::ScopedAStatus doFoo(int32_t* out) override;
}
Rust arka ucunda:
use aidl_interface_name::aidl::my::package::IFoo::{BnFoo, IFoo};
use binder;
/// This struct is defined to implement IRemoteService AIDL interface.
pub struct MyFoo;
impl Interface for MyFoo {}
impl IFoo for MyFoo {
fn doFoo(&self) -> binder::Result<()> {
...
Ok(())
}
}
Alternatif olarak eşzamansız Rust sürümlerinde:
use aidl_interface_name::aidl::my::package::IFoo::{BnFoo, IFooAsyncServer};
use binder;
/// This struct is defined to implement IRemoteService AIDL interface.
pub struct MyFoo;
impl Interface for MyFoo {}
#[async_trait]
impl IFooAsyncServer for MyFoo {
async fn doFoo(&self) -> binder::Result<()> {
...
Ok(())
}
}
Kaydolma ve hizmetleri alma
Android platformundaki hizmetler genellikle servicemanager
'e kayıtlıdır.
bahsedeceğim. Aşağıdaki API'lere ek olarak, bazı API'ler
hizmet kullanılamıyorsa (hizmet kullanılamıyorsa hemen geri dönerler).
Tam ayrıntılar için ilgili servicemanager
arayüzünü kontrol edin. Bu
işlemleri yalnızca Android platformuna göre derleme yaparken yapılabilir.
Java'da:
import android.os.ServiceManager;
// registering
ServiceManager.addService("service-name", myService);
// return if service is started now
myService = IFoo.Stub.asInterface(ServiceManager.checkService("service-name"));
// waiting until service comes up (new in Android 11)
myService = IFoo.Stub.asInterface(ServiceManager.waitForService("service-name"));
// waiting for declared (VINTF) service to come up (new in Android 11)
myService = IFoo.Stub.asInterface(ServiceManager.waitForDeclaredService("service-name"));
PBM arka ucunda:
#include <binder/IServiceManager.h>
// registering
defaultServiceManager()->addService(String16("service-name"), myService);
// return if service is started now
status_t err = checkService<IFoo>(String16("service-name"), &myService);
// waiting until service comes up (new in Android 11)
myService = waitForService<IFoo>(String16("service-name"));
// waiting for declared (VINTF) service to come up (new in Android 11)
myService = waitForDeclaredService<IFoo>(String16("service-name"));
NDK arka ucunda (ek aidl
ad alanına dikkat edin):
#include <android/binder_manager.h>
// registering
binder_exception_t err = AServiceManager_addService(myService->asBinder().get(), "service-name");
// return if service is started now
myService = IFoo::fromBinder(ndk::SpAIBinder(AServiceManager_checkService("service-name")));
// is a service declared in the VINTF manifest
// VINTF services have the type in the interface instance name.
bool isDeclared = AServiceManager_isDeclared("android.hardware.light.ILights/default");
// wait until a service is available (if isDeclared or you know it's available)
myService = IFoo::fromBinder(ndk::SpAIBinder(AServiceManager_waitForService("service-name")));
Rust arka ucunda:
use myfoo::MyFoo;
use binder;
use aidl_interface_name::aidl::my::package::IFoo::BnFoo;
fn main() {
binder::ProcessState::start_thread_pool();
// [...]
let my_service = MyFoo;
let my_service_binder = BnFoo::new_binder(
my_service,
BinderFeatures::default(),
);
binder::add_service("myservice", my_service_binder).expect("Failed to register service?");
// Does not return - spawn or perform any work you mean to do before this call.
binder::ProcessState::join_thread_pool()
}
Tek iş parçacıklı çalışma zamanına sahip eşzamansız Rust arka ucunda:
use myfoo::MyFoo;
use binder;
use binder_tokio::TokioRuntime;
use aidl_interface_name::aidl::my::package::IFoo::BnFoo;
#[tokio::main(flavor = "current_thread")]
async fn main() {
binder::ProcessState::start_thread_pool();
// [...]
let my_service = MyFoo;
let my_service_binder = BnFoo::new_async_binder(
my_service,
TokioRuntime(Handle::current()),
BinderFeatures::default(),
);
binder::add_service("myservice", my_service_binder).expect("Failed to register service?");
// Sleeps forever, but does not join the binder threadpool.
// Spawned tasks will run on this thread.
std::future::pending().await
}
Diğer seçenekler arasındaki önemli farklardan biri, önceden aramamızı yapmadığımız
join_thread_pool
eş zamansız Rust ve tek iş parçacıklı bir çalışma zamanı kullanırken. Bu
çünkü Tokio'ya oluşturulan görevleri yürütebileceği bir iş parçacığı vermeniz gerekiyor. İçinde
ana ileti dizisi bu amaca hizmet eder. Oluşturulan tüm görevler
tokio::spawn
, ana iş parçacığında yürütülecek.
Çok iş parçacıklı çalışma zamanına sahip eşzamansız Rust arka ucunda:
use myfoo::MyFoo;
use binder;
use binder_tokio::TokioRuntime;
use aidl_interface_name::aidl::my::package::IFoo::BnFoo;
#[tokio::main(flavor = "multi_thread", worker_threads = 2)]
async fn main() {
binder::ProcessState::start_thread_pool();
// [...]
let my_service = MyFoo;
let my_service_binder = BnFoo::new_async_binder(
my_service,
TokioRuntime(Handle::current()),
BinderFeatures::default(),
);
binder::add_service("myservice", my_service_binder).expect("Failed to register service?");
// Sleep forever.
tokio::task::block_in_place(|| {
binder::ProcessState::join_thread_pool();
});
}
Çok iş parçacıklı Tokio çalışma zamanı sayesinde ortaya çıkan görevler
ileti dizisi. Bu nedenle, ana makinede join_thread_pool
işlevini çağırmak daha mantıklıdır.
ana iş parçacığının sadece boşta olmamasını sağlayın. Görüşmeyi
Eş zamansız bağlamı bırakmak için block_in_place
.
Ölüm bağlantısı
Bağlayıcı barındıran bir hizmet öldüğünde bildirim alma isteğinde bulunabilirsiniz. Bu, geri çağırma proxy'lerinin sızdırılmasını önlemeye veya hata gidermeye yardımcı olabilir. Bu çağrıları bağlayıcı proxy nesnelerinde yapın.
- Java'da
android.os.IBinder::linkToDeath
ifadesini kullanın. - PBM arka ucunda
android::IBinder::linkToDeath
kullanın. - NDK arka ucunda
AIBinder_linkToDeath
kullanın. - Rust arka ucunda bir
DeathRecipient
nesnesi oluşturup şunu çağırın:my_binder.link_to_death(&mut my_death_recipient)
. Not: Geri çağırma,DeathRecipient
tarafından sağlanıyorsa söz konusu nesneyi uzun süre boyunca bildirimleri almak için.
Arayan bilgileri
Çekirdek bağlayıcı çağrısı alırken arayan bilgilerini şurada bulabilirsiniz: API'lerden yararlanabilirsiniz. PID (veya İşlem Kimliği), dosyanın Linux işlem kimliğini işlem gönderen bir işlemdir. UID (veya User-ID), Linux kullanıcı kimliği. Tek yönlü arama alırken çağrı PID'si 0'dır. Zaman bu işlevler, bağlayıcı işlem bağlamı dışında PID ve UID döndürür. bu riskleri azaltmaya yardımcı olur.
Java arka ucunda:
... = Binder.getCallingPid();
... = Binder.getCallingUid();
PBM arka ucunda:
... = IPCThreadState::self()->getCallingPid();
... = IPCThreadState::self()->getCallingUid();
NDK arka ucunda:
... = AIBinder_getCallingPid();
... = AIBinder_getCallingUid();
Rust arka ucunda, arayüzü uygularken aşağıdakileri belirtin (varsayılan olarak ayarlamak yerine):
... = ThreadState::get_calling_pid();
... = ThreadState::get_calling_uid();
Hizmetler için hata raporları ve hata ayıklama API'si
Hata raporları çalıştığında (örneğin, adb bugreport
ile)
bilgi edinerek çeşitli sorunları gidermenize yardımcı olabilir.
AIDL hizmetleri için hata raporları, tüm hizmetlerde dumpsys
ikili programını kullanır
hizmet yöneticisine kaydettirerek bilgilerini
hata raporu oluşturun. Bilgi almak için komut satırında dumpsys
tuşunu da kullanabilirsiniz
dumpsys SERVICE [ARGS]
ile bir hizmetten. C++ ve Java arka uçlarında
ek bağımsız değişkenler kullanarak hizmetlerin dökümün alınma sırasını kontrol edebilir
addService
numaralı telefona. Bir cihazın PID'sini almak için dumpsys --pid SERVICE
kullanabilirsiniz.
hizmetten bahsetmek istiyorum.
Hizmetinize özel çıkış eklemek için dump
ayarını geçersiz kılabilirsiniz.
yöntemini sunucu nesnenizde kullanabilirsiniz (ör. başka herhangi bir IPC yöntemini uyguladığınız gibi)
AIDL dosyasında tanımlanmıştır. Bunu yaparken, döküm işlemini uygulama ile kısıtlamanız gerekir
android.permission.DUMP
iznini etkinleştirin veya döküm işlemini belirli UID'lerle kısıtlayın.
Java arka ucunda:
@Override
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
@Nullable String[] args) {...}
PBM arka ucunda:
status_t dump(int, const android::android::Vector<android::String16>&) override;
NDK arka ucunda:
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
Rust arka ucunda, arayüzü uygularken aşağıdakileri belirtin (varsayılan olarak ayarlamak yerine):
fn dump(&self, mut file: &File, args: &[&CStr]) -> binder::Result<()>
Arayüz açıklayıcıyı dinamik olarak al
Arayüz tanımlayıcısı, bir arayüzün türünü tanımlar. Faydalı sırasında hata ayıklama sırasında veya bilinmeyen bir bağlayıcı olduğunda görebilirsiniz.
Java'da, arayüz tanımlayıcısını aşağıdaki gibi bir kodla alabilirsiniz:
service = /* get ahold of service object */
... = service.asBinder().getInterfaceDescriptor();
PBM arka ucunda:
service = /* get ahold of service object */
... = IInterface::asBinder(service)->getInterfaceDescriptor();
NDK ve Rust arka uçları bu özelliği desteklemez.
Arayüz açıklayıcısını statik olarak al
Bazen (ör. @VintfStability
hizmetlerini kaydettirirken)
arayüz tanımlayıcısının statik olarak ne olduğunu bilmek önemlidir. Java'da,
açıklayıcıya aşağıdaki gibi bir kod ekleyin:
import my.package.IFoo;
... IFoo.DESCRIPTOR
PBM arka ucunda:
#include <my/package/BnFoo.h>
... my::package::BnFoo::descriptor
NDK arka ucunda (ek aidl
ad alanına dikkat edin):
#include <aidl/my/package/BnFoo.h>
... aidl::my::package::BnFoo::descriptor
Rust arka ucunda:
aidl::my::package::BnFoo::get_descriptor()
Sıralama aralığı
Yerel arka uçlarda, bir enum'un alabileceği olası değerleri yineleyebilirsiniz. beklemeye gerek yoktur. Bu işlem, kod boyutuyla ilgili nedenlerden dolayı Java'da desteklenmemektedir.
AIDL'de tanımlanan bir sıralama MyEnum
için yineleme aşağıdaki gibi sağlanır.
PBM arka ucunda:
::android::enum_range<MyEnum>()
NDK arka ucunda:
::ndk::enum_range<MyEnum>()
Rust arka ucunda:
MyEnum::enum_values()
İleti dizisi yönetimi
Bir işlemdeki her libbinder
örneği bir iş parçacığı havuzuna sahiptir. Çoğu
kullanım alanlarında bu, tüm arka uçlar arasında paylaşılan tam olarak bir iş parçacığı havuzu olmalıdır.
Tek istisna, tedarikçi kodunun libbinder
dokümanının başka bir kopyasını yükleyebilmesidir
/dev/vndbinder
ile konuşmak için. Bu, ayrı bir bağlayıcı düğümde olduğu için
ileti dizisi paylaşılmıyor.
Java arka ucu için iş parçacığının boyutu yalnızca zaten başladı):
BinderInternal.setMaxThreads(<new larger value>);
PBM arka ucu için aşağıdaki işlemler kullanılabilir:
// set max threadpool count (default is 15)
status_t err = ProcessState::self()->setThreadPoolMaxThreadCount(numThreads);
// create threadpool
ProcessState::self()->startThreadPool();
// add current thread to threadpool (adds thread to max thread count)
IPCThreadState::self()->joinThreadPool();
Benzer şekilde, NDK arka ucunda:
bool success = ABinderProcess_setThreadPoolMaxThreadCount(numThreads);
ABinderProcess_startThreadPool();
ABinderProcess_joinThreadPool();
Rust arka ucunda:
binder::ProcessState::start_thread_pool();
binder::add_service("myservice", my_service_binder).expect("Failed to register service?");
binder::ProcessState::join_thread_pool();
Eş zamansız Rust arka ucunda iki iş parçacığı (iş parçacığı) kullanmanız gerekir: bağlayıcı ve Tokio.
Bu nedenle, eşzamansız Rust kullanan uygulamalar için
dikkat edilmesi gereken bazı özel noktalar vardır.
özellikle de join_thread_pool
kullanımı söz konusu. Bu konu hakkında daha fazla bilgi
hizmet kaydetme başlıklı makaleye göz atın.
Ayrılmış adlar
C++, Java ve Rust bazı adları anahtar kelime olarak veya dile özgü öğeler için
pek de iyi olmadığını unutmayın. AIDL dil kurallarına dayalı kısıtlamalar uygulamasa da
ayrılmış bir adla eşleşen alan veya tür adları bir derlemeyle sonuçlanabilir
başarısız oldu. Rust için, alan veya tür
"ham tanımlayıcı" söz dizimini kullanmalıdır. r#
öneki ile erişilebilir.
AIDL tanımlarınızda ayrılmış adlar kullanmaktan kaçınmanızı öneririz mümkün olduğunca fazla kod üretmenize olanak tanır.
AIDL tanımlarınızda zaten ayrılmış adlarınız varsa güvenli bir şekilde Protokol uyumlu kalarak alanları yeniden adlandırın; mevcut hesabınızı güncellemeniz gerekebilir kodlarla devam eder, ancak önceden geliştirilmiş programlar da birlikte çalışabilir.
Kaçınılması gereken adlar: