Android 10 hỗ trợ thêm Giao diện Android ổn định Ngôn ngữ định nghĩa (AIDL), một cách mới để theo dõi chương trình đăng ký giao diện (API) và giao diện nhị phân của ứng dụng (ABI) do AIDL cung cấp giao diện. AIDL ổn định hoạt động giống hệt AIDL, nhưng hệ thống xây dựng sẽ theo dõi khả năng tương thích giao diện và có những hạn chế về những việc bạn có thể làm:
- Giao diện được xác định trong hệ thống xây dựng bằng
aidl_interfaces
. - Giao diện chỉ có thể chứa dữ liệu có cấu trúc. Parcelables đại diện cho được tạo tự động dựa trên định nghĩa AIDL và sẽ tự động được tổng hợp và tách rời.
- Bạn có thể khai báo giao diện là ổn định (tương thích ngược). Khi việc này xảy ra, API của họ sẽ được theo dõi và tạo phiên bản trong tệp bên cạnh AIDL .
AIDL có cấu trúc so với AIDL ổ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 thông tin khai báo theo gói (Parceable tuỳ chỉnh) không có cấu trúc AIDL. Theo gói với các trường được xác định trong AIDL được gọi là Parceable (gói có cấu trúc).
AIDL ổn định cần có AIDL có cấu trúc để hệ thống xây dựng và trình biên dịch
có thể biết được liệu những thay đổi đối với sản phẩm theo gói có khả năng tương thích ngược hay không.
Tuy nhiên, không phải giao diện có cấu trúc nào cũng ổn định. Để ổn định,
một giao diện chỉ được sử dụng các loại có cấu trúc và cũng phải sử dụng các
các tính năng tạo phiên bản. Ngược lại, giao diện không ổn định nếu bản dựng cốt lõi
hệ thống được dùng để tạo nó hoặc nếu unstable:true
được đặt.
Xác định giao diện AIDL
Định nghĩa của aidl_interface
sẽ có dạng như sau:
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 cấu thành giao diện. Đường dẫn đối với loại AIDLFoo
được xác định trong góicom.acme
phải có giá trị là<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ứaAndroid.bp
. Trong ví dụ trước,<base_path>
là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>
được giải thích ở trên.imports
: Danh sách các mô-đunaidl_interface
mà mô-đun này sử dụng. Nếu một trong các Giao diện AIDL sử dụng một giao diện hoặc một gói có thể đóng gói từ một giao diện khácaidl_interface
, đặt tên của thiết bị tại đây. Đây có thể là tên riêng, để tham khảo thông tin mới nhất phiên bản 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ể. Tính năng chỉ định một phiên bản đã được hỗ trợ kể từ Android 12versions
: Các phiên bản trước đây của giao diện bị treo trongapi_dir
, Kể từ Android 11,versions
bị cố định trongaidl_api/name
. Nếu không có phiên bản bị treo của giao diện, bạn không nên chỉ định thuộc tính này và sẽ không kiểm tra khả năng tương thích. Trường này đã được thay thế bằngversions_with_info
đối với Android 13 trở lên.versions_with_info
: Danh sách các bộ dữ liệu, mỗi bộ dữ liệu chứa tên của một phiên bản bị treo và danh sách có bản nhập phiên bản của aidl_Interface khác các mô-đun mà phiên bản aidl_Interface này đã nhập. Định nghĩa của phiên bản V của giao diện AIDL IFACE được đặt tạiaidl_api/IFACE/V
. Trường này đã ra mắt trong Android 13, và bạn không nên sửa đổi trực tiếp tệp này trongAndroid.bp
. Trường này là 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ườngversions
sẽ được tự động di chuyển sangversions_with_info
khi người dùng gọi*-update-api
hoặc*-freeze-api
.stability
: Cờ tuỳ chọn cho cam kết về độ ổn định của giao diện này. Tính năng này chỉ hỗ trợ"vintf"
. Nếu bạn không đặtstability
, bản dựng hệ thống kiểm tra để đảm bảo giao diện đó có khả năng tương thích ngược trừ phi Đã chỉ địnhunstable
. Việc không đặt sẽ tương ứng với một giao diện có tính ổn định trong ngữ cảnh biên dịch này (do đó, mọi thứ hệ thống, ví dụ: những thứ trongsystem.img
và các phân vùng liên quan hoặc tất cả nhà cung cấp các mục trongvendor.img
và các phân vùng liên quan). Nếustability
được đặt thành"vintf"
, điều này tương ứng với cam kết về độ ổn định: giao diện phải được giữ ổn định miễn là nó được sử dụng.gen_trace
: Cờ không bắt buộc để bật hoặc tắt tính năng theo dõi. Bắt đầu sau Android 14 mặc định làtrue
chocpp
và Phần phụ trợjava
.host_supported
: Cờ không bắt buộc khi được đặt thànhtrue
sẽ khiến tạo sẵn cho môi trường máy chủ lưu trữ.unstable
: Cờ không bắt buộc dùng để đánh dấu giao diện này không cần phải ổn định. Khi bạn đặt thuộc tính này thànhtrue
, hệ thống xây dựng sẽ không tạo tệp kết xuất API cho giao diện và cũng không yêu cầu cập nhật.frozen
: Cờ không bắt buộc khi được đặt thànhtrue
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 nhiều bước kiểm tra thời gian xây dựng hơn. Khi bạn đặt thànhfalse
, điều này có nghĩa là giao diện đang ở và có các thay đổi mới, vì vậy, việc chạyfoo-freeze-api
sẽ tạo ra phiên bản mới và tự động thay đổi giá trị thànhtrue
. Lần đầu xuất hiện Android 14.backend.<type>.enabled
: Những cờ này bật/tắt từng phần phụ trợ trình biên dịch AIDL tạo mã cho. 4 phần phụ trợ là được hỗ trợ: Java, C++, NDK và Rust. Các phần phụ trợ Java, C++ và NDK đang bật theo mặc định. Nếu không cần bất kỳ phần phụ trợ nào trong số 3 phần phụ trợ này, thì tắt một cách rõ ràng. Theo mặc định, Rust sẽ bị tắt cho đến Android 15.backend.<type>.apex_available
: Danh sách các tên APEX mà hàm đã tạo stub cũng có sẵn cho bạn.backend.[cpp|java].gen_log
: Cờ không bắt buộc kiểm soát việc tạo thêm mã để thu thập thông tin về giao dịch.backend.[cpp|java].vndk.enabled
: Cờ không bắt buộc để tạo giao diện này một phần của VNDK. Mặc định làfalse
.backend.[cpp|ndk].additional_shared_libraries
: Ra mắt trong Trên Android 14, cờ này thêm các phần phụ thuộc vào thư viện gốc. Cờ này hữu ích vớindk_header
vàcpp_header
.backend.java.sdk_version
: Cờ tuỳ chọn để chỉ định phiên bản của SDK mà thư viện mã giả lập Java được xây dựng dựa trên đó. Mặc định là"system_current"
. Bạn không nên đặt giá trị này khibackend.java.platform_apis
làtrue
.backend.java.platform_apis
: Cờ không bắt buộc phải được đặt thànhtrue
khi thư viện đã 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 tổ hợp phiên bản và phần phụ trợ đã bật, một mã giả lập thư viện đã được tạo. Để biết cách tham khảo phiên bản cụ thể của thư viện mã giả lập đối với một phần phụ trợ cụ thể, hãy xem Quy tắc đặt tên mô-đun.
Ghi tệp AIDL
Các giao diện trong AIDL ổn định tương tự như các giao diện truyền thống, với có ngoại lệ là chúng không được phép sử dụng các gói không có cấu trúc (vì chúng không ổn định! xem Có cấu trúc so với ổn định AIDL). Điểm khác biệt chính đối với AIDL ổn định là cách Lô sản phẩm được xác định. Trước đây, các gói được khai báo chuyển tiếp; inch AIDL ổn định (và do đó có cấu trúc), các trường và biến của Parcelables đều đượ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;
}
Chế độ mặc định được hỗ trợ (nhưng không bắt buộc) cho boolean
, char
,
float
, double
, byte
, int
, long
và String
. Trong Android
12, giá trị mặc định cho giá trị enum 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 trống sẽ được sử dụng.
Liệt kê không có giá trị mặc định sẽ được khởi tạo về 0 ngay cả khi có
không có liệt kê 0.
Dùng thư viện mã giả lập
Sau khi thêm thư viện mã giả lập làm phần phụ thuộc cho mô-đun, bạn
có thể đưa chúng vào tệp của bạn. Sau đây là ví dụ về thư viện mã giả lập 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 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"],
...
}
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ụ trong Rust:
use aidl_interface_name::aidl::some::package::{IFoo, Thing};
...
// use just like traditional AIDL
Giao diện tạo phiên bản
Việc khai báo một mô-đun có tên foo cũng sẽ tạo 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 tạo, foo-freeze-api
thêm định nghĩa API mới trong api_dir
hoặc
aidl_api/name
, tuỳ thuộc vào phiên bản Android và
thêm một tệp .hash
, cả hai đều đại diện cho phiên bản mới bị treo của
. foo-freeze-api cũng cập nhật thuộc tính 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
. Tuy nhiên,
phiên bản ổn định mới nhất được chỉ định trong imports
trong versions_with_info
cho
import (nhập) không có phiên bản rõ ràng.
Sau khi thuộc tính versions_with_info
được chỉ định, hệ thống xây dựng sẽ chạy
kiểm tra khả năng tương thích giữa các phiên bản bị treo cũng như giữa các đầu cây (ToT)
và phiên bản bị treo 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 một 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ì tính ổ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ó phương thức mới được xác định rõ ràng sê-ri)
- Các phần tử nằm cuối gói có thể đóng gói (yêu cầu thêm giá trị mặc định cho mỗi phần tử phần tử)
- Giá trị không đổi
- Trong Android 11, enum
- Trong Android 12, các trường đến cuối kết hợp
Không được phép thực hiện hành động nào khác và không ai khác có thể sửa đổi giao diện (nếu không, chúng 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ó bị treo để phát hành hay không, bạn có thể tạo bằng phương thức tập hợp các biến môi trường sau đây:
AIDL_FROZEN_REL=true m ...
– bản dựng yêu cầu tất cả giao diện AIDL ổn định để bị cố định mà không có trườngowner:
được chỉ định.AIDL_FROZEN_OWNERS="aosp test"
– bản dựng yêu cầu tất cả giao diện AIDL ổn định được cố định bằng trườngowner:
được chỉ định là "aosp" hoặc "test".
Tính ổn định của quá trình nhập
Việc cập nhật phiên bản nhập cho các phiên bản giao diện bị treo tương thích ngược ở lớp AIDL chính thức. Tuy nhiên, việc cập nhật các giá trị này đòi hỏi cập nhật tất cả máy chủ và ứng dụng khách sử dụng phiên bản giao diện trước đó, và một số ứng dụng có thể bị nhầm lẫn khi kết hợp các phiên bản khác nhau của các loại. Nhìn chung, đối với các gói chỉ có loại hoặc gói phổ biến, đây là cách an toàn vì mã cần đã được viết để xử lý các loại không xác định trong giao dịch IPC.
Trong nền tảng Android, mã android.hardware.graphics.common
là mã lớn nhất
ví dụ về loại 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ột máy chủ cũ, các ứng dụng mới sẽ nhận được lỗi hoặc ngoại lệ, tuỳ thuộc vào phần phụ trợ.
- Phần phụ trợ
cpp
nhận được::android::UNKNOWN_TRANSACTION
. - Phần phụ trợ
ndk
nhận đượcSTATUS_UNKNOWN_TRANSACTION
. - Phần phụ trợ của
java
nhận đượcandroid.os.RemoteException
kèm theo một thông báo cho biết Chưa triển khai API.
Để 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ấn và sử dụng mặc định.
Theo gói
Khi bạn thêm các trường mới vào các gói được, các ứng dụng và máy chủ cũ sẽ loại bỏ những trường đó. Khi máy khách và máy chủ mới nhận được các bưu kiện cũ, giá trị mặc định cho các gói các trường sẽ được tự động điền vào. Điều này có nghĩa là bạn cần đặt mặc định được chỉ định cho tất cả các trường mới trong gói.
Máy chủ không nên trông đợi các trường mới trừ phi họ biết máy chủ đang triển khai phiên bản có trường đã xác định (xem phiên bản truy vấn).
Enum và hằng số
Tương tự như vậy, máy khách và máy chủ nên từ chối hoặc bỏ qua việc không nhận dạng được các giá trị không đổi và liệt kê khi thích hợp, vì có thể thêm các giá trị khác vào tương lai. Ví dụ: máy chủ không được huỷ khi nhận được mà nó không biết. Máy chủ nên bỏ qua enum hoặc trả về một giá trị nào đó để ứng dụng biết rằng giá trị đó không được hỗ trợ trong cách triển khai này.
Liên minh
Việc cố gắng gửi kết hợp với một trường mới sẽ không thành công nếu trình thu nhận cũ và
không biết về lĩnh vực này. Quá trình triển khai sẽ không bao giờ cho thấy sự kết hợp với
trường mới. Lỗi sẽ bị bỏ qua nếu đó là lỗi
giao dịch một chiều; nếu không, lỗi sẽ là BAD_VALUE
(đối với C++ hoặc NDK
phụ trợ) hoặc IllegalArgumentException
(đối với phần phụ trợ Java). Lỗi là
đã nhận được nếu máy khách đang gửi một hợp nhất được đặt đến trường mới thành một tập hợp
hoặc khi máy khách cũ nhận được liên kết từ máy chủ mới.
Quản lý nhiều phiên bản
Một không gian tên của trình liên kết trong Android chỉ được có 1 phiên bản của một aidl
cụ thể
để tránh các trường hợp loại aidl
đã tạo có nhiều
định nghĩa. C++ có Quy tắc một định nghĩa chỉ yêu cầu một định nghĩa
của từng ký hiệu.
Bản dựng Android báo lỗi khi một mô-đun phụ thuộc vào các
các phiên bản của cùng một thư viện aidl_interface
. Mô-đun này có thể phụ thuộc vào
các thư viện này một cách trực tiếp hoặc gián tiếp thông qua các phần phụ thuộc của
phần phụ thuộc. Những lỗi này cho thấy biểu đồ phần phụ thuộc từ mô-đun gặp lỗi đến
các phiên bản xung đột của thư viện aidl_interface
. Tất cả
các phần phụ thuộc cần được cập nhật để bao gồm cùng một phiên bản (thường là phiên bản mới nhất)
của các thư viện này.
Nếu thư viện giao diện được nhiều mô-đun khác nhau sử dụng, điều này có thể hữu ích
để tạo cc_defaults
, java_defaults
và rust_defaults
cho bất kỳ nhóm nào
những thư viện và quy trình cần sử dụng cùng một phiên bản. Khi giới thiệu một
phiên bản mới của giao diện, các giá trị mặc định đó có thể được cập nhật và tất cả các mô-đun
sử dụng chúng được cập nhật cùng nhau, đảm bảo chúng không sử dụng các phiên bản khác nhau
của giao diện.
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"],
...
}
Khi các mô-đun aidl_interface
nhập các mô-đun aidl_interface
khác, thao tác này sẽ tạo ra
các phần phụ thuộc bổ sung yêu cầu sử dụng cùng nhau các phiên bản cụ thể. Chiến dịch này
tình hình có thể trở nên khó quản lý khi có aidl_interface
thường gặp
các mô-đun được nhập trong nhiều mô-đun aidl_interface
được sử dụng
trong cùng một quy trình.
Có thể sử dụng aidl_interfaces_defaults
để giữ một định nghĩa của
phiên bản phần phụ thuộc mới nhất cho aidl_interface
có thể được cập nhật trong
một vị trí duy nhất và được sử dụng bởi tất cả mô-đun aidl_interface
muốn nhập
giao diện chung đó.
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"],
...
}
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 được cố định) trên 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ợ tính năng dự phòng thời gian chạy cho các thư viện giao diện không được cố định này theo thứ tự để mã được viết dựa trên phiên bản không được cố định 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 các ứng dụng tương tự như hành vi hiện tại và với phương án dự phòng thì việc triển khai cũng cần phải tuân thủ những hành vi đó. Xem Sử dụng giao diện được tạo phiên bản.
Cờ bản 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 được đóng băng của
giao diện này được dùng trong thời gian chạy và false
có nghĩa là các thư viện của
phiên bản không bị treo đều hoạt động như phiên bản bị treo gần đây nhất.
Bạn có thể ghi đè cờ thành true
cho
phát triển cục bộ, nhưng phải hoàn nguyên về false
trước khi phát hành. Giá 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
.
Tệp kê khai và ma trận tương thích
Đố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 ở mỗi bên giao diện của nhà cung cấp.
Hầu hết các thiết bị không phải là loài giáp xác đều nhắm đến ma trận tương thích mới nhất
chỉ sau khi giao diện bị treo, nên không có gì khác biệt trong 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 các thiết bị hoặc sản phẩm cụ thể
ma trận tương thích mà thiết bị nhắm đến trong quá trình phát triển. Vì vậy, khi một
phiên bản mới, không cố định của giao diện sẽ được thêm vào ma trận tương thích,
các phiên bản cố định trước đó cần được duy trì trong
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 cho RELEASE_AIDL_USE_UNFROZEN
các cấu hình hoặc cho phép cả hai phiên bản trong một tệp ma trận tương thích
được dùng trong tất cả các cấu hình.
Ví dụ: khi thêm phiên bản không cố định 4, hãy sử dụng <version>3-4</version>
.
Khi phiên bản 4 bị treo, bạn có thể xoá phiên bản 3 khỏi ma trận tương thích
vì phiên bản bị treo 4 được dùng khi RELEASE_AIDL_USE_UNFROZEN
được
false
.
Tệp kê khai
Trong Android 15, thay đổi trong libvintf
được áp dụng cho
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à mảnh tệp kê khai khai báo phiên bản giao diện
một dịch vụ sẽ triển khai. Khi sử dụng phiên bản được đóng băng mới nhất của một 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. Thời gian
RELEASE_AIDL_USE_UNFROZEN=false
các mục nhập tệp kê khai được điều chỉnh theo
libvintf
để phản ánh thay đổi trong thư viện AIDL đã tạo. Phiên bản
được sửa đổi từ phiên bản không cố định, N
, thành
phiên bản cố định cuối cùng N - 1
. Do đó, người dùng không cần phải quản lý nhiều
tệp kê khai hoặc mảnh tệp kê khai cho từng dịch vụ của họ.
Thay đổi ứng dụng HAL
Mã ứng dụng HAL phải có khả năng tương thích ngược với từng mã ứng dụng bị treo được hỗ trợ trước đó
. Khi RELEASE_AIDL_USE_UNFROZEN
là false
, các dịch vụ sẽ luôn xem
như phiên bản bị treo gần đây nhất hoặc phiên bản cũ hơn (ví dụ: gọi mới là phiên bản được đóng băng
phương thức trả về UNKNOWN_TRANSACTION
hoặc các trường parcelable
mới có
mặc định). Các ứng dụng khung Android bắt buộc phải quay ngược lại
tương thích với các phiên bản trước đó, nhưng đây là chi tiết mới của
khách hàng của nhà cung cấp và khách hàng sử dụng giao diện do đối tác sở hữu.
Thay đổi về cách triển khai HAL
Sự khác biệt lớn nhất trong việc phát triển HAL với việc phát triển dựa trên cờ là
yêu cầu về việc triển khai HAL để tương thích ngược với
phiên bản bị treo hoạt động khi RELEASE_AIDL_USE_UNFROZEN
là false
.
Cân nhắc khả năng tương thích ngược trong các phương pháp triển khai và mã thiết bị là một điều mới mẻ
tập thể dục. Xem phần Sử dụng phiên bản
.
Những cân nhắc về khả năng tương thích ngược thường giống nhau đối với ứng dụng 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 nhận thức được vì giờ đây bạn đang làm việc hiệu quả triển khai hai phiên bản sử dụng cùng một mã nguồn (phiên bản hiện tại, không bị cố định phiên bản).
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
phương pháp mới. Cả ứng dụng và dịch vụ đều được cập nhật để sử dụng phiên bản 4 mới
thư viện của bạn. Vì thư viện V4 dựa trên phiên bản chưa được đóng băng của
giao diện của bạn, nó hoạt động giống như phiên bản bị treo gần đây nhất, phiên bản 3, khi
RELEASE_AIDL_USE_UNFROZEN
là false
và ngăn việc sử dụng phương thức mới.
Khi giao diện bị cố định, tất cả giá trị của RELEASE_AIDL_USE_UNFROZEN
đều sử dụng giá trị đó
phiên bản bị treo và mã xử lý khả năng tương thích ngược có thể bị xoá.
Khi gọi phương thức trên lệnh gọi lại, bạn phải xử lý trường hợp một cách linh hoạt khi
Trả về UNKNOWN_TRANSACTION
. Khách hàng có thể triển khai hai chiến dịch khác nhau
của một lệnh gọi lại dựa trên cấu hình phát hành. Do đó, bạn không thể
giả định ứng dụng gửi phiên bản mới nhất và các phương thức mới có thể trả về
này. Điều này tương tự như cách ứng dụng AIDL ổn định duy trì ngược
khả năng tương thích với máy chủ được mô tả trong phần Sử dụng cá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 loại hiện tại (parcelable
, enum
, union
) có thể
không tồn tại hoặc chứa giá trị mặc định khi RELEASE_AIDL_USE_UNFROZEN
là
false
và giá trị của các trường mới mà một dịch vụ cố gắng gửi sẽ bị loại bỏ
ra khỏi quy trình.
Không thể gửi những loại mới được thêm vào phiên bản đã bỏ cố định này hoặc nhận được thông qua giao diện.
Quá trình triển khai không bao giờ nhận lệnh gọi phương thức mới từ bất kỳ ứng dụng nào khi
RELEASE_AIDL_USE_UNFROZEN
là false
.
Hãy cẩn thận, chỉ sử dụng liệt kê mới với phiên bản đượ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 phiên bản điều khiển từ xa
giao diện người dùng đang sử dụng. Tuy nhiên, với tính năng hỗ trợ tạo phiên bản dựa trên cờ, bạn
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
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 đối tượng khác
cho my_ver
. Xem phần Truy vấn phiên bản giao diện của điều khiển từ xa
đối tượng
để biết thêm thông tin.
Giao diện ổn định mới của VINTF
Khi bạn thêm một gói giao diện AIDL mới, thì không có phiên bản bị treo gần đây nhất, vì vậy
không có hành vi nào để quay lại khi RELEASE_AIDL_USE_UNFROZEN
là
false
. Đừng sử dụng những giao diện này. Khi RELEASE_AIDL_USE_UNFROZEN
là
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 quảng cáo đó.
Bạn có thể thêm các dịch vụ theo điều kiện dựa trên giá trị của
Cờ RELEASE_AIDL_USE_UNFROZEN
trong tệp makefile của thiết bị:
ifeq ($(RELEASE_AIDL_USE_UNFROZEN),true)
PRODUCT_PACKAGES += \
android.hardware.health.storage-service
endif
Nếu dịch vụ nằm trong một quy trình lớn hơn nên bạn không thêm được dịch vụ đó vào thiết bị
theo điều kiện, bạn có thể kiểm tra xem dịch vụ có được khai báo bằng
IServiceManager::isDeclared()
. Nếu ứng dụng được khai báo nhưng không đăng ký được, thì
huỷ quá trình này. Nếu bạn không khai báo miền này, thì hệ thống có thể sẽ không đăng ký được.
Mực ống làm công cụ phát triển
Mỗi năm sau khi VINTF bị đóng, chúng tôi sẽ điều chỉnh khả năng tương thích khung
ma trận (FCM) target-level
và PRODUCT_SHIPPING_API_LEVEL
của mực nang
để phản ánh các thiết bị ra mắt cùng với bản phát hành vào năm sau. Chúng tôi điều chỉnh
target-level
và PRODUCT_SHIPPING_API_LEVEL
để đảm bảo có một số
thiết bị sắp ra mắt được thử nghiệm và đáp ứng các yêu cầu mới cho năm tới
bản phát hành.
Khi RELEASE_AIDL_USE_UNFROZEN
là true
, mực nang sẽ
dùng để phát triển các bản phát hành Android sau này. Chiến dịch này nhắm đến Android trong năm tới
cấp FCM của bản phát hành và PRODUCT_SHIPPING_API_LEVEL
, đòi hỏi bản phát hành phải đáp ứng
các yêu cầu về phần mềm nhà cung cấp (VSR) của bản phát hành tiếp theo.
Khi RELEASE_AIDL_USE_UNFROZEN
là false
, mực ống sẽ có giá trị trước
target-level
và PRODUCT_SHIPPING_API_LEVEL
để phản ánh thiết bị phát hành.
Trên Android 14 trở xuống, sự khác biệt này sẽ là
đã thực hiện với các nhánh Git khác nhau không nhận được thay đổi đối với FCM
target-level
, cấp API vận chuyển hoặc bất kỳ mã nào khác nhắm mục tiêu cấp độ tiếp theo
bản phát hành.
Quy tắc đặt tên mô-đun
Trong Android 11, đối với mỗi tổ hợp phiên bản và
các phần phụ trợ được bật, mô-đun thư viện mã giả lập sẽ được tạo tự động. Để giới thiệu
vào một mô-đun thư viện mã giả lập cụ thể để liên kết, đừng sử dụng tên của
mô-đun aidl_interface
nhưng là tên của mô-đun thư viện mã giả lập,
ifacename-version-backend, trong đó
ifacename
: tên của mô-đunaidl_interface
version
là một trongVversion-number
đối với các phiên bản bị treoVlatest-frozen-version-number + 1
cho phiên bản tip-of-tree (chưa được đóng băng)
backend
là một trongjava
cho phần phụ trợ Java,cpp
cho phần phụ trợ C++,ndk
hoặcndk_platform
cho phần phụ trợ NDK. Hộp cát về quyền riêng tư là dành cho ứng dụng và dành cho việc sử dụng nền tảng cho đến Android 13. Ngang bằng Android 13 trở lên, chỉ sử dụngndk
.rust
cho phần phụ trợ Rust.
Giả sử có một mô-đun có tên foo và phiên bản mới nhất của mô-đun đó là 2, đồng thời hỗ trợ cả NDK và C++. Trong trường hợp này, AIDL sẽ tạo các mô-đun sau:
- 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
, là phiên bản ổn định mới nhất phiên bản trở thànhfoo-V2-backend
foo-unstable-backend
, đề cập đến Điều khoản dịch vụ phiên bản trở thànhfoo-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 Điều khoản dịch vụ:
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 tạo 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 cả phiên bản của giao diện đó.
Phương thức giao diện meta mới
Android 10 thêm 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
Ứng dụ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()
và
getInterfaceHash()
như sau (super
được dùng thay cho IFoo
để tránh
lỗi sao chép và dán. Chú giải @SuppressWarnings("static")
có thể
nếu cần để tắt cảnh báo, tuỳ 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 (IFoo
, IFoo.Stub
, v.v.) được dùng chung
giữa máy khách và máy chủ (ví dụ: các lớp có thể đang trong quá trình khởi động
đường dẫn lớp). Khi 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 các lớp này ngay cả khi phiên bản này được tạo bằng một phiên bản cũ
phiên bản của giao diện. Nếu giao diện meta này được triển khai trong
thì lớp này 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 pháp
như trên, số phiên bản của giao diện được nhúng vào mã của máy chủ
(vì IFoo.VERSION
là một static final int
cùng dòng khi được tham chiếu)
do đó phương thức này có thể trả về phiên bản chính xác mà máy chủ được tạo cùng.
Xử lý giao diện cũ
Có thể ứng dụng đã được cập nhật phiên bản AIDL mới hơn
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
.
Khi sử dụng AIDL ổn định, khách hàng sẽ có nhiều quyền kiểm soát hơn. Ở phía máy khách, bạn có thể đặt phương thức triển khai mặc định cho giao diện AIDL. Một phương thức trong giá trị mặc định Phương thức triển khai chỉ được gọi khi phương thức không được triển khai trong điều khiển từ xa (vì nó được xây dựng bằng phiên bản giao diện cũ hơn). Từ các giá trị mặc định được đặt trên toàn cầu, nên không nên sử dụng chúng từ ngữ cảnh.
Ví dụ trong 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 phương thức triển khai mặc định cho tất cả phương thức trong AIDL
. Các phương thức được đảm bảo sẽ triển khai ở phía 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
Nội dung mô tả giao diện AIDL) không cần ghi đè trong impl
mặc định
.
Chuyển đổi AIDL hiện có thành AIDL có cấu trúc hoặc ổn định
Nếu bạn đã có mã và giao diện AIDL sử dụng giao diện này, hãy dùng những cách sau các bước chuyển đổi giao diện sang giao diện AIDL ổn định.
Xác định tất cả phần phụ thuộc của giao diện. Đối với mỗi gói phụ thuộc vào giao diện nào, hãy xác định xem gói có được xác định trong AIDL ổn định hay không. Nếu chưa được xác định, gói phải được chuyển đổi.
Chuyển đổi tất cả các Parcelable trong giao diện của bạn thành các Parceable ổn định ( có thể giữ nguyên tệp giao diện). Thực hiện việc 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 loại mới này. Bạn có thể thực hiện việc này trước khi tạo Gói
aidl_interface
(bên dưới).Tạo một gói
aidl_interface
(như mô tả ở trên) chứa tên mô-đun, các phần phụ thuộc của mô-đun đó và bất kỳ thông tin nào khác mà bạn cần. Để làm cho mã ổn định (không chỉ có cấu trúc), bạn cũng cần tạo phiên bản cho mã. Để biết thêm thông tin, hãy xem bài viết Giao diện tạo phiên bản.