Sử dụng Binder IPC

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

Thay đổi trình điều khiển chất kết dính

Bắt đầu từ Android 8, khung Android và HAL hiện giao tiếp với nhau bằng chất kết dính. Vì giao tiếp này làm tăng đáng kể lưu lượng kết nối nên Android 8 bao gồm một số cải tiến được thiết kế để giữ cho IPC kết nối nhanh. Các nhà cung cấp SoC và OEM 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 và cao hơn của hạt nhân/dự án chung .

Nhiều miền liên kết (bối 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 liên kết giữa khung (không phụ thuộc vào thiết bị) và mã nhà cung cấp (dành riêng cho thiết bị), Android 8 đã giới thiệu khái niệm về ngữ cảnh liên kết . Mỗi bối cảnh liên kết có nút thiết bị riêng và trình quản lý bối cảnh (dịch vụ) riêng. Bạn chỉ có thể truy cập trình quản lý bối cảnh thông qua nút thiết bị mà nó thuộc về và khi chuyển một nút liên kết qua một ngữ cảnh nhất định, nó chỉ có thể được truy cập từ cùng một ngữ cảnh đó bằng một quy trình khác, do đó cách ly hoàn toàn các miền với nhau. Chi tiết cách sử dụng xem vndbindervndservicemanager .

phân tán-tập hợp

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

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

  • Một lần để tuần tự hóa nó thành Parcel trong quá trình gọi
  • Khi ở trong trình điều khiển kernel để sao chép Parcel vào tiến trình đích
  • Một lần để hủy xác nhận Parcel trong quy trình đích

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

Khóa hạt mịn

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 khóa chung để bảo vệ chống truy cập đồng thời vào các cấu trúc dữ liệu quan trọng. Mặc dù có sự tranh chấp tối thiểu về khóa, nhưng vấn đề chính là nếu một luồng có mức độ ưu tiên thấp lấy được khóa và sau đó được ưu tiên, thì nó có thể trì hoãn nghiêm trọng các luồng có mức độ ưu tiên cao hơn cần có cùng một khóa. Điều này gây ra hiện tượng giật trên nền tảng.

Những nỗ lực ban đầu để giải quyết vấn đề này liên quan đến việc vô hiệu hóa quyền ưu tiên trong khi giữ khóa chung. Tuy nhiên, đây giống như một vụ hack hơn là một giải pháp thực sự và cuối cùng đã bị từ chối và loại bỏ. Những nỗ lực tiếp theo tập trung vào việc làm cho việc khóa trở nên chi tiết hơn, một phiên bản đã chạy 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 những cải tiến đáng kể đã được thực hiện trong các phiên bản tiếp theo.

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

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

Common-4.4 và common-4.9 (sắp có phiên bản ngược dòng)

Trình điều khiển liên kết luôn hỗ trợ kế thừa ưu tiên tốt. Do ngày càng có nhiều quy trình trong Android chạy ở mức ưu tiên theo thời gian thực, nên trong một số trường hợp, giờ đây, điều hợp lý là nếu một luồng thời gian thực thực hiện lệnh gọi liên kết thì 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. . Để hỗ trợ các trường hợp sử dụng này, Android 8 hiện triển khai 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 kế thừa ưu tiên cấp độ giao dịch, kế thừa ưu tiên nút cho phép một nút (đối tượng dịch vụ liên kết) chỉ định mức ưu tiên tối thiểu mà tại đó các lệnh gọi vào nút này sẽ được thực thi. Các phiên bản trước của Android đã hỗ trợ kế thừa mức độ ưu tiên nút với các giá trị đẹp, nhưng Android 8 bổ sung thêm hỗ trợ cho kế thừa nút chính sách lập lịch theo thời gian thực.

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

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

Tác động của thay đổi này là tính kế thừa ưu tiên theo thời gian thực bị tắt theo mặc định đối với mọi nút. Nhóm hiệu suất Android nhận thấy việc bật kế thừa ưu tiên theo thời gian thực cho tất cả các nút trong miền hwbinder sẽ mang lại lợi ích. Để đạt được hiệu ứng tương tự, hãy chọn thay đổi này trong không gian người dùng.

SHA cho các hạt nhân phổ biến

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

  • Chung-3.18
    cc8b90c121de ANDROID: chất kết dính: không kiểm tra các quyền ưu tiên khi khôi phục.
  • Chung-4.4
    76b376eac7a2 ANDROID: chất kết dính: không kiểm tra các quyền ưu tiên khi khôi phục.
  • Chung-4.9
    ecd972d4f9b5 ANDROID: chất kết dính: không kiểm tra các quyền ưu tiên khi khôi phục.

Sử dụng chất kết dính IPC

Trong lịch sử, các quy trình của nhà cung cấp đã sử dụng giao tiếp liên tiến trình liên kết (IPC) để liên lạc. Trong Android 8, nút thiết bị /dev/binder trở thành độc quyền cho các quy trình khung, nghĩa là các quy trình của nhà cung cấp không còn có quyền truy cập vào nút đó nữa. Các quy trình của nhà cung cấp có thể truy cập /dev/hwbinder nhưng phải chuyển đổi giao diện AIDL của họ để sử dụng HIDL. Đối với các nhà cung cấp muốn tiếp tục 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 như 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 đề đảm bảo tính ổn định cho HIDL và /dev/hwbinder . Để biết cách sử dụng AIDL ổn định, hãy xem AIDL cho HAL .

vndbinder

Android 8 hỗ trợ 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 bằng /dev/vndbinder thay vì /dev/binder . Với việc bổ sung /dev/vndbinder , Android hiện có 3 miền IPC sau:

Tên miền IPC Sự miêu tả
/dev/binder IPC giữa các quy trình khung/ứng dụng với 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 với giao diện HIDL
/dev/vndbinder IPC giữa các quy trình của nhà cung cấp/nhà cung cấp với Giao diện AIDL

Để /dev/vndbinder xuất hiện, hãy đảm bảo mục cấu hình kernel CONFIG_ANDROID_BINDER_DEVICES được đặt thành "binder,hwbinder,vndbinder" (đây là mặc định trong các cây kernel phổ biến của Android).

Thông thường, các 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 vùng người dùng libbinder để mở trình điều khiển liên kết. Việc thêm phương thức cho ::android::ProcessState() sẽ chọn trình điều khiển liên kết cho libbinder . Các quy trình của nhà cung cấp nên 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. Để sử dụng, hãy thực hiện lệnh gọi sau sau hàm main() của quy trình nhà cung cấp (máy khách và máy chủ):

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

vndservicemanager

Trước đây, các dịch vụ liên kết đã được đăng ký với servicemanager , nơi các quy trình khác có thể truy xuất chúng. Trong Android 8, servicemanager hiện được sử dụng độc quyền bởi các quy trình khung và ứng dụng, đồng thời các quy trình của nhà cung cấp không còn có thể truy cập vào nó 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 phiên bản mới của servicemanager sử dụng /dev/vndbinder thay vì /dev/binder và được xây dựng từ cùng một nguồn với framework servicemanager . Quy trình của nhà cung cấp không cần thực hiện thay đổi để nói chuyện với vndservicemanager ; khi quy trình của nhà cung cấp mở / dev/vndbinder , việc tra cứu dịch vụ sẽ tự động chuyển đến vndservicemanager .

Tệp nhị phân vndservicemanager được bao gồm trong tệp tạo tệp mặc định của thiết bị Android.

Chính sách SELinux

Các quy trình của nhà cung cấp muốn sử dụng chức năng liên kết để liên lạc với nhau cần có những điều sau:

  1. Truy cập vào /dev/vndbinder .
  2. Binder {transfer, call} móc vào vndservicemanager .
  3. binder_call(A, B) cho bất kỳ miền A của nhà cung cấp 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 {add, find} dịch vụ trong vndservicemanager .

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

vndbinder_use(some_vendor_process_domain);

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

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

Để biết chi tiết về SELinux, hãy xem Linux được tăng cường bảo mật 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 xử lý tên dịch vụ đã đăng ký trong tệp 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 tệp vndservice_contexts . Các dịch vụ của nhà cung cấp di chuyển sang vndservicemanager (và đã có trong tệp service_contexts cũ) nên được thêm vào tệp vndservice_contexts mới.

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;

Trên Android 8 bạn phải đổi type thành vndservice_manager_type và di chuyển Rule vào file vndservice.te . Ví dụ:

type atfwd_service,      vndservice_manager_type;

Quy tắc 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ể được 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;