একটি এআইডিএল ব্যাকএন্ড হল স্টাব কোড তৈরির লক্ষ্য। AIDL ফাইলগুলি ব্যবহার করার সময়, আপনি সর্বদা একটি নির্দিষ্ট রানটাইম সহ একটি নির্দিষ্ট ভাষায় ব্যবহার করেন। প্রেক্ষাপটের উপর নির্ভর করে, আপনার বিভিন্ন AIDL ব্যাকএন্ড ব্যবহার করা উচিত।
AIDL এর নিম্নলিখিত ব্যাকএন্ড রয়েছে:
ব্যাকএন্ড | ভাষা | API পৃষ্ঠ | সিস্টেম তৈরি করুন |
---|---|---|---|
জাভা | জাভা | SDK/SystemApi (স্থিতিশীল*) | সব |
এনডিকে | সি++ | libbinder_ndk (স্থিতিশীল*) | aidl_interface |
সিপিপি | সি++ | লিবিন্ডার (অস্থির) | সব |
মরিচা | মরিচা | libbinder_rs (অস্থির) | aidl_interface |
- এই API পৃষ্ঠতলগুলি স্থিতিশীল, কিন্তু অনেক API, যেমন পরিষেবা পরিচালনার জন্য, অভ্যন্তরীণ প্ল্যাটফর্ম ব্যবহারের জন্য সংরক্ষিত এবং অ্যাপগুলিতে উপলব্ধ নয়। অ্যাপে এআইডিএল কীভাবে ব্যবহার করবেন সে সম্পর্কে আরও তথ্যের জন্য, বিকাশকারী ডকুমেন্টেশন দেখুন।
- মরিচা ব্যাকএন্ড অ্যান্ড্রয়েড 12 এ চালু করা হয়েছিল; NDK ব্যাকএন্ড Android 10 হিসাবে উপলব্ধ।
- মরিচা
libbinder_ndk
এর উপরে নির্মিত। APEXes বাইন্ডার ক্রেটটি একইভাবে ব্যবহার করে যেভাবে সিস্টেমের পাশে অন্য কেউ করে। মরিচা অংশটি একটি এপেক্সে বান্ডিল করা হয় এবং এর ভিতরে পাঠানো হয়। এটিlibbinder_ndk.so
সিস্টেম পার্টিশনের উপর নির্ভর করে।
সিস্টেম তৈরি করুন
ব্যাকএন্ডের উপর নির্ভর করে, স্টাব কোডে AIDL কম্পাইল করার দুটি উপায় রয়েছে। বিল্ড সিস্টেম সম্পর্কে আরো বিস্তারিত জানার জন্য, সুং মডিউল রেফারেন্স দেখুন।
কোর বিল্ড সিস্টেম
যেকোন cc_
বা java_
মডিউলে (বা তাদের Android.mk
সমতুল্য) .aidl
ফাইলগুলিকে সোর্স ফাইল হিসেবে উল্লেখ করা যেতে পারে। এই ক্ষেত্রে, AIDL-এর Java/CPP ব্যাকএন্ড ব্যবহার করা হয় (NDK ব্যাকএন্ড নয়), এবং সংশ্লিষ্ট AIDL ফাইলগুলি ব্যবহার করার জন্য ক্লাসগুলি স্বয়ংক্রিয়ভাবে মডিউলে যোগ করা হয়। বিকল্প যেমন local_include_dirs
, যা বিল্ড সিস্টেমকে সেই মডিউলের AIDL ফাইলগুলির রুট পাথ বলে একটি aidl:
গ্রুপের অধীনে এই মডিউলগুলিতে নির্দিষ্ট করা যেতে পারে। মনে রাখবেন যে মরিচা ব্যাকএন্ড শুধুমাত্র মরিচা ব্যবহার করার জন্য। rust_
মডিউলগুলি ভিন্নভাবে পরিচালনা করা হয় যাতে AIDL ফাইলগুলি উত্স ফাইল হিসাবে নির্দিষ্ট করা হয় না। পরিবর্তে, aidl_interface
মডিউলটি <aidl_interface name>-rust
নামে একটি rustlib
তৈরি করে যার সাথে সংযুক্ত করা যেতে পারে। আরো বিস্তারিত জানার জন্য, মরিচা এআইডিএল উদাহরণ দেখুন।
aidl_interface
স্থিতিশীল এআইডিএল দেখুন। এই বিল্ড সিস্টেমের সাথে ব্যবহৃত প্রকারগুলি অবশ্যই কাঠামোগত হতে হবে; যে, সরাসরি এআইডিএল-এ প্রকাশ করা হয়। এর মানে হল কাস্টম পার্সেলেবল ব্যবহার করা যাবে না।
প্রকারভেদ
আপনি প্রকারের জন্য একটি রেফারেন্স বাস্তবায়ন হিসাবে aidl
কম্পাইলার বিবেচনা করতে পারেন। আপনি যখন একটি ইন্টারফেস তৈরি করেন, তখন aidl --lang=<backend> ...
ব্যবহার করুন ফলাফলের ইন্টারফেস ফাইলটি দেখতে। আপনি যখন aidl_interface
মডিউল ব্যবহার করেন, আপনি out/soong/.intermediates/<path to module>/
এ আউটপুট দেখতে পারেন।
জাভা/এআইডিএল টাইপ | C++ প্রকার | এনডিকে টাইপ | মরিচা প্রকার |
---|---|---|---|
বুলিয়ান | bool | bool | bool |
বাইট | int8_t | int8_t | i8 |
চর | char16_t | char16_t | u16 |
int | int32_t | int32_t | i32 |
দীর্ঘ | int64_t | int64_t | i64 |
ভাসা | ভাসা | ভাসা | f32 |
দ্বিগুণ | দ্বিগুণ | দ্বিগুণ | f64 |
স্ট্রিং | অ্যান্ড্রয়েড::স্ট্রিং16 | std::স্ট্রিং | স্ট্রিং |
android.os.Parcelable | অ্যান্ড্রয়েড::পার্সেলেবল | N/A | N/A |
আইবিন্ডার | অ্যান্ড্রয়েড::আইবিন্ডার | ndk::SpAIBinder | বাইন্ডার::স্পাইবাইন্ডার |
টি[] | std::ভেক্টর<T> | std::ভেক্টর<T> | ইন: &T আউট: Vec<T> |
বাইট | std::vector<uint8_t> | std::ভেক্টর<int8_t> 1 | মধ্যে: &[u8] আউট: Vec<u8> |
তালিকা<T> | std::ভেক্টর<T> 2 | std::ভেক্টর<T> 3 | ইন: &[T] 4 আউট: Vec<T> |
ফাইল বর্ণনাকারী | android::base::unique_fd | N/A | বাইন্ডার::parcel::ParcelFileDescriptor |
পার্সেলফাইল বর্ণনাকারী | android::os::ParcelFileDescriptor | ndk::ScopedFileDescriptor | বাইন্ডার::parcel::ParcelFileDescriptor |
ইন্টারফেসের ধরন (টি) | android::sp<T> | std::shared_ptr<T> | বাইন্ডার::শক্তিশালী |
পার্সেলযোগ্য প্রকার (টি) | টি | টি | টি |
ইউনিয়ন টাইপ (T) 5 | টি | টি | টি |
T[N] 6 | std:: array<T, N> | std:: array<T, N> | [টি; ন] |
1. Android 12 বা উচ্চতর সংস্করণে, বাইট অ্যারে সামঞ্জস্যের কারণে int8_t-এর পরিবর্তে uint8_t ব্যবহার করে।
2. C++ ব্যাকএন্ড List<T>
সমর্থন করে যেখানে T
হল String
, IBinder
, ParcelFileDescriptor
বা parcelable-এর একটি। অ্যান্ড্রয়েড টি (এওএসপি পরীক্ষামূলক) বা উচ্চতর, T
অ্যারে ব্যতীত যেকোন নন-প্রিমিটিভ টাইপ (ইন্টারফেসের ধরন সহ) হতে পারে। AOSP সুপারিশ করে যে আপনি T[]
এর মত অ্যারে প্রকার ব্যবহার করুন, যেহেতু তারা সমস্ত ব্যাকএন্ডে কাজ করে।
3. NDK ব্যাকএন্ড List<T>
সমর্থন করে যেখানে T
হল একটি String
, ParcelFileDescriptor
বা পার্সেলেবল। অ্যান্ড্রয়েড টি (এওএসপি পরীক্ষামূলক) বা উচ্চতর, T
অ্যারে ব্যতীত যে কোনও অ-আদি প্রকার হতে পারে।
4. রাস্ট কোডের জন্য প্রকারগুলি ভিন্নভাবে পাস করা হয় তা নির্ভর করে যে সেগুলি ইনপুট (একটি যুক্তি), বা একটি আউটপুট (একটি প্রত্যাবর্তিত মান)।
5. ইউনিয়ন প্রকারগুলি Android 12 এবং উচ্চতর সংস্করণে সমর্থিত।
6. Android T (AOSP পরীক্ষামূলক) বা উচ্চতর, স্থির-আকারের অ্যারে সমর্থিত। স্থির-আকারের অ্যারেতে একাধিক মাত্রা থাকতে পারে (যেমন int[3][4]
)। জাভা ব্যাকএন্ডে, স্থির-আকারের অ্যারেগুলিকে অ্যারের প্রকার হিসাবে উপস্থাপন করা হয়।
দিকনির্দেশনা (ইন/আউট/ইনআউট)
ফাংশনে আর্গুমেন্টের ধরন নির্দিষ্ট করার সময়, আপনি এগুলিকে in
, out
বা inout
হিসাবে নির্দিষ্ট করতে পারেন। এটি আইপিসি কলের জন্য কোন দিক থেকে তথ্য পাঠানো হয় তা নিয়ন্ত্রণ করে। in
হল ডিফল্ট দিক, এবং এটি নির্দেশ করে যে কলার থেকে কলকারীর কাছে ডেটা পাঠানো হয়েছে। out
মানে কলকারী থেকে কলারের কাছে ডেটা প্রেরণ করা হয়। inout
হল এই উভয়ের সমন্বয়। যাইহোক, Android টিম সুপারিশ করে যে আপনি inout
আর্গুমেন্ট স্পেসিফায়ার ব্যবহার করা এড়িয়ে চলুন। আপনি যদি একটি সংস্করণযুক্ত ইন্টারফেস এবং একটি পুরানো কলির সাথে inout
ব্যবহার করেন, তবে অতিরিক্ত ক্ষেত্রগুলি যেগুলি শুধুমাত্র কলারের মধ্যে উপস্থিত থাকে তাদের ডিফল্ট মানগুলিতে পুনরায় সেট করা হয়। Rust এর ক্ষেত্রে, একটি সাধারণ inout
প্রকার &mut Vec<T>
গ্রহণ করে, এবং একটি তালিকা inout
প্রকার &mut Vec<T>
গ্রহণ করে।
UTF8/UTF16
CPP ব্যাকএন্ডের সাহায্যে আপনি স্ট্রিং utf-8 নাকি utf-16 চয়ন করতে পারেন। স্বয়ংক্রিয়ভাবে utf-8 তে রূপান্তর করতে AIDL-এ স্ট্রিংগুলিকে @utf8InCpp String
স্ট্রিং হিসাবে ঘোষণা করুন। NDK এবং Rust ব্যাকএন্ড সবসময় utf-8 স্ট্রিং ব্যবহার করে। utf8InCpp
টীকা সম্পর্কে আরও তথ্যের জন্য, AIDL- এ টীকা দেখুন।
শূন্যতা
আপনি CPP এবং NDK ব্যাকএন্ডে নাল মান প্রকাশ করতে @nullable
এর সাথে জাভা ব্যাকএন্ডে নাল হতে পারে এমন ধরনের টীকা দিতে পারেন। Rust ব্যাকএন্ডে এই @nullable
প্রকারগুলি Option<T>
হিসাবে উন্মুক্ত করা হয়েছে। নেটিভ সার্ভারগুলি ডিফল্টরূপে নাল মান প্রত্যাখ্যান করে। এর একমাত্র ব্যতিক্রম হল interface
এবং IBinder
প্রকার, যা NDK রিড এবং CPP/NDK লেখার জন্য সর্বদা শূন্য হতে পারে। nullable
টীকা সম্পর্কে আরও তথ্যের জন্য, AIDL-এ টীকা দেখুন।
কাস্টম পার্সেলেবল
কোর বিল্ড সিস্টেমে C++ এবং জাভা ব্যাকএন্ডে, আপনি একটি পার্সেবল ঘোষণা করতে পারেন যা একটি টার্গেট ব্যাকেন্ডে (C++ বা জাভাতে) ম্যানুয়ালি প্রয়োগ করা হয়েছে।
package my.package;
parcelable Foo;
অথবা C++ হেডার ঘোষণা সহ:
package my.package;
parcelable Foo cpp_header "my/package/Foo.h";
তারপরে আপনি এই পার্সেলেবলটিকে এআইডিএল ফাইলে একটি প্রকার হিসাবে ব্যবহার করতে পারেন, তবে এটি এআইডিএল দ্বারা তৈরি করা হবে না।
মরিচা কাস্টম পার্সেলেবল সমর্থন করে না।
ডিফল্ট মান
স্ট্রাকচার্ড পার্সেবলগুলি আদিম, String
এবং এই ধরনের অ্যারের জন্য প্রতি-ক্ষেত্র ডিফল্ট মান ঘোষণা করতে পারে।
parcelable Foo {
int numField = 42;
String stringField = "string value";
char charValue = 'a';
...
}
জাভা ব্যাকএন্ডে যখন ডিফল্ট মান অনুপস্থিত থাকে, ক্ষেত্রগুলি আদিম null
জন্য শূন্য মান হিসাবে এবং অ-আদি প্রকারের জন্য শূন্য হিসাবে আরম্ভ করা হয়।
অন্যান্য ব্যাকএন্ডে, যখন ডিফল্ট মান সংজ্ঞায়িত করা হয় না তখন ক্ষেত্রগুলি ডিফল্ট প্রারম্ভিক মান দিয়ে শুরু করা হয়। উদাহরণস্বরূপ, C++ ব্যাকএন্ডে, String
ক্ষেত্রগুলি একটি খালি স্ট্রিং হিসাবে আরম্ভ করা হয় এবং List<T>
ক্ষেত্রগুলি একটি খালি vector<T>
। @nullable
ক্ষেত্রগুলি null-value ক্ষেত্র হিসাবে আরম্ভ করা হয়।
ত্রুটি পরিচালনা
অ্যান্ড্রয়েড ওএস ত্রুটি রিপোর্ট করার সময় পরিষেবাগুলির জন্য অন্তর্নির্মিত ত্রুটির প্রকারগুলি সরবরাহ করে৷ এগুলি বাইন্ডার দ্বারা ব্যবহৃত হয় এবং একটি বাইন্ডার ইন্টারফেস বাস্তবায়নকারী যেকোনো পরিষেবা দ্বারা ব্যবহার করা যেতে পারে। এআইডিএল সংজ্ঞায় তাদের ব্যবহার ভালোভাবে নথিভুক্ত করা হয়েছে এবং তাদের কোনো ব্যবহারকারী-সংজ্ঞায়িত অবস্থা বা রিটার্ন টাইপের প্রয়োজন নেই।
যখন একটি এআইডিএল ফাংশন একটি ত্রুটি রিপোর্ট করে, তখন ফাংশনটি আউটপুট পরামিতিগুলি শুরু বা সংশোধন করতে পারে না। বিশেষত, আউটপুট প্যারামিটার পরিবর্তন করা যেতে পারে যদি ত্রুটিটি লেনদেনের প্রক্রিয়াকরণের সময় ঘটার বিপরীতে আনপার্সেলিংয়ের সময় ঘটে। সাধারণভাবে, যখন একটি AIDL ফাংশন থেকে একটি ত্রুটি পাওয়া যায়, তখন সমস্ত inout
এবং out
প্যারামিটারের পাশাপাশি রিটার্ন মান (যা কিছু ব্যাকএন্ডে একটি out
প্যারামিটারের মতো কাজ করে) একটি অনির্দিষ্ট অবস্থায় আছে বলে বিবেচনা করা উচিত।
যদি AIDL ইন্টারফেসের জন্য অতিরিক্ত ত্রুটির মান প্রয়োজন যা অন্তর্নির্মিত ত্রুটির ধরন দ্বারা আচ্ছাদিত না হয়, তাহলে তারা বিশেষ পরিষেবা-নির্দিষ্ট বিল্ট-ইন ত্রুটি ব্যবহার করতে পারে যা ব্যবহারকারীর দ্বারা সংজ্ঞায়িত পরিষেবা-নির্দিষ্ট ত্রুটি মান অন্তর্ভুক্ত করার অনুমতি দেয় . এই পরিষেবা-নির্দিষ্ট ত্রুটিগুলি সাধারণত AIDL ইন্টারফেসে একটি const int
বা int
-backed enum
হিসাবে সংজ্ঞায়িত করা হয় এবং বাইন্ডার দ্বারা পার্স করা হয় না।
জাভাতে, ত্রুটিগুলি ব্যতিক্রমগুলিতে ম্যাপ করে, যেমন android.os.RemoteException
। পরিষেবা-নির্দিষ্ট ব্যতিক্রমগুলির জন্য, Java ব্যবহারকারী-সংজ্ঞায়িত ত্রুটি সহ android.os.ServiceSpecificException
ব্যবহার করে।
অ্যান্ড্রয়েডে নেটিভ কোড ব্যতিক্রম ব্যবহার করে না। CPP ব্যাকএন্ড android::binder::Status
ব্যবহার করে। NDK ব্যাকএন্ড ndk::ScopedAStatus
ব্যবহার করে। এআইডিএল দ্বারা উত্পন্ন প্রতিটি পদ্ধতি এইগুলির মধ্যে একটি প্রদান করে, পদ্ধতির অবস্থার প্রতিনিধিত্ব করে। মরিচা ব্যাকএন্ড NDK-এর মতো একই ব্যতিক্রম কোড মান ব্যবহার করে, কিন্তু ব্যবহারকারীর কাছে সেগুলি সরবরাহ করার আগে সেগুলিকে নেটিভ রাস্ট এরর ( StatusCode
, ExceptionCode
) এ রূপান্তর করে। পরিষেবা-নির্দিষ্ট ত্রুটির জন্য, প্রত্যাবর্তিত Status
বা ScopedAStatus
ব্যবহারকারী-সংজ্ঞায়িত ত্রুটি সহ EX_SERVICE_SPECIFIC
ব্যবহার করে৷
অন্তর্নির্মিত ত্রুটি প্রকারগুলি নিম্নলিখিত ফাইলগুলিতে পাওয়া যাবে:
ব্যাকএন্ড | সংজ্ঞা |
---|---|
জাভা | android/os/Parcel.java |
সিপিপি | binder/Status.h |
এনডিকে | android/binder_status.h |
মরিচা | android/binder_status.h |
বিভিন্ন ব্যাকএন্ড ব্যবহার করে
এই নির্দেশাবলী Android প্ল্যাটফর্ম কোড নির্দিষ্ট. এই উদাহরণগুলি একটি সংজ্ঞায়িত প্রকার, my.package.IFoo
ব্যবহার করে। মরিচা ব্যাকএন্ড কীভাবে ব্যবহার করবেন তার নির্দেশাবলীর জন্য, অ্যান্ড্রয়েড রাস্ট প্যাটার্নস পৃষ্ঠায় রাস্ট এআইডিএল উদাহরণ দেখুন।
আমদানির ধরন
সংজ্ঞায়িত প্রকারটি একটি ইন্টারফেস, পার্সেলেবল বা ইউনিয়ন হোক না কেন, আপনি এটি জাভাতে আমদানি করতে পারেন:
import my.package.IFoo;
অথবা CPP ব্যাকএন্ডে:
#include <my/package/IFoo.h>
অথবা NDK ব্যাকএন্ডে (অতিরিক্ত aidl
নেমস্পেসটি লক্ষ্য করুন):
#include <aidl/my/package/IFoo.h>
অথবা মরিচা ব্যাকএন্ডে:
use my_package::aidl::my::package::IFoo;
যদিও আপনি জাভাতে একটি নেস্টেড টাইপ আমদানি করতে পারেন, তবে CPP/NDK ব্যাকএন্ডে আপনাকে অবশ্যই এর রুট টাইপের জন্য হেডার অন্তর্ভুক্ত করতে হবে। উদাহরণস্বরূপ, my/package/IFoo.aidl
( IFoo
হল ফাইলের রুট টাইপ) সংজ্ঞায়িত একটি নেস্টেড টাইপ Bar
আমদানি করার সময় আপনাকে CPP ব্যাকএন্ড (বা <aidl/my/package/IFoo.h>
) এর জন্য <my/package/IFoo.h>
অন্তর্ভুক্ত করতে হবে NDK ব্যাকএন্ডের জন্য <aidl/my/package/IFoo.h>
)।
সেবা বাস্তবায়ন
একটি পরিষেবা বাস্তবায়ন করতে, আপনাকে অবশ্যই নেটিভ স্টাব ক্লাস থেকে উত্তরাধিকারসূত্রে প্রাপ্ত হতে হবে। এই ক্লাসটি বাইন্ডার ড্রাইভারের কাছ থেকে কমান্ডগুলি পড়ে এবং আপনি যে পদ্ধতিগুলি প্রয়োগ করেন তা কার্যকর করে। কল্পনা করুন যে আপনার কাছে এইরকম একটি AIDL ফাইল আছে:
package my.package;
interface IFoo {
int doFoo();
}
জাভাতে, আপনাকে অবশ্যই এই ক্লাস থেকে প্রসারিত করতে হবে:
import my.package.IFoo;
public class MyFoo extends IFoo.Stub {
@Override
int doFoo() { ... }
}
CPP ব্যাকএন্ডে:
#include <my/package/BnFoo.h>
class MyFoo : public my::package::BnFoo {
android::binder::Status doFoo(int32_t* out) override;
}
NDK ব্যাকএন্ডে (অতিরিক্ত aidl
নেমস্পেসটি লক্ষ্য করুন):
#include <aidl/my/package/BnFoo.h>
class MyFoo : public aidl::my::package::BnFoo {
ndk::ScopedAStatus doFoo(int32_t* out) override;
}
মরিচা ব্যাকএন্ডে:
use aidl_interface_name::aidl::my::package::IFoo::{BnFoo, IFoo};
use binder;
/// This struct is defined to implement IRemoteService AIDL interface.
pub struct MyFoo;
impl Interface for MyFoo {}
impl IFoo for MyFoo {
fn doFoo(&self) -> binder::Result<()> {
...
Ok(())
}
}
নিবন্ধন এবং সেবা পেতে
প্ল্যাটফর্ম অ্যান্ড্রয়েডের পরিষেবাগুলি সাধারণত পরিষেবা ব্যবস্থাপক প্রক্রিয়ার সাথে servicemanager
হয়। নীচের APIগুলি ছাড়াও, কিছু API পরিষেবাটি পরীক্ষা করে (অর্থাৎ পরিষেবাটি উপলব্ধ না হলে তারা অবিলম্বে ফিরে আসে)। সঠিক বিবরণের জন্য সংশ্লিষ্ট servicemanager
ইন্টারফেস চেক করুন। প্ল্যাটফর্ম অ্যান্ড্রয়েডের বিরুদ্ধে কম্পাইল করার সময় এই অপারেশনগুলি করা যেতে পারে।
জাভাতে:
import android.os.ServiceManager;
// registering
ServiceManager.addService("service-name", myService);
// getting
myService = IFoo.Stub.asInterface(ServiceManager.getService("service-name"));
// waiting until service comes up (new in Android 11)
myService = IFoo.Stub.asInterface(ServiceManager.waitForService("service-name"));
// waiting for declared (VINTF) service to come up (new in Android 11)
myService = IFoo.Stub.asInterface(ServiceManager.waitForDeclaredService("service-name"));
CPP ব্যাকএন্ডে:
#include <binder/IServiceManager.h>
// registering
defaultServiceManager()->addService(String16("service-name"), myService);
// getting
status_t err = getService<IFoo>(String16("service-name"), &myService);
// waiting until service comes up (new in Android 11)
myService = waitForService<IFoo>(String16("service-name"));
// waiting for declared (VINTF) service to come up (new in Android 11)
myService = waitForDeclaredService<IFoo>(String16("service-name"));
NDK ব্যাকএন্ডে (অতিরিক্ত aidl
নেমস্পেসটি লক্ষ্য করুন):
#include <android/binder_manager.h>
// registering
status_t err = AServiceManager_addService(myService->asBinder().get(), "service-name");
// getting
myService = IFoo::fromBinder(SpAIBinder(AServiceManager_getService("service-name")));
// is a service declared in the VINTF manifest
// VINTF services have the type in the interface instance name.
bool isDeclared = AServiceManager_isDeclared("android.hardware.light.ILights/default");
// wait until a service is available (if isDeclared or you know it's available)
myService = IFoo::fromBinder(SpAIBinder(AServiceManager_waitForService("service-name")));
মরিচা ব্যাকএন্ডে:
use myfoo::MyFoo;
use binder;
use aidl_interface_name::aidl::my::package::IFoo::BnFoo;
fn main() {
binder::ProcessState::start_thread_pool();
// [...]
let my_service = MyFoo;
let my_service_binder = BnFoo::new_binder(
my_service,
BinderFeatures::default(),
);
binder::add_service("myservice", my_service_binder).expect("Failed to register service?");
// Does not return - spawn or perform any work you mean to do before this call.
binder::ProcessState::join_thread_pool()
}
মৃত্যুর সাথে যুক্ত
যখন একটি বাইন্ডার হোস্টিং পরিষেবা মারা যায় তখন আপনি একটি বিজ্ঞপ্তি পাওয়ার জন্য অনুরোধ করতে পারেন৷ এটি কলব্যাক প্রক্সি ফাঁস এড়াতে বা ত্রুটি পুনরুদ্ধারে সহায়তা করতে সহায়তা করতে পারে। বাইন্ডার প্রক্সি অবজেক্টে এই কলগুলি করুন।
- জাভাতে,
android.os.IBinder::linkToDeath
ব্যবহার করুন। - CPP ব্যাকএন্ডে,
android::IBinder::linkToDeath
ব্যবহার করুন। - NDK ব্যাকএন্ডে,
AIBinder_linkToDeath
ব্যবহার করুন। - মরিচা ব্যাকএন্ডে, একটি
DeathRecipient
অবজেক্ট তৈরি করুন, তারপরmy_binder.link_to_death(&mut my_death_recipient)
কল করুন। নোট করুন যেDeathRecipient
কলব্যাকের মালিক, তাই যতক্ষণ আপনি বিজ্ঞপ্তি পেতে চান ততক্ষণ আপনাকে সেই বস্তুটিকে জীবিত রাখতে হবে।
বাগ রিপোর্ট এবং পরিষেবার জন্য ডিবাগিং API
যখন বাগ রিপোর্ট চালানো হয় (উদাহরণস্বরূপ, adb bugreport
সহ), তারা বিভিন্ন সমস্যা ডিবাগ করতে সহায়তা করার জন্য সিস্টেমের চারপাশ থেকে তথ্য সংগ্রহ করে। AIDL পরিষেবাগুলির জন্য, বাগ রিপোর্টগুলি তাদের তথ্য বাগ রিপোর্টে ডাম্প করতে পরিষেবা পরিচালকের সাথে নিবন্ধিত সমস্ত পরিষেবাগুলিতে বাইনারি dumpsys
ব্যবহার করে৷ আপনি dumpsys SERVICE [ARGS]
এর সাথে একটি পরিষেবা থেকে তথ্য পেতে dumpsys
ব্যবহার করতে পারেন। C++ এবং Java ব্যাকএন্ডে, addService
এ অতিরিক্ত আর্গুমেন্ট ব্যবহার করে আপনি কোন ক্রমে পরিষেবাগুলি ডাম্প করা হবে তা নিয়ন্ত্রণ করতে পারেন। ডিবাগ করার সময় একটি পরিষেবার পিআইডি পেতে আপনি dumpsys --pid SERVICE
ব্যবহার করতে পারেন।
আপনার পরিষেবাতে কাস্টম আউটপুট যোগ করতে, আপনি আপনার সার্ভার অবজেক্টে dump
পদ্ধতিকে ওভাররাইড করতে পারেন যেমন আপনি একটি AIDL ফাইলে সংজ্ঞায়িত অন্য কোনো IPC পদ্ধতি প্রয়োগ করছেন। এটি করার সময়, আপনার অ্যাপের অনুমতি android.permission.DUMP
এ ডাম্পিং সীমাবদ্ধ করা উচিত বা নির্দিষ্ট UID-তে ডাম্পিং সীমাবদ্ধ করা উচিত।
জাভা ব্যাকএন্ডে:
@Override
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
@Nullable String[] args) {...}
CPP ব্যাকএন্ডে:
status_t dump(int, const android::android::Vector<android::String16>&) override;
NDK ব্যাকএন্ডে:
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
মরিচা ব্যাকএন্ডে, ইন্টারফেস প্রয়োগ করার সময়, নিম্নলিখিতটি নির্দিষ্ট করুন (এটিকে ডিফল্ট করার অনুমতি দেওয়ার পরিবর্তে):
fn dump(&self, mut file: &File, args: &[&CStr]) -> binder::Result<()>
গতিশীলভাবে ইন্টারফেস বর্ণনাকারী পাচ্ছেন
ইন্টারফেস বর্ণনাকারী একটি ইন্টারফেসের ধরন সনাক্ত করে। ডিবাগ করার সময় বা আপনার কাছে একটি অজানা বাইন্ডার থাকলে এটি কার্যকর।
জাভাতে, আপনি কোড সহ ইন্টারফেস বর্ণনাকারী পেতে পারেন যেমন:
service = /* get ahold of service object */
... = service.asBinder().getInterfaceDescriptor();
CPP ব্যাকএন্ডে:
service = /* get ahold of service object */
... = IInterface::asBinder(service)->getInterfaceDescriptor();
NDK এবং রাস্ট ব্যাকএন্ড এই কার্যকারিতা সমর্থন করে না।
স্থিরভাবে ইন্টারফেস বর্ণনাকারী পেয়ে
কখনও কখনও (যেমন @VintfStability
পরিষেবাগুলি নিবন্ধন করার সময়), আপনাকে জানতে হবে ইন্টারফেস বর্ণনাকারী স্থিরভাবে কী। জাভাতে, আপনি কোড যোগ করে বর্ণনাকারী পেতে পারেন যেমন:
import my.package.IFoo;
... IFoo.DESCRIPTOR
CPP ব্যাকএন্ডে:
#include <my/package/BnFoo.h>
... my::package::BnFoo::descriptor
NDK ব্যাকএন্ডে (অতিরিক্ত aidl
নেমস্পেসটি লক্ষ্য করুন):
#include <aidl/my/package/BnFoo.h>
... aidl::my::package::BnFoo::descriptor
মরিচা ব্যাকএন্ডে:
aidl::my::package::BnFoo::get_descriptor()
এনাম রেঞ্জ
নেটিভ ব্যাকএন্ডে, আপনি একটি enum গ্রহণ করতে পারে এমন সম্ভাব্য মানগুলির উপর পুনরাবৃত্তি করতে পারেন। কোড আকার বিবেচনার কারণে, এটি বর্তমানে জাভাতে সমর্থিত নয়।
AIDL-এ সংজ্ঞায়িত একটি MyEnum
এর জন্য, পুনরাবৃত্তি নিম্নরূপ প্রদান করা হয়েছে।
CPP ব্যাকএন্ডে:
::android::enum_range<MyEnum>()
NDK ব্যাকএন্ডে:
::ndk::enum_range<MyEnum>()
মরিচা ব্যাকএন্ডে:
MyEnum::enum_range()
থ্রেড ব্যবস্থাপনা
একটি প্রক্রিয়ায় libbinder
প্রতিটি উদাহরণ একটি থ্রেডপুল বজায় রাখে। বেশিরভাগ ব্যবহারের ক্ষেত্রে, এটি ঠিক একটি থ্রেডপুল হওয়া উচিত, সমস্ত ব্যাকএন্ড জুড়ে ভাগ করা। এর একমাত্র ব্যতিক্রম হল যখন ভেন্ডর কোড /dev/vndbinder
এর সাথে কথা বলার জন্য libbinder
এর অন্য একটি কপি লোড করতে পারে। যেহেতু এটি একটি পৃথক বাইন্ডার নোডে রয়েছে, তাই থ্রেডপুল ভাগ করা হয় না।
জাভা ব্যাকএন্ডের জন্য, থ্রেডপুল শুধুমাত্র আকারে বৃদ্ধি করতে পারে (যেহেতু এটি ইতিমধ্যেই শুরু হয়েছে):
BinderInternal.setMaxThreads(<new larger value>);
CPP ব্যাকএন্ডের জন্য, নিম্নলিখিত ক্রিয়াকলাপগুলি উপলব্ধ:
// set max threadpool count (default is 15)
status_t err = ProcessState::self()->setThreadPoolMaxThreadCount(numThreads);
// create threadpool
ProcessState::self()->startThreadPool();
// add current thread to threadpool (adds thread to max thread count)
IPCThreadState::self()->joinThreadPool();
একইভাবে, NDK ব্যাকএন্ডে:
bool success = ABinderProcess_setThreadPoolMaxThreadCount(numThreads);
ABinderProcess_startThreadPool();
ABinderProcess_joinThreadPool();
মরিচা ব্যাকএন্ডে:
binder::ProcessState::start_thread_pool();
binder::add_service(“myservice”, my_service_binder).expect(“Failed to register service?”);
binder::ProcessState::join_thread_pool();