Создайте интерфейс HAL

Вы должны использовать HIDL для описания всех флагов сборки, используемых для условной компиляции фреймворка. Соответствующие флаги сборки должны быть сгруппированы и включены в один файл .hal . Использование HIDL для указания элементов конфигурации включает следующие преимущества:

  • Версионность (для добавления новых элементов конфигурации поставщики/OEM-производители должны явно расширить HAL)
  • Хорошо документировано
  • Контроль доступа с использованием SELinux
  • Проверка работоспособности элементов конфигурации с помощью набора тестов поставщика (проверка диапазона, проверка взаимозависимости между элементами и т. д.)
  • Автоматически сгенерированные API на C++ и Java

Определите флаги сборки, используемые фреймворком

Начните с определения конфигураций сборки, используемых для условной компиляции фреймворка, затем откажитесь от устаревших конфигураций, чтобы уменьшить набор. Например, для surfaceflinger идентифицирован следующий набор флагов сборки:

  • 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

Создать интерфейс HAL

Конфигурации сборки для подсистемы доступны через интерфейс HAL, в то время как интерфейсы для задания значений конфигурации сгруппированы в пакете HAL android.hardware.configstore (в настоящее время версии 1.0). Например, чтобы создать файл интерфейса HAL для surfaceflinger , в hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal :

package android.hardware.configstore@1.0;

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

После создания файла .hal запустите hardware/interfaces/update-makefiles.sh чтобы добавить новый файл .hal в файлы Android.bp и Android.mk .

Добавить функции для флагов сборки

Для каждого флага сборки добавьте новую функцию в интерфейс. Например, в 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);
};

При добавлении функции:

  • Будьте лаконичны с именами. Избегайте преобразования имен переменных makefile в имена функций и помните, что префиксы TARGET_ и BOARD_ больше не нужны.
  • Добавьте комментарии. Помогите разработчикам понять цель элемента конфигурации, как он изменяет поведение фреймворка, допустимые значения и другую соответствующую информацию.

Типы возвращаемых функций могут быть Optional[Bool|String|Int32|UInt32|Int64|UInt64] . Типы определяются в types.hal в том же каталоге и заключают примитивные значения в поле, которое указывает, указано ли значение HAL; если нет, используется значение по умолчанию.

struct OptionalString {
    bool specified;
    string value;
};

При необходимости определите перечисление, которое наилучшим образом представляет тип элемента конфигурации, и используйте это перечисление в качестве возвращаемого типа. В приведенном выше примере перечисление NumBuffers определено для ограничения количества допустимых значений. При определении таких пользовательских типов данных добавьте поле или значение перечисления (например, USE_DEFAULT ) для обозначения того, указано ли значение HAL или нет.

Не обязательно, чтобы один флаг сборки становился одной функцией в HIDL. Владельцы модулей могут альтернативно объединить тесно связанные флаги сборки в структуру и иметь функцию, которая возвращает эту структуру (это может сократить количество вызовов функций).

Например, вариант объединения двух флагов сборки в одну структуру в hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal выглядит так:

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

Альтернативы одной функции HAL

В качестве альтернативы использованию одной функции HAL для всех флагов сборки интерфейс HAL также предоставляет простые функции, такие как getBoolean(string key) и getInteger(string key) . Фактические пары key=value хранятся в отдельных файлах, а служба HAL предоставляет значения путем чтения/анализа этих файлов.

Хотя этот подход легко определить, он не включает в себя преимущества, предоставляемые HIDL (принудительное управление версиями, простота документирования, контроль доступа), и поэтому не рекомендуется.

Одиночные и множественные интерфейсы

Конструкция интерфейса HAL для элементов конфигурации предусматривает два варианта:

  • Единый интерфейс, охватывающий все элементы конфигурации
  • Несколько интерфейсов, каждый из которых охватывает набор связанных элементов конфигурации

Единый интерфейс проще, но может стать неподдающимся поддержке по мере добавления большего количества элементов конфигурации в один файл. Кроме того, контроль доступа не является детализированным, поэтому процесс, которому предоставлен доступ к интерфейсу, может читать все элементы конфигурации (доступ к частичному набору элементов конфигурации не может быть предоставлен). В качестве альтернативы, если доступ не предоставлен, элементы конфигурации не могут быть прочитаны.

Из-за этих проблем Android использует несколько интерфейсов с одним интерфейсом HAL для группы связанных элементов конфигурации. Например, ISurfaceflingerConfigs для элементов конфигурации, связанных с surfaceflinger , и IBluetoothConfigs для элементов конфигурации, связанных с Bluetooth.