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 (at) 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 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. 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 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 81 Return<Result> Health::unregisterCallback(const sp<IHealthInfoCallback>& callback) { 82 return unregisterCallbackInternal(callback) ? Result::SUCCESS : Result::NOT_FOUND; 83 } 84 85 template <typename T> 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 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 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 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 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 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 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 142 Return<Result> Health::update() { 143 if (!healthd_mode_ops || !healthd_mode_ops->battery_update) { 144 LOG(WARNING) << "health (at) 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 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 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 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 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 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 266 void Health::serviceDied(uint64_t /* cookie */, const wp<IBase>& who) { 267 (void)unregisterCallbackInternal(who.promote()); 268 } 269 270 sp<IHealth> Health::initInstance(struct healthd_config* c) { 271 if (instance_ == nullptr) { 272 instance_ = new Health(c); 273 } 274 return instance_; 275 } 276 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