blob: 7a3e6504089f24820a1c63d4529098a638987ee6 [file] [log] [blame]
Hridya Valsaraju2b520832017-12-20 13:25:29 -08001/*
2 * Copyright (C) 2018 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 */
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080016#define LOG_TAG "android.hardware.health@2.0-impl"
17#include <android-base/logging.h>
18
19#include <health2/Health.h>
20
Hridya Valsaraju1bd37722018-01-12 10:25:59 -080021#include <hal_conversion.h>
Hridya Valsarajud3e3d722017-12-11 17:31:00 -080022#include <hidl/HidlTransportSupport.h>
23
24extern void healthd_battery_update_internal(bool);
25
26namespace android {
27namespace hardware {
28namespace health {
29namespace V2_0 {
30namespace implementation {
31
32sp<Health> Health::instance_;
33
34Health::Health(struct healthd_config* c) {
35 // TODO(b/69268160): remove when libhealthd is removed.
36 healthd_board_init(c);
37 battery_monitor_ = std::make_unique<BatteryMonitor>();
38 battery_monitor_->init(c);
39}
40
41// Methods from IHealth follow.
42Return<Result> Health::registerCallback(const sp<IHealthInfoCallback>& callback) {
43 if (callback == nullptr) {
44 return Result::SUCCESS;
45 }
46
47 {
48 std::lock_guard<std::mutex> _lock(callbacks_lock_);
49 callbacks_.push_back(callback);
50 // unlock
51 }
52
53 auto linkRet = callback->linkToDeath(this, 0u /* cookie */);
54 if (!linkRet.withDefault(false)) {
55 LOG(WARNING) << __func__ << "Cannot link to death: "
56 << (linkRet.isOk() ? "linkToDeath returns false" : linkRet.description());
57 // ignore the error
58 }
59
60 return update();
61}
62
63bool Health::unregisterCallbackInternal(const sp<IBase>& callback) {
64 if (callback == nullptr) return false;
65
66 bool removed = false;
67 std::lock_guard<std::mutex> _lock(callbacks_lock_);
68 for (auto it = callbacks_.begin(); it != callbacks_.end();) {
69 if (interfacesEqual(*it, callback)) {
70 it = callbacks_.erase(it);
71 removed = true;
72 } else {
73 ++it;
74 }
75 }
76 (void)callback->unlinkToDeath(this).isOk(); // ignore errors
77 return removed;
78}
79
80Return<Result> Health::unregisterCallback(const sp<IHealthInfoCallback>& callback) {
81 return unregisterCallbackInternal(callback) ? Result::SUCCESS : Result::NOT_FOUND;
82}
83
84template <typename T>
85void getProperty(const std::unique_ptr<BatteryMonitor>& monitor, int id, T defaultValue,
86 const std::function<void(Result, T)>& callback) {
87 struct BatteryProperty prop;
88 T ret = defaultValue;
89 Result result = Result::SUCCESS;
90 status_t err = monitor->getProperty(static_cast<int>(id), &prop);
91 if (err != OK) {
92 LOG(DEBUG) << "getProperty(" << id << ")"
93 << " fails: (" << err << ") " << strerror(-err);
94 } else {
95 ret = static_cast<T>(prop.valueInt64);
96 }
97 switch (err) {
98 case OK:
99 result = Result::SUCCESS;
100 break;
101 case NAME_NOT_FOUND:
102 result = Result::NOT_SUPPORTED;
103 break;
104 default:
105 result = Result::UNKNOWN;
106 break;
107 }
108 callback(result, static_cast<T>(ret));
109}
110
111Return<void> Health::getChargeCounter(getChargeCounter_cb _hidl_cb) {
Yifan Hong81874af2018-01-17 10:59:12 -0800112 getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CHARGE_COUNTER, 0, _hidl_cb);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800113 return Void();
114}
115
116Return<void> Health::getCurrentNow(getCurrentNow_cb _hidl_cb) {
Yifan Hong81874af2018-01-17 10:59:12 -0800117 getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CURRENT_NOW, 0, _hidl_cb);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800118 return Void();
119}
120
121Return<void> Health::getCurrentAverage(getCurrentAverage_cb _hidl_cb) {
Yifan Hong81874af2018-01-17 10:59:12 -0800122 getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CURRENT_AVG, 0, _hidl_cb);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800123 return Void();
124}
125
126Return<void> Health::getCapacity(getCapacity_cb _hidl_cb) {
Yifan Hong81874af2018-01-17 10:59:12 -0800127 getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CAPACITY, 0, _hidl_cb);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800128 return Void();
129}
130
131Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) {
Yifan Hong81874af2018-01-17 10:59:12 -0800132 getProperty<int64_t>(battery_monitor_, BATTERY_PROP_ENERGY_COUNTER, 0, _hidl_cb);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800133 return Void();
134}
135
136Return<void> Health::getChargeStatus(getChargeStatus_cb _hidl_cb) {
137 getProperty(battery_monitor_, BATTERY_PROP_BATTERY_STATUS, BatteryStatus::UNKNOWN, _hidl_cb);
138 return Void();
139}
140
141Return<Result> Health::update() {
142 if (!healthd_mode_ops || !healthd_mode_ops->battery_update) {
143 LOG(WARNING) << "health@2.0: update: not initialized. "
144 << "update() should not be called in charger / recovery.";
145 return Result::UNKNOWN;
146 }
147
148 // Retrieve all information and call healthd_mode_ops->battery_update, which calls
149 // notifyListeners.
150 bool chargerOnline = battery_monitor_->update();
151
152 // adjust uevent / wakealarm periods
153 healthd_battery_update_internal(chargerOnline);
154
155 return Result::SUCCESS;
156}
157
Hridya Valsarajud31932a2018-01-17 23:09:24 -0800158void Health::notifyListeners(HealthInfo* healthInfo) {
159 std::vector<StorageInfo> info;
160 get_storage_info(info);
161
162 std::vector<DiskStats> stats;
163 get_disk_stats(stats);
164
165 int32_t currentAvg = 0;
166
167 struct BatteryProperty prop;
168 status_t ret = battery_monitor_->getProperty(BATTERY_PROP_CURRENT_AVG, &prop);
169 if (ret == OK) {
170 currentAvg = static_cast<int32_t>(prop.valueInt64);
171 }
172
173 healthInfo->batteryCurrentAverage = currentAvg;
174 healthInfo->diskStats = stats;
175 healthInfo->storageInfos = info;
176
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800177 std::lock_guard<std::mutex> _lock(callbacks_lock_);
178 for (auto it = callbacks_.begin(); it != callbacks_.end();) {
Hridya Valsarajud31932a2018-01-17 23:09:24 -0800179 auto ret = (*it)->healthInfoChanged(*healthInfo);
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800180 if (!ret.isOk() && ret.isDeadObject()) {
181 it = callbacks_.erase(it);
182 } else {
183 ++it;
184 }
185 }
186}
187
188Return<void> Health::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
189 if (handle != nullptr && handle->numFds >= 1) {
190 int fd = handle->data[0];
191 battery_monitor_->dumpState(fd);
192 fsync(fd);
193 }
194 return Void();
195}
196
Hridya Valsaraju2b520832017-12-20 13:25:29 -0800197Return<void> Health::getStorageInfo(getStorageInfo_cb _hidl_cb) {
198 std::vector<struct StorageInfo> info;
199 get_storage_info(info);
200 hidl_vec<struct StorageInfo> info_vec(info);
201 if (!info.size()) {
202 _hidl_cb(Result::NOT_SUPPORTED, info_vec);
203 } else {
204 _hidl_cb(Result::SUCCESS, info_vec);
205 }
206 return Void();
207}
208
209Return<void> Health::getDiskStats(getDiskStats_cb _hidl_cb) {
210 std::vector<struct DiskStats> stats;
211 get_disk_stats(stats);
212 hidl_vec<struct DiskStats> stats_vec(stats);
213 if (!stats.size()) {
214 _hidl_cb(Result::NOT_SUPPORTED, stats_vec);
215 } else {
216 _hidl_cb(Result::SUCCESS, stats_vec);
217 }
218 return Void();
219}
220
Hridya Valsaraju1bd37722018-01-12 10:25:59 -0800221Return<void> Health::getHealthInfo(getHealthInfo_cb _hidl_cb) {
222 using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
223
224 update();
225 struct android::BatteryProperties p = getBatteryProperties(battery_monitor_.get());
226
227 V1_0::HealthInfo batteryInfo;
228 convertToHealthInfo(&p, batteryInfo);
229
230 std::vector<StorageInfo> info;
231 get_storage_info(info);
232
233 std::vector<DiskStats> stats;
234 get_disk_stats(stats);
235
236 int32_t currentAvg = 0;
237
238 struct BatteryProperty prop;
239 status_t ret = battery_monitor_->getProperty(BATTERY_PROP_CURRENT_AVG, &prop);
240 if (ret == OK) {
241 currentAvg = static_cast<int32_t>(prop.valueInt64);
242 }
243
244 V2_0::HealthInfo healthInfo = {};
245 healthInfo.legacy = std::move(batteryInfo);
246 healthInfo.batteryCurrentAverage = currentAvg;
247 healthInfo.diskStats = stats;
248 healthInfo.storageInfos = info;
249
250 _hidl_cb(Result::SUCCESS, healthInfo);
251 return Void();
252}
253
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800254void Health::serviceDied(uint64_t /* cookie */, const wp<IBase>& who) {
255 (void)unregisterCallbackInternal(who.promote());
256}
257
258sp<IHealth> Health::initInstance(struct healthd_config* c) {
259 if (instance_ == nullptr) {
260 instance_ = new Health(c);
261 }
262 return instance_;
263}
264
265sp<Health> Health::getImplementation() {
266 CHECK(instance_ != nullptr);
267 return instance_;
268}
269
270} // namespace implementation
271} // namespace V2_0
272} // namespace health
273} // namespace hardware
274} // namespace android