Các thuộc tính hệ thống giúp việc chia sẻ thông tin trở nên thuận tiện, thường
cấu hình, trên toàn hệ thống. Mỗi phân vùng có thể sử dụng các thuộc tính hệ thống riêng của nó
nội bộ. Sự cố có thể xảy ra khi thuộc tính được truy cập qua các phân vùng,
chẳng hạn như /vendor
truy cập vào các thuộc tính do /system
xác định. Kể từ Android 8.0,
một số phân vùng, chẳng hạn như /system
, có thể được nâng cấp, trong khi /vendor
được để lại
không thay đổi. Vì các thuộc tính hệ thống chỉ là một từ điển chuỗi toàn cục
các cặp khoá-giá trị không có giản đồ, thì rất khó để ổn định các thuộc tính. Chiến lược phát hành đĩa đơn
Phân vùng /system
có thể thay đổi hoặc xoá các thuộc tính mà /vendor
phân vùng phụ thuộc mà không có thông báo nào.
Kể từ bản phát hành Android 10, các thuộc tính hệ thống
được truy cập trên các phân vùng được giản đồ thành các tệp Mô tả Sysprop, và
Các API để truy cập vào các thuộc tính được tạo dưới dạng hàm cụ thể cho C++ và Rust,
và lớp cho Java. Các API này thuận tiện hơn khi sử dụng vì không có sự kỳ diệu nào
Các chuỗi (chẳng hạn như ro.build.date
) là cần thiết để truy cập và vì các chuỗi này có thể
được nhập tĩnh. Độ ổn định của ABI cũng được kiểm tra tại thời điểm xây dựng và bản dựng
bị hỏng nếu xảy ra thay đổi không tương thích. Bước kiểm tra này được xác định rõ ràng
giao diện giữa các phân vùng. Các API này cũng có thể cung cấp tính nhất quán giữa
Rust, Java và C++.
Xác định các thuộc tính hệ thống dưới dạng API
Xác định các thuộc tính hệ thống dưới dạng API bằng tệp Mô tả Sysprop (.sysprop
),
sử dụng TextFormat của protobuf với lược đồ sau:
// File: sysprop.proto
syntax = "proto3";
package sysprop;
enum Access {
Readonly = 0;
Writeonce = 1;
ReadWrite = 2;
}
enum Owner {
Platform = 0;
Vendor = 1;
Odm = 2;
}
enum Scope {
Public = 0;
Internal = 2;
}
enum Type {
Boolean = 0;
Integer = 1;
Long = 2;
Double = 3;
String = 4;
Enum = 5;
UInt = 6;
ULong = 7;
BooleanList = 20;
IntegerList = 21;
LongList = 22;
DoubleList = 23;
StringList = 24;
EnumList = 25;
UIntList = 26;
ULongList = 27;
}
message Property {
string api_name = 1;
Type type = 2;
Access access = 3;
Scope scope = 4;
string prop_name = 5;
string enum_values = 6;
bool integer_as_bool = 7;
string legacy_prop_name = 8;
}
message Properties {
Owner owner = 1;
string module = 2;
repeated Property prop = 3;
}
Một tệp Mô tả Sysprop chứa một thông báo thuộc tính, trong đó mô tả một một tập hợp thuộc tính. Sau đây là ý nghĩa của các trường.
Trường | Ý nghĩa |
---|---|
owner
|
Đặt thành phân vùng sở hữu các thuộc tính: Platform ,
Vendor hoặc Odm .
|
module
|
Dùng để tạo một không gian tên (C++) hoặc lớp tĩnh cuối cùng (Java) trong đó đặt các API được tạo. Ví dụ:
com.android.sysprop.BuildProperties
sẽ là không gian tên com::android::sysprop::BuildProperties trong C++,
và lớp BuildProperties trong gói trong
com.android.sysprop trong Java.
|
prop
|
Danh sách cơ sở lưu trú. |
Ý nghĩa của các trường thông báo Property
như sau.
Trường | Ý nghĩa |
---|---|
api_name
|
Tên của API đã tạo. |
type
|
Loại của cơ sở lưu trú này. |
access
|
Readonly : Chỉ tạo API getter
Writeonce , ReadWrite : Tạo API getter và setter
Lưu ý: Các thuộc tính có tiền tố ro. có thể không sử dụng quyền truy cập
ReadWrite .
|
scope
|
Internal : Chỉ chủ sở hữu mới có thể truy cập.
Public : Mọi người đều có thể truy cập, ngoại trừ các mô-đun NDK.
|
prop_name
|
Tên của thuộc tính hệ thống cơ bản, ví dụ:
ro.build.date .
|
enum_values
|
(chỉ Enum , EnumList ) Chuỗi được phân tách bằng thanh(|)
bao gồm các giá trị enum có thể có. Ví dụ: value1|value2 .
|
integer_as_bool
|
(Chỉ Boolean , BooleanList ) Đặt phương thức setter sử dụng 0 và 1 thay vì false và true .
|
legacy_prop_name
|
(không bắt buộc, chỉ dành cho thuộc tính Readonly ) Tên cũ của
thuộc tính hệ thống cơ bản. Khi gọi phương thức getter, API getter sẽ cố đọc
prop_name và sử dụng legacy_prop_name nếu
prop_name không tồn tại. Sử dụng legacy_prop_name khi
ngừng sử dụng một tài sản hiện có và chuyển sang một tài sản mới.
|
Mỗi loại thuộc tính liên kết với các loại sau trong C++, Java và Rust.
Loại | C++ | Java | Rust |
---|---|---|---|
Boolean | std::optional<bool>
|
Optional<Boolean>
|
bool
|
Số nguyên | std::optional<std::int32_t>
|
Optional<Integer>
|
i32
|
UInt | std::optional<std::uint32_t>
|
Optional<Integer>
|
u32
|
Dài | std::optional<std::int64_t>
|
Optional<Long>
|
i64
|
ULong | std::optional<std::uint64_t>
|
Optional<Long>
|
u64
|
Đôi | std::optional<double>
|
Optional<Double>
|
f64
|
Chuỗi | std::optional<std::string>
|
Optional<String>
|
String
|
Enum | std::optional<{api_name}_values>
|
Optional<{api_name}_values>
|
{ApiName}Values
|
Danh sách chữ T | std::vector<std::optional<T>>
|
List<T>
|
Vec<T>
|
Dưới đây là ví dụ về tệp Mô tả Sysprop xác định ba thuộc tính:
# File: android/sysprop/PlatformProperties.sysprop
owner: Platform
module: "android.sysprop.PlatformProperties"
prop {
api_name: "build_date"
type: String
prop_name: "ro.build.date"
scope: Public
access: Readonly
}
prop {
api_name: "date_utc"
type: Integer
prop_name: "ro.build.date_utc"
scope: Internal
access: Readonly
}
prop {
api_name: "device_status"
type: Enum
enum_values: "on|off|unknown"
prop_name: "device.status"
scope: Public
access: ReadWrite
}
Xác định thư viện thuộc tính hệ thống
Giờ đây, bạn có thể xác định các mô-đun sysprop_library
bằng tệp Mô tả Sysprop.
sysprop_library
đóng vai trò là API cho C++, Java và Rust. Hệ thống xây dựng
tạo nội bộ một rust_library
, một java_library
và một cc_library
cho từng thực thể của sysprop_library
.
// File: Android.bp
sysprop_library {
name: "PlatformProperties",
srcs: ["android/sysprop/PlatformProperties.sysprop"],
property_owner: "Platform",
vendor_available: true,
}
Bạn phải đưa các tệp danh sách API vào nguồn để kiểm tra API. Để thực hiện việc này,
tạo các tệp API và một thư mục api
. Đặt thư mục api
vào cùng một thư mục
thư mục có tên Android.bp
. Tên tệp API là <module_name>-current.txt
,
<module_name>-latest.txt
. <module_name>-current.txt
có các chữ ký API
mã nguồn hiện tại và <module_name>-latest.txt
chứa mã bị treo mới nhất
Chữ ký API. Hệ thống xây dựng sẽ kiểm tra xem các API có thay đổi hay không bằng cách so sánh các tệp API này với các tệp API được tạo tại thời điểm tạo bản dựng, đồng thời đưa ra thông báo lỗi và hướng dẫn để cập nhật tệp current.txt
nếu current.txt
không khớp với mã nguồn. Dưới đây là một thư mục và tệp mẫu
tổ chức:
├── api
│ ├── PlatformProperties-current.txt
│ └── PlatformProperties-latest.txt
└── Android.bp
Các mô-đun ứng dụng Rust, Java và C++ có thể liên kết với sysprop_library
để sử dụng
các API do chúng tôi tạo. Hệ thống xây dựng tạo liên kết từ ứng dụng khách đến C++ được tạo,
Thư viện Java và Rust, từ đó cấp cho ứng dụng khách quyền truy cập vào các API được tạo.
java_library {
name: "JavaClient",
srcs: ["foo/bar.java"],
libs: ["PlatformProperties"],
}
cc_binary {
name: "cc_client",
srcs: ["baz.cpp"],
shared_libs: ["PlatformProperties"],
}
rust_binary {
name: "rust_client",
srcs: ["src/main.rs"],
rustlibs: ["libplatformproperties_rust"],
}
Xin lưu ý rằng tên thư viện Rust được tạo bằng cách chuyển đổi sysprop_library
tên thành chữ thường, thay thế .
và -
bằng _
, sau đó thêm lib
và
thêm _rust
.
Trong ví dụ trước, bạn có thể truy cập vào các thuộc tính đã xác định như sau.
Ví dụ về Rust:
use platformproperties::DeviceStatusValues;
fn foo() -> Result<(), Error> {
// Read "ro.build.date_utc". default value is -1.
let date_utc = platformproperties::date_utc()?.unwrap_or_else(-1);
// set "device.status" to "unknown" if "ro.build.date" is not set.
if platformproperties::build_date()?.is_none() {
platformproperties::set_device_status(DeviceStatusValues::UNKNOWN);
}
…
}
Ví dụ về Java:
import android.sysprop.PlatformProperties;
…
static void foo() {
…
// read "ro.build.date_utc". default value is -1
Integer dateUtc = PlatformProperties.date_utc().orElse(-1);
// set "device.status" to "unknown" if "ro.build.date" is not set
if (!PlatformProperties.build_date().isPresent()) {
PlatformProperties.device_status(
PlatformProperties.device_status_values.UNKNOWN
);
}
…
}
…
Ví dụ về C++:
#include <android/sysprop/PlatformProperties.sysprop.h>
using namespace android::sysprop;
…
void bar() {
…
// read "ro.build.date". default value is "(unknown)"
std::string build_date = PlatformProperties::build_date().value_or("(unknown)");
// set "device.status" to "on" if it's "unknown" or not set
using PlatformProperties::device_status_values;
auto status = PlatformProperties::device_status();
if (!status.has_value() || status.value() == device_status_values::UNKNOWN) {
PlatformProperties::device_status(device_status_values::ON);
}
…
}
…