在 Android 8.0 中,Android 作業系統經過重新設計,能夠定義清楚的介面
獨立 Android 平台,以及適用於特定裝置和供應商的解決方案
再也不是件繁重乏味的工作Android 已經定義許多這類介面,格式為 HAL
介面,在 hardware/libhardware
中定義為 C 標頭。HIDL
已將這些 HAL 介面替換為穩定版本介面,
可能是 Java (如下所述) 或用戶端和伺服器端 HIDL
C++ 中的介面。
HIDL 介面主要適用於原生程式碼,且 結果 HIDL 著重於在 C++ 中自動產生有效率的程式碼。不過 您也必須能直接從 Java 使用 HIDL 介面,因為有些 Android 子系統 (例如電話通訊系統) 擁有 Java HIDL 介面。
本節的頁面會說明 HIDL 介面的 Java 前端。 詳細介紹如何建立、註冊及使用服務,並說明 HAL 與 HAL 如何 以 Java 編寫的用戶端會與 HIDL RPC 系統互動。
用戶端範例
以下是套件中介面 IFoo
的用戶端範例
android.hardware.foo@1.0
已登記為服務名稱
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 以上版本的系統或供應商應用程式,
靜態加入這些程式庫您也可以使用 (僅限) HIDL 類別
來源為安裝在裝置上且具備穩定 Java API 的自訂 JAR
針對系統應用程式,使用現有的 uses-library
機制。
後者可以節省裝置空間。詳情請參閱「實作 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 基礎程式庫和管理員程式庫
應用程式的類別路徑 (先前有時會做為隱藏 API,
Android 的委派優先類別載入器)。而是移到新的
具有 jarjar
的命名空間,以及使用這些元件的應用程式 (
應用程式) 必須各自有專屬副本。使用
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 中的架構程式碼可能需要提供介面以接收非同步 回呼。
適用於IFooCallback
android.hardware.foo
套件,您可以在
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 介面、Proxy 程式碼和虛設常式 (Proxy 和
這些虛設常式與介面相符)。
-Lmakefile
會產生在建構期間執行這個指令的規則
還能夠
android.hardware.foo-V1.0-java
並連結至
適當的檔案。可以為大量資源
自動執行上述作業的指令碼
您可以前往 hardware/interfaces/update-makefiles.sh
找到介面。
這個範例中的路徑是相對路徑;硬體/介面
程式碼樹狀結構下,讓您能先開發 HAL
發布新版本
執行服務
HAL 提供 IFoo
介面,而此介面必須設為非同步
透過 IFooCallback
介面回呼架構。
IFooCallback
介面未依名稱註冊為可搜尋
服務;相反地,IFoo
必須包含以下方法:
setFooCallback(IFooCallback x)
。
如何透過新版 1.0 版設定 IFooCallback
android.hardware.foo
套件,新增
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. }