หน้านี้อธิบายการเปลี่ยนแปลงไดรเวอร์ Binder ใน Android 8, รายละเอียดเกี่ยวกับการใช้ Binder IPC และแสดงนโยบาย SELinux ที่จำเป็น
การเปลี่ยนแปลงไดรเวอร์ Binder
ตั้งแต่ Android 8 เป็นต้นไป เฟรมเวิร์ก Android และ HAL จะสื่อสารกับ โดยใช้แฟ้ม เนื่องจากการสื่อสารนี้เพิ่มการเชื่อมโยงขึ้นอย่างมาก การเข้าชม Android 8 มีการปรับปรุงหลายอย่างที่ออกแบบมาเพื่อรักษา IPC ของ Binder ไว้ อย่างรวดเร็ว ผู้ให้บริการ SoC และ OEM ควรรวมธุรกิจจากสาขาที่เกี่ยวข้องโดยตรง Android-4.4, Android-4.9 ขึ้นไป kernel/common
โดเมนการเชื่อมโยงหลายโดเมน (บริบท)
Common-4.4 ขึ้นไป รวมถึงอัปสตรีมเพื่อแยกการเข้าชมการเชื่อมโยงระหว่างเฟรมเวิร์ก (ไม่อิงตามอุปกรณ์) กับ รหัสผู้ให้บริการ (เฉพาะอุปกรณ์) Android 8 ได้แนะนำแนวคิดของแฟ้ม บริบท บริบทของไฟล์ Binder แต่ละรายการจะมีโหนดอุปกรณ์และบริบทของตัวเอง (บริการ) คุณเข้าถึงเครื่องมือจัดการบริบทได้ผ่านอุปกรณ์เท่านั้น โหนดนั้นอยู่ และเมื่อส่งโหนด Binder ผ่านโหนด บริบทเดียวกัน จะสามารถเข้าถึงได้จากบริบทเดียวกันนั้นด้วยกระบวนการอื่นเท่านั้น ดังนั้น การแยกโดเมนออกจากกันโดยสิ้นเชิง ดูรายละเอียดเกี่ยวกับการใช้ได้ที่ vndbinder และ vndservicemanager
แบบกระจาย
Common-4.4 ขึ้นไป รวมถึงอัปสตรีมใน Android รุ่นก่อนหน้า ข้อมูลทั้งหมดในการเรียกใช้ Binder ได้รับการคัดลอก สามครั้ง:
- ครั้งเดียวเพื่อเรียงลำดับให้เป็น
Parcel
ในกระบวนการโทร - เมื่ออยู่ในไดรเวอร์เคอร์เนลเพื่อคัดลอก
Parcel
ไปยังเป้าหมาย กระบวนการ - จะยกเลิกอนุกรม
Parcel
ในกระบวนการเป้าหมาย 1 ครั้ง
Android 8 ใช้
กลุ่มแบบกระจาย
การเพิ่มประสิทธิภาพเพื่อลดจำนวนสำเนาจาก 3 เหลือ 1 แทนที่จะเป็น
การจัดลำดับข้อมูลใน Parcel
ก่อน ข้อมูลจะยังคงอยู่ในต้นฉบับ
โครงสร้างและเลย์เอาต์หน่วยความจำ และไดรเวอร์จะคัดลอกไปยังเป้าหมายทันที
ขั้นตอนได้ หลังจากข้อมูลอยู่ในกระบวนการเป้าหมายแล้ว โครงสร้างและหน่วยความจำ
เหมือนกัน และสามารถอ่านข้อมูลได้โดยไม่ต้องคัดลอกอีก
การล็อกแบบละเอียด
Common-4.4 ขึ้นไป รวมถึงอัปสตรีมใน Android รุ่นก่อนหน้า ไดรเวอร์ Binder ใช้ล็อกส่วนกลางเพื่อปกป้อง ต่อการเข้าถึงโครงสร้างข้อมูลที่สำคัญพร้อมกัน แม้มีน้อยที่สุด การช่วงชิงล็อก ปัญหาหลักคือถ้าเทรดที่มีลำดับความสำคัญต่ำ ล็อกและถูกขัดจังหวะชั่วคราว อาจทำให้ล่าช้าอย่างมาก ชุดข้อความที่มีลำดับความสำคัญสูงกว่าจำเป็นต้องได้รับการล็อกแบบเดียวกัน ซึ่งทำให้เกิดการกระตุกใน ที่มีการจัดการครบวงจรได้เลย
ความพยายามแรกเริ่มในการแก้ไขปัญหานี้ ได้แก่ การปิดใช้ชั่วคราว กดล็อกส่วนกลางค้างไว้ แต่วิธีนี้แฮ็กมากกว่าวิธีแก้ปัญหาที่แท้จริง และถูกปฏิเสธโดยอัปสตรีมและทิ้งไปในที่สุด ความพยายามครั้งต่อๆ ไป ที่เน้นไปที่การทำให้การล็อกทำงาน ได้ละเอียดขึ้น ซึ่งเป็นเวอร์ชัน ในอุปกรณ์ Pixel ตั้งแต่เดือนมกราคม 2017 เป็นต้นไป แม้ว่าการเปลี่ยนแปลงส่วนใหญ่ เผยแพร่ต่อสาธารณะ และได้มีการปรับปรุงที่สำคัญในเวอร์ชันต่อๆ มา
หลังจากพบปัญหาเล็กๆ น้อยๆ ในการใช้งานการล็อกอย่างละเอียด คิดค้นโซลูชันที่ปรับปรุงใหม่ ด้วยสถาปัตยกรรมการล็อกที่แตกต่าง การเปลี่ยนแปลงในสาขาเคอร์เนลทั่วไปทั้งหมด เราจะทดสอบต่อไป การใช้งานบนอุปกรณ์ต่างๆ จำนวนมาก เนื่องจากเราไม่ทราบเกี่ยวกับ ปัญหาที่ค้างอยู่ นี่คือการดำเนินการที่แนะนำสำหรับการจัดส่งอุปกรณ์ ที่ใช้ Android 8
การสืบทอดลำดับความสำคัญแบบเรียลไทม์
Common-4.4 และ Common-4.9 (อัปสตรีมเร็วๆ นี้)ไดรเวอร์ Binder สนับสนุนการรับค่าที่มีลำดับความสำคัญที่ดีเสมอ ในฐานะ จำนวนกระบวนการที่เพิ่มขึ้นใน Android จะทำงานตามลำดับความสำคัญแบบเรียลไทม์ ในกรณีเช่นนี้ ที่เหมาะสมคือถ้าเทรดแบบเรียลไทม์ทำการเรียก Binder ชุดข้อความในกระบวนการที่จัดการการเรียกนั้นจะทำงานตามลำดับความสำคัญแบบเรียลไทม์ด้วย ถึง รองรับกรณีการใช้งานเหล่านี้ Android 8 นำการสืบทอดลำดับความสำคัญแบบเรียลไทม์มาใช้แล้ว ในไดรเวอร์แฟ้ม
นอกเหนือจากการสืบทอดลำดับความสำคัญระดับธุรกรรมแล้ว ลำดับความสำคัญของโหนด การรับช่วงค่า จะอนุญาตให้โหนด (ออบเจ็กต์บริการ Binder) ระบุค่าต่ำสุด ลำดับความสำคัญที่เรียกใช้โหนดนี้ เวอร์ชันก่อนหน้าของ Android รองรับการรับช่วงลำดับความสำคัญของโหนดอยู่แล้วซึ่งมีค่าที่ดี แต่ Android 8 เพิ่มการรองรับการสืบทอดโหนดของนโยบายการกำหนดเวลาแบบเรียลไทม์
การเปลี่ยนแปลงพื้นที่ผู้ใช้
Android 8 มีการเปลี่ยนแปลงพื้นที่ผู้ใช้ทั้งหมดที่ต้องใช้เพื่อทำงานกับ
ไดรเวอร์ Binder ในเคอร์เนลทั่วไป โดยมีข้อยกเว้น 1 ข้อ คือ
เพื่อปิดใช้การรับค่าลำดับความสำคัญแบบเรียลไทม์สำหรับ
/dev/binder
ใช้
ioctl การพัฒนาต่อมามีการเปลี่ยนการควบคุมลำดับความสำคัญ
การสืบทอดไปยังเมธอดที่ละเอียดขึ้นซึ่งเป็นไปตามโหมด Binder (และไม่ใช่ตาม
บริบท) ของคุณ ดังนั้น ioctl ไม่อยู่ใน Branch ของ Android และเป็น
ที่ส่งมาในเคอร์เนลทั่วไปของเรา
ผลกระทบจากการเปลี่ยนแปลงนี้คือ การสืบทอดลำดับความสำคัญแบบเรียลไทม์ถูกปิดใช้โดย
ค่าเริ่มต้นสำหรับทุกโหนด ทีมประสิทธิภาพของ Android พบแล้ว
มีประโยชน์ในการเปิดใช้การสืบทอดลำดับความสำคัญแบบเรียลไทม์สำหรับโหนดทั้งหมดใน
hwbinder
และเพื่อให้ได้ผลลัพธ์เดียวกัน ให้ เลือก
การเปลี่ยนแปลงนี้ในพื้นที่ผู้ใช้
SHA สำหรับเคอร์เนลทั่วไป
หากต้องการได้รับการเปลี่ยนแปลงที่จำเป็นในไดรเวอร์ Binder ให้ซิงค์กับ SHA ที่เหมาะสม
- ทั่วไป-3.18
cc8b90c121de ANDROID: binder: อย่าตรวจสอบสิทธิ์ prio ในการคืนค่า - ทั่วไป-4.4
76b376eac7a2 ANDROID: binder: อย่าตรวจสอบสิทธิ์ของ prio ในการคืนค่า - ทั่วไป-4.9
ecd972d4f9b5 ANDROID: binder: อย่าตรวจสอบสิทธิ์ prio ในการคืนค่า
ทำงานกับ Binder IPC
ในอดีต กระบวนการของผู้ให้บริการใช้การสื่อสารระหว่างกระบวนการของ Binder
(IPC) เพื่อสื่อสาร ใน Android 8 โหนดของอุปกรณ์ /dev/binder
กลายเป็นส่วนหนึ่งของกระบวนการของเฟรมเวิร์กเท่านั้น ซึ่งหมายความว่ากระบวนการของผู้ให้บริการจะไม่มีอีกต่อไป
เข้าถึงได้ กระบวนการของผู้ให้บริการสามารถเข้าถึง /dev/hwbinder
แต่
ต้องแปลงอินเทอร์เฟซ AIDL เป็น HIDL สำหรับผู้ขายที่ต้องการดำเนินการต่อ
Android รองรับ Binder IPC โดยใช้อินเทอร์เฟซ AIDL ระหว่างกระบวนการของผู้ให้บริการ
ดังที่อธิบายไว้ด้านล่าง ใน Android 10 นั้น AIDL เวอร์ชันเสถียรจะอนุญาต
กระบวนการต่างๆ ไปใช้ /dev/binder
และในขณะเดียวกันก็ต้องแก้ปัญหาเรื่องความเสถียร
รับประกันได้ว่า HIDL และ /dev/hwbinder
ได้รับการแก้ไข สำหรับวิธีใช้เวอร์ชันเสถียร
AIDL โปรดดู
AIDL สำหรับ HAL
Vndbinder
Android 8 รองรับโดเมน Binder ใหม่สำหรับใช้ในโดยบริการของผู้ให้บริการ
โดยใช้ /dev/vndbinder
แทน /dev/binder
ด้วยฟังก์ชัน
การเพิ่ม /dev/vndbinder
ตอนนี้ Android มี
โดเมน IPC:
โดเมน IPC | คำอธิบาย |
---|---|
/dev/binder |
IPC ระหว่างกระบวนการของเฟรมเวิร์ก/แอปด้วยอินเทอร์เฟซ AIDL |
/dev/hwbinder |
IPC ระหว่างกระบวนการของเฟรมเวิร์ก/ผู้ให้บริการกับอินเทอร์เฟซ HIDL
IPC ระหว่างกระบวนการของผู้ให้บริการด้วยอินเทอร์เฟซ HIDL |
/dev/vndbinder |
IPC ระหว่างกระบวนการของผู้ให้บริการ/ผู้ให้บริการด้วยอินเทอร์เฟซ AIDL |
หากต้องการให้ /dev/vndbinder
ปรากฏขึ้น โปรดตรวจสอบว่าได้กำหนดค่าเคอร์เนลแล้ว
ตั้งค่ารายการ CONFIG_ANDROID_BINDER_DEVICES
เป็น
"binder,hwbinder,vndbinder"
(นี่คือค่าเริ่มต้นใน
ต้นไม้เคอร์เนลทั่วไป)
โดยปกติกระบวนการของผู้ให้บริการจะไม่เปิดไดรเวอร์ Binder โดยตรง แต่ใช้แทน
ลิงก์กับไลบรารี userspace ของ libbinder
ซึ่งจะเปิดแอป
ไดรเวอร์แฟ้ม กำลังเพิ่มเมธอดสำหรับ ::android::ProcessState()
เลือกไดรเวอร์แฟ้มสำหรับ libbinder
กระบวนการของผู้ให้บริการควร
เรียกใช้เมธอดนี้ก่อนโทรไปยัง ProcessState,
IPCThreadState
หรือก่อนที่จะเรียก Binder โดยทั่วไป ถึง
ใช้ โทรออกต่อไปนี้หลังจาก main()
ของกระบวนการของผู้ให้บริการ
(ไคลเอ็นต์และเซิร์ฟเวอร์):
ProcessState::initWithDriver("/dev/vndbinder");
vndservicemanager
ก่อนหน้านี้บริการ Binder ได้ลงทะเบียนไว้กับ servicemanager
ซึ่งกระบวนการอื่นๆ จะดึงมาใช้ได้ ใน Android 8
ตอนนี้เฟรมเวิร์กและแอปใช้เฉพาะ servicemanager
เท่านั้น
กระบวนการและกระบวนการของผู้ให้บริการไม่สามารถเข้าถึงกระบวนการดังกล่าวได้อีกต่อไป
แต่ขณะนี้บริการของผู้ให้บริการสามารถใช้ vndservicemanager
ซึ่งเป็น
อินสแตนซ์ของ servicemanager
ที่ใช้ /dev/vndbinder
แทนที่จะเป็น /dev/binder
และสร้างขึ้นจากแหล่งที่มาเดียวกันกับ
servicemanager
. กระบวนการของผู้ให้บริการไม่จำเป็นต้อง
การเปลี่ยนแปลงในการคุยกับ vndservicemanager
เมื่อกระบวนการของผู้ให้บริการเปิดขึ้น
/dev/vndbinder
การค้นหาบริการจะไปที่
vndservicemanager
ไบนารี vndservicemanager
รวมอยู่ในค่าเริ่มต้นของ Android
ไฟล์ในอุปกรณ์
นโยบาย SELinux
กระบวนการของผู้ให้บริการที่ต้องการใช้ฟังก์ชันการทำงานของ Binder เพื่อสื่อสารด้วย ซึ่งกันและกันก็ต้องการสิ่งต่อไปนี้
- มีสิทธิ์เข้าถึง
/dev/vndbinder
- ผูกฮุก
{transfer, call}
เข้าvndservicemanager
binder_call(A, B)
สำหรับโดเมนผู้ให้บริการ A ที่ต้องการเรียกใช้ ลงในโดเมนผู้ให้บริการ B ผ่านอินเทอร์เฟซ Binder ของผู้ให้บริการ- สิทธิ์สำหรับบริการ
{add, find}
รายการในvndservicemanager
เพื่อให้เป็นไปตามข้อกำหนด 1 และ 2 ให้ใช้ vndbinder_use()
:
vndbinder_use(some_vendor_process_domain);
เพื่อให้เป็นไปตามข้อกำหนด 3 binder_call(A, B)
สำหรับผู้ให้บริการ
กระบวนการ A และ B ที่ต้องพูดคุยผ่านแฟ้มสามารถคงไว้และไม่
ต้องเปลี่ยนชื่อ
คุณต้องเปลี่ยนแปลงชื่อบริการเพื่อให้เป็นไปตามข้อกำหนดที่ 4 ป้ายกำกับบริการ และกฎต่างๆ จะได้รับการจัดการ
โปรดดูรายละเอียดเกี่ยวกับ SELinux โปรดดูที่ Security-Enhanced Linux ใน Android โปรดดูรายละเอียดเกี่ยวกับ SELinux ใน Android 8.0 ที่หัวข้อ SELinux สำหรับ Android 8.0
ชื่อบริการ
ก่อนหน้านี้ ผู้ให้บริการจะประมวลผลชื่อบริการที่ลงทะเบียนไว้ใน
service_contexts
ไฟล์และเพิ่มกฎที่เกี่ยวข้องสำหรับการเข้าถึง
ไฟล์นั้น ตัวอย่างไฟล์ service_contexts
จาก
device/google/marlin/sepolicy
:
AtCmdFwd u:object_r:atfwd_service:s0 cneservice u:object_r:cne_service:s0 qti.ims.connectionmanagerservice u:object_r:imscm_service:s0 rcs u:object_r:radio_service:s0 uce u:object_r:uce_service:s0 vendor.qcom.PeripheralManager u:object_r:per_mgr_service:s0
ใน Android 8 vndservicemanager
จะโหลด
vndservice_contexts
แทน บริการของผู้ให้บริการที่กำลังย้ายข้อมูลไปที่
vndservicemanager
(และอยู่ในเวอร์ชันเก่าอยู่แล้ว
service_contexts
) ควรเพิ่มลงใน
vndservice_contexts
ไฟล์
ป้ายกำกับบริการ
ก่อนหน้านี้ ป้ายกำกับบริการ เช่น u:object_r:atfwd_service:s0
ถูกกำหนดไว้ในไฟล์ service.te
ตัวอย่าง
type atfwd_service, service_manager_type;
ใน Android 8 คุณต้องเปลี่ยนประเภทเป็น
vndservice_manager_type
และย้ายกฎไปไว้ใน
vndservice.te
ตัวอย่าง
type atfwd_service, vndservice_manager_type;
กฎ Servicemanager
ก่อนหน้านี้ กฎได้ให้สิทธิ์โดเมนในการเข้าถึงเพื่อเพิ่มหรือค้นหาบริการจาก
servicemanager
ตัวอย่าง
allow atfwd atfwd_service:service_manager find; allow some_vendor_app atfwd_service:service_manager add;
ใน Android 8 กฎดังกล่าวจะยังคงเดิมและใช้คลาสเดียวกัน ตัวอย่าง
allow atfwd atfwd_service:service_manager find; allow some_vendor_app atfwd_service:service_manager add;