Tworzenie interfejsu HAL

Musisz używać HIDL do opisywania wszystkich flag kompilacji używanych warunkowo budowania platformy. Odpowiednie flagi kompilacji muszą być zgrupowane i uwzględnione w pojedynczy plik .hal. Używanie HIDL do określania elementów konfiguracji zapewnia następujące korzyści:

  • Uwzględnione w wersji (aby można było dodać nowe elementy konfiguracji, dostawcy/producent OEM muszą wyraźnie rozszerzyć HAL)
  • Dobrze udokumentowany
  • Kontrola dostępu przy użyciu SELinux
  • Kontrola poprawności elementów konfiguracji w Test dostawcy Suite (sprawdzanie zakresu, współdziałanie elementów itp.)
  • Automatycznie generowane interfejsy API w C++ i Javie

Określ flagi kompilacji używane przez platformę

Zacznij od wskazania konfiguracji kompilacji używanych do warunkowej skompilowania platformy, a następnie zrezygnować z nieaktualnych konfiguracji, aby zmniejszyć zbiór. Przykład: dla surfaceflinger zidentyfikowano te flagi 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 dla podsystemu uzyskuje się przez interfejs HAL, a interfejsy do przekazywania wartości konfiguracyjnych są zgrupowane w pakiecie HAL android.hardware.configstore (obecnie w wersji 1.0). Aby np. utworzyć plik interfejsu HAL dla języka surfaceflinger, 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ć nowe .hal w folderach Android.bp i Android.mk plików.

Dodawanie funkcji do flag kompilacji

Do każdej flagi kompilacji dodaj nową funkcję do interfejsu. Na przykład w polu 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:

  • Zachowaj zwięzłość i nazwisko. Unikaj konwertowania zmiennej Makefile nazwy na nazwy funkcji. Pamiętaj, że TARGET_ oraz Prefiksy (BOARD_) nie są już potrzebne.
  • dodawać komentarze, Pomóż deweloperom zrozumieć, do czego służy funkcja jak zmienia działanie platformy, prawidłowe wartości i inne istotne i informacjami o nich.

Zwracane typy funkcji mogą być Optional[Bool|String|Int32|UInt32|Int64|UInt64] Typy są zdefiniowane w types.hal w tym samym katalogu i opakuj wartości podstawowe za pomocą tagu pole wskazujące, czy wartość jest określona przez HAL; Jeśli nie, zostanie zastosowany domyślny .

struct OptionalString {
    bool specified;
    string value;
};

W razie potrzeby zdefiniuj wyliczenie, które najlepiej odpowiada typowi wartości i użyć tego wyliczenia jako zwracanego typu. W przykładzie powyżej wyliczana NumBuffers jest zdefiniowana w celu ograniczenia liczby prawidłowych . Podczas definiowania takich niestandardowych typów danych dodaj pole lub wartość wyliczeniową (w przypadku np. USE_DEFAULT) do wskazania, czy wartość jest/nie jest określona przez HAL.

Nie jest konieczne, aby pojedyncza flaga kompilacji była pojedynczą funkcją w HIDL. Właściciele modułu mogą też agregować ściśle powiązane flagi kompilacji w mają strukturę struct i są wyposażone w funkcję, która zwraca tę strukturę (może to zmniejszyć liczbę wywołań funkcji).

Na przykład opcja agregacji 2 flag kompilacji w jedną strukturę w: hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal to:

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

Alternatywy dla pojedynczej funkcji HAL

Zamiast używać pojedynczej funkcji HAL na potrzeby wszystkich flag kompilacji, można użyć funkcji HAL interfejs udostępnia też proste funkcje, takie jak getBoolean(string key) i getInteger(string key). Rzeczywisty key=value pary są przechowywane w osobnych plikach i usłudze HAL dostarcza wartości przez odczyt/analizę tych plików.

Takie podejście jest łatwe do zdefiniowania, ale nie uwzględnia korzyści udostępniane przez HIDL (wymuszona obsługa wersji, łatwa dokumentacja, kontrola dostępu) i dlatego nie jest zalecana.

Jeden i wiele interfejsów

Interfejs HAL elementów konfiguracji zawiera 2 elementy: opcje:

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

Jeden interfejs jest prostszy, ale może też stać się problemem z utrzymaniem, elementy konfiguracji zostaną dodane do pojedynczego pliku. Ponadto kontrola dostępu nie jest bardzo szczegółowy, przez co proces z dostępem do interfejsu może odczytać wszystkich elementów konfiguracji (nie można mieć dostępu do częściowego zbioru elementów konfiguracji przyznane). Jeśli nie przyznasz dostępu, elementów konfiguracji nie będzie można przeczytaj.

Z tego powodu Android używa wielu interfejsów z jedną HAL. dla grupy powiązanych elementów konfiguracji. Przykład: ISurfaceflingerConfigs w związku z: surfaceflinger elementy konfiguracji oraz IBluetoothConfigs w przypadku funkcji związanych z Bluetoothem elementów konfiguracji.