Для описания всех флагов сборки, используемых для условной компиляции фреймворка, необходимо использовать HIDL. Соответствующие флаги сборки должны быть сгруппированы и включены в один файл .hal . Использование HIDL для указания элементов конфигурации дает следующие преимущества:
- Версионирование (для добавления новых элементов конфигурации поставщикам/производителям оборудования необходимо явно расширить 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.