دوربین خودرو HAL

اندروید حاوی یک لایه انتزاعی سخت افزاری HIDL (HAL) است که در مراحل اولیه بوت اندروید امکان ضبط و نمایش تصاویر را فراهم می کند و تا پایان عمر سیستم به کار خود ادامه می دهد. HAL شامل پشته سیستم نمای خارجی (EVS) است و معمولاً برای پشتیبانی از دوربین دید عقب و نمایشگرهای دید فراگیر در خودروهایی با سیستم‌های In-Vehicle Infotainment (IVI) مبتنی بر Android استفاده می‌شود. EVS همچنین امکان پیاده سازی ویژگی های پیشرفته را در برنامه های کاربر فراهم می کند.

اندروید همچنین شامل یک رابط درایور عکسبرداری و نمایشگر مخصوص EVS است (در /hardware/interfaces/automotive/evs/1.0 ). در حالی که امکان ساخت یک برنامه دوربین دید عقب در بالای خدمات دوربین و نمایشگر اندروید موجود وجود دارد، چنین برنامه ای احتمالاً در فرآیند بوت اندروید بسیار دیر اجرا می شود. استفاده از یک HAL اختصاصی، یک رابط کارآمد را فعال می‌کند و روشن می‌کند که یک OEM برای پشتیبانی از پشته EVS چه چیزی را باید پیاده‌سازی کند.

اجزای سیستم

EVS شامل اجزای سیستم زیر است:

سیستم EVS نمودار اجزاء

شکل 1. نمای کلی اجزای سیستم EVS.

برنامه EVS

یک نمونه برنامه C++ EVS ( /packages/services/Car/evs/app ) به عنوان پیاده‌سازی مرجع عمل می‌کند. این برنامه مسئول درخواست فریم های ویدیویی از مدیر EVS و ارسال فریم های تمام شده برای نمایش به مدیر EVS است. انتظار می رود به محض در دسترس بودن EVS و Car Service، توسط init راه اندازی شود و در عرض دو (2) ثانیه پس از روشن شدن روشن شود. OEM ها می توانند برنامه EVS را به دلخواه تغییر دهند یا جایگزین کنند.

مدیر EVS

مدیر EVS ( /packages/services/Car/evs/manager ) بلوک‌های ساختمان مورد نیاز یک برنامه EVS را برای پیاده‌سازی هر چیزی از یک نمایشگر ساده دوربین دید عقب گرفته تا یک رندر چند دوربینی 6DOF فراهم می‌کند. رابط آن از طریق HIDL ارائه شده است و برای پذیرش چندین مشتری همزمان ساخته شده است. سایر برنامه‌ها و سرویس‌ها (مخصوصاً Car Service) می‌توانند وضعیت EVS Manager را برای اطلاع از فعال بودن سیستم EVS پرس و جو کنند.

رابط EVS HIDL

سیستم EVS، هم دوربین و هم عناصر نمایشگر، در بسته android.hardware.automotive.evs تعریف شده است. یک نمونه پیاده‌سازی که رابط را تمرین می‌کند (تصاویر آزمایشی مصنوعی تولید می‌کند و تصاویر را در مسیر رفت و برگشت تأیید می‌کند) در /hardware/interfaces/automotive/evs/1.0/default ارائه شده است.

OEM مسئول پیاده سازی API است که توسط فایل های .hal در /hardware/interfaces/automotive/evs بیان شده است. چنین پیاده‌سازی‌هایی مسئول پیکربندی و جمع‌آوری داده‌ها از دوربین‌های فیزیکی و تحویل آن‌ها از طریق بافرهای حافظه مشترک قابل تشخیص توسط Gralloc هستند. سمت نمایش پیاده‌سازی مسئول ارائه یک بافر حافظه مشترک است که می‌تواند توسط برنامه پر شود (معمولاً از طریق رندر EGL) و ارائه فریم‌های تمام‌شده در اولویت به هر چیز دیگری که ممکن است بخواهد در صفحه نمایش فیزیکی ظاهر شود. پیاده سازی فروشنده رابط EVS ممکن است در /vendor/… /device/… یا hardware/… ذخیره شود (به عنوان مثال، /hardware/[vendor]/[platform]/evs ).

درایورهای کرنل

دستگاهی که پشته EVS را پشتیبانی می کند به درایورهای هسته نیاز دارد. به جای ایجاد درایورهای جدید، OEM ها این گزینه را دارند که از ویژگی های مورد نیاز EVS از طریق درایورهای سخت افزاری دوربین و/یا نمایشگر موجود پشتیبانی کنند. استفاده مجدد از درایورها می تواند سودمند باشد، به خصوص برای درایورهای نمایشگر که در آن ارائه تصویر ممکن است نیاز به هماهنگی با موضوعات فعال دیگر داشته باشد. Android 8.0 شامل یک درایور نمونه مبتنی بر v4l2 (در packages/services/Car/evs/sampleDriver ) است که برای پشتیبانی از v4l2 به هسته و برای ارائه تصویر خروجی به SurfaceFlinger بستگی دارد.

توضیحات رابط سخت افزاری EVS

این بخش HAL را توصیف می کند. از فروشندگان انتظار می رود که پیاده سازی هایی از این API متناسب با سخت افزار خود ارائه دهند.

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);

یک شیء رابط را بدست می آورد که برای تعامل منحصراً با نمایشگر EVS سیستم استفاده می شود. فقط یک کلاینت ممکن است یک نمونه کاربردی از IEvsDisplay را در آن زمان داشته باشد. مشابه رفتار تهاجمی باز توضیح داده شده در openCamera ، یک شی IEvsDisplay جدید ممکن است در هر زمان ایجاد شود و هر نمونه قبلی را غیرفعال کند. نمونه‌های نامعتبر همچنان وجود دارند و به فراخوانی‌های تابع از طرف صاحبان خود پاسخ می‌دهند، اما در صورت مرگ نباید هیچ عملیات جهشی را انجام دهند. در نهایت، انتظار می رود که برنامه مشتری متوجه کدهای بازگشت خطای OWNERSHIP_LOST شود و رابط غیرفعال را ببندد و آزاد کند.

closeDisplay(IEvsDisplay display);

رابط IEvsDisplay را آزاد می کند (و مخالف فراخوانی openDisplay() است). بافرهای برجسته دریافت شده از طریق فراخوانی getTargetBuffer() باید قبل از بستن نمایشگر به نمایشگر بازگردانده شوند.

getDisplayState() generates (DisplayState state);

وضعیت نمایش فعلی را دریافت می کند. اجرای HAL باید وضعیت فعلی واقعی را گزارش کند، که ممکن است با آخرین وضعیت درخواست شده متفاوت باشد. منطق مسئول تغییر حالت های نمایشگر باید در بالای لایه دستگاه وجود داشته باشد و تغییر خود به خود حالت نمایش برای اجرای HAL نامطلوب باشد. اگر نمایشگر در حال حاضر توسط هیچ کلاینت (با تماس با openDisplay) نگهداری نشود، این تابع NOT_OPEN برمی‌گرداند. در غیر این صورت، وضعیت فعلی نمایشگر EVS را گزارش می‌کند (به IEvsDisplay API مراجعه کنید).

struct CameraDesc {
    string      camera_id;
    int32       vendor_flags;       // Opaque value
}
  • camera_id . رشته ای که به طور منحصر به فرد یک دوربین معین را شناسایی می کند. می تواند نام دستگاه هسته دستگاه یا نامی برای دستگاه باشد، مانند نمای عقب . مقدار این رشته توسط اجرای HAL انتخاب شده و توسط پشته بالا به صورت غیر شفاف استفاده می شود.
  • vendor_flags . روشی برای انتقال اطلاعات تخصصی دوربین به صورت غیر شفاف از راننده به یک برنامه سفارشی EVS. بدون تفسیر از راننده به برنامه EVS منتقل می شود که نادیده گرفتن آن رایگان است.

دوربین IEVs

این شی یک دوربین واحد را نشان می دهد و رابط اصلی برای گرفتن تصاویر است.

getCameraInfo() generates (CameraDesc info);

CameraDesc این دوربین را برمی گرداند.

setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);

عمق زنجیره بافری را که از دوربین خواسته می شود پشتیبانی کند، مشخص می کند. تا این حد ممکن است فریم های زیادی به طور همزمان توسط مشتری IEvsCamera نگهداری شود. اگر این تعداد فریم بدون بازگرداندن توسط doneWithFrame به گیرنده تحویل داده شده باشد، جریان از فریم ها می گذرد تا زمانی که یک بافر برای استفاده مجدد برگردانده شود. قانونی است که این تماس در هر زمانی انجام شود، حتی زمانی که جریان‌ها از قبل در حال اجرا هستند، در این صورت بافرها باید در صورت لزوم از زنجیره اضافه یا حذف شوند. اگر تماسی با این نقطه ورودی برقرار نشود، IEvsCamera حداقل یک فریم را به طور پیش فرض پشتیبانی می کند. با قابل قبول تر

اگر باfferCount درخواستی قابل تطبیق نباشد، تابع BUFFER_NOT_AVAILABLE یا کد خطای مرتبط دیگر را برمی‌گرداند. در این حالت، سیستم با مقدار تعیین شده قبلی به کار خود ادامه می دهد.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

درخواست تحویل قاب دوربین EVS از این دوربین را دارد. IEvsCameraStream شروع به دریافت تماس های دوره ای با فریم های تصویر جدید می کند تا زمانی که stopVideoStream() فراخوانی شود. فریم‌ها باید در 500 میلی‌ثانیه پس از تماس startVideoStream تحویل داده شوند و پس از شروع، باید حداقل با سرعت 10 فریم در ثانیه تولید شوند. زمان لازم برای شروع پخش ویدئو به طور موثر در برابر هر زمان مورد نیاز راه اندازی دوربین دنده عقب حساب می شود. اگر جریان شروع نشد، یک کد خطا باید برگردانده شود. در غیر این صورت OK برگردانده می شود.

oneway doneWithFrame(BufferDesc buffer);

فریمی را برمی‌گرداند که توسط IEvsCameraStream تحویل داده شده است. پس از مصرف فریم تحویل داده شده به رابط IEvsCameraStream، فریم باید برای استفاده مجدد به IEvsCamera برگردانده شود. تعداد محدود و محدودی از بافرها در دسترس هستند (احتمالاً به کوچکی یک) و اگر منبع تمام شود، هیچ فریم دیگری تا زمانی که بافری برگردانده نشود، تحویل داده نمی‌شود که به طور بالقوه منجر به فریم‌های نادیده گرفته می‌شود (یک بافر با دسته تهی نشان دهنده انتهای جریان است و نیازی به بازگرداندن آن از طریق این تابع نیست). در صورت موفقیت، OK را برمی‌گرداند، یا کد خطای مناسب که احتمالاً شامل INVALID_ARG یا BUFFER_NOT_AVAILABLE می‌شود.

stopVideoStream();

تحویل قاب های دوربین EVS را متوقف می کند. از آنجایی که تحویل ناهمزمان است، ممکن است فریم‌ها برای مدتی پس از بازگشت این تماس همچنان به دستشان برسد. هر فریم باید بازگردانده شود تا زمانی که بسته شدن جریان به IEvsCameraStream علامت داده شود. فراخوانی stopVideoStream در جریانی که قبلاً متوقف شده یا هرگز شروع نشده است، قانونی است که در این موارد نادیده گرفته می‌شود.

getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);

اطلاعات مربوط به درایور را از اجرای HAL درخواست می کند. مقادیر مجاز برای opaqueIdentifier مختص درایور هستند، اما هیچ مقداری که ارسال شده ممکن است درایور را خراب کند. درایور باید 0 را برای هر opaqueIdentifier ناشناخته برگرداند.

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

یک مقدار خاص درایور را به اجرای HAL ارسال می کند. این برنامه افزودنی فقط برای تسهیل برنامه‌های افزودنی خاص خودرو ارائه شده است و هیچ اجرای 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
}

تصویری را توصیف می کند که از طریق API ارسال شده است. درایو HAL مسئول پر کردن این ساختار برای توصیف بافر تصویر است و سرویس گیرنده HAL باید این ساختار را فقط خواندنی در نظر بگیرد. فیلدها حاوی اطلاعات کافی هستند تا به مشتری اجازه دهند یک شی ANativeWindowBuffer را بازسازی کند، همانطور که ممکن است برای استفاده از تصویر با EGL از طریق پسوند eglCreateImageKHR() لازم باشد.

  • 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 برای شناسایی بافر پس از یک رفت و برگشت از طریق API های HAL. مقدار ذخیره شده در این فیلد ممکن است به طور دلخواه توسط اجرای HAL انتخاب شود.
  • memHandle . دسته برای بافر حافظه زیرین که حاوی داده های تصویر است. اجرای HAL ممکن است یک دسته بافر Gralloc را در اینجا ذخیره کند.

IEvsCameraStream

مشتری این رابط را برای دریافت تحویل فریم های ویدئویی ناهمزمان پیاده سازی می کند.

deliverFrame(BufferDesc buffer);

هر بار که فریم ویدیویی برای بازرسی آماده می شود، از HAL تماس دریافت می کند. دسته‌های بافر دریافت‌شده توسط این روش باید از طریق فراخوانی به IEvsCamera::doneWithFrame() برگردانده شوند. هنگامی که جریان ویدیو از طریق تماس با IEvsCamera::stopVideoStream() متوقف می شود، ممکن است این تماس با تخلیه خط لوله ادامه یابد. هر فریم همچنان باید بازگردانده شود. هنگامی که آخرین فریم در جریان تحویل داده شد، یک بافرHandle NULL تحویل داده می شود که به معنای پایان جریان است و هیچ تحویل فریم دیگری اتفاق نمی افتد. خود NULL bufferHandle نیازی به بازگردانی از طریق doneWithFrame() ندارد، اما همه دسته های دیگر باید برگردانده شوند.

در حالی که فرمت‌های بافر اختصاصی از نظر فنی امکان‌پذیر است، آزمایش سازگاری مستلزم آن است که بافر در یکی از چهار قالب پشتیبانی‌شده باشد: NV21 (YCrCb 4:2:0 نیمه مسطح)، YV12 (YCrCb 4:2:0 مسطح)، YUYV (YCrCb 4:2:2 (YCrCb 4:2:2 (RBT:RBT:RBX2) (32 بیت B:G:R:x). قالب انتخابی باید یک منبع بافت GL معتبر در اجرای GLES پلت فرم باشد.

برنامه نباید به هیچ گونه مطابقت بین فیلد bufferId و memHandle در ساختار BufferDesc متکی باشد. مقادیر bufferId اساساً برای اجرای درایور HAL خصوصی هستند و ممکن است هر طور که صلاح می‌داند از آنها استفاده کند (و مجدداً استفاده کند).

IEvsDisplay

این شیء نمایشگر Evs را نشان می دهد، وضعیت نمایشگر را کنترل می کند و نمایش واقعی تصاویر را مدیریت می کند.

getDisplayInfo() generates (DisplayDesc info);

اطلاعات اولیه در مورد صفحه نمایش EVS ارائه شده توسط سیستم را برمی گرداند (به DisplayDesc مراجعه کنید).

setDisplayState(DisplayState state) generates (EvsResult result);

وضعیت نمایش را تنظیم می کند. کلاینت‌ها ممکن است وضعیت نمایش را برای بیان حالت دلخواه تنظیم کنند، و اجرای HAL باید درخواستی را برای هر حالتی که در هر حالت دیگری است بپذیرد، اگرچه پاسخ ممکن است نادیده گرفتن درخواست باشد.

پس از مقداردهی اولیه، نمایشگر در حالت NOT_VISIBLE شروع به کار می کند، پس از آن انتظار می رود مشتری وضعیت VISIBLE_ON_NEXT_FRAME را درخواست کند و شروع به ارائه ویدیو کند. هنگامی که نمایشگر دیگر مورد نیاز نیست، انتظار می رود که مشتری پس از عبور از آخرین فریم ویدیو، حالت NOT_VISIBLE را درخواست کند.

برای هر ایالتی که در هر زمانی درخواست شود معتبر است. اگر نمایشگر از قبل قابل مشاهده است، اگر روی VISIBLE_ON_NEXT_FRAME تنظیم شده باشد، باید قابل مشاهده باقی بماند. همیشه OK را برمی‌گرداند مگر اینکه حالت درخواستی یک مقدار enum ناشناخته باشد که در این صورت INVALID_ARG برگردانده می‌شود.

getDisplayState() generates (DisplayState state);

حالت نمایش را دریافت می کند. اجرای HAL باید وضعیت فعلی واقعی را گزارش کند، که ممکن است با آخرین وضعیت درخواست شده متفاوت باشد. منطق مسئول تغییر حالت های نمایشگر باید در بالای لایه دستگاه وجود داشته باشد و تغییر خود به خود حالت نمایش برای اجرای HAL نامطلوب باشد.

getTargetBuffer() generates (handle bufferHandle);

یک دسته را به یک فریم بافر مرتبط با نمایشگر برمی گرداند. این بافر ممکن است توسط نرم افزار و/یا GL قفل شده و نوشته شود. این بافر باید از طریق فراخوانی به returnTargetBufferForDisplay() بازگردانده شود، حتی اگر نمایشگر دیگر قابل مشاهده نباشد.

در حالی که فرمت‌های بافر اختصاصی از نظر فنی امکان‌پذیر است، آزمایش سازگاری مستلزم آن است که بافر در یکی از چهار قالب پشتیبانی‌شده باشد: NV21 (YCrCb 4:2:0 نیمه مسطح)، YV12 (YCrCb 4:2:0 مسطح)، YUYV (YCrCb 4:2:2 (YCrCb 4:2:2 (RBT:RBT:RBX2) (32 بیت B:G:R:x). قالب انتخابی باید یک هدف رندر GL معتبر در اجرای GLES پلت فرم باشد.

در صورت بروز خطا، بافری با دسته تهی برگردانده می‌شود، اما نیازی نیست که چنین بافری به returnTargetBufferForDisplay بازگردانده شود.

returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);

به نمایشگر می گوید که بافر برای نمایش آماده است. فقط بافرهای بازیابی شده از طریق تماس با getTargetBuffer() برای استفاده با این تماس معتبر هستند و ممکن است محتویات BufferDesc توسط برنامه مشتری تغییر نکند. پس از این تماس، بافر دیگر برای استفاده توسط مشتری معتبر نیست. در صورت موفقیت، OK را برمی‌گرداند، یا کد خطای مناسب که احتمالاً شامل INVALID_ARG یا BUFFER_NOT_AVAILABLE می‌شود.

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

ویژگی های اساسی نمایشگر EVS و مورد نیاز اجرای EVS را شرح می دهد. HAL مسئول پر کردن این ساختار برای توصیف صفحه نمایش EVS است. می تواند یک نمایشگر فیزیکی یا یک نمایشگر مجازی باشد که با دستگاه ارائه دیگری روی هم قرار گرفته یا ترکیب شده است.

  • display_id . رشته ای که به طور منحصر به فرد نمایشگر را مشخص می کند. این می‌تواند نام دستگاه هسته دستگاه یا نامی برای دستگاه، مانند نمای عقب باشد. مقدار این رشته توسط اجرای HAL انتخاب شده و توسط پشته بالا به صورت غیر شفاف استفاده می شود.
  • vendor_flags . روشی برای انتقال اطلاعات تخصصی دوربین به صورت غیر شفاف از راننده به یک برنامه سفارشی EVS. بدون تفسیر از راننده به برنامه EVS منتقل می شود که نادیده گرفتن آن رایگان است.
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
}

وضعیت نمایشگر EVS را توصیف می کند که می تواند غیرفعال شود (برای راننده قابل مشاهده نیست) یا فعال شود (نمایش تصویر به راننده). شامل یک حالت گذرا است که در آن نمایشگر هنوز قابل مشاهده نیست اما آماده است تا با تحویل فریم بعدی تصاویر از طریق فراخوانی returnTargetBufferForDisplay() قابل مشاهده باشد.

مدیر EVS

مدیر EVS رابط عمومی را برای سیستم EVS برای جمع آوری و ارائه نماهای دوربین خارجی فراهم می کند. در جایی که درایورهای سخت افزاری تنها به یک رابط فعال در هر منبع (دوربین یا نمایشگر) اجازه می دهند، مدیر EVS دسترسی مشترک به دوربین ها را تسهیل می کند. یک برنامه اولیه EVS اولین مشتری EVS Manager است و تنها سرویس گیرنده ای است که مجاز به نوشتن داده های نمایشی است (به مشتریان اضافی می توان به تصاویر دوربین دسترسی فقط خواندنی داد).

مدیر EVS همان API درایورهای HAL زیربنایی را پیاده‌سازی می‌کند و خدمات گسترده‌ای را با پشتیبانی از چندین کلاینت همزمان ارائه می‌کند (بیش از یک کلاینت می‌توانند یک دوربین را از طریق مدیر EVS باز کنند و یک جریان ویدیویی دریافت کنند).

مدیر EVS و نمودار API سخت افزار EVS.

شکل 2. EVS Manager آینه های زیربنایی EVS Hardware API.

برنامه‌ها هنگام کار از طریق اجرای HAL سخت‌افزار EVS یا API مدیریت EVS هیچ تفاوتی نمی‌بینند، به جز اینکه EVS Manager API امکان دسترسی همزمان به جریان دوربین را می‌دهد. مدیر EVS خود مشتری مجاز لایه HAL سخت افزار EVS است و به عنوان یک پروکسی برای HAL سخت افزار EVS عمل می کند.

بخش‌های زیر فقط تماس‌هایی را توصیف می‌کنند که رفتار (گسترده) متفاوتی در اجرای EVS Manager دارند. تماس های باقی مانده با توضیحات EVS HAL یکسان هستند.

IEvsEnumerator

openCamera(string camera_id) generates (IEvsCamera camera);

یک شئ رابط مورد استفاده برای تعامل با یک دوربین خاص که توسط رشته منحصر به فرد camera_id شناسایی شده است را به دست می آورد. در صورت شکست یک عدد NULL برمی گرداند. در لایه EVS Manager، تا زمانی که منابع سیستم کافی در دسترس باشد، دوربینی که از قبل باز است ممکن است با فرآیند دیگری دوباره باز شود و امکان پخش جریان ویدئو را به چندین برنامه مصرف کننده فراهم کند. رشته های camera_id در لایه EVS Manager همان رشته هایی است که به لایه سخت افزار EVS گزارش شده است.

دوربین IEVs

مدیر 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

فقط یک مالک نمایشگر مجاز است، حتی در سطح مدیر EVS. مدیر هیچ عملکردی اضافه نمی کند و به سادگی رابط IEvsDisplay را مستقیماً به پیاده سازی زیرین HAL منتقل می کند.

برنامه EVS

Android شامل یک پیاده سازی مرجع C++ از یک برنامه EVS است که با مدیر EVS و Vehicle HAL برای ارائه عملکردهای اولیه دوربین دید عقب ارتباط برقرار می کند. انتظار می‌رود این برنامه در مراحل اولیه راه‌اندازی سیستم، با ویدیوی مناسب بسته به دوربین‌های موجود و وضعیت خودرو (دنده و وضعیت چراغ راه‌انداز) شروع به کار کند. OEM ها می توانند برنامه EVS را با منطق و ارائه خاص وسیله نقلیه خود تغییر دهند یا جایگزین کنند.

شکل 3. منطق نمونه برنامه EVS، لیست دوربین را دریافت کنید.



شکل 4. منطق نمونه برنامه EVS، پاسخ تماس فریم را دریافت کنید.

از آنجایی که داده های تصویر در یک بافر گرافیکی استاندارد به برنامه ارائه می شود، برنامه وظیفه انتقال تصویر از بافر منبع به بافر خروجی را بر عهده دارد. در حالی که این هزینه کپی داده را معرفی می کند، همچنین این فرصت را برای برنامه فراهم می کند تا تصویر را به هر شکلی که می خواهد در بافر نمایشگر ارائه دهد.

برای مثال، برنامه ممکن است انتخاب کند که داده‌های پیکسل را خودش جابه‌جا کند، احتمالاً با مقیاس درون خطی یا عملیات چرخش. این برنامه همچنین می‌تواند از تصویر منبع به عنوان یک بافت OpenGL استفاده کند و یک صحنه پیچیده را در بافر خروجی، از جمله عناصر مجازی مانند آیکون‌ها، دستورالعمل‌ها و انیمیشن‌ها ارائه دهد. یک برنامه پیچیده تر همچنین ممکن است چندین دوربین ورودی همزمان را انتخاب کرده و آنها را در یک فریم خروجی واحد ادغام کند (مانند استفاده در یک نمای مجازی از بالا به پایین از محیط اطراف خودرو).

از EGL/SurfaceFlinger در EVS Display HAL استفاده کنید

این بخش نحوه استفاده از EGL را برای رندر کردن اجرای EVS Display HAL در اندروید 10 توضیح می‌دهد.

یک پیاده‌سازی مرجع EVS HAL از EGL برای رندر کردن پیش‌نمایش دوربین روی صفحه و از libgui برای ایجاد سطح رندر EGL هدف استفاده می‌کند. در Android 8 (و بالاتر)، libgui به عنوان VNDK-private طبقه‌بندی می‌شود که به گروهی از کتابخانه‌های موجود در کتابخانه‌های VNDK اشاره دارد که پردازش‌های فروشنده نمی‌توانند از آنها استفاده کنند. از آنجا که پیاده سازی های HAL باید در پارتیشن فروشنده قرار داشته باشند، فروشندگان از استفاده از Surface در پیاده سازی های HAL جلوگیری می کنند.

ساخت libgui برای فرآیندهای فروشنده

استفاده از libgui به عنوان تنها گزینه برای استفاده از EGL/SurfaceFlinger در اجرای EVS Display HAL عمل می کند. ساده ترین راه برای پیاده سازی libgui از طریق فریمورک/نیتیو/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 استفاده کنید

در اندروید 8 (و بالاتر)، گره دستگاه /dev/binder منحصر به فرآیندهای فریمورک شد و بنابراین برای فرآیندهای فروشنده غیرقابل دسترسی بود. در عوض، فرآیندهای فروشنده باید از /dev/hwbinder استفاده کنند و باید هر رابط AIDL را به HIDL تبدیل کنند. برای کسانی که می خواهند به استفاده از رابط های AIDL بین فرآیندهای فروشنده ادامه دهند، از دامنه binder، /dev/vndbinder استفاده کنند.

دامنه IPC توضیحات
/dev/binder IPC بین فرآیندهای چارچوب/برنامه با رابط های AIDL
/dev/hwbinder IPC بین فرآیندهای چارچوب/فروشنده با رابط های HIDL
IPC بین فرآیندهای فروشنده با رابط های HIDL
/dev/vndbinder IPC بین فرآیندهای فروشنده/فروشنده با رابط های AIDL

در حالی که SurfaceFlinger رابط های AIDL را تعریف می کند، فرآیندهای فروشنده فقط می توانند از رابط های HIDL برای ارتباط با فرآیندهای چارچوب استفاده کنند. برای تبدیل رابط‌های AIDL موجود به HIDL، مقدار کمی کار لازم است. خوشبختانه، اندروید روشی را برای انتخاب درایور بایندر برای 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 اختصاص داده شده است و به مجوزهای r/w برای دامنه 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

با این حال، افزودن این مجوزها باعث خرابی ساخت می‌شود، زیرا قوانین neverallow زیر را که در 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;
،

اندروید حاوی یک لایه انتزاعی سخت افزاری HIDL (HAL) است که در مراحل اولیه بوت اندروید امکان ضبط و نمایش تصاویر را فراهم می کند و تا پایان عمر سیستم به کار خود ادامه می دهد. HAL شامل پشته سیستم نمای خارجی (EVS) است و معمولاً برای پشتیبانی از دوربین دید عقب و نمایشگرهای دید فراگیر در خودروهایی با سیستم‌های In-Vehicle Infotainment (IVI) مبتنی بر Android استفاده می‌شود. EVS همچنین امکان پیاده سازی ویژگی های پیشرفته را در برنامه های کاربر فراهم می کند.

اندروید همچنین شامل یک رابط درایور عکسبرداری و نمایشگر مخصوص EVS است (در /hardware/interfaces/automotive/evs/1.0 ). در حالی که امکان ساخت یک برنامه دوربین دید عقب در بالای خدمات دوربین و نمایشگر اندروید موجود وجود دارد، چنین برنامه ای احتمالاً در فرآیند بوت اندروید بسیار دیر اجرا می شود. استفاده از یک HAL اختصاصی، یک رابط کارآمد را فعال می‌کند و روشن می‌کند که یک OEM برای پشتیبانی از پشته EVS چه چیزی را باید پیاده‌سازی کند.

اجزای سیستم

EVS شامل اجزای سیستم زیر است:

سیستم EVS نمودار اجزاء

شکل 1. نمای کلی اجزای سیستم EVS.

برنامه EVS

یک نمونه برنامه C++ EVS ( /packages/services/Car/evs/app ) به عنوان پیاده‌سازی مرجع عمل می‌کند. این برنامه مسئول درخواست فریم های ویدیویی از مدیر EVS و ارسال فریم های تمام شده برای نمایش به مدیر EVS است. انتظار می رود به محض در دسترس بودن EVS و Car Service، توسط init راه اندازی شود و در عرض دو (2) ثانیه پس از روشن شدن روشن شود. OEM ها می توانند برنامه EVS را به دلخواه تغییر دهند یا جایگزین کنند.

مدیر EVS

مدیر EVS ( /packages/services/Car/evs/manager ) بلوک‌های ساختمان مورد نیاز یک برنامه EVS را برای پیاده‌سازی هر چیزی از یک نمایشگر ساده دوربین دید عقب گرفته تا یک رندر چند دوربینی 6DOF فراهم می‌کند. رابط آن از طریق HIDL ارائه شده است و برای پذیرش چندین مشتری همزمان ساخته شده است. سایر برنامه‌ها و سرویس‌ها (مخصوصاً Car Service) می‌توانند وضعیت EVS Manager را برای اطلاع از فعال بودن سیستم EVS پرس و جو کنند.

رابط EVS HIDL

سیستم EVS، هم دوربین و هم عناصر نمایشگر، در بسته android.hardware.automotive.evs تعریف شده است. یک نمونه پیاده‌سازی که رابط را تمرین می‌کند (تصاویر آزمایشی مصنوعی تولید می‌کند و تصاویر را در مسیر رفت و برگشت تأیید می‌کند) در /hardware/interfaces/automotive/evs/1.0/default ارائه شده است.

OEM مسئول پیاده سازی API است که توسط فایل های .hal در /hardware/interfaces/automotive/evs بیان شده است. چنین پیاده‌سازی‌هایی مسئول پیکربندی و جمع‌آوری داده‌ها از دوربین‌های فیزیکی و تحویل آن‌ها از طریق بافرهای حافظه مشترک قابل تشخیص توسط Gralloc هستند. سمت نمایش پیاده‌سازی مسئول ارائه یک بافر حافظه مشترک است که می‌تواند توسط برنامه پر شود (معمولاً از طریق رندر EGL) و ارائه فریم‌های تمام‌شده در اولویت به هر چیز دیگری که ممکن است بخواهد در صفحه نمایش فیزیکی ظاهر شود. پیاده سازی فروشنده رابط EVS ممکن است در /vendor/… /device/… یا hardware/… ذخیره شود (به عنوان مثال، /hardware/[vendor]/[platform]/evs ).

درایورهای کرنل

دستگاهی که پشته EVS را پشتیبانی می کند به درایورهای هسته نیاز دارد. به جای ایجاد درایورهای جدید، OEM ها این گزینه را دارند که از ویژگی های مورد نیاز EVS از طریق درایورهای سخت افزاری دوربین و/یا نمایشگر موجود پشتیبانی کنند. استفاده مجدد از درایورها می تواند سودمند باشد، به خصوص برای درایورهای نمایشگر که در آن ارائه تصویر ممکن است نیاز به هماهنگی با موضوعات فعال دیگر داشته باشد. Android 8.0 شامل یک درایور نمونه مبتنی بر v4l2 (در packages/services/Car/evs/sampleDriver ) است که برای پشتیبانی از v4l2 به هسته و برای ارائه تصویر خروجی به SurfaceFlinger بستگی دارد.

توضیحات رابط سخت افزاری EVS

این بخش HAL را توصیف می کند. از فروشندگان انتظار می رود که پیاده سازی هایی از این API متناسب با سخت افزار خود ارائه دهند.

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);

یک شیء رابط را بدست می آورد که برای تعامل منحصراً با نمایشگر EVS سیستم استفاده می شود. فقط یک کلاینت ممکن است یک نمونه کاربردی از IEvsDisplay را در آن زمان داشته باشد. مشابه رفتار تهاجمی باز توضیح داده شده در openCamera ، یک شی IEvsDisplay جدید ممکن است در هر زمان ایجاد شود و هر نمونه قبلی را غیرفعال کند. نمونه‌های نامعتبر همچنان وجود دارند و به فراخوانی‌های تابع از طرف صاحبان خود پاسخ می‌دهند، اما در صورت مرگ نباید هیچ عملیات جهشی را انجام دهند. در نهایت، انتظار می رود که برنامه مشتری متوجه کدهای بازگشت خطای OWNERSHIP_LOST شود و رابط غیرفعال را ببندد و آزاد کند.

closeDisplay(IEvsDisplay display);

رابط IEvsDisplay را آزاد می کند (و مخالف فراخوانی openDisplay() است). بافرهای برجسته دریافت شده از طریق فراخوانی getTargetBuffer() باید قبل از بستن نمایشگر به نمایشگر بازگردانده شوند.

getDisplayState() generates (DisplayState state);

وضعیت نمایش فعلی را دریافت می کند. اجرای HAL باید وضعیت فعلی واقعی را گزارش کند، که ممکن است با آخرین وضعیت درخواست شده متفاوت باشد. منطق مسئول تغییر حالت های نمایشگر باید در بالای لایه دستگاه وجود داشته باشد و تغییر خود به خود حالت نمایش برای اجرای HAL نامطلوب باشد. اگر نمایشگر در حال حاضر توسط هیچ کلاینت (با تماس با openDisplay) نگهداری نشود، این تابع NOT_OPEN برمی‌گرداند. در غیر این صورت، وضعیت فعلی نمایشگر EVS را گزارش می‌کند (به IEvsDisplay API مراجعه کنید).

struct CameraDesc {
    string      camera_id;
    int32       vendor_flags;       // Opaque value
}
  • camera_id . رشته ای که به طور منحصر به فرد یک دوربین معین را شناسایی می کند. می تواند نام دستگاه هسته دستگاه یا نامی برای دستگاه باشد ، مانند Rearview . مقدار این رشته توسط اجرای HAL انتخاب شده و از طریق پشته بالا استفاده می شود.
  • vendor_flags . روشی برای انتقال اطلاعات ویژه دوربین از درایور به یک برنامه EVS سفارشی. از درایور تا برنامه EVS بدون تفسیر منتقل می شود ، که می توان آن را نادیده گرفت.

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);

درخواست تحویل فریم های دوربین EVS از این دوربین را می دهد. IEVSCAMERASTREAM شروع به دریافت تماس های دوره ای با قاب های تصویر جدید تا زمان فراخوانی stopVideoStream() می کند. فریم ها باید در 500ms از تماس startVideoStream تحویل داده شوند و پس از شروع ، باید حداقل 10 فریم در ثانیه تولید شوند. زمان لازم برای شروع جریان ویدیو به طور مؤثر در برابر هرگونه نیاز به زمان راه اندازی دوربین عقب حساب می شود. اگر جریان شروع نشود ، باید یک کد خطا بازگردانده شود. در غیر این صورت خوب بازگردانده می شود.

oneway doneWithFrame(BufferDesc buffer);

قاب را که به IEVScameraStream تحویل داده شده است ، برمی گرداند. پس از اتمام مصرف یک قاب که به رابط ievscamerastream تحویل داده می شود ، قاب باید برای استفاده مجدد به ievscamera برگردانده شود. تعداد کمی از بافرها در دسترس هستند (احتمالاً به اندازه یک کوچک) ، و اگر عرضه خسته شود ، هیچ فریم دیگری تحویل داده نمی شود تا یک بافر بازگردانده شود ، به طور بالقوه منجر به فریم های پرش شده می شود (یک بافر با یک دسته تهی نشانگر انتهای یک جریان است و نیازی به بازگشت از طریق این عملکرد نیست). در موفقیت ، یا کد خطای مناسب به طور بالقوه شامل INVALID_ARG یا BUFFER_NOT_AVAILABLE باز می گردد.

stopVideoStream();

تحویل فریم های دوربین EVS را متوقف می کند. از آنجا که تحویل ناهمزمان است ، فریم ها ممکن است پس از بازگشت این تماس ، مدتی به آنجا برسند. هر قاب باید برگردانده شود تا بسته شدن جریان به IEVSCAMERASTREAM علامت گذاری شود. قانونی است که از stopVideoStream در جریانی تماس بگیرید که قبلاً متوقف شده یا هرگز شروع نشده است ، که در آن موارد نادیده گرفته می شود.

getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);

اطلاعات خاص راننده را از اجرای HAL درخواست می کند. مقادیر مجاز برای opaqueIdentifier خاص درایور هستند ، اما هیچ مقداری عبور نمی کند ممکن است درایور را خراب کند. درایور باید 0 را برای هر opaqueIdentifier ناشناخته بازگرداند.

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

مقدار خاص درایور را به اجرای HAL ارسال می کند. این پسوند فقط برای تسهیل پسوندهای خاص وسیله نقلیه ارائه شده است و هیچ اجرای HAL نباید این تماس را در حالت پیش فرض انجام دهد. اگر راننده مقادیر را تشخیص دهد و بپذیرد ، باید برگشت داده شود. در غیر این صورت باید کد خطای 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
}

تصویری را که از طریق API منتقل شده است ، توصیف می کند. درایو HAL وظیفه پر کردن این ساختار را برای توصیف بافر تصویر دارد و مشتری HAL باید این ساختار را فقط به عنوان خواندنی رفتار کند. این زمینه ها حاوی اطلاعات کافی هستند تا مشتری بتواند یک شیء ANativeWindowBuffer را بازسازی کند ، همانطور که ممکن است برای استفاده از تصویر با EGL از طریق eglCreateImageKHR() استفاده شود.

  • 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 برای اینکه یک بافر پس از یک سفر دور از طریق API های HAL شناخته شود. مقدار ذخیره شده در این زمینه ممکن است به طور خودسرانه توسط اجرای HAL انتخاب شود.
  • memHandle دسته برای بافر حافظه زیرین که حاوی داده های تصویر است. اجرای HAL ممکن است برای ذخیره یک دسته بافر Gralloc در اینجا انتخاب کند.

ievscamerastream

مشتری این رابط را برای دریافت تحویل قاب ویدیویی ناهمزمان پیاده سازی می کند.

deliverFrame(BufferDesc buffer);

هر بار که یک قاب ویدیویی برای بازرسی آماده است ، از HAL تماس می گیرد. دستگیره های بافر دریافت شده توسط این روش باید از طریق تماس به IEvsCamera::doneWithFrame() بازگردانده شود. هنگامی که جریان ویدیو از طریق تماس با IEvsCamera::stopVideoStream() متوقف می شود ، ممکن است با تخلیه خط لوله ، این پاسخ به تماس ادامه یابد. هر فریم هنوز باید برگردانده شود. هنگامی که آخرین قاب موجود در جریان تحویل داده شود ، یک بافر تهی تحویل داده می شود ، که نشانگر پایان جریان است و هیچ گونه تحویل فریم دیگری رخ نمی دهد. خود Bufferhandle خود نیازی به ارسال مجدد از طریق doneWithFrame() ندارد ، اما باید همه دستگیره های دیگر برگردانده شود

در حالی که قالبهای بافر اختصاصی از نظر فنی امکان پذیر است ، آزمایش سازگاری نیاز به بافر در یکی از چهار فرمت پشتیبانی شده دارد: NV21 (YCRCB 4: 2: 0 نیمه پلانار) ، yv12 (ycrcb 4: 2: 0 مسطح) ، yuyv (ycrcb 4: 2: 2: 2: 2: 2 interled) ، bgr: x rgba (32 bit rgba (32 rgba) (32 بیتی B: G: R: X). قالب انتخاب شده باید یک منبع معتبر GL Texture در اجرای GLES پلتفرم باشد.

برنامه نباید به هر مکاتبات بین میدان bufferId و memHandle در ساختار BufferDesc متکی باشد. مقادیر bufferId در اصل برای اجرای درایور HAL خصوصی است و ممکن است از آنها استفاده کند (و از آنها استفاده مجدد) همانطور که مناسب می بیند.

ievsdisplay

این شیء نمایشگر EVS را نشان می دهد ، وضعیت صفحه نمایش را کنترل می کند و ارائه واقعی تصاویر را کنترل می کند.

getDisplayInfo() generates (DisplayDesc info);

اطلاعات اساسی در مورد نمایشگر EVS ارائه شده توسط سیستم را برمی گرداند (به 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);

وضعیت نمایش را می گیرد. اجرای HAL باید وضعیت فعلی فعلی را گزارش کند ، که ممکن است با بیشترین وضعیت درخواست شده متفاوت باشد. منطق مسئول تغییر حالتهای نمایش باید در بالای لایه دستگاه وجود داشته باشد ، و این امر را برای اجرای HAL برای تغییر خود به خود حالت های نمایش نامطلوب می کند.

getTargetBuffer() generates (handle bufferHandle);

یک دسته را به یک بافر فریم مرتبط با صفحه نمایش برمی گرداند. این بافر ممکن است توسط نرم افزار و/یا GL به آن قفل و نوشته شود. این بافر باید از طریق تماس با returnTargetBufferForDisplay() برگردانده شود حتی اگر صفحه نمایش دیگر قابل مشاهده نباشد.

در حالی که قالبهای بافر اختصاصی از نظر فنی امکان پذیر است ، آزمایش سازگاری نیاز به بافر در یکی از چهار فرمت پشتیبانی شده دارد: NV21 (YCRCB 4: 2: 0 نیمه پلانار) ، yv12 (ycrcb 4: 2: 0 مسطح) ، yuyv (ycrcb 4: 2: 2: 2: 2: 2 interled) ، bgr: x rgba (32 bit rgba (32 rgba) (32 بیتی B: G: R: X). قالب انتخاب شده باید یک هدف ارائه GL معتبر در اجرای GLES پلتفرم باشد.

در خطا ، یک بافر با یک دسته تهی بازگردانده می شود ، اما چنین بافر نیازی به انتقال به returnTargetBufferForDisplay ندارد.

returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);

به صفحه نمایش می گوید که بافر برای نمایش آماده است. فقط بافرهای بازیابی شده از طریق تماس با getTargetBuffer() برای استفاده با این تماس معتبر هستند و محتوای BufferDesc ممکن است توسط برنامه مشتری اصلاح نشود. پس از این تماس ، بافر دیگر برای استفاده توسط مشتری معتبر نیست. در موفقیت ، یا کد خطای مناسب به طور بالقوه شامل INVALID_ARG یا BUFFER_NOT_AVAILABLE باز می گردد.

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

خصوصیات اساسی یک نمایشگر EVS را توصیف می کند و توسط اجرای EVS مورد نیاز است. HAL مسئول پر کردن این ساختار برای توصیف صفحه نمایش EVS است. می تواند یک نمایشگر فیزیکی یا یک صفحه نمایش مجازی باشد که با دستگاه ارائه دیگری پوشانده شده یا مخلوط شود.

  • display_id . رشته ای که منحصر به فرد صفحه نمایش را مشخص می کند. این می تواند نام دستگاه هسته دستگاه یا نامی برای دستگاه مانند Rearview باشد. مقدار این رشته توسط اجرای HAL انتخاب شده و از طریق پشته بالا استفاده می شود.
  • vendor_flags . روشی برای انتقال اطلاعات ویژه دوربین از درایور به یک برنامه EVS سفارشی. از درایور تا برنامه EVS بدون تفسیر منتقل می شود ، که می توان آن را نادیده گرفت.
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
}

وضعیت صفحه نمایش EVS را توصیف می کند ، که می تواند غیرفعال شود (برای درایور قابل مشاهده نیست) یا فعال شده (نشان دادن تصویری به درایور). شامل یک حالت گذرا است که هنوز صفحه نمایش قابل مشاهده نیست اما با تحویل قاب بعدی تصاویر از طریق تماس returnTargetBufferForDisplay() آماده می شود.

مدیر EVS

مدیر EVS برای جمع آوری و ارائه نماهای دوربین خارجی ، رابط عمومی را در سیستم EVS فراهم می کند. در جایی که درایورهای سخت افزاری فقط یک رابط فعال در هر منبع (دوربین یا نمایشگر) اجازه می دهند ، مدیر EVS دسترسی مشترک به دوربین ها را تسهیل می کند. یک برنامه اولیه EVS اولین مشتری مدیر EVS است و تنها مشتری مجاز به نوشتن داده های نمایشگر است (مشتری های اضافی می توانند به تصاویر دوربین دسترسی داشته باشند).

مدیر EVS همان API را به عنوان درایورهای اصلی HAL پیاده سازی می کند و با پشتیبانی از چندین مشتری همزمان ، خدمات گسترده ای را ارائه می دهد (بیش از یک مشتری می تواند یک دوربین را از طریق مدیر EVS باز کند و یک جریان ویدیویی دریافت کند).

مدیر EVS و نمودار API سخت افزار EVS.

شکل 2 آینه مدیر EVS در زیر API سخت افزار EVS.

برنامه ها هنگام کار از طریق اجرای HAL HAL سخت افزار EVS یا API مدیر EVS هیچ تفاوتی نمی بینند به جز اینکه API مدیر EVS امکان دسترسی به جریان دوربین همزمان را فراهم می کند. مدیر EVS به خودی خود ، مشتری مجاز به لایه سخت افزار HAL HAL است و به عنوان یک پروکسی برای HAL HAL سخت افزار EVS عمل می کند.

بخش های زیر فقط آن دسته از تماس هایی را که دارای رفتار متفاوت (گسترده) در اجرای مدیر EVS هستند ، شرح می دهد. تماس های باقیمانده با توضیحات EVS HAL یکسان است.

Ievsenumerator

openCamera(string camera_id) generates (IEvsCamera camera);

یک شیء رابط مورد استفاده برای تعامل با یک دوربین خاص مشخص شده توسط رشته منحصر به فرد Camera_ID را بدست می آورد. یک تهی را در مورد شکست برمی گرداند. در لایه EVS Manager ، تا زمانی که منابع سیستم کافی در دسترس باشد ، ممکن است دوربینی که در حال حاضر باز است ، دوباره توسط یک فرآیند دیگر باز شود و اجازه می دهد تا جریان ویدیو را به چندین برنامه مصرف کننده تبدیل کند. رشته های camera_id در لایه EVS Manager همان مواردی است که به لایه سخت افزار 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

فقط یک مالک نمایشگر حتی در سطح EVS Manager مجاز است. مدیر هیچ عملکردی را اضافه نمی کند و به سادگی رابط IEVSDISPLAY را مستقیماً به اجرای HAL اساسی منتقل می کند.

برنامه EVS

Android شامل اجرای مرجع C ++ بومی از یک برنامه EVS است که با مدیر EVS و وسیله نقلیه HAL ارتباط برقرار می کند تا عملکردهای اصلی دوربین عقب را ارائه دهد. انتظار می رود این برنامه خیلی زود در فرآیند بوت سیستم شروع شود ، با فیلم مناسب بسته به دوربین های موجود و وضعیت خودرو (حالت دنده و حالت سیگنال) نشان داده شده است. OEM ها می توانند برنامه EVS را با منطق و ارائه خاص خودرو خود تغییر داده یا جایگزین کنند.

شکل 3. منطق نمونه برنامه EVS ، لیست دوربین را دریافت کنید.



شکل 4. منطق نمونه برنامه EVS ، پاسخ به تماس فریم را دریافت کنید.

از آنجا که داده های تصویر در یک بافر گرافیکی استاندارد به برنامه ارائه می شود ، برنامه وظیفه انتقال تصویر از بافر منبع به بافر خروجی را بر عهده دارد. در حالی که این هزینه یک کپی داده را معرفی می کند ، همچنین فرصتی را برای برنامه فراهم می کند تا تصویر را به هر روشی که بخواهد به بافر صفحه نمایش منتقل کند.

به عنوان مثال ، برنامه ممکن است داده های پیکسل را به طور بالقوه با مقیاس درون خطی یا عملکرد چرخش تغییر دهد. این برنامه همچنین می تواند از تصویر منبع به عنوان یک بافت OpenGL استفاده کند و صحنه ای پیچیده را به بافر خروجی ، از جمله عناصر مجازی مانند نمادها ، دستورالعمل ها و انیمیشن ها ارائه دهد. یک برنامه پیشرفته تر همچنین ممکن است چندین دوربین ورودی همزمان را انتخاب کرده و آنها را در قاب خروجی منفرد (مانند استفاده در یک نمای از بالا به پایین و مجازی از محیط وسیله نقلیه) ادغام کند.

از EGL/SurfaceFlinger در نمایشگر EVS HAL استفاده کنید

در این بخش نحوه استفاده از EGL برای ارائه نمایشگر EVS نمایش HAL در Android 10 توضیح داده شده است.

اجرای مرجع EVS HAL از EGL برای ارائه پیش نمایش دوربین روی صفحه استفاده می کند و libgui برای ایجاد سطح Render Target EGL استفاده می کند. در Android 8 (و بالاتر) ، libgui به عنوان VNDK-Private طبقه بندی می شود ، که به گروهی از کتابخانه های موجود در کتابخانه های VNDK اشاره دارد که فرآیندهای فروشنده نمی توانند از آن استفاده کنند. از آنجا که اجرای HAL باید در پارتیشن فروشنده ساکن باشد ، از فروشندگان از استفاده از سطح در پیاده سازی های HAL جلوگیری می شود.

ساختمان Libgui برای فرآیندهای فروشنده

استفاده از libgui به عنوان تنها گزینه استفاده از EGL/SurfaceFlinger در نمایشگاه های HAL نمایش داده می شود. ساده ترین روش برای اجرای 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 انتظار دارد این زمینه را که برداشته شده است ، SuffaceFlinger نتواند بسته را تجزیه کند. این به عنوان یک شکست 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

از Binder در اجرای EVS HAL استفاده کنید

در Android 8 (و بالاتر) ، گره دستگاه /dev/binder منحصر به فرآیندهای چارچوب و بنابراین برای فرآیندهای فروشنده غیرقابل دسترسی است. در عوض ، فرآیندهای فروشنده باید از /dev/hwbinder استفاده کنند و باید هرگونه رابط AIDL را به HIDL تبدیل کنند. برای کسانی که می خواهند به استفاده از رابط های AIDL بین فرآیندهای فروشنده ادامه دهند ، از دامنه Binder ، /dev/vndbinder استفاده کنید.

دامنه IPC توضیحات
/dev/binder IPC بین فرآیندهای چارچوب/برنامه با رابط های AIDL
/dev/hwbinder IPC بین فرآیندهای چارچوب/فروشنده با رابط های HIDL
IPC بین فرآیندهای فروشنده با رابط های HIDL
/dev/vndbinder IPC بین فرآیندهای فروشنده/فروشنده با رابط های AIDL

در حالی که SurfaceFlinger رابط های AIDL را تعریف می کند ، فرآیندهای فروشنده فقط می توانند از رابط های HIDL برای برقراری ارتباط با فرآیندهای چارچوب استفاده کنند. برای تبدیل رابط های AIDL موجود به 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 اختصاص داده شده و به مجوزهای R/W به دامنه 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;
،

Android حاوی یک لایه انتزاع سخت افزاری HIDL خودرو (HAL) است که ضبط تصاویر را در مراحل اولیه بوت اندروید فراهم می کند و عملکرد خود را برای زندگی سیستم ادامه می دهد. HAL شامل پشته سیستم نمای بیرونی (EVS) است و به طور معمول برای پشتیبانی از دوربین نمای عقب و نمایشگرهای نمای اطراف در وسایل نقلیه دارای سیستم های سرگرمی درون وسیله نقلیه مبتنی بر اندروید (IVI) استفاده می شود. EVS همچنین ویژگی های پیشرفته را در برنامه های کاربر اجرا می کند.

Android همچنین شامل یک رابط درایور ضبط و نمایشگر خاص EVS (in /hardware/interfaces/automotive/evs/1.0 automotive/evs/1.0) است. در حالی که امکان ساخت یک برنامه دوربین عقب در بالای دوربین و نمایشگاه های موجود در Android وجود دارد ، چنین برنامه ای احتمالاً در فرآیند بوت Android خیلی دیر اجرا می شود. استفاده از یک HAL اختصاصی یک رابط کاربری ساده را امکان پذیر می کند و روشن می کند که OEM برای پشتیبانی از پشته EVS چه چیزی برای پیاده سازی نیاز دارد.

اجزای سیستم

EVS شامل اجزای سیستم زیر است:

سیستم EVS نمودار

شکل 1. نمای کلی اجزای سیستم EVS.

برنامه EVS

یک برنامه C ++ EVS ( /packages/services/Car/evs/app ) به عنوان یک اجرای مرجع عمل می کند. این برنامه مسئول درخواست فریم های ویدیویی از مدیر EVS و ارسال فریم های تمام شده برای نمایش به مدیر EVS است. انتظار می رود به محض اینکه EVS و سرویس CAR در دسترس هستند ، توسط INIT آغاز شود ، که در طی دو (2) ثانیه از قدرت قرار گرفته است. OEM ها می توانند برنامه EVS را به دلخواه تغییر یا جایگزین کنند.

مدیر EVS

مدیر EVS ( /packages/services/Car/evs/manager ) بلوک های ساختمانی مورد نیاز یک برنامه EVS را برای پیاده سازی هر چیزی از یک نمایشگر دوربین عقب ساده گرفته تا یک نمایش چند دوربین 6DOF فراهم می کند. رابط کاربری آن از طریق HIDL ارائه شده و برای پذیرش چندین مشتری همزمان ساخته شده است. برنامه ها و خدمات دیگر (به طور خاص سرویس خودرو) می توانند از وضعیت مدیر EVS پرس و جو کنند تا دریابند که سیستم EVS فعال است.

رابط HIDL EVS

سیستم EVS ، هم دوربین و هم عناصر نمایشگر ، در بسته android.hardware.automotive.evs تعریف شده است. اجرای نمونه ای که رابط کاربری را انجام می دهد (تصاویر تست مصنوعی را تولید می کند و تصاویر را تأیید می کند که سفر دور را انجام می دهد) در /hardware/interfaces/automotive/evs/1.0/default ارائه شده است.

OEM وظیفه اجرای API بیان شده توسط پرونده های .hal در /hardware/interfaces/automotive/evs دارد. چنین پیاده سازی هایی وظیفه پیکربندی و جمع آوری داده ها از دوربین های فیزیکی و ارائه آن از طریق بافرهای حافظه مشترک قابل تشخیص توسط Gralloc را بر عهده دارند. قسمت نمایش اجرای وظیفه ارائه یک بافر حافظه مشترک است که می تواند توسط برنامه (معمولاً از طریق ارائه EGL) پر شود و قاب های تمام شده را در اولویت به هر چیز دیگری که ممکن است بخواهد در صفحه نمایش فیزیکی ظاهر شود ، ارائه می دهد. اجرای فروشنده رابط EVS ممکن است تحت /vendor/… /device/… یا hardware/… (به عنوان مثال ، /hardware/[vendor]/[platform]/evs ) ذخیره شود.

رانندگان هسته

دستگاهی که از پشته EVS پشتیبانی می کند به درایورهای هسته نیاز دارد. به جای ایجاد درایورهای جدید ، OEM ها از طریق دوربین موجود و/یا نمایش درایورهای سخت افزاری ، گزینه ای برای پشتیبانی از ویژگی های مورد نیاز EVS دارند. استفاده مجدد از رانندگان می تواند سودمند باشد ، به خصوص برای درایورهای نمایشگر که در آن ارائه تصویر ممکن است به هماهنگی با سایر موضوعات فعال نیاز داشته باشد. Android 8.0 شامل یک درایور نمونه مبتنی بر V4L2 (در packages/services/Car/evs/sampleDriver ) است که به هسته برای پشتیبانی V4L2 و در سطح Surfaceflinger برای ارائه تصویر خروجی بستگی دارد.

توضیحات رابط سخت افزار EVS

این بخش HAL را توصیف می کند. انتظار می رود فروشندگان پیاده سازی این API را برای سخت افزار خود ارائه دهند.

Ievsenumerator

این شیء مسئول شمارش سخت افزار EVS موجود در سیستم (یک یا چند دوربین و دستگاه صفحه نمایش تک) است.

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

یک بردار حاوی توضیحات برای کلیه دوربین های موجود در سیستم را برمی گرداند. فرض بر این است که مجموعه دوربین ها در زمان بوت ثابت و شناخته شده است. برای جزئیات بیشتر در مورد توضیحات دوربین ، به CameraDesc مراجعه کنید.

openCamera(string camera_id) generates (IEvsCamera camera);

یک شیء رابط مورد استفاده برای تعامل با یک دوربین خاص مشخص شده توسط رشته منحصر به فرد Camera_ID را بدست می آورد. یک تهی را در مورد شکست برمی گرداند. تلاش برای بازگشایی دوربین که از قبل باز است ، نمی تواند شکست بخورد. برای جلوگیری از شرایط مسابقه مرتبط با راه اندازی و خاموش کردن برنامه ، بازگشایی یک دوربین باید نمونه قبلی را خاموش کند تا درخواست جدید انجام شود. یک نمونه دوربین که از این طریق پیش بینی شده است باید در حالت غیرفعال قرار گیرد ، در انتظار تخریب نهایی و پاسخ به هرگونه درخواست برای تأثیرگذاری بر وضعیت دوربین با کد بازگشت OWNERSHIP_LOST .

closeCamera(IEvsCamera camera);

رابط ievscamera را منتشر می کند (و برعکس تماس openCamera() ) است. قبل از تماس با closeCamera جریان ویدیوی دوربین باید با فراخوانی stopVideoStream() متوقف شود.

openDisplay() generates (IEvsDisplay display);

یک شیء رابط مورد استفاده برای تعامل منحصر به فرد با صفحه نمایش EVS سیستم را بدست می آورد. فقط یک مشتری ممکن است یک نمونه کاربردی از IEVSDisPlay را در زمان برگزار کند. مشابه رفتار باز تهاجمی که در openCamera شرح داده شده است ، ممکن است یک شیء جدید ievsdisplay در هر زمان ایجاد شود و هر نمونه قبلی را غیرفعال کند. نمونه های بی اعتبار همچنان وجود دارند و به تماس های عملکردی صاحبان خود پاسخ می دهند ، اما در هنگام کشته شدن نباید عملیات جهش یافته ای انجام دهند. سرانجام ، انتظار می رود برنامه مشتری به کدهای بازگشت خطای OWNERSHIP_LOST توجه کند و رابط غیرفعال را ببند و آزاد کند.

closeDisplay(IEvsDisplay display);

رابط iEvsDisplay را منتشر می کند (و برعکس تماس openDisplay() ) است. بافرهای برجسته دریافت شده از طریق getTargetBuffer() تماس باید قبل از بستن صفحه نمایش به صفحه نمایش برگردانده شود.

getDisplayState() generates (DisplayState state);

وضعیت نمایش فعلی را بدست می آورد. اجرای HAL باید وضعیت فعلی فعلی را گزارش کند ، که ممکن است با بیشترین وضعیت درخواست شده متفاوت باشد. منطق مسئول تغییر حالتهای نمایش باید در بالای لایه دستگاه وجود داشته باشد ، و این امر را برای اجرای HAL برای تغییر خود به خود حالت های نمایش نامطلوب می کند. اگر صفحه نمایش در حال حاضر توسط هیچ مشتری (با تماس با OpenDisplay) برگزار نشود ، این عملکرد NOT_OPEN را برمی گرداند. در غیر این صورت ، وضعیت فعلی نمایشگر EVS را گزارش می کند (به API Ievsdisplay مراجعه کنید).

struct CameraDesc {
    string      camera_id;
    int32       vendor_flags;       // Opaque value
}
  • camera_id . رشته ای که منحصر به فرد یک دوربین خاص را مشخص می کند. می تواند نام دستگاه هسته دستگاه یا نامی برای دستگاه باشد ، مانند Rearview . مقدار این رشته توسط اجرای HAL انتخاب شده و از طریق پشته بالا استفاده می شود.
  • vendor_flags . روشی برای انتقال اطلاعات ویژه دوربین از درایور به یک برنامه EVS سفارشی. از درایور تا برنامه EVS بدون تفسیر منتقل می شود ، که می توان آن را نادیده گرفت.

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);

درخواست تحویل فریم های دوربین EVS از این دوربین را می دهد. IEVSCAMERASTREAM شروع به دریافت تماس های دوره ای با قاب های تصویر جدید تا زمان فراخوانی stopVideoStream() می کند. فریم ها باید در 500ms از تماس startVideoStream تحویل داده شوند و پس از شروع ، باید حداقل 10 فریم در ثانیه تولید شوند. زمان لازم برای شروع جریان ویدیو به طور مؤثر در برابر هرگونه نیاز به زمان راه اندازی دوربین عقب حساب می شود. اگر جریان شروع نشود ، باید یک کد خطا بازگردانده شود. در غیر این صورت خوب بازگردانده می شود.

oneway doneWithFrame(BufferDesc buffer);

قاب را که به IEVScameraStream تحویل داده شده است ، برمی گرداند. پس از اتمام مصرف یک قاب که به رابط ievscamerastream تحویل داده می شود ، قاب باید برای استفاده مجدد به ievscamera برگردانده شود. تعداد کمی از بافرها در دسترس هستند (احتمالاً به اندازه یک کوچک) ، و اگر عرضه خسته شود ، هیچ فریم دیگری تحویل داده نمی شود تا یک بافر بازگردانده شود ، به طور بالقوه منجر به فریم های پرش شده می شود (یک بافر با یک دسته تهی نشانگر انتهای یک جریان است و نیازی به بازگشت از طریق این عملکرد نیست). در موفقیت ، یا کد خطای مناسب به طور بالقوه شامل INVALID_ARG یا BUFFER_NOT_AVAILABLE باز می گردد.

stopVideoStream();

تحویل فریم های دوربین EVS را متوقف می کند. از آنجا که تحویل ناهمزمان است ، فریم ها ممکن است پس از بازگشت این تماس ، مدتی به آنجا برسند. هر قاب باید برگردانده شود تا بسته شدن جریان به IEVSCAMERASTREAM علامت گذاری شود. قانونی است که از stopVideoStream در جریانی تماس بگیرید که قبلاً متوقف شده یا هرگز شروع نشده است ، که در آن موارد نادیده گرفته می شود.

getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);

اطلاعات خاص راننده را از اجرای HAL درخواست می کند. مقادیر مجاز برای opaqueIdentifier خاص درایور هستند ، اما هیچ مقداری عبور نمی کند ممکن است درایور را خراب کند. درایور باید 0 را برای هر opaqueIdentifier ناشناخته بازگرداند.

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

مقدار خاص درایور را به اجرای HAL ارسال می کند. این پسوند فقط برای تسهیل پسوندهای خاص وسیله نقلیه ارائه شده است و هیچ اجرای HAL نباید این تماس را در حالت پیش فرض انجام دهد. اگر راننده مقادیر را تشخیص دهد و بپذیرد ، باید برگشت داده شود. در غیر این صورت باید کد خطای 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
}

تصویری را که از طریق API منتقل شده است ، توصیف می کند. درایو HAL وظیفه پر کردن این ساختار را برای توصیف بافر تصویر دارد و مشتری HAL باید این ساختار را فقط به عنوان خواندنی رفتار کند. این زمینه ها حاوی اطلاعات کافی هستند تا مشتری بتواند یک شیء ANativeWindowBuffer را بازسازی کند ، همانطور که ممکن است برای استفاده از تصویر با EGL از طریق eglCreateImageKHR() استفاده شود.

  • 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 برای اینکه یک بافر پس از یک سفر دور از طریق API های HAL شناخته شود. مقدار ذخیره شده در این زمینه ممکن است به طور خودسرانه توسط اجرای HAL انتخاب شود.
  • memHandle دسته برای بافر حافظه زیرین که حاوی داده های تصویر است. اجرای HAL ممکن است برای ذخیره یک دسته بافر Gralloc در اینجا انتخاب کند.

ievscamerastream

مشتری این رابط را برای دریافت تحویل قاب ویدیویی ناهمزمان پیاده سازی می کند.

deliverFrame(BufferDesc buffer);

هر بار که یک قاب ویدیویی برای بازرسی آماده است ، از HAL تماس می گیرد. دستگیره های بافر دریافت شده توسط این روش باید از طریق تماس به IEvsCamera::doneWithFrame() بازگردانده شود. هنگامی که جریان ویدیو از طریق تماس با IEvsCamera::stopVideoStream() متوقف می شود ، ممکن است با تخلیه خط لوله ، این پاسخ به تماس ادامه یابد. هر فریم هنوز باید برگردانده شود. هنگامی که آخرین قاب موجود در جریان تحویل داده شود ، یک بافر تهی تحویل داده می شود ، که نشانگر پایان جریان است و هیچ گونه تحویل فریم دیگری رخ نمی دهد. خود Bufferhandle خود نیازی به ارسال مجدد از طریق doneWithFrame() ندارد ، اما باید همه دستگیره های دیگر برگردانده شود

در حالی که قالبهای بافر اختصاصی از نظر فنی امکان پذیر است ، آزمایش سازگاری نیاز به بافر در یکی از چهار فرمت پشتیبانی شده دارد: NV21 (YCRCB 4: 2: 0 نیمه پلانار) ، yv12 (ycrcb 4: 2: 0 مسطح) ، yuyv (ycrcb 4: 2: 2: 2: 2: 2 interled) ، bgr: x rgba (32 bit rgba (32 rgba) (32 بیتی B: G: R: X). قالب انتخاب شده باید یک منبع معتبر GL Texture در اجرای GLES پلتفرم باشد.

برنامه نباید به هر مکاتبات بین میدان bufferId و memHandle در ساختار BufferDesc متکی باشد. مقادیر bufferId در اصل برای اجرای درایور HAL خصوصی است و ممکن است از آنها استفاده کند (و از آنها استفاده مجدد) همانطور که مناسب می بیند.

ievsdisplay

This object represents the Evs display, controls the state of the display, and handles the actual presentation of images.

getDisplayInfo() generates (DisplayDesc info);

Returns basic information about the EVS display provided by the system (see DisplayDesc ).

setDisplayState(DisplayState state) generates (EvsResult result);

Sets the display state. Clients may set the display state to express the desired state, and the HAL implementation must gracefully accept a request for any state while in any other state, although the response may be to ignore the request.

Upon initialization, the display is defined to start in the NOT_VISIBLE state, after which the client is expected to request the VISIBLE_ON_NEXT_FRAME state and begin providing video. When the display is no longer required, the client is expected to request the NOT_VISIBLE state after passing the last video frame.

It is valid for any state to be requested at any time. If the display is already visible, it should remain visible if set to VISIBLE_ON_NEXT_FRAME . Always returns OK unless the requested state is an unrecognized enum value, in which case INVALID_ARG is returned.

getDisplayState() generates (DisplayState state);

Gets the display state. The HAL implementation should report the actual current state, which might differ from the most recently requested state. The logic responsible for changing display states should exist above the device layer, making it undesirable for the HAL implementation to spontaneously change display states.

getTargetBuffer() generates (handle bufferHandle);

Returns a handle to a frame buffer associated with the display. This buffer may be locked and written to by software and/or GL. This buffer must be returned via a call to returnTargetBufferForDisplay() even if the display is no longer visible.

While proprietary buffer formats are technically possible, compatibility testing requires the buffer be in one of four supported formats: NV21 (YCrCb 4:2:0 Semi-Planar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4:2:2 Interleaved), RGBA (32 bit R:G:B:x), BGRA (32 bit B:G:R:x). The selected format must be a valid GL render target on the platform's GLES implementation.

On error, a buffer with a null handle is returned, but such a buffer doesn't need to be passed back to returnTargetBufferForDisplay .

returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);

Tells the display the buffer is ready for display. Only buffers retrieved through a call to getTargetBuffer() are valid for use with this call, and the contents of the BufferDesc may not be modified by the client app. After this call, the buffer is no longer valid for use by the client. Returns OK on success, or appropriate error code potentially including INVALID_ARG or BUFFER_NOT_AVAILABLE .

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

Describes the basic properties of an EVS display and required by an EVS implementation. The HAL is responsible for filling out this structure to describe the EVS display. Can be a physical display or a virtual display that is overlaid or mixed with another presentation device.

  • display_id . A string that uniquely identifies the display. This could be the kernel device name of the device, or a name for the device, such as rearview . The value for this string is chosen by the HAL implementation and used opaquely by the stack above.
  • vendor_flags . A method for passing specialized camera information opaquely from the driver to a custom EVS app. It is passed uninterpreted from the driver up to the EVS app, which is free to ignore it.
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
}

Describes the state of the EVS display, which can be disabled (not visible to the driver) or enabled (showing an image to the driver). Includes a transient state where the display isn't visible yet but is prepared to become visible with the delivery of the next frame of imagery via the returnTargetBufferForDisplay() call.

EVS Manager

The EVS Manager provides the public interface to the EVS system for collecting and presenting external camera views. Where hardware drivers allow only one active interface per resource (camera or display), the EVS Manager facilitates shared access to the cameras. A single primary EVS app is the first client of the EVS Manager, and is the only client permitted to write display data (additional clients can be granted read-only access to camera images).

The EVS Manager implements the same API as the underlying HAL drivers and provides expanded service by supporting multiple concurrent clients (more than one client can open a camera through the EVS Manager and receive a video stream).

EVS Manager and
EVS Hardware API diagram.

Figure 2. EVS Manager mirrors underlying EVS Hardware API.

Apps see no differences when operating through the EVS Hardware HAL implementation or the EVS Manager API except that the EVS Manager API allows concurrent camera stream access. The EVS Manager is, itself, the one allowed client of the EVS Hardware HAL layer, and acts as a proxy for the EVS Hardware HAL.

The following sections describe only those calls that have a different (extended) behavior in the EVS Manager implementation; remaining calls are identical to EVS HAL descriptions.

IEvsEnumerator

openCamera(string camera_id) generates (IEvsCamera camera);

Obtains an interface object used to interact with a specific camera identified by the unique camera_id string. Returns a NULL on failure. At the EVS Manager layer, as long as sufficient system resources are available, a camera that is already open may be opened again by another process, allowing teeing of the video stream to multiple consumer apps. The camera_id strings at the EVS Manager layer are the same as those reported to the EVS Hardware layer.

IEvsCamera

The EVS Manager provided IEvsCamera implementation is internally virtualized so operations on a camera by one client don't affect other clients, which retain independent access to their cameras.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

Starts video streams. Clients may independently start and stop video streams on the same underlying camera. The underlying camera starts when the first client starts.

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

Returns a frame. Each client must return their frames when they are done, but are permitted to hold onto their frames for as long as they desire. When the frame count held by a client reaches its configured limit, it won't receive any more frames until it returns one. This frame skipping doesn't affect other clients, which continue to receive all frames as expected.

stopVideoStream();

Stops a video stream. Each client can stop its video stream any time without affecting other clients. The underlying camera stream at the hardware layer is stopped when the last client of a given camera stops its stream.

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

Sends a driver-specific value, potentially enabling one client to affect another client. Because the EVS Manager cannot understand the implications of vendor-defined control words, they aren't virtualized and any side effects apply to all clients of a given camera. For example, if a vendor used this call to change frame rates, all clients of the affected hardware layer camera would receive frames at the new rate.

IEvsDisplay

Only one owner of the display is allowed, even at the EVS Manager level. The Manager adds no functionality and simply passes the IEvsDisplay interface directly through to the underlying HAL implementation.

EVS app

Android includes a native C++ reference implementation of an EVS app that communicates with the EVS Manager and the Vehicle HAL to provide basic rearview camera functions. The app is expected to start very early in the system boot process, with suitable video shown depending on the available cameras and the state of the car (gear and turn signal state). OEMs can modify or replace the EVS app with their own vehicle-specific logic and presentation.

Figure 3. EVS app sample logic, get camera list.



Figure 4. EVS app sample logic, receive frame callback.

Because image data is presented to the app in a standard graphics buffer, the app is responsible for moving the image from the source buffer into the output buffer. While this introduces the cost of a data copy, it also offers the opportunity for the app to render the image into the display buffer in any fashion it desires.

For example, the app may choose to move the pixel data itself, potentially with an inline scale or rotation operation. The app could also choose to use the source image as an OpenGL texture and render a complex scene to the output buffer, including virtual elements such as icons, guidelines, and animations. A more sophisticated app may also select multiple concurrent input cameras and merge them into the single output frame (such as for use in a top-down, virtual view of vehicle surroundings).

Use the EGL/SurfaceFlinger in the EVS Display HAL

This section explains how to use EGL to render an EVS Display HAL implementation in Android 10.

An EVS HAL reference implementation uses EGL to render the camera preview on the screen and uses libgui to create the target EGL render surface. In Android 8 (and higher), libgui is classified as VNDK-private , which refers to a group of libraries available to VNDK libraries that vendor processes cannot use. Because HAL implementations must reside in the vendor partition, vendors are prevented from using Surface in HAL implementations.

Building libgui for vendor processes

The use of libgui serves as the only option to use EGL/SurfaceFlinger in EVS Display HAL implementations. The most straightforward way to implement libgui is through frameworks/native/libs/gui directly by using an additional build target in the build script. This target is exactly the same as the libgui target except for the addition of two fields:

  • 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", ],

Note: Vendor targets are built with the NO_INPUT macro, which removes one 32-bit word from the parcel data. Because SurfaceFlinger expects this field that has been removed, SurfaceFlinger fails to parse the parcel. This is observed as a fcntl failure:

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

To resolve this condition:

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);

Sample build instructions are provided below. Expect to receive a $(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

Use binder in an EVS HAL implementation

In Android 8 (and higher), the /dev/binder device node became exclusive to framework processes and, therefore, inaccessible to vendor processes. Instead, vendor processes should use /dev/hwbinder and must convert any AIDL interfaces to HIDL. For those who want to continue using AIDL interfaces between vendor processes, use the binder domain, /dev/vndbinder .

IPC Domain توضیحات
/dev/binder IPC between framework/app processes with AIDL interfaces
/dev/hwbinder IPC between framework/vendor processes with HIDL interfaces
IPC between vendor processes with HIDL interfaces
/dev/vndbinder IPC between vendor/vendor processes with AIDL Interfaces

While SurfaceFlinger defines AIDL interfaces, vendor processes can only use HIDL interfaces to communicate with framework processes. A non-trivial amount of work is required to convert existing AIDL interfaces into HIDL. Fortunately, Android provides a method with which to select the binder driver for libbinder , to which the userspace library processes are linked.

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));

Note: Vendor processes should call this before calling into Process or IPCThreadState , or before making any binder calls.

SELinux policies

If the device implementation is full treble, SELinux prevents vendor processes from using /dev/binder . For example, an EVS HAL sample implementation is assigned to the hal_evs_driver domain and requires r/w permissions to the binder_device domain.

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

Adding these permissions, however, causes a build failure because it violates the following neverallow rules defined in system/sepolicy/domain.te for a full-treble device.

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 is an attribute provided to catch a bug and guide development. It can also be used to resolve the Android 10 violation described above.

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)

Build an EVS HAL reference implementation as a vendor process

As a reference, you can apply the following changes to packages/services/Car/evs/Android.mk . Be sure to confirm that all described changes work for your implementation.

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;
،

Android contains an automotive HIDL Hardware Abstraction Layer (HAL) that provides for imagery capture and display very early in the Android boot process and continues functioning for the life of the system. The HAL includes the exterior view system (EVS) stack and is typically used to support rearview camera and surround view displays in vehicles with Android-based In-Vehicle Infotainment (IVI) systems. EVS also enables advanced features to be implemented in user apps.

Android also includes an EVS-specific capture and display driver interface (in /hardware/interfaces/automotive/evs/1.0 ). While it is possible to build a rearview camera app on top of existing Android camera and display services, such an app would likely run too late in the Android boot process. Using a dedicated HAL enables a streamlined interface and makes it clear what an OEM needs to implement to support the EVS stack.

اجزای سیستم

EVS includes the following system components:

EVS System
components diagram

Figure 1. EVS system components overview.

EVS app

A sample C++ EVS app ( /packages/services/Car/evs/app ) serves as a reference implementation. This app is responsible for requesting video frames from the EVS Manager and sending finished frames for display back to the EVS Manager. It expects to be started by init as soon as EVS and Car Service are available, targeted within two (2) seconds of power on. OEMs can modify or replace the EVS app as desired.

EVS Manager

The EVS Manager ( /packages/services/Car/evs/manager ) provides the building blocks needed by an EVS app to implement anything from a simple rearview camera display to a 6DOF multi-camera rendering. Its interface is presented through HIDL and is built to accept multiple concurrent clients. Other apps and services (specifically the Car Service) can query the EVS Manager state to find out when the EVS system is active.

EVS HIDL interface

The EVS system, both the camera and the display elements, is defined in the android.hardware.automotive.evs package. A sample implementation that exercises the interface (generates synthetic test images and validates the images make the round trip) is provided in /hardware/interfaces/automotive/evs/1.0/default .

The OEM is responsible for implementing the API expressed by the .hal files in /hardware/interfaces/automotive/evs . Such implementations are responsible for configuring and gathering data from physical cameras and delivering it via shared memory buffers recognizable by Gralloc. The display side of the implementation is responsible for providing a shared memory buffer that can be filled by the app (usually via EGL rendering) and presenting the finished frames in preference to anything else that might want to appear on the physical display. Vendor implementations of the EVS interface may be stored under /vendor/… /device/… or hardware/… (eg, /hardware/[vendor]/[platform]/evs ).

Kernel drivers

A device that supports the EVS stack requires kernel drivers. Instead of creating new drivers, OEMs have the option to support EVS-required features via existing camera and/or display hardware drivers. Reusing drivers could be advantageous, especially for display drivers where image presentation may require coordination with other active threads. Android 8.0 includes a v4l2-based sample driver (in packages/services/Car/evs/sampleDriver ) that depends on the kernel for v4l2 support and on SurfaceFlinger for presenting the output image.

EVS hardware interface description

The section describes the HAL. Vendors are expected to provide implementations of this API adapted for their hardware.

IEvsEnumerator

This object is responsible for enumerating the available EVS hardware in the system (one or more cameras and the single display device).

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

Returns a vector containing descriptions for all cameras in the system. It is assumed the set of cameras is fixed and knowable at boot time. For details on camera descriptions, see CameraDesc .

openCamera(string camera_id) generates (IEvsCamera camera);

Obtains an interface object used to interact with a specific camera identified by the unique camera_id string. Returns a NULL on failure. Attempts to reopen a camera that is already open cannot fail. To avoid race conditions associated with app startup and shutdown, reopening a camera should shut down the previous instance so the new request can be fulfilled. A camera instance that has been preempted in this way must be put in an inactive state, awaiting final destruction and responding to any request to affect the camera state with a return code of OWNERSHIP_LOST .

closeCamera(IEvsCamera camera);

Releases the IEvsCamera interface (and is the opposite of the openCamera() call). The camera video stream must be stopped by calling stopVideoStream() before calling closeCamera .

openDisplay() generates (IEvsDisplay display);

Obtains an interface object used to exclusively interact with the system's EVS display. Only one client may hold a functional instance of IEvsDisplay at time. Similar to the aggressive open behavior described in openCamera , a new IEvsDisplay object may be created at any time and will disable any previous instances. Invalidated instances continue to exist and respond to function calls from their owners, but must perform no mutating operations when dead. Eventually, the client app is expected to notice the OWNERSHIP_LOST error return codes and close and release the inactive interface.

closeDisplay(IEvsDisplay display);

Releases the IEvsDisplay interface (and is the opposite of the openDisplay() call). Outstanding buffers received via getTargetBuffer() calls must be returned to the display before closing the display.

getDisplayState() generates (DisplayState state);

Gets the current display state. The HAL implementation should report the actual current state, which might differ from the most recently requested state. The logic responsible for changing display states should exist above the device layer, making it undesirable for the HAL implementation to spontaneously change display states. If the display isn't currently held by any client (by a call to openDisplay), then this function returns NOT_OPEN . Otherwise, it reports the current state of the EVS Display (see IEvsDisplay API ).

struct CameraDesc {
    string      camera_id;
    int32       vendor_flags;       // Opaque value
}
  • camera_id . A string that uniquely identifies a given camera. Can be the kernel device name of the device or a name for the device, such as rearview . The value for this string is chosen by the HAL implementation and used opaquely by the stack above.
  • vendor_flags . A method for passing specialized camera information opaquely from the driver to a custom EVS app. It is passed uninterpreted from the driver up to the EVS app, which is free to ignore it.

IEvsCamera

This object represents a single camera and is the primary interface for capturing images.

getCameraInfo() generates (CameraDesc info);

Returns CameraDesc of this camera.

setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);

Specifies the depth of the buffer chain the camera is asked to support. Up to this many frames may be held concurrently by the client of IEvsCamera. If this many frames have been delivered to the receiver without being returned by doneWithFrame , the stream skips frames until a buffer is returned for reuse. It is legal for this call to come at any time, even while streams are already running, in which case buffers should be added or removed from the chain as appropriate. If no call is made to this entry point, the IEvsCamera supports at least one frame by default; with more acceptable.

If the requested bufferCount cannot be accommodated, the function returns BUFFER_NOT_AVAILABLE or other relevant error code. In this case, the system continues to operate with the previously-set value.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

Requests delivery of EVS camera frames from this camera. The IEvsCameraStream begins receiving periodic calls with new image frames until stopVideoStream() is called. Frames must begin being delivered within 500ms of the startVideoStream call and after starting, must generated at a minimum of 10 FPS. The time required to start the video stream effectively counts against any rearview camera startup time requirement. If the stream isn't started, an error code must be returned; otherwise OK is returned.

oneway doneWithFrame(BufferDesc buffer);

Returns a frame that was delivered by to the IEvsCameraStream. When done consuming a frame delivered to the IEvsCameraStream interface, the frame must be returned to the IEvsCamera for reuse. A small, finite number of buffers are available (possibly as small as one), and if the supply is exhausted, no further frames are delivered until a buffer is returned, potentially resulting in skipped frames (a buffer with a null handle denotes the end of a stream and does not need to be returned through this function). Returns OK on success, or appropriate error code potentially including INVALID_ARG or BUFFER_NOT_AVAILABLE .

stopVideoStream();

Stops the delivery of EVS camera frames. Because delivery is asynchronous, frames may continue to arrive for some time after this call returns. Each frame must be returned until the closure of the stream is signaled to the IEvsCameraStream. It is legal to call stopVideoStream on a stream that has already been stopped or never started, in which cases it is ignored.

getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);

Requests driver-specific information from the HAL implementation. Values allowed for opaqueIdentifier are driver-specific, but no value passed may crash the driver. The driver should return 0 for any unrecognized opaqueIdentifier .

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

Sends a driver-specific value to the HAL implementation. This extension is provided only to facilitate vehicle-specific extensions and no HAL implementation should require this call to function in a default state. If the driver recognizes and accepts the values, OK should be returned; otherwise INVALID_ARG or other representative error code should be returned.

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
}

Describes an image passed through the API. The HAL drive is responsible for filling out this structure to describe the image buffer and the HAL client should treat this structure as read-only. The fields contain enough information to allow the client to reconstruct an ANativeWindowBuffer object, as may be required to use the image with EGL via the eglCreateImageKHR() extension.

  • width . The width in pixels of the presented image.
  • height . The height in pixels of the presented image.
  • stride . Number of pixels each row actually occupies in memory, accounting for any padding for alignment of rows. Expressed in pixels to match the convention adopted by gralloc for its buffer descriptions.
  • pixelSize . Number of bytes occupied by each individual pixel, enabling computation of the size in bytes necessary to step between rows in the image ( stride in bytes = stride in pixels * pixelSize ).
  • format . The pixel format used by the image. The format provided must be compatible with the platform's OpenGL implementation. To pass compatibility testing, HAL_PIXEL_FORMAT_YCRCB_420_SP should be preferred for camera usage, and RGBA or BGRA should be preferred for display.
  • usage . Usage flags set by the HAL implementation. HAL clients are expected to pass these unmodified (for details, refer to Gralloc.h related flags).
  • bufferId . A unique value specified by the HAL implementation to allow a buffer to be recognized after a round trip through the HAL APIs. The value stored in this field may be arbitrarily chosen by the HAL implementation.
  • memHandle . The handle for the underlying memory buffer that contains the image data. The HAL implementation might choose to store a Gralloc buffer handle here.

IEvsCameraStream

The client implements this interface to receive asynchronous video frame deliveries.

deliverFrame(BufferDesc buffer);

Receives calls from the HAL each time a video frame is ready for inspection. Buffer handles received by this method must be returned via calls to IEvsCamera::doneWithFrame() . When the video stream is stopped via a call to IEvsCamera::stopVideoStream() , this callback might continue as the pipeline drains. Each frame must still be returned; when the last frame in the stream has been delivered, a NULL bufferHandle will be delivered, signifying the end of the stream and no further frame deliveries occur. The NULL bufferHandle itself doesn't need to be sent back via doneWithFrame() , but all other handles must be returned

While proprietary buffer formats are technically possible, compatibility testing requires the buffer be in one of four supported formats: NV21 (YCrCb 4:2:0 Semi-Planar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4:2:2 Interleaved), RGBA (32 bit R:G:B:x), BGRA (32 bit B:G:R:x). The selected format must be a valid GL texture source on the platform's GLES implementation.

The app should not rely on any correspondence between the bufferId field and the memHandle in the BufferDesc structure. The bufferId values are essentially private to the HAL driver implementation, and it may use (and reuse) them as it sees fit.

IEvsDisplay

This object represents the Evs display, controls the state of the display, and handles the actual presentation of images.

getDisplayInfo() generates (DisplayDesc info);

Returns basic information about the EVS display provided by the system (see DisplayDesc ).

setDisplayState(DisplayState state) generates (EvsResult result);

Sets the display state. Clients may set the display state to express the desired state, and the HAL implementation must gracefully accept a request for any state while in any other state, although the response may be to ignore the request.

Upon initialization, the display is defined to start in the NOT_VISIBLE state, after which the client is expected to request the VISIBLE_ON_NEXT_FRAME state and begin providing video. When the display is no longer required, the client is expected to request the NOT_VISIBLE state after passing the last video frame.

It is valid for any state to be requested at any time. If the display is already visible, it should remain visible if set to VISIBLE_ON_NEXT_FRAME . Always returns OK unless the requested state is an unrecognized enum value, in which case INVALID_ARG is returned.

getDisplayState() generates (DisplayState state);

Gets the display state. The HAL implementation should report the actual current state, which might differ from the most recently requested state. The logic responsible for changing display states should exist above the device layer, making it undesirable for the HAL implementation to spontaneously change display states.

getTargetBuffer() generates (handle bufferHandle);

Returns a handle to a frame buffer associated with the display. This buffer may be locked and written to by software and/or GL. This buffer must be returned via a call to returnTargetBufferForDisplay() even if the display is no longer visible.

While proprietary buffer formats are technically possible, compatibility testing requires the buffer be in one of four supported formats: NV21 (YCrCb 4:2:0 Semi-Planar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4:2:2 Interleaved), RGBA (32 bit R:G:B:x), BGRA (32 bit B:G:R:x). The selected format must be a valid GL render target on the platform's GLES implementation.

On error, a buffer with a null handle is returned, but such a buffer doesn't need to be passed back to returnTargetBufferForDisplay .

returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);

Tells the display the buffer is ready for display. Only buffers retrieved through a call to getTargetBuffer() are valid for use with this call, and the contents of the BufferDesc may not be modified by the client app. After this call, the buffer is no longer valid for use by the client. Returns OK on success, or appropriate error code potentially including INVALID_ARG or BUFFER_NOT_AVAILABLE .

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

Describes the basic properties of an EVS display and required by an EVS implementation. The HAL is responsible for filling out this structure to describe the EVS display. Can be a physical display or a virtual display that is overlaid or mixed with another presentation device.

  • display_id . A string that uniquely identifies the display. This could be the kernel device name of the device, or a name for the device, such as rearview . The value for this string is chosen by the HAL implementation and used opaquely by the stack above.
  • vendor_flags . A method for passing specialized camera information opaquely from the driver to a custom EVS app. It is passed uninterpreted from the driver up to the EVS app, which is free to ignore it.
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
}

Describes the state of the EVS display, which can be disabled (not visible to the driver) or enabled (showing an image to the driver). Includes a transient state where the display isn't visible yet but is prepared to become visible with the delivery of the next frame of imagery via the returnTargetBufferForDisplay() call.

EVS Manager

The EVS Manager provides the public interface to the EVS system for collecting and presenting external camera views. Where hardware drivers allow only one active interface per resource (camera or display), the EVS Manager facilitates shared access to the cameras. A single primary EVS app is the first client of the EVS Manager, and is the only client permitted to write display data (additional clients can be granted read-only access to camera images).

The EVS Manager implements the same API as the underlying HAL drivers and provides expanded service by supporting multiple concurrent clients (more than one client can open a camera through the EVS Manager and receive a video stream).

EVS Manager and
EVS Hardware API diagram.

Figure 2. EVS Manager mirrors underlying EVS Hardware API.

Apps see no differences when operating through the EVS Hardware HAL implementation or the EVS Manager API except that the EVS Manager API allows concurrent camera stream access. The EVS Manager is, itself, the one allowed client of the EVS Hardware HAL layer, and acts as a proxy for the EVS Hardware HAL.

The following sections describe only those calls that have a different (extended) behavior in the EVS Manager implementation; remaining calls are identical to EVS HAL descriptions.

IEvsEnumerator

openCamera(string camera_id) generates (IEvsCamera camera);

Obtains an interface object used to interact with a specific camera identified by the unique camera_id string. Returns a NULL on failure. At the EVS Manager layer, as long as sufficient system resources are available, a camera that is already open may be opened again by another process, allowing teeing of the video stream to multiple consumer apps. The camera_id strings at the EVS Manager layer are the same as those reported to the EVS Hardware layer.

IEvsCamera

The EVS Manager provided IEvsCamera implementation is internally virtualized so operations on a camera by one client don't affect other clients, which retain independent access to their cameras.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

Starts video streams. Clients may independently start and stop video streams on the same underlying camera. The underlying camera starts when the first client starts.

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

Returns a frame. Each client must return their frames when they are done, but are permitted to hold onto their frames for as long as they desire. When the frame count held by a client reaches its configured limit, it won't receive any more frames until it returns one. This frame skipping doesn't affect other clients, which continue to receive all frames as expected.

stopVideoStream();

Stops a video stream. Each client can stop its video stream any time without affecting other clients. The underlying camera stream at the hardware layer is stopped when the last client of a given camera stops its stream.

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

Sends a driver-specific value, potentially enabling one client to affect another client. Because the EVS Manager cannot understand the implications of vendor-defined control words, they aren't virtualized and any side effects apply to all clients of a given camera. For example, if a vendor used this call to change frame rates, all clients of the affected hardware layer camera would receive frames at the new rate.

IEvsDisplay

Only one owner of the display is allowed, even at the EVS Manager level. The Manager adds no functionality and simply passes the IEvsDisplay interface directly through to the underlying HAL implementation.

EVS app

Android includes a native C++ reference implementation of an EVS app that communicates with the EVS Manager and the Vehicle HAL to provide basic rearview camera functions. The app is expected to start very early in the system boot process, with suitable video shown depending on the available cameras and the state of the car (gear and turn signal state). OEMs can modify or replace the EVS app with their own vehicle-specific logic and presentation.

Figure 3. EVS app sample logic, get camera list.



Figure 4. EVS app sample logic, receive frame callback.

Because image data is presented to the app in a standard graphics buffer, the app is responsible for moving the image from the source buffer into the output buffer. While this introduces the cost of a data copy, it also offers the opportunity for the app to render the image into the display buffer in any fashion it desires.

For example, the app may choose to move the pixel data itself, potentially with an inline scale or rotation operation. The app could also choose to use the source image as an OpenGL texture and render a complex scene to the output buffer, including virtual elements such as icons, guidelines, and animations. A more sophisticated app may also select multiple concurrent input cameras and merge them into the single output frame (such as for use in a top-down, virtual view of vehicle surroundings).

Use the EGL/SurfaceFlinger in the EVS Display HAL

This section explains how to use EGL to render an EVS Display HAL implementation in Android 10.

An EVS HAL reference implementation uses EGL to render the camera preview on the screen and uses libgui to create the target EGL render surface. In Android 8 (and higher), libgui is classified as VNDK-private , which refers to a group of libraries available to VNDK libraries that vendor processes cannot use. Because HAL implementations must reside in the vendor partition, vendors are prevented from using Surface in HAL implementations.

Building libgui for vendor processes

The use of libgui serves as the only option to use EGL/SurfaceFlinger in EVS Display HAL implementations. The most straightforward way to implement libgui is through frameworks/native/libs/gui directly by using an additional build target in the build script. This target is exactly the same as the libgui target except for the addition of two fields:

  • 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", ],

Note: Vendor targets are built with the NO_INPUT macro, which removes one 32-bit word from the parcel data. Because SurfaceFlinger expects this field that has been removed, SurfaceFlinger fails to parse the parcel. This is observed as a fcntl failure:

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

To resolve this condition:

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);

Sample build instructions are provided below. Expect to receive a $(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

Use binder in an EVS HAL implementation

In Android 8 (and higher), the /dev/binder device node became exclusive to framework processes and, therefore, inaccessible to vendor processes. Instead, vendor processes should use /dev/hwbinder and must convert any AIDL interfaces to HIDL. For those who want to continue using AIDL interfaces between vendor processes, use the binder domain, /dev/vndbinder .

IPC Domain توضیحات
/dev/binder IPC between framework/app processes with AIDL interfaces
/dev/hwbinder IPC between framework/vendor processes with HIDL interfaces
IPC between vendor processes with HIDL interfaces
/dev/vndbinder IPC between vendor/vendor processes with AIDL Interfaces

While SurfaceFlinger defines AIDL interfaces, vendor processes can only use HIDL interfaces to communicate with framework processes. A non-trivial amount of work is required to convert existing AIDL interfaces into HIDL. Fortunately, Android provides a method with which to select the binder driver for libbinder , to which the userspace library processes are linked.

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));

Note: Vendor processes should call this before calling into Process or IPCThreadState , or before making any binder calls.

SELinux policies

If the device implementation is full treble, SELinux prevents vendor processes from using /dev/binder . For example, an EVS HAL sample implementation is assigned to the hal_evs_driver domain and requires r/w permissions to the binder_device domain.

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

Adding these permissions, however, causes a build failure because it violates the following neverallow rules defined in system/sepolicy/domain.te for a full-treble device.

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 is an attribute provided to catch a bug and guide development. It can also be used to resolve the Android 10 violation described above.

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)

Build an EVS HAL reference implementation as a vendor process

As a reference, you can apply the following changes to packages/services/Car/evs/Android.mk . Be sure to confirm that all described changes work for your implementation.

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;