穩定的 AIDL

Android 10 開始支援穩定版的 Android 介面定義語言 (AIDL),這種新方式可追蹤 AIDL 介面提供的應用程式程式介面 (API)/應用程式二進位檔介面 (ABI)。穩定版 AIDL 與 AIDL 有下列主要差異:

  • 介面是在建構系統中透過 aidl_interfaces 定義。
  • 介面只能包含結構化資料。系統會根據其 AIDL 定義自動建立代表所需類型的 Parcelable,並自動加以編組及拆解。
  • 介面可宣告為穩定版 (回溯相容)。如果發生這種情況,系統會追蹤他們的 API,並透過 AIDL 介面旁邊的檔案進行版本追蹤。

結構化與穩定版 AIDL

結構化 AIDL 是指純粹在 AIDL 中定義的類型,舉例來說,Parcelable 宣告 (自訂 parcelable) 並非結構化 AIDL。Parcelable 及其在 AIDL 中定義的欄位稱為「結構化 parcelable」

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

定義 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 介面模組的名稱,專門用於識別 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 下凍結。如果介面沒有凍結版本,請勿指定此屬性,且不會進行相容性檢查。這個欄位已由 13 及以上版本取代為 versions_with_info
  • versions_with_info:元組清單,每個元組都包含凍結版本名稱,以及此版本匯入的其他 aidl_interface 模組版本匯入清單。AIDL 介面 IFACE 版本 V 的定義位於 aidl_api/IFACE/V。這個欄位是在 Android 13 中推出,因此不應直接在 Android.bp 中修改。可叫用 *-update-api*-freeze-api 來新增或更新此欄位。此外,使用者叫用 *-update-api*-freeze-api 時,versions 欄位會自動遷移至 versions_with_info
  • stability:針對此介面穩定性承諾的選用標記。這項功能目前僅支援 "vintf"。如未設定 stability,建構系統會檢查介面是否具有回溯相容性,除非指定 unstable。未設定會對應至具有此編譯情境中穩定性的介面 (因此適用於所有系統項目、system.img 中的例項和相關分區,或所有供應商事物,例如 vendor.img 和相關分區的例項)。如果將 stability 設為 "vintf",這就會對應到穩定性保證:介面一旦使用,就必須保持穩定。
  • gen_trace:開啟或關閉追蹤功能的選用標記。自 Android 14 起,cppjava 後端的預設值為 true
  • host_supported:設為 true 時的選用標記,可將產生的程式庫提供給主機環境使用。
  • unstable:非必要的選用標記,用來標示這個介面不需要穩定。將此值設為 true 時,建構系統不會為介面建立 API 傾印,也無須更新。
  • frozen:選用標記,如果設為 true,表示介面自舊版介面沒有變更。因此可進行更多建構時間檢查。如果設為 false,表示介面仍在開發階段,並且有新的變更,因此執行 foo-freeze-api 會產生新版本,並自動將值變更為 true。相關元素已在 Android 14 中推出。
  • backend.<type>.enabled:這些旗標會切換 AIDL 編譯器為各個後端產生程式碼的後端。目前支援四個後端:Java、C++、NDK 和 Rust。Java、C++ 和 NDK 後端預設為啟用。如果不需要這三個後端中的任何一個,則必須明確停用。在 Android 15 (Android 開放原始碼計畫實驗功能) 之前,Rust 會預設為停用。
  • 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:選用標記,可指定用於指定 Java 虛設常式程式庫的 SDK 版本。預設為 "system_current"。當 backend.java.platform_apis 為 true 時,請不要設定此屬性。
  • backend.java.platform_apis:如果產生的程式庫需要根據平台 API (而非 SDK) 進行建構,應設為 true 的選用標記。

每個版本和已啟用後端的組合都會建立一個虛設常式程式庫。如要瞭解如何參照特定後端的虛設常式程式庫特定版本,請參閱模組命名規則

編寫 AIDL 檔案

穩定 AIDL 中的介面與傳統介面類似,差別在於允許使用非結構化 parcelable 時 (因為這類介面並不穩定!請參閱結構化與穩定的 AIDL)。穩定版 AIDL 的主要差異在於定義 parcelable 的方式。先前是「轉送宣告」;在穩定版 AIDL 中則是明確定義 parcelable 欄位和變數。

// 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 desire 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-凍結-api 會根據 Android 版本,在 api_diraidl_api/name 下新增 API 定義,並新增 .hash 檔案,兩者都代表新的凍結版本。foo-凍結-api 也會更新 versions_with_info 屬性,以反映其他版本和 imports 版本。基本上,versions_with_info 中的 imports 是從 imports 欄位複製。不過,在 versions_with_infoimports 中指定了匯入作業的最新穩定版本,該版本沒有明確版本。指定 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 介面在指定為「aosp」或「test」的 owner: 欄位時凍結。

匯入的穩定性

針對凍結版本的介面更新匯入版本,在 Stable 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 後端)。如果用戶端將聯集集傳送至新欄位,或從新伺服器接收聯集的舊用戶端,就會收到錯誤訊息。

旗標式開發

開發中 (未凍結) 介面無法用於發布裝置,因為無法保證能回溯相容。

AIDL 支援這些未凍結介面程式庫的執行時間備用作業,以便根據最新的未凍結版本編寫程式碼,並在發布裝置上執行。用戶端的回溯相容行為與現有行為類似,且實作也需要遵循這些行為。請參閱使用版本化介面一文。

AIDL 版本標記

控制此行為的標記是在 build/release/build_flags.bzl 中定義 RELEASE_AIDL_USE_UNFROZENtrue 表示系統會在執行階段使用介面的凍結版本,false 則代表未凍結版本的程式庫會照常運作。您可以將標記覆寫為 true 以進行本機開發,但必須在發布前將其還原為 false。一般來說,開發作業會在設定的旗標設為 true 的情況下完成。

相容性矩陣和資訊清單

供應商介面物件 (VINTF 物件) 定義預期的版本,以及供應商介面任一端提供的版本。

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

矩陣

合作夥伴擁有的介面會新增至裝置在開發期間鎖定的裝置專屬或產品專屬相容性矩陣。因此,在相容性矩陣中加入新的未凍結版本介面時,先前的凍結版本需要保留給 RELEASE_AIDL_USE_UNFROZEN=false。如要處理這個問題,您可以針對不同的 RELEASE_AIDL_USE_UNFROZEN 設定使用不同的相容性矩陣檔案,或是在單一相容性矩陣檔案中允許兩個版本,供所有設定使用。

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

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

資訊清單

在 Android 15 (Android 開放原始碼計畫實驗功能) 中,我們導入了 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 時妥善處理情況。用戶端可能會根據版本設定實作兩種不同版本的回呼,因此您無法假設用戶端會傳送最新版本,而新方法可能會傳回這個項目。這類似於 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();
  }
}

RELEASE_AIDL_USE_UNFROZENfalse 時,現有類型 (parcelableenumunion) 中的新欄位可能不存在或包含其預設值,而服務嘗試傳送的新欄位值會在程序中斷時遭到捨棄。

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

RELEASE_AIDL_USE_UNFROZENfalse 時,實作絕不會從任何用戶端收到新方法的呼叫。

請謹慎使用新的列舉工具,請僅使用其導入的版本,而不是先前版本。

一般來說,您可以透過 foo->getInterfaceVersion() 查看遠端介面正在使用哪個版本。但是,使用標記型版本管理功能時,您將實作兩個不同版本,因此您可能會想要取得目前介面的版本。方法是取得目前物件的介面版本,例如 this->getInterfaceVersion(),或 my_ver 的其他方法。詳情請參閱「查詢遠端物件的介面版本」。

新 VINTF 穩定介面

新增 AIDL 介面套件時,沒有最後一個凍結版本,因此當 RELEASE_AIDL_USE_UNFROZENfalse 時,沒有可改回的行為。請勿使用這些介面。當 RELEASE_AIDL_USE_UNFROZENfalse 時,Service Manager 不允許服務註冊介面,而用戶端找不到該介面。

您可以依據 device 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、運送 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 後端)。前者用於應用程式,後者用於平台
    • 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,稱為《服務條款》版本變為 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 編譯器不會為穩定的 AIDL 介面建立 unstable 版本模組或非版本化模組。在 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,以免發生複製/貼上錯誤)。視 javac 設定而定,可能需要註解 @SuppressWarnings("static") 才能停用警告:

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

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

這是因為產生的類別 (IFooIFoo.Stub 等) 會在用戶端和伺服器之間共用 (例如,類別可位於啟動類別路徑中)。共用類別時,即使伺服器可能是用舊版介面建構而成,伺服器也會連結至最新版的類別。如果共用類別中實作了這個中繼介面,則一律會傳回最新版本。不過,透過上述實作方法,介面版本號碼會嵌入伺服器程式碼中 (因為 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 介面中提供所有方法的預設實作方式。確保遠端實作的方法 (因為您確定遠端建構的方法是在 AIDL 介面說明中就已建構) 無需在預設 impl 類別中覆寫。

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

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

  1. 找出介面的所有依附元件。針對介面依附的各個套件,判斷套件是否已在穩定的 AIDL 中定義。如未定義,則必須轉換套件。

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

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