एआईडीएल बैकएंड स्टब कोड जनरेशन के लिए एक लक्ष्य है। एआईडीएल फाइलों का उपयोग करते समय, आप हमेशा उन्हें एक विशेष भाषा में एक विशिष्ट रनटाइम के साथ उपयोग करते हैं। संदर्भ के आधार पर, आपको अलग-अलग एआईडीएल बैकएंड का उपयोग करना चाहिए।
एआईडीएल के निम्नलिखित बैकएंड हैं:
बैकएंड | भाषा | एपीआई सतह | सिस्टम बनाएं |
---|---|---|---|
जावा | जावा | SDK/SystemApi (स्थिर*) | सब |
एनडीके | सी ++ | libbinder_ndk (स्थिर*) | aidl_interface |
सीपीपी | सी ++ | लिबबाइंडर (अस्थिर) | सब |
जंग | जंग | libbinder_rs (अस्थिर) | aidl_interface |
- ये एपीआई सतहें स्थिर हैं, लेकिन कई एपीआई, जैसे सेवा प्रबंधन के लिए, आंतरिक प्लेटफॉर्म उपयोग के लिए आरक्षित हैं और ऐप्स के लिए उपलब्ध नहीं हैं। ऐप्स में AIDL का उपयोग कैसे करें, इस बारे में अधिक जानकारी के लिए, डेवलपर दस्तावेज़ीकरण देखें।
- एंड्रॉइड 12 में रस्ट बैकएंड पेश किया गया था; एनडीके बैकएंड एंड्रॉइड 10 के रूप में उपलब्ध है।
- रस्ट क्रेट
libbinder_ndk
के ऊपर बनाया गया है। एपेक्स बाइंडर क्रेट का उसी तरह उपयोग करते हैं जैसे सिस्टम साइड पर कोई और करता है। जंग वाले हिस्से को APEX में बांधा जाता है और उसके अंदर भेज दिया जाता है। यह सिस्टम विभाजन परlibbinder_ndk.so
पर निर्भर करता है।
सिस्टम बनाएं
बैकएंड के आधार पर, एआईडीएल को स्टब कोड में संकलित करने के दो तरीके हैं। बिल्ड सिस्टम के बारे में अधिक जानकारी के लिए सूंग मॉड्यूल संदर्भ देखें।
कोर बिल्ड सिस्टम
किसी भी cc_
या java_
Android.bp मॉड्यूल में (या उनके Android.mk
समकक्षों में), .aidl
फ़ाइलों को स्रोत फ़ाइलों के रूप में निर्दिष्ट किया जा सकता है। इस मामले में, एआईडीएल के जावा/सीपीपी बैकएंड का उपयोग किया जाता है (एनडीके बैकएंड नहीं), और संबंधित एआईडीएल फाइलों का उपयोग करने के लिए कक्षाएं स्वचालित रूप से मॉड्यूल में जोड़ दी जाती हैं। local_include_dirs
जैसे विकल्प, जो बिल्ड सिस्टम को उस मॉड्यूल में AIDL फ़ाइलों का रूट पथ बताते हैं, इन मॉड्यूल में एक aidl:
समूह के तहत निर्दिष्ट किया जा सकता है। ध्यान दें कि रस्ट बैकएंड केवल रस्ट के साथ उपयोग के लिए है। rust_
मॉड्यूल को अलग तरीके से संभाला जाता है क्योंकि एआईडीएल फाइलें स्रोत फाइलों के रूप में निर्दिष्ट नहीं होती हैं। इसके बजाय, aidl_interface
मॉड्यूल <aidl_interface name>-rust
नामक एक rustlib
उत्पन्न करता है, जिसके विरुद्ध लिंक किया जा सकता है। अधिक विवरण के लिए, जंग एआईडीएल उदाहरण देखें।
aidl_interface
स्थिर एआईडीएल देखें। इस बिल्ड सिस्टम के साथ उपयोग किए जाने वाले प्रकार संरचित होने चाहिए; यानी सीधे एआईडीएल में व्यक्त किया गया। इसका अर्थ है कि कस्टम पार्सलयोग्य का उपयोग नहीं किया जा सकता.
प्रकार
आप aidl
संकलक को प्रकारों के संदर्भ कार्यान्वयन के रूप में मान सकते हैं। जब आप एक इंटरफ़ेस बनाते हैं, तो परिणामी इंटरफ़ेस फ़ाइल देखने के लिए aidl --lang=<backend> ...
करें। जब आप aidl_interface
मॉड्यूल का उपयोग करते हैं, तो आप आउटपुट को out/soong/.intermediates/<path to module>/
में देख सकते हैं।
जावा/एआईडीएल प्रकार | सी ++ प्रकार | एनडीके प्रकार | जंग का प्रकार |
---|---|---|---|
बूलियन | बूल | बूल | बूल |
बाइट | int8_t | int8_t | i8 |
चार | char16_t | char16_t | यू 16 |
पूर्णांक | int32_t | int32_t | i32 |
लंबा | int64_t | int64_t | i64 |
पानी पर तैरना | पानी पर तैरना | पानी पर तैरना | f32 |
दोहरा | दोहरा | दोहरा | f64 |
डोरी | एंड्रॉइड :: स्ट्रिंग 16 | एसटीडी :: स्ट्रिंग | डोरी |
android.os.Parcelable | एंड्रॉइड :: पार्सल करने योग्य | लागू नहीं | लागू नहीं |
इबिंदर | एंड्रॉइड :: आईबिन्डर | ndk::SpAIBinder | बाइंडर :: स्पाइडर बाइंडर |
टी[] | एसटीडी :: वेक्टर <टी> | एसटीडी :: वेक्टर <टी> | में: &[टी] आउट: वीसी <टी> |
बाइट[] | एसटीडी :: वेक्टर <uint8_t> | एसटीडी :: वेक्टर <int8_t> 1 | में: &[u8] आउट: वेक<u8> |
सूची <टी> | एसटीडी :: वेक्टर <टी> 2 | एसटीडी :: वेक्टर <टी> 3 | में: &[टी] 4 आउट: वीसी <टी> |
फाइलडिस्क्रिप्टर | एंड्रॉइड :: बेस :: Unique_fd | लागू नहीं | बाइंडर :: पार्सल :: पार्सलफाइल डिस्क्रिप्टर |
ParcelFileDescriptor | एंड्रॉइड :: ओएस :: पार्सलफाइल डिस्क्रिप्टर | ndk :: ScopedFileDescriptor | बाइंडर :: पार्सल :: पार्सलफाइल डिस्क्रिप्टर |
इंटरफ़ेस प्रकार (टी) | एंड्रॉइड :: एसपी <टी> | एसटीडी :: साझा_ptr <टी> | बाइंडर :: मजबूत |
पार्सल योग्य प्रकार (टी) | टी | टी | टी |
संघ प्रकार (टी) 5 | टी | टी | टी |
टी [एन] 6 | एसटीडी :: सरणी <टी, एन> | एसटीडी :: सरणी <टी, एन> | [टी; एन] |
1. Android 12 या उच्चतर में, बाइट सरणियाँ संगतता कारणों से int8_t के बजाय uint8_t का उपयोग करती हैं।
2. C++ बैकएंड List<T>
को सपोर्ट करता है, जहां T
String
, IBinder
, ParcelFileDescriptor
या पार्सलेबल में से एक है। Android 13 या उच्चतर में, सरणियों को छोड़कर T
कोई भी गैर-आदिम प्रकार (इंटरफ़ेस प्रकार सहित) हो सकता है। एओएसपी अनुशंसा करता है कि आप T[]
जैसे सरणी प्रकारों का उपयोग करें, क्योंकि वे सभी बैकएंड में काम करते हैं।
3. एनडीके बैकएंड List<T>
का समर्थन करता है जहां T
String
, ParcelFileDescriptor
या पार्सल योग्य में से एक है। Android 13 या उच्चतर में, T
सरणियों को छोड़कर कोई भी गैर-आदिम प्रकार हो सकता है।
4. रस्ट कोड के लिए प्रकार अलग-अलग तरीके से पारित किए जाते हैं, जो इस बात पर निर्भर करता है कि वे इनपुट (एक तर्क), या एक आउटपुट (एक लौटाया गया मान) हैं।
5. एंड्रॉइड 12 और उच्चतर में यूनियन प्रकार समर्थित हैं।
6. एंड्रॉइड 13 या उच्चतर में, निश्चित आकार के सरणियों का समर्थन किया जाता है। निश्चित आकार की सरणियों में कई आयाम हो सकते हैं (उदाहरण के लिए int[3][4]
)। जावा बैकएंड में, निश्चित आकार के सरणियों को सरणी प्रकारों के रूप में दर्शाया जाता है।
दिशात्मकता (इन/आउट/इनआउट)
फ़ंक्शन के तर्कों के प्रकार निर्दिष्ट करते समय, आप उन्हें in
, out
, या inout
के रूप में निर्दिष्ट कर सकते हैं। यह नियंत्रित करता है कि IPC कॉल के लिए किस दिशा में जानकारी दी जाती है। in
डिफ़ॉल्ट दिशा है, और यह इंगित करता है कि कॉल करने वाले से प्राप्त करने वाले को डेटा पास किया गया है। out
का मतलब है कि कैली से कॉलर को डेटा पास किया जाता है। inout
इन दोनों का संयोजन है। हालाँकि, Android टीम अनुशंसा करती है कि आप तर्क विनिर्देशक inout
का उपयोग करने से बचें। यदि आप संस्करणित इंटरफ़ेस और पुराने कैली के साथ inout
का उपयोग करते हैं, तो केवल कॉलर में मौजूद अतिरिक्त फ़ील्ड उनके डिफ़ॉल्ट मानों पर रीसेट हो जाते हैं। जंग के संबंध में, एक सामान्य inout
प्रकार &mut Vec<T>
प्राप्त करता है, और एक सूची inout
प्रकार &mut Vec<T>
प्राप्त करता है।
यूटीएफ8/यूटीएफ16
सीपीपी बैकएंड के साथ आप चुन सकते हैं कि तार utf-8 या utf-16 हैं या नहीं। स्वचालित रूप से उन्हें utf-8 में बदलने के लिए AIDL में @utf8InCpp String
के रूप में स्ट्रिंग्स की घोषणा करें। NDK और Rust बैकएंड हमेशा utf-8 स्ट्रिंग्स का उपयोग करते हैं। utf8InCpp
एनोटेशन के बारे में अधिक जानकारी के लिए, एआईडीएल में एनोटेशन देखें।
अशक्तता
आप CPP और NDK बैकएंड में शून्य मानों को उजागर करने के लिए @nullable
के साथ जावा बैकएंड में रिक्त प्रकारों को एनोटेट कर सकते हैं। रस्ट बैकएंड में ये @nullable
प्रकार Option<T>
के रूप में सामने आते हैं। नेटिव सर्वर डिफ़ॉल्ट रूप से शून्य मानों को अस्वीकार करते हैं। इसका एकमात्र अपवाद interface
और IBinder
प्रकार हैं, जो एनडीके पढ़ने और सीपीपी/एनडीके लिखने के लिए हमेशा शून्य हो सकते हैं। अशक्त एनोटेशन के बारे में अधिक जानकारी के लिए nullable
में एनोटेशन देखें।
कस्टम पार्सल
कोर बिल्ड सिस्टम में सी ++ और जावा बैकएंड में, आप एक पार्सल योग्य घोषित कर सकते हैं जो लक्ष्य बैकएंड (सी ++ या जावा में) में मैन्युअल रूप से कार्यान्वित किया गया है।
package my.package;
parcelable Foo;
या सी ++ हेडर घोषणा के साथ:
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
होते हैं।
अन्य बैकएंड में, डिफ़ॉल्ट मानों को परिभाषित नहीं किए जाने पर फ़ील्ड को डिफ़ॉल्ट प्रारंभिक मानों के साथ प्रारंभ किया जाता है। उदाहरण के लिए, सी ++ बैकएंड में, String
फ़ील्ड को खाली स्ट्रिंग के रूप में प्रारंभ किया जाता है और List<T>
फ़ील्ड को खाली vector<T>
के रूप में प्रारंभ किया जाता है। @nullable
फ़ील्ड को शून्य-मान फ़ील्ड के रूप में प्रारंभ किया गया है।
त्रुटि प्रबंधन
Android OS त्रुटियों की रिपोर्ट करते समय सेवाओं का उपयोग करने के लिए अंतर्निहित त्रुटि प्रकार प्रदान करता है। इनका उपयोग बाइंडर द्वारा किया जाता है और बाइंडर इंटरफ़ेस को लागू करने वाली किसी भी सेवा द्वारा उपयोग किया जा सकता है। उनका उपयोग एआईडीएल परिभाषा में अच्छी तरह से प्रलेखित है और उन्हें किसी उपयोगकर्ता-परिभाषित स्थिति या रिटर्न प्रकार की आवश्यकता नहीं है।
त्रुटियों के साथ आउटपुट पैरामीटर
जब कोई एआईडीएल फ़ंक्शन किसी त्रुटि की रिपोर्ट करता है, तो फ़ंक्शन आउटपुट पैरामीटर को प्रारंभ या संशोधित नहीं कर सकता है। विशेष रूप से, आउटपुट मापदंडों को संशोधित किया जा सकता है यदि त्रुटि अनपार्सलिंग के दौरान होती है जैसा कि लेन-देन के प्रसंस्करण के दौरान होने के विपरीत होता है। सामान्य तौर पर, एआईडीएल फ़ंक्शन से त्रुटि प्राप्त होने पर, सभी inout
और out
पैरामीटर के साथ-साथ वापसी मान (जो कुछ बैकेंड में out
पैरामीटर की तरह कार्य करता है) को अनिश्चित स्थिति में माना जाना चाहिए।
किस त्रुटि मान का उपयोग करना है
कई अंतर्निहित त्रुटि मान किसी भी एआईडीएल इंटरफेस में उपयोग किए जा सकते हैं, लेकिन कुछ को एक विशेष तरीके से व्यवहार किया जाता है। उदाहरण के लिए, जब वे त्रुटि स्थिति का वर्णन करते हैं तो EX_UNSUPPORTED_OPERATION
और EX_ILLEGAL_ARGUMENT
का उपयोग करना ठीक है, लेकिन EX_TRANSACTION_FAILED
का उपयोग नहीं किया जाना चाहिए क्योंकि इसे अंतर्निहित बुनियादी ढांचे द्वारा विशेष माना जाता है। इन अंतर्निर्मित मूल्यों पर अधिक जानकारी के लिए बैकएंड विशिष्ट परिभाषाओं की जाँच करें।
यदि एआईडीएल इंटरफ़ेस को अतिरिक्त त्रुटि मानों की आवश्यकता होती है जो अंतर्निहित त्रुटि प्रकारों द्वारा कवर नहीं होते हैं, तो वे विशेष सेवा-विशिष्ट अंतर्निहित त्रुटि का उपयोग कर सकते हैं जो उपयोगकर्ता द्वारा परिभाषित सेवा-विशिष्ट त्रुटि मान को शामिल करने की अनुमति देता है। . इन सेवा-विशिष्ट त्रुटियों को आमतौर पर AIDL इंटरफ़ेस में const int
या int
enum
एनम के रूप में परिभाषित किया जाता है और बाइंडर द्वारा पार्स नहीं किया जाता है।
जावा में, त्रुटियाँ अपवादों को मैप करती हैं, जैसे कि android.os.RemoteException
। सेवा-विशिष्ट अपवादों के लिए, जावा उपयोगकर्ता परिभाषित त्रुटि के साथ android.os.ServiceSpecificException
का उपयोग करता है।
एंड्रॉइड में मूल कोड अपवादों का उपयोग नहीं करता है। सीपीपी बैकएंड android::binder::Status
का उपयोग करता है। एनडीके बैकएंड 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;
या सीपीपी बैकएंड में:
#include <my/package/IFoo.h>
या aidl
बैकएंड में (अतिरिक्त सहायता नामस्थान देखें):
#include <aidl/my/package/IFoo.h>
या रस्ट बैकएंड में:
use my_package::aidl::my::package::IFoo;
यद्यपि आप जावा में एक नेस्टेड प्रकार आयात कर सकते हैं, CPP/NDK बैकएंड में आपको इसके रूट प्रकार के लिए हेडर शामिल करना होगा। उदाहरण के लिए, my/package/IFoo.aidl
( IFoo
फ़ाइल का मूल प्रकार है) में परिभाषित एक नेस्टेड प्रकार Bar
आयात करते समय आपको CPP बैकएंड के लिए <my/package/IFoo.h>
शामिल करना होगा (या <aidl/my/package/IFoo.h>
NDK बैकएंड के लिए)।
सेवाओं को लागू करना
किसी सेवा को लागू करने के लिए, आपको मूल स्टब क्लास से इनहेरिट करनी होगी। यह वर्ग बाइंडर ड्राइवर से आदेश पढ़ता है और आपके द्वारा कार्यान्वित विधियों को निष्पादित करता है। कल्पना कीजिए कि आपके पास एआईडीएल फ़ाइल इस तरह है:
package my.package;
interface IFoo {
int doFoo();
}
जावा में, आपको इस वर्ग से विस्तार करना होगा:
import my.package.IFoo;
public class MyFoo extends IFoo.Stub {
@Override
int doFoo() { ... }
}
सीपीपी बैकएंड में:
#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(())
}
}
पंजीकरण और सेवाएं प्राप्त करना
प्लेटफ़ॉर्म Android में सेवाएँ आमतौर पर servicemanager
प्रक्रिया के साथ पंजीकृत होती हैं। नीचे दिए गए एपीआई के अलावा, कुछ एपीआई सेवा की जांच करते हैं (यानी सेवा उपलब्ध नहीं होने पर वे तुरंत वापस आ जाते हैं)। सटीक विवरण के लिए संबंधित servicemanager
इंटरफ़ेस की जाँच करें। ये ऑपरेशन केवल तभी किए जा सकते हैं जब प्लेटफ़ॉर्म Android के विरुद्ध संकलन किया जाए।
जावा में:
import android.os.ServiceManager;
// registering
ServiceManager.addService("service-name", myService);
// return if service is started now
myService = IFoo.Stub.asInterface(ServiceManager.checkService("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"));
सीपीपी बैकएंड में:
#include <binder/IServiceManager.h>
// registering
defaultServiceManager()->addService(String16("service-name"), myService);
// return if service is started now
status_t err = checkService<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");
// return if service is started now
myService = IFoo::fromBinder(SpAIBinder(AServiceManager_checkService("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
का उपयोग करें। - सीपीपी बैकएंड में,
android::IBinder::linkToDeath
का उपयोग करें। - NDK बैकएंड में,
AIBinder_linkToDeath
का उपयोग करें। - रस्ट बैकएंड में,
DeathRecipient
ऑब्जेक्ट बनाएं, फिरmy_binder.link_to_death(&mut my_death_recipient)
कॉल करें। ध्यान दें कि क्योंकिDeathRecipient
कॉलबैक का मालिक है, आपको उस वस्तु को तब तक जीवित रखना चाहिए जब तक आप सूचनाएं प्राप्त करना चाहते हैं।
कॉलर जानकारी
कर्नेल बाइंडर कॉल प्राप्त करते समय, कॉलर जानकारी कई एपीआई में उपलब्ध होती है। पीआईडी (या प्रोसेस आईडी) प्रक्रिया की लिनक्स प्रक्रिया आईडी को संदर्भित करता है जो लेनदेन भेज रहा है। यूआईडी (या यूजर आईडी) लिनक्स यूजर आईडी को संदर्भित करता है। एकतरफा कॉल प्राप्त करते समय, कॉलिंग पीआईडी 0 है। बाइंडर लेनदेन संदर्भ के बाहर होने पर, ये फ़ंक्शन वर्तमान प्रक्रिया के पीआईडी और यूआईडी को वापस कर देते हैं।
जावा बैकएंड में:
... = Binder.getCallingPid();
... = Binder.getCallingUid();
सीपीपी बैकएंड में:
... = IPCThreadState::self()->getCallingPid();
... = IPCThreadState::self()->getCallingUid();
एनडीके बैकएंड में:
... = AIBinder_getCallingPid();
... = AIBinder_getCallingUid();
रस्ट बैकएंड में, इंटरफ़ेस को लागू करते समय, निम्नलिखित निर्दिष्ट करें (इसे डिफ़ॉल्ट रूप से अनुमति देने के बजाय):
... = ThreadState::get_calling_pid();
... = ThreadState::get_calling_uid();
बग रिपोर्ट और सेवाओं के लिए डिबगिंग एपीआई
जब बगरेपोर्ट चलते हैं (उदाहरण के लिए, adb bugreport
के साथ), तो वे विभिन्न मुद्दों को डीबग करने में मदद करने के लिए पूरे सिस्टम से जानकारी एकत्र करते हैं। एआईडीएल सेवाओं के लिए, बगरेपोर्ट सेवा प्रबंधक के साथ पंजीकृत सभी सेवाओं पर बाइनरी dumpsys
का उपयोग करते हैं ताकि उनकी जानकारी को बगरेपोर्ट में डाला जा सके। आप dumpsys SERVICE [ARGS]
के साथ सेवा से जानकारी प्राप्त करने के लिए कमांडलाइन पर dumpsys
का भी उपयोग कर सकते हैं। सी ++ और जावा बैकएंड में, आप उस क्रम को नियंत्रित कर सकते हैं जिसमें सेवा जोड़ने के लिए अतिरिक्त तर्कों का उपयोग करके सेवाओं को addService
किया जाता है। डिबगिंग के दौरान किसी सेवा की पीआईडी प्राप्त करने के लिए आप dumpsys --pid SERVICE
का भी उपयोग कर सकते हैं।
अपनी सेवा में कस्टम आउटपुट जोड़ने के लिए, आप अपने सर्वर ऑब्जेक्ट में dump
विधि को ओवरराइड कर सकते हैं जैसे कि आप एआईडीएल फ़ाइल में परिभाषित किसी अन्य आईपीसी विधि को कार्यान्वित कर रहे हैं। ऐसा करते समय, आपको डंपिंग को ऐप की अनुमति android.permission.DUMP
तक सीमित कर देना चाहिए या डंपिंग को विशिष्ट यूआईडी तक सीमित कर देना चाहिए।
जावा बैकएंड में:
@Override
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
@Nullable String[] args) {...}
सीपीपी बैकएंड में:
status_t dump(int, const android::android::Vector<android::String16>&) override;
एनडीके बैकएंड में:
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();
सीपीपी बैकएंड में:
service = /* get ahold of service object */
... = IInterface::asBinder(service)->getInterfaceDescriptor();
एनडीके और जंग बैकएंड इस कार्यक्षमता का समर्थन नहीं करते हैं।
स्थिर रूप से इंटरफ़ेस डिस्क्रिप्टर प्राप्त करना
कभी-कभी (जैसे कि @VintfStability
सेवाओं को पंजीकृत करते समय), आपको यह जानना होगा कि इंटरफ़ेस डिस्क्रिप्टर स्थिर रूप से क्या है। जावा में, आप कोड जोड़कर डिस्क्रिप्टर प्राप्त कर सकते हैं जैसे:
import my.package.IFoo;
... IFoo.DESCRIPTOR
सीपीपी बैकएंड में:
#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()
एनम रेंज
देशी बैकएंड में, आप उन संभावित मानों पर पुनरावृति कर सकते हैं जो एक एनुम ले सकता है। कोड आकार के विचारों के कारण, यह वर्तमान में जावा में समर्थित नहीं है।
एआईडीएल में परिभाषित MyEnum
के लिए, पुनरावृत्ति निम्नानुसार प्रदान की जाती है।
सीपीपी बैकएंड में:
::android::enum_range<MyEnum>()
एनडीके बैकएंड में:
::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();
इसी प्रकार, एनडीके बैकएंड में:
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();
आरक्षित नाम
C++, Java, और Rust कुछ नामों को कीवर्ड या भाषा-विशिष्ट उपयोग के लिए आरक्षित रखते हैं। जबकि एआईडीएल भाषा नियमों के आधार पर प्रतिबंधों को लागू नहीं करता है, आरक्षित नाम से मेल खाने वाले फ़ील्ड या प्रकार के नामों का उपयोग सी ++ या जावा के लिए संकलन विफलता का परिणाम हो सकता है। जंग के लिए, फ़ील्ड या प्रकार का नाम बदलकर "रॉ आइडेंटिफ़ायर" सिंटैक्स का उपयोग किया जाता है, जिसे r#
उपसर्ग का उपयोग करके एक्सेस किया जा सकता है।
हम अनुशंसा करते हैं कि आप अपनी एआईडीएल परिभाषाओं में आरक्षित नामों का उपयोग करने से बचें, जहां संभव हो कि गैर-अर्जितिक बंधनों या एकमुश्त संकलन विफलता से बचा जा सके।
यदि आपके पास पहले से ही आपकी एआईडीएल परिभाषाओं में आरक्षित नाम हैं, तो आप प्रोटोकॉल संगत रहते हुए सुरक्षित रूप से फ़ील्ड का नाम बदल सकते हैं; निर्माण जारी रखने के लिए आपको अपना कोड अपडेट करने की आवश्यकता हो सकती है, लेकिन पहले से निर्मित कोई भी प्रोग्राम इंटरऑपरेट करना जारी रखेगा।
बचने के लिए नाम: * सी ++ कीवर्ड्स * जावा कीवर्ड्स * जंग कीवर्ड्स