HAL กล้องของยานพาหนะ

Android มีเลเยอร์การแยกแยะฮาร์ดแวร์ HIDL (HAL) ยานยนต์ที่ให้บริการจับภาพและแสดงภาพตั้งแต่เนิ่นๆ ในกระบวนการบูตของ Android และทำงานต่อไปตลอดอายุของระบบ HAL ประกอบด้วยกองซ้อนระบบภาพภายนอก (EVS) และมักใช้เพื่อรองรับกล้องมองหลังและจอแสดงภาพรอบทิศทางในยานพาหนะที่ระบบสาระบันเทิงในรถ (IVI) ทำงานบน Android นอกจากนี้ EVS ยังช่วยให้ติดตั้งใช้งานฟีเจอร์ขั้นสูงในแอปของผู้ใช้ได้ด้วย

นอกจากนี้ Android ยังมีอินเทอร์เฟซของโปรแกรมควบคุมการแสดงผลและอุปกรณ์จับภาพสำหรับ EVS โดยเฉพาะ (ใน /hardware/interfaces/automotive/evs/1.0) แม้ว่าจะสร้างแอปกล้องมองหลังบนบริการกล้องและจอแสดงผลที่มีอยู่ของ Android ได้ แต่แอปดังกล่าวมีแนวโน้มที่จะทำงานช้าเกินไปในกระบวนการบูตของ Android การใช้ HAL โดยเฉพาะช่วยให้อินเทอร์เฟซมีประสิทธิภาพมากขึ้นและทำให้ OEM ทราบสิ่งที่ต้องติดตั้งใช้งานเพื่อรองรับสแต็ก EVS

คอมโพเนนต์ของระบบ

EVS ประกอบด้วยคอมโพเนนต์ของระบบต่อไปนี้

แผนภาพส่วนประกอบของระบบ EVS

รูปที่ 1 ภาพรวมคอมโพเนนต์ของระบบ EVS

แอป EVS

แอป EVS ตัวอย่าง C++ (/packages/services/Car/evs/app) ใช้เป็นข้อมูลอ้างอิงสำหรับการใช้งาน แอปนี้มีหน้าที่ขอเฟรมวิดีโอจากผู้จัดการ EVS และส่งเฟรมที่เสร็จแล้วเพื่อแสดงกลับไปยังผู้จัดการ EVS ระบบคาดว่าจะเริ่มต้นโดย init ทันทีที่ EVS และบริการของรถพร้อมใช้งาน โดยกำหนดเป้าหมายให้เริ่มภายใน 2 (2) วินาทีหลังจากเปิดเครื่อง OEM สามารถแก้ไขหรือแทนที่แอป EVS ตามต้องการ

เครื่องมือจัดการ EVS

EVS Manager (/packages/services/Car/evs/manager) มีองค์ประกอบพื้นฐานที่จําเป็นสําหรับแอป EVS เพื่อติดตั้งใช้งานตั้งแต่การแสดงผลกล้องมองหลังแบบธรรมดาไปจนถึงการแสดงผลภาพจากกล้องหลายตัวแบบ 6DOF อินเทอร์เฟซจะแสดงผ่าน HIDL และสร้างขึ้นเพื่อรองรับไคลเอ็นต์หลายรายพร้อมกัน แอปและบริการอื่นๆ (โดยเฉพาะบริการรถยนต์) สามารถค้นหาสถานะ 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 ที่มีอยู่ในระบบ (กล้องอย่างน้อย 1 ตัวและอุปกรณ์แสดงผล 1 เครื่อง)

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

แสดงผลเวกเตอร์ที่มีคำอธิบายของกล้องทั้งหมดในระบบ ระบบจะถือว่าชุดกล้องเป็นแบบคงที่และทราบได้เมื่อทำการบูต ดูรายละเอียดเกี่ยวกับคำอธิบายกล้องได้ที่ CameraDesc

openCamera(string camera_id) generates (IEvsCamera camera);

รับออบเจ็กต์อินเทอร์เฟซที่ใช้โต้ตอบกับกล้องที่เฉพาะเจาะจงซึ่งระบุด้วยสตริง camera_id ที่ไม่ซ้ำ แสดงผล Null เมื่อดำเนินการไม่สำเร็จ การพยายามเปิดกล้องที่เปิดอยู่อีกครั้งจะไม่สำเร็จ เพื่อหลีกเลี่ยงเงื่อนไขการแข่งขันที่เกี่ยวข้องกับการเริ่มต้นและปิดแอป การเปิดกล้องอีกครั้งควรปิดอินสแตนซ์ก่อนหน้าเพื่อให้คำขอใหม่ดำเนินการได้ อินสแตนซ์กล้องที่มีการจองก่อนด้วยวิธีนี้ต้องอยู่ในสถานะไม่ทำงาน โดยรอการทำลายขั้นสุดท้ายและตอบสนองต่อคําขอใดๆ ที่ส่งผลต่อสถานะกล้องด้วยรหัสผลลัพธ์ OWNERSHIP_LOST

closeCamera(IEvsCamera camera);

ปล่อยอินเทอร์เฟซ IEvsCamera (และตรงข้ามกับการเรียกใช้ openCamera()) คุณต้องหยุดสตรีมวิดีโอจากกล้องโดยเรียกใช้ stopVideoStream() ก่อนเรียกใช้ closeCamera

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 โดยไม่ตีความ ซึ่งแอป EVS สามารถละเว้นข้อมูลดังกล่าวได้

IEvsCamera

ออบเจ็กต์นี้แสดงกล้องตัวเดียวและเป็นอินเทอร์เฟซหลักสำหรับการจับภาพ

getCameraInfo() generates (CameraDesc info);

แสดงผล CameraDesc ของกล้องนี้

setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);

ระบุความลึกของเชนบัฟเฟอร์ที่ขอให้กล้องรองรับ ไคลเอ็นต์ของ IEvsCamera อาจเก็บเฟรมได้สูงสุดเท่านี้พร้อมกัน หากมีการส่งเฟรมจำนวนมากนี้ไปยังผู้รับโดยที่doneWithFrameไม่ได้ส่งคืน ข้อมูลสตรีมจะข้ามเฟรมจนกว่าจะมีการส่งบัฟเฟอร์คืนเพื่อใช้ซ้ำ การเรียกใช้นี้สามารถเกิดขึ้นได้ทุกเมื่อ แม้ในขณะที่สตรีมกำลังทำงานอยู่ก็ตาม ซึ่งในกรณีนี้ คุณควรเพิ่มหรือนำบัฟเฟอร์ออกจากเชนตามความเหมาะสม หากไม่มีการเรียกใช้จุดแรกเข้านี้ IEvsCamera จะรองรับเฟรมอย่างน้อย 1 เฟรมโดยค่าเริ่มต้น โดยรับเฟรมได้มากกว่า

หากรองรับ bufferCount ที่ขอไม่ได้ ฟังก์ชันจะแสดงผล BUFFER_NOT_AVAILABLE หรือรหัสข้อผิดพลาดอื่นๆ ที่เกี่ยวข้อง ในกรณีนี้ ระบบจะยังคงทำงานโดยใช้ค่าที่ตั้งไว้ก่อนหน้านี้

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

ส่งคำขอส่งเฟรมกล้อง EVS จากกล้องนี้ IEvsCameraStream จะเริ่มต้นรับการเรียกด้วยเฟรมรูปภาพใหม่เป็นระยะๆ จนกว่าจะมีการเรียกstopVideoStream() ระบบต้องเริ่มส่งเฟรมภายใน 500 มิลลิวินาทีหลังจากการเรียกใช้ startVideoStream และหลังจากเริ่มแล้ว เฟรมต้องสร้างขึ้นที่อัตราเฟรมอย่างน้อย 10 FPS เวลาที่จำเป็นในการเริ่มสตรีมวิดีโอจะนับรวมอยู่ในข้อกำหนดเวลาเริ่มต้นของกล้องมองหลัง หากสตรีมไม่เริ่มต้น ระบบจะแสดงรหัสข้อผิดพลาด มิเช่นนั้นระบบจะแสดงผลว่า "OK"

oneway doneWithFrame(BufferDesc buffer);

ส่งคืนเฟรมที่ส่งโดย IEvsCameraStream เมื่อใช้เฟรมที่ส่งไปยังอินเทอร์เฟซ IEvsCameraStream เสร็จแล้ว จะต้องส่งคืนเฟรมไปยัง IEvsCamera เพื่อใช้ซ้ำ มีบัฟเฟอร์จํานวนไม่มาก (อาจน้อยเพียง 1 รายการ) หากใช้บัฟเฟอร์หมดแล้ว ระบบจะไม่ส่งเฟรมเพิ่มเติมจนกว่าจะได้รับบัฟเฟอร์ ซึ่งอาจส่งผลให้เฟรมข้ามไป (บัฟเฟอร์ที่มีแฮนเดิล Null หมายถึงจุดสิ้นสุดของสตรีม และไม่จำเป็นต้องส่งผ่านผ่านฟังก์ชันนี้) แสดงผล 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. Flag การใช้งานที่การตั้งค่า HAL กำหนด คาดว่าไคลเอ็นต์ HAL จะส่งค่าเหล่านี้โดยไม่มีการแก้ไข (ดูรายละเอียดได้ในGralloc.h Flag ที่เกี่ยวข้อง)
  • bufferId. ค่าที่ไม่ซ้ำกันซึ่งการใช้งาน HAL ระบุไว้เพื่ออนุญาตให้ระบบจดจำบัฟเฟอร์หลังจากการไปกลับผ่าน HAL API การใช้งาน HAL อาจเลือกค่าที่เก็บไว้ในช่องนี้โดยพลการ
  • memHandle. แฮนเดิลสำหรับบัฟเฟอร์หน่วยความจำที่อยู่เบื้องหลังซึ่งมีข้อมูลรูปภาพ การใช้งาน HAL อาจเลือกจัดเก็บตัวแฮนเดิลบัฟเฟอร์ Gralloc ไว้ที่นี่

IEvsCameraStream

ไคลเอ็นต์ใช้อินเทอร์เฟซนี้เพื่อรับการส่งเฟรมวิดีโอแบบไม่ประสานเวลา

deliverFrame(BufferDesc buffer);

รับสายจาก HAL ทุกครั้งที่เฟรมวิดีโอพร้อมสําหรับการตรวจสอบ แฮนเดิลบัฟเฟอร์ที่ได้รับจากเมธอดนี้ต้องแสดงผลผ่านการเรียกใช้ IEvsCamera::doneWithFrame() เมื่อสตรีมวิดีโอหยุดลงผ่านการเรียก IEvsCamera::stopVideoStream() การเรียกกลับนี้อาจยังคงดำเนินต่อไปเมื่อไปป์ไลน์หมด แต่ละเฟรมยังคงต้องส่งคืน เมื่อส่งเฟรมสุดท้ายในสตรีมแล้ว ระบบจะส่ง bufferHandle ที่เป็นค่า NULL ซึ่งบ่งบอกว่าสตรีมสิ้นสุดลงและจะไม่มีการส่งเฟรมอีก คุณไม่จำเป็นต้องส่งตัวแปร NULL ของ bufferHandle กลับผ่าน doneWithFrame() แต่ต้องส่งตัวแฮนเดิลอื่นๆ ทั้งหมดกลับ

แม้ว่ารูปแบบบัฟเฟอร์ที่เป็นกรรมสิทธิ์จะเป็นไปได้ในทางเทคนิค แต่การทดสอบความเข้ากันได้กำหนดให้บัฟเฟอร์ต้องอยู่ในรูปแบบใดรูปแบบหนึ่งที่รองรับ ซึ่งได้แก่ NV21 (YCrCb 4:2:0 Semi-Planar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4:2:2 Interleaved), RGBA (32 บิต R:G:B:x), BGRA (32 บิต B:G:R:x) รูปแบบที่เลือกต้องเป็นแหล่งที่มาของพื้นผิว 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() แม้ว่าจะไม่เห็นจอแสดงผลแล้วก็ตาม

แม้ว่ารูปแบบบัฟเฟอร์ที่เป็นกรรมสิทธิ์จะใช้งานได้ในทางเทคนิค แต่การทดสอบความเข้ากันได้กำหนดให้บัฟเฟอร์อยู่ในรูปแบบใดรูปแบบหนึ่งจาก 4 รูปแบบที่รองรับ ได้แก่ NV21 (YCrCb 4:2:0 แบบ Semi-Planar), YV12 (YCrCb 4:2:0 แบบ Planar), YUYV (YCrCb 4:2:2 แบบ Interleaved), RGBA (32 บิต R:G:B:x), BGRA (32 บิต B:G:R:x) รูปแบบที่เลือกต้องเป็นเป้าหมายการแสดงผล GL ที่ถูกต้องในการใช้งาน GLES ของแพลตฟอร์ม

หากเกิดข้อผิดพลาด ระบบจะแสดงผลบัฟเฟอร์ที่มีแฮนเดิล Null แต่ไม่จำเป็นต้องส่งบัฟเฟอร์ดังกล่าวกลับไปยัง 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 สตริงที่ระบุจอแสดงผลที่ไม่ซ้ำกัน ซึ่งอาจเป็นชื่ออุปกรณ์เคอร์เนลของอุปกรณ์ หรือชื่อของอุปกรณ์ เช่น rearview สตริงนี้จะได้รับค่าจากการใช้งาน HAL และกองซ้อนด้านบนจะใช้สตริงนี้แบบทึบ
  • vendor_flags. วิธีการส่งข้อมูลกล้องเฉพาะจากไดรเวอร์ไปยังแอป EVS ที่กําหนดเองแบบไม่ระบุรายละเอียด โดยระบบจะส่งข้อมูลดังกล่าวจากไดรเวอร์ไปยังแอป 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 Manager ใช้ API เดียวกับไดรเวอร์ HAL ที่เกี่ยวข้องและให้บริการที่ขยายการให้บริการโดยรองรับไคลเอ็นต์หลายรายพร้อมกัน (ไคลเอ็นต์มากกว่า 1 รายสามารถเปิดกล้องผ่าน EVS Manager และรับสตรีมวิดีโอได้)

แผนภาพ EVS Manager และ EVS Hardware API

รูปที่ 2 EVS Manager จะมิเรอร์ EVS Hardware API ที่เกี่ยวข้อง

แอปจะไม่พบความแตกต่างเมื่อทํางานผ่านการใช้งาน HAL ของฮาร์ดแวร์ EVS หรือ EVS Manager API ยกเว้นว่า EVS Manager API จะอนุญาตให้เข้าถึงสตรีมกล้องพร้อมกันได้ เครื่องมือจัดการ EVS นั้นเป็นไคลเอ็นต์ที่ได้รับอนุญาตของเลเยอร์ HAL ของฮาร์ดแวร์ EVS และทำหน้าที่เป็นพร็อกซีสำหรับ HAL ของฮาร์ดแวร์ EVS

ส่วนต่อไปนี้จะอธิบายเฉพาะการเรียกที่มีลักษณะการทำงาน (ขยาย) แตกต่างจากการใช้งาน EVS Manager ส่วนการเรียกที่เหลือจะเหมือนกับคำอธิบาย HAL ของ EVS

IEvsEnumerator

openCamera(string camera_id) generates (IEvsCamera camera);

รับออบเจ็กต์อินเทอร์เฟซที่ใช้โต้ตอบกับกล้องที่เฉพาะเจาะจงซึ่งระบุด้วยสตริง camera_id ที่ไม่ซ้ำ แสดงผล Null เมื่อดำเนินการไม่สำเร็จ ที่เลเยอร์ EVS Manager กระบวนการอื่นอาจเปิดกล้องที่เปิดอยู่แล้วอีกครั้งได้ตราบใดที่มีทรัพยากรระบบเพียงพอ ซึ่งจะช่วยให้ส่งสตรีมวิดีโอไปยังแอปต่างๆ ของผู้บริโภคได้ สตริง camera_id ที่เลเยอร์ EVS Manager จะเหมือนกับสตริงที่รายงานไปยังเลเยอร์ฮาร์ดแวร์ EVS

IEvsCamera

การติดตั้งใช้งาน IEvsCamera ที่ได้จาก EVS Manager จะเป็นแบบเสมือนภายในเพื่อให้การดำเนินการกับกล้องโดยลูกค้ารายหนึ่งไม่ส่งผลต่อลูกค้ารายอื่นๆ ซึ่งจะยังคงเข้าถึงกล้องของตนได้อย่างอิสระ

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 Manager และ HAL ของยานพาหนะเพื่อให้บริการฟังก์ชันพื้นฐานของกล้องมองหลัง แอปคาดว่าจะเริ่มทำงานตั้งแต่เนิ่นๆ ในกระบวนการบูตระบบ โดยจะมีวิดีโอที่เหมาะสมแสดงขึ้นโดยขึ้นอยู่กับกล้องที่ใช้ได้และสถานะของรถ (สถานะเกียร์และไฟเลี้ยว) OEM สามารถแก้ไขหรือแทนที่แอป EVS ด้วยตรรกะและการแสดงผลเฉพาะรถยนต์ของตนเองได้

รูปที่ 3 ตัวอย่างตรรกะแอป EVS, get camera list



รูปที่ 4 ตรรกะตัวอย่างแอป EVS, รับการเรียกกลับเฟรม

เนื่องจากระบบจะแสดงข้อมูลรูปภาพต่อแอปในบัฟเฟอร์กราฟิกมาตรฐาน แอปจึงมีหน้าที่รับผิดชอบในการย้ายรูปภาพจากบัฟเฟอร์ต้นทางไปยังบัฟเฟอร์เอาต์พุต แม้ว่าวิธีนี้จะเพิ่มค่าใช้จ่ายในการคัดลอกข้อมูล แต่ก็เปิดโอกาสให้แอปแสดงผลภาพไปยังบัฟเฟอร์การแสดงผลในลักษณะที่ต้องการ

ตัวอย่างเช่น แอปอาจเลือกย้ายข้อมูลพิกเซลด้วยตนเอง ซึ่งอาจมีการดําเนินการเพื่อปรับขนาดหรือหมุนในบรรทัด นอกจากนี้ แอปยังเลือกที่จะใช้รูปภาพต้นฉบับเป็นพื้นผิว OpenGL และแสดงผลฉากที่ซับซ้อนไปยังบัฟเฟอร์เอาต์พุตได้ ซึ่งรวมถึงองค์ประกอบเสมือนจริง เช่น ไอคอน เส้นกํากับ และภาพเคลื่อนไหว แอปที่ซับซ้อนกว่านั้นอาจเลือกกล้องอินพุตหลายตัวพร้อมกันและผสานเข้าด้วยกันเป็นเฟรมเอาต์พุตเดียว (เช่น ใช้สําหรับมุมมองภาพเสมือนจริงจากด้านบนของสภาพแวดล้อมรอบๆ ยานพาหนะ)

ใช้ EGL/SurfaceFlinger ใน HAL ของจอแสดงผล EVS

ส่วนนี้จะอธิบายวิธีใช้ EGL เพื่อแสดงผลการใช้งาน HAL ของจอแสดงผล EVS ใน Android 10

การใช้งานตามข้อมูลอ้างอิง EVS HAL ใช้ EGL เพื่อแสดงผลตัวอย่างจากกล้องบนหน้าจอ และใช้ libgui เพื่อสร้างพื้นผิวการแสดงผล EGL เป้าหมาย ใน Android 8 (และเวอร์ชันที่ใหม่กว่า) libgui จะจัดอยู่ในประเภท VNDK-private ซึ่งหมายถึงกลุ่มไลบรารีที่ใช้ได้กับไลบรารี VNDK ที่กระบวนการของผู้ให้บริการใช้ไม่ได้ เนื่องจากการติดตั้งใช้งาน HAL ต้องอยู่ในพาร์ติชันของผู้ให้บริการ ผู้ให้บริการจึงไม่สามารถใช้ Surface ในการติดตั้งใช้งาน HAL

การสร้าง libgui สำหรับกระบวนการของผู้ให้บริการ

การใช้ libgui เป็นตัวเลือกเดียวในการใช้ EGL/SurfaceFlinger ในการใช้งาน HAL ของจอแสดงผล EVS วิธีที่ตรงที่สุดในการใช้ libgui คือผ่าน frameworks/native/libs/gui โดยตรงโดยใช้เป้าหมายการสร้างเพิ่มเติมในสคริปต์การสร้าง เป้าหมายนี้เหมือนกับเป้าหมาย libgui ทุกประการ ยกเว้นการเพิ่มช่อง 2 ช่องต่อไปนี้

  • 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 บิต 1 รายการออกจากข้อมูลพัสดุ เนื่องจาก 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

ใช้ 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 มีวิธีการเลือก Binder Driver สำหรับ 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 หรือก่อนทำการเรียกใช้ Binder

นโยบาย SELinux

หากการติดตั้งใช้งานอุปกรณ์เป็นแบบ Full Treble นั้น SELinux จะป้องกันไม่ให้กระบวนการของผู้ให้บริการใช้ /dev/binder เช่น การติดตั้งใช้งานตัวอย่าง HAL ของ EVS ได้รับการกําหนดให้กับโดเมน hal_evs_driver และต้องได้รับสิทธิ์อ่าน/เขียนในโดเมน binder_device

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

อย่างไรก็ตาม การเพิ่มสิทธิ์เหล่านี้จะทำให้การบิลด์ไม่สำเร็จเนื่องจากละเมิดกฎ neverallow ต่อไปนี้ที่ระบุไว้ใน system/sepolicy/domain.te สำหรับอุปกรณ์แบบ Treble เต็มรูปแบบ

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;