Tworzenie interfejsu HAL

Musisz użyć języka HIDL, aby opisać wszystkie flagi kompilacji używane do warunkowej kompilacji frameworka. Odpowiednie flagi kompilacji muszą być zgrupowane i zawarte w jednym pliku .hal . Używanie języka HIDL do określania elementów konfiguracji zapewnia następujące korzyści:

  • Wersjonowane (aby dodać nowe elementy konfiguracji, dostawcy/producenci OEM muszą jawnie rozszerzyć warstwę HAL)
  • Dobrze udokumentowane
  • Kontrola dostępu za pomocą SELinux
  • Kontrola poprawności elementów konfiguracji za pomocą pakietu Vendor Test Suite (sprawdzanie zakresu, sprawdzanie współzależności między elementami itp.)
  • Automatycznie generowane interfejsy API w językach C++ i Java

Identyfikowanie flag kompilacji używanych przez platformę

Zacznij od zidentyfikowania konfiguracji kompilacji używanych do warunkowej kompilacji frameworka, a następnie porzuć przestarzałe konfiguracje, aby zmniejszyć zestaw. Na przykład dla surfaceflinger zidentyfikowano następujący zestaw flag kompilacji:

  • TARGET_USES_HWC2
  • TARGET_BOARD_PLATFORM
  • TARGET_DISABLE_TRIPLE_BUFFERING
  • TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS
  • NUM_FRAMEBUFFER_SURFACE_BUFFERS
  • TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK
  • VSYNC_EVENT_PHASE_OFFSET_NS
  • SF_VSYNC_EVENT_PHASE_OFFSET_NS
  • PRESENT_TIME_OFFSET_FROM_VSYNC_NS
  • MAX_VIRTUAL_DISPLAY_DIMENSION

Tworzenie interfejsu HAL

Dostęp do konfiguracji kompilacji podsystemu możliwy jest poprzez interfejs HAL, natomiast interfejsy służące do podawania wartości konfiguracyjnych zgrupowane są w pakiecie HAL android.hardware.configstore (obecnie w wersji 1.0). Na przykład, aby utworzyć plik interfejsu HAL dla surfaceflinger , w hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal :

package android.hardware.configstore@1.0;

interface ISurfaceFlingerConfigs {
    // TO-BE-FILLED-BELOW
};

Po utworzeniu pliku .hal uruchom hardware/interfaces/update-makefiles.sh aby dodać nowy plik .hal do plików Android.bp i Android.mk .

Dodanie funkcji dla flag kompilacji

Dla każdej flagi kompilacji dodaj nową funkcję do interfejsu. Na przykład w hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal :

interface ISurfaceFlingerConfigs {
    disableTripleBuffering() generates(OptionalBool ret);
    forceHwcForVirtualDisplays() generates(OptionalBool ret);
    enum NumBuffers: uint8_t {
        USE_DEFAULT = 0,
        TWO = 2,
        THREE = 3,
    };
    numFramebufferSurfaceBuffers() generates(NumBuffers ret);
    runWithoutSyncFramework() generates(OptionalBool ret);
    vsyncEventPhaseOffsetNs generates (OptionalUInt64 ret);
    presentTimeOffsetFromSyncNs generates (OptionalUInt64 ret);
    maxVirtualDisplayDimension() generates(OptionalInt32 ret);
};

Podczas dodawania funkcji:

  • Bądź zwięzły w nazwach. Unikaj konwertowania nazw zmiennych makefile na nazwy funkcji i pamiętaj, że przedrostki TARGET_ i BOARD_ nie są już potrzebne.
  • Dodaj Komentarze. Pomóż programistom zrozumieć cel elementu konfiguracji, sposób, w jaki zmienia on zachowanie platformy, prawidłowe wartości i inne istotne informacje.

Typy zwracanych funkcji mogą być Optional[Bool|String|Int32|UInt32|Int64|UInt64] . Typy są zdefiniowane w types.hal w tym samym katalogu i otaczają pierwotne wartości polem wskazującym, czy wartość jest określona przez warstwę HAL; jeśli nie, używana jest wartość domyślna.

struct OptionalString {
    bool specified;
    string value;
};

Jeśli to konieczne, zdefiniuj wyliczenie, które najlepiej reprezentuje typ elementu konfiguracji i użyj tego wyliczenia jako typu zwracanego. W powyższym przykładzie zdefiniowano wyliczenie NumBuffers w celu ograniczenia liczby prawidłowych wartości. Definiując takie niestandardowe typy danych, dodaj pole lub wartość wyliczeniową (na przykład USE_DEFAULT ) w celu oznaczenia, czy wartość jest/nie jest określona przez warstwę HAL.

Nie jest obowiązkowe, aby pojedyncza flaga kompilacji stała się pojedynczą funkcją w HIDL. Właściciele modułów mogą alternatywnie agregować ściśle powiązane flagi kompilacji w strukturę i mieć funkcję zwracającą tę strukturę (może to zmniejszyć liczbę wywołań funkcji).

Na przykład opcją agregacji dwóch flag kompilacji w jedną strukturę w hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal jest:

 interface ISurfaceFlingerConfigs {
    // other functions here
    struct SyncConfigs {
        OptionalInt64 vsyncEventPhaseoffsetNs;
        OptionalInt64 presentTimeoffsetFromSyncNs;
    };
    getSyncConfigs() generates (SyncConfigs ret);
    // other functions here
};

Alternatywy dla pojedynczej funkcji HAL

Jako alternatywę do używania pojedynczej funkcji HAL dla wszystkich flag kompilacji, interfejs HAL udostępnia również proste funkcje, takie jak getBoolean(string key) i getInteger(string key) . Rzeczywiste pary key=value są przechowywane w oddzielnych plikach, a usługa HAL dostarcza wartości poprzez odczyt/analizę tych plików.

Chociaż podejście to jest łatwe do zdefiniowania, nie obejmuje korzyści zapewnianych przez HIDL (wymuszone wersjonowanie, łatwość dokumentacji, kontrola dostępu) i dlatego nie jest zalecane.

Pojedynczy i wielokrotny interfejs

Projekt interfejsu HAL dla elementów konfiguracyjnych oferuje dwie możliwości:

  • Pojedynczy interfejs obejmujący wszystkie elementy konfiguracji
  • Wiele interfejsów, z których każdy obejmuje zestaw powiązanych elementów konfiguracyjnych

Pojedynczy interfejs jest łatwiejszy, ale może stać się niemożliwy do utrzymania w przypadku dodania większej liczby elementów konfiguracyjnych do pojedynczego pliku. Ponadto kontrola dostępu nie jest precyzyjna, więc proces, któremu przyznano dostęp do interfejsu, może odczytać wszystkie elementy konfiguracji (nie można przyznać dostępu do częściowego zestawu elementów konfiguracji). Alternatywnie, jeśli dostęp nie zostanie przyznany, elementów konfiguracji nie będzie można odczytać.

Z powodu tych problemów system Android używa wielu interfejsów z jednym interfejsem HAL dla grupy powiązanych elementów konfiguracji. Na przykład ISurfaceflingerConfigs dla elementów konfiguracji związanych z surfaceflinger i IBluetoothConfigs dla elementów konfiguracji związanych z Bluetooth.