सिस्टम प्रॉपर्टी की मदद से, सिस्टम-वाइड जानकारी शेयर करना आसान हो जाता है. आम तौर पर, यह जानकारी कॉन्फ़िगरेशन होती है. हर पार्टीशन, सिस्टम की अपनी प्रॉपर्टी का इस्तेमाल अंदरूनी तौर पर कर सकता है. जब अलग-अलग पार्टीशन में मौजूद प्रॉपर्टी को ऐक्सेस किया जाता है, तब समस्या हो सकती है. जैसे, /vendor
से तय की गई प्रॉपर्टी को ऐक्सेस करना./system
Android 8.0 के बाद से, कुछ पार्टिशन, जैसे कि /system
को अपग्रेड किया जा सकता है. वहीं, /vendor
में कोई बदलाव नहीं किया जाता. सिस्टम प्रॉपर्टी, स्ट्रिंग की-वैल्यू पेयर की सिर्फ़ एक ग्लोबल डिक्शनरी होती है. इसमें कोई स्कीमा नहीं होता. इसलिए, प्रॉपर्टी को स्थिर करना मुश्किल होता है. /system
पार्टीशन, उन प्रॉपर्टी को बदल सकता है या हटा सकता है जिन पर /vendor
पार्टीशन निर्भर करता है. इसके लिए, वह कोई सूचना नहीं देगा.
Android 10 के रिलीज़ होने के बाद से, सभी पार्टीशन में ऐक्सेस की गई सिस्टम प्रॉपर्टी को Sysprop Description फ़ाइलों में व्यवस्थित किया जाता है. साथ ही, प्रॉपर्टी को ऐक्सेस करने के लिए एपीआई, C++ और Rust के लिए कॉन्क्रीट फ़ंक्शन के तौर पर और Java के लिए क्लास के तौर पर जनरेट किए जाते हैं. इन एपीआई का इस्तेमाल करना ज़्यादा आसान है, क्योंकि इन्हें ऐक्सेस करने के लिए किसी मैजिक स्ट्रिंग (जैसे कि ro.build.date
) की ज़रूरत नहीं होती. साथ ही, इन्हें स्टैटिक टाइप किया जा सकता है. बिल्ड के समय भी एबीआई की स्थिरता की जांच की जाती है. अगर एबीआई में ऐसे बदलाव होते हैं जो काम नहीं करते, तो बिल्ड रुक जाता है. यह जांच, पार्टीशन के बीच इंटरफ़ेस के तौर पर काम करती है. ये एपीआई, Rust, Java, और C++ के बीच एक जैसा अनुभव देने में भी मदद कर सकते हैं.
सिस्टम प्रॉपर्टी को एपीआई के तौर पर तय करना
सिस्टम प्रॉपर्टी को Sysprop Description फ़ाइलों (.sysprop
) के साथ एपीआई के तौर पर तय करें. ये फ़ाइलें, protobuf के TextFormat का इस्तेमाल करती हैं. इनका स्कीमा यह है:
// 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 फ़ाइल में एक Properties मैसेज होता है. इसमें प्रॉपर्टी के सेट के बारे में जानकारी होती है. इसके फ़ील्ड का मतलब यहां दिया गया है.
फ़ील्ड | मतलब |
---|---|
owner
|
उस पार्टीशन पर सेट करें जिसके पास प्रॉपर्टी हैं: Platform ,
Vendor या Odm .
|
module
|
इसका इस्तेमाल, C++ में नेमस्पेस या Java में स्टैटिक फ़ाइनल क्लास बनाने के लिए किया जाता है. इसमें जनरेट किए गए एपीआई रखे जाते हैं. उदाहरण के लिए,
com.android.sysprop.BuildProperties
C++ में com::android::sysprop::BuildProperties नेमस्पेस होगा,
और Java में com.android.sysprop पैकेज में BuildProperties क्लास होगा.
|
prop
|
प्रॉपर्टी की सूची. |
Property
मैसेज फ़ील्ड के मतलब यहां दिए गए हैं.
फ़ील्ड | मतलब |
---|---|
api_name
|
जनरेट किए गए एपीआई का नाम. |
type
|
यह प्रॉपर्टी किस तरह की है. |
access
|
Readonly : सिर्फ़ getter API जनरेट करता है
Writeonce , ReadWrite : getter और setter API जनरेट करता है
ध्यान दें: ro. प्रीफ़िक्स वाली प्रॉपर्टी, ReadWrite ऐक्सेस का इस्तेमाल नहीं कर सकती हैं.
|
scope
|
Internal : इसे सिर्फ़ मालिक ऐक्सेस कर सकता है.
Public : NDK मॉड्यूल को छोड़कर, हर कोई इसे ऐक्सेस कर सकता है.
|
prop_name
|
सिस्टम प्रॉपर्टी का नाम. उदाहरण के लिए, ro.build.date .
|
enum_values
|
(सिर्फ़ Enum , EnumList के लिए) बार(|) से अलग की गई स्ट्रिंग
जिसमें संभावित enum वैल्यू शामिल होती हैं. उदाहरण के लिए, value1|value2 .
|
integer_as_bool
|
(सिर्फ़ Boolean , BooleanList के लिए) सेटर को false और true के बजाय 0 और 1 का इस्तेमाल करने के लिए कहें.
|
legacy_prop_name
|
(ज़रूरी नहीं, सिर्फ़ Readonly प्रॉपर्टी के लिए) यह अंडरलाइंग सिस्टम प्रॉपर्टी का लेगसी नाम है. गेटर को कॉल करते समय, Getter API prop_name को पढ़ने की कोशिश करता है. अगर prop_name मौजूद नहीं है, तो वह legacy_prop_name का इस्तेमाल करता है. किसी मौजूदा प्रॉपर्टी को बंद करके नई प्रॉपर्टी पर माइग्रेट करते समय, legacy_prop_name का इस्तेमाल करें.
|
हर तरह की प्रॉपर्टी, C++, Java, और Rust में इन टाइप के साथ मैप होती है.
टाइप | C++ | Java | रस्ट |
---|---|---|---|
बूलियन | 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 Description फ़ाइलों की मदद से, sysprop_library
मॉड्यूल तय किए जा सकते हैं.
sysprop_library
, C++, Java, और Rust के लिए एपीआई के तौर पर काम करता है. बिल्ड सिस्टम, sysprop_library
के हर इंस्टेंस के लिए, अंदरूनी तौर पर एक rust_library
, एक java_library
, और एक cc_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);
}
…
}
…