AIDL ổn định

Android 10 bổ sung hỗ trợ cho Ngôn ngữ định nghĩa giao diện Android (AIDL) ổn định, một cách mới để theo dõi giao diện chương trình ứng dụng (API)/giao diện nhị phân ứng dụng (ABI) do giao diện AIDL cung cấp. AIDL ổn định có những điểm khác biệt chính sau đây so với AIDL:

  • Các giao diện được xác định trong hệ thống xây dựng với aidl_interfaces .
  • Giao diện chỉ có thể chứa dữ liệu có cấu trúc. Các bưu kiện đại diện cho các loại mong muốn sẽ được tạo tự động dựa trên định nghĩa AIDL của chúng và được tự động sắp xếp theo thứ tự và không được sắp xếp theo thứ tự.
  • Giao diện có thể được khai báo là ổn định (tương thích ngược). Khi điều này xảy ra, API của họ sẽ được theo dõi và lập phiên bản trong một tệp bên cạnh giao diện AIDL.

AIDL có cấu trúc và ổn định

AIDL có cấu trúc đề cập đến các loại được xác định hoàn toàn trong AIDL. Ví dụ: một khai báo có thể gửi được (một khai báo có thể gửi được tùy chỉnh) không có cấu trúc AIDL. Các bưu kiện có các trường được xác định trong AIDL được gọi là bưu kiện có cấu trúc .

AIDL ổn định yêu cầu AIDL có cấu trúc để hệ thống xây dựng và trình biên dịch có thể hiểu được liệu những thay đổi được thực hiện đối với các gói có thể phân chia có tương thích ngược hay không. Tuy nhiên, không phải tất cả các giao diện có cấu trúc đều ổn định. Để ổn định, giao diện chỉ được sử dụng các loại có cấu trúc và nó cũng phải sử dụng các tính năng lập phiên bản sau. Ngược lại, một giao diện sẽ không ổn định nếu hệ thống xây dựng cốt lõi được sử dụng để xây dựng nó hoặc nếu unstable:true được đặt.

Xác định giao diện AIDL

Định nghĩa của aidl_interface trông như thế này:

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 : Tên của mô-đun giao diện AIDL xác định duy nhất một giao diện AIDL.
  • srcs : Danh sách các tệp nguồn AIDL tạo nên giao diện. Đường dẫn cho loại AIDL Foo được xác định trong gói com.acme phải ở <base_path>/com/acme/Foo.aidl , trong đó <base_path> có thể là bất kỳ thư mục nào liên quan đến thư mục chứa Android.bp . Trong ví dụ trên, <base_path>srcs/aidl .
  • local_include_dir : Đường dẫn từ nơi tên gói bắt đầu. Nó tương ứng với <base_path> đã giải thích ở trên.
  • imports : Danh sách các mô-đun viện aidl_interface mà nó sử dụng. Nếu một trong các giao diện AIDL của bạn sử dụng một giao diện hoặc một giao diện có thể phân phối từ một aidl_interface khác, hãy đặt tên của nó ở đây. Đây có thể là tên riêng để chỉ phiên bản mới nhất hoặc tên có hậu tố phiên bản (chẳng hạn như -V1 ) để chỉ một phiên bản cụ thể. Việc chỉ định phiên bản đã được hỗ trợ kể từ Android 12
  • versions : Các phiên bản trước của giao diện bị đóng băng dưới api_dir , Bắt đầu từ Android 11, các versions bị đóng băng dưới aidl_api/ name . Nếu không có phiên bản cố định của giao diện thì không nên chỉ định điều này và sẽ không có kiểm tra tính tương thích. Trường này đã được thay thế bằng versions_with_info cho phiên bản 13 trở lên.
  • versions_with_info : Danh sách các bộ dữ liệu, mỗi bộ chứa tên của phiên bản cố định và danh sách nhập phiên bản của các mô-đun viện trợ_interface khác mà phiên bản viện trợ_interface này đã nhập. Định nghĩa phiên bản V của giao diện AIDL IFACE nằm ở aidl_api/ IFACE / V . Trường này đã được giới thiệu trong Android 13 và không được sửa đổi trực tiếp trong Android.bp. Trường được thêm hoặc cập nhật bằng cách gọi *-update-api hoặc *-freeze-api . Ngoài ra, các trường versions sẽ tự động được di chuyển versions_with_info khi người dùng gọi *-update-api hoặc *-freeze-api .
  • stability : Cờ tùy chọn cho lời hứa về tính ổn định của giao diện này. Hiện tại chỉ hỗ trợ "vintf" . Nếu bạn không đặt tùy chọn này, thì tùy chọn này tương ứng với một giao diện có độ ổn định trong ngữ cảnh biên dịch này (vì vậy, giao diện được tải ở đây chỉ có thể được sử dụng với những thứ được biên dịch cùng nhau, ví dụ như trên system.img). Nếu giá trị này được đặt thành "vintf" , điều này tương ứng với lời hứa về tính ổn định: giao diện phải được giữ ổn định miễn là nó được sử dụng.
  • gen_trace : Cờ tùy chọn để bật hoặc tắt tính năng theo dõi. Bắt đầu từ Android 14, mặc định này true dụng cho các chương trình phụ trợ cppjava .
  • host_supported : Cờ tùy chọn khi được đặt thành true sẽ làm cho các thư viện được tạo có sẵn cho môi trường máy chủ.
  • unstable : Cờ tùy chọn được sử dụng để đánh dấu rằng giao diện này không cần phải ổn định. Khi điều này được đặt thành true , hệ thống xây dựng sẽ không tạo kết xuất API cho giao diện cũng như không yêu cầu cập nhật giao diện đó.
  • frozen : Cờ tùy chọn khi được đặt thành true có nghĩa là giao diện không có thay đổi nào kể từ phiên bản giao diện trước đó. Điều này cho phép kiểm tra thời gian xây dựng nhiều hơn. Khi được đặt thành false điều này có nghĩa là giao diện đang được phát triển và có những thay đổi mới nên việc chạy foo-freeze-api sẽ tạo ra một phiên bản mới và tự động thay đổi giá trị thành true . Được giới thiệu trong Android 14.
  • backend.<type>.enabled : Các cờ này chuyển đổi từng phần phụ trợ mà trình biên dịch AIDL tạo mã cho. Hiện tại, bốn chương trình phụ trợ được hỗ trợ: Java, C++, NDK và Rust. Các chương trình phụ trợ Java, C++ và NDK được bật theo mặc định. Nếu bất kỳ chương trình phụ trợ nào trong số ba chương trình phụ trợ này không cần thiết thì nó cần phải được tắt một cách rõ ràng. Rust bị tắt theo mặc định.
  • backend.<type>.apex_available : Danh sách tên APEX mà thư viện sơ khai được tạo có sẵn.
  • backend.[cpp|java].gen_log : Cờ tùy chọn kiểm soát xem có tạo mã bổ sung để thu thập thông tin về giao dịch hay không.
  • backend.[cpp|java].vndk.enabled : Cờ tùy chọn để biến giao diện này thành một phần của VNDK. Mặc định là false .
  • backend.[cpp|ndk].additional_shared_libraries : Được giới thiệu trong Android 14, cờ này bổ sung các phần phụ thuộc vào thư viện gốc. Cờ này hữu ích với ndk_headercpp_header .
  • backend.java.sdk_version : Cờ tùy chọn để chỉ định phiên bản SDK mà thư viện sơ khai Java được xây dựng dựa trên đó. Mặc định là "system_current" . Không nên đặt giá trị này khi backend.java.platform_apis là đúng.
  • backend.java.platform_apis : Cờ tùy chọn phải được đặt thành true khi thư viện được tạo cần xây dựng dựa trên API nền tảng thay vì SDK.

Đối với mỗi sự kết hợp của các phiên bản và phần phụ trợ được kích hoạt, một thư viện sơ khai sẽ được tạo. Để biết cách tham khảo phiên bản cụ thể của thư viện sơ khai cho một chương trình phụ trợ cụ thể, hãy xem Quy tắc đặt tên mô-đun .

Viết tập tin AIDL

Các giao diện trong AIDL ổn định tương tự như các giao diện truyền thống, ngoại trừ việc chúng không được phép sử dụng các bưu kiện không có cấu trúc (vì những giao diện này không ổn định! hãy xem AIDL có cấu trúc so với ổn định ). Sự khác biệt chính trong AIDL ổn định là cách xác định các bưu kiện. Trước đây, bưu kiện được khai báo chuyển tiếp ; trong AIDL ổn định (và do đó có cấu trúc), các trường và biến có thể phân chia được xác định rõ ràng.

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

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

Một giá trị mặc định hiện được hỗ trợ (nhưng không bắt buộc) cho boolean , char , float , double , byte , int , longString . Trong Android 12, các giá trị mặc định cho bảng liệt kê do người dùng xác định cũng được hỗ trợ. Khi giá trị mặc định không được chỉ định, giá trị giống 0 hoặc giá trị trống sẽ được sử dụng. Các bảng liệt kê không có giá trị mặc định được khởi tạo bằng 0 ngay cả khi không có bộ liệt kê bằng 0.

Sử dụng thư viện sơ khai

Sau khi thêm các thư viện sơ khai làm phần phụ thuộc vào mô-đun của bạn, bạn có thể đưa chúng vào tệp của mình. Dưới đây là ví dụ về các thư viện sơ khai trong hệ thống xây dựng ( Android.mk cũng có thể được sử dụng cho các định nghĩa mô-đun cũ):

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"],
    ...
}

Ví dụ trong C++:

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

Ví dụ trong Java:

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

Ví dụ ở Rust:

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

Giao diện phiên bản

Việc khai báo một mô-đun có tên foo cũng tạo ra một mục tiêu trong hệ thống xây dựng mà bạn có thể sử dụng để quản lý API của mô-đun. Khi được xây dựng, foo-freeze-api thêm định nghĩa API mới dưới api_dir hoặc aidl_api/ name , tùy thuộc vào phiên bản Android và thêm tệp .hash , cả hai đều đại diện cho phiên bản giao diện mới được cố định. foo-freeze-api cũng cập nhật thuộc versions_with_info để phản ánh phiên bản bổ sung và imports cho phiên bản đó. Về cơ bản, imports trong versions_with_info được sao chép từ trường imports . Nhưng phiên bản ổn định mới nhất được chỉ định trong imports versions_with_info cho lần nhập không có phiên bản rõ ràng. Sau khi chỉ định thuộc versions_with_info , hệ thống xây dựng sẽ chạy kiểm tra tính tương thích giữa các phiên bản cố định cũng như giữa Top of Tree (ToT) và phiên bản cố định mới nhất.

Ngoài ra, bạn cần quản lý định nghĩa API của phiên bản ToT. Bất cứ khi nào API được cập nhật, hãy chạy foo-update-api để cập nhật aidl_api/ name /current chứa định nghĩa API của phiên bản ToT.

Để duy trì sự ổn định của giao diện, chủ sở hữu có thể thêm mới:

  • Các phương thức ở cuối giao diện (hoặc các phương thức có các chuỗi mới được xác định rõ ràng)
  • Các phần tử ở cuối phần tử có thể gửi được (yêu cầu thêm giá trị mặc định cho mỗi phần tử)
  • Giá trị không đổi
  • Trong Android 11, điều tra viên
  • Trong Android 12, các trường ở cuối liên kết

Không có hành động nào khác được phép và không ai khác có thể sửa đổi giao diện (nếu không họ có nguy cơ xung đột với những thay đổi mà chủ sở hữu thực hiện).

Để kiểm tra xem tất cả các giao diện đã được đóng băng để phát hành hay chưa, bạn có thể xây dựng với bộ biến môi trường sau:

  • AIDL_FROZEN_REL=true m ... - bản dựng yêu cầu đóng băng tất cả các giao diện AIDL ổn định không có owner: trường được chỉ định.
  • AIDL_FROZEN_OWNERS="aosp test" - bản dựng yêu cầu tất cả các giao diện AIDL ổn định phải được đóng băng với owner: trường được chỉ định là "aosp" hoặc "test".

Sự ổn định của nhập khẩu

Việc cập nhật các phiên bản nhập cho phiên bản cố định của giao diện tương thích ngược ở lớp AIDL ổn định. Tuy nhiên, việc cập nhật những thứ này yêu cầu cập nhật tất cả các máy chủ và máy khách sử dụng phiên bản giao diện cũ và một số ứng dụng có thể bị nhầm lẫn khi trộn các phiên bản khác nhau của các loại. Nói chung, đối với các gói chỉ có loại hoặc gói phổ biến, điều này an toàn vì mã cần phải được viết sẵn để xử lý các loại không xác định từ giao dịch IPC.

Trong mã nền tảng Android android.hardware.graphics.common là ví dụ lớn nhất về kiểu nâng cấp phiên bản này.

Sử dụng giao diện được phiên bản

Phương thức giao diện

Trong thời gian chạy, khi cố gắng gọi các phương thức mới trên máy chủ cũ, các máy khách mới sẽ gặp lỗi hoặc ngoại lệ, tùy thuộc vào chương trình phụ trợ.

  • chương trình phụ trợ cpp nhận được ::android::UNKNOWN_TRANSACTION .
  • phụ trợ ndk nhận STATUS_UNKNOWN_TRANSACTION .
  • chương trình phụ trợ java nhận được android.os.RemoteException với thông báo cho biết API không được triển khai.

Để biết các chiến lược xử lý vấn đề này, hãy xem các phiên bản truy vấnsử dụng giá trị mặc định .

bưu kiện

Khi các trường mới được thêm vào các gói có thể gửi được, các máy khách và máy chủ cũ sẽ loại bỏ chúng. Khi máy khách và máy chủ mới nhận được các bưu kiện cũ, các giá trị mặc định cho các trường mới sẽ tự động được điền vào. Điều này có nghĩa là các giá trị mặc định cần phải được chỉ định cho tất cả các trường mới trong một bưu kiện.

Khách hàng không nên mong đợi máy chủ sử dụng các trường mới trừ khi họ biết máy chủ đang triển khai phiên bản có trường được xác định (xem phiên bản truy vấn ).

Enum và hằng

Tương tự, máy khách và máy chủ nên từ chối hoặc bỏ qua các giá trị hằng số và bộ liệt kê không được công nhận nếu phù hợp, vì có thể thêm nhiều giá trị khác trong tương lai. Ví dụ: máy chủ không nên hủy bỏ khi nhận được một điều tra viên mà nó không biết. Nó nên bỏ qua nó hoặc trả lại một cái gì đó để khách hàng biết nó không được hỗ trợ trong quá trình triển khai này.

Công đoàn

Việc cố gắng gửi liên kết với một trường mới không thành công nếu người nhận đã cũ và không biết về trường đó. Việc thực hiện sẽ không bao giờ thấy sự kết hợp với lĩnh vực mới. Lỗi này sẽ bị bỏ qua nếu đó là giao dịch một chiều; nếu không thì lỗi là BAD_VALUE (đối với chương trình phụ trợ C++ hoặc NDK) hoặc IllegalArgumentException (đối với chương trình phụ trợ Java). Lỗi được nhận nếu máy khách đang gửi tập hợp liên kết đến trường mới tới máy chủ cũ hoặc khi đó là máy khách cũ nhận liên kết từ máy chủ mới.

Phát triển dựa trên cờ

Không thể sử dụng giao diện đang phát triển (không đóng băng) trên các thiết bị phát hành vì chúng không được đảm bảo tương thích ngược.

AIDL hỗ trợ dự phòng thời gian chạy cho các thư viện giao diện chưa đóng băng này để mã được viết dựa trên phiên bản chưa đóng băng mới nhất và vẫn được sử dụng trên các thiết bị đã phát hành. Hành vi tương thích ngược của máy khách tương tự như hành vi hiện có và với phương án dự phòng, việc triển khai cũng cần tuân theo những hành vi đó. Xem Sử dụng giao diện được phiên bản .

Cờ xây dựng AIDL

Cờ kiểm soát hành vi này là RELEASE_AIDL_USE_UNFROZEN được xác định trong build/release/build_flags.bzl . true có nghĩa là phiên bản không đóng băng của giao diện được sử dụng trong thời gian chạy và false nghĩa là tất cả các thư viện của các phiên bản không đóng băng đều hoạt động giống như phiên bản đóng băng cuối cùng của chúng. Bạn có thể ghi đè cờ thành true để phát triển cục bộ nhưng phải hoàn nguyên thành false trước khi phát hành. Thông thường, quá trình phát triển được thực hiện với cấu hình có cờ được đặt thành true .

Ma trận tương thích và bảng kê khai

Các đối tượng giao diện nhà cung cấp (đối tượng VINTF) xác định phiên bản nào được mong đợi và phiên bản nào được cung cấp ở hai bên giao diện nhà cung cấp.

Hầu hết các thiết bị không phải Mực nang chỉ nhắm mục tiêu ma trận tương thích mới nhất sau khi các giao diện bị đóng băng, do đó không có sự khác biệt nào trong các thư viện AIDL dựa trên RELEASE_AIDL_USE_UNFROZEN .

Ma trận

Giao diện do đối tác sở hữu được thêm vào ma trận tương thích dành riêng cho thiết bị hoặc sản phẩm cụ thể mà thiết bị nhắm tới trong quá trình phát triển. Vì vậy, khi một phiên bản mới, chưa đóng băng của giao diện được thêm vào ma trận tương thích, các phiên bản đã đóng băng trước đó cần được giữ nguyên RELEASE_AIDL_USE_UNFROZEN=false . Bạn có thể xử lý vấn đề này bằng cách sử dụng các tệp ma trận tương thích khác nhau cho các cấu hình RELEASE_AIDL_USE_UNFROZEN khác nhau hoặc cho phép cả hai phiên bản trong một tệp ma trận tương thích duy nhất được sử dụng trong tất cả các cấu hình.

Ví dụ: khi thêm phiên bản 4 chưa đóng băng, hãy sử dụng <version>3-4</version> .

Khi phiên bản 4 bị treo, bạn có thể xóa phiên bản 3 khỏi ma trận tương thích vì phiên bản 4 bị treo được sử dụng khi RELEASE_AIDL_USE_UNFROZENfalse .

Bản kê khai

Trong Android 15 (thử nghiệm AOSP), một thay đổi trong libvintf được đưa ra để sửa đổi các tệp kê khai tại thời điểm xây dựng dựa trên giá trị của RELEASE_AIDL_USE_UNFROZEN .

Tệp kê khai và các đoạn tệp kê khai khai báo phiên bản giao diện nào mà dịch vụ triển khai. Khi sử dụng phiên bản không cố định mới nhất của giao diện, tệp kê khai phải được cập nhật để phản ánh phiên bản mới này. Khi RELEASE_AIDL_USE_UNFROZEN=false các mục kê khai được điều chỉnh bởi libvintf để phản ánh sự thay đổi trong thư viện AIDL được tạo. Phiên bản được sửa đổi từ phiên bản không đóng băng N , thành phiên bản đóng băng cuối cùng N - 1 . Do đó, người dùng không cần quản lý nhiều tệp kê khai hoặc phân đoạn tệp kê khai cho từng dịch vụ của mình.

Thay đổi ứng dụng khách HAL

Mã máy khách HAL phải tương thích ngược với từng phiên bản cố định được hỗ trợ trước đó. Khi RELEASE_AIDL_USE_UNFROZEN false , các dịch vụ luôn trông giống như phiên bản cố định cuối cùng hoặc phiên bản cũ hơn (ví dụ: gọi các phương thức không đóng băng mới sẽ trả về UNKNOWN_TRANSACTION hoặc các trường parcelable mới có giá trị mặc định). Ứng dụng khách khung Android bắt buộc phải tương thích ngược với các phiên bản bổ sung trước đó, nhưng đây là một chi tiết mới dành cho khách hàng của nhà cung cấp và khách hàng của giao diện do đối tác sở hữu.

Thay đổi triển khai HAL

Sự khác biệt lớn nhất trong quá trình phát triển HAL với phát triển dựa trên cờ là yêu cầu triển khai HAL phải tương thích ngược với phiên bản cố định cuối cùng để hoạt động khi RELEASE_AIDL_USE_UNFROZENfalse . Xem xét khả năng tương thích ngược trong triển khai và mã thiết bị là một bài tập mới. Xem Sử dụng giao diện được phiên bản .

Các cân nhắc về khả năng tương thích ngược nhìn chung giống nhau đối với máy khách và máy chủ cũng như đối với mã khung và mã nhà cung cấp, nhưng có những khác biệt nhỏ mà bạn cần lưu ý vì hiện tại bạn đang triển khai hiệu quả hai phiên bản sử dụng cùng một mã nguồn (phiên bản hiện tại chưa đóng băng).

Ví dụ: Một giao diện có ba phiên bản cố định. Giao diện được cập nhật với một phương pháp mới. Cả máy khách và dịch vụ đều được cập nhật để sử dụng thư viện phiên bản 4 mới. Vì thư viện V4 dựa trên phiên bản giao diện không đóng băng nên nó hoạt động giống như phiên bản đóng băng cuối cùng, phiên bản 3, khi RELEASE_AIDL_USE_UNFROZENfalse và ngăn việc sử dụng phương thức mới.

Khi giao diện bị đóng băng, tất cả các giá trị của RELEASE_AIDL_USE_UNFROZEN đều sử dụng phiên bản bị đóng băng đó và mã xử lý khả năng tương thích ngược có thể bị xóa.

Khi gọi các phương thức trong lệnh gọi lại, bạn phải xử lý khéo léo trường hợp khi trả về UNKNOWN_TRANSACTION . Khách hàng có thể đang triển khai hai phiên bản gọi lại khác nhau dựa trên cấu hình phát hành, vì vậy bạn không thể cho rằng khách hàng sẽ gửi phiên bản mới nhất và các phương thức mới có thể trả về phiên bản này. Điều này tương tự như cách các máy khách AIDL ổn định duy trì khả năng tương thích ngược với các máy chủ được mô tả trong Sử dụng giao diện được phiên bản .

// 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();
  }
}

Các trường mới trong các loại hiện có ( parcelable , enum , union ) có thể không tồn tại hoặc chứa các giá trị mặc định của chúng khi RELEASE_AIDL_USE_UNFROZEN false và giá trị của các trường mới mà dịch vụ cố gắng gửi sẽ bị loại bỏ trong quá trình xử lý.

Các loại mới được thêm vào trong phiên bản chưa đóng băng này không thể gửi hoặc nhận qua giao diện.

Việc triển khai không bao giờ nhận được lệnh gọi phương thức mới từ bất kỳ ứng dụng khách nào khi RELEASE_AIDL_USE_UNFROZENfalse .

Hãy cẩn thận khi chỉ sử dụng các điều tra viên mới với phiên bản mà chúng được giới thiệu chứ không phải phiên bản trước đó.

Thông thường, bạn sử dụng foo->getInterfaceVersion() để xem giao diện từ xa đang sử dụng phiên bản nào. Tuy nhiên, với hỗ trợ lập phiên bản dựa trên cờ, bạn đang triển khai hai phiên bản khác nhau, vì vậy bạn có thể muốn lấy phiên bản của giao diện hiện tại. Bạn có thể thực hiện việc này bằng cách lấy phiên bản giao diện của đối tượng hiện tại, ví dụ: this->getInterfaceVersion() hoặc các phương thức khác cho my_ver . Xem Truy vấn phiên bản giao diện của đối tượng từ xa để biết thêm thông tin.

Giao diện ổn định VINTF mới

Khi gói giao diện AIDL mới được thêm vào thì không có phiên bản cố định cuối cùng, do đó không có hành vi nào được áp dụng khi RELEASE_AIDL_USE_UNFROZENfalse . Không sử dụng các giao diện này. Khi RELEASE_AIDL_USE_UNFROZEN false , Trình quản lý dịch vụ sẽ không cho phép dịch vụ đăng ký giao diện và khách hàng sẽ không tìm thấy nó.

Bạn có thể thêm các dịch vụ có điều kiện dựa trên giá trị của cờ RELEASE_AIDL_USE_UNFROZEN trong tệp thực hiện của thiết bị:

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

Nếu dịch vụ là một phần của quy trình lớn hơn nên bạn không thể thêm nó vào thiết bị một cách có điều kiện, bạn có thể kiểm tra xem liệu dịch vụ có được khai báo bằng IServiceManager::isDeclared() hay không. Nếu nó được khai báo và không đăng ký được thì hãy hủy bỏ quá trình. Nếu nó không được khai báo thì có thể sẽ không đăng ký được.

Mực nang như một công cụ phát triển

Hàng năm sau khi VINTF bị đóng băng, chúng tôi điều chỉnh target-level ma trận tương thích khung (FCM) và PRODUCT_SHIPPING_API_LEVEL của Mực nang để chúng phản ánh các thiết bị sẽ ra mắt cùng với bản phát hành vào năm tới. Chúng tôi điều chỉnh target-levelPRODUCT_SHIPPING_API_LEVEL để đảm bảo có một số thiết bị khởi chạy đã được thử nghiệm và đáp ứng các yêu cầu mới cho bản phát hành vào năm tới.

Khi RELEASE_AIDL_USE_UNFROZEN true , Mực nang được sử dụng để phát triển các bản phát hành Android trong tương lai. Nó nhắm mục tiêu cấp độ FCM của bản phát hành Android vào năm tới và PRODUCT_SHIPPING_API_LEVEL , yêu cầu nó phải đáp ứng Yêu cầu phần mềm dành cho nhà cung cấp (VSR) của bản phát hành tiếp theo.

Khi RELEASE_AIDL_USE_UNFROZEN false , Mực nang có target-level trước đó và PRODUCT_SHIPPING_API_LEVEL để phản ánh thiết bị phát hành. Trong Android 14 trở xuống, sự khác biệt này sẽ được thực hiện bằng các nhánh Git khác nhau không nhận thay đổi về target-level FCM, cấp API vận chuyển hoặc bất kỳ mã nào khác nhắm mục tiêu vào bản phát hành tiếp theo.

Quy tắc đặt tên mô-đun

Trong Android 11, đối với mỗi sự kết hợp giữa phiên bản và chương trình phụ trợ được bật, một mô-đun thư viện sơ khai sẽ tự động được tạo. Để tham chiếu đến một mô-đun thư viện sơ khai cụ thể để liên kết, không sử dụng tên của mô-đun viện aidl_interface mà hãy sử dụng tên của mô-đun thư viện sơ khai, đó là ifacename - version - backend , trong đó

  • ifacename : tên của mô-đun viện aidl_interface
  • version là một trong hai
    • V version-number cho phiên bản đông lạnh
    • V latest-frozen-version-number + 1 cho phiên bản ngọn cây (chưa đông lạnh)
  • backend là một trong hai
    • java cho phần phụ trợ Java,
    • cpp cho phần phụ trợ C++,
    • ndk hoặc ndk_platform cho phần phụ trợ NDK. Cái trước dành cho ứng dụng và cái sau dành cho việc sử dụng nền tảng,
    • rust cho chương trình phụ trợ Rust.

Giả sử rằng có một mô-đun có tên foo và phiên bản mới nhất của nó là 2 và nó hỗ trợ cả NDK và C++. Trong trường hợp này, AIDL tạo ra các mô-đun này:

  • Dựa trên phiên bản 1
    • foo-V1-(java|cpp|ndk|ndk_platform|rust)
  • Dựa trên phiên bản 2 (phiên bản ổn định mới nhất)
    • foo-V2-(java|cpp|ndk|ndk_platform|rust)
  • Dựa trên phiên bản ToT
    • foo-V3-(java|cpp|ndk|ndk_platform|rust)

So với Android 11,

  • foo- backend , phiên bản ổn định mới nhất sẽ trở thành foo- V2 - backend
  • foo-unstable- backend , ám chỉ phiên bản ToT sẽ trở thành foo- V3 - backend

Tên tệp đầu ra luôn giống với tên mô-đun.

  • Dựa trên phiên bản 1: foo-V1-(cpp|ndk|ndk_platform|rust).so
  • Dựa trên phiên bản 2: foo-V2-(cpp|ndk|ndk_platform|rust).so
  • Dựa trên phiên bản ToT: foo-V3-(cpp|ndk|ndk_platform|rust).so

Lưu ý rằng trình biên dịch AIDL không tạo mô-đun phiên bản unstable hoặc mô-đun không có phiên bản cho giao diện AIDL ổn định. Kể từ Android 12, tên mô-đun được tạo từ giao diện AIDL ổn định luôn bao gồm phiên bản của nó.

Phương pháp giao diện meta mới

Android 10 bổ sung một số phương thức giao diện meta cho AIDL ổn định.

Truy vấn phiên bản giao diện của đối tượng từ xa

Khách hàng có thể truy vấn phiên bản và hàm băm của giao diện mà đối tượng từ xa đang triển khai và so sánh các giá trị được trả về với các giá trị của giao diện mà khách hàng đang sử dụng.

Ví dụ với phần phụ trợ 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();

Ví dụ với phần phụ trợ ndk (và 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);

Ví dụ với phần phụ trợ 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();

Đối với ngôn ngữ Java, phía từ xa PHẢI triển khai getInterfaceVersion()getInterfaceHash() như sau ( super được sử dụng thay vì IFoo để tránh lỗi sao chép/dán. Chú thích @SuppressWarnings("static") có thể cần thiết để tắt cảnh báo, tùy thuộc vào cấu hình javac ):

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

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

Điều này là do các lớp được tạo ra ( IFoo , IFoo.Stub , v.v.) được chia sẻ giữa máy khách và máy chủ (ví dụ: các lớp có thể nằm trong đường dẫn lớp khởi động). Khi các lớp được chia sẻ, máy chủ cũng được liên kết với phiên bản mới nhất của lớp mặc dù nó có thể được xây dựng bằng phiên bản giao diện cũ hơn. Nếu giao diện meta này được triển khai trong lớp dùng chung, nó sẽ luôn trả về phiên bản mới nhất. Tuy nhiên, bằng cách triển khai phương thức như trên, số phiên bản của giao diện sẽ được nhúng trong mã của máy chủ (vì IFoo.VERSION là một static final int được nội tuyến khi được tham chiếu) và do đó phương thức có thể trả về phiên bản chính xác mà máy chủ đã được tạo với.

Xử lý các giao diện cũ hơn

Có thể máy khách được cập nhật phiên bản mới hơn của giao diện AIDL nhưng máy chủ đang sử dụng giao diện AIDL cũ. Trong những trường hợp như vậy, việc gọi một phương thức trên giao diện cũ sẽ trả về UNKNOWN_TRANSACTION .

Với AIDL ổn định, khách hàng có nhiều quyền kiểm soát hơn. Ở phía máy khách, bạn có thể đặt triển khai mặc định thành giao diện AIDL. Một phương thức trong quá trình triển khai mặc định chỉ được gọi khi phương thức đó không được triển khai ở phía từ xa (vì nó được xây dựng bằng phiên bản giao diện cũ hơn). Vì các giá trị mặc định được đặt trên toàn cầu nên chúng không nên được sử dụng trong các bối cảnh có khả năng được chia sẻ.

Ví dụ về C++ trên Android 13 trở lên:

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

Ví dụ trong 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(...);

Bạn không cần cung cấp cách triển khai mặc định cho tất cả các phương thức trong giao diện AIDL. Các phương thức được đảm bảo sẽ được triển khai ở phía từ xa (vì bạn chắc chắn rằng điều khiển từ xa được tạo khi các phương thức đó nằm trong mô tả giao diện AIDL) không cần phải được ghi đè trong lớp impl mặc định.

Chuyển đổi AIDL hiện có sang AIDL có cấu trúc/ổn định

Nếu bạn có giao diện AIDL hiện có và mã sử dụng giao diện đó, hãy làm theo các bước sau để chuyển đổi giao diện sang giao diện AIDL ổn định.

  1. Xác định tất cả các phụ thuộc của giao diện của bạn. Đối với mỗi gói mà giao diện phụ thuộc vào, hãy xác định xem gói đó có được xác định trong AIDL ổn định hay không. Nếu không được xác định, gói phải được chuyển đổi.

  2. Chuyển đổi tất cả các bưu kiện trong giao diện của bạn thành các bưu kiện ổn định (bản thân các tệp giao diện có thể không thay đổi). Thực hiện điều này bằng cách thể hiện cấu trúc của chúng trực tiếp trong tệp AIDL. Các lớp quản lý phải được viết lại để sử dụng các kiểu mới này. Điều này có thể được thực hiện trước khi bạn tạo gói aidl_interface (bên dưới).

  3. Tạo gói aidl_interface (như được mô tả ở trên) chứa tên mô-đun của bạn, các phần phụ thuộc của nó và bất kỳ thông tin nào khác mà bạn cần. Để làm cho nó ổn định (không chỉ về cấu trúc), nó cũng cần phải được phiên bản hóa. Để biết thêm thông tin, hãy xem Giao diện lập phiên bản .