Merge "health: Add default impl of health AIDL HAL"
This commit is contained in:
commit
236fa8908c
13 changed files with 925 additions and 0 deletions
76
health/aidl/default/Android.bp
Normal file
76
health/aidl/default/Android.bp
Normal file
|
@ -0,0 +1,76 @@
|
|||
// Copyright (C) 2021 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
cc_defaults {
|
||||
name: "libhealth_aidl_common_defaults",
|
||||
vendor: true,
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libbinder_ndk",
|
||||
"libcutils",
|
||||
"liblog",
|
||||
"libutils",
|
||||
"android.hardware.health-V1-ndk",
|
||||
|
||||
// TODO(b/177269435): remove when BatteryMonitor works with AIDL HealthInfo.
|
||||
"libhidlbase",
|
||||
],
|
||||
static_libs: [
|
||||
"libbatterymonitor",
|
||||
"libhealthloop",
|
||||
|
||||
// TODO(b/177269435): remove when BatteryMonitor works with AIDL HealthInfo.
|
||||
"android.hardware.health-translate-ndk",
|
||||
],
|
||||
}
|
||||
|
||||
// AIDL version of libhealth2impl.
|
||||
// A helper library for health HAL implementation.
|
||||
// HAL implementations can link to this library and extend the Health class.
|
||||
cc_library_static {
|
||||
name: "libhealth_aidl_impl",
|
||||
defaults: [
|
||||
"libhealth_aidl_common_defaults",
|
||||
],
|
||||
export_include_dirs: ["include"],
|
||||
export_static_lib_headers: [
|
||||
"libbatterymonitor",
|
||||
],
|
||||
srcs: [
|
||||
"health-convert.cpp",
|
||||
"HalHealthLoop.cpp",
|
||||
"Health.cpp",
|
||||
"LinkedCallback.cpp",
|
||||
],
|
||||
visibility: [
|
||||
":__subpackages__",
|
||||
"//hardware/interfaces/tests/extension/health:__subpackages__",
|
||||
],
|
||||
}
|
||||
|
||||
// AIDL version of android.hardware.health@2.1-service.
|
||||
// Default binder service of the health HAL.
|
||||
cc_binary {
|
||||
name: "android.hardware.health-service.example",
|
||||
relative_install_path: "hw",
|
||||
init_rc: ["android.hardware.health-service.example.rc"],
|
||||
vintf_fragments: ["android.hardware.health-service.example.xml"],
|
||||
defaults: [
|
||||
"libhealth_aidl_common_defaults",
|
||||
],
|
||||
static_libs: [
|
||||
"libhealth_aidl_impl",
|
||||
],
|
||||
srcs: ["main.cpp"],
|
||||
}
|
67
health/aidl/default/HalHealthLoop.cpp
Normal file
67
health/aidl/default/HalHealthLoop.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <health-impl/HalHealthLoop.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include <health-impl/Health.h>
|
||||
#include "health-convert.h"
|
||||
|
||||
namespace aidl::android::hardware::health {
|
||||
|
||||
// Unlike the HIDL version android::hardware::health::V2_1::implementation::HalHealthLoop,
|
||||
// do not define HalHealthLoop::Init because we no longer have Health::getHealthConfig.
|
||||
// Let the Health class handle Init.
|
||||
void HalHealthLoop::Init(struct healthd_config* config) {
|
||||
callback_->OnInit(this, config);
|
||||
}
|
||||
|
||||
void HalHealthLoop::Heartbeat() {
|
||||
callback_->OnHeartbeat();
|
||||
}
|
||||
|
||||
void HalHealthLoop::ScheduleBatteryUpdate() {
|
||||
// ignore errors. impl may not be able to handle any callbacks, so
|
||||
// update() may return errors.
|
||||
if (auto res = service_->update(); !res.isOk()) {
|
||||
LOG(WARNING) << "update() on the health HAL implementation failed with "
|
||||
<< res.getDescription();
|
||||
}
|
||||
|
||||
HealthInfo health_info;
|
||||
auto res = service_->getHealthInfo(&health_info);
|
||||
CHECK(res.isOk()) << "getHealthInfo() on the health HAL implementation failed with "
|
||||
<< res.getDescription();
|
||||
OnHealthInfoChanged(health_info);
|
||||
}
|
||||
|
||||
int HalHealthLoop::PrepareToWait() {
|
||||
return callback_->OnPrepareToWait();
|
||||
}
|
||||
|
||||
void HalHealthLoop::OnHealthInfoChanged(const HealthInfo& health_info) {
|
||||
callback_->OnHealthInfoChanged(health_info);
|
||||
set_charger_online(health_info);
|
||||
AdjustWakealarmPeriods(charger_online());
|
||||
}
|
||||
|
||||
void HalHealthLoop::set_charger_online(const HealthInfo& health_info) {
|
||||
charger_online_ = health_info.chargerAcOnline || health_info.chargerUsbOnline ||
|
||||
health_info.chargerWirelessOnline;
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::health
|
341
health/aidl/default/Health.cpp
Normal file
341
health/aidl/default/Health.cpp
Normal file
|
@ -0,0 +1,341 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "health-impl/Health.h"
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android/binder_manager.h>
|
||||
#include <android/binder_process.h>
|
||||
#include <android/hardware/health/translate-ndk.h>
|
||||
#include <health/utils.h>
|
||||
|
||||
#include "LinkedCallback.h"
|
||||
#include "health-convert.h"
|
||||
|
||||
using std::string_literals::operator""s;
|
||||
|
||||
namespace aidl::android::hardware::health {
|
||||
|
||||
namespace {
|
||||
// Wrap LinkedCallback::OnCallbackDied() into a void(void*).
|
||||
void OnCallbackDiedWrapped(void* cookie) {
|
||||
LinkedCallback* linked = reinterpret_cast<LinkedCallback*>(cookie);
|
||||
linked->OnCallbackDied();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/*
|
||||
// If you need to call healthd_board_init, construct the Health instance with
|
||||
// the healthd_config after calling healthd_board_init:
|
||||
class MyHealth : public Health {
|
||||
protected:
|
||||
MyHealth() : Health(CreateConfig()) {}
|
||||
private:
|
||||
static std::unique_ptr<healthd_config> CreateConfig() {
|
||||
auto config = std::make_unique<healthd_config>();
|
||||
::android::hardware::health::InitHealthdConfig(config.get());
|
||||
healthd_board_init(config.get());
|
||||
return std::move(config);
|
||||
}
|
||||
};
|
||||
*/
|
||||
Health::Health(std::string_view instance_name, std::unique_ptr<struct healthd_config>&& config)
|
||||
: instance_name_(instance_name),
|
||||
healthd_config_(std::move(config)),
|
||||
death_recipient_(AIBinder_DeathRecipient_new(&OnCallbackDiedWrapped)) {
|
||||
battery_monitor_.init(healthd_config_.get());
|
||||
}
|
||||
|
||||
//
|
||||
// Getters.
|
||||
//
|
||||
|
||||
template <typename T>
|
||||
static ndk::ScopedAStatus GetProperty(::android::BatteryMonitor* monitor, int id, T defaultValue,
|
||||
T* out) {
|
||||
*out = defaultValue;
|
||||
struct ::android::BatteryProperty prop;
|
||||
::android::status_t err = monitor->getProperty(static_cast<int>(id), &prop);
|
||||
if (err == ::android::OK) {
|
||||
*out = static_cast<T>(prop.valueInt64);
|
||||
} else {
|
||||
LOG(DEBUG) << "getProperty(" << id << ")"
|
||||
<< " fails: (" << err << ") " << ::android::statusToString(err);
|
||||
}
|
||||
|
||||
switch (err) {
|
||||
case ::android::OK:
|
||||
return ndk::ScopedAStatus::ok();
|
||||
case ::android::NAME_NOT_FOUND:
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
default:
|
||||
return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
|
||||
IHealth::STATUS_UNKNOWN, ::android::statusToString(err).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Health::getChargeCounterUah(int32_t* out) {
|
||||
return GetProperty<int32_t>(&battery_monitor_, ::android::BATTERY_PROP_CHARGE_COUNTER, 0, out);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Health::getCurrentNowMicroamps(int32_t* out) {
|
||||
return GetProperty<int32_t>(&battery_monitor_, ::android::BATTERY_PROP_CURRENT_NOW, 0, out);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Health::getCurrentAverageMicroamps(int32_t* out) {
|
||||
return GetProperty<int32_t>(&battery_monitor_, ::android::BATTERY_PROP_CURRENT_AVG, 0, out);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Health::getCapacity(int32_t* out) {
|
||||
return GetProperty<int32_t>(&battery_monitor_, ::android::BATTERY_PROP_CAPACITY, 0, out);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Health::getEnergyCounterNwh(int64_t* out) {
|
||||
return GetProperty<int64_t>(&battery_monitor_, ::android::BATTERY_PROP_ENERGY_COUNTER, 0, out);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Health::getChargeStatus(BatteryStatus* out) {
|
||||
return GetProperty(&battery_monitor_, ::android::BATTERY_PROP_BATTERY_STATUS,
|
||||
BatteryStatus::UNKNOWN, out);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Health::getDiskStats(std::vector<DiskStats>*) {
|
||||
// This implementation does not support DiskStats. An implementation may extend this
|
||||
// class and override this function to support disk stats.
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Health::getStorageInfo(std::vector<StorageInfo>*) {
|
||||
// This implementation does not support StorageInfo. An implementation may extend this
|
||||
// class and override this function to support storage info.
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Health::getHealthInfo(HealthInfo* out) {
|
||||
battery_monitor_.updateValues();
|
||||
|
||||
// TODO(b/177269435): BatteryMonitor should store AIDL HealthInfo instead.
|
||||
auto health_info_2_1 = battery_monitor_.getHealthInfo_2_1();
|
||||
if (!::android::h2a::translate(health_info_2_1, out)) {
|
||||
return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
|
||||
IHealth::STATUS_UNKNOWN, "Cannot translate HIDL HealthInfo to AIDL");
|
||||
}
|
||||
|
||||
// Fill in storage infos; these aren't retrieved by BatteryMonitor.
|
||||
if (auto res = getStorageInfo(&out->storageInfos); !res.isOk()) {
|
||||
if (res.getServiceSpecificError() == 0 &&
|
||||
res.getExceptionCode() != EX_UNSUPPORTED_OPERATION) {
|
||||
return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
|
||||
IHealth::STATUS_UNKNOWN,
|
||||
("getStorageInfo fails: " + res.getDescription()).c_str());
|
||||
}
|
||||
LOG(DEBUG) << "getHealthInfo: getStorageInfo fails with service-specific error, clearing: "
|
||||
<< res.getDescription();
|
||||
out->storageInfos = {};
|
||||
}
|
||||
if (auto res = getDiskStats(&out->diskStats); !res.isOk()) {
|
||||
if (res.getServiceSpecificError() == 0 &&
|
||||
res.getExceptionCode() != EX_UNSUPPORTED_OPERATION) {
|
||||
return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
|
||||
IHealth::STATUS_UNKNOWN,
|
||||
("getDiskStats fails: " + res.getDescription()).c_str());
|
||||
}
|
||||
LOG(DEBUG) << "getHealthInfo: getDiskStats fails with service-specific error, clearing: "
|
||||
<< res.getDescription();
|
||||
out->diskStats = {};
|
||||
}
|
||||
|
||||
// A subclass may want to update health info struct before returning it.
|
||||
UpdateHealthInfo(out);
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
binder_status_t Health::dump(int fd, const char**, uint32_t) {
|
||||
battery_monitor_.dumpState(fd);
|
||||
|
||||
::android::base::WriteStringToFd("\ngetHealthInfo -> ", fd);
|
||||
HealthInfo health_info;
|
||||
auto res = getHealthInfo(&health_info);
|
||||
if (res.isOk()) {
|
||||
::android::base::WriteStringToFd(health_info.toString(), fd);
|
||||
} else {
|
||||
::android::base::WriteStringToFd(res.getDescription(), fd);
|
||||
}
|
||||
|
||||
fsync(fd);
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
std::optional<bool> Health::ShouldKeepScreenOn() {
|
||||
if (!healthd_config_->screen_on) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
HealthInfo health_info;
|
||||
auto res = getHealthInfo(&health_info);
|
||||
if (!res.isOk()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
::android::BatteryProperties props = {};
|
||||
convert(health_info, &props);
|
||||
return healthd_config_->screen_on(&props);
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool IsDeadObjectLogged(const ndk::ScopedAStatus& ret) {
|
||||
if (ret.isOk()) return false;
|
||||
if (ret.getStatus() == ::STATUS_DEAD_OBJECT) return true;
|
||||
LOG(ERROR) << "Cannot call healthInfoChanged on callback: " << ret.getDescription();
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
//
|
||||
// Subclass helpers / overrides
|
||||
//
|
||||
|
||||
void Health::UpdateHealthInfo(HealthInfo* /* health_info */) {
|
||||
/*
|
||||
// Sample code for a subclass to implement this:
|
||||
// If you need to modify values (e.g. batteryChargeTimeToFullNowSeconds), do it here.
|
||||
health_info->batteryChargeTimeToFullNowSeconds = calculate_charge_time_seconds();
|
||||
|
||||
// If you need to call healthd_board_battery_update, modify its signature
|
||||
// and implementation to operate on HealthInfo directly, then call:
|
||||
healthd_board_battery_update(health_info);
|
||||
*/
|
||||
}
|
||||
|
||||
//
|
||||
// Methods that handle callbacks.
|
||||
//
|
||||
|
||||
ndk::ScopedAStatus Health::registerCallback(const std::shared_ptr<IHealthInfoCallback>& callback) {
|
||||
if (callback == nullptr) {
|
||||
// For now, this shouldn't happen because argument is not nullable.
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
|
||||
callbacks_.emplace_back(LinkedCallback::Make(ref<Health>(), callback));
|
||||
// unlock
|
||||
}
|
||||
|
||||
HealthInfo health_info;
|
||||
if (auto res = getHealthInfo(&health_info); !res.isOk()) {
|
||||
LOG(WARNING) << "Cannot call getHealthInfo: " << res.getDescription();
|
||||
// No health info to send, so return early.
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
if (auto res = callback->healthInfoChanged(health_info); IsDeadObjectLogged(res)) {
|
||||
(void)unregisterCallback(callback);
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Health::unregisterCallback(
|
||||
const std::shared_ptr<IHealthInfoCallback>& callback) {
|
||||
if (callback == nullptr) {
|
||||
// For now, this shouldn't happen because argument is not nullable.
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
|
||||
}
|
||||
|
||||
std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
|
||||
|
||||
auto matches = [callback](const auto& linked) {
|
||||
return linked->callback() == callback; // compares shared_ptr
|
||||
};
|
||||
auto it = std::remove_if(callbacks_.begin(), callbacks_.end(), matches);
|
||||
bool removed = (it != callbacks_.end());
|
||||
callbacks_.erase(it, callbacks_.end()); // calls unlinkToDeath on deleted callbacks.
|
||||
return removed ? ndk::ScopedAStatus::ok()
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
|
||||
// A combination of the HIDL version
|
||||
// android::hardware::health::V2_1::implementation::Health::update() and
|
||||
// android::hardware::health::V2_1::implementation::BinderHealth::update()
|
||||
ndk::ScopedAStatus Health::update() {
|
||||
HealthInfo health_info;
|
||||
if (auto res = getHealthInfo(&health_info); !res.isOk()) {
|
||||
LOG(DEBUG) << "Cannot call getHealthInfo for update(): " << res.getDescription();
|
||||
// Propagate service specific errors. If there's none, report unknown error.
|
||||
if (res.getServiceSpecificError() != 0 ||
|
||||
res.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
|
||||
return res;
|
||||
}
|
||||
return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
|
||||
IHealth::STATUS_UNKNOWN, res.getDescription().c_str());
|
||||
}
|
||||
battery_monitor_.logValues();
|
||||
OnHealthInfoChanged(health_info);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
void Health::OnHealthInfoChanged(const HealthInfo& health_info) {
|
||||
// Notify all callbacks
|
||||
std::unique_lock<decltype(callbacks_lock_)> lock(callbacks_lock_);
|
||||
// is_dead notifies a callback and return true if it is dead.
|
||||
auto is_dead = [&](const auto& linked) {
|
||||
auto res = linked->callback()->healthInfoChanged(health_info);
|
||||
return IsDeadObjectLogged(res);
|
||||
};
|
||||
auto it = std::remove_if(callbacks_.begin(), callbacks_.end(), is_dead);
|
||||
callbacks_.erase(it, callbacks_.end()); // calls unlinkToDeath on deleted callbacks.
|
||||
lock.unlock();
|
||||
|
||||
// Let HalHealthLoop::OnHealthInfoChanged() adjusts uevent / wakealarm periods
|
||||
}
|
||||
|
||||
void Health::BinderEvent(uint32_t /*epevents*/) {
|
||||
if (binder_fd_ >= 0) {
|
||||
ABinderProcess_handlePolledCommands();
|
||||
}
|
||||
}
|
||||
|
||||
void Health::OnInit(HalHealthLoop* hal_health_loop, struct healthd_config* config) {
|
||||
LOG(INFO) << instance_name_ << " instance initializing with healthd_config...";
|
||||
|
||||
// Similar to HIDL's android::hardware::health::V2_1::implementation::HalHealthLoop::Init,
|
||||
// copy configuration parameters to |config| for HealthLoop (e.g. uevent / wake alarm periods)
|
||||
*config = *healthd_config_.get();
|
||||
|
||||
binder_status_t status = ABinderProcess_setupPolling(&binder_fd_);
|
||||
|
||||
if (status == ::STATUS_OK && binder_fd_ >= 0) {
|
||||
std::shared_ptr<Health> thiz = ref<Health>();
|
||||
auto binder_event = [thiz](auto*, uint32_t epevents) { thiz->BinderEvent(epevents); };
|
||||
if (hal_health_loop->RegisterEvent(binder_fd_, binder_event, EVENT_NO_WAKEUP_FD) != 0) {
|
||||
PLOG(ERROR) << instance_name_ << " instance: Register for binder events failed";
|
||||
}
|
||||
}
|
||||
|
||||
std::string health_name = IHealth::descriptor + "/"s + instance_name_;
|
||||
CHECK_EQ(STATUS_OK, AServiceManager_addService(this->asBinder().get(), health_name.c_str()))
|
||||
<< instance_name_ << ": Failed to register HAL";
|
||||
|
||||
LOG(INFO) << instance_name_ << ": Hal init done";
|
||||
}
|
||||
|
||||
// Unlike hwbinder, for binder, there's no need to explicitly call flushCommands()
|
||||
// in PrepareToWait(). See b/139697085.
|
||||
|
||||
} // namespace aidl::android::hardware::health
|
66
health/aidl/default/LinkedCallback.cpp
Normal file
66
health/aidl/default/LinkedCallback.cpp
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android/binder_ibinder.h>
|
||||
|
||||
#include <health-impl/Health.h>
|
||||
#include <utils/Errors.h>
|
||||
|
||||
#include "LinkedCallback.h"
|
||||
|
||||
namespace aidl::android::hardware::health {
|
||||
|
||||
std::unique_ptr<LinkedCallback> LinkedCallback::Make(
|
||||
std::shared_ptr<Health> service, std::shared_ptr<IHealthInfoCallback> callback) {
|
||||
std::unique_ptr<LinkedCallback> ret(new LinkedCallback());
|
||||
binder_status_t linkRet =
|
||||
AIBinder_linkToDeath(callback->asBinder().get(), service->death_recipient_.get(),
|
||||
reinterpret_cast<void*>(ret.get()));
|
||||
if (linkRet != ::STATUS_OK) {
|
||||
LOG(WARNING) << __func__ << "Cannot link to death: " << linkRet;
|
||||
return nullptr;
|
||||
}
|
||||
ret->service_ = service;
|
||||
ret->callback_ = std::move(callback);
|
||||
return ret;
|
||||
}
|
||||
|
||||
LinkedCallback::LinkedCallback() = default;
|
||||
|
||||
LinkedCallback::~LinkedCallback() {
|
||||
if (callback_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
auto status =
|
||||
AIBinder_unlinkToDeath(callback_->asBinder().get(), service()->death_recipient_.get(),
|
||||
reinterpret_cast<void*>(this));
|
||||
if (status != STATUS_OK && status != STATUS_DEAD_OBJECT) {
|
||||
LOG(WARNING) << __func__ << "Cannot unlink to death: " << ::android::statusToString(status);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Health> LinkedCallback::service() {
|
||||
auto service_sp = service_.lock();
|
||||
CHECK_NE(nullptr, service_sp);
|
||||
return service_sp;
|
||||
}
|
||||
|
||||
void LinkedCallback::OnCallbackDied() {
|
||||
service()->unregisterCallback(callback_);
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::health
|
60
health/aidl/default/LinkedCallback.h
Normal file
60
health/aidl/default/LinkedCallback.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <aidl/android/hardware/health/IHealthInfoCallback.h>
|
||||
#include <android-base/macros.h>
|
||||
#include <android/binder_auto_utils.h>
|
||||
|
||||
#include <health-impl/Health.h>
|
||||
|
||||
namespace aidl::android::hardware::health {
|
||||
|
||||
// Type of the cookie pointer in linkToDeath.
|
||||
// A (Health, IHealthInfoCallback) tuple.
|
||||
class LinkedCallback {
|
||||
public:
|
||||
// Automatically linkToDeath upon construction with the returned object as the cookie.
|
||||
// service->death_reciepient() should be from CreateDeathRecipient().
|
||||
// Not using a strong reference to |service| to avoid circular reference. The lifetime
|
||||
// of |service| must be longer than this LinkedCallback object.
|
||||
static std::unique_ptr<LinkedCallback> Make(std::shared_ptr<Health> service,
|
||||
std::shared_ptr<IHealthInfoCallback> callback);
|
||||
|
||||
// Automatically unlinkToDeath upon destruction. So, it is always safe to reinterpret_cast
|
||||
// the cookie back to the LinkedCallback object.
|
||||
~LinkedCallback();
|
||||
|
||||
// The wrapped IHealthInfoCallback object.
|
||||
const std::shared_ptr<IHealthInfoCallback>& callback() const { return callback_; }
|
||||
|
||||
// On callback died, unreigster it from the service.
|
||||
void OnCallbackDied();
|
||||
|
||||
private:
|
||||
LinkedCallback();
|
||||
DISALLOW_COPY_AND_ASSIGN(LinkedCallback);
|
||||
|
||||
std::shared_ptr<Health> service();
|
||||
|
||||
std::weak_ptr<Health> service_;
|
||||
std::shared_ptr<IHealthInfoCallback> callback_;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::health
|
|
@ -0,0 +1,6 @@
|
|||
service vendor.health-default /vendor/bin/hw/android.hardware.health-service.example
|
||||
class hal
|
||||
user system
|
||||
group system
|
||||
capabilities WAKE_ALARM BLOCK_SUSPEND
|
||||
file /dev/kmsg w
|
|
@ -0,0 +1,7 @@
|
|||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>android.hardware.health</name>
|
||||
<version>1</version>
|
||||
<fqname>IHealth/default</fqname>
|
||||
</hal>
|
||||
</manifest>
|
40
health/aidl/default/health-convert.cpp
Normal file
40
health/aidl/default/health-convert.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "health-convert.h"
|
||||
|
||||
namespace aidl::android::hardware::health {
|
||||
|
||||
void convert(const HealthInfo& info, struct ::android::BatteryProperties* p) {
|
||||
p->chargerAcOnline = info.chargerAcOnline;
|
||||
p->chargerUsbOnline = info.chargerUsbOnline;
|
||||
p->chargerWirelessOnline = info.chargerWirelessOnline;
|
||||
p->maxChargingCurrent = info.maxChargingCurrentMicroamps;
|
||||
p->maxChargingVoltage = info.maxChargingVoltageMicrovolts;
|
||||
p->batteryStatus = static_cast<int>(info.batteryStatus);
|
||||
p->batteryHealth = static_cast<int>(info.batteryHealth);
|
||||
p->batteryPresent = info.batteryPresent;
|
||||
p->batteryLevel = info.batteryLevel;
|
||||
p->batteryVoltage = info.batteryVoltageMillivolts;
|
||||
p->batteryTemperature = info.batteryTemperatureTenthsCelsius;
|
||||
p->batteryCurrent = info.batteryCurrentMicroamps;
|
||||
p->batteryCycleCount = info.batteryCycleCount;
|
||||
p->batteryFullCharge = info.batteryFullChargeUah;
|
||||
p->batteryChargeCounter = info.batteryChargeCounterUah;
|
||||
p->batteryTechnology = ::android::String8(info.batteryTechnology.c_str());
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::health
|
31
health/aidl/default/health-convert.h
Normal file
31
health/aidl/default/health-convert.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/health/HealthInfo.h>
|
||||
#include <batteryservice/BatteryService.h>
|
||||
#include <healthd/healthd.h>
|
||||
|
||||
// Conversion between healthd types and AIDL health HAL types. Note that most
|
||||
// of the conversion loses information, because these types have a different
|
||||
// set of information.
|
||||
|
||||
namespace aidl::android::hardware::health {
|
||||
|
||||
void convert(const HealthInfo& info, struct ::android::BatteryProperties* out);
|
||||
|
||||
} // namespace aidl::android::hardware::health
|
77
health/aidl/default/include/health-impl/HalHealthLoop.h
Normal file
77
health/aidl/default/include/health-impl/HalHealthLoop.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <aidl/android/hardware/health/IHealth.h>
|
||||
#include <health/HealthLoop.h>
|
||||
|
||||
namespace aidl::android::hardware::health {
|
||||
|
||||
class HalHealthLoop;
|
||||
|
||||
class HalHealthLoopCallback {
|
||||
public:
|
||||
virtual ~HalHealthLoopCallback() = default;
|
||||
|
||||
// Called by HalHealthLoop::Init
|
||||
virtual void OnInit(HalHealthLoop* hal_health_loop, struct healthd_config* config) = 0;
|
||||
// Called by HalHealthLoop::Heartbeat
|
||||
virtual void OnHeartbeat(){};
|
||||
// Called by HalHealthLoop::PrepareToWait
|
||||
virtual int OnPrepareToWait() { return -1; }
|
||||
// Called by HalHealthLoop::ScheduleBatteryUpdate
|
||||
virtual void OnHealthInfoChanged(const HealthInfo&) {}
|
||||
};
|
||||
|
||||
// AIDL version of android::hardware::health::V2_1::implementation::HalHealthLoop.
|
||||
// An implementation of HealthLoop for using a given health HAL.
|
||||
class HalHealthLoop final : public ::android::hardware::health::HealthLoop {
|
||||
public:
|
||||
// Caller must ensure that the lifetime of service_ is not shorter than this object.
|
||||
HalHealthLoop(std::shared_ptr<IHealth> service, std::shared_ptr<HalHealthLoopCallback> callback)
|
||||
: service_(std::move(service)), callback_(std::move(callback)) {}
|
||||
|
||||
using HealthLoop::RegisterEvent;
|
||||
|
||||
bool charger_online() const { return charger_online_; }
|
||||
|
||||
protected:
|
||||
virtual void Init(struct healthd_config* config) override;
|
||||
virtual void Heartbeat() override;
|
||||
virtual int PrepareToWait() override;
|
||||
virtual void ScheduleBatteryUpdate() override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<IHealth> service_;
|
||||
std::shared_ptr<HalHealthLoopCallback> callback_;
|
||||
bool charger_online_ = false;
|
||||
|
||||
// Helpers of OnHealthInfoChanged.
|
||||
void set_charger_online(const HealthInfo& health_info);
|
||||
|
||||
// HealthLoop periodically calls ScheduleBatteryUpdate, which calls
|
||||
// OnHealthInfoChanged callback. A subclass of the callback can override
|
||||
// HalHealthLoopCallback::OnHealthInfoChanged to
|
||||
// broadcast the health_info to interested listeners.
|
||||
// This adjust uevents / wakealarm periods.
|
||||
void OnHealthInfoChanged(const HealthInfo& health_info);
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::health
|
113
health/aidl/default/include/health-impl/Health.h
Normal file
113
health/aidl/default/include/health-impl/Health.h
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <aidl/android/hardware/health/BnHealth.h>
|
||||
#include <aidl/android/hardware/health/IHealthInfoCallback.h>
|
||||
#include <android/binder_auto_utils.h>
|
||||
#include <health-impl/HalHealthLoop.h>
|
||||
#include <healthd/BatteryMonitor.h>
|
||||
#include <healthd/healthd.h>
|
||||
|
||||
namespace aidl::android::hardware::health {
|
||||
|
||||
class LinkedCallback;
|
||||
|
||||
// AIDL version of android::hardware::health::V2_1::implementation::Health and BinderHealth.
|
||||
// There's no need to separate the two in AIDL because AIDL does not support passthrough transport.
|
||||
//
|
||||
// Instead of inheriting from HalHealthLoop directly, implements the callback interface to
|
||||
// HalHealthLoop instead.
|
||||
//
|
||||
// Sample implementation of health HAL.
|
||||
class Health : public BnHealth, public HalHealthLoopCallback {
|
||||
public:
|
||||
// Initialize with |config|.
|
||||
// A subclass may modify |config| before passing it to the parent constructor.
|
||||
// See implementation of Health for code samples.
|
||||
Health(std::string_view instance_name, std::unique_ptr<struct healthd_config>&& config);
|
||||
|
||||
ndk::ScopedAStatus registerCallback(
|
||||
const std::shared_ptr<IHealthInfoCallback>& callback) override;
|
||||
ndk::ScopedAStatus unregisterCallback(
|
||||
const std::shared_ptr<IHealthInfoCallback>& callback) override;
|
||||
ndk::ScopedAStatus update() override;
|
||||
|
||||
// A subclass should not override this. Override UpdateHealthInfo instead.
|
||||
ndk::ScopedAStatus getHealthInfo(HealthInfo* out) override final;
|
||||
|
||||
// A subclass is recommended to override the path in healthd_config in the constructor.
|
||||
// Only override these if there are no suitable kernel interfaces to read these values.
|
||||
ndk::ScopedAStatus getChargeCounterUah(int32_t* out) override;
|
||||
ndk::ScopedAStatus getCurrentNowMicroamps(int32_t* out) override;
|
||||
ndk::ScopedAStatus getCurrentAverageMicroamps(int32_t* out) override;
|
||||
ndk::ScopedAStatus getCapacity(int32_t* out) override;
|
||||
ndk::ScopedAStatus getChargeStatus(BatteryStatus* out) override;
|
||||
|
||||
// A subclass may either override these or provide function pointers in
|
||||
// in healthd_config in the constructor.
|
||||
// Prefer overriding these for efficiency.
|
||||
ndk::ScopedAStatus getEnergyCounterNwh(int64_t* out) override;
|
||||
|
||||
// A subclass may override these for a specific device.
|
||||
// The default implementations return nothing in |out|.
|
||||
ndk::ScopedAStatus getDiskStats(std::vector<DiskStats>* out) override;
|
||||
ndk::ScopedAStatus getStorageInfo(std::vector<StorageInfo>* out) override;
|
||||
|
||||
// A subclass may override these to provide a different implementation.
|
||||
binder_status_t dump(int fd, const char** args, uint32_t num_args) override;
|
||||
|
||||
// HalHealthLoopCallback implementation.
|
||||
void OnInit(HalHealthLoop* hal_health_loop, struct healthd_config* config) override;
|
||||
void OnHealthInfoChanged(const HealthInfo& health_info) override;
|
||||
|
||||
// A subclass may override this if it wants to handle binder events differently.
|
||||
virtual void BinderEvent(uint32_t epevents);
|
||||
|
||||
// A subclass may override this to determine whether screen should be kept on in charger mode.
|
||||
// Default is to invoke healthd_config->screen_on() on the BatteryProperties converted
|
||||
// from getHealthInfo.
|
||||
// Prefer overriding these to providing screen_on in healthd_config in the constructor
|
||||
// for efficiency.
|
||||
virtual std::optional<bool> ShouldKeepScreenOn();
|
||||
|
||||
protected:
|
||||
// A subclass can override this to modify any health info object before
|
||||
// returning to clients. This is similar to healthd_board_battery_update().
|
||||
// By default, it does nothing.
|
||||
// See implementation of Health for code samples.
|
||||
virtual void UpdateHealthInfo(HealthInfo* health_info);
|
||||
|
||||
private:
|
||||
friend LinkedCallback; // for exposing death_recipient_
|
||||
|
||||
bool unregisterCallbackInternal(std::shared_ptr<IHealthInfoCallback> callback);
|
||||
|
||||
std::string instance_name_;
|
||||
::android::BatteryMonitor battery_monitor_;
|
||||
std::unique_ptr<struct healthd_config> healthd_config_;
|
||||
|
||||
ndk::ScopedAIBinder_DeathRecipient death_recipient_;
|
||||
int binder_fd_ = -1;
|
||||
std::mutex callbacks_lock_;
|
||||
std::vector<std::unique_ptr<LinkedCallback>> callbacks_;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::health
|
35
health/aidl/default/main.cpp
Normal file
35
health/aidl/default/main.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android/binder_interface_utils.h>
|
||||
#include <health-impl/Health.h>
|
||||
#include <health/utils.h>
|
||||
|
||||
using aidl::android::hardware::health::HalHealthLoop;
|
||||
using aidl::android::hardware::health::Health;
|
||||
|
||||
static constexpr const char* gInstanceName = "default";
|
||||
|
||||
int main() {
|
||||
// TODO(b/203246116): handle charger
|
||||
// make a default health service
|
||||
auto config = std::make_unique<healthd_config>();
|
||||
::android::hardware::health::InitHealthdConfig(config.get());
|
||||
auto binder = ndk::SharedRefBase::make<Health>(gInstanceName, std::move(config));
|
||||
auto hal_health_loop = std::make_shared<HalHealthLoop>(binder, binder);
|
||||
return hal_health_loop->StartLoop();
|
||||
}
|
|
@ -46,6 +46,12 @@ class HealthLoop {
|
|||
// Init is called right after epollfd_ is initialized (so RegisterEvent
|
||||
// is allowed) but before other things are initialized (so SetChargerOnline
|
||||
// is not allowed.)
|
||||
// The implementation of Init() should pull configuration from the
|
||||
// underlying health HAL (via getHealthConfig()), and store it into
|
||||
// |config|. The implementation may not initialize:
|
||||
// - screen_on, because charger calls getScreenOn() from the HAL directly
|
||||
// - ignorePowerSupplyNames, because it isn't used by any clients of the
|
||||
// health HAL.
|
||||
virtual void Init(healthd_config* config) = 0;
|
||||
virtual void Heartbeat() = 0;
|
||||
virtual int PrepareToWait() = 0;
|
||||
|
|
Loading…
Reference in a new issue