在 Android 8.0 中,Android 作業系統進行了重新架構,以在獨立於裝置的 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 套件中的類,但不包含android.hidl.base-V1.0-java
中的類,後者包含所有 HIDL 的基類介面。如果您要建立的庫已具有可用作依賴項的首選介面的基類,則可以使用以下內容:
// 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. }