التعليقات التوضيحية في لغة تعريف واجهة نظام 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>>> في حال كان الخادم الخلفي لـ CPP متوافقًا مع الإصدار 11 من نظام التشغيل Android أو إصدار أقدم).

هناك استثناء لهذه العملية. عندما يكون 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 عن إمكانية استخدام نوع محدّد من قِبل المستخدم (واجهة، وقابل للتجزئة، وتعداد) في جميع نطاقات النظام والمورّد. راجِع 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 عليها.

تتميز عناصر FixedSize بأحجام وعمليات محاذاة ثابتة في الخلفية ndk.

النوع الحجم (بايت) المحاذاة (بايت)
boolean 1 1
byte 1 1
char 2 2
int 4 4
long 8 8
float 4 4
double 8 8
parcelable إجمالي حجم جميع الحقول أكبر محاذاة لجميع الحقول
union أكبر حجم لجميع الحقول أكبر محاذاة لجميع الحقول
enum حجم نوع النسخ الاحتياطي محاذاة نوع الخلفية
T[N] (مصفوفة ذات حجم ثابت) حجم T * N محاذاة T
String, IBinder, FileDescriptor, ParcelFileDescriptor N/A N/A

الواصف

تحدّد 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 يدرك أنّ واجهات برمجة تطبيقات لغة تعريف واجهة نظام Android ‏(AIDL) ليست واجهات برمجة تطبيقات حزمة تطوير البرامج (SDK).

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

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

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

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