توفر خصائص النظام طريقة ملائمة لمشاركة المعلومات، عادةً
عمليات الضبط، على مستوى النظام. يمكن لكل قسم استخدام خصائص النظام الخاصة به داخليًا. قد تحدث مشكلة عند الوصول إلى الخصائص على مستوى الأقسام المختلفة،
مثل وصول /vendor
إلى الخصائص المحددة عبر /system
. بدءًا من الإصدار Android 8.0، يمكن ترقية
بعض الأقسام، مثل /system
، بينما يتم ترك /vendor
بدون تغيير. نظرًا لأن خصائص النظام هي مجرد قاموس عالمي لأزواج المفتاح
والقيمة بدون مخطط، فمن الصعب استقرار الخصائص. ويمكن أن يغيّر القسم /system
أو يزيل السمات التي يعتمد عليها القسم /vendor
بدون أي إشعار.
بدءًا من إصدار Android 10، يتم تخطيط خصائص النظام
التي يتم الوصول إليها على مستوى الأقسام في ملفات وصف Sysbro، ويتم إنشاء واجهات برمجة التطبيقات للوصول إلى الخصائص كوظائف ملموسة لكل من C++ وRust
وفئات لـ Java. إنّ استخدام واجهات برمجة التطبيقات هذه أكثر سهولة في الاستخدام لأنّه لا حاجة لاستخدام سلاسل سحرية (مثل ro.build.date
) للوصول إليها، ولأنّها يمكن كتابتها بشكل ثابت. يتم أيضًا التحقّق من ثبات واجهة التطبيق الثنائية (ABI) في وقت الإصدار، ويتعطّل الإصدار في حال حدوث تغييرات غير متوافقة. يعمل هذا الفحص كواجهات محددة
بشكل واضح بين الأقسام. ويمكن لواجهات برمجة التطبيقات هذه أيضًا توفير الاتساق بين Rust وJava وC++.
تحديد خصائص النظام كواجهات برمجة تطبيقات
عرِّف خصائص النظام كواجهات برمجة تطبيقات باستخدام ملفات وصف Sysbro (.sysprop
)، التي تستخدم TextFormat of 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;
}
يحتوي ملف وصف Syspr واحد على رسالة خصائص واحدة تصف مجموعة من الخصائص. وفي ما يلي معنى حقولها.
الحقل | المعنى |
---|---|
owner
|
اضبط السمة على القسم الذي يملك السمات: Platform أو Vendor أو Odm .
|
module
|
يتم استخدام البيانات لإنشاء مساحة اسم (C++ ) أو فئة نهائية ثابتة (Java) يتم فيها وضع واجهات برمجة التطبيقات التي تم إنشاؤها. على سبيل المثال، ستكون com.android.sysprop.BuildProperties
مساحة الاسم com::android::sysprop::BuildProperties في C++ ،
والفئة BuildProperties في الحزمة في
com.android.sysprop في Java.
|
prop
|
قائمة المواقع |
في ما يلي معاني حقول رسالة Property
.
الحقل | المعنى |
---|---|
api_name
|
اسم واجهة برمجة التطبيقات التي تم إنشاؤها. |
type
|
تمثّل هذه السمة نوع هذا الموقع. |
access
|
Readonly : إنشاء واجهة برمجة تطبيقات getter فقط
Writeonce ، ReadWrite : إنشاء واجهات برمجة تطبيقات getter وsetter
ملاحظة: المواقع التي تحمل البادئة ro. قد لا تستخدم إذن الوصول إلى
ReadWrite .
|
scope
|
Internal : يمكن للمالك فقط الوصول إليه.
Public : يمكن لجميع المستخدمين الوصول إلى المحتوى، باستثناء وحدات NDK.
|
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 قراءة prop_name وتستخدم legacy_prop_name في حال عدم توفّر prop_name . يمكنك استخدام السمة legacy_prop_name عند
إيقاف موقع حالي نهائيًا والانتقال إلى موقع جديد.
|
يتم تعيين كل نوع من المواقع للأنواع التالية في لغة C++ وJava وRust.
Type | C++ | Java | Rust |
---|---|---|---|
قيمة منطقية | std::optional<bool>
|
Optional<Boolean>
|
bool
|
عدد صحيح | std::optional<std::int32_t>
|
Optional<Integer>
|
i32
|
واجهة | 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
|
قائمة T | std::vector<std::optional<T>>
|
List<T>
|
Vec<T>
|
في ما يلي مثال على ملف وصف النظام الذي يحدد ثلاث خصائص:
# 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
باستخدام ملفات وصف SysPro.
تعمل sysprop_library
كواجهة برمجة تطبيقات للغة 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
في الدليل نفسه مثل Android.bp
. اسما ملفات واجهة برمجة التطبيقات هما <module_name>-current.txt
و<module_name>-latest.txt
. يحتوي <module_name>-current.txt
على توقيعات واجهة برمجة التطبيقات لرموز المصدر الحالية، بينما يحتفظ <module_name>-latest.txt
بأحدث توقيعات البيانات المجمّدة من واجهة برمجة التطبيقات. يتحقّق نظام التصميم مما إذا كان قد تم تغيير واجهات برمجة التطبيقات من خلال مقارنة ملفات واجهات برمجة التطبيقات هذه بملفات واجهة برمجة التطبيقات التي تم إنشاؤها، ثم يعرض رسالة خطأ وتعليمات لتعديل ملف current.txt
في حال عدم تطابق current.txt
مع رموز المصدر. فيما يلي مثال على مؤسسة
الدليل والملفات:
├── api
│ ├── PlatformProperties-current.txt
│ └── PlatformProperties-latest.txt
└── Android.bp
يمكن ربط وحدات برامج Rust وJava وC++ بـ sysprop_library
لاستخدام
واجهات برمجة التطبيقات التي تم إنشاؤها. ينشئ نظام التصميم روابط من العملاء إلى مكتبات C++
وJava وRust التي تم إنشاؤها، ما يتيح للعملاء الوصول إلى واجهات برمجة التطبيقات التي تم إنشاؤها.
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);
}
…
}
مثال على 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
);
}
…
}
…
مثال على 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);
}
…
}
…