एपीआई के तौर पर सिस्टम की प्रॉपर्टी को लागू करना

सिस्टम प्रॉपर्टी की मदद से, जानकारी आसानी से शेयर की जा सकती है. आम तौर पर, कॉन्फ़िगरेशन, पूरे सिस्टम पर. हर पार्टीशन अपनी सिस्टम प्रॉपर्टी का इस्तेमाल कर सकता है मिल सकता है. जब प्रॉपर्टी को सभी सेगमेंट में ऐक्सेस किया जाता है, तो समस्या हो सकती है. जैसे, /vendor से तय की गई प्रॉपर्टी ऐक्सेस करना. 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 की जानकारी वाली एक फ़ाइल में, प्रॉपर्टी का एक मैसेज होता है. इसमें प्रॉपर्टी के सेट के बारे में बताया जाता है. इसके फ़ील्ड के मतलब यहां दिए गए हैं.

फ़ील्ड मतलब
owner प्रॉपर्टी के मालिकाना हक वाले सेगमेंट पर सेट करें: Platform, Vendor या Odm.
module इसका इस्तेमाल नेमस्पेस (C++) या स्टैटिक फ़ाइनल क्लास (Java) बनाने में किया जाता है, जिनमें जनरेट किए गए एपीआई दिखाए जाते हैं. उदाहरण के लिए, com.android.sysprop.BuildProperties C++ में नेमस्पेस com::android::sysprop::BuildProperties होगा, और Java में पैकेज में BuildProperties क्लास, com.android.sysprop होगी.
prop प्रॉपर्टी की सूची.

Property मैसेज फ़ील्ड का मतलब यहां बताया गया है.

फ़ील्ड मतलब
api_name जनरेट किए गए एपीआई का नाम.
type इस प्रॉपर्टी का टाइप.
access Readonly: सिर्फ़ गेटर एपीआई जनरेट करता है
Writeonce, ReadWrite: गेटर और सेटर एपीआई जनरेट करता है
ध्यान दें: ro. प्रीफ़िक्स वाली प्रॉपर्टी का इस्तेमाल नहीं किया जा सकता ReadWrite का ऐक्सेस.
scope Internal: सिर्फ़ मालिक ही ऐक्सेस कर सकता है.
Public: एनडीके (NDK) मॉड्यूल को छोड़कर, कोई भी व्यक्ति ऐक्सेस कर सकता है.
prop_name सिस्टम की मौजूदा प्रॉपर्टी का नाम, उदाहरण के लिए ro.build.date.
enum_values (सिर्फ़ Enum, EnumList के लिए) बार(|) से अलग की गई स्ट्रिंग इसमें संभावित ईनम वैल्यू शामिल हों. उदाहरण के लिए, value1|value2.
integer_as_bool (सिर्फ़ Boolean, BooleanList के लिए) सेटर का इस्तेमाल करें false के बजाय 0 और 1 और true.
legacy_prop_name (ज़रूरी नहीं, सिर्फ़ Readonly प्रॉपर्टी) सिस्टम की प्रॉपर्टी. गैटर को कॉल करते समय, गैटर एपीआई पढ़ने की कोशिश करता है prop_name और legacy_prop_name का इस्तेमाल करता है, अगर prop_name मौजूद नहीं है. legacy_prop_name का इस्तेमाल तब करें, जब किसी मौजूदा प्रॉपर्टी को रोकने और नई प्रॉपर्टी का इस्तेमाल करने के लिए.

C++, Java, और Rust में हर तरह की प्रॉपर्टी, नीचे बताए गए टाइप से मैप होगी.

टाइप C++ Java रस्ट
बूलियन 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
Enum std::optional<{api_name}_values> Optional<{api_name}_values> {ApiName}Values
T सूची 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 की जानकारी वाली फ़ाइलों की मदद से, sysprop_library मॉड्यूल तय किए जा सकते हैं. 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);
    }
    …
}
…