Android มีเลเยอร์การแยกแยะฮาร์ดแวร์ HIDL (HAL) ยานยนต์ที่รองรับการจับภาพและแสดงภาพตั้งแต่เนิ่นๆ ในกระบวนการบูตของ Android และทำงานต่อไปตลอดอายุการใช้งานของระบบ HAL ประกอบด้วยกองซ้อนระบบภาพภายนอก (EVS) และมักใช้เพื่อรองรับกล้องมองหลังและจอแสดงผลภาพรอบตัวในยานพาหนะที่ติดตั้งระบบสาระบันเทิงในรถ (IVI) ที่ใช้ Android นอกจากนี้ EVS ยังช่วยให้ติดตั้งใช้งานฟีเจอร์ขั้นสูงในแอปของผู้ใช้ได้ด้วย
นอกจากนี้ Android ยังมีอินเทอร์เฟซของโปรแกรมควบคุมการแสดงผลและอุปกรณ์จับภาพสำหรับ EVS โดยเฉพาะ (ใน /hardware/interfaces/automotive/evs/1.0
) แม้ว่าจะสร้างแอปกล้องมองหลังบนบริการกล้องและจอแสดงผลที่มีอยู่ของ Android ได้ แต่แอปดังกล่าวมีแนวโน้มที่จะทำงานในกระบวนการบูตของ Android ช้าเกินไป การใช้ HAL โดยเฉพาะช่วยให้อินเทอร์เฟซมีประสิทธิภาพมากขึ้นและทำให้ OEM ทราบสิ่งที่ต้องติดตั้งใช้งานเพื่อรองรับสแต็ก 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 และรับสตรีมวิดีโอได้)
แอปจะไม่พบความแตกต่างเมื่อทํางานผ่านการใช้งาน 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;