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

กล้อง IEv

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

getCameraInfo() generates (CameraDesc info);

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

setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);

ระบุความลึกของเชนบัฟเฟอร์ที่ขอให้กล้องรองรับ เฟรมจำนวนมากอาจถือพร้อมกันโดยไคลเอ็นต์ของ IEvsกล้องถ่ายรูป หากมีการส่งเฟรมจำนวนมากนี้ไปยังผู้รับโดยที่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 จำนวนพิกเซลแต่ละแถวจะใช้หน่วยความจำจริง ซึ่งพิจารณา Padding สำหรับการจัดแถวของแถว แสดงเป็นพิกเซลเพื่อให้ตรงกับรูปแบบที่ 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() Callback นี้อาจทำงานต่อไปขณะที่ไปป์ไลน์จะระบายน้ำ แต่ละเฟรมยังคงต้องส่งคืน เมื่อมีการส่งเฟรมสุดท้ายในสตรีม ระบบจะส่ง bufferHandle เป็นค่าว่าง ซึ่งเป็นสัญลักษณ์จุดสิ้นสุดของสตรีมและไม่มีการส่งเฟรมเพิ่มเติม คุณไม่จำเป็นต้องส่ง 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 ของแพลตฟอร์ม

หากเกิดข้อผิดพลาด ระบบจะแสดงผลบัฟเฟอร์ที่มีแฮนเดิลค่า 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 โดยไม่ตีความ ซึ่งแอป 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 Manager และ EVS Hardware API
รูปที่ 2 EVS Manager จะมิเรอร์ EVS พื้นฐาน Hardware API

แอปจะไม่มีความแตกต่างกันเมื่อทำงานผ่านการติดตั้งใช้งานฮาร์ดแวร์ EVS ระดับฮาร์ดแวร์ HAL หรือ 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 และ 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;