التعليقات التوضيحية في لغة تعريف واجهة نظام Android ‏(AIDL)

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

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

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

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

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

@AnnotationName AidlEntity

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

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

التعليقات التوضيحيةتمت إضافة هذا الإذن في إصدار Android
nullable7
utf8InCpp7
VintfStability11
UnsupportedAppUsage10
Hide11
Backing11
NdkOnlyStableParcelable14
JavaOnlyStableParcelable11
JavaDerive12
JavaPassthrough12
FixedSize12
Descriptor12

nullable

تعلن 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> في الإصدار 11 من نظام التشغيل Android أو الإصدارات الأقدم، وبـ std::optional<T> في الإصدار 12 من نظام التشغيل Android أو الإصدارات الأحدث.

في الخلفية الأصلية (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>، وهو قابل للقيم الخالية لأنّه مؤشر قوي (لا تزال عمليات القراءة في CPP تفرض إمكانية القيم الخالية، ولكن يظل النوع 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 لخادم CPP الخلفي. وكما يشير اسمه، فإنّ التعليق التوضيحي لا يؤدي أي عملية في الأنظمة الخلفية الأخرى. على وجه التحديد، يكون String دائمًا بتنسيق UTF16 في الخلفية المستندة إلى Java وبتنسيق UTF8 في الخلفية المستندة إلى NDK.

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

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

VintfStability

تعلن السمة VintfStability عن إمكانية استخدام نوع محدّد من قِبل المستخدم (واجهة، وقابل للتجزئة، وقائمة تعداد) في جميع نطاقات النظام والمورّد. راجِع لغة تعريف واجهة Android‏ (AIDL) لطبقات تجريد الأجهزة (HAL) لمزيد من المعلومات حول إمكانية التشغيل التفاعلي بين النظام والمورّد.

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

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

@VintfStability
interface IFoo {
    ....
}

@VintfStability
parcelable Data {
    ....
}

@VintfStability
enum Type {
    ....
}

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

@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 إلا باستخدام نوع وحدة aidl_interface Soong، مع ضبط السمة 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, }

في الخلفية البرمجية للغة CPP، يؤدي ذلك إلى إنشاء فئة تعداد C++‎ من النوع int32_t:

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

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

لا يمكن ضبط وسيطة 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 إلى واجهة Java API التي تم إنشاؤها.

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

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

يصبح ما يلي في رمز Java الذي تم إنشاؤه:

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

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

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

RustDerive

تنفّذ RustDerive تلقائيًا السمات لأنواع Rust التي تم إنشاؤها.

تتطلّب التعليقات التوضيحية مَعلمات إضافية للتحكّم في المحتوى الذي سيتم إنشاؤه. المَعلمات المتوافقة هي:

  • Copy=true
  • Clone=true
  • Ord=true
  • PartialOrd=true
  • Eq=true
  • PartialEq=true
  • Hash=true

للحصول على توضيحات حول هذه السمات، يُرجى الاطّلاع على مستندات Rust.

FixedSize

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

الواصف

تحدّد Descriptor بشكل إلزامي واصف الواجهة لواجهة معيّنة:

package android.foo;

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

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

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

‎@hide in comments

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

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

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

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

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