Veri Türleri

Bu bölümde HIDL veri türleri açıklanmaktadır. Uygulama ayrıntıları için bkz. HIDL C++ (C++ uygulamaları için) veya HIDL Java (Java uygulamaları için).

C++ ile benzerlikler şunları içerir:

  • structs C++ sözdizimini kullanır; unions varsayılan olarak C++ sözdizimini destekler. Her ikisinin de adlandırılması gerekir; anonim yapılar ve birleşimler desteklenmez.
  • HIDL'de tip tanımlarına izin verilir (C++'da olduğu gibi).
  • C++ tarzı yorumlara izin verilir ve oluşturulan başlık dosyasına kopyalanır.

Java ile benzerlikler şunları içerir:

  • HIDL, her dosya için android.hardware. . Oluşturulan C++ ad alanı ::android::hardware::… .
  • Dosyanın tüm tanımları Java tarzı bir interface sarmalayıcısında bulunur.
  • HIDL dizisi bildirimleri C++ stilini değil Java stilini izler. Örnek:
    struct Point {
        int32_t x;
        int32_t y;
    };
    Point[3] triangle;   // sized array
    
  • Yorumlar javadoc formatına benzer.

Temsili veri

Standart Düzen'den (düz eski veri türlerinin gereksinimlerinin bir alt kümesi) oluşan bir struct veya union , oluşturulan C++ kodunda struct ve union üyelerinde açık hizalama nitelikleriyle uygulanan tutarlı bir bellek düzenine sahiptir.

İlkel HIDL türlerinin yanı sıra enum ve bitfield türleri (her zaman ilkel türlerden türetilir), cstdint'ten std::uint32_t gibi standart C++ türleriyle eşlenir.

Java imzasız türleri desteklemediğinden, imzasız HIDL türleri karşılık gelen imzalı Java türüyle eşlenir. Yapılar Java sınıflarıyla eşleşir; diziler Java dizileriyle eşleşir; birleşimler şu anda Java'da desteklenmemektedir. Dizeler dahili olarak UTF8 olarak saklanır. Java yalnızca UTF16 dizelerini desteklediğinden, bir Java uygulamasına gönderilen veya Java uygulamasından gönderilen dize değerleri çevrilir ve karakter kümeleri her zaman düzgün şekilde eşlenmediğinden yeniden çeviride aynı olmayabilir.

C++'da IPC üzerinden alınan veriler const olarak işaretlenir ve yalnızca işlev çağrısı süresince kalıcı olan salt okunur bellekte bulunur. Java'da IPC üzerinden alınan veriler zaten Java nesnelerine kopyalanmıştır, dolayısıyla ek kopyalamaya gerek kalmadan saklanabilir (ve değiştirilebilir).

Ek açıklamalar

Tür bildirimlerine Java tarzı açıklamalar eklenebilir. Ek açıklamalar, HIDL derleyicisinin Satıcı Test Paketi (VTS) arka ucu tarafından ayrıştırılır, ancak bu tür ayrıştırılan ek açıklamaların hiçbiri aslında HIDL derleyicisi tarafından anlaşılmaz. Bunun yerine, ayrıştırılmış VTS ek açıklamaları VTS Derleyicisi (VTSC) tarafından işlenir.

Ek açıklamalar Java sözdizimini kullanır: @annotation veya @annotation(value) veya @annotation(id=value, id=value…) burada değer, tıpkı aşağıdaki gibi, sabit bir ifade, bir dize veya {} içindeki bir değerler listesi olabilir. Java. Aynı öğeye aynı adda birden fazla ek açıklama eklenebilir.

İleri beyanlar

HIDL'de yapılar ileri bildirimli olmayabilir, bu da kullanıcı tanımlı, kendine referanslı veri türlerini imkansız hale getirir (örneğin, HIDL'de bağlantılı bir listeyi veya bir ağacı tanımlayamazsınız). Mevcut (Android 8.x öncesi) HAL'lerin çoğu, ileri bildirimlerin sınırlı kullanımına sahiptir ve bu, veri yapısı bildirimlerinin yeniden düzenlenmesiyle kaldırılabilir.

Bu kısıtlama, kendine referanslı bir veri yapısında birden çok kez oluşabilecek işaretçi değerlerinin izini sürmek yerine, veri yapılarının basit bir derin kopya ile değere göre kopyalanmasına olanak tanır. Aynı veri iki yöntem parametresi veya aynı veriye işaret eden vec<T> ile iki kez iletilirse, iki ayrı kopya oluşturulur ve teslim edilir.

İç içe bildirimler

HIDL, iç içe bildirimleri istenilen düzeyde destekler (aşağıda belirtilen bir istisna dışında). Örneğin:

interface IFoo {
    uint32_t[3][4][5][6] multidimArray;

    vec<vec<vec<int8_t>>> multidimVector;

    vec<bool[4]> arrayVec;

    struct foo {
        struct bar {
            uint32_t val;
        };
        bar b;
    }
    struct baz {
        foo f;
        foo.bar fb; // HIDL uses dots to access nested type names
    }
    …

Bunun istisnası, arayüz türlerinin yalnızca vec<T> içine ve yalnızca bir düzey derinliğe gömülebilmesidir ( vec<vec<IFoo>> yok).

Ham işaretçi sözdizimi

HIDL dili * kullanmaz ve C/C++ ham işaretçilerinin tam esnekliğini desteklemez. HIDL'nin işaretçileri ve dizileri/vektörleri nasıl kapsüllediğine ilişkin ayrıntılar için bkz. vec<T> şablonu .

Arayüzler

interface anahtar sözcüğünün iki kullanımı vardır.

  • Bir .hal dosyasındaki arayüzün tanımını açar.
  • Yapı/birlik alanlarında, yöntem parametrelerinde ve dönüşlerde özel bir tür olarak kullanılabilir. Genel bir arayüz ve android.hidl.base@1.0::IBase ile eşanlamlı olarak görülüyor.

Örneğin, IServiceManager aşağıdaki yönteme sahiptir:

get(string fqName, string name) generates (interface service);

Yöntem, bazı arayüzleri ada göre aramayı vaat ediyor. Arayüzü android.hidl.base@1.0::IBase ile değiştirmek de aynıdır.

Arayüzler yalnızca iki şekilde iletilebilir: üst düzey parametreler olarak veya bir vec<IMyInterface> üyesi olarak. İç içe geçmiş vec'lerin, yapıların, dizilerin veya birliklerin üyesi olamazlar.

MQDescriptorSync ve MQDescriptorUnsync

MQDescriptorSync ve MQDescriptorUnsync türleri, bir HIDL arayüzü üzerinden senkronize edilmiş veya senkronize edilmemiş bir Hızlı Mesaj Kuyruğu (FMQ) tanımlayıcılarını iletir. Ayrıntılar için bkz. HIDL C++ (FMQ'lar Java'da desteklenmez).

bellek türü

memory türü, HIDL'de eşlenmemiş paylaşılan belleği temsil etmek için kullanılır. Yalnızca C++'da desteklenir. Bu türden bir değer, alıcı tarafta bir IMemory nesnesini başlatmak, belleği eşlemek ve kullanılabilir hale getirmek için kullanılabilir. Ayrıntılar için bkz. HIDL C++ .

Uyarı: Paylaşılan belleğe yerleştirilen yapılandırılmış veriler, memory geçen arayüz sürümünün ömrü boyunca formatı asla değişmeyecek bir tür OLMALIDIR. Aksi takdirde HAL'ler ölümcül uyumluluk sorunları yaşayabilir.

işaretçi türü

pointer türü yalnızca HIDL dahili kullanımı içindir.

bitfield<T> türü şablonu

T kullanıcı tanımlı bir numaralandırma olduğu bitfield<T> değerin T içinde tanımlanan numaralandırma değerlerinin bit düzeyinde VEYA olduğunu gösterir. Oluşturulan kodda bitfield<T> T'nin temel türü olarak görünür. Örneğin:

enum Flag : uint8_t {
    HAS_FOO = 1 << 0,
    HAS_BAR = 1 << 1,
    HAS_BAZ = 1 << 2
};
typedef bitfield<Flag> Flags;
setFlags(Flags flags) generates (bool success);

Derleyici, Flags türünü uint8_t ile aynı şekilde işler.

Neden (u)int8_t / (u)int16_t / (u)int32_t / (u)int64_t kullanmıyorsunuz? bitfield kullanılması, setFlags Flag'in bit düzeyinde VEYA değerini aldığını artık bilen okuyucuya ek HAL bilgisi sağlar (yani setFlags 16 ile çağırmanın geçersiz olduğunu bilir). bitfield olmadan bu bilgiler yalnızca dokümantasyon yoluyla aktarılır. Ek olarak VTS, bayrakların değerinin Bayrağın bit düzeyinde VEYA olup olmadığını gerçekten kontrol edebilir.

ilkel türü ele al

UYARI: Her türlü adres (fiziksel cihaz adresleri bile) hiçbir zaman yerel tanıtıcının parçası olmamalıdır. Bu bilgilerin süreçler arasında aktarılması tehlikelidir ve onları saldırıya açık hale getirir. İşlemler arasında iletilen herhangi bir değer, bir işlem içinde tahsis edilen belleği aramak için kullanılmadan önce doğrulanmalıdır. Aksi takdirde hatalı tanıtıcılar hatalı belleğe erişime veya belleğin bozulmasına neden olabilir.

HIDL semantiği değere göre kopyalanır, bu da parametrelerin kopyalandığı anlamına gelir. Büyük veri parçaları veya işlemler arasında paylaşılması gereken veriler (bir senkronizasyon çiti gibi), kalıcı nesnelere işaret eden dosya tanımlayıcılarının etrafından geçirilerek işlenir: paylaşılan bellek için ashmem , gerçek dosyalar veya arkasına saklanabilecek başka herhangi bir şey. bir dosya tanımlayıcı. Ciltleyici sürücüsü, dosya tanımlayıcısını diğer işleme kopyalar.

native_handle_t

Android, libcutils tanımlanan genel bir tanıtıcı kavramı olan native_handle_t öğesini destekler.

typedef struct native_handle
{
  int version;        /* sizeof(native_handle_t) */
  int numFds;         /* number of file-descriptors at &data[0] */
  int numInts;        /* number of ints at &data[numFds] */
  int data[0];        /* numFds + numInts ints */
} native_handle_t;

Yerel tanıtıcı, değere göre aktarılan bir int ve dosya tanımlayıcı koleksiyonudur. Tek bir dosya tanımlayıcı, ints olmadan ve tek bir dosya tanımlayıcıyla yerel bir tanıtıcıda saklanabilir. handle temel türüyle kapsüllenmiş yerel tanıtıcıları kullanan tanıtıcıların geçirilmesi, yerel tanıtıcıların doğrudan HIDL'ye dahil edilmesini sağlar.

Bir native_handle_t değişken boyuta sahip olduğundan doğrudan yapıya dahil edilemez. Bir tanıtıcı alanı, ayrı olarak tahsis edilmiş bir native_handle_t için bir işaretçi oluşturur.

Android'in önceki sürümlerinde, libcutils'de bulunan aynı işlevler kullanılarak yerel tanıtıcılar oluşturuldu. Android 8.0 ve üzeri sürümlerde, bu işlevler artık android::hardware::hidl ad alanına kopyalanmıştır veya NDK'ya taşınmıştır. HIDL otomatik olarak oluşturulan kod, bu işlevleri kullanıcı tarafından yazılan kodun katılımı olmadan otomatik olarak serileştirir ve seri durumdan çıkarır.

Tanıtıcı ve dosya tanımlayıcı sahipliği

Bir hidl_handle nesnesini (üst düzey veya bileşik türün bir parçası) ileten (veya döndüren) bir HIDL arabirim yöntemini çağırdığınızda, içinde bulunan dosya tanımlayıcıların sahipliği aşağıdaki gibidir:

  • Bağımsız değişken olarak bir hidl_handle nesnesini ileten çağıran , sardığı native_handle_t dosyasında bulunan dosya tanımlayıcılarının sahipliğini korur; arayan kişinin bu dosya tanımlayıcılarla işi bittiğinde bunları kapatması gerekir.
  • Bir hidl_handle nesnesini döndüren süreç (bunu bir _cb işlevine geçirerek), nesnenin sardığı native_handle_t dosyasında bulunan dosya tanımlayıcılarının sahipliğini korur; işlem bu dosya tanımlayıcılarla tamamlandığında kapatılmalıdır.
  • Bir hidl_handle alan aktarım , nesne tarafından sarılmış native_handle_t içindeki dosya tanımlayıcılarının sahipliğine sahiptir; alıcı, işlem geri çağırma sırasında bu dosya tanımlayıcılarını olduğu gibi kullanabilir, ancak geri aramanın ötesinde dosya tanımlayıcılarını kullanmak için yerel tanıtıcıyı klonlaması gerekir. Aktarım, işlem tamamlandığında dosya tanımlayıcılarını otomatik olarak close() .

HIDL, Java'daki tanıtıcıları desteklemez (çünkü Java tanıtıcıları hiç desteklemez).

Boyutlandırılmış diziler

HIDL yapılarındaki boyutlu dizilerin öğeleri, bir yapının içerebileceği herhangi bir türde olabilir:

struct foo {
uint32_t[3] x; // array is contained in foo
};

Teller

Dizeler C++ ve Java'da farklı görünür, ancak temel aktarım depolama türü bir C++ yapısıdır. Ayrıntılar için bkz. HIDL C++ Veri Türleri veya HIDL Java Veri Türleri .

Not: Bir dizenin Java'ya veya Java'dan HIDL arabirimi (Java'dan Java'ya dahil) aracılığıyla iletilmesi, orijinal kodlamayı tam olarak koruyamayabilecek karakter kümesi dönüşümlerine neden olur.

vec<T> türü şablonu

vec<T> şablonu, T örneklerini içeren değişken boyutlu bir arabelleği temsil eder.

T aşağıdakilerden biri olabilir:

  • İlkel türler (örn. uint32_t)
  • Teller
  • Kullanıcı tanımlı numaralandırmalar
  • Kullanıcı tanımlı yapılar
  • Arayüzler veya interface anahtar sözcüğü ( vec<IFoo> , vec<interface> yalnızca üst düzey bir parametre olarak desteklenir)
  • Kollar
  • bit alanı<U>
  • vec<U>, burada arayüz hariç U bu listede yer alır (örn. vec<vec<IFoo>> desteklenmez)
  • U[] (U'nun boyutlu dizisi), burada U, arayüz dışında bu listededir

Kullanıcı tanımlı türler

Bu bölümde kullanıcı tanımlı türler açıklanmaktadır.

Sıralama

HIDL anonim numaralandırmaları desteklemez. Aksi takdirde, HIDL'deki numaralandırmalar C++11'e benzer:

enum name : type { enumerator , enumerator = constexpr , …  }

Bir temel numaralandırma, HIDL'deki tamsayı türlerinden birine göre tanımlanır. Tamsayı türüne dayalı bir numaralandırmanın ilk numaralandırıcısı için değer belirtilmezse, değer varsayılan olarak 0 olur. Daha sonraki bir numaralandırıcı için değer belirtilmezse, değer varsayılan olarak önceki değer artı bir olur. Örneğin:

// RED == 0
// BLUE == 4 (GREEN + 1)
enum Color : uint32_t { RED, GREEN = 3, BLUE }

Bir numaralandırma ayrıca önceden tanımlanmış bir numaralandırmadan da miras alabilir. Bir alt numaralandırmanın ilk numaralandırıcısı için bir değer belirtilmemişse (bu durumda FullSpectrumColor ), varsayılan olarak üst numaralandırmanın son numaralandırıcısının değeri artı bir olur. Örneğin:

// ULTRAVIOLET == 5 (Color:BLUE + 1)
enum FullSpectrumColor : Color { ULTRAVIOLET }

Uyarı: Enum mirası, diğer birçok miras türünden geriye doğru çalışır. Bir alt numaralandırma değeri, üst numaralandırma değeri olarak kullanılamaz. Bunun nedeni, bir alt numaralandırmanın ebeveynden daha fazla değer içermesidir. Bununla birlikte, alt numaralandırma değerleri tanım gereği üst numaralandırma değerlerinin bir üst kümesi olduğundan, bir üst numaralandırma değeri güvenli bir şekilde alt numaralandırma değeri olarak kullanılabilir. Arayüzleri tasarlarken bunu aklınızda bulundurun; çünkü bu, ana numaralandırmalara atıfta bulunan türlerin, arayüzünüzün daha sonraki yinelemelerinde alt numaralandırmalara başvuramayacağı anlamına gelir.

Numaralandırmaların değerleri iki nokta üst üste sözdizimi ile anılır (iç içe türler olarak nokta sözdizimi değil). Söz dizimi Type:VALUE_NAME . Değere aynı numaralandırma türünde veya alt türlerde başvuruluyorsa türü belirtmenize gerek yoktur. Örnek:

enum Grayscale : uint32_t { BLACK = 0, WHITE = BLACK + 1 };
enum Color : Grayscale { RED = WHITE + 1 };
enum Unrelated : uint32_t { FOO = Color:RED + 1 };

Android 10'dan itibaren numaralandırmalar, sabit ifadelerde kullanılabilen bir len özelliğine sahiptir. MyEnum::len bu numaralandırmadaki toplam giriş sayısıdır. Bu, toplam değer sayısından farklıdır ve değerler kopyalandığında daha küçük olabilir.

Yapı

HIDL anonim yapıları desteklemez. Aksi halde HIDL'deki yapılar C'ye çok benzer.

HIDL, tamamen bir yapı içinde yer alan değişken uzunluktaki veri yapılarını desteklemez. Bu, bazen C/C++'da bir yapının son alanı olarak kullanılan (bazen [0] boyutuyla görülen) belirsiz uzunluklu diziyi içerir. HIDL vec<T> verileri ayrı bir arabellekte depolanan dinamik olarak boyutlandırılmış dizileri temsil eder; bu tür örnekler struct içindeki vec<T> örneğiyle temsil edilir.

Benzer şekilde, string bir struct içinde yer alabilir (ilişkili arabellekler ayrıdır). Oluşturulan C++'da, HIDL tanıtıcı türünün örnekleri, temeldeki veri türünün örnekleri değişken uzunlukta olduğundan, gerçek yerel tanıtıcıya yönelik bir işaretçi aracılığıyla temsil edilir.

Birlik

HIDL anonim birleşmeleri desteklemez. Aksi takdirde sendikalar C'ye benzer.

Birleşimler düzeltme türleri (işaretçiler, dosya tanımlayıcılar, ciltleyici nesneler vb.) içeremez. Özel alanlara veya ilgili türlere ihtiyaç duymazlar ve memcpy() veya eşdeğeri aracılığıyla kolayca kopyalanırlar. Bir birleşim, ciltleyici ofsetlerinin ayarlanmasını gerektiren herhangi bir şeyi (yani tanıtıcı veya ciltleyici arayüzü referansları) doğrudan içeremez (veya diğer veri yapıları aracılığıyla içeremez). Örneğin:

union UnionType {
uint32_t a;
//  vec<uint32_t> r;  // Error: can't contain a vec<T>
uint8_t b;1
};
fun8(UnionType info); // Legal

Birlikler yapıların içinde de bildirilebilir. Örneğin:

struct MyStruct {
    union MyUnion {
      uint32_t a;
      uint8_t b;
    }; // declares type but not member

    union MyUnion2 {
      uint32_t a;
      uint8_t b;
    } data; // declares type but not member
  }