خلفيات AIDL

تنظيم صفحاتك في مجموعات يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.

تعد الواجهة الخلفية لـ AIDL هدفًا لإنشاء كود كعب الروتين. عند استخدام ملفات AIDL ، فأنت تستخدمها دائمًا بلغة معينة مع وقت تشغيل محدد. اعتمادًا على السياق ، يجب عليك استخدام خلفيات AIDL مختلفة.

AIDL لديه الخلفيات التالية:

الخلفية لغة سطح API بناء الأنظمة
جافا جافا SDK / SystemApi (مستقر *) الكل
NDK C ++ libbinder_ndk (مستقر *) واجهة المساعد
CPP C ++ libbinder (غير مستقر) الكل
الصدأ الصدأ libbinder_rs (غير مستقر) واجهة المساعد
  • أسطح API هذه مستقرة ، ولكن العديد من واجهات برمجة التطبيقات ، مثل تلك الخاصة بإدارة الخدمة ، محجوزة لاستخدام النظام الأساسي الداخلي وليست متاحة للتطبيقات. لمزيد من المعلومات حول كيفية استخدام AIDL في التطبيقات ، راجع وثائق المطور .
  • تم تقديم Rust backend في Android 12 ؛ كانت الواجهة الخلفية NDK متاحة اعتبارًا من Android 10.
  • تم بناء صندوق الصدأ فوق libbinder_ndk . يستخدم APEXes صندوق الموثق بنفس الطريقة التي يستخدمها أي شخص آخر على جانب النظام. يتم تجميع جزء الصدأ في APEX ويتم شحنه بداخله. يعتمد ذلك على libbinder_ndk.so على قسم النظام.

بناء الأنظمة

اعتمادًا على الخلفية ، هناك طريقتان لتجميع AIDL في كود كعب الروتين. لمزيد من التفاصيل حول أنظمة الإنشاء ، راجع مرجع وحدة Soong .

نظام البناء الأساسي

في أي cc_ أو java_ Android.bp (أو في معادلاتها Android.mk ) ، يمكن تحديد ملفات .aidl كملفات مصدر. في هذه الحالة ، يتم استخدام الواجهات الخلفية لـ Java / CPP لـ AIDL (وليس الخلفية NDK) ، ويتم إضافة الفئات التي تستخدم ملفات AIDL المقابلة إلى الوحدة تلقائيًا. يمكن تحديد خيارات مثل local_include_dirs ، التي تخبر نظام الإنشاء مسار الجذر لملفات AIDL في تلك الوحدة النمطية في هذه الوحدات ضمن aidl: group. لاحظ أن الواجهة الخلفية Rust مخصصة للاستخدام مع Rust فقط. يتم التعامل مع وحدات rust_ بشكل مختلف حيث لم يتم تحديد ملفات AIDL كملفات مصدر. بدلاً من ذلك ، تنتج الوحدة النمطية aidl_interface عنصرًا rustlib يسمى <aidl_interface name>-rust والذي يمكن ربطه. لمزيد من التفاصيل ، راجع مثال Rust AIDL .

واجهة المساعد

انظر AIDL المستقر . يجب هيكلة الأنواع المستخدمة مع نظام البناء هذا ؛ وهذا معبر عنه في AIDL مباشرة. هذا يعني أنه لا يمكن استخدام الطرود المخصصة.

أنواع

يمكنك اعتبار مترجم aidl كتطبيق مرجعي للأنواع. عند إنشاء واجهة ، قم باستدعاء aidl --lang=<backend> ... لمشاهدة ملف الواجهة الناتج. عند استخدام وحدة aidl_interface ، يمكنك عرض الإخراج في out/soong/.intermediates/<path to module>/ .

جافا / نوع AIDL نوع C ++ نوع NDK نوع الصدأ
قيمة منطقية منطقي منطقي منطقي
بايت int8_t int8_t i8
شار char16_t char16_t u16
int int32_t int32_t i32
طويل int64_t int64_t i64
يطفو يطفو يطفو f32
مزدوج مزدوج مزدوج f64
سلسلة android :: String16 الأمراض المنقولة جنسيا :: سلسلة سلسلة
android.os.Parcelable android :: Parcelable غير متاح غير متاح
آي بيندر android :: IBinder ndk :: SpAIBinder الموثق :: SpIBinder
تي [] الأمراض المنقولة جنسيا :: متجه <T> الأمراض المنقولة جنسيا :: متجه <T> في: & [T]
خارج: Vec <T>
بايت [] الأمراض المنقولة جنسيا :: متجه <uint8_t> الأمراض المنقولة جنسياً :: المتجه <int8_t> 1 في: & [u8]
خارج: Vec <u8>
قائمة <T> الأمراض المنقولة جنسياً :: متجه <T> 2 الأمراض المنقولة جنسيا :: متجه <T> 3 في: & [T] 4
خارج: Vec <T>
واصف الملف android :: base :: unique_fd غير متاح الموثق :: parcel :: ParcelFileDescriptor
ParcelFileDescriptor android :: os :: ParcelFileDescriptor ndk :: ScopedFileDescriptor الموثق :: parcel :: ParcelFileDescriptor
نوع الواجهة (T) android :: sp <T> الأمراض المنقولة جنسيا :: shared_ptr <T> الموثق :: قوي
نوع لا يتجزأ (T) تي تي تي
نوع الاتحاد (T) 5 تي تي تي
T [N] 6 الأمراض المنقولة جنسيا :: مجموعة <T ، N> الأمراض المنقولة جنسيا :: مجموعة <T ، N> [تي ؛ ن]

1. في Android 12 أو إصدار أحدث ، تستخدم مصفوفات البايت uint8_t بدلاً من int8_t لأسباب تتعلق بالتوافق.

2. تدعم الواجهة الخلفية C ++ List<T> حيث تكون T واحدة من String أو IBinder أو ParcelFileDescriptor أو لا يتجزأ. في Android 13 أو أعلى ، يمكن أن يكون T أي نوع غير بدائي (بما في ذلك أنواع الواجهة) باستثناء المصفوفات. توصي AOSP باستخدام أنواع مصفوفة مثل T[] ، لأنها تعمل في جميع الخلفيات.

3. تدعم الواجهة الخلفية NDK List<T> حيث تكون T واحدة من String أو ParcelFileDescriptor أو لا يتجزأ. في Android 13 أو أعلى ، يمكن أن يكون T أي نوع غير بدائي باستثناء المصفوفات.

4. يتم تمرير الأنواع بشكل مختلف لرمز Rust اعتمادًا على ما إذا كانت مدخلات (وسيطة) ، أو مخرجات (قيمة تم إرجاعها).

5. أنواع الاتحاد مدعومة في Android 12 والإصدارات الأحدث.

6. في Android 13 أو أعلى ، يتم دعم المصفوفات ذات الحجم الثابت. يمكن أن تحتوي المصفوفات ذات الحجم الثابت على أبعاد متعددة (على سبيل المثال int[3][4] ). في الواجهة الخلفية لـ Java ، يتم تمثيل المصفوفات ذات الحجم الثابت كأنواع مصفوفة.

الاتجاهية (الداخل / الخارج / الداخل)

عند تحديد أنواع الوسيطات الخاصة بالدوال ، يمكنك تحديدها كما in الداخل أو out أو inout . يتحكم هذا في تحديد معلومات الاتجاه التي يتم تمريرها لمكالمة IPC. in هو الاتجاه الافتراضي ، ويشير إلى أن البيانات يتم تمريرها من المتصل إلى المستدعي. out يعني أن البيانات يتم تمريرها من المستدعى إلى المتصل. inout هو مزيج من كلاهما. ومع ذلك ، يوصي فريق Android بتجنب استخدام محدد الوسيطة inout . إذا كنت تستخدم inout مع واجهة ذات إصدار ومستدعي أقدم ، فسيتم إعادة تعيين الحقول الإضافية الموجودة فقط في المتصل إلى قيمها الافتراضية. فيما يتعلق بالصدأ ، يتلقى نوع inout العادي &mut Vec<T> ، ويستقبل نوع القائمة inout &mut Vec<T> .

UTF8 / UTF16

باستخدام الواجهة الخلفية لـ CPP ، يمكنك اختيار ما إذا كانت السلاسل هي utf-8 أو utf-16. قم بتعريف السلاسل على أنها @utf8InCpp String في AIDL لتحويلها تلقائيًا إلى utf-8. تستخدم الخلفيات NDK و Rust دائمًا سلاسل utf-8. لمزيد من المعلومات حول التعليق التوضيحي utf8InCpp ، راجع التعليقات التوضيحية في AIDL .

بطلان

يمكنك إضافة تعليق توضيحي على الأنواع التي يمكن أن تكون خالية في الواجهة الخلفية لـ Java باستخدام @nullable لفضح القيم الفارغة للخلفيات الخلفية CPP و NDK. في الواجهة الخلفية Rust ، يتم عرض هذه الأنواع @nullable كخيار Option<T> . ترفض الخوادم الأصلية القيم الخالية افتراضيًا. الاستثناءات الوحيدة لذلك هي أنواع interface وأنواع IBinder ، والتي يمكن أن تكون دائمًا خالية لقراءات NDK وكتب CPP / NDK. لمزيد من المعلومات حول التعليق التوضيحي nullable ، راجع التعليقات التوضيحية في AIDL .

الطرود المخصصة

في خلفيات C ++ و Java الخلفية في نظام البناء الأساسي ، يمكنك إعلان عنصر لا يتجزأ يتم تنفيذه يدويًا في الخلفية المستهدفة (في C ++ أو في Java).

    package my.package;
    parcelable Foo;

أو مع إعلان رأس C ++:

    package my.package;
    parcelable Foo cpp_header "my/package/Foo.h";

بعد ذلك ، يمكنك استخدام هذا الجزء القابل للتجزئة كنوع في ملفات AIDL ، لكن لن يتم إنشاؤه بواسطة AIDL.

الصدأ لا يدعم الطرود المخصصة.

قيم افتراضية

يمكن أن تعلن العناصر المركبة الهيكلية عن القيم الافتراضية لكل حقل للأولويات والسلسلة String من هذه الأنواع.

    parcelable Foo {
      int numField = 42;
      String stringField = "string value";
      char charValue = 'a';
      ...
    }

في الواجهة الخلفية لـ Java عندما تكون القيم الافتراضية مفقودة ، تتم تهيئة الحقول كقيم صفرية للأنواع الأولية null للأنواع غير الأولية.

في الخلفيات الأخرى ، تتم تهيئة الحقول بقيم افتراضية تم تهيئتها عندما لا يتم تحديد القيم الافتراضية. على سبيل المثال ، في الواجهة الخلفية لـ C ++ ، تتم تهيئة حقول String كسلسلة فارغة ويتم تهيئة حقول List<T> vector<T> . يتم تهيئة الحقول @nullable كحقول ذات قيمة خالية.

معالجة الأخطاء

يوفر نظام التشغيل Android أنواع أخطاء مضمنة للخدمات لاستخدامها عند الإبلاغ عن الأخطاء. يتم استخدامها بواسطة Binder ويمكن استخدامها من قبل أي خدمات تقوم بتنفيذ واجهة Binder. تم توثيق استخدامها جيدًا في تعريف AIDL ولا تتطلب أي حالة محددة من قبل المستخدم أو نوع إرجاع.

معلمات الإخراج مع وجود أخطاء

عندما تبلغ دالة AIDL عن خطأ ، قد لا تقوم الوظيفة بتهيئة معلمات الإخراج أو تعديلها. على وجه التحديد ، يمكن تعديل معلمات الإخراج في حالة حدوث الخطأ أثناء عدم التنازل بدلاً من حدوثه أثناء معالجة المعاملة نفسها. بشكل عام ، عند الحصول على خطأ من دالة inout ، يجب اعتبار out المعلمات الداخلة والخارجة بالإضافة إلى قيمة الإرجاع (التي تعمل كمعامل out في بعض الخلفيات الخلفية) في حالة غير محددة.

قيم الخطأ التي يجب استخدامها

يمكن استخدام العديد من قيم الخطأ المضمنة في أي واجهات AIDL ، ولكن يتم التعامل مع بعضها بطريقة خاصة. على سبيل المثال ، لا بأس من استخدام EX_UNSUPPORTED_OPERATION و EX_ILLEGAL_ARGUMENT عندما يصفان حالة الخطأ ، ولكن يجب عدم استخدام EX_TRANSACTION_FAILED نظرًا لأنه يتم التعامل معها بشكل خاص من خلال البنية التحتية الأساسية. تحقق من تعريفات الواجهة الخلفية المحددة لمزيد من المعلومات حول هذه القيم المضمنة.

إذا كانت واجهة AIDL تتطلب قيم خطأ إضافية لا تغطيها أنواع الأخطاء المضمنة ، فقد يستخدمون الخطأ المدمج الخاص بالخدمة والذي يسمح بإدراج قيمة خطأ خاصة بالخدمة يحددها المستخدم . يتم تعريف هذه الأخطاء الخاصة بالخدمة عادةً في واجهة AIDL على أنها عدد ثابت أو enum const int int ولا يتم تحليلها بواسطة الموثق.

في Java ، يتم تعيين الأخطاء للاستثناءات ، مثل android.os.RemoteException . بالنسبة للاستثناءات الخاصة بالخدمة ، تستخدم Java android.os.ServiceSpecificException جنبًا إلى جنب مع الخطأ المحدد من قبل المستخدم.

لا يستخدم الكود الأصلي في Android استثناءات. تستخدم الواجهة الخلفية CPP android::binder::Status . تستخدم الواجهة الخلفية NDK ndk::ScopedAStatus . كل طريقة تم إنشاؤها بواسطة AIDL ترجع واحدة من هذه ، والتي تمثل حالة الطريقة. تستخدم الواجهة الخلفية Rust نفس قيم رمز الاستثناء مثل NDK ، ولكنها تحولها إلى أخطاء Rust أصلية ( StatusCode ، ExceptionCode ) قبل تسليمها إلى المستخدم. بالنسبة للأخطاء الخاصة بالخدمة ، تستخدم الحالة التي تم إرجاعها أو Status ScopedAStatus EX_SERVICE_SPECIFIC جنبًا إلى جنب مع الخطأ المحدد من قبل المستخدم.

يمكن العثور على أنواع الأخطاء المضمنة في الملفات التالية:

الخلفية تعريف
جافا android/os/Parcel.java
CPP binder/Status.h
NDK android/binder_status.h
الصدأ android/binder_status.h

استخدام خلفيات مختلفة

هذه التعليمات خاصة برمز نظام Android الأساسي. تستخدم هذه الأمثلة نوعًا محددًا ، my.package.IFoo . للحصول على إرشادات حول كيفية استخدام واجهة Rust الخلفية ، راجع مثال Rust AIDL في صفحة Android Rust Patterns .

استيراد الأنواع

سواء كان النوع المحدد واجهة أم لا يتجزأ أم اتحادًا ، يمكنك استيراده في Java:

import my.package.IFoo;

أو في الخلفية CPP:

#include <my/package/IFoo.h>

أو في NDK الخلفية (لاحظ مساحة الاسم الإضافية aidl ):

#include <aidl/my/package/IFoo.h>

أو في الواجهة الخلفية Rust:

use my_package::aidl::my::package::IFoo;

على الرغم من أنه يمكنك استيراد نوع متداخل في Java ، إلا أنه في الواجهات الخلفية CPP / NDK ، يجب عليك تضمين الرأس لنوع الجذر الخاص به. على سبيل المثال ، عند استيراد Bar من النوع المتداخل محدد في my/package/IFoo.aidl ( IFoo هو نوع الجذر للملف) ، يجب عليك تضمين <my/package/IFoo.h> للواجهة الخلفية CPP (أو <aidl/my/package/IFoo.h> NDK).

تنفيذ الخدمات

لتنفيذ خدمة ، يجب أن ترث من فئة كعب الروتين الأصلي. يقرأ هذا الفصل الأوامر من برنامج تشغيل الموثق وينفذ الأساليب التي تقوم بتنفيذها. تخيل أن لديك ملف AIDL مثل هذا:

    package my.package;
    interface IFoo {
        int doFoo();
    }

في Java ، يجب أن تمتد من هذه الفئة:

    import my.package.IFoo;
    public class MyFoo extends IFoo.Stub {
        @Override
        int doFoo() { ... }
    }

في الخلفية CPP:

    #include <my/package/BnFoo.h>
    class MyFoo : public my::package::BnFoo {
        android::binder::Status doFoo(int32_t* out) override;
    }

في NDK الخلفية (لاحظ مساحة الاسم الإضافية aidl ):

    #include <aidl/my/package/BnFoo.h>
    class MyFoo : public aidl::my::package::BnFoo {
        ndk::ScopedAStatus doFoo(int32_t* out) override;
    }

في الواجهة الخلفية Rust:

    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(())
        }
    }

التسجيل والحصول على الخدمات

عادة ما يتم تسجيل الخدمات في النظام الأساسي Android في عملية مدير servicemanager . بالإضافة إلى واجهات برمجة التطبيقات أدناه ، تتحقق بعض واجهات برمجة التطبيقات من الخدمة (مما يعني أنها تعود على الفور إذا لم تكن الخدمة متاحة). تحقق من واجهة مدير servicemanager المقابلة للحصول على التفاصيل الدقيقة. لا يمكن إجراء هذه العمليات إلا عند التجميع باستخدام نظام Android الأساسي.

في جافا:

    import android.os.ServiceManager;
    // registering
    ServiceManager.addService("service-name", myService);
    // getting
    myService = IFoo.Stub.asInterface(ServiceManager.getService("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"));

في الخلفية CPP:

    #include <binder/IServiceManager.h>
    // registering
    defaultServiceManager()->addService(String16("service-name"), myService);
    // getting
    status_t err = getService<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 الخلفية (لاحظ مساحة الاسم الإضافية aidl ):

    #include <android/binder_manager.h>
    // registering
    status_t err = AServiceManager_addService(myService->asBinder().get(), "service-name");
    // getting
    myService = IFoo::fromBinder(SpAIBinder(AServiceManager_getService("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(SpAIBinder(AServiceManager_waitForService("service-name")));

في الواجهة الخلفية Rust:

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()
}

يمكنك طلب الحصول على إشعار عند وفاة خدمة استضافة الموثق. يمكن أن يساعد ذلك في تجنب تسريب وكلاء رد الاتصال أو المساعدة في استعادة الأخطاء. قم بإجراء هذه المكالمات على كائنات وكيل الموثق.

  • في Java ، استخدم android.os.IBinder::linkToDeath .
  • في الواجهة الخلفية CPP ، استخدم android::IBinder::linkToDeath .
  • في NDK الخلفية ، استخدم AIBinder_linkToDeath .
  • في الواجهة الخلفية Rust ، أنشئ كائن DeathRecipient ، ثم اتصل my_binder.link_to_death(&mut my_death_recipient) . لاحظ أنه نظرًا لأن DeathRecipient يمتلك رد الاتصال ، يجب أن تبقي هذا الكائن حيًا طالما أنك تريد تلقي الإشعارات.

معلومات المتصل

عند تلقي مكالمة kernel Binder ، تتوفر معلومات المتصل في العديد من واجهات برمجة التطبيقات. يشير PID (أو معرف العملية) إلى معرف عملية Linux للعملية التي ترسل المعاملة. يشير UID (أو معرف المستخدم) إلى معرف مستخدم Linux. عند تلقي مكالمة في الطريق ، يكون PID المستدعي هو 0. عندما تكون خارج سياق معاملة Binder ، تقوم هذه الوظائف بإرجاع PID و UID للعملية الحالية.

في الواجهة الخلفية لـ Java:

    ... = Binder.getCallingPid();
    ... = Binder.getCallingUid();

في الخلفية CPP:

    ... = IPCThreadState::self()->getCallingPid();
    ... = IPCThreadState::self()->getCallingUid();

في الخلفية NDK:

    ... = AIBinder_getCallingPid();
    ... = AIBinder_getCallingUid();

في الواجهة الخلفية Rust ، عند تنفيذ الواجهة ، حدد ما يلي (بدلاً من السماح لها بالتعيين الافتراضي):

    ... = ThreadState::get_calling_pid();
    ... = ThreadState::get_calling_uid();

تقارير الأخطاء وتصحيح أخطاء API للخدمات

عند تشغيل تقارير الأخطاء (على سبيل المثال ، مع adb bugreport ) ، فإنها تجمع المعلومات من جميع أنحاء النظام للمساعدة في تصحيح المشكلات المختلفة. بالنسبة لخدمات dumpsys ، تستخدم تقارير الأخطاء عمليات التفريغ الثنائية في جميع الخدمات المسجلة لدى مدير الخدمة لتفريغ معلوماتها في تقرير الأخطاء. يمكنك أيضًا استخدام dumpsys في سطر الأوامر للحصول على معلومات من خدمة مع خدمة dumpsys SERVICE [ARGS] . في الخلفيات C ++ و Java ، يمكنك التحكم في الترتيب الذي يتم به إغراق الخدمات باستخدام وسيطات إضافية addService . يمكنك أيضًا استخدام dumpsys --pid SERVICE للحصول على معرف المنتج للخدمة أثناء التصحيح.

لإضافة مخرجات مخصصة إلى خدمتك ، يمكنك تجاوز طريقة dump في كائن الخادم الخاص بك كما لو كنت تقوم بتنفيذ أي طريقة IPC أخرى محددة في ملف AIDL. عند القيام بذلك ، يجب عليك تقييد الإغراق على إذن التطبيق android.permission.DUMP أو تقييد الإغراق على معرّفات UID محددة.

في الواجهة الخلفية لـ Java:

    @Override
    protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
        @Nullable String[] args) {...}

في الخلفية CPP:

    status_t dump(int, const android::android::Vector<android::String16>&) override;

في الخلفية NDK:

    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;

في الواجهة الخلفية Rust ، عند تنفيذ الواجهة ، حدد ما يلي (بدلاً من السماح لها بالتعيين الافتراضي):

    fn dump(&self, mut file: &File, args: &[&CStr]) -> binder::Result<()>

ديناميكي الحصول على واصف الواجهة

يحدد واصف الواجهة نوع الواجهة. هذا مفيد عند التصحيح أو عندما يكون لديك رابط غير معروف.

في Java ، يمكنك الحصول على واصف الواجهة برمز مثل:

    service = /* get ahold of service object */
    ... = service.asBinder().getInterfaceDescriptor();

في الخلفية CPP:

    service = /* get ahold of service object */
    ... = IInterface::asBinder(service)->getInterfaceDescriptor();

لا تدعم الخلفيات NDK و Rust هذه الوظيفة.

الحصول على واصف الواجهة بشكل ثابت

في بعض الأحيان (مثل تسجيل خدمات @VintfStability ) ، تحتاج إلى معرفة واصف الواجهة بشكل ثابت. في Java ، يمكنك الحصول على الواصف عن طريق إضافة كود مثل:

    import my.package.IFoo;
    ... IFoo.DESCRIPTOR

في الخلفية CPP:

    #include <my/package/BnFoo.h>
    ... my::package::BnFoo::descriptor

في NDK الخلفية (لاحظ مساحة الاسم الإضافية aidl ):

    #include <aidl/my/package/BnFoo.h>
    ... aidl::my::package::BnFoo::descriptor

في الواجهة الخلفية Rust:

    aidl::my::package::BnFoo::get_descriptor()

نطاق التعداد

في الخلفيات الأصلية ، يمكنك تكرار القيم المحتملة التي يمكن أن يتخذها التعداد. نظرًا لاعتبارات حجم الكود ، فإن هذا غير مدعوم في Java حاليًا.

بالنسبة MyEnum المحدد في AIDL ، يتم توفير التكرار على النحو التالي.

في الخلفية CPP:

    ::android::enum_range<MyEnum>()

في الخلفية NDK:

   ::ndk::enum_range<MyEnum>()

في الواجهة الخلفية Rust:

    MyEnum::enum_range()

إدارة الخيط

كل مثيل من libbinder في عملية تحافظ على ترابط واحد. بالنسبة لمعظم حالات الاستخدام ، يجب أن تكون مجموعة سلاسل محادثات واحدة بالضبط ، يتم مشاركتها عبر جميع الواجهات الخلفية. الاستثناء الوحيد لذلك هو عندما يقوم رمز البائع بتحميل نسخة أخرى من libbinder للتحدث إلى /dev/vndbinder . نظرًا لأن هذا موجود على عقدة رابط منفصلة ، لا تتم مشاركة مجموعة مؤشرات الترابط.

بالنسبة للواجهة الخلفية لجافا ، يمكن أن يزيد حجم مجموعة سلاسل العمليات (حيث أنها بدأت بالفعل):

    BinderInternal.setMaxThreads(<new larger value>);

بالنسبة للواجهة الخلفية CPP ، تتوفر العمليات التالية:

    // 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();

وبالمثل ، في الخلفية NDK:

    bool success = ABinderProcess_setThreadPoolMaxThreadCount(numThreads);
    ABinderProcess_startThreadPool();
    ABinderProcess_joinThreadPool();

في الواجهة الخلفية Rust:

    binder::ProcessState::start_thread_pool();
    binder::add_service(“myservice”, my_service_binder).expect(“Failed to register service?”);
    binder::ProcessState::join_thread_pool();

الأسماء المحجوزة

تحتفظ C ++ و Java و Rust ببعض الأسماء ككلمات رئيسية أو لاستخدام لغة معينة. بينما لا يفرض AIDL قيودًا استنادًا إلى قواعد اللغة ، فإن استخدام أسماء الحقول أو الأنواع التي تتطابق مع اسم محجوز قد يؤدي إلى فشل تجميع لـ C ++ أو Java. بالنسبة إلى Rust ، تتم إعادة تسمية الحقل أو النوع باستخدام بناء جملة "المعرف الخام" ، ويمكن الوصول إليه باستخدام البادئة r# .

نوصي بتجنب استخدام الأسماء المحجوزة في تعريفات AIDL الخاصة بك حيثما أمكن لتجنب الارتباطات غير المريحة أو الفشل التام في الترجمة.

إذا كان لديك بالفعل أسماء محجوزة في تعريفات AIDL الخاصة بك ، فيمكنك إعادة تسمية الحقول بأمان بينما تظل متوافقًا مع البروتوكول ؛ قد تحتاج إلى تحديث التعليمات البرمجية الخاصة بك لمواصلة البناء ، ولكن أي برامج تم إنشاؤها بالفعل ستستمر في العمل البيني.

الأسماء التي يجب تجنبها: * كلمات رئيسية C ++ * كلمات رئيسية Java * كلمات مفتاحية الصدأ