गाड़ी के कैमरा एचएएल

Android में ऑटोमोटिव HIDL हार्डवेयर एब्स्ट्रैक्शन लेयर (एचएएल) होता है. यह Android की बूट प्रोसेस के शुरुआती चरणों में ही इमेज कैप्चर और डिसप्ले करने की सुविधा देता है. साथ ही, सिस्टम के बंद होने तक काम करता रहता है. एचएएल में बाहरी व्यू सिस्टम (ईवीएस) स्टैक शामिल होता है. इसका इस्तेमाल आम तौर पर, Android पर आधारित इन-वाहन मनोरंजन (आईवीआई) सिस्टम वाली गाड़ियों में, पीछे देखने वाले कैमरे और चारों तरफ़ दिखने वाले व्यू के डिसप्ले के साथ काम करने के लिए किया जाता है. ईवीएस की मदद से, उपयोगकर्ता के ऐप्लिकेशन में बेहतर सुविधाएं भी लागू की जा सकती हैं.

Android में, /hardware/interfaces/automotive/evs/1.0 में EVS के हिसाब से कैप्चर और डिसप्ले ड्राइवर इंटरफ़ेस भी शामिल है. हालांकि, Android के मौजूदा कैमरे और डिसप्ले सेवाओं के ऊपर, रियरव्यू कैमरा ऐप्लिकेशन बनाया जा सकता है, लेकिन ऐसा ऐप्लिकेशन Android की बूट प्रोसेस में बहुत देर से चलेगा. खास तौर पर बनाए गए एचएएल का इस्तेमाल करने से बेहतर इंटरफ़ेस चालू होता है. साथ ही, इससे यह पता चलता है कि ईवीएस स्टैक के साथ काम करने के लिए, OEM को क्या लागू करना होगा.

सिस्टम के कॉम्पोनेंट

ईवीएस में ये सिस्टम कॉम्पोनेंट शामिल होते हैं:

ईवीएस सिस्टम के घटकों का डायग्राम
पहली इमेज. ईवीएस सिस्टम के कॉम्पोनेंट की खास जानकारी.

ईवीएस ऐप्लिकेशन

C++ EVS ऐप्लिकेशन का एक सैंपल (/packages/services/Car/evs/app), रेफ़रंस के तौर पर काम करता है. यह ऐप्लिकेशन, ईवीएस मैनेजर से वीडियो फ़्रेम का अनुरोध करने और डिसप्ले के लिए तैयार फ़्रेम को ईवीएस मैनेजर को वापस भेजने के लिए ज़िम्मेदार होता है. यह उम्मीद की जाती है कि ईवीएस और कार सर्विस के उपलब्ध होते ही, यह सुविधा शुरू हो जाएगी. साथ ही, इसे चालू करने के दो (2) सेकंड के अंदर टारगेट किया जाएगा. OEM, अपनी पसंद के मुताबिक EVS ऐप्लिकेशन में बदलाव कर सकते हैं या उसे बदल सकते हैं.

ईवीएस मैनेजर

ईवीएस मैनेजर (/packages/services/Car/evs/manager), ईवीएस ऐप्लिकेशन के लिए ज़रूरी बुनियादी चीज़ें उपलब्ध कराता है. इनकी मदद से, पीछे की तरफ़ दिखने वाले कैमरे के आसान डिसप्ले से लेकर, 6डीओएफ़ वाले मल्टी-कैमरा रेंडरिंग तक, कुछ भी लागू किया जा सकता है. इसका इंटरफ़ेस, HIDL के ज़रिए दिखाया जाता है. साथ ही, इसे एक साथ कई क्लाइंट स्वीकार करने के लिए बनाया गया है. अन्य ऐप्लिकेशन और सेवाएं (खास तौर पर, कार सेवा), ईवीएस मैनेजर की स्थिति के बारे में क्वेरी कर सकती हैं, ताकि यह पता लगाया जा सके कि ईवीएस सिस्टम कब चालू है.

EVS HIDL इंटरफ़ेस

ईवीएस सिस्टम, कैमरा, और डिसप्ले एलिमेंट, दोनों को android.hardware.automotive.evs पैकेज में तय किया गया है. /hardware/interfaces/automotive/evs/1.0/default में, इंटरफ़ेस को इस्तेमाल करने का एक सैंपल दिया गया है. इसमें, सिंथेटिक टेस्ट इमेज जनरेट की जाती हैं और यह पुष्टि की जाती है कि इमेज, राउंड ट्रिप करती हैं.

/hardware/interfaces/automotive/evs में .hal फ़ाइलों के ज़रिए बताए गए एपीआई को लागू करने की ज़िम्मेदारी OEM की है. इस तरह के काम करने की ज़िम्मेदारी, फ़िज़िकल कैमरों से डेटा को कॉन्फ़िगर करने और इकट्ठा करने की होती है. साथ ही, इसे शेयर की गई मेमोरी बफ़र की मदद से डिलीवर करने की ज़िम्मेदारी भी होती है, जिसे Gralloc के ज़रिए पहचाना जा सकता है. डिसप्ले के हिस्से को, शेयर की गई मेमोरी वाला बफ़र उपलब्ध कराना होता है. आम तौर पर, इसे ऐप्लिकेशन (EGL रेंडरिंग की मदद से) भरता है. साथ ही, डिसप्ले पर दिखने वाले किसी भी दूसरे फ़्रेम के बजाय, तैयार फ़्रेम को दिखाता है. EVS इंटरफ़ेस को वेंडर के तौर पर लागू करने पर, उसे /vendor/… /device/… या hardware/… में से किसी एक में सेव किया जा सकता है. उदाहरण के लिए, /hardware/[vendor]/[platform]/evs).

कर्नेल ड्राइवर

EVS स्टैक के साथ काम करने वाले डिवाइस के लिए, कर्नेल ड्राइवर की ज़रूरत होती है. नए ड्राइवर बनाने के बजाय, OEM के पास मौजूदा कैमरा या डिसप्ले हार्डवेयर ड्राइवर की मदद से, EVS की ज़रूरी सुविधाओं का इस्तेमाल करने का विकल्प होता है. ड्राइवर का फिर से इस्तेमाल करना फ़ायदेमंद हो सकता है. खास तौर पर, डिसप्ले ड्राइवर के लिए, जहां इमेज के प्रज़ेंटेशन के लिए, अन्य ऐक्टिव थ्रेड के साथ समन्वय की ज़रूरत पड़ सकती है. Android 8.0 में, v4l2 पर आधारित एक सैंपल ड्राइवर (packages/services/Car/evs/sampleDriver में) शामिल है. यह ड्राइवर, v4l2 के साथ काम करने के लिए, कर्नेल पर निर्भर करता है. साथ ही, आउटपुट इमेज को दिखाने के लिए, SurfaceFlinger पर निर्भर करता है.

ईवीएस हार्डवेयर इंटरफ़ेस की जानकारी

इस सेक्शन में, एचएएल के बारे में बताया गया है. वेंडर से उम्मीद की जाती है कि वे अपने हार्डवेयर के हिसाब से, इस एपीआई को लागू करें.

IEvsEnumerator

यह ऑब्जेक्ट, सिस्टम में उपलब्ध EVS हार्डवेयर (एक या उससे ज़्यादा कैमरे और एक डिसप्ले डिवाइस) की जानकारी देता है.

getCameraList() generates (vec<CameraDesc> cameras);

सिस्टम में सभी कैमरों के लिए विवरण वाला वेक्टर देता है. यह माना जाता है कि कैमरा सेट अप पहले से तय है और बूट के समय पता किया जा सकता है. कैमरे की जानकारी के बारे में ज़्यादा जानने के लिए, CameraDesc देखें.

openCamera(string camera_id) generates (IEvsCamera camera);

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

closeCamera(IEvsCamera camera);

इससे IEvsCamera इंटरफ़ेस रिलीज़ होता है (यह openCamera() कॉल से उलट होता है). closeCamera को कॉल करने से पहले, stopVideoStream() को कॉल करके कैमरे की वीडियो स्ट्रीम को बंद करना होगा.

openDisplay() generates (IEvsDisplay display);

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

closeDisplay(IEvsDisplay display);

IEvsDisplay इंटरफ़ेस को रिलीज़ करता है. यह openDisplay() कॉल के उलट होता है. getTargetBuffer() कॉल के साथ मिले बफ़र को डिसप्ले बंद करने से पहले, डिसप्ले पर वापस लाया जाना चाहिए.

getDisplayState() generates (DisplayState state);

डिसप्ले की मौजूदा स्थिति दिखाता है. एचएएल लागू करने पर, असल मौजूदा स्थिति की जानकारी मिलनी चाहिए. यह स्थिति, हाल ही में अनुरोध की गई स्थिति से अलग हो सकती है. डिसप्ले की स्थितियों में बदलाव करने के लिए ज़रूरी लॉजिक, डिवाइस लेयर के ऊपर होना चाहिए. इससे, एचएएल लागू करने के दौरान डिसप्ले की स्थितियों में अपने-आप बदलाव होने की संभावना कम हो जाती है. अगर फ़िलहाल डिसप्ले को किसी क्लाइंट ने (openDisplay को कॉल करके) होल्ड नहीं किया है, तो यह फ़ंक्शन NOT_OPEN दिखाता है. ऐसा न होने पर, यह ईवीएस डिसप्ले की मौजूदा स्थिति की जानकारी देता है. IEvsDisplay API देखें.

struct CameraDesc {
    string      camera_id;
    int32       vendor_flags;       // Opaque value
}
  • camera_id. एक स्ट्रिंग, जो किसी कैमरे की खास तौर पर पहचान करती है. यह डिवाइस का नाम या डिवाइस के लिए कोई नाम हो सकता है, जैसे कि rearview. इस स्ट्रिंग के लिए वैल्यू, HAL लागू करती है और ऊपर दिए गए स्टैक में, वैल्यू को ओपेक तरीके से इस्तेमाल नहीं किया जाता है.
  • vendor_flags. यह खास तरह के कैमरे की जानकारी को ड्राइवर से लेकर कस्टम ईवीएस ऐप्लिकेशन तक साफ़ तौर पर पास करने का तरीका है. इसे ड्राइवर से बिना किसी रुकावट के ईवीएस ऐप्लिकेशन में पास किया जाता है, जिसे अनदेखा किया जा सकता है.

IEvsCamera

यह ऑब्जेक्ट एक कैमरा दिखाता है और इमेज कैप्चर करने के लिए मुख्य इंटरफ़ेस है.

getCameraInfo() generates (CameraDesc info);

इस कैमरे का CameraDesc दिखाता है.

setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);

उस बफ़र चेन की डेप्थ के बारे में बताता है जिस पर कैमरे को काम करने के लिए कहा जाता है. ज़्यादा से ज़्यादा एक साथ कई फ़्रेम, IEvsCamera क्लाइंट के पास हो सकते हैं. अगर doneWithFrame से वापस किए बिना, इतना ज़्यादा फ़्रेम रिसीवर को डिलीवर किए गए हैं, तो स्ट्रीम तब तक फ़्रेम स्किप करती है, जब तक कि फिर से इस्तेमाल करने के लिए बफ़र वापस नहीं किया जाता. किसी भी समय इस कॉल का जवाब देना कानूनी है. भले ही, स्ट्रीम पहले से चल रही हों. अगर ऐसा है, तो बफ़र को ज़रूरत के हिसाब से चेन में जोड़ा या हटाया जाना चाहिए. अगर इस एंट्री पॉइंट पर कोई कॉल नहीं किया जाता है, तो IEvsCamera डिफ़ॉल्ट रूप से कम से कम एक फ़्रेम के साथ काम करता है. हालांकि, ज़्यादा फ़्रेम भी काम कर सकते हैं.

अगर अनुरोध किए गए bufferCount को शामिल नहीं किया जा सकता, तो फ़ंक्शन BUFFER_NOT_AVAILABLE या गड़बड़ी से जुड़ा कोई अन्य कोड दिखाता है. इस मामले में, सिस्टम पहले से सेट की गई वैल्यू के साथ काम करता रहेगा.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

इस कैमरे से ईवीएस कैमरा फ़्रेम डिलीवर करने का अनुरोध करता है. IEvsCameraStream को समय-समय पर नए इमेज फ़्रेम के साथ कॉल आते हैं, जब तक कि stopVideoStream() को कॉल नहीं किया जाता. फ़्रेम, startVideoStream कॉल के 500 मिलीसेकंड के अंदर डिलीवर होने चाहिए. साथ ही, शुरू होने के बाद, कम से कम 10 एफ़पीएस पर जनरेट होने चाहिए. वीडियो स्ट्रीम शुरू होने में लगने वाला समय, रीयर व्यू कैमरा के चालू होने में लगने वाले समय में भी शामिल होता है. अगर स्ट्रीम शुरू नहीं हुई है, तो एक गड़बड़ी कोड देना ज़रूरी है. ऐसा न होने पर, 'ठीक है' दिखता है.

oneway doneWithFrame(BufferDesc buffer);

IEvsCameraStream से डिलीवर किया गया फ़्रेम दिखाता है. IEvsCameraStream इंटरफ़ेस पर डिलीवर किए गए फ़्रेम का इस्तेमाल करने के बाद, उसे फिर से इस्तेमाल करने के लिए IEvsCamera पर वापस भेजना होगा. बफ़र की संख्या कम और सीमित होती है. यह संख्या एक भी हो सकती है. अगर बफ़र की संख्या खत्म हो जाती है, तो बफ़र वापस आने तक कोई फ़्रेम डिलीवर नहीं किया जाता. इस वजह से, हो सकता है कि कुछ फ़्रेम स्किप हो जाएं. कोई बफ़र न होने का मतलब है कि स्ट्रीम खत्म हो गई है. ऐसे में, इस फ़ंक्शन की मदद से बफ़र वापस नहीं लाया जाता. सही तरीके से काम करने पर OK दिखाता है या गड़बड़ी का सही कोड दिखाता है. इसमें INVALID_ARG या BUFFER_NOT_AVAILABLE शामिल हो सकता है.

stopVideoStream();

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

getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);

HAL लागू करने से जुड़ी ड्राइवर की जानकारी का अनुरोध करता है. opaqueIdentifier के लिए अनुमति वाली वैल्यू, ड्राइवर के हिसाब से होती हैं. हालांकि, कोई वैल्यू न देने पर ड्राइवर क्रैश हो सकता है. ड्राइवर को किसी भी ऐसे opaqueIdentifier के लिए 0 दिखाना चाहिए जिसे वह नहीं पहचानता.

setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);

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

struct BufferDesc {
    uint32  width;      // Units of pixels
    uint32  height;     // Units of pixels
    uint32  stride;     // Units of pixels
    uint32  pixelSize;  // Size of single pixel in bytes
    uint32  format;     // May contain values from android_pixel_format_t
    uint32  usage;      // May contain values from Gralloc.h
    uint32  bufferId;   // Opaque value
    handle  memHandle;  // gralloc memory buffer handle
}

एपीआई से भेजी गई इमेज के बारे में जानकारी देता है. इमेज बफ़र की जानकारी देने के लिए इस स्ट्रक्चर को भरने की ज़िम्मेदारी HAL ड्राइव की है. वहीं, HAL क्लाइंट इस स्ट्रक्चर को सिर्फ़ पढ़ने के लिए मानेगा. फ़ील्ड में ज़रूरत के मुताबिक जानकारी होती है, ताकि क्लाइंट ANativeWindowBuffer ऑब्जेक्ट को फिर से बना सके. ऐसा इसलिए ज़रूरी है, ताकि eglCreateImageKHR() एक्सटेंशन के साथ EGL में इमेज का इस्तेमाल किया जा सके.

  • width. दिखाई गई इमेज की चौड़ाई, पिक्सल में.
  • height. दिखाई गई इमेज की लंबाई पिक्सल में है.
  • stride. हर पंक्ति की मेमोरी में मौजूद पिक्सल की संख्या, पंक्तियों के अलाइनमेंट के लिए किसी भी पैडिंग (जगह) को ध्यान में रखती है. इसे पिक्सल में दिखाया जाता है, ताकि यह बफ़र के ब्यौरे के लिए, gralloc के इस्तेमाल किए गए कॉन्वेंशन से मेल खा सके.
  • pixelSize. हर एक पिक्सल में लगे बाइट की संख्या, इससे इमेज की एक लाइन (stride बाइट में = stride पिक्सल में * pixelSize) आने के लिए ज़रूरी बाइट साइज़ की गिनती चालू हो जाती है.
  • format. इमेज में इस्तेमाल किया गया पिक्सल फ़ॉर्मैट. दिया गया फ़ॉर्मैट, प्लैटफ़ॉर्म के OpenGL लागू करने के तरीके के साथ काम करना चाहिए. काम करने की जांच में पास होने के लिए, कैमरे के इस्तेमाल के लिए HAL_PIXEL_FORMAT_YCRCB_420_SP और डिसप्ले के लिए RGBA या BGRA का इस्तेमाल करना चाहिए.
  • usage. इस्तेमाल के लिए फ़्लैग, एचएएल लागू करने से सेट किए गए. HAL क्लाइंट को इनमें कोई बदलाव किए बिना पास करना होगा. ज़्यादा जानकारी के लिए, Gralloc.h से जुड़े फ़्लैग देखें.
  • bufferId. HAL लागू करने के लिए तय की गई एक यूनीक वैल्यू, ताकि HAL API के ज़रिए राउंड ट्रिप के बाद बफ़र की पहचान की जा सके. इस फ़ील्ड में सेव की गई वैल्यू को, एचएएल लागू करने वाला सिस्टम अपनी मर्ज़ी से चुन सकता है.
  • memHandle. उस मेमोरी बफ़र का हैंडल जिसमें इमेज का डेटा होता है. HAL लागू करने के दौरान, यहां Gralloc बफ़र हैंडल सेव किया जा सकता है.

IEvsCameraStream

क्लाइंट, असाइनॉन्स वीडियो फ़्रेम डिलीवरी पाने के लिए, इस इंटरफ़ेस को लागू करता है.

deliverFrame(BufferDesc buffer);

जब भी कोई वीडियो फ़्रेम जांच के लिए तैयार होता है, तब एचएएल से कॉल मिलता है. इस तरीके से मिले बफ़र हैंडल, IEvsCamera::doneWithFrame() को किए गए कॉल के ज़रिए लौटाए जाने चाहिए. जब IEvsCamera::stopVideoStream() को कॉल करके वीडियो स्ट्रीम बंद की जाती है, तो पाइपलाइन के खाली होने तक यह कॉलबैक जारी रह सकता है. हर फ़्रेम को अब भी वापस लौटाना ज़रूरी है. जब स्ट्रीम का आखिरी फ़्रेम डिलीवर हो जाता है, तो NULL bufferHandle डिलीवर किया जाता है. इससे पता चलता है कि स्ट्रीम खत्म हो गई है और आगे कोई फ़्रेम डिलीवर नहीं किया जाएगा. doneWithFrame() के साथ, NULLbufferHandle को वापस भेजने की ज़रूरत नहीं है. हालांकि, सभी दूसरे हैंडल को वापस भेजना ज़रूरी है

तकनीकी तौर पर, मालिकाना बफ़र फ़ॉर्मैट इस्तेमाल किए जा सकते हैं. हालांकि, काम करने की जांच के लिए ज़रूरी है कि बफ़र इनमें से किसी एक फ़ॉर्मैट में हो: NV21 (YCrCb 4:2:0 सेमी-प्लानर), YV12 (YCrCb 4:2:0 प्लानर), YUYV (YCrCb 4:2:2 इंटरलीव्ड), RGBA (32 बिट R:G:B:x), BGRA (32 बिट B:G:R:x). चुना गया फ़ॉर्मैट, प्लैटफ़ॉर्म के GLES लागू करने पर, मान्य GL टेक्स्चर सोर्स होना चाहिए.

ऐप्लिकेशन को BufferDesc स्ट्रक्चर में, bufferId फ़ील्ड और memHandle के बीच किसी भी तरह के संबंध पर भरोसा नहीं करना चाहिए. bufferId वैल्यू, एचएएल ड्राइवर के लागू होने के लिए ज़रूरी रूप से निजी होती हैं. साथ ही, एचएएल ड्राइवर अपनी ज़रूरत के हिसाब से इनका इस्तेमाल (और फिर से इस्तेमाल) कर सकता है.

IEvsDisplay

यह ऑब्जेक्ट, Evs डिसप्ले को दिखाता है, डिसप्ले की स्थिति को कंट्रोल करता है, और इमेज के असल प्रज़ेंटेशन को मैनेज करता है.

getDisplayInfo() generates (DisplayDesc info);

सिस्टम से मिले ईवीएस डिसप्ले के बारे में बुनियादी जानकारी दिखाता है (DisplayDesc देखें).

setDisplayState(DisplayState state) generates (EvsResult result);

डिसप्ले की स्थिति सेट करता है. क्लाइंट, अपनी पसंद की स्थिति दिखाने के लिए डिसप्ले की स्थिति सेट कर सकते हैं. साथ ही, HAL लागू करने के लिए, किसी भी स्थिति में किसी भी स्थिति के लिए अनुरोध स्वीकार करना ज़रूरी है. हालांकि, अनुरोध को अनदेखा किया जा सकता है.

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

किसी भी राज्य के लिए, किसी भी समय अनुरोध किया जा सकता है. अगर डिसप्ले पहले से दिख रहा है, तो VISIBLE_ON_NEXT_FRAME पर सेट करने पर भी वह दिखता रहेगा. जब तक अनुरोध की गई स्थिति, सूची में शामिल किसी ऐसी वैल्यू से मेल नहीं खाती जिसकी पहचान नहीं की जा सकी है, तब तक हमेशा 'ठीक है' दिखाता है. इस मामले में, INVALID_ARG दिखाया जाता है.

getDisplayState() generates (DisplayState state);

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

getTargetBuffer() generates (handle bufferHandle);

डिसप्ले से जुड़े फ़्रेम बफ़र में हैंडल दिखाता है. इस बफ़र को लॉक किया जा सकता है और सॉफ़्टवेयर और/या GL की मदद से लिखा जा सकता है. इस बफ़र को returnTargetBufferForDisplay() को कॉल करने के साथ लौटाया जाना चाहिए, भले ही डिसप्ले अब न दिख रहा हो.

तकनीकी तौर पर, मालिकाना बफ़र फ़ॉर्मैट इस्तेमाल किए जा सकते हैं. हालांकि, काम करने की जांच के लिए ज़रूरी है कि बफ़र इनमें से किसी एक फ़ॉर्मैट में हो: NV21 (YCrCb 4:2:0 Semi-Planar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4:2:2 Interleaved), RGBA (32 बिट R:G:B:x), BGRA (32 बिट B:G:R:x). चुना गया फ़ॉर्मैट, प्लैटफ़ॉर्म के GLES लागू करने पर मान्य GL रेंडर टारगेट होना चाहिए.

गड़बड़ी होने पर, शून्य हैंडल वाला बफ़र दिखाया जाता है. हालांकि, ऐसे बफ़र को returnTargetBufferForDisplay में वापस भेजने की ज़रूरत नहीं होती.

returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);

डिसप्ले को बताता है कि बफ़र डिसप्ले के लिए तैयार है. इस कॉल के साथ इस्तेमाल करने के लिए, सिर्फ़ getTargetBuffer() को कॉल करके हासिल किए गए बफ़र मान्य हैं. साथ ही, क्लाइंट ऐप्लिकेशन BufferDesc के कॉन्टेंट में बदलाव नहीं कर सकता. इस कॉल के बाद, बफ़र का इस्तेमाल क्लाइंट के लिए मान्य नहीं होता. सही नतीजे मिलने पर 'ठीक है' या गड़बड़ी का सही कोड दिखाता है, जिसमें INVALID_ARG या BUFFER_NOT_AVAILABLE शामिल हो सकता है.

struct DisplayDesc {
    string  display_id;
    int32   vendor_flags;  // Opaque value
}

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

  • display_id. डिसप्ले की खास पहचान करने वाली स्ट्रिंग. यह डिवाइस का कर्नेल डिवाइस नाम या डिवाइस का कोई नाम हो सकता है, जैसे कि rearview. इस स्ट्रिंग की वैल्यू, एचएएल के लागू होने से चुनी जाती है और ऊपर दिए गए स्टैक का इस्तेमाल करके, इसका इस्तेमाल किया जाता है.
  • vendor_flags. यह खास तरह के कैमरे की जानकारी को ड्राइवर से लेकर कस्टम ईवीएस ऐप्लिकेशन में पास करने का तरीका होता है. इसे ड्राइवर से बिना किसी रुकावट के ईवीएस ऐप्लिकेशन में पास कर दिया जाता है, जिसे अनदेखा किया जा सकता है.
enum DisplayState : uint32 {
    NOT_OPEN,               // Display has not been “opened” yet
    NOT_VISIBLE,            // Display is inhibited
    VISIBLE_ON_NEXT_FRAME,  // Will become visible with next frame
    VISIBLE,                // Display is currently active
    DEAD,                   // Display is not available. Interface should be closed
}

ईवीएस डिसप्ले की स्थिति के बारे में बताता है. यह बंद (ड्राइवर को नहीं दिखता) या चालू (ड्राइवर को इमेज दिखाता है) हो सकता है. इसमें ऐसी अस्थायी स्थिति शामिल होती है जिसमें डिसप्ले अभी तक नहीं दिख रहा है. हालांकि, returnTargetBufferForDisplay() कॉल के साथ तस्वीरों के अगले फ़्रेम के डिलीवर होने पर, उसे दिखने के लिए तैयार किया जाता है.

ईवीएस मैनेजर

ईवीएस मैनेजर, ईवीएस सिस्टम को सार्वजनिक इंटरफ़ेस उपलब्ध कराता है. इससे बाहरी कैमरे के व्यू इकट्ठा किए जा सकते हैं और उन्हें दिखाया जा सकता है. अगर हार्डवेयर ड्राइवर, हर संसाधन (कैमरा या डिसप्ले) के लिए सिर्फ़ एक ऐक्टिव इंटरफ़ेस की अनुमति देते हैं, तो EVS मैनेजर, कैमरों के शेयर किए गए ऐक्सेस की सुविधा देता है. एक मुख्य EVS ऐप्लिकेशन, EVS मैनेजर का पहला क्लाइंट होता है. साथ ही, यह एक ऐसा क्लाइंट होता है जिसे डिसप्ले डेटा को लिखने की अनुमति होती है. अन्य क्लाइंट को कैमरे की इमेज का रीड-ओनली ऐक्सेस दिया जा सकता है.

EVS मैनेजर, HAL ड्राइवर के तौर पर उसी एपीआई को लागू करता है और एक साथ कई क्लाइंट के साथ काम करके बेहतर सेवा देता है. एक से ज़्यादा क्लाइंट, EVS मैनेजर की मदद से कैमरा खोल सकते हैं और वीडियो स्ट्रीम पा सकते हैं.

ईवीएस मैनेजर और
ईवीएस हार्डवेयर एपीआई का डायग्राम.
दूसरी इमेज. ईवीएस मैनेजर, ईवीएस हार्डवेयर एपीआई की डुप्लीकेट कॉपी बनाता है.

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

यहां दिए गए सेक्शन में, सिर्फ़ उन कॉल के बारे में बताया गया है जिनका व्यवहार ईवीएस मैनेजर लागू करने के तरीके से अलग (एक्सटेंडेड) है. बाकी कॉल, ईवीएस एचएएल के ब्यौरे जैसे ही होते हैं.

IEvsEnumerator

openCamera(string camera_id) generates (IEvsCamera camera);

इसकी मदद से, किसी खास कैमरे के साथ इंटरैक्ट करने के लिए इस्तेमाल किया जाने वाला इंटरफ़ेस ऑब्जेक्ट मिलता है. इस ऑब्जेक्ट की पहचान यूनीक camera_id स्ट्रिंग से की जाती है. गड़बड़ी होने पर NULL दिखाता है. ईवीएस मैनेजर लेयर पर, जब तक सिस्टम के लिए ज़रूरी संसाधन उपलब्ध हो जाते हैं, तब तक किसी दूसरे तरीके से खोले गए कैमरे को फिर से चालू किया जा सकता है. इससे वीडियो स्ट्रीम, कई उपभोक्ता ऐप्लिकेशन में ट्रांसफ़र हो जाएगी. EVS मैनेजर लेयर में मौजूद camera_id स्ट्रिंग, EVS हार्डवेयर लेयर में रिपोर्ट की गई स्ट्रिंग जैसी ही होती हैं.

IEvsCamera

EVS मैनेजर की ओर से उपलब्ध कराए गए IEvsCamera को अंदरूनी तौर पर वर्चुअलाइज़ किया जाता है, ताकि एक क्लाइंट के कैमरे पर किए गए ऑपरेशन का असर, दूसरे क्लाइंट पर न पड़े. साथ ही, वे अपने कैमरों का अलग से ऐक्सेस बनाए रख सकें.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

वीडियो स्ट्रीम शुरू हो जाती हैं. क्लाइंट, एक ही कैमरे पर अलग-अलग वीडियो स्ट्रीम शुरू और बंद कर सकते हैं. पहला क्लाइंट शुरू होने पर, कैमरा चालू हो जाता है.

doneWithFrame(uint32 frameId, handle bufferHandle) generates (EvsResult result);

फ़्रेम दिखाता है. काम पूरा होने के बाद, हर क्लाइंट को अपने फ़्रेम लौटाने होंगे. हालांकि, वे अपने फ़्रेम को जितनी चाहें उतनी देर तक अपने पास रख सकते हैं. जब क्लाइंट के पास मौजूद फ़्रेम की संख्या, कॉन्फ़िगर की गई सीमा तक पहुंच जाती है, तो उसे तब तक कोई फ़्रेम नहीं मिलेगा, जब तक वह फ़्रेम रेंडर नहीं कर लेता. फ़्रेम स्किप करने से, दूसरे क्लाइंट पर कोई असर नहीं पड़ता. उन्हें उम्मीद के मुताबिक सभी फ़्रेम मिलते रहते हैं.

stopVideoStream();

वीडियो स्ट्रीम को रोकता है. हर क्लाइंट, दूसरे क्लाइंट पर असर डाले बिना किसी भी समय अपनी वीडियो स्ट्रीम को बंद कर सकता है. जब किसी कैमरे का आखिरी क्लाइंट अपनी स्ट्रीम बंद कर देता है, तो हार्डवेयर लेयर पर मौजूद कैमरे की स्ट्रीम बंद हो जाती है.

setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);

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

IEvsDisplay

डिसप्ले के सिर्फ़ एक मालिक को अनुमति है. यहां तक कि ईवीएस मैनेजर लेवल पर भी अनुमति नहीं दी जा सकती. मैनेजर कोई सुविधा नहीं जोड़ता है और सीधे तौर पर IEvsDisplay इंटरफ़ेस को HAL लागू करने के लिए पास करता है.

ईवीएस ऐप्लिकेशन

Android में, ईवीएस ऐप्लिकेशन का नेटिव C++ रेफ़रंस लागू होता है. यह ऐप्लिकेशन, ईवीएस मैनेजर और वाहन के एचएएल के साथ संपर्क करके, पीछे देखने वाले कैमरे के बुनियादी फ़ंक्शन उपलब्ध कराता है. यह उम्मीद है कि ऐप्लिकेशन, सिस्टम के बूट होने की प्रोसेस के शुरुआती दौर में ही शुरू हो जाएगा. साथ ही, उपलब्ध कैमरों और कार की स्थिति (गियर और टर्न सिग्नल की स्थिति) के आधार पर, सही वीडियो दिखाया जाएगा. OEM, EVS ऐप्लिकेशन में बदलाव कर सकते हैं या उसे अपनी गाड़ी के हिसाब से बनाए गए लॉजिक और प्रज़ेंटेशन से बदल सकते हैं.

तीसरा डायग्राम. EVS ऐप्लिकेशन का सैंपल लॉजिक, कैमरे की सूची पाएं.


चौथी इमेज. ईवीएस ऐप्लिकेशन का सैंपल लॉजिक, फ़्रेम कॉलबैक पाना.

इमेज का डेटा, ऐप्लिकेशन को स्टैंडर्ड ग्राफ़िक्स बफ़र में दिखाया जाता है. इसलिए, ऐप्लिकेशन को इमेज को सोर्स बफ़र से आउटपुट बफ़र में ले जाने की ज़िम्मेदारी होती है. इससे डेटा कॉपी करने की लागत बढ़ती है. हालांकि, इससे ऐप्लिकेशन को इमेज को डिसप्ले बफ़र में अपनी पसंद के मुताबिक रेंडर करने का मौका भी मिलता है.

उदाहरण के लिए, ऐप्लिकेशन खुद ही पिक्सल डेटा को मूव कर सकता है. ऐसा, इनलाइन स्केल या रोटेशन ऑपरेशन की मदद से किया जा सकता है. ऐप्लिकेशन, सोर्स इमेज को OpenGL टेक्सचर के तौर पर इस्तेमाल करने का विकल्प भी चुन सकता है. साथ ही, आइकॉन, दिशा-निर्देश, और ऐनिमेशन जैसे वर्चुअल एलिमेंट के साथ, आउटपुट बफ़र में जटिल सीन को रेंडर कर सकता है. ज़्यादा बेहतर ऐप्लिकेशन, एक साथ काम करने वाले कई इनपुट कैमरों को चुनकर, उन्हें एक आउटपुट फ़्रेम में मर्ज कर सकता है. जैसे, वाहन के आस-पास के वर्चुअल व्यू में, ऊपर से नीचे की ओर देखने के लिए.

EVS Display HAL में EGL/SurfaceFlinger का इस्तेमाल करना

इस सेक्शन में, Android 10 में EVS Display HAL को रेंडर करने के लिए, EGL का इस्तेमाल करने का तरीका बताया गया है.

EVS HAL रेफ़रंस लागू करने के लिए, स्क्रीन पर कैमरे की झलक को रेंडर करने के लिए EGL का इस्तेमाल किया जाता है. साथ ही, टारगेट EGL रेंडरिंग प्लैटफ़ॉर्म बनाने के लिए libgui का इस्तेमाल किया जाता है. Android 8 (और उसके बाद के वर्शन) में, libgui को VNDK-private के तौर पर बांटा गया है. यह VNDK लाइब्रेरी के लिए उपलब्ध लाइब्रेरी के ग्रुप को दिखाता है. वेंडर प्रोसेस इनका इस्तेमाल नहीं कर सकतीं. एचएएल लागू करने का तरीका, वेंडर पार्टीशन में होना चाहिए. इसलिए, वेंडर को Surface in HAL लागू करने की अनुमति नहीं है.

वेंडर प्रोसेस के लिए libgui बनाना

libgui का इस्तेमाल, EVS Display HAL लागू करने के लिए EGL/SurfaceFlinger का इस्तेमाल करने का एकमात्र विकल्प है. libgui को लागू करने का सबसे आसान तरीका, frameworks/native/libs/gui के ज़रिए है. इसके लिए, बिल्ड स्क्रिप्ट में सीधे तौर पर एक और बिल्ड टारगेट का इस्तेमाल करें. यह टारगेट, libgui टारगेट जैसा ही है. इसमें सिर्फ़ दो फ़ील्ड जोड़े गए हैं:

  • name
  • vendor_available
cc_library_shared {
    name: "libgui_vendor",
    vendor_available: true,
    vndk: {
        enabled: false,
    },
    double_loadable: true,

defaults: ["libgui_bufferqueue-defaults"],
srcs: [ … // bufferhub is not used when building libgui for vendors target: { vendor: { cflags: [ "-DNO_BUFFERHUB", "-DNO_INPUT", ], …

ध्यान दें: वेंडर टारगेट, NO_INPUT मैक्रो की मदद से बनाए जाते हैं. यह मैक्रो, पार्सल डेटा से एक 32-बिट शब्द हटा देता है. SurfaceFlinger फ़ाइल, हटाए जा चुके फ़ील्ड के हिसाब से काम करती है. इसलिए, SurfaceFlinger पार्सल को पार्स नहीं कर सका. ऐसा fcntl की गड़बड़ी के तौर पर देखा गया है:

W Parcel  : Attempt to read object from Parcel 0x78d9cffad8 at offset 428 that is not in the object list
E Parcel  : fcntl(F_DUPFD_CLOEXEC) failed in Parcel::read, i is 0, fds[i] is 0, fd_count is 20, error: Unknown error 2147483647
W Parcel  : Attempt to read object from Parcel 0x78d9cffad8 at offset 544 that is not in the object list

इस समस्या को हल करने के लिए:

diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 6066421fa..25cf5f0ce 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -54,6 +54,9 @@ status_t layer_state_t::write(Parcel& output) const
    output.writeFloat(color.b);
#ifndef NO_INPUT
    inputInfo.write(output);
+#else
+    // Write a dummy 32-bit word.
+    output.writeInt32(0);
#endif
    output.write(transparentRegion);
    output.writeUint32(transform);

बिल्ड करने के निर्देशों के उदाहरण नीचे दिए गए हैं. आपको $(ANDROID_PRODUCT_OUT)/system/lib64/libgui_vendor.so मिलेगा.

$ cd <your_android_source_tree_top>
$ . ./build/envsetup.
$ lunch <product_name>-<build_variant>
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=10
TARGET_PRODUCT=<product_name>
TARGET_BUILD_VARIANT=<build_variant>
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm64
TARGET_ARCH_VARIANT=armv8-a
TARGET_CPU_VARIANT=generic
TARGET_2ND_ARCH=arm
TARGET_2ND_ARCH_VARIANT=armv7-a-neon
TARGET_2ND_CPU_VARIANT=cortex-a9
HOST_ARCH=x86_64
HOST_2ND_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=<host_linux_version>
HOST_CROSS_OS=windows
HOST_CROSS_ARCH=x86
HOST_CROSS_2ND_ARCH=x86_64
HOST_BUILD_TYPE=release
BUILD_ID=QT
OUT_DIR=out
============================================

$ m -j libgui_vendor … $ find $ANDROID_PRODUCT_OUT/system -name "libgui_vendor*" .../out/target/product/hawk/system/lib64/libgui_vendor.so .../out/target/product/hawk/system/lib/libgui_vendor.so

EVS HAL लागू करने के लिए बाइंडर का इस्तेमाल करना

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

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

SurfaceFlinger, एआईडीएल इंटरफ़ेस तय करता है. वहीं, वेंडर प्रोसेस, फ़्रेमवर्क प्रोसेस के साथ बातचीत करने के लिए सिर्फ़ एचआईडीएल इंटरफ़ेस का इस्तेमाल कर सकती हैं. मौजूदा एआईडीएल इंटरफ़ेस को HIDL में बदलने के लिए थोड़ा-बहुत काम करना पड़ता है. सौभाग्य से, Android में libbinder के लिए बाइंडर ड्राइवर चुनने का एक तरीका उपलब्ध है. इस ड्राइवर से, यूज़रस्पेस लाइब्रेरी प्रोसेस लिंक होती हैं.

diff --git a/evs/sampleDriver/service.cpp b/evs/sampleDriver/service.cpp
index d8fb3166..5fd02935 100644
--- a/evs/sampleDriver/service.cpp
+++ b/evs/sampleDriver/service.cpp
@@ -21,6 +21,7 @@
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
#include <utils/Log.h>
+#include <binder/ProcessState.h>

#include "ServiceNames.h"
#include "EvsEnumerator.h"
@@ -43,6 +44,9 @@ using namespace android;
int main() {
    ALOGI("EVS Hardware Enumerator service is starting");


+    // Use /dev/binder for SurfaceFlinger
+    ProcessState::initWithDriver("/dev/binder");
+


    // Start a thread to listen to video device addition events.
    std::atomic<bool> running { true };
    std::thread ueventHandler(EvsEnumerator::EvsUeventThread, std::ref(running));

ध्यान दें: वेंडर प्रोसेस को Process या IPCThreadState पर कॉल करने से पहले या बाइंडर कॉल करने से पहले इसे कॉल करना चाहिए.

SELinux नीतियां

अगर डिवाइस में फ़ुल ट्रिबल लागू किया गया है, तो SELinux, वेंडर प्रोसेस को /dev/binder का इस्तेमाल करने से रोकता है. उदाहरण के लिए, EVS HAL के सैंपल को लागू करने के लिए, hal_evs_driver डोमेन को असाइन किया गया है. साथ ही, binder_device डोमेन के लिए, पढ़ने और लिखने की अनुमतियां ज़रूरी हैं.

W ProcessState: Opening '/dev/binder' failed: Permission denied
F ProcessState: Binder driver could not be opened. Terminating.
F libc    : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 9145 (android.hardwar), pid 9145 (android.hardwar)
W android.hardwar: type=1400 audit(0.0:974): avc: denied { read write } for name="binder" dev="tmpfs" ino=2208 scontext=u:r:hal_evs_driver:s0 tcontext=u:object_r:binder_device:s0 tclass=chr_file permissive=0

हालांकि, इन अनुमतियों को जोड़ने पर, बिल्ड पूरा नहीं होता. ऐसा इसलिए होता है, क्योंकि यह system/sepolicy/domain.te में बताए गए, 'कभी अनुमति न दें' नियमों का उल्लंघन करता है.

libsepol.report_failure: neverallow on line 631 of system/sepolicy/public/domain.te (or line 12436 of policy.conf) violated by allow hal_evs_driver binder_device:chr_file { read write };
libsepol.check_assertions: 1 neverallow failures occurred
full_treble_only(`
neverallow {
    domain
    -coredomain
    -appdomain
    -binder_in_vendor_violators
} binder_device:chr_file rw_file_perms;
')

binder_in_vendor_violators एक एट्रिब्यूट है, जो किसी गड़बड़ी का पता लगाने और डेवलपमेंट में मदद करने के लिए दिया जाता है. इसका इस्तेमाल, ऊपर बताए गए Android 10 के उल्लंघन को ठीक करने के लिए भी किया जा सकता है.

diff --git a/evs/sepolicy/evs_driver.te b/evs/sepolicy/evs_driver.te
index f1f31e9fc..6ee67d88e 100644
--- a/evs/sepolicy/evs_driver.te
+++ b/evs/sepolicy/evs_driver.te
@@ -3,6 +3,9 @@ type hal_evs_driver, domain, coredomain;
hal_server_domain(hal_evs_driver, hal_evs)
hal_client_domain(hal_evs_driver, hal_evs)

+# Allow to use /dev/binder
+typeattribute hal_evs_driver binder_in_vendor_violators;
+
# allow init to launch processes in this context
type hal_evs_driver_exec, exec_type, file_type, system_file_type;
init_daemon_domain(hal_evs_driver)

वेंडर प्रोसेस के तौर पर, ईवीएस एचएएल रेफ़रंस को लागू करने की प्रोसेस बनाएं

रेफ़रंस के तौर पर, packages/services/Car/evs/Android.mk में ये बदलाव किए जा सकते हैं. पक्का करें कि बताए गए सभी बदलाव, आपके ऐप्लिकेशन के लिए काम करते हों.

diff --git a/evs/sampleDriver/Android.mk b/evs/sampleDriver/Android.mk
index 734feea7d..0d257214d 100644
--- a/evs/sampleDriver/Android.mk
+++ b/evs/sampleDriver/Android.mk
@@ -16,7 +16,7 @@ LOCAL_SRC_FILES := \
LOCAL_SHARED_LIBRARIES := \
    android.hardware.automotive.evs@1.0 \
    libui \
-    libgui \
+    libgui_vendor \
    libEGL \
    libGLESv2 \
    libbase \
@@ -33,6 +33,7 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_INIT_RC := android.hardware.automotive.evs@1.0-sample.rc

LOCAL_MODULE := android.hardware.automotive.evs@1.0-sample
+LOCAL_PROPRIETARY_MODULE := true

LOCAL_MODULE_TAGS := optional
LOCAL_STRIP_MODULE := keep_symbols
@@ -40,6 +41,7 @@ LOCAL_STRIP_MODULE := keep_symbols
LOCAL_CFLAGS += -DLOG_TAG=\"EvsSampleDriver\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_CFLAGS += -Iframeworks/native/include

#NOTE:  It can be helpful, while debugging, to disable optimizations
#LOCAL_CFLAGS += -O0 -g
diff --git a/evs/sampleDriver/service.cpp b/evs/sampleDriver/service.cpp
index d8fb31669..5fd029358 100644
--- a/evs/sampleDriver/service.cpp
+++ b/evs/sampleDriver/service.cpp
@@ -21,6 +21,7 @@
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
#include <utils/Log.h>
+#include <binder/ProcessState.h>

#include "ServiceNames.h"
#include "EvsEnumerator.h"
@@ -43,6 +44,9 @@ using namespace android;
int main() {
    ALOGI("EVS Hardware Enumerator service is starting");
+    // Use /dev/binder for SurfaceFlinger
+    ProcessState::initWithDriver("/dev/binder");
+
     // Start a thread to listen video device addition events.
    std::atomic<bool> running { true };
    std::thread ueventHandler(EvsEnumerator::EvsUeventThread, std::ref(running));
diff --git a/evs/sepolicy/evs_driver.te b/evs/sepolicy/evs_driver.te
index f1f31e9fc..632fc7337 100644
--- a/evs/sepolicy/evs_driver.te
+++ b/evs/sepolicy/evs_driver.te
@@ -3,6 +3,9 @@ type hal_evs_driver, domain, coredomain;
hal_server_domain(hal_evs_driver, hal_evs)
hal_client_domain(hal_evs_driver, hal_evs)

+# allow to use /dev/binder
+typeattribute hal_evs_driver binder_in_vendor_violators;
+
# allow init to launch processes in this context
type hal_evs_driver_exec, exec_type, file_type, system_file_type;
init_daemon_domain(hal_evs_driver)
@@ -22,3 +25,7 @@ allow hal_evs_driver ion_device:chr_file r_file_perms;

# Allow the driver to access kobject uevents
allow hal_evs_driver self:netlink_kobject_uevent_socket create_socket_perms_no_ioctl;
+
+# Allow the driver to use the binder device
+allow hal_evs_driver binder_device:chr_file rw_file_perms;