Как реализовать Health 2.1

В Android 11 весь код healthd был переработан в libhealthloop и libhealth2impl, а затем изменен для реализации HAL health@2.1. Эти две библиотеки статически связаны с помощью health@2.0-impl-2.1 – реализации Health 2.1 с передачей данных. Статически связанные библиотеки позволяют health@2.0-impl-2.1 выполнять те же действия, что и healthd, например запускать healthd_mainloop и опрашивать. В init health@2.1-service регистрирует реализацию интерфейса IHealth в hwservicemanager. При обновлении устройств с образом поставщика Android 8.x или 9 и фреймворком Android 11 образ поставщика может не предоставлять сервис health@2.1. Обратная совместимость со старыми изображениями поставщиков обеспечивается графиком прекращения поддержки.

Чтобы обеспечить обратную совместимость:

  1. healthd регистрирует IHealth в hwservicemanager, несмотря на то, что является системным демоном. IHealth добавляется в манифест системы с именем экземпляра backup.
  2. Фреймворк и storaged взаимодействуют с healthd через hwbinder, а не binder.
  3. Код для фреймворка и storaged изменен таким образом, чтобы сначала извлекать экземпляр "default", если он доступен, а затем "backup".
    • Клиентский код C++ использует логику, определенную в libhealthhalutils.
    • Клиентский код Java использует логику, определенную в HealthServiceWrapper.
  4. После того как iHealth/default станет широко доступен, а образы поставщика Android 8.1 будут признаны устаревшими, можно будет признать устаревшими iHealth/backup и healthd.

Переменные сборки для healthd, относящиеся к определенной плате

BOARD_PERIODIC_CHORES_INTERVAL_* – это переменные, относящиеся к определенной плате, которые используются для создания healthd. В рамках разделения сборки на системную и сборку поставщика для системных модулей нельзя задавать значения, относящиеся к плате. Раньше эти значения можно было переопределить с помощью устаревшей функции healthd_board_init.

В health@2.1 поставщики могут переопределить значения интервалов этих двух периодических задач в структуре healthd_config, прежде чем передавать их конструктору класса реализации health. Класс реализации health должен быть унаследован от android::hardware::health::V2_1::implementation::Health.

Как реализовать сервис Health 2.1

Информацию о реализации сервиса Health 2.1 можно найти в файле hardware/interfaces/health/2.1/README.md.

Клиенты Health

У health@2.x есть следующие клиенты:

  • зарядное устройство. Код libbatterymonitor и healthd_common заключен в health@2.0-impl.
  • восстановления; Ссылка на libbatterymonitor заключена в теги health@2.0-impl. Все вызовы BatteryMonitor заменяются вызовами класса реализации Health.
  • BatteryManager BatteryManager.queryProperty(int id) был единственным клиентом IBatteryPropertiesRegistrar.getProperty. IBatteryPropertiesRegistrar.getProperty предоставлен компанией "healthd" и непосредственно прочитан /sys/class/power_supply.

    В целях безопасности приложениям запрещено напрямую вызывать HAL для здоровья. В Android 9 и более поздних версиях сервис binder IBatteryPropertiesRegistrar предоставляется BatteryService, а не healthd. BatteryService делегирует вызов HAL-модулю Health, чтобы получить запрошенную информацию.

  • BatteryService В Android 9 и более поздних версий BatteryService использует HealthServiceWrapper, чтобы определить, какой экземпляр сервисов наблюдения за здоровьем использовать: основной из vendor или резервный из healthd. BatteryService прослушивает события, связанные со здоровьем, с помощью IHealth.registerCallback.

  • Storaged В Android 9 и более поздних версий storaged использует libhealthhalutils, чтобы определить, какой экземпляр сервисов наблюдения за здоровьем использовать: основной из vendor или резервный из healthd. Затем storaged отслеживает события, связанные с состоянием, через IHealth.registerCallback и получает информацию о хранилище.

Изменения SELinux

В HAL health@2.1 в платформу внесены следующие изменения SELinux:

  • Добавляет android.hardware.health@2.1-service в file_contexts.

Для устройств с собственной реализацией могут потребоваться некоторые изменения SELinux поставщика. Пример:

# device/<manufacturer>/<device>/sepolicy/vendor/hal_health_default.te
# Add device specific permissions to hal_health_default domain, especially
# if it links to board-specific libhealthd or implements storage APIs.

Интерфейсы ядра

Демон healthd и реализация по умолчанию android.hardware.health@2.0-impl-2.1 получают информацию о батарее, используя следующие интерфейсы ядра:

  • /sys/class/power_supply/*/capacity_level (добавлено в Health 2.1)
  • /sys/class/power_supply/*/capacity
  • /sys/class/power_supply/*/charge_counter
  • /sys/class/power_supply/*/charge_full
  • /sys/class/power_supply/*/charge_full_design (добавлено в Health 2.1)
  • /sys/class/power_supply/*/current_avg
  • /sys/class/power_supply/*/current_max
  • /sys/class/power_supply/*/current_now
  • /sys/class/power_supply/*/cycle_count
  • /sys/class/power_supply/*/health
  • /sys/class/power_supply/*/online
  • /sys/class/power_supply/*/present
  • /sys/class/power_supply/*/status
  • /sys/class/power_supply/*/technology
  • /sys/class/power_supply/*/temp
  • /sys/class/power_supply/*/time_to_full_now (добавлено в Health 2.1)
  • /sys/class/power_supply/*/type
  • /sys/class/power_supply/*/voltage_max
  • /sys/class/power_supply/*/voltage_now

Любая реализация HAL для здоровья, относящаяся к определенному устройству и использующая libbatterymonitor, по умолчанию обращается к этим интерфейсам ядра, если только это не переопределено в конструкторе класса реализации HAL для здоровья.

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

Некоторые интерфейсы ядра, используемые в Health 2.1, например /sys/class/power_supply/*/capacity_level и /sys/class/power_supply/*/time_to_full_now, могут быть необязательными. Однако, чтобы предотвратить некорректное поведение фреймворка из-за отсутствия интерфейсов ядра, рекомендуется выбрать CL 1398913 перед созданием сервиса Health HAL 2.1.

Тестирование

В Android 11 добавлены новые тесты VTS, разработанные специально для HAL health@2.1. Если в манифесте устройства объявлен HAL health@2.1, оно должно пройти соответствующие тесты VTS. Тесты пишутся как для экземпляра по умолчанию (чтобы убедиться, что устройство правильно реализует HAL), так и для резервного экземпляра (чтобы убедиться, что healthd продолжает работать правильно до его удаления).

Требования к информации о батарее

В HAL версии 2.0 для здоровья указан ряд требований к интерфейсу HAL, но соответствующие тесты VTS относительно слабо контролируют их соблюдение. В Android 11 добавлены новые тесты VTS, которые позволяют обеспечить выполнение следующих требований на устройствах с Android 11 и более поздних версий:

  • Единица измерения мгновенного и среднего тока батареи – микроампер (мкА).
  • Знак мгновенного и среднего тока батареи должен быть правильным. А именно:
    • current == 0, когда статус батареи – UNKNOWN
    • current > 0, если статус батареи – CHARGING
    • current <= 0, когда статус батареи – NOT_CHARGING
    • current < 0, когда статус батареи – DISCHARGING
    • Не применяется, если уровень заряда батареи составляет FULL.
  • Статус батареи должен соответствовать тому, подключен ли источник питания. А именно:
    • статус батареи должен быть одним из следующих: CHARGING, NOT_CHARGING или FULL, если и только если подключен источник питания;
    • Статус батареи должен быть DISCHARGING, только если источник питания отключен.

Если вы используете libbatterymonitor и передаете значения из интерфейсов ядра, убедитесь, что узлы sysfs сообщают правильные значения:

  • Убедитесь, что ток батареи передается с правильным знаком и единицами измерения. Это относится к следующим узлам sysfs:
    • /sys/class/power_supply/*/current_avg
    • /sys/class/power_supply/*/current_max
    • /sys/class/power_supply/*/current_now
    • Положительные значения указывают на входящий ток в батарею.
    • Значения должны быть указаны в микроамперах (мкА).
  • Убедитесь, что напряжение батареи указывается в микровольтах (мкВ). К ним относятся следующие узлы sysfs:
    • /sys/class/power_supply/*/voltage_max
    • /sys/class/power_supply/*/voltage_now
    • Обратите внимание, что реализация HAL по умолчанию делит voltage_now на 1000 и сообщает значения в милливольтах (мВ). Подробнее о HealthInfo…

Подробнее о классе источника питания Linux…