HIDL Java

在 Android 8.0 中,Android OS 進行了重新架構,以在獨立於設備的 Android 平台與設備和供應商特定代碼之間定義清晰的接口。 Android 已經以 HAL 接口的形式定義了許多這樣的接口,在hardware/libhardware中定義為 C 頭文件。 HIDL 將這些 HAL 接口替換為穩定的版本化接口,這些接口可以是 Java(如下所述),也可以是C++中的客戶端和服務器端 HIDL 接口。

HIDL 接口主要用於本機代碼,因此 HIDL 專注於在 C++ 中自動生成高效代碼。但是,HIDL 接口也必須可以直接從 Java 中使用,因為某些 Android 子系統(例如 Telephony)具有 Java HIDL 接口。

本節中的頁面介紹了 HIDL 接口的 Java 前端,詳細說明瞭如何創建、註冊和使用服務,並解釋了用 Java 編寫的 HAL 和 HAL 客戶端如何與 HIDL RPC 系統交互。

作為客戶

這是包android.hardware.foo@1.0中接口IFoo的客戶端示例,該接口註冊為服務名稱default和具有自定義服務名稱second_impl的附加服務。

添加庫

如果要使用它,您需要在相應的 HIDL 存根庫上添加依賴項。通常,這是一個靜態庫:

// in Android.bp
static_libs: [ "android.hardware.foo-V1.0-java", ],
// in Android.mk
LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java

如果你知道你已經引入了對這些庫的依賴,你也可以使用共享鏈接:

// in Android.bp
libs: [ "android.hardware.foo-V1.0-java", ],
// in Android.mk
LOCAL_JAVA_LIBRARIES += android.hardware.foo-V1.0-java

在 Android 10 中添加庫的其他注意事項

如果您有面向 Android 10 或更高版本的系統或供應商應用,則可以靜態包含這些庫。您還可以(僅)使用來自安裝在設備上的自定義 JAR 中的 HIDL 類,以及使用系統應用程序的現有uses-library機制提供的穩定 Java API。後一種方法節省了設備上的空間。有關更多詳細信息,請參閱實現 Java SDK 庫。對於較舊的應用程序,舊的行為會被保留。

從 Android 10 開始,這些庫的“淺層”版本也可用。這些包括有問題的類,但不包括任何依賴類。例如, android.hardware.foo-V1.0-java-shallow包含 foo 包中的類,但不包含包含所有 HIDL 基類的android.hidl.base-V1.0-java中的類接口。如果您要創建的庫已經具有可用作依賴項的首選接口的基類,則可以使用以下內容:

// in Android.bp
static_libs: [ "android.hardware.foo-V1.0-java-shallow", ],
// in Android.mk
LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java-shallow

HIDL 基礎庫和管理器庫也不再在應用的引導類路徑中可用(以前,由於 Android 的委託優先類加載器,它們有時被用作隱藏 API)。相反,它們已被移動到帶有jarjar的新命名空間中,並且使用這些的應用程序(必須是 priv 應用程序)必須有自己的單獨副本。使用 HIDL 的引導類路徑上的模塊必須使用這些 Java 庫的淺變體,並將jarjar_rules: ":framework-jarjar-rules"添加到其Android.bp以使用引導類路徑中存在的這些庫的版本。

修改 Java 源代碼

此服務只有一個版本 ( @1.0 ),因此此代碼僅檢索該版本。請參閱接口擴展以了解如何處理多個不同版本的服務。

import android.hardware.foo.V1_0.IFoo;
...
// retry to wait until the service starts up if it is in the manifest
IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
IFoo anotherServer = IFoo.getService("second_impl", true /* retry */);
server.doSomething(…);

提供服務

Java 中的框架代碼可能需要提供接口以接收來自 HAL 的異步回調。

對於android.hardware.foo包 1.0 版中的IFooCallback接口,您可以使用以下步驟在 Java 中實現您的接口:

  1. 在 HIDL 中定義您的界面。
  2. 打開/tmp/android/hardware/foo/IFooCallback.java作為參考。
  3. 為您的 Java 實現創建一個新模塊。
  4. 檢查抽像類android.hardware.foo.V1_0.IFooCallback.Stub ,然後編寫一個新類來擴展它並實現抽象方法。

查看自動生成的文件

要查看自動生成的文件,請運行:

hidl-gen -o /tmp -Ljava \
  -randroid.hardware:hardware/interfaces \
  -randroid.hidl:system/libhidl/transport android.hardware.foo@1.0

這些命令生成目錄/tmp/android/hardware/foo/1.0 。對於文件hardware/interfaces/foo/1.0/IFooCallback.hal ,這會生成文件/tmp/android/hardware/foo/1.0/IFooCallback.java ,它封裝了 Java 接口、代理代碼和存根(都是代理和存根符合接口)。

-Lmakefile生成在構建時運行此命令的規則,並允許您包含android.hardware.foo-V1.0-java並鏈接到相應的文件。可以在hardware/interfaces/update-makefiles.sh中找到為充滿接口的項目自動執行此操作的腳本。本例中的路徑是相對的; hardware/interfaces 可以是代碼樹下的臨時目錄,使您能夠在發布 HAL 之前開發它。

運行服務

HAL 提供IFoo接口,該接口必須通過IFooCallback接口對框架進行異步回調。 IFooCallback接口未按名稱註冊為可發現服務;相反, IFoo必須包含諸如setFooCallback(IFooCallback x)類的方法。

要從android.hardware.foo包的 1.0 版設置IFooCallback ,請將android.hardware.foo-V1.0-java添加到Android.mk 。運行服務的代碼是:

import android.hardware.foo.V1_0.IFoo;
import android.hardware.foo.V1_0.IFooCallback.Stub;
....
class FooCallback extends IFooCallback.Stub {
    // implement methods
}
....
// Get the service from which you will be receiving callbacks.
// This also starts the threadpool for your callback service.
IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
....
// This must be a persistent instance variable, not local,
//   to avoid premature garbage collection.
FooCallback mFooCallback = new FooCallback();
....
// Do this once to create the callback service and tell the "foo-bar" service
server.setFooCallback(mFooCallback);

接口擴展

假設給定的服務在所有設備上實現了IFoo接口,那麼在特定設備上,該服務可能會提供在接口擴展IBetterFoo中實現的附加功能,如下所示:

interface IFoo {
   ...
};

interface IBetterFoo extends IFoo {
   ...
};

調用知道擴展接口的代碼可以使用castFrom() Java 方法安全地將基本接口轉換為擴展接口:

IFoo baseService = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
IBetterFoo extendedService = IBetterFoo.castFrom(baseService);
if (extendedService != null) {
  // The service implements the extended interface.
} else {
  // The service implements only the base interface.
}