Sistem Özelliklerini API'ler Olarak Uygulamak,Sistem Özelliklerini API'ler Olarak Uygulamak

Sistem özellikleri, genellikle konfigürasyonlar olmak üzere sistem çapında bilgi paylaşımı için uygun bir yol sağlar. Her bölüm kendi sistem özelliklerini dahili olarak kullanabilir. /vendor /system tanımlı özelliklere erişmesi gibi özelliklere bölümler arasında erişildiğinde bir sorun ortaya çıkabilir. Android 8.0'dan bu yana, /system gibi bazı bölümler yükseltilebilirken /vendor değişmeden bırakılır. Sistem özellikleri, şeması olmayan, yalnızca dize anahtar/değer çiftlerinden oluşan genel bir sözlük olduğundan, özellikleri dengelemek zordur. /system bölümü, /vendor bölümünün bağlı olduğu özellikleri herhangi bir bildirimde bulunmaksızın değiştirebilir veya kaldırabilir.

Android 10 sürümünden başlayarak, bölümler arasında erişilen sistem özellikleri Sysprop Açıklama dosyaları halinde şematize edilir ve özelliklere erişim için API'ler, C++ ve Rust için somut işlevler ve Java için sınıflar olarak oluşturulur. Erişim için sihirli dizelere ( ro.build.date gibi) ihtiyaç duyulmadığından ve statik olarak yazılabildiklerinden bu API'lerin kullanımı daha uygundur. ABI kararlılığı aynı zamanda derleme sırasında da kontrol edilir ve uyumsuz değişiklikler meydana gelirse derleme kesilir. Bu kontrol, bölümler arasında açıkça tanımlanmış arayüzler olarak işlev görür. Bu API'ler aynı zamanda Rust, Java ve C++ arasında tutarlılık da sağlayabilir.

Sistem özelliklerini API olarak tanımlama

Sistem özelliklerini, aşağıdaki şemayla protobuf'un TextFormat'ını kullanan Sysprop Açıklama dosyalarına ( .sysprop ) sahip API'ler olarak tanımlayın:

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

Bir Sysprop Açıklama dosyası, bir dizi özelliği açıklayan bir özellikler mesajı içerir. Alanlarının anlamları aşağıdaki gibidir.

Alan Anlam
owner Şu özelliklere sahip olan bölüme ayarlayın: Platform , Vendor veya Odm .
module Oluşturulan API'lerin yerleştirildiği bir ad alanı (C++) veya statik son sınıf (Java) oluşturmak için kullanılır. Örneğin, com.android.sysprop.BuildProperties , C++'da com::android::sysprop::BuildProperties ad alanı ve Java'da com.android.sysprop pakette BuildProperties sınıfı olacaktır.
prop Özelliklerin listesi.

Property mesaj alanlarının anlamları aşağıdaki gibidir.

Alan Anlam
api_name Oluşturulan API'nin adı.
type Bu özelliğin türü.
access Readonly : Yalnızca alıcı API'sini oluşturur

Writeonce , ReadWrite : Alıcı ve ayarlayıcı API'leri oluşturur

Not: ro. Okuma ReadWrite erişimini kullanamaz.

scope Internal : Yalnızca sahibi erişebilir.

Public : NDK modülleri dışında herkes erişebilir.

prop_name Temel sistem özelliğinin adı, örneğin ro.build.date .
enum_values ( Yalnızca Enum , EnumList ) Olası numaralandırma değerlerinden oluşan çubuk(|) ile ayrılmış bir dize. Örneğin value1|value2 .
integer_as_bool (Yalnızca Boolean , BooleanList ) Ayarlayıcıların false ve true yerine 0 ve 1 kullanmasını sağlayın.
legacy_prop_name (isteğe bağlı, Yalnızca Readonly özellikler) Temel sistem özelliğinin eski adı. Alıcıyı çağırırken, alıcı API'si prop_name okumaya çalışır ve prop_name yoksa, legacy_prop_name kullanır. Mevcut bir mülkü kullanımdan kaldırırken ve yeni bir mülke taşırken legacy_prop_name kullanın.

Her özellik türü C++, Java ve Rust'ta aşağıdaki türlerle eşlenir.

Tip C++ Java Pas
Boolean std::optional<bool> Optional<Boolean> bool
Tamsayı std::optional<std::int32_t> Optional<Integer> i32
Unt std::optional<std::uint32_t> Optional<Integer> u32
Uzun std::optional<std::int64_t> Optional<Long> i64
Uuzun std::optional<std::uint64_t> Optional<Long> u64
Çift std::optional<double> Optional<Double> f64
Sicim std::optional<std::string> Optional<String> String
Sıralama std::optional<{api_name}_values> Optional<{api_name}_values> {ApiName}Values
T Listesi std::vector<std::optional<T>> List<T> Vec<T>

Burada üç özelliği tanımlayan bir Sysprop Açıklama dosyası örneği verilmiştir:

# 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
}

Sistem özellikleri kitaplıklarını tanımlama

Artık sysprop_library modüllerini Sysprop Açıklama dosyalarıyla tanımlayabilirsiniz. sysprop_library , C++, Java ve Rust için bir API görevi görür. Derleme sistemi dahili olarak her sysprop_library örneği için bir rust_library , bir java_library ve bir cc_library oluşturur.

// File: Android.bp
sysprop_library {
    name: "PlatformProperties",
    srcs: ["android/sysprop/PlatformProperties.sysprop"],
    property_owner: "Platform",
    vendor_available: true,
}

API kontrolleri için kaynağa API listeleri dosyalarını dahil etmeniz gerekir. Bunu yapmak için API dosyaları ve bir api dizini oluşturun. api dizinini Android.bp ile aynı dizine yerleştirin. API dosya adları <module_name>-current.txt , <module_name>-latest.txt şeklindedir. <module_name>-current.txt geçerli kaynak kodlarının API imzalarını tutar ve <module_name>-latest.txt en son dondurulmuş API imzalarını tutar. Derleme sistemi, bu API dosyalarını derleme sırasında oluşturulan API dosyalarıyla karşılaştırarak API'lerin değişip değişmediğini kontrol eder ve current.txt kaynak kodlarıyla eşleşmezse current.txt dosyasını güncellemek için bir hata mesajı ve talimatlar verir. Aşağıda örnek bir dizin ve dosya organizasyonu verilmiştir:

├── api
│   ├── PlatformProperties-current.txt
│   └── PlatformProperties-latest.txt
└── Android.bp

Rust, Java ve C++ istemci modülleri, oluşturulan API'leri kullanmak için sysprop_library bağlanabilir. Derleme sistemi, istemcilerden oluşturulan C++, Java ve Rust kitaplıklarına bağlantılar oluşturarak müşterilerin oluşturulan API'lere erişmesini sağlar.

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 kitaplığı adının, sysprop_library adının yerine küçük harfe dönüştürülmesiyle oluşturulduğunu unutmayın . ve - _ ile ve ardından lib başına ve _rust eklenmesi.

Yukarıdaki örnekte tanımlı özelliklere aşağıdaki gibi erişebilirsiniz.

Pas örneği:

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 örneği:

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++ örneği:

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