ویژگی های سیستم راهی مناسب برای به اشتراک گذاشتن اطلاعات، معمولاً پیکربندی ها، در سراسر سیستم فراهم می کند. هر پارتیشن می تواند از ویژگی های سیستم خود به صورت داخلی استفاده کند. هنگامی که ویژگیها از طریق پارتیشنها قابل دسترسی هستند، مانند /vendor
دسترسی به /system
-defined ویژگیها، ممکن است مشکلی رخ دهد. از اندروید 8.0، برخی از پارتیشنها، مانند /system
را میتوان ارتقا داد، در حالی که /vendor
بدون تغییر باقی میماند. از آنجایی که ویژگیهای سیستم فقط یک فرهنگ لغت جهانی از جفتهای کلید-مقدار رشتهای هستند که هیچ طرحی ندارند، تثبیت ویژگیها دشوار است. پارتیشن /system
میتواند ویژگیهایی را که پارتیشن /vendor
به آنها وابسته است، بدون اطلاع قبلی تغییر دهد یا حذف کند.
با شروع نسخه اندروید 10، ویژگیهای سیستمی که از طریق پارتیشنها قابل دسترسی هستند، در فایلهای Sysprop Description شماتیک میشوند و APIها برای دسترسی به ویژگیها به عنوان توابع مشخص برای C++ و Rust و کلاسهایی برای جاوا تولید میشوند. استفاده از این 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++) یا کلاس نهایی ثابت (جاوا) استفاده می شود که در آن APIهای تولید شده قرار می گیرند. به عنوان مثال، com.android.sysprop.BuildProperties فضای نام com::android::sysprop::BuildProperties در C++ و کلاس BuildProperties در بسته در com.android.sysprop در جاوا خواهد بود. |
prop | لیست املاک. |
معانی فیلدهای پیام Property
به شرح زیر است.
میدان | معنی |
---|---|
api_name | نام API ایجاد شده. |
type | نوع این ملک. |
access | Readonly : فقط API دریافت کننده را ایجاد می کندWriteonce ، ReadWrite : API های گیرنده و تنظیم کننده را تولید می کندتوجه: خواص با پیشوند ro. ممکن است از دسترسی ReadWrite استفاده نکند. |
scope | Internal : فقط مالک می تواند دسترسی داشته باشد.Public : همه می توانند دسترسی داشته باشند، به جز ماژول های NDK. |
prop_name | نام ویژگی سیستم زیربنایی، به عنوان مثال ro.build.date . |
enum_values | ( Enum , EnumList فقط) یک رشته جدا شده با نوار(|) که از مقادیر enum ممکن تشکیل شده است. برای مثال value1|value2 . |
integer_as_bool | (فقط Boolean ، BooleanList ) تنظیمکنندهها از 0 و 1 به جای false و true استفاده کنند. |
legacy_prop_name | (اختیاری، فقط ویژگی های Readonly ) نام قدیمی ویژگی سیستم زیربنایی. هنگام فراخوانی getter، API دریافت کننده سعی می کند prop_name بخواند و اگر prop_name وجود نداشته باشد legacy_prop_name استفاده می کند. از legacy_prop_name هنگام منسوخ کردن یک ویژگی موجود و انتقال به یک ویژگی جدید استفاده کنید. |
هر نوع ویژگی به انواع زیر در C++، Java و Rust نگاشت می شود.
تایپ کنید | C++ | جاوا | زنگ زدگی |
---|---|---|---|
بولی | 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 |
ULong | std::optional<std::uint64_t> | Optional<Long> | u64 |
دوبل | std::optional<double> | Optional<Double> | f64 |
رشته | std::optional<std::string> | Optional<String> | String |
Enum | 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++، جاوا و 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++، جاوا و 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);
}
…
}
…