คุณสมบัติของระบบจัดเตรียมวิธีที่สะดวกในการแบ่งปันข้อมูล ซึ่งโดยปกติจะเป็นการกำหนดค่าทั่วทั้งระบบ แต่ละพาร์ติชันสามารถใช้คุณสมบัติระบบของตัวเองภายในได้ ปัญหาอาจเกิดขึ้นได้เมื่อมีการเข้าถึงคุณสมบัติข้ามพาร์ติชัน เช่น /vendor
เข้าถึงคุณสมบัติ /system
-definition ตั้งแต่ Android 8.0 พาร์ติชันบางส่วน เช่น /system
สามารถอัปเกรดได้ ในขณะที่ /vendor
ไม่มีการเปลี่ยนแปลง เนื่องจากคุณสมบัติของระบบเป็นเพียงพจนานุกรมสากลของคู่คีย์สตริง/ค่าที่ไม่มีสคีมา จึงเป็นเรื่องยากที่จะรักษาเสถียรภาพของคุณสมบัติ พาร์ติชัน /system
สามารถเปลี่ยนหรือลบคุณสมบัติที่พาร์ติชัน /vendor
ขึ้นอยู่กับได้โดยไม่ต้องแจ้งให้ทราบล่วงหน้า
ตั้งแต่การเปิดตัว Android 10 คุณสมบัติของระบบที่เข้าถึงข้ามพาร์ติชั่นจะถูกจัดแผนผังเป็นไฟล์ Sysprop Description และ API เพื่อเข้าถึงคุณสมบัติจะถูกสร้างขึ้นเป็นฟังก์ชันที่เป็นรูปธรรมสำหรับ C++ และ Rust และคลาสสำหรับ Java API เหล่านี้ใช้งานได้สะดวกกว่าเนื่องจากไม่จำเป็นต้องใช้สตริงวิเศษ (เช่น ro.build.date
) ในการเข้าถึง และเนื่องจากสามารถพิมพ์แบบคงที่ได้ ความเสถียรของ ABI จะถูกตรวจสอบ ณ เวลาสร้างด้วย และบิลด์จะพังหากการเปลี่ยนแปลงที่เข้ากันไม่ได้เกิดขึ้น การตรวจสอบนี้ทำหน้าที่เป็นอินเทอร์เฟซที่กำหนดไว้อย่างชัดเจนระหว่างพาร์ติชัน API เหล่านี้ยังสามารถให้ความสอดคล้องระหว่าง Rust, Java และ C++ ได้อีกด้วย
การกำหนดคุณสมบัติของระบบเป็น API
กำหนดคุณสมบัติของระบบเป็น API ด้วยไฟล์ Sysprop Description ( .sysprop
) ซึ่งใช้ TextFormat ของ protobuf โดยมีสคีมาต่อไปนี้:
// 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;
}
ไฟล์ Sysprop Description หนึ่งไฟล์มีข้อความคุณสมบัติหนึ่งข้อความ ซึ่งอธิบายชุดของคุณสมบัติ ความหมายของสาขามีดังนี้
สนาม | ความหมาย |
---|---|
owner | ตั้งค่าเป็นพาร์ติชันที่เป็นเจ้าของคุณสมบัติ: Platform , Vendor หรือ Odm |
module | ใช้เพื่อสร้างเนมสเปซ (C++) หรือคลาสสุดท้ายแบบคงที่ (Java) ซึ่งวาง API ที่สร้างขึ้น ตัวอย่างเช่น com.android.sysprop.BuildProperties จะเป็น namespace com::android::sysprop::BuildProperties ใน C++ และคลาส BuildProperties ในแพ็คเกจใน com.android.sysprop ใน Java |
prop | รายการคุณสมบัติ |
ความหมายของ Property
ข้อความคุณสมบัติมีดังนี้
สนาม | ความหมาย |
---|---|
api_name | ชื่อของ API ที่สร้างขึ้น |
type | ประเภทของคุณสมบัตินี้ |
access | Readonly : สร้าง getter API เท่านั้น หมายเหตุ: คุณสมบัติที่มีคำนำหน้า |
scope | Internal : เฉพาะเจ้าของเท่านั้นที่สามารถเข้าถึงได้ |
prop_name | ชื่อของคุณสมบัติระบบพื้นฐาน เช่น ro.build.date |
enum_values | ( Enum , EnumList เท่านั้น) สตริงที่คั่นด้วยแถบ (|) ที่ประกอบด้วยค่าแจงนับที่เป็นไปได้ ตัวอย่างเช่น value1|value2 |
integer_as_bool | ( Boolean , BooleanList เท่านั้น) ให้ผู้ตั้งค่าใช้ 0 และ 1 แทน false และ true |
legacy_prop_name | (เป็นทางเลือก คุณสมบัติ Readonly อย่างเดียวเท่านั้น) ชื่อดั้งเดิมของคุณสมบัติระบบพื้นฐาน เมื่อเรียก getter getter API จะพยายามอ่าน prop_name และใช้ legacy_prop_name หากไม่มี prop_name ใช้ legacy_prop_name เมื่อเลิกใช้พร็อพเพอร์ตี้ที่มีอยู่และย้ายไปยังพร็อพเพอร์ตี้ใหม่ |
คุณสมบัติแต่ละประเภทแมปกับประเภทต่อไปนี้ใน C++, Java และ Rust
พิมพ์ | ซี++ | ชวา | สนิม |
---|---|---|---|
บูลีน | std::optional<bool> | Optional<Boolean> | bool |
จำนวนเต็ม | std::optional<std::int32_t> | Optional<Integer> | i32 |
UInt | std::optional<std::uint32_t> | Optional<Integer> | u32 |
ยาว | std::optional<std::int64_t> | Optional<Long> | i64 |
อู๋หลง | std::optional<std::uint64_t> | Optional<Long> | u64 |
สองเท่า | std::optional<double> | Optional<Double> | f64 |
สตริง | std::optional<std::string> | Optional<String> | String |
เอนัม | std::optional<{api_name}_values> | Optional<{api_name}_values> | {ApiName}Values |
ทีลิสต์ | std::vector<std::optional<T>> | List<T> | Vec<T> |
นี่คือตัวอย่างของไฟล์ Sysprop Description ที่กำหนดคุณสมบัติสามประการ:
# 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
}
การกำหนดไลบรารีคุณสมบัติระบบ
ตอนนี้คุณสามารถกำหนดโมดูล sysprop_library
ด้วยไฟล์ Sysprop Description sysprop_library
ทำหน้าที่เป็น API สำหรับ C++, Java และ Rust ระบบบิลด์ภายในจะสร้างหนึ่ง rust_library
หนึ่ง java_library
และหนึ่ง cc_library
สำหรับแต่ละอินสแตนซ์ของ sysprop_library
// File: Android.bp
sysprop_library {
name: "PlatformProperties",
srcs: ["android/sysprop/PlatformProperties.sysprop"],
property_owner: "Platform",
vendor_available: true,
}
คุณต้องรวมไฟล์รายการ API ไว้ในแหล่งที่มาสำหรับการตรวจสอบ API หากต้องการดำเนินการนี้ ให้สร้างไฟล์ API และไดเรกทอรี api
วางไดเร็กทอรี api
ไว้ในไดเร็กทอรีเดียวกันกับ Android.bp
ชื่อไฟล์ API คือ <module_name>-current.txt
, <module_name>-latest.txt
<module_name>-current.txt
เก็บลายเซ็น API ของซอร์สโค้ดปัจจุบัน และ <module_name>-latest.txt
เก็บลายเซ็น API ที่แช่แข็งล่าสุด ระบบบิลด์ตรวจสอบว่า API มีการเปลี่ยนแปลงหรือไม่โดยการเปรียบเทียบไฟล์ API เหล่านี้กับไฟล์ API ที่สร้างขึ้นในขณะสร้าง และส่งข้อความแสดงข้อผิดพลาดและคำแนะนำในการอัปเดตไฟล์ current.txt
หาก current.txt
ไม่ตรงกับซอร์สโค้ด นี่คือตัวอย่างไดเร็กทอรีและการจัดระเบียบไฟล์:
├── api
│ ├── PlatformProperties-current.txt
│ └── PlatformProperties-latest.txt
└── Android.bp
โมดูลไคลเอนต์ Rust, Java และ C++ สามารถเชื่อมโยงกับ sysprop_library
เพื่อใช้ API ที่สร้างขึ้น ระบบบิลด์สร้างลิงก์จากไคลเอนต์ไปยังไลบรารี C++, Java และ Rust ที่สร้างขึ้น ซึ่งทำให้ไคลเอนต์สามารถเข้าถึง API ที่สร้างขึ้นได้
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"],
}
โปรดทราบว่าชื่อไลบรารี Rust ถูกสร้างขึ้นโดยการแปลงชื่อ sysprop_library
เป็นตัวพิมพ์เล็ก โดยแทนที่ .
และ -
ด้วย _
จากนั้นเติม lib
และต่อท้าย _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);
}
…
}
ตัวอย่างจาวา:
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
);
}
…
}
…
ตัวอย่างภาษา 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);
}
…
}
…