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

ตัวอย่างแอป C++ EVS (/packages/services/Car/evs/app) ทำหน้าที่เป็นข้อมูลอ้างอิงการใช้งาน แอปนี้รับหน้าที่ขอเฟรมวิดีโอจาก EVS Manager และส่งเฟรมที่เสร็จแล้วเพื่อแสดงกลับไปยังเครื่องมือจัดการ 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 เสร็จแล้ว เฟรมดังกล่าวจะต้องกลับไปอยู่ใน IEvs Camera เพื่อใช้ซ้ำ มีบัฟเฟอร์เล็กน้อย (ซึ่งอาจมีขนาดเล็กเพียง 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() การเรียกกลับนี้อาจยังคงดำเนินต่อไปเมื่อไปป์ไลน์หมด แต่ละเฟรมยังคงต้องส่งคืนอยู่ เมื่อมีการนำส่งเฟรมสุดท้ายในสตรีม ระบบจะส่งบัฟเฟอร์ค่า Null ซึ่งแสดงถึงจุดสิ้นสุดของสตรีมและไม่มีการนำส่งเฟรมเพิ่มเติม คุณไม่จำเป็นต้องส่งตัวแปร NULL ของ bufferHandle กลับผ่าน doneWithFrame() แต่ต้องส่งแฮนเดิลอื่นๆ ทั้งหมดกลับ

แม้ว่ารูปแบบบัฟเฟอร์ที่เป็นกรรมสิทธิ์จะเป็นไปได้ในทางเทคนิค แต่การทดสอบความเข้ากันได้กำหนดให้บัฟเฟอร์ต้องอยู่ในรูปแบบใดรูปแบบหนึ่งที่รองรับ 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 ของแพลตฟอร์ม

แอปไม่ควรใช้การเชื่อมโยงใดๆ ระหว่างช่อง 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() แม้ว่าจอแสดงผลจะไม่แสดงอีกต่อไปก็ตาม

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

EVS Manager ใช้ API เดียวกับไดรเวอร์ HAL ที่เกี่ยวข้องและให้บริการที่ขยายการให้บริการโดยรองรับไคลเอ็นต์หลายรายพร้อมกัน (ไคลเอ็นต์มากกว่า 1 รายสามารถเปิดกล้องผ่าน EVS Manager และรับสตรีมวิดีโอได้)

แผนภาพตัวจัดการ EVS และ
ฮาร์ดแวร์ API ของ EVS

รูปที่ 2 EVS Manager มิเรอร์ API ฮาร์ดแวร์ EVS ที่เกี่ยวข้อง

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

แอป EVS

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

รูปที่ 3 ตรรกะตัวอย่างแอป EVS ดู รายการกล้อง



รูปที่ 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 สำหรับ libbinder ที่จะลิงก์กับกระบวนการของคลัง Userspace

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 ตัวอย่างเช่น ตัวอย่างการติดตั้งใช้งาน 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 สำหรับอุปกรณ์แบบ 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;