التعليقات التوضيحية في 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

يشير الرمز 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 لنظام CPP الخلفي. وكما يشير اسمه، لا يُستخدَم التعليق التوضيحي مع الخلفيات الأخرى. على وجه التحديد، يكون 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 لواجهة HAL لمعرفة مزيد من المعلومات حول إمكانية التشغيل التفاعلي بين النظام والمورّد.

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

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

@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 في الخلفية في تنسيق CPP.

لا يمكن ضبط الوسيطة type إلا على الأنواع الصحيحة التالية:

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

NdkOnlyStableParcelable

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

لاستخدام هذه الميزة:

  • يجب تحديد ndk_header.
  • يجب أن تتوفّر لديك مكتبة NDK تحدّد العنصر القابل للتعبئة، ويجب compiling المكتبة في المكتبة. على سبيل المثال، في نظام الإنشاء الأساسي في وحدة 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 إلغاء عملية التحقّق عندما يكون العنصر parcelable الذي تشير إليه متوفّرًا بأمان كجزء من حزمة تطوير البرامج (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.

RustDerive

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

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

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

للحصول على تفسيرات لهذه السمات، يُرجى الاطّلاع على https://doc.rust-lang.org.

FixedSize

يُستخدَم الرمز FixedSize لتمييز قطعة أرض قابلة للتقسيم بحجم ثابت. بعد وضع العلامة، لن يُسمح بإضافة حقول جديدة إلى العنصر parcelable. يجب أن تكون جميع حقول العنصر القابل للنقل من أنواع ذات حجم ثابت، بما في ذلك الأنواع الأساسية، والقوائم المحددة، والمصفوفات ذات الحجم الثابت، والعناصر القابلة للنقل الأخرى التي تم وضع علامة 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.