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