Trang này mô tả cách đăng ký và khám phá các dịch vụ cũng như cách gửi
đến một dịch vụ bằng cách gọi các phương thức được xác định trong giao diện ở .hal
tệp.
Đăng ký dịch vụ
Máy chủ giao diện HIDL (đối tượng triển khai giao diện) có thể được đăng ký dưới dạng dịch vụ được đặt tên. Tên đã đăng ký không cần liên quan đến giao diện hoặc tên gói. Nếu không có tên nào được chỉ định, tên là "default" được sử dụng; điều này sẽ được sử dụng cho HAL mà không cần đăng ký hai cách triển khai giống nhau . Ví dụ: lệnh gọi C++ để đăng ký dịch vụ được xác định trong mỗi là:
status_t status = myFoo->registerAsService(); status_t anotherStatus = anotherFoo->registerAsService("another_foo_service"); // if needed
Phiên bản của giao diện HIDL được đưa vào chính giao diện đó. Đó là
tự động liên kết với đăng ký dịch vụ và có thể được truy xuất thông qua
lệnh gọi phương thức (android::hardware::IInterface::getInterfaceVersion()
)
trên mọi giao diện HIDL. Các đối tượng máy chủ không cần được đăng ký và có thể được truyền
thông qua các tham số phương thức HIDL sang một quy trình khác thực hiện lệnh gọi phương thức HIDL
vào máy chủ.
Khám phá các dịch vụ
Các yêu cầu bằng mã ứng dụng khách được thực hiện cho một giao diện đã cho theo tên và theo
phiên bản, gọi getService
trên lớp HAL mong muốn:
// C++ sp<V1_1::IFooService> service = V1_1::IFooService::getService(); sp<V1_1::IFooService> alternateService = V1_1::IFooService::getService("another_foo_service"); // Java V1_1.IFooService service = V1_1.IFooService.getService(true /* retry */); V1_1.IFooService alternateService = V1_1.IFooService.getService("another", true /* retry */);
Mỗi phiên bản của giao diện HIDL được xem là một giao diện riêng biệt. Do đó,
IFooService
phiên bản 1.1 và IFooService
phiên bản 2.2
cả hai đều có thể được đăng ký là "foo_service" và
getService("foo_service")
trên một trong hai giao diện đều nhận được
cho giao diện đó. Đây là lý do tại sao trong hầu hết các trường hợp, không cần tham số tên
được cung cấp để đăng ký hoặc khám phá (có nghĩa là tên "mặc định").
Đối tượng giao diện nhà cung cấp cũng đóng một vai trò trong phương thức truyền tải của
giao diện trả về. Đối với giao diện IFoo
trong gói
android.hardware.foo@1.0
, giao diện được trả về bởi
IFoo::getService
luôn sử dụng phương thức truyền tải được khai báo cho
android.hardware.foo
trong tệp kê khai thiết bị nếu mục nhập tồn tại;
và nếu không có phương thức truyền tải, nullptr sẽ được trả về.
Trong một số trường hợp, có thể cần phải tiếp tục ngay lập tức mà không cần
nhận được dịch vụ. Điều này có thể xảy ra (chẳng hạn như) khi khách hàng muốn
tự quản lý thông báo dịch vụ hoặc trong một chương trình chẩn đoán (chẳng hạn như
atrace
) cần nhận tất cả hwservices và truy xuất chúng. Trong
trường hợp này, các API bổ sung sẽ được cung cấp, chẳng hạn như tryGetService
trong C++ hoặc
getService("instance-name", false)
trong Java. API cũ
Bạn cũng phải dùng getService
được cung cấp trong Java cùng với dịch vụ
thông báo. Việc sử dụng API này không tránh được tình trạng tương tranh, trong đó máy chủ
tự đăng ký sau khi ứng dụng yêu cầu bằng một trong các API không thử lại này.
Thông báo dịch vụ ngừng hoạt động
Khách hàng muốn nhận thông báo khi một dịch vụ bị ngừng hoạt động có thể phải chấp nhận các thông báo mà khung này gửi. Để nhận thông báo, ứng dụng phải:
- Lớp con của lớp/giao diện HIDL
hidl_death_recipient
(trong C++ chứ không phải trong HIDL). - Ghi đè phương thức
serviceDied()
. - Tạo thực thể cho một đối tượng của lớp con
hidl_death_recipient
. - Gọi phương thức
linkToDeath()
trên dịch vụ để giám sát, truyền vào đối tượng giao diện củaIDeathRecipient
. Lưu ý rằng không lấy quyền sở hữu của người nhận qua đời hoặc proxy khiến người đó qua đời sẽ được gọi.
Ví dụ về mã giả (C++ và Java tương tự nhau):
class IMyDeathReceiver : hidl_death_recipient { virtual void serviceDied(uint64_t cookie, wp<IBase>& service) override { log("RIP service %d!", cookie); // Cookie should be 42 } }; .... IMyDeathReceiver deathReceiver = new IMyDeathReceiver(); m_importantService->linkToDeath(deathReceiver, 42);
Cùng một người nhận qua đời có thể được đăng ký trên nhiều dịch vụ.
Chuyển dữ liệu
Dữ liệu có thể được gửi đến một dịch vụ bằng cách gọi các phương thức được xác định trong giao diện trong
.hal
tệp. Có hai loại phương pháp:
- Phương pháp chặn chờ cho đến khi máy chủ tạo kết quả.
- Các phương thức một chiều sẽ chỉ gửi dữ liệu theo một hướng chứ không gửi dữ liệu chặn. Nếu lượng dữ liệu đang truyền trong các lệnh gọi RPC vượt quá mức triển khai giới hạn, các lệnh gọi có thể chặn hoặc trả về chỉ báo lỗi (hành vi là chưa được xác định).
Phương thức không trả về giá trị nhưng không được khai báo là
oneway
vẫn đang chặn.
Tất cả phương thức được khai báo trong giao diện HIDL được gọi theo một hướng, từ HAL hoặc vào HAL. Giao diện không chỉ định theo hướng tên. Các cấu trúc cần lệnh gọi bắt nguồn từ HAL phải cung cấp hai (hoặc nhiều) giao diện trong gói HAL và phục vụ giao diện thích hợp trong mỗi quy trình. Những từ client và server được dùng theo hướng gọi của giao diện (tức là HAL có thể là máy chủ của một giao diện và một ứng dụng khách của một giao diện khác giao diện).
Lệnh gọi lại
Từ callback đề cập đến hai khái niệm khác nhau, được phân biệt bằng lệnh gọi lại đồng bộ và lệnh gọi lại không đồng bộ.
Lệnh gọi lại đồng bộ được dùng trong một số phương thức HIDL trả về . Phương thức HIDL trả về nhiều giá trị (hoặc trả về một giá trị của không nguyên gốc) trả về kết quả thông qua hàm callback. Nếu chỉ có một giá trị được trả về là loại nguyên gốc, hàm gọi lại không được sử dụng và giá trị được trả về từ phương thức này. Máy chủ triển khai các phương thức HIDL và ứng dụng khách triển khai các lệnh gọi lại.
Các lệnh gọi lại không đồng bộ cho phép máy chủ giao diện HIDL
thực hiện cuộc gọi. Bạn có thể thực hiện việc này bằng cách truyền một thực thể của giao diện thứ hai
thông qua giao diện đầu tiên. Ứng dụng của giao diện đầu tiên phải đóng vai trò là
máy chủ thứ hai. Máy chủ của giao diện đầu tiên có thể gọi các phương thức trên
đối tượng giao diện thứ hai. Ví dụ: việc triển khai HAL có thể gửi thông tin
quay lại không đồng bộ quy trình đang sử dụng bằng cách gọi các phương thức trên
đối tượng giao diện do quy trình đó tạo và phân phát. Phương thức trong giao diện được sử dụng
đối với lệnh gọi lại không đồng bộ có thể đang chặn (và có thể trả về giá trị cho phương thức gọi)
hoặc oneway
. Ví dụ: hãy xem phần "Lệnh gọi lại không đồng bộ" inch
HIDL C++.
Để đơn giản hoá quyền sở hữu bộ nhớ, các lệnh gọi phương thức và lệnh gọi lại chỉ mất
in
tham số và không hỗ trợ out
hoặc
Tham số inout
.
Hạn mức mỗi giao dịch
Hạn mức mỗi giao dịch không được áp dụng cho lượng dữ liệu được gửi trong HIDL
phương thức và lệnh gọi lại. Tuy nhiên, số cuộc gọi vượt quá 4KB mỗi giao dịch
bị coi là thừa. Nếu bạn thấy lỗi này, hãy thiết kế lại giao diện HIDL đã cho
. Một hạn chế khác là các tài nguyên có sẵn cho HIDL
để xử lý nhiều giao dịch đồng thời. Nhiều
các giao dịch có thể diễn ra đồng thời do có nhiều luồng hoặc
xử lý gửi cuộc gọi đến một quy trình hoặc nhiều lệnh gọi oneway
không được quy trình nhận xử lý nhanh chóng. Tổng dung lượng tối đa
có sẵn cho tất cả các giao dịch đồng thời là 1MB theo mặc định.
Trong một giao diện được thiết kế tốt, bạn không nên vượt quá những giới hạn về tài nguyên này xảy ra; nếu có, cuộc gọi vượt quá giới hạn đó có thể chặn cho đến sẵn có hoặc báo hiệu lỗi truyền tải. Mỗi lần xuất hiện của vượt quá giới hạn mỗi giao dịch hoặc làm vượt quá tài nguyên triển khai HIDL bằng cách giao dịch tổng hợp trong chuyến bay được ghi lại để hỗ trợ gỡ lỗi.
Triển khai phương thức
HIDL tạo các tệp tiêu đề khai báo các loại, phương thức và các lệnh gọi lại bằng ngôn ngữ đích (C++ hoặc Java). Nguyên mẫu của HIDL do định nghĩa các phương thức và lệnh gọi lại là giống nhau đối với cả mã ứng dụng và mã máy chủ. HIDL hệ thống cung cấp cách triển khai proxy của các phương thức trên bên gọi sắp xếp dữ liệu cho việc truyền tải IPC và mã giả lập ở phía người được gọi sẽ chuyển dữ liệu vào các hoạt động triển khai của nhà phát triển các phương thức.
Phương thức gọi của một hàm (phương thức hoặc lệnh gọi lại HiDL) có quyền sở hữu dữ liệu các cấu trúc được truyền vào hàm và giữ lại quyền sở hữu sau lệnh gọi; inch tất cả trường hợp mà người được gọi không cần giải phóng hoặc giải phóng bộ nhớ.
- Trong C++, dữ liệu có thể ở chế độ chỉ đọc (việc cố ghi vào dữ liệu có thể khiến lỗi phân đoạn) và có hiệu lực trong suốt thời gian diễn ra cuộc gọi. Khách hàng có thể sao chép sâu dữ liệu để truyền ra ngoài lệnh gọi.
- Trong Java, mã sẽ nhận được bản sao cục bộ của dữ liệu (một đối tượng Java thông thường), mà nó có thể giữ lại và sửa đổi hoặc cho phép thu thập rác.
Chuyển dữ liệu không phải RPC
HIDL có hai cách chuyển dữ liệu mà không cần sử dụng lệnh gọi RPC: dùng chung và Hàng đợi thông báo nhanh (FMQ), cả hai đều chỉ được hỗ trợ trong C++.
- Bộ nhớ dùng chung. Loại HIDL tích hợp sẵn
memory
được dùng để truyền một đối tượng đại diện cho bộ nhớ dùng chung đã được phân bổ. Có thể dùng trong quá trình nhận để liên kết bộ nhớ dùng chung. - Hàng đợi tin nhắn nhanh (FMQ). HIDL đưa ra thông báo theo mẫu
loại hàng đợi triển khai tính năng chuyển thông báo không chờ. Không sử dụng nhân hệ điều hành
hoặc trình lập lịch biểu ở chế độ truyền qua hoặc liên kết (hoạt động giao tiếp giữa các thiết bị không
có các thuộc tính này). Thông thường, HAL (Lớp trừu tượng phần cứng) thiết lập phần cuối của hàng đợi,
tạo một đối tượng có thể được truyền qua RPC thông qua một tham số tích hợp sẵn
Loại HIDL
MQDescriptorSync
hoặcMQDescriptorUnsync
. Chiến dịch này quá trình nhận có thể sử dụng đối tượng này để thiết lập đầu kia của hàng đợi.- Hàng đợi Đồng bộ hoá không được phép tràn và chỉ có thể có một hàng đợi người đọc.
- Hàng đợi Huỷ đồng bộ hoá được phép bị tràn và có thể có nhiều người đọc, mỗi thiết bị phải đọc dữ liệu kịp thời, nếu không sẽ bị mất dữ liệu.
Để biết thêm thông tin về FMQ, hãy xem Hàng đợi tin nhắn nhanh (FMQ).