blob: c1dd194dcf5423e6c389cc27205c87f690cbe2c5 [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) {
112 getProperty(battery_monitor_, BATTERY_PROP_CHARGE_COUNTER, INT32_MIN, _hidl_cb);
113 return Void();
114}
115
116Return<void> Health::getCurrentNow(getCurrentNow_cb _hidl_cb) {
117 getProperty(battery_monitor_, BATTERY_PROP_CURRENT_NOW, INT32_MIN, _hidl_cb);
118 return Void();
119}
120
121Return<void> Health::getCurrentAverage(getCurrentAverage_cb _hidl_cb) {
122 getProperty(battery_monitor_, BATTERY_PROP_CURRENT_AVG, INT32_MIN, _hidl_cb);
123 return Void();
124}
125
126Return<void> Health::getCapacity(getCapacity_cb _hidl_cb) {
127 getProperty(battery_monitor_, BATTERY_PROP_CAPACITY, INT32_MIN, _hidl_cb);
128 return Void();
129}
130
131Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) {
132 getProperty(battery_monitor_, BATTERY_PROP_ENERGY_COUNTER, INT64_MIN, _hidl_cb);
133 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
158void Health::notifyListeners(const HealthInfo& info) {
159 std::lock_guard<std::mutex> _lock(callbacks_lock_);
160 for (auto it = callbacks_.begin(); it != callbacks_.end();) {
161 auto ret = (*it)->healthInfoChanged(info);
162 if (!ret.isOk() && ret.isDeadObject()) {
163 it = callbacks_.erase(it);
164 } else {
165 ++it;
166 }
167 }
168}
169
170Return<void> Health::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
171 if (handle != nullptr && handle->numFds >= 1) {
172 int fd = handle->data[0];
173 battery_monitor_->dumpState(fd);
174 fsync(fd);
175 }
176 return Void();
177}
178
Hridya Valsaraju2b520832017-12-20 13:25:29 -0800179Return<void> Health::getStorageInfo(getStorageInfo_cb _hidl_cb) {
180 std::vector<struct StorageInfo> info;
181 get_storage_info(info);
182 hidl_vec<struct StorageInfo> info_vec(info);
183 if (!info.size()) {
184 _hidl_cb(Result::NOT_SUPPORTED, info_vec);
185 } else {
186 _hidl_cb(Result::SUCCESS, info_vec);
187 }
188 return Void();
189}
190
191Return<void> Health::getDiskStats(getDiskStats_cb _hidl_cb) {
192 std::vector<struct DiskStats> stats;
193 get_disk_stats(stats);
194 hidl_vec<struct DiskStats> stats_vec(stats);
195 if (!stats.size()) {
196 _hidl_cb(Result::NOT_SUPPORTED, stats_vec);
197 } else {
198 _hidl_cb(Result::SUCCESS, stats_vec);
199 }
200 return Void();
201}
202
Hridya Valsaraju1bd37722018-01-12 10:25:59 -0800203Return<void> Health::getHealthInfo(getHealthInfo_cb _hidl_cb) {
204 using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
205
206 update();
207 struct android::BatteryProperties p = getBatteryProperties(battery_monitor_.get());
208
209 V1_0::HealthInfo batteryInfo;
210 convertToHealthInfo(&p, batteryInfo);
211
212 std::vector<StorageInfo> info;
213 get_storage_info(info);
214
215 std::vector<DiskStats> stats;
216 get_disk_stats(stats);
217
218 int32_t currentAvg = 0;
219
220 struct BatteryProperty prop;
221 status_t ret = battery_monitor_->getProperty(BATTERY_PROP_CURRENT_AVG, &prop);
222 if (ret == OK) {
223 currentAvg = static_cast<int32_t>(prop.valueInt64);
224 }
225
226 V2_0::HealthInfo healthInfo = {};
227 healthInfo.legacy = std::move(batteryInfo);
228 healthInfo.batteryCurrentAverage = currentAvg;
229 healthInfo.diskStats = stats;
230 healthInfo.storageInfos = info;
231
232 _hidl_cb(Result::SUCCESS, healthInfo);
233 return Void();
234}
235
Hridya Valsarajud3e3d722017-12-11 17:31:00 -0800236void Health::serviceDied(uint64_t /* cookie */, const wp<IBase>& who) {
237 (void)unregisterCallbackInternal(who.promote());
238}
239
240sp<IHealth> Health::initInstance(struct healthd_config* c) {
241 if (instance_ == nullptr) {
242 instance_ = new Health(c);
243 }
244 return instance_;
245}
246
247sp<Health> Health::getImplementation() {
248 CHECK(instance_ != nullptr);
249 return instance_;
250}
251
252} // namespace implementation
253} // namespace V2_0
254} // namespace health
255} // namespace hardware
256} // namespace android