حاشیه نویسی در AIDL

AIDL از حاشیه‌نویسی‌هایی پشتیبانی می‌کند که به کامپایلر AIDL اطلاعات بیشتری در مورد عنصر حاشیه‌نویسی می‌دهد، که بر کد خرد تولید شده نیز تأثیر می‌گذارد.

سینتکس شبیه به جاوا است:

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

در اینجا AnnotationName نام حاشیه‌نویسی است و AidlEntity یک موجودیت AIDL مانند interface Foo ، void method() یا int arg است. یک حاشیه نویسی به موجودی که آن را دنبال می کند پیوست می شود.

برخی از حاشیه نویسی ها می توانند آرگومان هایی را در داخل پرانتز قرار دهند، همانطور که در بالا نشان داده شده است. حاشیه نویسی هایی که استدلال ندارند نیازی به پرانتز ندارند. به عنوان مثال:

@AnnotationName AidlEntity

این حاشیه نویسی ها با حاشیه نویسی های جاوا یکسان نیستند، اگرچه بسیار شبیه به هم هستند. کاربران نمی توانند حاشیه نویسی سفارشی AIDL را تعریف کنند. حاشیه نویسی ها همه از پیش تعریف شده اند. برخی از حاشیه نویسی ها تنها بر یک باطن خاص تأثیر می گذارند و در سایر باطن ها بدون عملیات هستند. آنها محدودیت های مختلفی دارند که می توانند به آنها متصل شوند.

در اینجا لیستی از حاشیه نویسی های از پیش تعریف شده AIDL آمده است:

حاشیه نویسی ها در نسخه اندروید اضافه شد
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

این حاشیه نویسی برای باطن جاوا بدون عملیات است. این به این دلیل است که در جاوا، همه انواع غیر ابتدایی با مرجع ارسال می شوند که می تواند null باشد.

در پشتیبان CPP، @nullable T به std::unique_ptr<T> در اندروید 11 یا پایین‌تر و به std::optional<T> در اندروید 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>>> نگاشت std::unique_ptr<std::vector<std::unique_ptr<T>>> در مورد CPP backend برای اندروید 11 یا پایین تر).

یک استثنا برای این نقشه برداری وجود دارد. هنگامی که T IBinder یا یک رابط AIDL است، @nullable برای همه backendها به جز Rust غیر فعال است. In other words, both @nullable IBinder and IBinder equally map to android::sp<IBinder> , which is already nullable because it is a strong pointer (CPP reads still enforce nullability, but the type is still android::sp<IBinder> ). در Rust، این نوع‌ها فقط درصورتی‌که با @nullable حاشیه‌نویسی شوند، nullable هستند. آنها در صورت حاشیه نویسی به Option<T> نگاشت می شوند.

با شروع اندروید 13، @nullable(heap=true) می‌تواند برای فیلدهای parcelable برای مدل‌سازی انواع بازگشتی استفاده شود. @nullable(heap=true) نمی توان با پارامترهای متد یا انواع برگشتی استفاده کرد. هنگامی که با آن حاشیه نویسی می شود، این فیلد به یک مرجع تخصیص داده شده پشته ای std::unique_ptr<T> در backendهای CPP/NDK نگاشت می شود. @nullable(heap=true) در باطن جاوا بدون عملیات است.

utf8InCpp

utf8InCpp اعلام می کند که یک String در قالب UTF8 برای باطن CPP نشان داده شده است. همانطور که از نام آن مشخص است، حاشیه نویسی برای سایر باطن ها بدون عملیات است. به طور خاص، String همیشه UTF16 در باطن جاوا و UTF8 در باطن NDK است.

این حاشیه‌نویسی را می‌توان در هر جایی که بتوان از نوع String استفاده کرد، از جمله مقادیر بازگشتی، پارامترها، اعلان‌های ثابت و فیلدهای قابل بسته‌بندی پیوست کرد.

برای باطن CPP، @utf8InCpp String در نقشه های AIDL به std::string ، در حالی که String بدون حاشیه نویسی به android::String16 که در آن UTF16 استفاده می شود، نقشه می دهد.

توجه داشته باشید که وجود حاشیه نویسی utf8InCpp نحوه انتقال رشته ها از طریق سیم را تغییر نمی دهد. رشته ها همیشه به صورت UTF16 از طریق سیم منتقل می شوند. یک رشته حاشیه نویسی utf8InCpp قبل از انتقال به UTF16 تبدیل می شود. هنگامی که یک رشته دریافت می شود، اگر به عنوان utf8InCpp حاشیه نویسی شده باشد، از UTF16 به UTF8 تبدیل می شود.

VintfStability

VintfStability اعلام می‌کند که یک نوع تعریف‌شده توسط کاربر (رابط، بسته‌پذیر، و 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 را تعریف می‌کنند، فقط می‌توانند با استفاده از نوع ماژول aidl_interface Soong، با ویژگی stability روی "vintf" ساخته شوند.

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

UnsupportedAppUsage

حاشیه نویسی UnsupportedAppUsage نشان می دهد که نوع AIDL حاشیه نویسی شده بخشی از رابط غیر SDK است که برای برنامه های قدیمی در دسترس بوده است. برای اطلاعات بیشتر در مورد APIهای پنهان، به محدودیت‌های رابط‌های غیر SDK مراجعه کنید.

حاشیه نویسی UnsupportedAppUsage بر رفتار کد تولید شده تأثیر نمی گذارد. حاشیه نویسی فقط کلاس جاوای تولید شده را با حاشیه نویسی جاوا به همین نام حاشیه نویسی می کند.

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

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

این یک برنامه بدون عملیات برای پشتیبان های غیر جاوا است.

پشتیبان گیری

حاشیه نویسی Backing نوع ذخیره سازی یک نوع AIDL enum را مشخص می کند.

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

در باطن CPP، یک کلاس C++ enum از نوع int32_t منتشر می‌کند.

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

اگر حاشیه‌نویسی حذف شود، type byte در نظر گرفته می‌شود که برای backend CPP به int8_t نگاشت می‌شود.

آرگومان type را می توان فقط برای انواع انتگرال زیر تنظیم کرد:

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

NdkOnlyStableParcelable

NdkOnlyStableParcelable یک اعلان parcelable (نه تعریف) را به عنوان پایدار علامت گذاری می کند تا بتوان آن را از سایر انواع AIDL پایدار ارجاع داد. این مانند JavaOnlyStableParcelable است، اما NdkOnlyStableParcelable یک اعلان بسته‌پذیر را به‌جای جاوا برای باطن NDK به‌عنوان پایدار علامت‌گذاری می‌کند.

برای استفاده از این بسته بندی:

  • باید ndk_header مشخص کنید.
  • شما باید یک کتابخانه NDK داشته باشید که بسته پذیر را مشخص کند و کتابخانه باید در کتابخانه کامپایل شود. به عنوان مثال، در سیستم ساخت هسته در یک ماژول cc_* ، از static_libs یا shared_libs استفاده کنید. برای aidl_interface ، کتابخانه را در زیر additional_shared_libraries در Android.bp اضافه کنید.

JavaOnlyStableParcelable

JavaOnlyStableParcelable یک اعلان parcelable (نه تعریف) را به عنوان پایدار علامت گذاری می کند تا بتوان آن را از سایر انواع 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 به شما امکان می دهد تا زمانی که بسته ای که به آن ارجاع می دهید به صورت ایمن به عنوان بخشی از Android SDK در دسترس است، بررسی را لغو کنید.

@JavaOnlyStableParcelable
parcelable Data;

parcelable AnotherData {
    Data d; // OK
}

JavaDerive

JavaDerive به طور خودکار متدهایی را برای انواع قابل تقسیم در باطن جاوا تولید می کند.

@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 اجازه می دهد تا API جاوا ایجاد شده با یک حاشیه نویسی دلخواه جاوا حاشیه نویسی شود.

حاشیه نویسی های زیر در 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)

در کد جاوا تولید شده

مقدار پارامتر annotation مستقیماً منتشر می شود. کامپایلر AIDL به مقدار پارامتر نگاه نمی کند. اگر هر گونه خطای نحوی در سطح جاوا وجود داشته باشد، توسط کامپایلر AIDL شناسایی نمی شود، بلکه توسط کامپایلر جاوا شناسایی می شود.

این حاشیه نویسی را می توان به هر موجودیت AIDL پیوست. این حاشیه نویسی برای برنامه های پشتیبان غیر جاوا یک برنامه بدون عملیات است.

FixedSize

FixedSize یک بسته بندی ساختار یافته را به عنوان اندازه ثابت علامت گذاری می کند. پس از علامت‌گذاری، بسته‌بندی مجاز به افزودن فیلدهای جدید به آن نخواهد بود. همه فیلدهای parcelable نیز باید دارای انواع با اندازه ثابت باشند، از جمله انواع اولیه، enums، آرایه‌های با اندازه ثابت، و سایر قابلمه‌هایی که با FixedSize مشخص شده‌اند.

این هیچ تضمینی برای بیت های مختلف ارائه نمی دهد و نباید برای ارتباط با بیت های مختلف به آن اعتماد کرد.

توصیفگر

Descriptor به اجبار توصیفگر رابط یک رابط را مشخص می کند.

package android.foo;

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

توصیف کننده این رابط android.bar.IWorld است. اگر حاشیه‌نویسی Descriptor وجود نداشته باشد، توصیف‌گر android.foo.IHello .

این برای تغییر نام یک رابط از قبل منتشر شده مفید است. قبل از تغییر نام، توصیف کننده رابط تغییر نام یافته مشابه توصیف کننده رابط کاربری قبل از تغییر نام، به دو رابط اجازه می دهد تا با یکدیگر صحبت کنند.

@hide در نظرات

کامپایلر AIDL، @hide در کامنت‌ها تشخیص می‌دهد و آن را به خروجی جاوا ارسال می‌کند تا metalava به پیکاپ شود. این نظر تضمین می کند که سیستم ساخت اندروید می داند که APIهای AIDL APIهای SDK نیستند.

@ منسوخ شده در نظرات

کامپایلر AIDL، @deprecated در نظرات به عنوان برچسبی برای شناسایی موجودیت AIDL که دیگر نباید استفاده شود، شناسایی می کند.

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

هر پشتیبان موجودیت های منسوخ شده را با یک حاشیه نویسی یا ویژگی خاص باطن علامت گذاری می کند تا در صورت ارجاع به موجودیت های منسوخ شده به کد مشتری هشدار داده شود. به عنوان مثال، حاشیه نویسی @Deprecated و تگ @deprecated به کد تولید شده جاوا متصل می شوند.