Sistem özelliklerini API olarak uygulayın

Sistem özellikleri, genellikle bilgi paylaşımı için uygun bir yol sunar. yapılandırmalarına yardımcı olur. Her bölüm kendi sistem özelliklerini kullanabilir içten içe. Mülklere bölümler arasında erişildiğinde (ör. /vendor tarafından tanımlanan mülklere /system tarafından erişilmesi) bir sorun oluşabilir. Android 8.0'dan beri /system gibi bazı bölümler yükseltilebilir, ancak /vendor kaldı değişmedi. Sistem özellikleri yalnızca dizenin genel bir sözlüğü olduğundan anahtar/değer çiftleri içeriyorsa özelliklerin dengelenmesi zordur. İlgili içeriği oluşturmak için kullanılan /system bölümü, /vendor öğesinin etkinleştirebileceği özellikleri değiştirebilir veya kaldırabilir bağlı olarak değişiklik gösterebilir.

Android 10 sürümünden itibaren, bölümler arasında erişilen sistem özellikleri Sysprop Description dosyalarında şematize edilir ve özelliklere erişmek için API'ler C++ ve Rust için somut işlevler, Java için sınıflar olarak oluşturulur. Herhangi bir sihirbazlık olanağı olmadığı için bu API'lerin kullanımı daha kolaydır. dizeler (ro.build.date gibi) erişim için gereklidir ve otomatik olarak yazılır. Derleme sırasında ABI kararlılığı da kontrol edilir ve çalışmaya devam edebilir. Bu kontrol, açıkça tanımlanmış şekilde çalışır nasıl yapılandıracağınızı kontrol edin. Bu API'ler, aynı zamanda Rust, Java ve C++.

Sistem özelliklerini API olarak tanımlama

Sistem özelliklerini, aşağıdaki şemayı kullanan protobuf TextFormat'ı kullanan Sysprop Description dosyaları (.sysprop) ile API 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ı, grubudur. Alanlarının anlamı aşağıdaki gibidir.

Alan Anlamı
owner Şu mülklerin sahibi olan bölüm olarak ayarlandı: Platform, Vendor veya Odm.
module İçinde bulunduğunuz adın kullanıldığı bir ad alanı (C++) veya statik son sınıf (Java) oluşturmak için kullanılır. oluşturulan API'lerin yerleştirilmesine yardımcı olur. Örneğin, com.android.sysprop.BuildProperties C++'ta com::android::sysprop::BuildProperties ad alanı olacaktır ve paketteki BuildProperties sınıfını Java'da com.android.sysprop.
prop Tesis listesi.

Property mesaj alanlarının anlamları aşağıda verilmiştir.

Alan Anlamı
api_name Oluşturulan API'nin adı.
type Bu mülkün türü.
access Readonly: Yalnızca getter API oluşturur
Writeonce, ReadWrite: Alıcı ve belirleyici API'ler oluşturur
Not: ro. ön ekine sahip mülkler, ReadWrite erişim.
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 (Enum, yalnızca EnumList) Çubuk(|) ile ayrılmış bir dize olası enum değerlerinden oluşur. Örneğin, value1|value2.
integer_as_bool (Yalnızca Boolean, BooleanList) Setterleri kullan false ve yerine 0 ve 1 true.
legacy_prop_name (isteğe bağlı, yalnızca Readonly mülkleri) Etiketin eski adı temel sistem özelliğini kullanabilirsiniz. Alıcıyı çağırırken alıcı API'si prop_name ve aşağıdaki durumlarda legacy_prop_name kullanır prop_name mevcut değil. Şu durumlarda legacy_prop_name kullanın: mevcut bir mülkü kullanımdan kaldırıp yeni bir mülke taşıma

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

Tür C++ Java Rust
Boole std::optional<bool> Optional<Boolean> bool
Tam sayı std::optional<std::int32_t> Optional<Integer> i32
Kullanıcı arayüzü std::optional<std::uint32_t> Optional<Integer> u32
Uzun std::optional<std::int64_t> Optional<Long> i64
ULong std::optional<std::uint64_t> Optional<Long> u64
Çift std::optional<double> Optional<Double> f64
Dize std::optional<std::string> Optional<String> String
Enum 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ğini bulabilirsiniz:

# 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 özelliği kitaplıklarını tanımlama

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

// 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 listesi dosyaları eklemeniz gerekir. Bunu yapmak için API dosyaları ve api dizini oluşturabilirsiniz. api dizinini aynı klasöre koyun Android.bp olarak dizin. API dosya adları <module_name>-current.txt, <module_name>-latest.txt. API imzalarını <module_name>-current.txt barındırır güncel kaynak kodundan oluşur ve <module_name>-latest.txt dondurulmuş en son kodu barındırır API imzaları. Derleme sistemi API'lerin bu API dosyalarını, derleme sırasında oluşturulan API dosyalarıyla karşılaştırır ve current.txt durumunda hata mesajı ve current.txt dosyasını güncelleme talimatları kaynak kodlarıyla eşleşmiyor. Burada, örnek bir dizin ve dosya kuruluş:

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

Rust, Java ve C++ istemci modülleri, sysprop_library ile bağlantı kurarak API'lerden yararlanıldı. Derleme sistemi, istemcilerden oluşturulan C++, Java ve Rust kitaplıklarına bağlantılar oluşturur. Böylece istemcilere oluşturulan API'lere erişim izni verir.

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 dönüştürülerek oluşturulduğunu unutmayın önce . ve - yerine _, sonra da başa lib ve _rust ekleniyor.

Yukarıdaki örnekte, tanımlanan ö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);
    }
    …
}
…