ใช้ Binder IPC

หน้านี้อธิบายการเปลี่ยนแปลงไดรเวอร์ 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 เพื่อสื่อสารด้วย ซึ่งกันและกันก็ต้องการสิ่งต่อไปนี้

  1. มีสิทธิ์เข้าถึง /dev/vndbinder
  2. ผูกฮุก {transfer, call} เข้า vndservicemanager.
  3. binder_call(A, B) สำหรับโดเมนผู้ให้บริการ A ที่ต้องการเรียกใช้ ลงในโดเมนผู้ให้บริการ B ผ่านอินเทอร์เฟซ Binder ของผู้ให้บริการ
  4. สิทธิ์สำหรับบริการ {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;