Google is committed to advancing racial equity for Black communities. See how.
หน้านี้ได้รับการแปลโดย Cloud Translation API
Switch to English

ใช้ Binder IPC

หน้านี้อธิบายถึงการเปลี่ยนแปลงไดรเวอร์ binder ใน Android 8 ให้รายละเอียดเกี่ยวกับการใช้ binder IPC และรายการนโยบาย SELinux ที่จำเป็น

การเปลี่ยนแปลงไดรเวอร์เครื่องผูก

ตั้งแต่ Android 8 ตอนนี้เฟรมเวิร์กของ Android และ HAL จะสื่อสารกันโดยใช้ Binder ขณะที่การสื่อสารนี้เพิ่มขึ้นอย่างรวดเร็วจราจรเครื่องผูก, Android 8 รวมถึงการปรับปรุงหลายออกแบบมาเพื่อให้เครื่องผูก IPC รวดเร็ว ผู้ให้บริการ SoC และ OEM ควรผสานโดยตรงจากสาขาที่เกี่ยวข้องของ android-4.4, android-4.9 และรุ่นที่สูงกว่าของ เคอร์เนล / โครงการ ทั่วไป

โดเมน Binder หลายโดเมน (บริบท)

Common-4.4 และสูงกว่ารวมถึงต้นน้ำ

ในการแยกทราฟฟิกของ binder อย่างหมดจดระหว่างเฟรมเวิร์ก (ไม่ขึ้นกับอุปกรณ์) และโค้ดของผู้ขาย (เฉพาะอุปกรณ์) Android 8 ได้นำเสนอแนวคิดของ บริบทตัวประสาน บริบท Binder แต่ละรายการมีโหนดอุปกรณ์ของตัวเองและตัวจัดการบริบท (บริการ) ของตัวเอง คุณสามารถเข้าถึงตัวจัดการบริบทผ่านโหนดอุปกรณ์ที่เป็นสมาชิกเท่านั้นและเมื่อส่งโหนด binder ผ่านบริบทบางอย่างจะสามารถเข้าถึงได้จากบริบทเดียวกันโดยกระบวนการอื่นเท่านั้นดังนั้นจึงแยกโดเมนออกจากกันอย่างสมบูรณ์ ดูรายละเอียดการใช้งานได้ที่ vndbinder และ vndservicemanager

กระจัดกระจาย

Common-4.4 และสูงกว่ารวมถึงต้นน้ำ

ใน Android รุ่นก่อนหน้าข้อมูลทุกชิ้นในการเรียก Binder จะถูกคัดลอกสามครั้ง:

  • หนึ่งครั้งเพื่อต่ออนุกรมลงใน Parcel ในขั้นตอนการโทร
  • เมื่ออยู่ในไดรเวอร์เคอร์เนลเพื่อคัดลอก Parcel ไปยังกระบวนการเป้าหมาย
  • หนึ่งครั้งเพื่อยกเลิกการปิดผนึก Parcel ในกระบวนการเป้าหมาย

Android 8 ใช้ การเพิ่มประสิทธิภาพการรวบรวมกระจาย เพื่อลดจำนวนสำเนาจาก 3 เป็น 1 แทนที่จะจัดลำดับข้อมูลใน Parcel ก่อนข้อมูลจะยังคงอยู่ในโครงสร้างเดิมและเค้าโครงหน่วยความจำและไดรเวอร์จะคัดลอกไปยังกระบวนการเป้าหมายทันที หลังจากข้อมูลอยู่ในกระบวนการเป้าหมายโครงสร้างและเค้าโครงหน่วยความจำจะเหมือนกันและสามารถอ่านข้อมูลได้โดยไม่ต้องใช้สำเนาอื่น

การล็อคแบบละเอียด

Common-4.4 และสูงกว่ารวมถึงต้นน้ำ

ใน Android รุ่นก่อนหน้าโปรแกรมควบคุมเครื่องผูกใช้การล็อกทั่วโลกเพื่อป้องกันการเข้าถึงโครงสร้างข้อมูลที่สำคัญพร้อมกัน แม้ว่าจะมีการโต้แย้งเล็กน้อยสำหรับการล็อก แต่ปัญหาหลักก็คือหากเธรดที่มีลำดับความสำคัญต่ำได้รับการล็อกและได้รับการป้องกันไว้ก่อนแล้วเธรดที่มีลำดับความสำคัญสูงกว่าจะล่าช้าอย่างมากซึ่งจำเป็นต้องได้รับการล็อกเดียวกัน สิ่งนี้ทำให้เกิดปัญหาในแพลตฟอร์ม

ความพยายามครั้งแรกในการแก้ไขปัญหานี้เกี่ยวข้องกับการปิดการใช้งานใบจองในขณะที่ล็อกโกลบอลล็อก อย่างไรก็ตามนี่เป็นการแฮ็กมากกว่าวิธีแก้ปัญหาที่แท้จริงและในที่สุดก็ถูกปฏิเสธโดยต้นน้ำและทิ้งไป ความพยายามในครั้งต่อมามุ่งเน้นไปที่การล็อกแบบละเอียดยิ่งขึ้นซึ่งเป็นเวอร์ชันที่ใช้งานบนอุปกรณ์ Pixel ตั้งแต่เดือนมกราคม 2017 ในขณะที่การเปลี่ยนแปลงส่วนใหญ่เปิดเผยต่อสาธารณะ แต่มีการปรับปรุงที่สำคัญในเวอร์ชันต่อ ๆ ไป

หลังจากระบุปัญหาเล็กน้อยในการใช้งานการล็อกแบบละเอียดแล้วเราได้คิดค้นโซลูชันที่ได้รับการปรับปรุงด้วยสถาปัตยกรรมการล็อกที่แตกต่างกันและส่งการเปลี่ยนแปลงในสาขาเคอร์เนลทั่วไปทั้งหมด เรายังคงทดสอบการใช้งานนี้กับอุปกรณ์ต่างๆจำนวนมาก เนื่องจากเราไม่ทราบถึงปัญหาที่ค้างคานี่คือการใช้งานที่แนะนำสำหรับอุปกรณ์ที่จัดส่งด้วย Android 8

การสืบทอดลำดับความสำคัญแบบเรียลไทม์

Common-4.4 และ common-4.9 (อัปสตรีมเร็ว ๆ นี้)

โปรแกรมควบคุมเครื่องผูกสนับสนุนการสืบทอดลำดับความสำคัญที่ดีเสมอ เนื่องจากจำนวนกระบวนการที่เพิ่มขึ้นใน Android ทำงานตามลำดับความสำคัญแบบเรียลไทม์ในบางกรณีตอนนี้จึงสมเหตุสมผลแล้วว่าหากเธรดแบบเรียลไทม์ทำการเรียกตัวประสานเธรดในกระบวนการที่จัดการการโทรนั้นจะทำงานตามลำดับความสำคัญแบบเรียลไทม์ . เพื่อรองรับกรณีการใช้งานเหล่านี้ตอนนี้ Android 8 ใช้การสืบทอดลำดับความสำคัญแบบเรียลไทม์ในโปรแกรมควบคุมเครื่องผูก

นอกเหนือจากการสืบทอดลำดับความสำคัญระดับธุรกรรมแล้วการสืบทอดลำดับความสำคัญของ โหนดยัง อนุญาตให้โหนด (วัตถุบริการ binder) ระบุลำดับความสำคัญขั้นต่ำที่ควรเรียกใช้ในโหนดนี้ Android เวอร์ชันก่อนหน้ารองรับการสืบทอดลำดับความสำคัญของโหนดที่มีค่าที่ดีอยู่แล้ว แต่ Android 8 เพิ่มการรองรับการสืบทอดโหนดของนโยบายการตั้งเวลาแบบเรียลไทม์

การเปลี่ยนแปลง Userspace

Android 8 มีการเปลี่ยนแปลงพื้นที่ผู้ใช้ทั้งหมดที่จำเป็นในการทำงานกับไดรเวอร์ตัวประสานปัจจุบันในเคอร์เนลทั่วไปโดยมีข้อยกเว้นหนึ่งข้อ: การใช้งานดั้งเดิมเพื่อปิดใช้งานการสืบทอดลำดับความสำคัญแบบเรียลไทม์สำหรับ /dev/binder ใช้ ioctl การพัฒนาในภายหลังได้เปลี่ยนการควบคุมการสืบทอดลำดับความสำคัญไปเป็นวิธีการที่ละเอียดยิ่งขึ้นซึ่งเป็นโหมดต่อ binder (ไม่ใช่ตามบริบท) ดังนั้น IOCTL ไม่ได้ใน Android สาขาทั่วไปและแทนที่จะ ส่งในเมล็ดร่วมกันของเรา

ผลของการเปลี่ยนแปลงนี้คือการสืบทอดลำดับความสำคัญแบบเรียลไทม์ถูกปิดใช้งานโดยค่าเริ่มต้นสำหรับ ทุก โหนด ทีมประสิทธิภาพ Android พบว่ามีประโยชน์ในการเปิดใช้งานการสืบทอดลำดับความสำคัญแบบเรียลไทม์สำหรับทุกโหนดในโดเมน hwbinder เพื่อให้ได้ผลเช่นเดียวกันเชอร์รี่เลือก การเปลี่ยนแปลงนี้ ใน userspace

SHAs สำหรับเมล็ดพืชทั่วไป

ในการรับการเปลี่ยนแปลงที่จำเป็นในโปรแกรมควบคุมเครื่องผูกให้ซิงค์กับ SHA ที่เหมาะสม:

  • สามัญ - 3.18
    cc8b90c121de ANDROID: binder: อย่าตรวจสอบสิทธิ์เบื้องต้นในการกู้คืน
  • สามัญ -4.4
    76b376eac7a2 ANDROID: binder: อย่าตรวจสอบสิทธิ์เบื้องต้นในการกู้คืน
  • Common-4.9
    ecd972d4f9b5 ANDROID: binder: อย่าตรวจสอบสิทธิ์เบื้องต้นในการกู้คืน

ใช้ Binder IPC

ในอดีตกระบวนการของผู้ขายได้ใช้ binder interprocess Communication (IPC) ในการสื่อสาร ใน Android 8 โหนดอุปกรณ์ /dev/binder กลายเป็นเอกสิทธิ์ของกระบวนการเฟรมเวิร์กซึ่งหมายความว่ากระบวนการของผู้ขายจะไม่สามารถเข้าถึงได้อีกต่อไป กระบวนการของผู้จัดจำหน่ายสามารถเข้าถึง /dev/hwbinder ได้ แต่ต้องแปลงอินเตอร์เฟส AIDL เพื่อใช้ HIDL สำหรับผู้ขายที่ต้องการใช้อินเทอร์เฟซ AIDL ต่อไประหว่างกระบวนการของผู้ขาย Android รองรับ binder IPC ตามที่อธิบายไว้ด้านล่าง

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 Interfaces

เพื่อให้ /dev/vndbinder ปรากฏขึ้นตรวจสอบให้แน่ใจว่ารายการคอนฟิกูเรชันเคอร์เนล CONFIG_ANDROID_BINDER_DEVICES ถูกตั้งค่าเป็น "binder,hwbinder,vndbinder" (นี่เป็นค่าเริ่มต้นในโครงสร้างเคอร์เนลทั่วไปของ Android)

โดยปกติกระบวนการของผู้ขายจะไม่เปิดโปรแกรมควบคุมเครื่องผูกโดยตรงและแทนที่จะเชื่อมโยงกับ libbinder userspace ซึ่งจะเปิดโปรแกรมควบคุมเครื่องผูก การเพิ่มวิธีการสำหรับ ::android::ProcessState() จะเลือกไดรเวอร์ binder สำหรับ libbinder กระบวนการของผู้จัดจำหน่ายควรเรียกใช้เมธอดนี้ ก่อนที่จะ เรียกเข้าสู่ ProcessState, IPCThreadState หรือก่อนทำการเรียก binder โดยทั่วไป ในการใช้งานให้วางคำเรียกต่อไปนี้ไว้หลัง main() ของกระบวนการผู้ขาย (ไคลเอนต์และเซิร์ฟเวอร์):

ProcessState::initWithDriver("/dev/vndbinder");

vndservicemanager

ก่อนหน้านี้บริการ Binder ได้รับการลงทะเบียนกับ servicemanager ซึ่งสามารถเรียกคืนได้โดยกระบวนการอื่น ๆ ใน Android 8 ตอนนี้ servicemanager ใช้เฉพาะกับเฟรมเวิร์กและกระบวนการแอพและกระบวนการของผู้ขายไม่สามารถเข้าถึงได้อีกต่อไป

อย่างไรก็ตามขณะนี้บริการของผู้ขายสามารถใช้ vndservicemanager ซึ่งเป็นอินสแตนซ์ใหม่ของ servicemanager ที่ใช้ /dev/vndbinder แทน /dev/binder และสร้างขึ้นจากแหล่งเดียวกันกับ framework servicemanager กระบวนการของผู้ขายไม่จำเป็นต้องทำการเปลี่ยนแปลงเพื่อพูดคุยกับ vndservicemanager เมื่อกระบวนการผู้ขายเปิดขึ้น / dev/vndbinder ค้นหาบริการจะไปที่ vndservicemanager โดยอัตโนมัติ

ไบนารี vndservicemanager รวมอยู่ใน makefiles ของอุปกรณ์เริ่มต้นของ Android

นโยบาย SELinux

กระบวนการของผู้ขายที่ต้องการใช้ฟังก์ชันการทำงานของสารยึดเกาะเพื่อสื่อสารกันจำเป็นต้องมีสิ่งต่อไปนี้:

  1. เข้าถึง /dev/vndbinder
  2. Binder {transfer, call} hooks into vndservicemanager .
  3. binder_call(A, B) สำหรับโดเมนผู้ขาย A ใด ๆ ที่ต้องการเรียกเข้าสู่โดเมนผู้ขาย B ผ่านอินเทอร์เฟซผู้จัดจำหน่าย
  4. สิทธิ์ในการ {add, find} บริการใน vndservicemanager

ในการปฏิบัติตามข้อกำหนด 1 และ 2 ให้ใช้ vndbinder_use() :

vndbinder_use(some_vendor_process_domain);

เพื่อให้เป็นไปตามข้อกำหนด 3 binder_call(A, B) สำหรับผู้ขายกระบวนการ A และ B ที่ต้องพูดคุยกับ Binder สามารถอยู่ในตำแหน่งได้และไม่จำเป็นต้องเปลี่ยนชื่อ

เพื่อให้เป็นไปตามข้อกำหนดที่ 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 ตัวอย่าง:

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;