HIDL Java

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

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

本節中的頁面描述了 HIDL 接口的 Java 前端,詳細介紹瞭如何創建、註冊和使用服務,並解釋了用 Java 編寫的 HAL 和 HAL 客戶端如何與 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 或更高版本,則可以靜態包含這些庫。您還可以使用從安裝了穩定的Java API在設備上定制的JAR(只)HIDL類中使用現有的可用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 基礎庫和管理器庫也不再可用於應用的啟動類路徑(以前,由於 Android 的委託優先類加載器,它們有時被用作隱藏 API)。取而代之的是,他們已經搬進了新的命名空間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 中的框架代碼可能需要提供接口以從 HAL 接收異步回調。

對於IFooCallback在1.0版接口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接口,代理代碼,和短截線(既代理和存根符合接口)。

-Lmakefile生成運行在編譯時這個命令,讓你有規則android.hardware.foo-V1.0-java ,並連接相應的文件。自動做這行全接口項目的腳本,可以發現hardware/interfaces/update-makefiles.sh 。本例中的路徑是相對的; hardware/interfaces 可以是代碼樹下的臨時目錄,使您能夠在發布 HAL 之前開發它。

運行服務

HAL提供了IFoo接口,它必須進行異步回調在框架IFooCallback接口。該IFooCallback接口叫不上名字的發現服務登記;相反, IFoo必須包含如方法setFooCallback(IFooCallback x)

要設置IFooCallback從1.0版本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.
}