Tạo luồng mô hình

Các phương thức được đánh dấu là oneway không chặn. Đối với các phương thức không được đánh dấu là oneway, lệnh gọi phương thức của ứng dụng sẽ chặn cho đến khi máy chủ hoàn tất quá trình thực thi hoặc gọi lệnh gọi lại đồng bộ (bất kỳ lệnh nào đến trước). Việc triển khai phương thức máy chủ có thể gọi tối đa một lệnh gọi lại đồng bộ; các lệnh gọi lại bổ sung sẽ bị loại bỏ và ghi lại dưới dạng lỗi. Nếu một phương thức được dự kiến sẽ trả về giá trị thông qua lệnh gọi lại và không gọi lệnh gọi lại, thì lỗi này sẽ được ghi lại dưới dạng lỗi và báo cáo dưới dạng lỗi truyền tải cho ứng dụng.

Luồng ở chế độ truyền tải

Ở chế độ truyền thẳng, hầu hết các lệnh gọi đều đồng bộ. Tuy nhiên, để duy trì hành vi dự kiến mà các lệnh gọi oneway không chặn ứng dụng, một luồng sẽ được tạo cho mỗi quy trình. Để biết thông tin chi tiết, hãy xem nội dung tổng quan về HIDL.

Luồng trong HAL liên kết

Để phân phát các lệnh gọi RPC đến (bao gồm cả lệnh gọi lại không đồng bộ từ HAL đến người dùng HAL) và thông báo về sự kiện ngừng hoạt động, một nhóm luồng được liên kết với mỗi quy trình sử dụng HIDL. Nếu một quy trình triển khai nhiều giao diện HIDL và/hoặc trình xử lý thông báo về sự kiện ngừng hoạt động, thì nhóm luồng của quy trình đó sẽ được chia sẻ giữa tất cả các giao diện và trình xử lý đó. Khi một quy trình nhận được lệnh gọi phương thức đến từ ứng dụng khách, quy trình đó sẽ chọn một luồng trống từ nhóm luồng và thực thi lệnh gọi trên luồng đó. Nếu không có luồng trống, luồng này sẽ chặn cho đến khi có luồng trống.

Nếu máy chủ chỉ có một luồng, thì các lệnh gọi đến máy chủ sẽ được hoàn tất theo thứ tự. Một máy chủ có nhiều luồng có thể hoàn tất các lệnh gọi không theo thứ tự ngay cả khi ứng dụng chỉ có một luồng. Tuy nhiên, đối với một đối tượng giao diện nhất định, các lệnh gọi oneway được đảm bảo được sắp xếp (xem Mô hình tạo luồng máy chủ). Đối với máy chủ nhiều luồng lưu trữ nhiều giao diện, các lệnh gọi oneway đến các giao diện khác nhau có thể được xử lý đồng thời với nhau hoặc các lệnh gọi chặn khác.

Nhiều lệnh gọi lồng nhau được gửi trên cùng một luồng hwbinder. Ví dụ: nếu một quy trình (A) thực hiện lệnh gọi đồng bộ từ luồng hwbinder vào quy trình (B), sau đó quy trình (B) thực hiện lệnh gọi đồng bộ trở lại quy trình (A), thì lệnh gọi này sẽ được thực thi trên luồng hwbinder ban đầu trong (A) bị chặn trên lệnh gọi ban đầu. Tính năng tối ưu hoá này cho phép một máy chủ có một luồng có thể xử lý các lệnh gọi lồng nhau, nhưng không áp dụng cho các trường hợp lệnh gọi đi qua một trình tự lệnh gọi IPC khác. Ví dụ: nếu quy trình (B) đã thực hiện lệnh gọi liên kết/vndbinder gọi vào một quy trình (C) và sau đó quy trình (C) gọi lại vào (A), thì quy trình này không thể được phân phát trên luồng ban đầu trong (A).

Mô hình tạo luồng máy chủ

Ngoại trừ chế độ chuyển tiếp, việc triển khai giao diện HIDL của máy chủ diễn ra trong một quy trình khác với ứng dụng và cần một hoặc nhiều luồng chờ lệnh gọi phương thức đến. Các luồng này là nhóm luồng của máy chủ; máy chủ có thể quyết định số lượng luồng mà máy chủ muốn chạy trong nhóm luồng và có thể sử dụng kích thước nhóm luồng là một để chuyển đổi tuần tự tất cả các lệnh gọi trên giao diện của máy chủ. Nếu máy chủ có nhiều luồng trong nhóm luồng, thì máy chủ có thể nhận các lệnh gọi đến đồng thời trên bất kỳ giao diện nào của máy chủ (trong C++, điều này có nghĩa là dữ liệu dùng chung phải được khoá cẩn thận).

Các lệnh gọi một chiều vào cùng một giao diện được chuyển đổi tuần tự. Nếu một ứng dụng nhiều luồng gọi method1method2 trên giao diện IFoomethod3 trên giao diện IBar, thì method1method2 luôn được chuyển đổi tuần tự, nhưng method3 có thể chạy song song với method1method2.

Một luồng thực thi ứng dụng có thể gây ra quá trình thực thi đồng thời trên máy chủ có nhiều luồng theo hai cách:

  • Lệnh gọi oneway không chặn. Nếu một lệnh gọi oneway được thực thi và sau đó một lệnh gọi không phải oneway được gọi, thì máy chủ có thể thực thi lệnh gọi oneway và lệnh gọi không phải oneway cùng một lúc.
  • Các phương thức máy chủ truyền dữ liệu trở lại bằng lệnh gọi lại đồng bộ có thể bỏ chặn ứng dụng ngay khi lệnh gọi lại được gọi từ máy chủ.

Đối với cách thứ hai, mọi mã trong hàm máy chủ thực thi sau khi gọi lệnh gọi lại đều có thể thực thi đồng thời, với máy chủ xử lý các lệnh gọi tiếp theo từ ứng dụng. Điều này bao gồm mã trong hàm máy chủ và các hàm huỷ tự động thực thi ở cuối hàm. Nếu máy chủ có nhiều luồng trong nhóm luồng, thì các vấn đề về đồng thời sẽ phát sinh ngay cả khi các lệnh gọi chỉ đến từ một luồng ứng dụng duy nhất. (Nếu bất kỳ HAL nào do một quy trình phân phát cần nhiều luồng, thì tất cả HAL đều có nhiều luồng vì nhóm luồng được chia sẻ cho mỗi quy trình.)

Ngay khi máy chủ gọi lệnh gọi lại được cung cấp, phương thức truyền tải có thể gọi lệnh gọi lại đã triển khai trên ứng dụng và bỏ chặn ứng dụng. Ứng dụng sẽ tiến hành song song với mọi hoạt động triển khai máy chủ sau khi gọi lệnh gọi lại (có thể bao gồm cả việc chạy hàm huỷ). Mã trong hàm máy chủ sau khi lệnh gọi lại không còn chặn ứng dụng khách (miễn là nhóm luồng máy chủ có đủ luồng để xử lý các lệnh gọi đến), nhưng có thể được thực thi đồng thời với các lệnh gọi trong tương lai từ ứng dụng khách (trừ khi nhóm luồng máy chủ chỉ có một luồng).

Ngoài lệnh gọi lại đồng bộ, các lệnh gọi oneway từ một ứng dụng đơn luồng có thể được máy chủ xử lý đồng thời với nhiều luồng trong nhóm luồng, nhưng chỉ khi các lệnh gọi oneway đó được thực thi trên các giao diện khác nhau. Các lệnh gọi oneway trên cùng một giao diện luôn được chuyển đổi tuần tự.

Lưu ý: Bạn nên trả về các hàm máy chủ ngay khi các hàm này gọi hàm gọi lại.

Ví dụ (trong C++):

Return<void> someMethod(someMethod_cb _cb) {
    // Do some processing, then call callback with return data
    hidl_vec<uint32_t> vec = ...
    _cb(vec);
    // At this point, the client's callback is called,
    // and the client resumes execution.
    ...
    return Void(); // is basically a no-op
};

Mô hình tạo luồng ứng dụng

Mô hình tạo luồng trên ứng dụng khác với các lệnh gọi không chặn (các hàm được đánh dấu bằng từ khoá oneway) và các lệnh gọi chặn (các hàm không có từ khoá oneway được chỉ định).

Chặn cuộc gọi

Đối với các lệnh gọi chặn, ứng dụng sẽ chặn cho đến khi một trong các trường hợp sau xảy ra:

  • Lỗi truyền tải xảy ra; đối tượng Return chứa trạng thái lỗi có thể được truy xuất bằng Return::isOk().
  • Quá trình triển khai máy chủ sẽ gọi lệnh gọi lại (nếu có).
  • Quá trình triển khai máy chủ sẽ trả về một giá trị (nếu không có tham số gọi lại).

Trong trường hợp thành công, hàm callback mà ứng dụng truyền dưới dạng đối số luôn được máy chủ gọi trước khi hàm đó trả về. Lệnh gọi lại được thực thi trên cùng một luồng mà lệnh gọi hàm được thực hiện, vì vậy, người triển khai phải cẩn thận khi giữ khoá trong các lệnh gọi hàm (và tránh hoàn toàn các lệnh gọi đó khi có thể). Một hàm không có câu lệnh generates hoặc từ khoá oneway vẫn đang chặn; ứng dụng sẽ chặn cho đến khi máy chủ trả về đối tượng Return<void>.

Cuộc gọi một chiều

Khi một hàm được đánh dấu là oneway, ứng dụng sẽ trả về ngay lập tức và không chờ máy chủ hoàn tất lệnh gọi hàm. Ở bề mặt (và tổng hợp), điều này có nghĩa là lệnh gọi hàm mất một nửa thời gian vì đang thực thi một nửa mã, nhưng khi viết các phương thức triển khai nhạy cảm về hiệu suất, điều này sẽ ảnh hưởng đến một số hoạt động lên lịch. Thông thường, việc sử dụng lệnh gọi một chiều sẽ khiến phương thức gọi tiếp tục được lên lịch, trong khi việc sử dụng lệnh gọi đồng bộ thông thường sẽ khiến trình lập lịch biểu chuyển ngay từ phương thức gọi sang quy trình được gọi. Đây là một tính năng tối ưu hoá hiệu suất trong trình liên kết. Đối với các dịch vụ mà lệnh gọi một chiều phải được thực thi trong quy trình mục tiêu với mức độ ưu tiên cao, bạn có thể thay đổi chính sách lên lịch của dịch vụ nhận. Trong C++, việc sử dụng phương thức setMinSchedulerPolicy của libhidltransport với các chính sách và mức độ ưu tiên của trình lập lịch biểu được xác định trong sched.h đảm bảo rằng tất cả các lệnh gọi vào dịch vụ đều chạy ít nhất ở chính sách và mức độ ưu tiên đã đặt.