Sử dụng IPC liên kết

Trang này mô tả các thay đổi đối với trình điều khiển liên kết trong Android 8, cung cấp chi tiết về việc sử dụng IPC liên kết và liệt kê chính sách SELinux bắt buộc.

Các thay đổi đối với trình điều khiển liên kết

Kể từ Android 8, khung Android và HAL (Lớp trừu tượng phần cứng) hiện giao tiếp với với nhau bằng liên kết. Vì hoạt động giao tiếp này làm tăng đáng kể tính liên kết lưu lượng truy cập, Android 8 có một số điểm cải tiến được thiết kế để duy trì IPC liên kết một cách nhanh chóng. Nhà cung cấp hệ thống SoC (SoC) và OEM (Nhà sản xuất thiết bị gốc) nên hợp nhất trực tiếp từ các nhánh có liên quan của android-4.4, android-4.9 trở lên của kernel/common (hạt nhân/phổ biến).

Nhiều miền liên kết (ngữ cảnh)

Common-4.4 trở lên, bao gồm cả thượng nguồn

Để phân chia rõ ràng lưu lượng truy cập liên kết giữa khung (độc lập với thiết bị) và mã của nhà cung cấp (dành riêng cho thiết bị), Android 8 đưa ra khái niệm trình liên kết ngữ cảnh. Mỗi ngữ cảnh liên kết đều có nút thiết bị riêng và ngữ cảnh riêng (dịch vụ). Bạn chỉ có thể truy cập vào trình quản lý bối cảnh thông qua thiết bị này nút mà nó thuộc về và khi chuyển nút liên kết qua một nút nhất định ngữ cảnh đó, nó chỉ có thể truy cập được từ cùng một ngữ cảnh đó bởi một quy trình khác, do đó tách biệt hoàn toàn các miền với nhau. Để biết chi tiết về cách sử dụng, hãy xem vndbindervndservicemanager.

Tán xạ

Common-4.4 trở lên, bao gồm cả thượng nguồn

Trong các bản phát hành Android trước đây, mọi phần dữ liệu trong lệnh gọi liên kết đều được sao chép ba lần:

  • Để chuyển đổi tuần tự thành một Parcel trong quá trình gọi
  • Sau khi truy cập vào trình điều khiển nhân hệ điều hành, hãy sao chép Parcel vào mục tiêu quy trình
  • Một lần để huỷ chuyển đổi tuần tự Parcel trong quy trình mục tiêu

Cách sử dụng Android 8 thu thập phân tán tối ưu hoá để giảm số lượng bản sao từ 3 xuống còn 1. Thay vì chuyển đổi tuần tự dữ liệu trong Parcel trước, dữ liệu vẫn ở trạng thái ban đầu cấu trúc và bố cục bộ nhớ, đồng thời trình điều khiển ngay lập tức sao chép cấu trúc đó vào mục tiêu của chúng tôi. Sau khi dữ liệu ở trong quá trình xử lý mục tiêu, cấu trúc và bộ nhớ bố cục giống nhau và dữ liệu có thể được đọc mà không cần bản sao khác.

Khoá chi tiết nhỏ

Common-4.4 trở lên, bao gồm cả thượng nguồn

Trong các bản phát hành Android trước đây, trình điều khiển liên kết đã sử dụng một phương thức khoá chung để bảo vệ chống lại quyền truy cập đồng thời vào các cấu trúc dữ liệu quan trọng. Mặc dù có rất ít tranh chấp khoá, vấn đề chính là nếu một luồng có mức độ ưu tiên thấp lấy được khoá rồi bị giành quyền, nó có thể trì hoãn rất nghiêm trọng các luồng có mức độ ưu tiên cao hơn cần có được cùng một khoá. Điều này gây ra hiện tượng giật trong chủ.

Nỗ lực ban đầu để giải quyết sự cố này liên quan đến việc vô hiệu hoá quyền giành quyền trong khi giữ khoá chung. Tuy nhiên, đây là một giải pháp xâm nhập nhiều hơn là một giải pháp thực sự, và cuối cùng đã bị từ chối bởi thượng nguồn và bị loại bỏ. Các lần thử tiếp theo tập trung vào việc làm cho việc khoá chi tiết hơn, một phiên bản của tính năng này đang hoạt động trên thiết bị Pixel kể từ tháng 1 năm 2017. Mặc dù phần lớn những thay đổi đó được công khai, nhưng đã được cải tiến đáng kể trong các phiên bản tiếp theo.

Sau khi xác định các vấn đề nhỏ trong việc triển khai khoá chi tiết, chúng tôi đã nghĩ ra một giải pháp cải tiến với một cấu trúc khoá khác và cho rằng các thay đổi trong tất cả các nhánh hạt nhân phổ biến. Chúng tôi sẽ tiếp tục thử nghiệm triển khai trên một số lượng lớn các thiết bị khác nhau; vì chúng ta không biết về vấn đề còn tồn đọng, đây là cách triển khai được đề xuất cho việc vận chuyển thiết bị trên Android 8.

Kế thừa mức độ ưu tiên theo thời gian thực

Common-4.4 và phổ biến-4.9 (sắp ra mắt)

Trình điều khiển liên kết luôn hỗ trợ tính kế thừa mức độ ưu tiên tốt. Là một số lượng quy trình trong Android chạy ở mức độ ưu tiên theo thời gian thực tăng lên, trong một số Trong các trường hợp khác, giờ đây sẽ trở nên hợp lý khi một luồng thời gian thực thực hiện lệnh gọi liên kết, luồng trong quy trình xử lý lệnh gọi đó cũng chạy ở mức độ ưu tiên theo thời gian thực. Người nhận hỗ trợ các trường hợp sử dụng này, Android 8 nay triển khai tính năng kế thừa ưu tiên theo thời gian thực trong trình điều khiển liên kết.

Ngoài cơ chế kế thừa mức độ ưu tiên ở cấp giao dịch, mức độ ưu tiên của nút tính kế thừa cho phép một nút (đối tượng dịch vụ liên kết) chỉ định một giá trị tối thiểu mức độ ưu tiên mà tại đó các lệnh gọi đến nút này sẽ được thực thi. Các phiên bản trước của Android vốn đã hỗ trợ tính năng kế thừa mức độ ưu tiên của nút với các giá trị tốt, nhưng Android 8 bổ sung tính năng hỗ trợ kế thừa nút của chính sách lên lịch theo thời gian thực.

Thay đổi về không gian người dùng

Android 8 bao gồm tất cả các thay đổi cần thiết đối với không gian người dùng để tương thích với trình điều khiển liên kết trong nhân hệ điều hành chung với một ngoại lệ: Chương trình gốc để vô hiệu hoá tính năng kế thừa ưu tiên theo thời gian thực cho /dev/binder đã dùng một ioctl. Quá trình phát triển tiếp theo chuyển đổi điều khiển mức độ ưu tiên sang một phương thức chi tiết hơn theo chế độ liên kết (không theo ngữ cảnh). Do đó, ioctl không nằm trong nhánh chung của Android mà thay vào đó được gửi trong kernel thông thường của chúng tôi.

Ảnh hưởng của thay đổi này là tính kế thừa mức độ ưu tiên theo thời gian thực bị vô hiệu hoá mặc định cho mọi nút. Nhóm hiệu suất Android đã tìm thấy sẽ hữu ích khi bật tính năng kế thừa mức độ ưu tiên theo thời gian thực cho tất cả các nút trong phương thức hwbinder. Để đạt được hiệu quả tương tự, hãy chọn quả anh đào thay đổi này trong không gian người dùng.

SHA cho các nhân phổ biến

Để có được các thay đổi cần thiết đối với trình điều khiển liên kết, hãy đồng bộ hoá với SHA thích hợp:

  • Phổ biến-3,18
    cc8b90c121de ANDROID: binder: không kiểm tra quyền prio khi khôi phục.
  • Phổ biến-4,4
    76b376eac7a2 ANDROID: liên kết: không kiểm tra quyền prio khi khôi phục.
  • Phổ biến-4,9
    ecd972d4f9b5 ANDROID: binder: không kiểm tra quyền prio khi khôi phục.

Thao tác với IPC liên kết

Trước đây, các quy trình của nhà cung cấp sử dụng giao tiếp liên quy trình liên kết (IPC) để giao tiếp. Trong Android 8, nút thiết bị /dev/binder chỉ áp dụng cho các quy trình khung, nghĩa là quy trình của nhà cung cấp không còn sẽ có quyền truy cập vào thiết bị đó. Quy trình của nhà cung cấp có thể truy cập vào /dev/hwbinder, nhưng phải chuyển đổi giao diện AIDL để sử dụng HIDL. Dành cho những nhà cung cấp muốn tiếp tục bằng cách sử dụng giao diện AIDL giữa các quy trình của nhà cung cấp, Android hỗ trợ IPC liên kết dưới dạng được mô tả bên dưới. Trong Android 10, AIDL ổn định cho phép tất cả các quy trình để sử dụng /dev/binder, đồng thời giải quyết vấn đề ổn định đảm bảo đã giải quyết HIDL và /dev/hwbinder. Để biết cách sử dụng Kênh chính thức AIDL, xem AIDL cho HAL.

vndbinder

Android 8 hỗ trợ một miền liên kết mới để các dịch vụ của nhà cung cấp sử dụng, được truy cập vào sử dụng /dev/vndbinder thay vì /dev/binder. Với Ngoài /dev/vndbinder, Android hiện có 3 tính năng Miền IPC:

Miền IPC Mô tả
/dev/binder IPC giữa các quy trình khung/ứng dụng có giao diện AIDL
/dev/hwbinder IPC giữa các quy trình khung/nhà cung cấp với giao diện HIDL
IPC giữa các quy trình của nhà cung cấp có giao diện HIDL
/dev/vndbinder IPC giữa các quy trình của nhà cung cấp/nhà cung cấp bằng giao diện AIDL

Để /dev/vndbinder xuất hiện, hãy đảm bảo cấu hình nhân hệ điều hành mục CONFIG_ANDROID_BINDER_DEVICES được đặt thành "binder,hwbinder,vndbinder" (đây là tuỳ chọn mặc định trong cây nhân hệ điều hành chung).

Thường thì quy trình của nhà cung cấp không trực tiếp mở trình điều khiển liên kết mà thay vào đó liên kết với thư viện không gian người dùng libbinder, điều này sẽ mở ra trình điều khiển liên kết. Thêm một phương thức cho ::android::ProcessState() hãy chọn trình điều khiển liên kết cho libbinder. Quy trình của nhà cung cấp phải gọi phương thức này trước khi gọi vào ProcessState, IPCThreadState hoặc trước khi thực hiện bất kỳ lệnh gọi liên kết nào nói chung. Người nhận sử dụng, thực hiện lệnh gọi sau đây sau main() trong quy trình của nhà cung cấp (máy khách và máy chủ):

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

vndservicemanager

Trước đây, dịch vụ liên kết được đăng ký bằng servicemanager, nơi chúng có thể được truy xuất bởi các quy trình khác. Trong Android 8, servicemanager hiện được dùng riêng cho khung và ứng dụng các quy trình và quy trình của nhà cung cấp không thể truy cập vào dữ liệu đó nữa.

Tuy nhiên, các dịch vụ của nhà cung cấp hiện có thể sử dụng vndservicemanager, một thực thể của servicemanager sử dụng /dev/vndbinder thay vì /dev/binder và được tạo từ cùng các nguồn với khung servicemanager. Quy trình của nhà cung cấp không cần phải thực hiện các thay đổi để trò chuyện với vndservicemanager; khi một quy trình của nhà cung cấp mở /dev/vndbinder, tra cứu dịch vụ sẽ tự động chuyển đến vndservicemanager.

Tệp nhị phân vndservicemanager có trong mặc định của Android tệp makefile của thiết bị.

Chính sách SELinux

Những quy trình của nhà cung cấp muốn sử dụng chức năng liên kết để giao tiếp với nhau cần những thứ sau:

  1. Quyền truy cập vào /dev/vndbinder.
  2. Nối {transfer, call} móc vào vndservicemanager.
  3. binder_call(A, B) cho bất kỳ miền của nhà cung cấp A nào muốn gọi vào miền B của nhà cung cấp qua giao diện liên kết của nhà cung cấp.
  4. Quyền đối với các dịch vụ của {add, find} trong vndservicemanager.

Để đáp ứng yêu cầu 1 và 2, hãy sử dụng vndbinder_use() macro:

vndbinder_use(some_vendor_process_domain);

Để đáp ứng yêu cầu 3, binder_call(A, B) dành cho nhà cung cấp các quy trình A và B cần trao đổi qua liên kết có thể giữ nguyên mà không cần đổi tên.

Để đáp ứng yêu cầu 4, bạn phải thay đổi cách tên dịch vụ, nhãn dịch vụ và quy tắc đều được xử lý.

Để biết chi tiết về SELinux, hãy xem phần Bảo mật được tăng cường Linux trong Android. Để biết chi tiết về SELinux trong Android 8.0, hãy xem SELinux cho Android 8.0.

Tên dịch vụ

Trước đây, nhà cung cấp sẽ xử lý tên dịch vụ đã đăng ký trong một service_contexts và đã thêm các quy tắc tương ứng để truy cập tệp đó. Tệp service_contexts mẫu từ 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

Trong Android 8, vndservicemanager sẽ tải Thay vào đó, tệp vndservice_contexts. Chuyển dịch vụ của nhà cung cấp sang vndservicemanager (và những giá trị này đã thuộc phiên bản cũ service_contexts) vào tệp mới vndservice_contexts.

Nhãn dịch vụ

Trước đây, các nhãn dịch vụ như u:object_r:atfwd_service:s0 được xác định trong tệp service.te. Ví dụ:

type atfwd_service,      service_manager_type;

Trong Android 8, bạn phải thay đổi loại thành vndservice_manager_type rồi di chuyển quy tắc này sang vndservice.te. Ví dụ:

type atfwd_service,      vndservice_manager_type;

quy tắc về người quản lý dịch vụ

Trước đây, các quy tắc cấp cho miền quyền truy cập để thêm hoặc tìm dịch vụ từ servicemanager. Ví dụ:

allow atfwd atfwd_service:service_manager find;
allow some_vendor_app atfwd_service:service_manager add;

Trong Android 8, các quy tắc như vậy có thể giữ nguyên và sử dụng cùng một lớp. Ví dụ:

allow atfwd atfwd_service:service_manager find;
allow some_vendor_app atfwd_service:service_manager add;