在 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 中實現您的接口:
- 在 HIDL 中定義您的界面。
- 打開
/tmp/android/hardware/foo/IFooCallback.java
作為參考。 - 為您的 Java 實現創建一個新模塊。
- 檢查抽像類
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. }