बाइंडर आईपीसी का इस्तेमाल करें

इस पेज पर, Android 8 में बाइंडर ड्राइवर में हुए बदलावों के बारे में बताया गया है. साथ ही, बाइंडर आईपीसी का इस्तेमाल करने के बारे में जानकारी दी गई है. साथ ही, ज़रूरी SELinux नीति की सूची दी गई है.

बाइंडर ड्राइवर में हुए बदलाव

Android 8 से, Android फ़्रेमवर्क और एचएएल अब बाइंडर का इस्तेमाल करके एक-दूसरे से बातचीत करते हैं. इस बातचीत से, बाइंडर ट्रैफ़िक काफ़ी बढ़ जाता है. इसलिए, Android 8 में कई सुधार किए गए हैं, ताकि बाइंडर आईपीसी को तेज़ रखा जा सके. SoC वेंडर और OEM को सीधे kernel/common प्रोजेक्ट के android-4.4, android-4.9, और उसके बाद के वर्शन की काम की शाखाओं से मर्ज करना चाहिए.

एक से ज़्यादा बाइंडर डोमेन (कॉन्टेक्स्ट)

Common-4.4 और उसके बाद के वर्शन, जिनमें अपस्ट्रीम भी शामिल है

Android 8 में बाइंडर कॉन्टेक्स्ट का कॉन्सेप्ट जोड़ा गया है. इससे, बाइंडर ट्रैफ़िक को फ़्रेमवर्क (डिवाइस पर निर्भर नहीं) और वेंडर (डिवाइस पर निर्भर) कोड के बीच आसानी से बांटा जा सकता है. हर बाइंडर कॉन्टेक्स्ट का अपना डिवाइस नोड और अपना कॉन्टेक्स्ट (सेवा) मैनेजर होता है. कॉन्टेक्स्ट मैनेजर को सिर्फ़ उस डिवाइस नोड के ज़रिए ऐक्सेस किया जा सकता है जिससे वह जुड़ा है. साथ ही, किसी खास कॉन्टेक्स्ट के ज़रिए बाइंडर नोड को पास करते समय, उसे उसी कॉन्टेक्स्ट से सिर्फ़ दूसरी प्रोसेस के ज़रिए ऐक्सेस किया जा सकता है. इस तरह, डोमेन को एक-दूसरे से पूरी तरह से अलग किया जाता है. इस्तेमाल करने के बारे में ज़्यादा जानने के लिए, vndbinder और vndservicemanager देखें.

स्कैटर-इकट्ठा करना

Common-4.4 और उसके बाद के वर्शन, जिनमें अपस्ट्रीम भी शामिल है

Android के पिछले वर्शन में, बाइंडर कॉल में मौजूद हर डेटा को तीन बार कॉपी किया जाता था:

  • कॉल करने की प्रोसेस में, इसे Parcel में बदलने के लिए एक बार
  • Parcel को टारगेट प्रोसेस में कॉपी करने के लिए, kernel ड्राइवर में
  • टारगेट प्रोसेस में Parcel को अनसीरियलाइज़ करने के लिए एक बार

Android 8, कॉपी की संख्या को तीन से घटाकर एक करने के लिए, स्कैटर-इकट्ठा करने की सुविधा के ऑप्टिमाइज़ेशन का इस्तेमाल करता है. डेटा को पहले Parcel में सीरियलाइज़ करने के बजाय, डेटा अपने मूल स्ट्रक्चर और मेमोरी लेआउट में ही रहता है. साथ ही, ड्राइवर उसे तुरंत टारगेट प्रोसेस में कॉपी कर देता है. डेटा टारगेट प्रोसेस में आने के बाद, उसका स्ट्रक्चर और मेमोरी लेआउट एक जैसा होता है. साथ ही, डेटा को दूसरी कॉपी के बिना पढ़ा जा सकता है.

ज़्यादा सटीक लॉकिंग

Common-4.4 और उसके बाद के वर्शन, जिनमें अपस्ट्रीम भी शामिल है

Android की पिछली रिलीज़ में, बाइंडर ड्राइवर ने ज़रूरी डेटा स्ट्रक्चर को एक साथ ऐक्सेस होने से बचाने के लिए, ग्लोबल लॉक का इस्तेमाल किया था. लॉक के लिए कम मुकाबला होने के बावजूद, मुख्य समस्या यह थी कि अगर कम प्राथमिकता वाली थ्रेड को लॉक मिल जाता है और फिर उसे रोक दिया जाता है, तो उसी लॉक को पाने के लिए ज़्यादा प्राथमिकता वाली थ्रेड को काफ़ी देरी हो सकती है. इससे प्लैटफ़ॉर्म पर रुकावट आती है.

इस समस्या को हल करने के शुरुआती प्रयासों में, ग्लोबल लॉक को बनाए रखते हुए, प्रीएमपशन को बंद करना शामिल था. हालांकि, यह सही समाधान के बजाय एक हैक था. इसलिए, इसे अपस्ट्रीम ने अस्वीकार कर दिया और उसे खारिज कर दिया गया. इसके बाद, हमने लॉक करने की सुविधा को ज़्यादा बेहतर बनाने पर काम किया. इसका एक वर्शन, जनवरी 2017 से Pixel डिवाइसों पर काम कर रहा है. हालांकि, ज़्यादातर बदलावों को सार्वजनिक कर दिया गया था, लेकिन बाद के वर्शन में काफ़ी सुधार किए गए.

ज़्यादा सटीक तरीके से लॉक करने की सुविधा को लागू करने में आ रही छोटी समस्याओं की पहचान करने के बाद, हमने लॉक करने के लिए अलग-अलग तरीके का इस्तेमाल करके, बेहतर समाधान तैयार किया. साथ ही, सभी सामान्य कर्नेल शाखाओं में बदलाव सबमिट किए. हम इस तरीके को कई डिवाइसों पर टेस्ट कर रहे हैं. हमें कोई समस्या नहीं मिली है. इसलिए, हमारा सुझाव है कि Android 8 वाले डिवाइसों पर इस तरीके का इस्तेमाल करें.

रीयल-टाइम में प्राथमिकता इनहेरिट करना

Common-4.4 और common-4.9 (अपस्ट्रीम जल्द ही उपलब्ध होगा)

बाइंडर ड्राइवर, प्राथमिकता के इनहेरिटेंस के साथ हमेशा काम करता है. Android में रीयल-टाइम प्राथमिकता पर चलने वाली प्रोसेस की संख्या बढ़ रही है. इसलिए, कुछ मामलों में यह समझ आता है कि अगर कोई रीयल-टाइम थ्रेड, बाइंडर कॉल करता है, तो उस कॉल को मैनेज करने वाली प्रोसेस में मौजूद थ्रेड भी रीयल-टाइम प्राथमिकता पर चलती है. इन इस्तेमाल के उदाहरणों के साथ काम करने के लिए, Android 8 अब बाइंडर ड्राइवर में रीयल-टाइम प्राथमिकता इनहेरिटेंस लागू करता है.

लेन-देन के लेवल पर प्राथमिकता के इनहेरिटेंस के अलावा, नोड की प्राथमिकता के इनहेरिटेंस की मदद से, किसी नोड (बाइंडर सेवा ऑब्जेक्ट) में कम से कम प्राथमिकता तय की जा सकती है. Android के पिछले वर्शन में, अच्छी वैल्यू के साथ नोड की प्राथमिकता के इनहेरिटेंस की सुविधा पहले से ही मौजूद थी. हालांकि, Android 8 में रीयल-टाइम शेड्यूलिंग नीतियों के नोड इनहेरिटेंस की सुविधा जोड़ी गई है.

Userspace में हुए बदलाव

Android 8 में, यूज़रस्पेस में किए गए सभी बदलाव शामिल हैं. ये बदलाव, सामान्य कर्नेल में मौजूद मौजूदा बाइंडर ड्राइवर के साथ काम करने के लिए ज़रूरी हैं. हालांकि, इसमें एक अपवाद है: /dev/binder के लिए रीयल-टाइम प्राथमिकता इनहेरिटेंस को बंद करने के लिए, ओरिजनल तरीके में ioctl का इस्तेमाल किया गया था. इसके बाद के डेवलपमेंट में, प्राथमिकता के इनहेरिटेंस के कंट्रोल को ज़्यादा बेहतर तरीके पर स्विच किया गया. यह तरीका हर बाइंडर मोड के हिसाब से होता है, न कि हर कॉन्टेक्स्ट के हिसाब से. इसलिए, ioctl, Android की सामान्य शाखा में नहीं है. इसके बजाय, इसे हमारे सामान्य कर्नेल में सबमिट किया गया है.

इस बदलाव का असर यह हुआ है कि हर नोड के लिए, रियल-टाइम प्राथमिकता इनहेरिटेंस डिफ़ॉल्ट रूप से बंद है. Android की परफ़ॉर्मेंस टीम को पता चला है कि hwbinder डोमेन के सभी नोड के लिए, रीयल-टाइम प्राथमिकता इनहेरिटेंस की सुविधा चालू करना फ़ायदेमंद है. वही इफ़ेक्ट पाने के लिए, यूज़रस्पेस में यह बदलाव चुनें.

सामान्य कर्नेल के लिए SHA

बाइंडर ड्राइवर में ज़रूरी बदलाव करने के लिए, सही SHA के साथ सिंक करें:

  • Common-3.18
    cc8b90c121de ANDROID: binder: don't check prio permissions on restore.
  • Common-4.4
    76b376eac7a2 ANDROID: binder: don't check prio permissions on restore.
  • Common-4.9
    ecd972d4f9b5 ANDROID: binder: don't check prio permissions on restore.

बाइंडर आईपीसी के साथ काम करना

अब तक, वेंडर प्रोसेस, कम्यूनिकेट करने के लिए बाइंडर इंटरप्रोसेस कम्यूनिकेशन (आईपीसी) का इस्तेमाल करती रही हैं. Android 8 में, /dev/binder डिवाइस नोड, फ़्रेमवर्क प्रोसेस के लिए खास तौर पर उपलब्ध होता है. इसका मतलब है कि वेंडर प्रोसेस के पास अब इसका ऐक्सेस नहीं होता. वेंडर प्रोसेस, /dev/hwbinder को ऐक्सेस कर सकती हैं. हालांकि, HIDL का इस्तेमाल करने के लिए, उन्हें अपने एआईडीएल इंटरफ़ेस को बदलना होगा. वेंडर प्रोसेस के बीच, AIDL इंटरफ़ेस का इस्तेमाल जारी रखने वाले वेंडर के लिए, Android यहां बताए गए तरीके के हिसाब से बाइंडर आईपीसी के साथ काम करता है. Android 10 में, Stable AIDL की मदद से सभी प्रोसेस, /dev/binder का इस्तेमाल कर सकती हैं. साथ ही, HIDL और /dev/hwbinder की स्थिरता की गारंटी भी मिलती है. स्टेबल एआईडीएल का इस्तेमाल करने का तरीका जानने के लिए, एचएएल के लिए एआईडीएल लेख पढ़ें.

vndbinder

Android 8 में, वेंडर की सेवाओं के इस्तेमाल के लिए एक नया बाइंडर डोमेन उपलब्ध है. इसे /dev/binder के बजाय /dev/vndbinder का इस्तेमाल करके ऐक्सेस किया जाता है. /dev/vndbinder के जुड़ने के बाद, Android में अब ये तीन आईपीसी डोमेन हैं:

आईपीसी डोमेन ब्यौरा
/dev/binder AIDL इंटरफ़ेस वाले फ़्रेमवर्क/ऐप्लिकेशन प्रोसेस के बीच आईपीसी
/dev/hwbinder HIDL इंटरफ़ेस वाले फ़्रेमवर्क/वेंडर प्रोसेस के बीच आईपीसी
HIDL इंटरफ़ेस वाले वेंडर प्रोसेस के बीच आईपीसी
/dev/vndbinder AIDL इंटरफ़ेस की मदद से, वेंडर/वेंडर प्रोसेस के बीच आईपीसी

/dev/vndbinder दिखने के लिए, पक्का करें कि कर्नेल कॉन्फ़िगरेशन आइटम CONFIG_ANDROID_BINDER_DEVICES को "binder,hwbinder,vndbinder" पर सेट किया गया हो. यह Android के सामान्य कर्नेल ट्री में डिफ़ॉल्ट रूप से सेट होता है.

आम तौर पर, वेंडर प्रोसेस सीधे बाइंडर ड्राइवर को नहीं खोलती हैं. इसके बजाय, वे libbinder यूज़रस्पेस लाइब्रेरी से लिंक करती हैं, जो बाइंडर ड्राइवर को खोलती है. ::android::ProcessState() के लिए कोई तरीका जोड़ने पर, libbinder के लिए बाइंडर ड्राइवर चुन लिया जाता है. वेंडर प्रोसेस को ProcessState, IPCThreadState को कॉल करने से पहले या सामान्य तौर पर कोई भी बाइंडर कॉल करने से पहले, इस मेथड को कॉल करना चाहिए. इस्तेमाल करने के लिए, वेंडर प्रोसेस (क्लाइंट और सर्वर) के main() के बाद यह कॉल करें:

ProcessState::initWithDriver("/dev/vndbinder");

vndservicemanager

पहले, बाइंडर सेवाओं को servicemanager के साथ रजिस्टर किया जाता था, जहां उन्हें अन्य प्रोसेस से वापस पाया जा सकता था. Android 8 में, servicemanager का इस्तेमाल अब सिर्फ़ फ़्रेमवर्क और ऐप्लिकेशन प्रोसेस के लिए किया जाता है. वेंडर प्रोसेस अब इसे ऐक्सेस नहीं कर सकतीं.

हालांकि, वेंडर सेवाएं अब vndservicemanager का इस्तेमाल कर सकती हैं. यह servicemanager का एक नया इंस्टेंस है, जो /dev/binder के बजाय /dev/vndbinder का इस्तेमाल करता है. साथ ही, इसे फ़्रेमवर्क servicemanager के जैसे ही सोर्स से बनाया गया है. vndservicemanager से बात करने के लिए, वेंडर प्रोसेस में बदलाव करने की ज़रूरत नहीं होती. जब कोई वेंडर प्रोसेस dev/vndbinder खोलती है, तो सेवा लुकअप अपने-आप vndservicemanager पर जाते हैं.

vndservicemanager बाइनरी, Android के डिफ़ॉल्ट डिवाइस मेकफ़ाइल में शामिल होती है.

SELinux नीति

वेंडर की जिन प्रोसेस को एक-दूसरे के साथ कम्यूनिकेट करने के लिए, बाइंडर की सुविधा का इस्तेमाल करना है उन्हें इन चीज़ों की ज़रूरत होगी:

  1. /dev/vndbinder का ऐक्सेस.
  2. बाइंडर {transfer, call}, vndservicemanager में हुक करता है.
  3. binder_call(A, B), वेंडर बाइंडर इंटरफ़ेस के ज़रिए, वेंडर डोमेन B को कॉल करने वाले किसी भी वेंडर डोमेन A के लिए.
  4. vndservicemanager में {add, find} सेवाओं के इस्तेमाल की अनुमति.

पहली और दूसरी ज़रूरी शर्तें पूरी करने के लिए, vndbinder_use() मैक्रो का इस्तेमाल करें:

vndbinder_use(some_vendor_process_domain);

तीसरी शर्त को पूरा करने के लिए, वेंडर की प्रोसेस A और B के लिए binder_call(A, B) को बाइंडर के साथ काम करने की ज़रूरत है. इसलिए, इसे बदलने की ज़रूरत नहीं है.

चौथी ज़रूरी शर्त को पूरा करने के लिए, आपको सेवा के नाम, सेवा के लेबल, और नियमों को मैनेज करने के तरीके में बदलाव करने होंगे.

SELinux के बारे में ज़्यादा जानने के लिए, Android में बेहतर सुरक्षा के लिए Linux लेख पढ़ें. Android 8.0 में SELinux के बारे में ज़्यादा जानने के लिए, Android 8.0 के लिए SELinux लेख पढ़ें.

सेवा के नाम

पहले, वेंडर रजिस्टर की गई सेवा के नामों को service_contexts फ़ाइल में प्रोसेस करता था और उस फ़ाइल को ऐक्सेस करने के लिए, उससे जुड़े नियम जोड़ता था. device/google/marlin/sepolicy से मिली service_contexts फ़ाइल का उदाहरण:

AtCmdFwd                              u:object_r:atfwd_service:s0
cneservice                            u:object_r:cne_service:s0
qti.ims.connectionmanagerservice      u:object_r:imscm_service:s0
rcs                                   u:object_r:radio_service:s0
uce                                   u:object_r:uce_service:s0
vendor.qcom.PeripheralManager         u:object_r:per_mgr_service:s0

Android 8 में, vndservicemanager के बजाय vndservice_contexts फ़ाइल लोड होती है. वेंडर की ऐसी सेवाओं को vndservicemanager पर माइग्रेट किया जाना चाहिए जो पहले से ही service_contexts फ़ाइल में मौजूद हैं. साथ ही, उन्हें नई vndservice_contexts फ़ाइल में जोड़ना चाहिए.

सेवा लेबल

पहले, u:object_r:atfwd_service:s0 जैसे सेवा लेबल को service.te फ़ाइल में तय किया जाता था. उदाहरण:

type atfwd_service,      service_manager_type;

Android 8 में, आपको टाइप को vndservice_manager_type में बदलना होगा और नियम को vndservice.te फ़ाइल में ले जाना होगा. उदाहरण:

type atfwd_service,      vndservice_manager_type;

servicemanager के नियम

पहले, नियमों के तहत डोमेन को servicemanager से सेवाएं जोड़ने या खोजने का ऐक्सेस दिया जाता था. उदाहरण:

allow atfwd atfwd_service:service_manager find;
allow some_vendor_app atfwd_service:service_manager add;

Android 8 में, ऐसे नियम लागू रहेंगे और उसी क्लास का इस्तेमाल किया जाएगा. उदाहरण:

allow atfwd atfwd_service:service_manager find;
allow some_vendor_app atfwd_service:service_manager add;