APIs হিসাবে সিস্টেম বৈশিষ্ট্য প্রয়োগ করুন

সিস্টেম প্রোপার্টিজ (sysprops) সাধারণত কনফিগারেশনের মতো তথ্য সিস্টেমজুড়ে শেয়ার করার একটি সুবিধাজনক উপায় প্রদান করে। প্রতিটি পার্টিশন অভ্যন্তরীণভাবে তার নিজস্ব সিস্টেম প্রোপার্টিজ ব্যবহার করতে পারে। যখন বিভিন্ন পার্টিশনের মধ্যে প্রোপার্টিজ অ্যাক্সেস করা হয়, তখন একটি সমস্যা দেখা দিতে পারে, যেমন /vendor পার্টিশন যখন /system সংজ্ঞায়িত প্রোপার্টিজ অ্যাক্সেস করে। অ্যান্ড্রয়েড ৮.০ থেকে, /system এর মতো কিছু পার্টিশন আপগ্রেড করা গেলেও /vendor অপরিবর্তিত থাকে। যেহেতু সিস্টেম প্রোপার্টিজ হলো কোনো স্কিমা ছাড়া স্ট্রিং কী-ভ্যালু পেয়ারের একটি গ্লোবাল ডিকশনারি মাত্র, তাই প্রোপার্টিজ স্থিতিশীল রাখা কঠিন। /system পার্টিশন কোনো পূর্ব বিজ্ঞপ্তি ছাড়াই এমন প্রোপার্টিজ পরিবর্তন বা মুছে ফেলতে পারে, যার উপর /vendor পার্টিশন নির্ভরশীল।

অ্যান্ড্রয়েড ১০ এবং তার পরবর্তী সংস্করণগুলিতে, পার্টিশন জুড়ে অ্যাক্সেস করা সিস্টেম প্রোপার্টিগুলিকে sysprop ডেসক্রিপশন ফাইলে পরিকল্পিতভাবে সাজানো হয়, এবং প্রোপার্টিগুলি অ্যাক্সেস করার জন্য API-গুলি C++ ও Rust-এর জন্য কনক্রিট ফাংশন এবং Java-এর জন্য ক্লাস হিসাবে তৈরি করা হয়। এই API-গুলি ব্যবহার করা আরও সুবিধাজনক, কারণ অ্যাক্সেসের জন্য কোনো ম্যাজিক স্ট্রিং (যেমন ro.build.date ) প্রয়োজন হয় না এবং এগুলিকে স্ট্যাটিক্যালি টাইপ করা যায়। বিল্ড করার সময় ABI স্থিতিশীলতাও পরীক্ষা করা হয়, এবং যদি কোনো বেমানান পরিবর্তন ঘটে তবে বিল্ডটি ভেঙে যায়। এই পরীক্ষাটি পার্টিশনগুলির মধ্যে সুস্পষ্টভাবে সংজ্ঞায়িত ইন্টারফেস হিসাবে কাজ করে। এই API-গুলি Rust, Java এবং C++-এর মধ্যে সামঞ্জস্যও প্রদান করতে পারে।

সিস্টেম প্রোপার্টিগুলোকে API হিসেবে সংজ্ঞায়িত করুন

Sysprop Description ফাইল ( .sysprop ) ব্যবহার করে সিস্টেম প্রোপার্টিগুলোকে API হিসেবে সংজ্ঞায়িত করুন, যেগুলোর 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 বর্ণনা ফাইলে একটি properties message থাকে, যা একগুচ্ছ প্রপার্টির বর্ণনা দেয়। এর ফিল্ডগুলোর অর্থ নিম্নরূপ:

মাঠ অর্থ
owner যে পার্টিশনটি platform , vendor , বা odm প্রোপার্টিগুলোর মালিক, সেটিতে সেট করুন।
module এটি একটি নেমস্পেস (C++) বা স্ট্যাটিক ফাইনাল ক্লাস (Java) তৈরি করতে ব্যবহৃত হয়, যার মধ্যে জেনারেটেড এপিআইগুলো রাখা হয়। উদাহরণস্বরূপ, C++-এ com.android.sysprop.BuildProperties হলো com::android::sysprop::BuildProperties নেমস্পেসের অন্তর্গত, এবং Java-তে এটি com.android.sysprop প্যাকেজের BuildProperties ক্লাস।
prop বৈশিষ্ট্যসমূহের তালিকা।

Property মেসেজ ফিল্ডগুলোর অর্থ নিম্নরূপ:

মাঠ অর্থ
api_name তৈরি করা এপিআই-এর নাম।
type এই প্রপার্টির ধরণ।
access Readonly : শুধুমাত্র গেটার এপিআই তৈরি করে
Writeonce , ReadWrite : গেটার এবং সেটার এপিআই তৈরি করে
scope Internal : শুধুমাত্র মালিক প্রবেশ করতে পারবেন।
Public : এনডিকে মডিউলগুলো ছাড়া সবাই প্রবেশ করতে পারবে।
prop_name অন্তর্নিহিত সিস্টেম প্রপার্টির নাম, উদাহরণস্বরূপ ro.build.date
enum_values (শুধুমাত্র Enum , EnumList ) একটি বার(|) দ্বারা পৃথক করা স্ট্রিং যা সম্ভাব্য enum মানগুলো নিয়ে গঠিত। উদাহরণস্বরূপ, value1|value2
integer_as_bool (শুধুমাত্র BooleanBooleanList ) সেটারগুলোকে false এবং true এর পরিবর্তে 0 এবং 1 ব্যবহার করতে দিন।
legacy_prop_name (ঐচ্ছিক, শুধুমাত্র Readonly প্রপার্টির জন্য) অন্তর্নিহিত সিস্টেম প্রপার্টির লিগ্যাসি নাম। গেটার কল করার সময়, গেটার এপিআই prop_name পড়ার চেষ্টা করে এবং prop_name বিদ্যমান না থাকলে legacy_prop_name ব্যবহার করে। বিদ্যমান কোনো প্রপার্টি বাতিল করে নতুন প্রপার্টিতে যাওয়ার সময় legacy_prop_name ব্যবহার করুন।

C++, Java, এবং Rust-এ প্রতিটি ধরণের প্রপার্টি নিম্নলিখিত টাইপগুলোর সাথে ম্যাপ করা হয়:

প্রকার C++ (নালযোগ্য) জাভা (নালযোগ্য) রাস্ট (ঐচ্ছিক বা বাতিলযোগ্য)
বুলিয়ান std::optional<bool> Optional<Boolean> Option<bool>
পূর্ণসংখ্যা std::optional<std::int32_t> Optional<Integer> Option<i32>
ইউইন্ট std::optional<std::uint32_t> Optional<Integer> Option<u32>
দীর্ঘ std::optional<std::int64_t> Optional<Long> Option<i64>
ইউলং std::optional<std::uint64_t> Optional<Long> Option<u64>
দ্বিগুণ std::optional<double> Optional<Double> Option<f64>
স্ট্রিং std::optional<std::string> Optional<String> Option<String>
এনাম std::optional<{api\_name}\_values> Optional<{api\_name}\_values> Option<{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-এর জন্য একটি 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 ডিরেক্টরি তৈরি করুন। 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 সাথে লিঙ্ক করতে পারে। বিল্ড সিস্টেম ক্লায়েন্টদের জন্য জেনারেটেড সি++, জাভা এবং রাস্ট লাইব্রেরিতে লিঙ্ক তৈরি করে, যার ফলে ক্লায়েন্টরা জেনারেটেড এপিআইগুলো অ্যাক্সেস করতে পারে।

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"],
}

পূর্ববর্তী উদাহরণে, আপনি নিম্নলিখিতভাবে সংজ্ঞায়িত প্রোপার্টিগুলো অ্যাক্সেস করতে পারতেন।

রাস্টের উদাহরণ:

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

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