AIDL-এ অ্যানোটেশন

AIDL অ্যানোটেশনকে সাপোর্ট করে যা AIDL কম্পাইলারকে অ্যানোটেটেড এলিমেন্ট সম্পর্কে অতিরিক্ত তথ্য প্রদান করে, যা জেনারেট করা স্টাব কোডকেও প্রভাবিত করে।

সিনট্যাক্স জাভার মতো:

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

এখানে, AnnotationName হল অ্যানোটেশনের নাম এবং AidlEntity হল interface Foo, void method() বা int arg-এর মতো AIDL এন্টিটি। কোনও অ্যানোটেশন সেই এন্টিটির সাথে অ্যাটাচ করা হয় যেটি এটিকে অনুসরণ করে।

কিছু অ্যানোটেশনে প্যারেন্থেসিসের মধ্যে আর্গুমেন্ট সেট করা থাকতে পারে, যেমনটি আগের উদাহরণে দেখানো হয়েছে। যেসব অ্যানোটেশনে কোনও যুক্তি নেই সেগুলিতে বন্ধনী দেওয়ার প্রয়োজন নেই। যেমন:

@AnnotationName AidlEntity

এইসব অ্যানোটেশন Java অ্যানোটেশনের মতো নয়, যদিও সেগুলি দেখতে একই রকম। সব অ্যানোটেশনই আগে থেকে নির্ধারিত করা থাকে, এবং আপনি কোথায় সেগুলি অ্যাটাচ করতে পারবেন সেই ব্যাপারে বিধিনিষেধ থাকে। কিছু অ্যানোটেশন শুধুমাত্র নির্দিষ্ট ব্যাকএন্ডকে প্রভাবিত করে এবং অন্যান্য ব্যাকএন্ডে কোনও কাজ করে না।

এখানে পূর্বনির্ধারিত AIDL অ্যানোটেশনের তালিকা দেওয়া হল:

টিকাAndroid ভার্সনে যোগ করা হয়েছে
nullable7
utf8InCpp7
VintfStability11
UnsupportedAppUsage10
Hide11
Backing11
NdkOnlyStableParcelable14
JavaOnlyStableParcelable11
JavaDerive12
JavaPassthrough12
FixedSize12
Descriptor12

নাল ভ্যালু থাকতে পারে

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 ব্যাকএন্ডে, Android 11 বা তার আগের ভার্সনে @nullable T, std::unique_ptr<T>-এ ম্যাপ করে এবং Android 12 বা তার পরের ভার্সনে std::optional<T>-এ ম্যাপ করে।

NDK ব্যাকএন্ডে, @nullable T, std::optional<T>-এর সাথে ম্যাপ করে।

Rust ব্যাকএন্ডে, @nullable T Option<T>-এর সাথে ম্যাপ করে।

L-এর মতো তালিকার জন্য, যেমন T[] বা List<T>, @nullable L ম্যাপ করে std::optional<std::vector<std::optional<T>>> (বা Android 11 বা তার আগের ভার্সনের জন্য CPP ব্যাকএন্ডের ক্ষেত্রে std::unique_ptr<std::vector<std::unique_ptr<T>>>)।

এই ম্যাপিংয়ের ক্ষেত্রে একটি ব্যতিক্রম আছে। T যদি IBinder বা AIDL ইন্টারফেস হয়, তাহলে @nullable হল Java, CPP ও NDK ব্যাকএন্ডের জন্য নো-অপ। যেমন, CPP ব্যাকএন্ডে, @nullable IBinder ও IBinder দুটিই সমানভাবে android::sp<IBinder>-এর সাথে ম্যাপ করে, যা আগে থেকেই নাল হতে পারে কারণ এটি একটি শক্তিশালী পয়েন্টার (CPP ও NDK এখনও নাল হতে পারে, কিন্তু ধরন android::sp<IBinder> বা ndk::SpAIBinder হিসেবেই থেকে যায়)।

Rust ব্যাকএন্ডে, যেসব টাইপ Default (IBinder, AIDL ইন্টারফেস, ParcelFileDescriptor এবং আনস্ট্রাকচার্ড পার্সেলযোগ্য) প্রয়োগ করে না, সেগুলি Option<T>-এর সাথে ম্যাপ করে, যা তাদের কনটেক্সটের উপর নির্ভর করে:

  • মেথড রিটার্ন টাইপ, in প্যারামিটার ও inout প্যারামিটার: এই ধরনের ভ্যালু তখনই নাল হতে পারে যদি @nullable দিয়ে অ্যানোটেট করা হয়, যা Option<T>-এর সাথে ম্যাপ করে (অথবা in প্যারামিটারের জন্য Option<&T> এবং inout প্যারামিটারের জন্য &mut Option<T>)। @nullable না থাকলে, সেগুলি সরাসরি T (বা &T এবং &mut T)-এর সাথে ম্যাপ করা হয়।
  • পার্সেলযোগ্য ফিল্ড ও out প্যারামিটার: জেনারেট করা Rust পার্সেলযোগ্য আইটেম থেকে Default ও out প্যারামিটার ডিফল্ট-ইনিশিয়ালাইজ করা হয় বলে, এইসব ধরনের আইটেম সবসময় Option<T>-এর সাথে ম্যাপ করে (এবং এইসব কনটেক্সটে নির্দিষ্ট সাইজের অ্যারে [Option<T>; N]-এর সাথে ম্যাপ করে, অন্যদিকে out প্যারামিটারে ডাইনামিক অ্যারে Vec<Option<T>>-এর সাথে ম্যাপ করে), এমনকি @nullable না থাকলেও। @nullable-এর সাথে অ্যানোটেট করা না থাকলে, পার্সেলিংয়ের সময় রানটাইমে নন-নালেবিলিটি এখনও এনফোর্স করা হয় (ভ্যালু None হলে StatusCode::UNEXPECTED_NULL রিটার্ন করা হয়)।

Android 13 থেকে শুরু করে, রিকার্সিভ টাইপ মডেল করার জন্য পার্সেলযোগ্য ফিল্ডে @nullable(heap=true) ব্যবহার করা যাবে। @nullable(heap=true) পদ্ধতি প্যারামিটার বা রিটার্ন টাইপের সাথে ব্যবহার করা যাবে না। এটি দিয়ে অ্যানোটেট করা হলে, CPP ও NDK ব্যাকএন্ডে হিপ-অ্যালোকেটেড রেফারেন্স std::unique_ptr<T>-এর সাথে ফিল্ডটি ম্যাপ করা হয়। Java ব্যাকএন্ডে @nullable(heap=true)-এর কোনও অপারেশন নেই।

utf8InCpp

utf8InCpp ঘোষণা করে যে CPP ব্যাকএন্ডের জন্য String UTF8 ফর্ম্যাটে দেখানো হয়। নাম থেকেই বোঝা যায় যে, অন্যান্য ব্যাকএন্ডের জন্য অ্যানোটেশনটি কোনও কাজ করে না। বিশেষত, String সবসময় Java ব্যাকএন্ডে UTF16 এবং NDK ব্যাকএন্ডে UTF8 হয়।

এই অ্যানোটেশনটি String টাইপ ব্যবহার করা যায় এমন যেকোনও জায়গায় অ্যাটাচ করা যেতে পারে, এর মধ্যে রিটার্ন ভ্যালু, প্যারামিটার, কনস্ট্যান্ট ডিক্লারেশন ও পার্সেলযোগ্য ফিল্ড অন্তর্ভুক্ত।

CPP ব্যাকএন্ডের জন্য, @utf8InCpp String AIDL-এ std::string-এর সাথে ম্যাপ করে, যেখানে String অ্যানোটেশন ছাড়া android::String16-এর সাথে ম্যাপ করে যেখানে UTF16 ব্যবহার করা হয়।

VintfStability

VintfStability ঘোষণা করে যে ব্যবহারকারীর দ্বারা সংজ্ঞায়িত প্রকার (ইন্টারফেস, পার্সেলযোগ্য, এবং এনাম) সিস্টেম এবং ভেন্ডর ডোমেন জুড়ে ব্যবহার করা যেতে পারে। সিস্টেম-ভেন্ডর ইন্টার-অপারেবিলিটি সম্পর্কে আরও জানতে HAL-এর জন্য AIDL দেখুন।

অ্যানোটেশনটি টাইপের সিগনেচার পরিবর্তন করে না, কিন্তু এটি সেট করা হলে, টাইপের ইনস্ট্যান্সকে স্টেবল হিসেবে চিহ্নিত করা হয় যাতে এটি ভেন্ডর ও সিস্টেম প্রসেস জুড়ে ট্রাভেল করতে পারে।

অ্যানোটেশন শুধুমাত্র ব্যবহারকারীর দ্বারা সংজ্ঞায়িত টাইপ ঘোষণার সাথে সংযুক্ত করা যেতে পারে, যেমনটি এখানে দেখানো হয়েছে:

@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 {...}

এছাড়াও, VintfStability অ্যানোটেশন সহ ধরনকে ডিফাইন করা AIDL ফাইল শুধুমাত্র 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 {...}

Java নয় এমন ব্যাকএন্ডের ক্ষেত্রে এটি কোনও কাজ করে না।

ব্যাকগ্রাউন্ড অ্যানোটেশন

Backing অ্যানোটেশন AIDL enum ধরনের স্টোরেজ ধরন নির্দিষ্ট করে:

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

CPP ব্যাকএন্ডে, এটি int32_t ধরনের একটি C++ enum ক্লাস এমিট করে:

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

অ্যানোটেশন বাদ দেওয়া হলে, type-কে byte হিসেবে ধরে নেওয়া হয়, যা CPP ব্যাকএন্ডের জন্য int8_t-এর সাথে ম্যাপ করে।

type আর্গুমেন্ট শুধুমাত্র নিম্নলিখিত ইন্টিগ্রাল ধরনের জন্য সেট করা যেতে পারে:

  • byte (৮-বিট চওড়া)
  • int (32-বিট ওয়াইড)
  • long (64-বিট ওয়াইড)

NdkOnlyStableParcelable

NdkOnlyStableParcelable একটি পার্সেলযোগ্য ঘোষণা (সংজ্ঞা নয়) কে স্থিতিশীল হিসেবে চিহ্নিত করে যাতে এটি অন্যান্য স্থিতিশীল AIDL ধরন থেকে রেফারেন্স করা যায়। এটি JavaOnlyStableParcelable-এর মতো, তবে NdkOnlyStableParcelable জাভার পরিবর্তে NDK ব্যাকএন্ডের জন্য পার্সেল করা যায় এমন ঘোষণা স্টেবেল হিসেবে চিহ্নিত করে।

এই পার্সেলযোগ্য আইটেম ব্যবহার করতে:

  • আপনাকে অবশ্যই ndk_header উল্লেখ করতে হবে।
  • আপনার কাছে অবশ্যই পার্সেলযোগ্য নির্দিষ্ট করা NDK লাইব্রেরি থাকতে হবে এবং লাইব্রেরিটিকে অবশ্যই লাইব্রেরিতে কম্পাইল করতে হবে। যেমন, cc_* মডিউলের কোর বিল্ড সিস্টেমে, static_libs বা shared_libs ব্যবহার করুন। aidl_interface-এর জন্য, Android.bp-এ additional_shared_libraries-এর অধীনে লাইব্রেরি যোগ করুন।

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 আপনাকে চেক ওভাররাইড করতে দেয় যখন আপনি যে পার্সেলযোগ্য রেফার করছেন সেটি Android SDK-এর অংশ হিসেবে নিরাপদে উপলভ্য থাকে:

@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 (বন্ধ করা হয়েছে)

Android 13-এ যোগ করা JavaDefault, ডিফল্ট ইমপ্লিমেন্টেশন ভার্সনিং সাপোর্ট জেনারেট করা হবে কিনা তা নিয়ন্ত্রণ করে (setDefaultImpl-এর জন্য)। স্পেস বাঁচানোর জন্য এই সাপোর্ট আর ডিফল্ট হিসেবে জেনারেট করা হয় না।

JavaPassthrough

JavaPassthrough জেনারেট করা Java API-কে যেকোনও Java অ্যানোটেশন দিয়ে অ্যানোটেট করতে দেয়।

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 কম্পাইলার প্যারামিটারের ভ্যালু পরীক্ষা করে না। কোনও জাভা-লেভেল সিনট্যাক্স সংক্রান্ত সমস্যা থাকলে, সেটি AIDL কম্পাইলার ধরতে পারবে না, তবে জাভা কম্পাইলার ধরতে পারবে।

এই অ্যানোটেশন যেকোনও AIDL এন্টিটির সাথে অ্যাটাচ করা যেতে পারে। নন-জাভা ব্যাকএন্ডের জন্য এই অ্যানোটেশনটি হল নো-অপ ।

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 শনাক্ত করে এবং metalava-র পিক-আপের জন্য Java আউটপুটে এটি পাস করে। এই কমেন্ট নিশ্চিত করে যে Android বিল্ড সিস্টেম বুঝতে পারে যে AIDL API, SDK API নয়।

কমেন্টে @deprecated

AIDL কম্পাইলার কমেন্টে @deprecated-কে এমন AIDL এন্টিটি শনাক্ত করার ট্যাগ হিসেবে চেনে যা আর ব্যবহার করা উচিত নয়:

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

প্রতিটি ব্যাকএন্ড, ব্যাকএন্ড-নির্দিষ্ট অ্যানোটেশন বা অ্যাট্রিবিউট দিয়ে বাতিল করা এন্টিটি চিহ্নিত করে যাতে ক্লায়েন্ট কোড বাতিল করা এন্টিটি রেফার করলে সেটিকে সতর্ক করা যায়। যেমন, @Deprecated অ্যানোটেশন এবং @deprecated ট্যাগ Java জেনারেটেড কোডের সাথে অ্যাটাচ করা আছে।