التعليقات التوضيحية في AIDL

تتيح لغة AIDL التعليقات التوضيحية التي تمنح مُجمِّع AIDL معلومات إضافية عن العنصر الذي يحتوي على تعليق توضيحي، ما يؤثر أيضًا في رمز الرمز المرجعي الذي تم إنشاؤه.

تتشابه بنية هذه الأوامر مع بنية Java:

@AnnotationName(argument1=value, argument2=value) AidlEntity

في هذه الحالة، AnnotationName هو اسم التعليق التوضيحي، وAidlEntity هو عنصر لغة تعريف واجهة نظام Android ‏(AIDL) مثل interface Foo أو void method() أو int arg. يتم إرفاق annotation بالعنصر الذي يليه.

يمكن أن تحتوي بعض التعليقات التوضيحية على وسيطات تم ضبطها داخل الأقواس، كما هو موضّح أعلاه. لا تحتاج التعليقات التوضيحية التي لا تحتوي على وسيطة إلى قوس. مثلاً:

@AnnotationName AidlEntity

هذه التعليقات التوضيحية ليست مماثلة لتعليقات Java التوضيحية، على الرغم من أنّها تبدو متشابهة جدًا. لا يمكن للمستخدمين تحديد ملفًا شخصيًا مخصّصًا لتعليقات توضيحية في AIDL، لأنّ جميع التعليقات التوضيحية محدّدة مسبقًا. لا تؤثّر بعض التعليقات التوضيحية سوى في خلفية معيّنة ولا تُنفَّذ في الخلفيات الأخرى. وتفرض هذه العناصر قيودًا مختلفة على الأماكن التي يمكن إرفاقها بها.

في ما يلي قائمة التعليقات التوضيحية المحدَّدة مسبقًا لـ AIDL:

التعليقات التوضيحية تمت الإضافة في إصدار Android
nullable 7
utf8InCpp 7
VintfStability 11
UnsupportedAppUsage 10
Hide 11
Backing 11
NdkOnlyStableParcelable 14
JavaOnlyStableParcelable 11
JavaDerive 12
JavaPassthrough 12
FixedSize 12
Descriptor 12

قابلة للقيم الفارغة

يشير الرمز nullable إلى أنّه قد لا يتم تقديم قيمة الكيان الذي تمت التعليق عليه.

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

interface IFoo {
    // method return types
    @nullable Data method();

    // method parameters
    void method2(in @nullable Data d);
}

parcelable Data {
    // parcelable fields
    @nullable Data d;
}

لا يمكن إرفاق التعليقات التوضيحية بالأنواع الأساسية. حدث خطأ ما يلي.

void method(in @nullable int a); // int is a primitive type

هذا التعليق التوضيحي ليس جاهزًا بالنسبة إلى واجهة Java الخلفية. ويرجع ذلك إلى أنّه في Java، يتم تمرير كل الأنواع غير الأساسية من خلال مرجع، والذي يمكن أن يكون null.

في الخلفية في ملف CPP، يتم ربط @nullable T بـ std::unique_ptr<T> في Android 11 أو الإصدارات الأقدم، وبـ std::optional<T> في Android 12 أو الإصدارات الأحدث.

في الخلفية في NDK، يتم دائمًا ربط @nullable T بـ std::optional<T>.

في الخلفية في Rust، يتم دائمًا ربط @nullable T بـ Option<T>.

بالنسبة إلى النوع L الذي يشبه القائمة، مثل T[] أو List<T>، يتمّ ربط @nullable L بقيمة std::optional<std::vector<std::optional<T>>> (أو std::unique_ptr<std::vector<std::unique_ptr<T>>> في حال استخدام الخلفية في خدمة مقارنة الأسعار لنظام التشغيل Android 11 أو الإصدارات الأقدم).

هناك استثناء لهذا الربط. عندما يكون T IBinder أو واجهة AIDL، يكون @nullable غير فعّال لجميع الخلفيات باستثناء Rust. بعبارة أخرى، يتم ربط كل من @nullable IBinder وIBinder بالتساوي بـ android::sp<IBinder>، وهو يمكن أن يكون خاليًا من القيمة لأنّه مُشير قوي (لا تزال قراءات لغة C++ تفرض عدم السماح بقيمة خالية، ولكن النوع لا يزال android::sp<IBinder>). في لغة Rust، تكون هذه الأنواع nullable فقط إذا تم التعليق التوضيحي عليها باستخدام @nullable. ويتم ربطها بعلامة Option<T> إذا تمّت إضافة تعليقات توضيحية إليها.

بدءًا من Android 13، يمكن استخدام @nullable(heap=true) ل الحقول القابلة للتقسيم لتصميم أنواع متكررة. لا يمكن استخدام @nullable(heap=true) مع معلمات الطريقة أو أنواع الإرجاع. وعند إضافة تعليق توضيحي به، يتم ربط الحقل بإشارة std::unique_ptr<T> مخصّصة للمساحة العشوائية في الخلفيات CPP/NDK. @nullable(heap=true) هي عملية لا تؤدي إلى أيّ إجراء في الخلفية في Java.

utf8InCpp

يُعلِن utf8InCpp أنّ String يتم تمثيله بتنسيق UTF8 لخلفية String. وكما يشير اسمه، لا يُستخدَم التعليق التوضيحي مع الخلفيات الأخرى. على وجه التحديد، يكون String دائمًا بترميز UTF16 في الخلفية في Java وUTF8 في ‎NDK الخلفية.

يمكن إرفاق هذا التعليق التوضيحي في أي مكان يمكن فيه استخدام نوع String، بما في ذلك قيم الإرجاع والمَعلمات وإعلانات الثوابت وحقول parcelable.

بالنسبة إلى الخلفية في لغة C++، يتم ربط @utf8InCpp String في AIDL بـ std::string، في حين يتم ربط String بدون التعليق التوضيحي بـ android::String16 حيث يتم استخدام UTF16.

يُرجى العلم أنّ وجود التعليق التوضيحي utf8InCpp لا يغيّر طريقة إرسال سلاسل العلامات عبر الشبكة. يتم دائمًا نقل السلاسل بتنسيق UTF16 عبر السلك. يتم تحويل سلسلة utf8InCpp التي تحتوي على تعليقات توضيحية إلى UTF16 قبل إرسالها. عند تلقّي سلسلة، يتم تحويلها من UTF16 إلى UTF8 إذا تمّت إضافة تعليق توضيحي لها على أنّها utf8InCpp.

ثبات VintfStability

تُعلِن العلامة VintfStability أنّه يمكن استخدام نوع يحدّده المستخدم (interface وparcelable وenum) في نطاقَي النظام والمورّد. يمكنك الاطّلاع على AIDL لـ HALs لمعرفة مزيد من المعلومات عن إمكانية التشغيل التفاعلي بين مورّدي النظام.

ولا يغير التعليق التوضيحي توقيع النوع، ولكن عند تعيينه، يتم وضع علامة على المثيل من النوع كثابت بحيث يمكن الانتقال عبر عمليات المورد والنظام.

لا يمكن إرفاق التعليق التوضيحي إلا ببيانات أنواع محدّدة من قِبل المستخدم كما هو موضّح هنا:

@VintfStability
interface IFoo {
    ....
}

@VintfStability
parcelable Data {
    ....
}

@VintfStability
enum Type {
    ....
}

عند إضافة تعليق توضيحي على نوع باستخدام الرمز VintfStability، يجب أيضًا إضافة تعليق توضيحي على أي نوع آخر تتم الإشارة إليه في النوع. في المثال التالي، يجب إضافة تعليقات توضيحية إلى كل من Data وIBar باستخدام VintfStability.

@VintfStability
interface IFoo {
    void doSomething(in IBar b); // references IBar
    void doAnother(in Data d); // references Data
}

@VintfStability // required
interface IBar {...}

@VintfStability // required
parcelable Data {...}

بالإضافة إلى ذلك، لا يمكن إنشاء ملفات AIDL التي تحدّد الأنواع التي تمت عليها تعليقات توضيحية باستخدام VintfStability إلا باستخدام نوع وحدة Soong‏ aidl_interface، مع ضبط السمة stability على "vintf".

aidl_interface {
    name: "my_interface",
    srcs: [...],
    stability: "vintf",
}

UnsupportedAppUsage

يشير التعليق التوضيحي UnsupportedAppUsage إلى أنّ نوع AIDL الذي تمّت إضافة تعليق توضيحي له هو جزء من الواجهة غير المتوفّرة في حزمة SDK التي كان بالإمكان الوصول إليها من خلال التطبيقات القديمة. اطّلِع على القيود المفروضة على واجهات برمجة التطبيقات التي لا تستند إلى حِزم تطوير البرامج (SDK) لمزيد من المعلومات عن واجهات برمجة التطبيقات المخفية.

ولا يؤثر تعليق UnsupportedAppUsage التوضيحي في سلوك الرمز الذي تم إنشاؤه. لا يُضيف التعليق التوضيحي سوى تعليق توضيحي لفئة Java التي تم إنشاؤها باستخدام تعليق توضيحي Java بالاسم نفسه.

// in AIDL
@UnsupportedAppUsage
interface IFoo {...}

// in Java
@android.compat.annotation.UnsupportedAppUsage
public interface IFoo {...}

لا يُسمح بتنفيذ هذا الإجراء مع الخلفيات غير المستندة إلى Java.

النسخ الاحتياطي

يحدّد التعليق التوضيحي Backing نوع مساحة التخزين لنوع قائمة بيانات متغيّرات AIDL.

@Backing(type="int")
enum Color { RED, BLUE, }

في الخلفية في لغة C++، يؤدي ذلك إلى إنشاء فئة قائمة بقيم ثابتة من النوع int32_t.

enum class Color : int32_t {
    RED = 0,
    BLUE = 1,
}

في حال حذف التعليق التوضيحي، يتم افتراض أنّ type هي byte، والتي يتم ربطها بـ int8_t في الخلفية في "المعالجة المحدودة للصور".

يمكن ضبط الوسيطة type على أنواع التكامل التالية فقط:

  • byte (بعرض 8 بت)
  • int (عرض 32 بت)
  • long (بعرض 64 بت)

NdkOnlyStableParcelable

يضع الرمز NdkOnlyStableParcelable علامة على بيان قابل للتقسيم (وليس التعريف) كثابت حتى يمكن الإشارة إليه من أنواع AIDL الثابتة الأخرى. يشبه هذا الرمز JavaOnlyStableParcelable، ولكن يضع NdkOnlyStableParcelable علامة على بيان قابل للتقسيم على أنّه ثابت لنظام NDK العميق بدلاً من Java.

لاستخدام هذا القِطع:

  • يجب تحديد ndk_header.
  • يجب أن يكون لديك مكتبة NDK تحدد العنصر ويجب تجميع المكتبة في المكتبة. على سبيل المثال، في نظام التصميم الأساسي على وحدة cc_*، استخدِم static_libs أو shared_libs. بالنسبة إلى aidl_interface، أضِف المكتبة ضمن additional_shared_libraries في Android.bp.

JavaOnlyStableParcelable

يضع الرمز JavaOnlyStableParcelable علامة على بيان قابل للتقسيم (وليس التعريف) كثابت حتى يمكن الإشارة إليه من أنواع AIDL الثابتة الأخرى.

تتطلّب واجهة برمجة التطبيقات AIDL الثابتة أن تكون جميع الأنواع التي يحدّدها المستخدمون ثابتة. بالنسبة إلى العناصر القابلة للتقسيم، يتطلّب ثباتها وصف حقولها صراحةً في ملف مصدر AIDL.

parcelable Data { // Data is a structured parcelable.
    int x;
    int y;
}

parcelable AnotherData { // AnotherData is also a structured parcelable
    Data d; // OK, because Data is a structured parcelable
}

إذا كان العنصر القابل للتقسيم غير منظَّم (أو تم الإعلان عنه فقط)، لا يمكن الإشارة إليه.

parcelable Data; // Data is NOT a structured parcelable

parcelable AnotherData {
    Data d; // Error
}

يتيح لك JavaOnlyStableParcelable إلغاء عملية التحقّق عندما يكون العنصر المرسَل الذي تشير إليه متاحًا بأمان كجزء من حزمة تطوير البرامج (SDK) لنظام التشغيل Android.

@JavaOnlyStableParcelable
parcelable Data;

parcelable AnotherData {
    Data d; // OK
}

لغة JavaDerive

ينشئ JavaDerive تلقائيًا طرقًا لأنواع العناصر المقطوعة في خلفية Java.

@JavaDerive(equals = true, toString = true)
parcelable Data {
  int number;
  String str;
}

يتطلّب التعليق التوضيحي مَعلمات إضافية للتحكّم في ما ينبغي إنشاءه. المعلمات المتاحة هي:

  • ينشئ equals=true طريقتَي equals وhashCode.
  • ينشئ toString=true طريقة toString تطبع اسم النوع والحقول. على سبيل المثال: Data{number: 42, str: foo}

JavaDefault

تتحكّم القيمة JavaDefault، التي تمت إضافتها في Android 13، في ما إذا كان سيتم إنشاء الإصدار التلقائي لدعم التنفيذ (لأجل setDefaultImpl). لم يعُد يتم إنشاء هذا الدعم تلقائيًا بهدف توفير المساحة.

JavaPassthrough

JavaPassthrough يتيح وضع تعليق توضيحي على واجهة برمجة التطبيقات Java API التي تم إنشاؤها باستخدام تعليق توضيحي произвольн Java.

التعليقات التوضيحية التالية في AIDL

@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Alice.Value.A)")

تصبح

@android.annotation.Alice
@com.android.Alice(arg=com.android.Alice.Value.A)

في رمز Java الذي تم إنشاؤه.

يتمّ بثّ قيمة المَعلمة annotation مباشرةً. لا يفحص مجمع AIDL قيمة المَعلمة. إذا كان هناك أي خطأ في البنية على مستوى Java، لن يرصده برنامج تجميع AIDL بل سيرصده برنامج تجميع Java.

يمكن إرفاق هذا التعليق التوضيحي بأي عنصر AIDL. لا يؤدي هذا التعليق التوضيحي إلى أي إجراء لأنظمة التشغيل غير المستندة إلى Java.

FixedSize

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

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

الوصف

Descriptor يحدِّد بشكلٍ قسري وصف الواجهة لواجهة معيّنة.

package android.foo;

@Descriptor(value="android.bar.IWorld")
interface IHello {...}

واصف هذه الواجهة هو android.bar.IWorld. إذا لم يكن هناك تعليق توضيحي Descriptor، سيكون الواصف android.foo.IHello.

يكون هذا الإجراء مفيدًا لإعادة تسمية واجهة سبق نشرها. جعل واصف الواجهة المُعاد تسميتها مماثلاً لواصف الواجهة قبل إعادة التسمية يمكن للواجهتين التحدث مع بعضها البعض.

@hide في التعليقات

يتعرّف مُجمِّع AIDL على @hide في التعليقات ويمرّره من خلال إلى إخراج Java لكي تلتقطه أداة Metalava. يضمن هذا التعليق أن يعرف نظام ملف APK لنظام Android أنّ واجهات برمجة التطبيقات AIDL ليست واجهات برمجة تطبيقات حزمة تطوير البرامج (SDK).

@deprecated في التعليقات

يتعرّف مُجمِّع AIDL على @deprecated في التعليقات كعلامة لتحديد كيان AIDL الذي يجب عدم استخدامه بعد الآن.

interface IFoo {
  /** @deprecated use bar() instead */
  void foo();
  void bar();
}

يضع كل نظام أساسي علامة على العناصر المتوقّفة نهائيًا باستخدام تعليق توضيحي أوسمة خاصة بالنظام الأساسي حتى يتم تحذير رمز العميل إذا كان يشير إلى العناصر التي تم إيقافها نهائيًا. على سبيل المثال، يتم إرفاق التعليق التوضيحي @Deprecated والعلامة @deprecated بالرمز الذي تم إنشاؤه باستخدام Java.