穩定的 AIDL

Android 10 增加了對穩定的 Android 介面定義語言 (AIDL) 的支持,這是一種追蹤 AIDL 介面提供的應用程式介面 (API)/應用程式二進位介面 (ABI) 的新方法。穩定版 AIDL 與 AIDL 有以下主要差異:

  • 介面是在建置系統中使用aidl_interfaces定義的。
  • 介面只能包含結構化資料。表示所需類型的 Parcelable 會根據其 AIDL 定義自動創建,並自動編組和解組。
  • 介面可以聲明為穩定的(向後相容)。發生這種情況時,他們的 API 會在 AIDL 介面旁的檔案中進行追蹤和版本控制。

結構化 AIDL 與穩定 AIDL

結構化 AIDL是指純粹在 AIDL 中定義的類型。例如,parcelable 聲明(自訂 Parcelable)不是結構化 AIDL。其欄位在 AIDL 中定義的 Parcelable 稱為結構化 Parcelable

穩定的 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介面或 Parcelable,請將其名稱放在此處。這可以是名稱本身,以指涉最新版本,也可以是帶有版本後綴的名稱(例如-V1 )以指涉特定版本。從 Android 12 開始支援指定版本
  • versions :凍結在api_dir下的先前版本的接口,從 Android 11 開始, versions被凍結在aidl_api/ name下。如果介面沒有凍結版本,則不應指定這一點,並且不會進行相容性檢查。對於 13 及更高版本,此欄位已替換為versions_with_info
  • versions_with_info :元組列表,每個元組包含凍結版本的名稱以及此版本的aidl_interface導入的其他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" 。如果未設置,則對應於在此編譯上下文中具有穩定性的介面(因此此處載入的介面只能與一起編譯的內容一起使用,例如在 system.img 上)。如果將其設為"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 後端。如果不需要這三個後端中的任何一個,則需要明確地停用它。 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 中,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 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-freeze-apiapi_diraidl_api/ name下新增一個新的 API 定義(取決於 Android 版本),並新增一個.hash文件,兩者都代表介面的新凍結版本。 foo-freeze-api也會更新versions_with_info屬性以反映附加版本和該版本的imports 。基本上, versions_with_info中的imports是從imports欄位複製的。但是對於沒有明確版本的導入,最新的穩定版本是在versions_with_infoimports中指定的。一旦指定了versions_with_info屬性,建置系統就會在凍結版本之間以及樹頂 (ToT) 和最新凍結版本之間執行相容性檢查。

此外,您還需要管理ToT版本的API定義。每當更新 API 時,執行foo-update-api來更新包含 ToT 版本的 API 定義的aidl_api/ name /current

為了保持介面的穩定性,擁有者可以添加新的:

  • 介面末尾的方法(或具有明確定義的新序列的方法)
  • 位於 Parcelable 末尾的元素(需要為每個元素添加預設值)
  • 恆定值
  • 在 Android 11 中,枚舉器
  • 在 Android 12 中,聯合末尾的字段

不允許任何其他操作,並且任何其他人都不能修改介面(否則他們可能會與所有者所做的更改發生衝突)。

若要測試所有介面是否都已凍結以供發布,您可以使用以下環境變數集進行建置:

  • AIDL_FROZEN_REL=true m ... - 建置要求凍結所有未指定owner:欄位的穩定 AIDL 介面。
  • 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 時,舊客戶端和伺服器會刪除它們。當新的用戶端和伺服器收到舊的 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(AOSP 實驗版)中,引入了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 庫基於介面的未凍結版本,因此當RELEASE_AIDL_USE_UNFROZENfalse時,它的行為類似於最後一個凍結版本(版本 3),並阻止使用新方法。

當介面被凍結時, 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時,服務管理員將不允許服務註冊接口,客戶端也找不到它。

您可以根據裝置 makefile 中RELEASE_AIDL_USE_UNFROZEN標誌的值有條件地新增服務:

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

如果服務是較大進程的一部分,因此您無法有條件地將其新增至設備,則可以檢查該服務是否使用IServiceManager::isDeclared()進行宣告。如果已聲明但註冊失敗,則中止該程序。如果未聲明,則預計將無法註冊。

Cuttlefish 作為開發工具

每年,在 VINTF 凍結後,我們都會調整 Cuttlefish 的框架相容性矩陣 (FCM) target-levelPRODUCT_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是以下任一版本
    • 凍結版本的V version-number
    • V latest-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 ,引用 ToT 版本變為foo- V3 - backend

輸出檔名始終與模組名稱相同。

  • 基於版本1: foo-V1-(cpp|ndk|ndk_platform|rust).so
  • 基於版本2: foo-V2-(cpp|ndk|ndk_platform|rust).so
  • 基於ToT版本: 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以避免複製/貼上錯誤。可能需要註解@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等)在客戶端和伺服器之間共用(例如,這些類別可以位於引導類別路徑中)。當共用類別時,伺服器也會連結到最新版本的類,即使它可能是使用舊版本的介面建構的。如果此元介面在共用類別中實現,則它始終會傳回最新版本。然而,透過實作上述方法,介面的版本號被嵌入到伺服器的程式碼中(因為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包(如上所述),其中包含模組的名稱、其依賴項以及您需要的任何其他資訊。為了使其穩定(不僅僅是結構化),還需要對其進行版本控制。有關更多信息,請參閱版本控制介面