กล้องติดรถยนต์ HAL

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

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

ส่วนประกอบของระบบ

EVS มีส่วนประกอบของระบบดังต่อไปนี้:

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

รูปที่ 1 ภาพ รวมส่วนประกอบของระบบ EVS

แอพ EVS

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

ผู้จัดการ EVS

EVS Manager ( /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 stack ต้องใช้ไดรเวอร์เคอร์เนล แทนที่จะสร้างไดรเวอร์ใหม่ OEM มีตัวเลือกในการรองรับคุณสมบัติที่ต้องการ EVS ผ่านทางกล้องและ/หรือไดรเวอร์ฮาร์ดแวร์จอแสดงผลที่มีอยู่ การใช้ไดรเวอร์ซ้ำอาจมีข้อได้เปรียบ โดยเฉพาะอย่างยิ่งสำหรับไดรเวอร์การแสดงผลซึ่งการนำเสนอรูปภาพอาจต้องอาศัยการประสานงานกับเธรดอื่นๆ ที่ใช้งานอยู่ Android 8.0 มีไดรเวอร์ตัวอย่างที่ใช้ v4l2 (ใน packages/services/Car/evs/sampleDriver ) ที่ขึ้นอยู่กับเคอร์เนลสำหรับการรองรับ v4l2 และบน SurfaceFlinger สำหรับการนำเสนอภาพที่ส่งออก

คำอธิบายอินเทอร์เฟซฮาร์ดแวร์ EVS

ในส่วนนี้อธิบายถึง HAL ผู้จำหน่ายได้รับการคาดหวังให้จัดเตรียมการใช้งาน API นี้ซึ่งปรับให้เหมาะกับฮาร์ดแวร์ของตน

IEvsตัวแจงนับ

วัตถุนี้มีหน้าที่รับผิดชอบในการแจงนับฮาร์ดแวร์ EVS ที่มีอยู่ในระบบ (กล้องตั้งแต่หนึ่งตัวขึ้นไปและอุปกรณ์แสดงผลเดียว)

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 สตริงที่ระบุกล้องที่ระบุโดยไม่ซ้ำกัน อาจเป็นชื่ออุปกรณ์เคอร์เนลของอุปกรณ์หรือชื่ออุปกรณ์ เช่น กล้องมองหลัง ค่าสำหรับสตริงนี้ถูกเลือกโดยการใช้งาน 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() เฟรมจะต้องเริ่มส่งภายใน 500 มิลลิวินาทีของการเรียก startVideoStream และหลังจากเริ่มต้นแล้ว ต้องสร้างอย่างน้อย 10 FPS เวลาที่ต้องใช้ในการเริ่มสตรีมวิดีโอจะนับอย่างมีประสิทธิภาพกับข้อกำหนดเวลาเริ่มต้นของกล้องมองหลัง หากไม่เริ่มสตรีม จะต้องส่งคืนรหัสข้อผิดพลาด มิฉะนั้น ตกลง จะถูกส่งกลับ

oneway doneWithFrame(BufferDesc buffer);

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

IEvsCameraStream

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

deliverFrame(BufferDesc buffer);

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

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

getDisplayState() generates (DisplayState state);

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

getTargetBuffer() generates (handle bufferHandle);

ส่งคืนหมายเลขอ้างอิงไปยังเฟรมบัฟเฟอร์ที่เกี่ยวข้องกับจอแสดงผล บัฟเฟอร์นี้อาจถูกล็อคและเขียนโดยซอฟต์แวร์และ/หรือ GL บัฟเฟอร์นี้จะต้องส่งคืนผ่านการเรียกเพื่อ returnTargetBufferForDisplay() แม้ว่าจอแสดงผลจะไม่สามารถมองเห็นได้อีกต่อไป

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

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

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

รูปที่ 2 EVS Manager จำลอง EVS Hardware API พื้นฐาน

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

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

IEvsตัวแจงนับ

openCamera(string camera_id) generates (IEvsCamera camera);

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

IEvsCamera

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

IEvsDisplay

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

แอพ EVS

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

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



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

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

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

ใช้ EGL/SurfaceFlinger ใน EVS Display HAL

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

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

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

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

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

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

หมายเหตุ: เป้าหมายผู้ขายถูกสร้างขึ้นด้วยมาโคร NO_INPUT ซึ่งจะลบคำ 32 บิตหนึ่งคำออกจากข้อมูลพัสดุ เนื่องจาก SurfaceFlinger คาดว่าฟิลด์นี้จะถูกลบออก SurfaceFlinger จึงไม่สามารถแยกวิเคราะห์พัสดุได้ สิ่งนี้ถูกมองว่าเป็นความล้มเหลว fcntl :

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

หากต้องการแก้ไขเงื่อนไขนี้:

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

คำแนะนำในการสร้าง ตัวอย่างมีดังต่อไปนี้ คาดว่าจะได้รับ $(ANDROID_PRODUCT_OUT)/system/lib64/libgui_vendor.so

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

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

ใช้สารยึดเกาะในการใช้งาน EVS HAL

ใน Android 8 (และสูงกว่า) โหนดอุปกรณ์ /dev/binder กลายเป็นเอกสิทธิ์ของกระบวนการเฟรมเวิร์ก ดังนั้นจึงไม่สามารถเข้าถึงกระบวนการของผู้จำหน่ายได้ กระบวนการของผู้จำหน่ายควรใช้ /dev/hwbinder และต้องแปลงอินเทอร์เฟซ AIDL ให้เป็น HIDL แทน สำหรับผู้ที่ต้องการใช้อินเทอร์เฟซ AIDL ระหว่างกระบวนการของผู้จำหน่ายต่อไป ให้ใช้โดเมนเครื่องผูก /dev/vndbinder

โดเมนไอพีซี คำอธิบาย
/dev/binder IPC ระหว่างเฟรมเวิร์ก/กระบวนการแอปด้วยอินเทอร์เฟซ AIDL
/dev/hwbinder IPC ระหว่างกรอบงาน/กระบวนการของผู้จำหน่ายด้วยอินเทอร์เฟซ HIDL
IPC ระหว่างกระบวนการของผู้ขายด้วยอินเทอร์เฟซ HIDL
/dev/vndbinder IPC ระหว่างกระบวนการของผู้ขาย/ผู้ขายด้วยอินเทอร์เฟซ AIDL

ในขณะที่ SurfaceFlinger กำหนดอินเทอร์เฟซ AIDL กระบวนการของผู้จำหน่ายสามารถใช้อินเทอร์เฟซ HIDL เพื่อสื่อสารกับกระบวนการเฟรมเวิร์กเท่านั้น จำเป็นต้องมีงานที่ไม่สำคัญในการแปลงอินเทอร์เฟซ AIDL ที่มีอยู่ให้เป็น HIDL โชคดีที่ Android มีวิธีในการเลือกไดรเวอร์เครื่องผูกสำหรับ 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

หากการใช้งานอุปกรณ์มีเสียงแหลมเต็ม 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;