توفّر خصائص النظام طريقة سهلة لمشاركة المعلومات، وعادةً ما تكون إعدادات على مستوى النظام. يمكن لكل قسم استخدام خصائص النظام الخاصة به داخليًا. قد تحدث مشكلة عند الوصول إلى السمات في أقسام مختلفة،
مثل وصول /vendor
إلى السمات المحدّدة في /system
. منذ الإصدار 8.0 من Android،
يمكن ترقية بعض الأقسام، مثل /system
، بينما يظل /vendor
بدون تغيير. وبما أنّ خصائص النظام هي مجرد قاموس عام لأزواج السلسلة الرئيسية والقيمة بدون مخطط، يصعب تثبيت الخصائص. قد يغيّر القسم /system
أو يزيل الخصائص التي يعتمد عليها القسم /vendor
بدون أي إشعار.
بدءًا من إصدار Android 10، يتم وضع مخطط لخصائص النظام التي يتم الوصول إليها في جميع الأقسام في ملفات وصف Sysprop، ويتم إنشاء واجهات برمجة التطبيقات للوصول إلى الخصائص كدوال ملموسة للغة C++ وRust، وفئات للغة Java. تتميّز واجهات برمجة التطبيقات هذه بسهولة الاستخدام لأنّها لا تتطلّب سلاسل سحرية (مثل ro.build.date
) للوصول إليها، ولأنّه يمكن كتابة أنواعها بشكل ثابت. يتم أيضًا التحقّق من ثبات واجهة التطبيق الثنائية (ABI) في وقت الإنشاء، ويتعذّر إنشاء التطبيق إذا حدثت تغييرات غير متوافقة. يعمل هذا الفحص كواجهات محددة بشكل صريح بين الأقسام. ويمكن أن توفّر واجهات برمجة التطبيقات هذه أيضًا اتساقًا بين Rust وJava وC++.
تحديد خصائص النظام على أنّها واجهات برمجة تطبيقات
حدِّد سمات النظام على أنّها واجهات برمجة تطبيقات تتضمّن ملفات وصف Sysprop (.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 على رسالة خصائص واحدة، والتي تصف مجموعة من الخصائص. في ما يلي معنى حقولها.
الحقل | المعنى |
---|---|
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.
النوع | 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
|
ULong | 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 List | std::vector<std::optional<T>>
|
List<T>
|
Vec<T>
|
في ما يلي مثال على ملف وصف Sysprop يحدّد ثلاث سمات:
# 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.
تعمل 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: ["libPlatformProperties"],
}
rust_binary {
name: "rust_client",
srcs: ["src/main.rs"],
rustlibs: ["libplatformproperties_rust"],
}
يُرجى العِلم أنّه يتم إنشاء اسم مكتبة Rust من خلال تحويل sysprop_library
الاسم إلى أحرف صغيرة، واستبدال .
و-
بـ _
، ثم إضافة lib
في البداية و_rust
في النهاية.
في المثال السابق، يمكنك الوصول إلى السمات المحدّدة على النحو التالي.
مثال على 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);
}
…
}
…