HIDL Java

在 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 應用程式,

  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 介面、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-javaAndroid.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.
}