穩定的 AIDL

Android 10 開始支援穩定版 Android 介面 定義語言 (AIDL),以全新方式追蹤應用程式計畫 AIDL 提供的介面 (API) 和應用程式二進位檔介面 (ABI) 存取 API穩定版 AIDL 的運作方式與 AIDL 完全相同,但建構系統會追蹤 介面相容性,而且您可以執行的操作都受到限制:

  • 介面是在建構系統中透過 aidl_interfaces 定義。
  • 介面只能包含結構化資料。代表 系統會根據其 AIDL 定義和偏好的類型 由系統自動打組及拆解
  • 介面可宣告為穩定版 (回溯相容)。當此情況 客戶的 API 會被追蹤並版本於 AIDL 旁的檔案中 存取 API

結構化與穩定版 AIDL

結構化 AIDL 是指純粹在 AIDL 中定義的類型,舉例來說 parcelable 宣告 (自訂 parcelable) 不是 AIDL 的結構化。Parcelable 這類物件在 AIDL 中定義的欄位稱為「結構化 parcelables」

穩定 AIDL 需要結構化 AIDL,因此建構系統和編譯器 就能瞭解對 parcelable 所做的變更是否具有回溯相容性。 不過,並非所有結構化介面都會穩定。為保持穩定 介面只能使用結構化類型,且也必須使用以下格式 版本管理功能相反地,如果核心版本 或已設定 unstable:true 時,則會使用 Kubernetes。

定義 AIDL 介面

aidl_interface 的定義如下所示:

aidl_interface {
    name: "my-aidl",
    srcs: ["srcs/aidl/**/*.aidl"],
    local_include_dir: "srcs/aidl",
    imports: ["other-aidl"],
    versions_with_info: [
        {
            version: "1",
            imports: ["other-aidl-V1"],
        },
        {
            version: "2",
            imports: ["other-aidl-V3"],
        }
    ],
    stability: "vintf",
    backend: {
        java: {
            enabled: true,
            platform_apis: true,
        },
        cpp: {
            enabled: true,
        },
        ndk: {
            enabled: true,
        },
        rust: {
            enabled: true,
        },
    },

}
  • name:可明確識別 AIDL 介面。
  • srcs:組成介面的 AIDL 來源檔案清單。路徑 對於 com.acme 套件中定義的 AIDL 類型 Foo,應位於 <base_path>/com/acme/Foo.aidl,其中 <base_path> 可以是任何目錄 與 Android.bp 所在的目錄有關。在上述範例中 <base_path>srcs/aidl
  • local_include_dir:套件名稱起始路徑。這項服務 對應於上文所述的 <base_path>
  • imports:此清單使用的 aidl_interface 模組清單。如果你任一個 AIDL 介面使用介面,或從其他可封裝的介面或 aidl_interface,請在這裡輸入名稱。這個名稱可以單獨使用 請參閱 版本,或是包含版本後置字串 (例如 -V1) 的名稱 而非特定版本指定版本自 Android 12 起,即支援指定版本
  • versions:舊版介面, 在 api_dir 之下凍結。自 Android 11 起, versions 已在 aidl_api/name 下凍結。 如果介面沒有凍結版本, 請勿指定此屬性,也不會進行相容性檢查。 這個欄位適用於 Android 的 versions_with_info 13 以及更高版本。
  • versions_with_info:元組清單,每個元組都包含 凍結版本和內含其他 aidl_interface 版本匯入的清單 模組。定義 AIDL 介面 IFACE 的 V 版本位於 aidl_api/IFACE/V。 這個欄位已在 Android 13 中推出 也不應直接在 Android.bp 中修改。這個欄位 叫用 *-update-api*-freeze-api 以新增或更新。 此外,versions 個欄位會自動遷移至 versions_with_info 當使用者叫用 *-update-api*-freeze-api 時。
  • stability:針對此介面穩定性承諾的選用標記。 這項功能僅支援 "vintf"。如果未設定 stability,版本就會是 系統會檢查介面是否具備回溯相容性 已指定 unstable。未設定會對應至 所發生的穩定性 (也就是說,所有系統因素 例如 system.img 中的事物和相關分區,或所有供應商 例如 vendor.img 中的項目和相關分區)。如果 stability 設為 "vintf",這對應穩定性承諾: 介面使用時必須保持穩定。
  • gen_trace:用於開啟或關閉追蹤的選用標記。距離開始還有 在 Android 14 中,cpp 的預設值為 truejava 後端。
  • host_supported:設定 true 時,選用標記會 可用的產生程式庫
  • unstable:用於標示這個介面不含的選用標記 您必須保持穩定如果設為 true,建構系統 建立介面的 API 傾印,也不需要更新。
  • frozen:設為 true 時選用旗標,表示介面 與舊版介面沒有差別。這樣一來, 再檢查 Vertex AI Pipelines 的建構時間如果設為 false,表示介面處於 並有新的變更內容,因此執行 foo-freeze-api 會產生一個 新版本,並將該值自動變更為 true。首次引入 Android 14。
  • backend.<type>.enabled:這些旗標會切換各個會切換後端的後端 AIDL 編譯器會產生程式碼四個後端 支援:Java、C++、NDK 和 Rust。Java、C++ 和 NDK 後端已啟用 根據預設。如果不需要這三個後端中的任何一個 遭到明確停用在 Android 之前,Rust 預設為停用 15.
  • backend.<type>.apex_available:產生的 APEX 名稱清單 虛設常式程式庫適用於
  • backend.[cpp|java].gen_log:可控制 產生額外的程式碼來收集交易相關資訊。
  • backend.[cpp|java].vndk.enabled:用來建立此介面的選用標記 為 VNDK 的一部分預設值為 false
  • backend.[cpp|ndk].additional_shared_libraries:首次引入 Android 14,此旗標會將依附元件新增至 原生資料庫此標記在 ndk_headercpp_header 方面有所幫助。
  • backend.java.sdk_version:用來指定版本的選用標記 。預設值為 "system_current"backend.java.platform_apis 時不應設定這個屬性 為 true
  • backend.java.platform_apis:應設為這個選用標記 如果產生的程式庫需要根據平台 API 進行建構,則為 true 而非 SDK

針對每個版本和啟用的後端組合,此為虛設常式 資料庫建立完成瞭解如何參照特定版本的虛設常式程式庫 請參閱模組命名規則

寫入 AIDL 檔案

穩定 AIDL 中的介面與傳統介面類似, 但是不得使用非結構化的 parcelable (因為 這些不穩定!請參閱結構化和穩定版 AIDL)。穩定的 AIDL 主要差異在於 parcelables。先前宣告 parcelable;英吋 穩定 (以及結構化) AIDL、parcelables 欄位和變數 。

// in a file like 'some/package/Thing.aidl'
package some.package;

parcelable SubThing {
    String a = "foo";
    int b;
}

支援 booleancharfloatdoublebyteintlongString。在 Android 中 12,使用者定義列舉的預設值也屬於 。如未指定預設值,則會使用 0 形式或空白值。 沒有預設值的列舉會初始化為 0 沒有零列舉值。

使用虛設常式程式庫

將虛設常式程式庫新增為模組依附元件後, 可以加入檔案以下是 建構系統 (Android.mk 也可用於舊版模組定義):

cc_... {
    name: ...,
    shared_libs: ["my-module-name-cpp"],
    ...
}
# or
java_... {
    name: ...,
    // can also be shared_libs if your preference is to load a library and share
    // it among multiple users or if you only need access to constants
    static_libs: ["my-module-name-java"],
    ...
}
# or
rust_... {
    name: ...,
    rustlibs: ["my-module-name-rust"],
    ...
}

C++ 中的範例:

#include "some/package/IFoo.h"
#include "some/package/Thing.h"
...
    // use just like traditional AIDL

Java 中的範例:

import some.package.IFoo;
import some.package.Thing;
...
    // use just like traditional AIDL

Rust 中的範例:

use aidl_interface_name::aidl::some::package::{IFoo, Thing};
...
    // use just like traditional AIDL

版本管理介面

宣告名稱為 foo 的模組也會在建構系統中建立一個目標 管理模組 API建構時,foo-凍結-apiapi_diraidl_api/name (視 Android 版本而定)。 新增 .hash 檔案,分別代表新的凍結版本 存取 APIfoo-凍結-api 也會更新 versions_with_info 屬性 反映其他版本和版本的 imports。基本上 「versions_with_info」中的「imports」是從「imports」欄位複製而來。不過 我們已在 importsversions_with_info 中指定最新的穩定版本給 則沒有明確版本 指定 versions_with_info 屬性後,建構系統會執行 凍結版本和樹狀結構頂部 (ToT) 之間的相容性檢查 以及最新的凍結版本

此外,您必須管理 ToT 版本的 API 定義。如果 API 已停止運作 已更新,只要執行 foo-update-api 即可 aidl_api/name/current 其中包含 ToT 版本的 API 定義。

為了維持介面的穩定性,擁有者可以新增下列項目:

  • 介面結尾的方法 (或明確定義新 序號)
  • parcelable 結尾的元素 (需要為每個元素新增預設值 元素)
  • 常數值
  • 在 Android 11 中,列舉
  • 在 Android 12 中,組合結尾的欄位

不得執行其他動作,也無人可以修改介面 (否則,擁有者所做的變更可能會發生衝突)。

如要測試所有介面都會凍結以進行發布,您可以使用 已設定下列環境變數:

  • AIDL_FROZEN_REL=true m ... - 建構作業需要所有穩定的 AIDL 介面才能 將遭到凍結,且未指定 owner: 欄位。
  • AIDL_FROZEN_OWNERS="aosp test" - 建構作業需要所有穩定的 AIDL 介面 將 owner: 欄位指定為「aosp」以凍結或「test」等

匯入的穩定性

以下是更新凍結介面的匯入版本 在穩定版 AIDL 層回溯相容不過,更新這些檔案時 更新所有使用舊版介面的伺服器和用戶端。 而且在混合使用不同類型的版本時,可能會感到困惑。 一般來說,針對僅限型別或常見套件而言,這很安全,因為程式碼需要 來處理 IPC 交易中的不明類型。

在 Android 平台代碼中,android.hardware.graphics.common 是最大的 查看這類版本升級的範例

使用版本化介面

介面方法

在執行階段,嘗試在舊伺服器上呼叫新方法時,新用戶端會獲得 視後端而定,可能出現錯誤或例外狀況。

  • cpp 後端可取得 ::android::UNKNOWN_TRANSACTION
  • ndk 後端可取得 STATUS_UNKNOWN_TRANSACTION
  • java 後端會取得 android.os.RemoteException,並顯示以下訊息: 未實作 API。

如要瞭解處理這類資訊的策略,請參閱: 查詢版本使用預設值

Parcelable

在 parcelables 中新增欄位時,舊的用戶端和伺服器會捨棄這些欄位。 當新用戶端和伺服器收到舊的 parcelable 時,新用戶端和新伺服器的預設值 ] 欄位就會自動填入值。也就是說,如要使用預設值 會為 parcelable 中的所有新欄位指定。

除非用戶端知道 伺服器實作了已定義該欄位的版本 (詳情請參閱 查詢版本)。

列舉和常數

同樣地,用戶端和伺服器應拒絕或忽略系統無法辨識的資料 常數值和列舉器,因為 未來的發展方向例如,伺服器收到 一些不知道的列舉值伺服器應會忽略 列舉或傳回內容,讓用戶端瞭解 實作方式

聯合工會

如果接收器老舊,且無法傳送包含新欄位的聯集, 不知道該欄位是什麼實作中絕對不會看到 新欄位。失敗時則會遭到忽略 單向交易;如果沒有,則錯誤為 BAD_VALUE(適用於 C++ 或 NDK) ) 或 IllegalArgumentException(適用於 Java 後端)。錯誤: 則會收到這個狀態。 或舊用戶端從新伺服器接收聯集時。

管理多個版本

Android 中的連接器命名空間只能有一個特定 aidl 的 1 個版本 避免產生的 aidl 類型包含多個 定義。C++ 的一個定義規則只需要一個定義 。

當模組依附於不同項目時,Android 版本就會產生錯誤 同一個 aidl_interface 程式庫的版本。模組可能取決於 開發人員可透過其依附元件 直接或間接使用這些程式庫 依附元件這些錯誤會顯示從失敗模組到 與 aidl_interface 程式庫的衝突版本所有的 依附元件需要更新,納入相同 (通常是最新版本) 的版本 一系列程式庫

如果許多不同的模組都使用這個介面程式庫, 為任何群組建立 cc_defaultsjava_defaultsrust_defaults 會需要採用相同版本的程式庫和程序。導入 您可以在新版介面中更新這些預設值,並更新所有模組 會一起更新,確保它們不會使用不同的版本 存取 API

cc_defaults {
  name: "my.aidl.my-process-group-ndk-shared",
  shared_libs: ["my.aidl-V3-ndk"],
  ...
}

cc_library {
  name: "foo",
  defaults: ["my.aidl.my-process-group-ndk-shared"],
  ...
}

cc_binary {
  name: "bar",
  defaults: ["my.aidl.my-process-group-ndk-shared"],
  ...
}

aidl_interface 模組匯入其他 aidl_interface 模組時,即可建立這個模組 需要搭配使用特定版本的其他依附元件。這個 遇到常見aidl_interface,情況可能難以應對 在多個 aidl_interface 模組中匯入的模組 在同一程序中合併多個項目

aidl_interfaces_defaults 可用於保留 可在以下位置更新的 aidl_interface 依附元件最新版本 單一位置,並用於所有要匯入的 aidl_interface 模組 擁有共通介面

aidl_interface_defaults {
  name: "android.popular.common-latest-defaults",
  imports: ["android.popular.common-V3"],
  ...
}

aidl_interface {
  name: "android.foo",
  defaults: ["my.aidl.latest-ndk-shared"],
  ...
}

aidl_interface {
  name: "android.bar",
  defaults: ["my.aidl.latest-ndk-shared"],
  ...
}

旗標式開發

您無法在發布裝置上使用開發中 (未凍結) 的介面, 無法保證能回溯相容

AIDL 支援這些未凍結的介面程式庫執行時間。 ,以便根據最新的未凍結版本編寫程式碼 。用戶端的回溯相容行為與 採用備用廣告,在導入時也需要遵循 這些行為詳情請見 使用版本化介面

AIDL 版本標記

控制此行為的標記是 RELEASE_AIDL_USE_UNFROZEN 定義於 build/release/build_flags.bzltrue 是指的未凍結版本 系統會在執行階段使用介面,false 則是指 未凍結版本的運作方式都與上次凍結版本相同。 您可將標記覆寫為 true: 本機開發作業,但在發布前必須將其還原為 false。一般價格 方法是使用將旗標設為 true 的設定完成。

相容性矩陣和資訊清單

供應商介面物件 (VINTF 物件) 定義 預期版本有哪些,以及側邊 供應商介面

大多數非 Cuttlefish 裝置都指定最新的相容性矩陣 只有在介面凍結後,AIDL 就沒有差異 以 RELEASE_AIDL_USE_UNFROZEN 為基礎的程式庫。

矩陣

新增合作夥伴擁有的介面,新增至裝置專屬或特定產品 相容性矩陣:裝置開發期間指定的相容性矩陣。所以當 新的介面未凍結版本新增至相容性矩陣 先前的凍結版本 RELEASE_AIDL_USE_UNFROZEN=false。您可以用不同的方法處理 不同RELEASE_AIDL_USE_UNFROZEN的相容性矩陣檔案 或在單一相容性矩陣檔案中允許兩種版本 使用 GCP 控制台

舉例來說,新增凍結版本 4 時,請使用 <version>3-4</version>

版本 4 凍結時,您可以從相容性矩陣中移除第 3 版 因為當 RELEASE_AIDL_USE_UNFROZEN 使用時,凍結的第 4 版 false

資訊清單

在 Android 15 中,libvintf 會導入一項變更, 並根據 RELEASE_AIDL_USE_UNFROZEN

資訊清單和資訊清單片段會宣告哪個介面版本 使用最新的未凍結版本介面時 資訊清單就必須更新以反映這個新版本。時間 RELEASE_AIDL_USE_UNFROZEN=false:資訊清單項目會受到以下調整: libvintf,以反映產生的 AIDL 程式庫中的變更。版本 已從凍結版本 N 修改為 上一個凍結版本 N - 1。因此,使用者不必管理多個 資訊清單或資訊清單片段。

HAL 用戶端變更

HAL 用戶端程式碼必須與先前支援的凍結值回溯相容 版本。如果 RELEASE_AIDL_USE_UNFROZENfalse,服務一律會顯示 例如最新的凍結版本 (例如呼叫新的未凍結版本) 方法會傳回 UNKNOWN_TRANSACTION,或者新的 parcelable 欄位包含 預設值)。Android 架構用戶端必須回溯使用 可與先前的其他版本相容 或合作夥伴自有介面的用戶端。

HAL 實作變更

HAL 開發的最大差異在於採用旗標式開發 HAL 實作項目必須能回溯相容於 凍結版本,以在 RELEASE_AIDL_USE_UNFROZENfalse 時運作。 考量到實作項目和裝置程式碼時的回溯相容性,這是一項新的做法 運動。請參閱使用版本化 介面

至於回溯相容性方面的考量,則通常相同 以及架構程式碼和供應商程式碼 您必須留意的細微差異 您實作了兩個使用相同原始碼 (目前、未凍結) 的版本 版本)。

範例:一個介面有三個凍結版本。介面上已更新 新方式。用戶端和服務已更新為使用新版本 4 資源庫。因為 V4 程式庫是以 它的行為類似於上次凍結的第 3 版 RELEASE_AIDL_USE_UNFROZENfalse,且禁止使用新方法。

介面凍結時,RELEASE_AIDL_USE_UNFROZEN 的所有值都會使用該介面 凍結版本和處理回溯相容性的程式碼可以移除。

對回呼呼叫方法時,您必須妥善處理 傳回 UNKNOWN_TRANSACTION。客戶可能導入了兩種 版本更新和回呼版本,因此您無法 假設用戶端會傳送最新版本,而新方法可能會傳回 而負責任的 AI 技術做法 有助於達成這項目標這類似於 AIDL 用戶端在回溯期間保持不變的方式 請參閱「使用版本化 介面

// Get the callback along with the version of the callback
ScopedAStatus RegisterMyCallback(const std::shared_ptr<IMyCallback>& cb) override {
    mMyCallback = cb;
    // Get the version of the callback for later when we call methods on it
    auto status = mMyCallback->getInterfaceVersion(&mMyCallbackVersion);
    return status;
}

// Example of using the callback later
void NotifyCallbackLater() {
  // From the latest frozen version (V2)
  mMyCallback->foo();
  // Call this method from the unfrozen V3 only if the callback is at least V3
  if (mMyCallbackVersion >= 3) {
    mMyCallback->bar();
  }
}

現有類型 (parcelableenumunion) 中的新欄位可能會 不存在,或在 RELEASE_AIDL_USE_UNFROZENfalse 和服務嘗試傳送的新欄位值會遭到捨棄 再去處理工作流程

在這個未凍結版本中新增的新類型無法傳送 或透過介面接收的資料

這項實作絕對不會收到來自任何用戶端的新方法呼叫 RELEASE_AIDL_USE_UNFROZENfalse

請謹慎使用新的列舉器,只處理其引進的版本。 而不是舊版本

一般而言,您可以使用 foo->getInterfaceVersion() 查看遙控器版本 介面。不過,支援標記型版本管理 因此您可能會想取得 現有介面方法很簡單,只要取得 目前物件,例如 this->getInterfaceVersion() 或其他 my_ver 方法。請參閱查詢遠端介面版本 物體 瞭解詳情

新 VINTF 穩定介面

新增 AIDL 介面套件時,沒有最新的凍結版本,因此, 沒有可改回使用 RELEASE_AIDL_USE_UNFROZEN 時的行為 false。請勿使用這些介面。RELEASE_AIDL_USE_UNFROZENfalse,服務管理工具不允許服務註冊介面 而客戶就不會找到這些資訊

您可以根據 在裝置 makefile 中的 RELEASE_AIDL_USE_UNFROZEN 標記:

ifeq ($(RELEASE_AIDL_USE_UNFROZEN),true)
PRODUCT_PACKAGES += \
    android.hardware.health.storage-service
endif

如果服務屬於大型程序,你無法將該服務新增到裝置 如果有條件,您就可以檢查服務是否已宣告 IServiceManager::isDeclared()。如果已宣告且無法註冊,則 取消程序。如未宣告,就能夠註冊失敗。

將 Cuttlefish 開發

VINTF 凍結後,每年都會調整架構相容性 矩陣 (FCM) target-level 和 Cuttlefish PRODUCT_SHIPPING_API_LEVEL 以便反映明年推出的裝置。調整後的 target-levelPRODUCT_SHIPPING_API_LEVEL確保 啟動經測試且符合明年新規定的裝置 版本。

RELEASE_AIDL_USE_UNFROZENtrue 時,Cuttlefish 是 來開發未來的 Android 版本指定明年的 Android 為目標 的 FCM 層級和 PRODUCT_SHIPPING_API_LEVEL,因為必須符合 下一版的供應商軟體要求 (VSR)。

RELEASE_AIDL_USE_UNFROZENfalse 時,Cuttlefish 是上一個 target-levelPRODUCT_SHIPPING_API_LEVEL 用於反映發布裝置。 在 Android 14 以下版本中,這項差異會是 透過不同 Git 分支版本來完成,這些分支版本不會納入到 FCM 的變更。 target-level、shipping API 級別或任何其他指定下一個目標的程式碼 版本。

模組命名規則

在 Android 11 中,每個版本的組合 後端啟用時,系統會自動建立虛設常式程式庫模組。推薦 連結到特定虛設常式程式庫模組進行連結,請不要使用 aidl_interface 模組,但虛設常式程式庫模組的名稱 ifacename-version-backend,地點

  • ifacenameaidl_interface 模組的名稱
  • version 為以下兩者之一
    • Vversion-number 適用於凍結版本
    • Vlatest-frozen-version-number + 1: 樹狀圖 (尚未凍結) 版本
  • backend 為以下兩者之一
    • java 代表 Java 後端
    • cpp 適用於 C++ 後端
    • ndkndk_platform (用於 NDK 後端)。前者用於應用程式, 後者適用於 Android 13 以下版本的平台。於 Android 13 以上版本,只能使用 ndk
    • rust 適用於 Rust 後端。

假設有一個模組名稱為 foo,最新版本為 2。 並支援 NDK 和 C++在此情況下,AIDL 會產生以下模組:

  • 根據版本 1
    • foo-V1-(java|cpp|ndk|ndk_platform|rust)
  • 以版本 2 (最新的穩定版本) 為依據
    • foo-V2-(java|cpp|ndk|ndk_platform|rust)
  • 根據 ToT 版本
    • foo-V3-(java|cpp|ndk|ndk_platform|rust)

與 Android 11 相比:

  • foo-backend,是指最新的穩定版 版本變成 foo-V2-backend
  • foo-unstable-backend,稱為 ToT 版本變成 foo-V3-backend

輸出檔案名稱一律與模組名稱相同。

  • 根據版本 1:foo-V1-(cpp|ndk|ndk_platform|rust).so
  • 根據版本 2:foo-V2-(cpp|ndk|ndk_platform|rust).so
  • 根據服務條款版本:foo-V3-(cpp|ndk|ndk_platform|rust).so

請注意,AIDL 編譯器不會建立 unstable 版本模組。 或未版本化的模組,用於穩定的 AIDL 介面 在 Android 12 中,模組名稱由 穩定的 AIDL 介面一律會包含其版本。

新增中繼介面方法

Android 10 針對 穩定的 AIDL。

查詢遠端物件的介面版本

用戶端可以查詢遠端物件的介面版本和雜湊 將傳回的值與介面值 用戶端所使用的連線

使用 cpp 後端的範例:

sp<IFoo> foo = ... // the remote object
int32_t my_ver = IFoo::VERSION;
int32_t remote_ver = foo->getInterfaceVersion();
if (remote_ver < my_ver) {
  // the remote side is using an older interface
}

std::string my_hash = IFoo::HASH;
std::string remote_hash = foo->getInterfaceHash();

使用 ndk (和 ndk_platform) 後端的範例:

IFoo* foo = ... // the remote object
int32_t my_ver = IFoo::version;
int32_t remote_ver = 0;
if (foo->getInterfaceVersion(&remote_ver).isOk() && remote_ver < my_ver) {
  // the remote side is using an older interface
}

std::string my_hash = IFoo::hash;
std::string remote_hash;
foo->getInterfaceHash(&remote_hash);

使用 java 後端的範例:

IFoo foo = ... // the remote object
int myVer = IFoo.VERSION;
int remoteVer = foo.getInterfaceVersion();
if (remoteVer < myVer) {
  // the remote side is using an older interface
}

String myHash = IFoo.HASH;
String remoteHash = foo.getInterfaceHash();

如果是 Java 語言,遠端端「必須」實作 getInterfaceVersion() 和 如下所示:getInterfaceHash() (使用 super,而不是 IFoo,藉此避免 複製及貼上錯誤註解 @SuppressWarnings("static") 可能會 視 javac 設定而定,必須停用警告:

class MyFoo extends IFoo.Stub {
    @Override
    public final int getInterfaceVersion() { return super.VERSION; }

    @Override
    public final String getInterfaceHash() { return super.HASH; }
}

這是因為產生的類別 (IFooIFoo.Stub 等) 是共用的 之間的路徑 (例如類別可位於啟動程序) classpath)。共用課程時,伺服器也會連結至 最新版的課程 介面版本如果共用中已實作這個中繼介面 類別,則一律會傳回最新版本。不過,實作這個方法時 如上所述,介面版本號碼嵌入在伺服器的程式碼中 (因為 IFoo.VERSION 是在參照時內嵌的 static final int) 因此,這個方法可傳回伺服器建構的確切版本。

處理舊版介面

用戶端可能已使用新版 AIDL 更新。 但伺服器使用的是舊版 AIDL 介面。此時 在舊介面上呼叫方法會傳回 UNKNOWN_TRANSACTION

穩定的 AIDL 能讓客戶享有更多掌控權。在用戶端中 預設實作為 AIDL 介面預設方法 只有在遠端中並未實作 方法時,才會叫用實作 (因為該版本是以舊版介面建構而成)。開始時間 均預設為全域設定,因此不應在可能共用的情況下 定義。

Android 13 以上版本的 C++ 範例:

class MyDefault : public IFooDefault {
  Status anAddedMethod(...) {
   // do something default
  }
};

// once per an interface in a process
IFoo::setDefaultImpl(::android::sp<MyDefault>::make());

foo->anAddedMethod(...); // MyDefault::anAddedMethod() will be called if the
                         // remote side is not implementing it

Java 中的範例:

IFoo.Stub.setDefaultImpl(new IFoo.Default() {
    @Override
    public xxx anAddedMethod(...)  throws RemoteException {
        // do something default
    }
}); // once per an interface in a process

foo.anAddedMethod(...);

您不需要提供 AIDL 中所有方法的預設實作方式 存取 API保證會在遠端端實作的方法 (因為您確定遠端元件的建構方式位於 AIDL 介面說明) 不需要在預設 impl 中覆寫 類別

將現有的 AIDL 轉換為結構化或穩定的 AIDL

如果您現有的 AIDL 介面和使用該介面的程式碼,請使用下列指令 將介面轉換為穩定的 AIDL 介面。

  1. 找出介面的所有依附元件。對於每個套件 介面取決於介面,會決定套件是否已在穩定的 AIDL 中定義。如果 則必須先轉換套件。

  2. 將介面中的所有 parcelable 轉換為穩定的 parcelable ( 介面檔案本身可能維持不變)。操作方法如下: 直接在 AIDL 檔案中表達結構。管理類別必須 已重寫以使用這些新類型這樣就能在建立 aidl_interface 套件 (如下所示)。

  3. 建立 aidl_interface 套件 (如上所述),其中包含 模組名稱、依附元件和所需的任何其他資訊。 為使應用程式更加穩定 (而不僅是結構化的),也需要建立版本。 詳情請參閱版本管理介面