Dịch vụ và chuyển dữ liệu

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:

  1. Lớp con của lớp/giao diện HIDL hidl_death_recipient (trong C++ chứ không phải trong HIDL).
  2. Ghi đè phương thức serviceDied().
  3. Tạo thực thể cho một đối tượng của lớp con hidl_death_recipient.
  4. 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ủa IDeathRecipient. 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ừ clientserver đượ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ộ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ặc MQDescriptorUnsync. 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.
    Không có loại nào được phép chạy dưới mức (đọc từ hàng đợi trống không thành công) và mỗi loại chỉ có thể có một người viết.

Để biết thêm thông tin về FMQ, hãy xem Hàng đợi tin nhắn nhanh (FMQ).