सिस्टम गुणों को एपीआई के रूप में कार्यान्वित करना

सिस्टम गुण जानकारी साझा करने का एक सुविधाजनक तरीका प्रदान करते हैं, आमतौर पर कॉन्फ़िगरेशन, सिस्टम-व्यापी। प्रत्येक विभाजन आंतरिक रूप से अपने स्वयं के सिस्टम गुणों का उपयोग कर सकता है। समस्या तब हो सकती है जब संपत्तियों को विभाजनों के माध्यम से एक्सेस किया जाता है, जैसे /vendor /system -परिभाषित संपत्तियों तक पहुंच। एंड्रॉइड 8.0 के बाद से, कुछ विभाजन, जैसे /system , को अपग्रेड किया जा सकता है, जबकि /vendor अपरिवर्तित छोड़ दिया गया है। चूँकि सिस्टम गुण बिना किसी स्कीमा के स्ट्रिंग कुंजी/मान जोड़े का एक वैश्विक शब्दकोश मात्र हैं, इसलिए गुणों को स्थिर करना मुश्किल है। /system विभाजन उन गुणों को बदल या हटा सकता है जिन पर /vendor विभाजन बिना किसी सूचना के निर्भर करता है।

एंड्रॉइड 10 रिलीज के साथ शुरू करके, सभी विभाजनों में एक्सेस किए गए सिस्टम गुणों को Sysprop विवरण फ़ाइलों में योजनाबद्ध किया गया है, और गुणों तक पहुंचने के लिए एपीआई सी ++ और रस्ट के लिए ठोस फ़ंक्शन और जावा के लिए कक्षाओं के रूप में उत्पन्न होते हैं। ये एपीआई उपयोग करने के लिए अधिक सुविधाजनक हैं क्योंकि एक्सेस के लिए किसी जादुई स्ट्रिंग (जैसे ro.build.date ) की आवश्यकता नहीं होती है, और क्योंकि इन्हें स्थिर रूप से टाइप किया जा सकता है। निर्माण के समय एबीआई स्थिरता की भी जाँच की जाती है, और असंगत परिवर्तन होने पर निर्माण टूट जाता है। यह जाँच विभाजनों के बीच स्पष्ट रूप से परिभाषित इंटरफेस के रूप में कार्य करती है। ये एपीआई रस्ट, जावा और सी++ के बीच स्थिरता भी प्रदान कर सकते हैं।

सिस्टम गुणों को एपीआई के रूप में परिभाषित करना

सिस्टम गुणों को Sysprop विवरण फ़ाइलों ( .sysprop ) के साथ API के रूप में परिभाषित करें, जो निम्नलिखित स्कीमा के साथ प्रोटोबफ के टेक्स्टफॉर्मेट का उपयोग करते हैं:

// 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 एक नेमस्पेस (सी++) या स्टैटिक फाइनल क्लास (जावा) बनाने के लिए उपयोग किया जाता है जिसमें जेनरेट किए गए एपीआई रखे जाते हैं। उदाहरण के लिए, com.android.sysprop.BuildProperties C++ में नेमस्पेस com::android::sysprop::BuildProperties होगा, और Java में com.android.sysprop में पैकेज में BuildProperties क्लास होगा।
prop संपत्तियों की सूची.

Property संदेश फ़ील्ड के अर्थ इस प्रकार हैं।

मैदान अर्थ
api_name जनरेट की गई एपीआई का नाम.
type इस संपत्ति का प्रकार.
access Readonly : केवल गेटर एपीआई उत्पन्न करता है

Writeonce , ReadWrite : गेटर और सेटर एपीआई उत्पन्न करता है

नोट: उपसर्ग ro. ReadWrite एक्सेस का उपयोग नहीं किया जा सकता.

scope Internal : केवल स्वामी ही पहुंच सकता है।

Public : एनडीके मॉड्यूल को छोड़कर, हर कोई एक्सेस कर सकता है।

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 गुण) अंतर्निहित सिस्टम गुण का विरासती नाम। गेटर को कॉल करते समय, गेटर एपीआई prop_name पढ़ने की कोशिश करता है और यदि prop_name मौजूद नहीं है तो legacy_prop_name उपयोग करता है। किसी मौजूदा संपत्ति को हटाते समय और नई संपत्ति में स्थानांतरित करते समय legacy_prop_name उपयोग करें।

प्रत्येक प्रकार की संपत्ति 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
Enum std::optional<{api_name}_values> Optional<{api_name}_values> {ApiName}Values
टी सूची 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 के लिए API के रूप में कार्य करता है। बिल्ड सिस्टम आंतरिक रूप से 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

रस्ट, जावा और सी++ क्लाइंट मॉड्यूल जेनरेट किए गए एपीआई का उपयोग करने के लिए sysprop_library के विरुद्ध लिंक कर सकते हैं। बिल्ड सिस्टम क्लाइंट से जेनरेट किए गए C++, Java और रस्ट लाइब्रेरीज़ के लिए लिंक बनाता है, इस प्रकार क्लाइंट को जेनरेट किए गए 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"],
}

ध्यान दें कि रस्ट लाइब्रेरी का नाम 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
        );
    }
    …
}
…

सी++ उदाहरण:

#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);
    }
    …
}
…