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
แอป 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 ของระบบโดยเฉพาะ มีเพียงลูกค้ารายเดียวที่จะมีอินสแตนซ์ที่ใช้งานได้ของ 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 เสร็จแล้ว จะต้องส่งคืนเฟรมไปยัง 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
. Flag การใช้งานที่การตั้งค่า HAL กำหนด คาดว่าไคลเอ็นต์ HAL จะส่งค่าเหล่านี้โดยไม่มีการแก้ไข (ดูรายละเอียดได้ในGralloc.h
Flag ที่เกี่ยวข้อง)bufferId
. ค่าที่ไม่ซ้ำกันซึ่งการใช้งาน HAL ระบุไว้เพื่ออนุญาตให้ระบบจดจำบัฟเฟอร์หลังจากการไปกลับผ่าน HAL API การใช้งาน HAL อาจเลือกค่าที่เก็บไว้ในช่องนี้โดยพลการmemHandle
. แฮนเดิลสำหรับบัฟเฟอร์หน่วยความจำที่อยู่เบื้องหลังซึ่งมีข้อมูลรูปภาพ การใช้งาน HAL อาจเลือกจัดเก็บตัวแฮนเดิลบัฟเฟอร์ Gralloc ไว้ที่นี่
IEvsCameraStream
ไคลเอ็นต์ใช้อินเทอร์เฟซนี้เพื่อรับการส่งเฟรมวิดีโอแบบไม่ประสานเวลา
deliverFrame(BufferDesc buffer);
รับสายจาก HAL ทุกครั้งที่เฟรมวิดีโอพร้อมสําหรับการตรวจสอบ
แฮนเดิลบัฟเฟอร์ที่ได้รับจากเมธอดนี้ต้องแสดงผลผ่านการเรียกใช้ IEvsCamera::doneWithFrame()
เมื่อสตรีมวิดีโอหยุดลงผ่านการเรียก IEvsCamera::stopVideoStream()
การเรียกกลับนี้อาจยังคงดำเนินต่อไปเมื่อไปป์ไลน์หมด แต่ละเฟรมยังคงต้องส่งคืน เมื่อส่งเฟรมสุดท้ายในสตรีมแล้ว ระบบจะส่ง bufferHandle ที่เป็นค่า NULL ซึ่งบ่งบอกว่าสตรีมสิ้นสุดลงและจะไม่มีการส่งเฟรมอีก คุณไม่จำเป็นต้องส่งตัวแปร NULL ของ bufferHandle กลับผ่าน doneWithFrame()
แต่ต้องส่งตัวแฮนเดิลอื่นๆ ทั้งหมดกลับ
แม้ว่ารูปแบบบัฟเฟอร์ที่เป็นกรรมสิทธิ์จะเป็นไปได้ในทางเทคนิค แต่การทดสอบความเข้ากันได้กำหนดให้บัฟเฟอร์ต้องอยู่ในรูปแบบใดรูปแบบหนึ่งที่รองรับ ซึ่งได้แก่ 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 บิต 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
สตริงที่ระบุจอแสดงผลที่ไม่ซ้ำกัน ซึ่งอาจเป็นชื่ออุปกรณ์เคอร์เนลของอุปกรณ์ หรือชื่อของอุปกรณ์ เช่น rearview สตริงนี้จะได้รับค่าจากการใช้งาน 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 Manager และเป็นไคลเอ็นต์เพียงรายเดียวที่ได้รับอนุญาตให้เขียนข้อมูลการแสดงผล (สามารถให้สิทธิ์เข้าถึงภาพจากกล้องแบบอ่านอย่างเดียวแก่ไคลเอ็นต์เพิ่มเติมได้)
EVS Manager ใช้ API เดียวกับไดรเวอร์ HAL ที่เกี่ยวข้องและให้บริการที่ขยายการให้บริการโดยรองรับไคลเอ็นต์หลายรายพร้อมกัน (ไคลเอ็นต์มากกว่า 1 รายสามารถเปิดกล้องผ่าน EVS Manager และรับสตรีมวิดีโอได้)

รูปที่ 2 EVS Manager จะมิเรอร์ EVS Hardware API ที่เกี่ยวข้อง
แอปจะไม่พบความแตกต่างเมื่อทํางานผ่านการใช้งาน 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 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 Manager และ 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;