1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <health2impl/Health.h>
18
19 #include <functional>
20 #include <string_view>
21
22 #include <android-base/file.h>
23 #include <android-base/logging.h>
24 #include <android/hardware/health/1.0/types.h>
25 #include <android/hardware/health/2.0/IHealthInfoCallback.h>
26 #include <android/hardware/health/2.0/types.h>
27 #include <android/hardware/health/2.1/IHealthInfoCallback.h>
28 #include <hal_conversion.h>
29 #include <healthd/healthd.h>
30 #include <hidl/HidlTransportSupport.h>
31 #include <hwbinder/IPCThreadState.h>
32
33 #include <health2impl/Callback.h>
34 #include <health2impl/HalHealthLoop.h>
35
36 using android::hardware::health::V1_0::BatteryStatus;
37 using android::hardware::health::V1_0::toString;
38 using android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;
39 using android::hardware::health::V1_0::hal_conversion::convertToHealthConfig;
40 using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
41 using android::hardware::health::V2_0::Result;
42 using android::hardware::health::V2_1::IHealth;
43
44 using ScreenOn = decltype(healthd_config::screen_on);
45
46 namespace android {
47 namespace hardware {
48 namespace health {
49 namespace V2_1 {
50 namespace implementation {
51
52 /*
53 // If you need to call healthd_board_init, construct the Health instance with
54 // the healthd_config after calling healthd_board_init:
55 struct healthd_config* init_config(struct healthd_config* config) {
56 healthd_board_init(config);
57 return config;
58 }
59 class MyHealth : public Health {
60 MyHealth(struct healthd_config* config) :
61 Health(init_config(config)) {}
62 };
63 */
64
Health(std::unique_ptr<healthd_config> && config)65 Health::Health(std::unique_ptr<healthd_config>&& config) : healthd_config_(std::move(config)) {
66 battery_monitor_.init(healthd_config_.get());
67 }
68
69 //
70 // Callbacks are not supported by the passthrough implementation.
71 //
72
registerCallback(const sp<V2_0::IHealthInfoCallback> &)73 Return<Result> Health::registerCallback(const sp<V2_0::IHealthInfoCallback>&) {
74 return Result::NOT_SUPPORTED;
75 }
76
unregisterCallback(const sp<V2_0::IHealthInfoCallback> &)77 Return<Result> Health::unregisterCallback(const sp<V2_0::IHealthInfoCallback>&) {
78 return Result::NOT_SUPPORTED;
79 }
80
update()81 Return<Result> Health::update() {
82 Result result = Result::UNKNOWN;
83 getHealthInfo_2_1([&](auto res, const auto& /* health_info */) {
84 result = res;
85 if (res != Result::SUCCESS) {
86 LOG(ERROR) << "Cannot call getHealthInfo_2_1: " << toString(res);
87 return;
88 }
89
90 battery_monitor_.logValues();
91 });
92 return result;
93 }
94
95 //
96 // Getters.
97 //
98
99 template <typename T>
GetProperty(BatteryMonitor * monitor,int id,T defaultValue,const std::function<void (Result,T)> & callback)100 static Return<void> GetProperty(BatteryMonitor* monitor, int id, T defaultValue,
101 const std::function<void(Result, T)>& callback) {
102 struct BatteryProperty prop;
103 T ret = defaultValue;
104 Result result = Result::SUCCESS;
105 status_t err = monitor->getProperty(static_cast<int>(id), &prop);
106 if (err != OK) {
107 LOG(DEBUG) << "getProperty(" << id << ")"
108 << " fails: (" << err << ") " << strerror(-err);
109 } else {
110 ret = static_cast<T>(prop.valueInt64);
111 }
112 switch (err) {
113 case OK:
114 result = Result::SUCCESS;
115 break;
116 case NAME_NOT_FOUND:
117 result = Result::NOT_SUPPORTED;
118 break;
119 default:
120 result = Result::UNKNOWN;
121 break;
122 }
123 callback(result, static_cast<T>(ret));
124 return Void();
125 }
126
getChargeCounter(getChargeCounter_cb _hidl_cb)127 Return<void> Health::getChargeCounter(getChargeCounter_cb _hidl_cb) {
128 return GetProperty<int32_t>(&battery_monitor_, BATTERY_PROP_CHARGE_COUNTER, 0, _hidl_cb);
129 }
130
getCurrentNow(getCurrentNow_cb _hidl_cb)131 Return<void> Health::getCurrentNow(getCurrentNow_cb _hidl_cb) {
132 return GetProperty<int32_t>(&battery_monitor_, BATTERY_PROP_CURRENT_NOW, 0, _hidl_cb);
133 }
134
getCurrentAverage(getCurrentAverage_cb _hidl_cb)135 Return<void> Health::getCurrentAverage(getCurrentAverage_cb _hidl_cb) {
136 return GetProperty<int32_t>(&battery_monitor_, BATTERY_PROP_CURRENT_AVG, 0, _hidl_cb);
137 }
138
getCapacity(getCapacity_cb _hidl_cb)139 Return<void> Health::getCapacity(getCapacity_cb _hidl_cb) {
140 return GetProperty<int32_t>(&battery_monitor_, BATTERY_PROP_CAPACITY, 0, _hidl_cb);
141 }
142
getEnergyCounter(getEnergyCounter_cb _hidl_cb)143 Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) {
144 return GetProperty<int64_t>(&battery_monitor_, BATTERY_PROP_ENERGY_COUNTER, 0, _hidl_cb);
145 }
146
getChargeStatus(getChargeStatus_cb _hidl_cb)147 Return<void> Health::getChargeStatus(getChargeStatus_cb _hidl_cb) {
148 return GetProperty(&battery_monitor_, BATTERY_PROP_BATTERY_STATUS, BatteryStatus::UNKNOWN,
149 _hidl_cb);
150 }
151
getStorageInfo(getStorageInfo_cb _hidl_cb)152 Return<void> Health::getStorageInfo(getStorageInfo_cb _hidl_cb) {
153 // This implementation does not support StorageInfo. An implementation may extend this
154 // class and override this function to support storage info.
155 _hidl_cb(Result::NOT_SUPPORTED, {});
156 return Void();
157 }
158
getDiskStats(getDiskStats_cb _hidl_cb)159 Return<void> Health::getDiskStats(getDiskStats_cb _hidl_cb) {
160 // This implementation does not support DiskStats. An implementation may extend this
161 // class and override this function to support disk stats.
162 _hidl_cb(Result::NOT_SUPPORTED, {});
163 return Void();
164 }
165
166 template <typename T, typename Method>
GetHealthInfoField(Health * service,Method func,T * out)167 static inline void GetHealthInfoField(Health* service, Method func, T* out) {
168 *out = T{};
169 std::invoke(func, service, [out](Result result, const T& value) {
170 if (result == Result::SUCCESS) *out = value;
171 });
172 }
173
getHealthInfo(getHealthInfo_cb _hidl_cb)174 Return<void> Health::getHealthInfo(getHealthInfo_cb _hidl_cb) {
175 return getHealthInfo_2_1(
176 [&](auto res, const auto& health_info) { _hidl_cb(res, health_info.legacy); });
177 }
178
getHealthInfo_2_1(getHealthInfo_2_1_cb _hidl_cb)179 Return<void> Health::getHealthInfo_2_1(getHealthInfo_2_1_cb _hidl_cb) {
180 battery_monitor_.updateValues();
181
182 HealthInfo health_info = battery_monitor_.getHealthInfo_2_1();
183
184 // Fill in storage infos; these aren't retrieved by BatteryMonitor.
185 GetHealthInfoField(this, &Health::getStorageInfo, &health_info.legacy.storageInfos);
186 GetHealthInfoField(this, &Health::getDiskStats, &health_info.legacy.diskStats);
187
188 // A subclass may want to update health info struct before returning it.
189 UpdateHealthInfo(&health_info);
190
191 _hidl_cb(Result::SUCCESS, health_info);
192 return Void();
193 }
194
debug(const hidl_handle & handle,const hidl_vec<hidl_string> &)195 Return<void> Health::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
196 if (handle == nullptr || handle->numFds == 0) {
197 return Void();
198 }
199
200 int fd = handle->data[0];
201 battery_monitor_.dumpState(fd);
202 getHealthInfo_2_1([fd](auto res, const auto& info) {
203 android::base::WriteStringToFd("\ngetHealthInfo -> ", fd);
204 if (res == Result::SUCCESS) {
205 android::base::WriteStringToFd(toString(info), fd);
206 } else {
207 android::base::WriteStringToFd(toString(res), fd);
208 }
209 android::base::WriteStringToFd("\n", fd);
210 });
211
212 fsync(fd);
213 return Void();
214 }
215
getHealthConfig(getHealthConfig_cb _hidl_cb)216 Return<void> Health::getHealthConfig(getHealthConfig_cb _hidl_cb) {
217 HealthConfig config = {};
218 convertToHealthConfig(healthd_config_.get(), config.battery);
219 config.bootMinCap = static_cast<int32_t>(healthd_config_->boot_min_cap);
220
221 _hidl_cb(Result::SUCCESS, config);
222 return Void();
223 }
224
shouldKeepScreenOn(shouldKeepScreenOn_cb _hidl_cb)225 Return<void> Health::shouldKeepScreenOn(shouldKeepScreenOn_cb _hidl_cb) {
226 if (!healthd_config_->screen_on) {
227 _hidl_cb(Result::NOT_SUPPORTED, true);
228 return Void();
229 }
230
231 Result returned_result = Result::UNKNOWN;
232 bool screen_on = true;
233 getHealthInfo_2_1([&](auto res, const auto& health_info) {
234 returned_result = res;
235 if (returned_result != Result::SUCCESS) return;
236
237 struct BatteryProperties props = {};
238 V1_0::hal_conversion::convertFromHealthInfo(health_info.legacy.legacy, &props);
239 screen_on = healthd_config_->screen_on(&props);
240 });
241 _hidl_cb(returned_result, screen_on);
242 return Void();
243 }
244
245 //
246 // Subclass helpers / overrides
247 //
248
UpdateHealthInfo(HealthInfo *)249 void Health::UpdateHealthInfo(HealthInfo* /* health_info */) {
250 /*
251 // Sample code for a subclass to implement this:
252 // If you need to modify values (e.g. batteryChargeTimeToFullNowSeconds), do it here.
253 health_info->batteryChargeTimeToFullNowSeconds = calculate_charge_time_seconds();
254
255 // If you need to call healthd_board_battery_update:
256 struct BatteryProperties props;
257 convertFromHealthInfo(health_info.legacy.legacy, &props);
258 healthd_board_battery_update(&props);
259 convertToHealthInfo(&props, health_info.legacy.legacy);
260 */
261 }
262
263 } // namespace implementation
264 } // namespace V2_1
265 } // namespace health
266 } // namespace hardware
267 } // namespace android
268