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

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

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

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

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

ईवीएस सिस्टम के घटकों का डायग्राम

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

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

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

ईवीएस मैनेजर

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

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. एक स्ट्रिंग, जो किसी कैमरे की खास तौर पर पहचान करती है. डिवाइस के कर्नेल डिवाइस का नाम या डिवाइस का नाम हो सकता है, जैसे रीयरव्यू. इस स्ट्रिंग की वैल्यू, एचएएल लागू करने की प्रोसेस से चुनी जाती है और ऊपर दिए गए स्टैक में इसका इस्तेमाल साफ़ तौर पर नहीं किया जाता.
  • 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 में वापस भेजना चाहिए. बफ़र की संख्या कम और सीमित होती है. यह संख्या एक भी हो सकती है. अगर बफ़र की संख्या खत्म हो जाती है, तो बफ़र वापस आने तक कोई फ़्रेम डिलीवर नहीं किया जाता. इस वजह से, हो सकता है कि कुछ फ़्रेम स्किप हो जाएं. कोई बफ़र न होने का मतलब है कि स्ट्रीम खत्म हो गई है. ऐसे में, इस फ़ंक्शन की मदद से बफ़र वापस नहीं लाया जाता. सफलता मिलने पर 'ठीक है' या INVALID_ARG या BUFFER_NOT_AVAILABLE के साथ सही गड़बड़ी कोड दिखाता है.

stopVideoStream();

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

getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);

एचएएल लागू करने से ड्राइवर से जुड़ी खास जानकारी का अनुरोध करता है. 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 लागू करने के दौरान सेट किए गए इस्तेमाल के फ़्लैग. HAL क्लाइंट को इनमें कोई बदलाव किए बिना पास करना होगा. ज़्यादा जानकारी के लिए, Gralloc.h से जुड़े फ़्लैग देखें.
  • bufferId. HAL लागू करने के लिए तय की गई एक यूनीक वैल्यू, ताकि HAL API के ज़रिए राउंड ट्रिप के बाद बफ़र की पहचान की जा सके. इस फ़ील्ड में सेव की गई वैल्यू को, एचएएल लागू करने वाला सिस्टम अपनी मर्ज़ी से चुन सकता है.
  • memHandle. उस मेमोरी बफ़र का हैंडल जिसमें इमेज का डेटा होता है. HAL लागू करने के दौरान, यहां Gralloc बफ़र हैंडल सेव किया जा सकता है.

IEvsCameraStream

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

deliverFrame(BufferDesc buffer);

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

तकनीकी तौर पर, मालिकाना बफ़र फ़ॉर्मैट इस्तेमाल किए जा सकते हैं. हालांकि, काम करने की जांच के लिए ज़रूरी है कि बफ़र इनमें से किसी एक फ़ॉर्मैट में हो: 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);

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

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

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

IEvsEnumerator

openCamera(string camera_id) generates (IEvsCamera camera);

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

IEvsCamera

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

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

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

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

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

stopVideoStream();

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

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

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

IEvsDisplay

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

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

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

तीसरी इमेज. ईवीएस ऐप्लिकेशन का सैंपल लॉजिक, कैमरे की सूची पाएं.



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

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

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

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

इस सेक्शन में बताया गया है कि Android 10 में ईवीएस डिसप्ले एचएएल को रेंडर करने के लिए, 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/अनुमतियों की मदद से लागू करना है. यह टारगेट, 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 का इस्तेमाल करना चाहिए और किसी भी AIDL इंटरफ़ेस को HIDL में बदलना चाहिए. अगर आपको वेंडर प्रोसेस के बीच AIDL इंटरफ़ेस का इस्तेमाल जारी रखना है, तो /dev/vndbinder बाइंडर डोमेन का इस्तेमाल करें.

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

SurfaceFlinger, एआईडीएल इंटरफ़ेस तय करता है. वहीं, वेंडर प्रोसेस, फ़्रेमवर्क प्रोसेस के साथ बातचीत करने के लिए सिर्फ़ एचआईडीएल इंटरफ़ेस का इस्तेमाल कर सकती हैं. मौजूदा एआईडीएल इंटरफ़ेस को एचआईडीएल में बदलने के लिए, काफ़ी काम करना पड़ता है. अच्छी बात यह है कि 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)

वेंडर प्रोसेस के तौर पर, EVS HAL रेफ़रंस लागू करना

रेफ़रंस के तौर पर, 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;