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

Android มี Hardware Abstraction Layer (HAL) ของ HIDL สำหรับยานยนต์ที่ รองรับการจับภาพและแสดงภาพตั้งแต่ช่วงแรกๆ ของกระบวนการบูต 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 Manager และส่งเฟรมที่เสร็จสมบูรณ์เพื่อแสดงกลับไปยัง EVS Manager โดยคาดว่า init จะเริ่มทำงานทันทีที่ EVS และ Car Service พร้อมใช้งาน ซึ่งมีเป้าหมายภายใน 2 วินาทีหลังจากเปิดเครื่อง OEM สามารถแก้ไขหรือแทนที่แอป EVS ได้ตามต้องการ

EVS Manager

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

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 เวลาที่ต้องใช้ในการเริ่มสตรีมวิดีโอจะนับรวมกับข้อกำหนดเวลาเริ่มต้นของกล้องมองหลัง หากไม่ได้เริ่มสตรีม จะต้องแสดงรหัสข้อผิดพลาด มิฉะนั้นจะแสดง "ตกลง"

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

IEvsCameraStream

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

deliverFrame(BufferDesc buffer);

รับการเรียกจาก HAL ทุกครั้งที่เฟรมวิดีโอพร้อมสำหรับการตรวจสอบ ต้องส่งคืนบัฟเฟอร์ที่จัดการโดยเมธอดนี้ผ่านการเรียก IEvsCamera::doneWithFrame() เมื่อหยุดสตรีมวิดีโอด้วยการเรียกใช้ IEvsCamera::stopVideoStream() คอลแบ็กนี้อาจทำงานต่อไป ขณะที่ไปป์ไลน์ระบายข้อมูล คุณยังคงต้องส่งคืนแต่ละเฟรม เมื่อส่งเฟรมสุดท้าย ในสตรีมแล้ว ระบบจะส่ง bufferHandle ที่เป็น 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() แม้ว่าจะมองไม่เห็นจอแสดงผลแล้วก็ตาม

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

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

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

แผนภาพ EVS Manager และ
EVS Hardware API
รูปที่ 2 EVS Manager จะจำลอง EVS Hardware API ที่อยู่เบื้องหลัง

แอปจะไม่เห็นความแตกต่างเมื่อทำงานผ่านการติดตั้งใช้งาน EVS Hardware HAL หรือ EVS Manager API ยกเว้นว่า 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

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

IEvsDisplay

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

แอป EVS

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

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


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

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

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

ใช้ EGL/SurfaceFlinger ใน EVS Display HAL

ส่วนนี้จะอธิบายวิธีใช้ 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 ซึ่งลิงก์กับกระบวนการไลบรารีในพื้นที่ผู้ใช้

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

หากการติดตั้งใช้งานอุปกรณ์เป็น 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;