Devices may have actions triggered by init.svc.vendor.charger. If the name is changed, these actions are not triggered properly. The name is usually vendor.charger, so the default service will also use vendor.charger as the name. Test: none Bug: 215152892 Change-Id: Icb296ae82a6f3472730fdb3abc35dcede22889e7
12 KiB
Health AIDL HAL
Determine whether the example service implementation is sufficient
You need a custom implementation if any of the following is true:
- You are migrating from a custom health 2.1 HIDL HAL implementation.
- System properties
ro.charger.enable_suspend
and/orro.charger.no_ui
are set to atrue
value. See below. - The device supports offline charging mode, and the
service
declaration withclass charger
ininit.rc
is different from the one provided by the example implementation. See below.
If the example HAL service is sufficient, install it. Otherwise, implement a custom HAL service.
System properties for charger
The health AIDL HAL service also provides functionalities of charger
. As a
result, the system charger at /system/bin/charger
is deprecated.
However, the health AIDL HAL service is not allowed to read ro.charger.*
system properties. These properties include:
ro.charger.enable_suspend
. If set, you need a custom health AIDL HAL service. See below.ro.charger.no_ui
. If set, you need a custom health AIDL HAL service. See below.ro.charger.draw_split_screen
. The system property is deprecated.ro.charger.draw_split_offset
. The system property is deprecated.ro.charger.disable_init_blank
. The system property is deprecated.
If you need to set any of the deprecated system properties, contact OWNERS.
Default service
declaration for charger in init.rc
See android.hardware.health-service.example.rc.
Check the service
declaration in your device-specific init.rc
file that
has class charger
. Most likely, the declaration looks something like this
(Below is an excerpt from Pixel 3):
service vendor.charger /system/bin/charger
class charger
seclabel u:r:charger:s0
user system
group system wakelock input
capabilities SYS_BOOT
file /dev/kmsg w
file /sys/fs/pstore/console-ramoops-0 r
file /sys/fs/pstore/console-ramoops r
file /proc/last_kmsg r
Compare each line against the one provided by the example health AIDL HAL service in android.hardware.health-service.example.rc. Specifically:
- For the
service
line, if the name of the service is NOTvendor.charger
, and there are actions in the rc file triggered byon property:init.svc.<name>=running
where<name>
is the name of your charger service, then you need a custom health AIDL service. - If your service belongs to additional classes beside
charger
, you need a custom health AIDL service. - Modify the
seclabel
line. Replacecharger
withcharger_vendor
. - If your service has a different
user
(notsystem
), you need a custom health AIDL service. - If your service belongs to additional
group
s besidesystem wakelock input
, you need a custom health AIDL service. - If your service requires additional capabilities beside
SYS_BOOT
, you need a custom health AIDL service. - If your service requires additional
file
s to be opened prior to execution, you need a custom health AIDL service.
Using the example health AIDL HAL service
If you determined that the example health AIDL HAL service works for your device, install it with
PRODUCT_PACKAGES += \
android.hardware.health-service.example \
android.hardware.health-service.example_recovery \
Then, delete any existing service
with class charger
in your device-specific
init.rc
files, because
android.hardware.health-service.example.rc
already contains an entry for charger.
If your device supports charger mode and it has custom charger resources,
move charger resources to /vendor
Implementing a custom health AIDL HAL service
Override the Health
class
See Health.h
for its class
declaration. Inherit the class to customize for your device.
namespace aidl::android::hardware::health {
class HealthImpl : public Health {
// ...
};
} // namespace aidl::android::hardware::health
int main(int, char**) {
// ...
auto binder = ndk::SharedRefBase::make<aidl::android::hardware::health::HealthImpl>(
"default", std::move(config));
// ...
}
-
The logic to modify
healthd_config
, traditionally inhealthd_board_init()
should be called before passing thehealthd_config
struct to yourHealthImpl
class inmain()
. -
The following functions are similar to the ones in the health 2.1 HIDL HAL:
AIDL implementation | HIDL implementation |
---|---|
Health::getChargeCounterUah |
Health::getChargeCounter |
Health::getCurrentNowMicroamps |
Health::getCurrentNow |
Health::getCurrentAverageMicroamps |
Health::getCurrentAverage |
Health::getCapacity |
Health::getCapacity |
Health::getChargeStatus |
Health::getChargeStatus |
Health::getEnergyCounterNwh |
Health::getEnergyCounter |
Health::getDiskStats |
Health::getDiskStats |
Health::getStorageInfo |
Health::getStorageInfo |
Health::BinderEvent |
BinderHealth::BinderEvent |
Health::dump |
Health::debug |
Health::ShouldKeepScreenOn |
Health::shouldKeepScreenOn |
Health::UpdateHealthInfo |
Health::UpdateHealthInfo |
Implement main()
See the main.cpp
for the example health AIDL service for
an example.
If you need to modify healthd_config
, do it before passing it to the
constructor of HealthImpl
(or Health
if you did not implement a subclass
of it).
int main(int argc, char** argv) {
auto config = std::make_unique<healthd_config>();
::android::hardware::health::InitHealthdConfig(config.get());
healthd_board_init(config.get());
auto binder = ndk::SharedRefBase::make<Health>("default", std::move(config));
// ...
}
If your device does not support off-line charging mode, or does not have a UI
for charger (ro.charger.no_ui=true
), skip the invocation of
ChargerModeMain()
in main()
.
Build system changes
Install both the platform and recovery variant of the service. For example:
PRODUCT_PACKAGES += \
android.hardware.health-service.cuttlefish \
android.hardware.health-service.cuttlefish_recovery \
SELinux rules
Add device specific permissions to the domain where the health HAL
process is executed, especially if a device-specific libhealthd
is used
and/or device-specific storage related APIs are implemented.
Example (assuming that your health AIDL service runs in domain
hal_health_tuna
:
type hal_health_tuna, domain;
hal_server_domain(hal_health_tuna, hal_health)
type hal_health_tuna_exec, exec_type, vendor_file_type, file_type;
# allow hal_health_tuna ...;
If you did not define a separate domain, the domain is likely
hal_health_default
. The device-specific rules for it is likely at
device/<manufacturer>/<device>/sepolicy/vendor/hal_health_default.te
.
In this case, the aforementioned SELinux rules and types has already been
defined. You only need to add device-specific permissions.
# allow hal_health_default ...;
Implementing charger
Move charger resources to /vendor
Ensure that charger resources are installed to /vendor
, not /product
.
animation.txt
must be moved to the following location:
/vendor/etc/res/values/charger/animation.txt
Charger resources in /system
is not read by the health HAL service in
/vendor
. Specifically, resources should be installed to the following
location:
/vendor/etc/res/images/charger/*.png
If resources are not found in these locations, the health HAL service falls back to the following locations:
/vendor/etc/res/images/charger/default/*.png
You can use the default resources by installing the default module:
PRODUCT_PACKAGES += charger_res_images_vendor
Modify init.rc
for charger
It is recommended that you move the existing service
entry with
class charger
to the init.rc
file in your custom health service.
If there are existing actions in the rc file triggered by
on property:init.svc.<name>=running
, where <name>
is the name of your
existing charger service (usually vendor.charger
), then the name of the
service must be kept as-is. If you modify the name of the service, the actions
are not triggered properly.
Modify the entry to invoke the health service binary with --charger
argument.
See
android.hardware.health-service.example.rc
for an example:
service vendor.charger /vendor/bin/hw/android.hardware.health-service-tuna --charger
class charger
seclabel u:r:charger_vendor:s0
# ...
No charger mode
If your device does not support off-line charging mode, skip the invocation of
ChargerModeMain()
in main()
.
int main(int, char**) {
// ...
// Skip checking if arguments contain "--charger"
auto hal_health_loop = std::make_shared<HalHealthLoop>(binder, binder);
return hal_health_loop->StartLoop();
}
You may optionally delete the service
entry with class charger
in the
init.rc
file.
No charger UI
If your device does not have a UI for charger (ro.charger.no_ui=true
), skip
the invocation of ChargerModeMain()
in main()
.
You may want to keep the KernelLogger
so that charger still logs battery
information to the kernel logs.
int main(int argc, char** argv) {
// ...
if (argc >= 2 && argv[1] == "--charger"sv) {
android::base::InitLogging(argv, &android::base::KernelLogger);
// fallthrough to HalHealthLoop::StartLoop()
}
auto hal_health_loop = std::make_shared<HalHealthLoop>(binder, binder);
return hal_health_loop->StartLoop();
}
Enable suspend
If your device has ro.charger.enable_suspend=true
, implement a new class,
ChargerCallbackImpl
, that inherits from
ChargerCallback
. Then
override the ChargerEnableSuspend
function to return true
. Then pass an
instance of ChargerCallbackImpl
to ChargerModeMain()
instead.
namespace aidl::android::hardware::health {
class ChargerCallbackImpl : public ChargerCallback {
bool ChargerEnableSuspend() override { return true; }
};
} // namespace aidl::android::hardware::health
int main(int argc, char** argv) {
// ...
if (argc >= 2 && argv[1] == "--charger"sv) {
android::base::InitLogging(argv, &android::base::KernelLogger);
#if !CHARGER_FORCE_NO_UI
return ChargerModeMain(binder,
std::make_shared<aidl::android::hardware::health::ChargerCallbackImpl>(binder));
#endif
}
// ...
}
SELinux rules for charger
If your health AIDL service runs in a domain other than hal_health_default
,
add charger_type
to it so the health HAL service can have charger-specific
permissions. Example (assuming that your health AIDL service runs in domain
hal_health_tuna
:
domain_trans(init, hal_health_tuna_exec, charger_vendor)