From bae3a655a0fd922f08ea79c1e68f01b57cd38b3a Mon Sep 17 00:00:00 2001 From: Wasb Liu Date: Mon, 17 Sep 2018 14:51:30 +0800 Subject: HealthService: save and restore charge cycle counts Bug: 115849755 Test: boot to home and cycle count works Change-Id: I1e4390bf538a368544d5469e1e21457b0a7bd3fc Signed-off-by: Wasb Liu --- health/Android.bp | 1 + health/CycleCountBackupRestore.cpp | 151 +++++++++++++++++++++++++++++++++++++ health/CycleCountBackupRestore.h | 60 +++++++++++++++ health/HealthService.cpp | 7 ++ 4 files changed, 219 insertions(+) create mode 100644 health/CycleCountBackupRestore.cpp create mode 100644 health/CycleCountBackupRestore.h (limited to 'health') diff --git a/health/Android.bp b/health/Android.bp index ab6a52aa..735e0325 100644 --- a/health/Android.bp +++ b/health/Android.bp @@ -21,6 +21,7 @@ cc_binary { srcs: [ "HealthService.cpp", "BatteryRechargingControl.cpp", + "CycleCountBackupRestore.cpp", ], cflags: [ diff --git a/health/CycleCountBackupRestore.cpp b/health/CycleCountBackupRestore.cpp new file mode 100644 index 00000000..05f656ab --- /dev/null +++ b/health/CycleCountBackupRestore.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CycleCountBackupRestore.h" + +namespace device { +namespace google { +namespace bonito { +namespace health { + +static constexpr int kBackupTrigger = 20; + +CycleCountBackupRestore::CycleCountBackupRestore(int nb_buckets, const char *sysfs_path, + const char *persist_path, const char *serial_path) + : nb_buckets_(nb_buckets), + saved_soc_(-1), + soc_inc_(0), + sysfs_path_(sysfs_path), + persist_path_(persist_path), + serial_path_(serial_path) { + sw_bins_ = new int[nb_buckets]; + memset(sw_bins_, 0, sizeof(sw_bins_)); + hw_bins_ = new int[nb_buckets]; + memset(hw_bins_, 0, sizeof(hw_bins_)); +} + +void CycleCountBackupRestore::Restore() { + if (CheckSerial()) { + Read(persist_path_, sw_bins_); + } + Read(sysfs_path_, hw_bins_); + UpdateAndSave(); +} + +bool CycleCountBackupRestore::CheckSerial() { + std::string device_battery_serial; + std::string persist_battery_serial; + + if (serial_path_.empty()) + return true; + + if (!android::base::ReadFileToString(serial_path_, &device_battery_serial)) { + LOG(ERROR) << "Failed to read " << serial_path_; + return true; + } + + if (!android::base::ReadFileToString(kPersistSerial, &persist_battery_serial)) { + LOG(ERROR) << "Failed to read " << kPersistSerial; + } + + if (device_battery_serial != persist_battery_serial) { + // Battery pack has been changed or first time, + // cycle counts on the pack are the ones to save + if (!android::base::WriteStringToFile(device_battery_serial, kPersistSerial)) { + LOG(ERROR) << "Write to " << kPersistSerial << " error: " << strerror(errno); + } + return false; + } + + return true; +} + +void CycleCountBackupRestore::Backup(int battery_level) { + if (saved_soc_ == -1) { + saved_soc_ = battery_level; + return; + } + // Cycle counts only increases on increasing level + if (battery_level > saved_soc_) { + soc_inc_ += battery_level - saved_soc_; + } + saved_soc_ = battery_level; + // To avoid writting file too often just rate limit it + if (soc_inc_ >= kBackupTrigger) { + Read(sysfs_path_, hw_bins_); + UpdateAndSave(); + soc_inc_ = 0; + } +} + +void CycleCountBackupRestore::Read(const std::string &path, int *bins) { + std::string buffer; + + if (!android::base::ReadFileToString(path, &buffer)) { + LOG(ERROR) << "Failed to read " << path; + return; + } + + buffer = ::android::base::Trim(buffer); + std::vector counts = android::base::Split(buffer, " "); + if (counts.size() != (size_t)nb_buckets_) { + LOG(ERROR) << "data format \"" << buffer << "\" is wrong in " << path; + } else { + LOG(INFO) << "Read: \"" << buffer << "\" from " << path; + for (int i = 0; i < nb_buckets_; ++i) { + bins[i] = std::stoi(counts[i]); + } + } +} + +void CycleCountBackupRestore::Write(int *bins, const std::string &path) { + std::string str_data = ""; + + for (int i = 0; i < nb_buckets_; ++i) { + if (i) { + str_data += " "; + } + str_data += std::to_string(bins[i]); + } + + LOG(INFO) << "Write: \"" << str_data << "\" to " << path; + if (!android::base::WriteStringToFile(str_data, path)) + LOG(ERROR) << "Write to " << path << " error: " << strerror(errno); +} + +void CycleCountBackupRestore::UpdateAndSave() { + bool backup = false; + bool restore = false; + for (int i = 0; i < nb_buckets_; i++) { + if (hw_bins_[i] < sw_bins_[i]) { + hw_bins_[i] = sw_bins_[i]; + restore = true; + } else if (hw_bins_[i] > sw_bins_[i]) { + sw_bins_[i] = hw_bins_[i]; + backup = true; + } + } + if (restore) + Write(hw_bins_, sysfs_path_); + if (backup) + Write(sw_bins_, persist_path_); +} + +} // namespace health +} // namespace bonito +} // namespace google +} // namespace device + diff --git a/health/CycleCountBackupRestore.h b/health/CycleCountBackupRestore.h new file mode 100644 index 00000000..e2ba1f21 --- /dev/null +++ b/health/CycleCountBackupRestore.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DEVICE_GOOGLE_BONITO_HEALTH_CYCLECOUNTBACKUPRESTORE_H +#define DEVICE_GOOGLE_BONITO_HEALTH_CYCLECOUNTBACKUPRESTORE_H + +#include +#include +#include +#include + +namespace device { +namespace google { +namespace bonito { +namespace health { + +class CycleCountBackupRestore { + public: + CycleCountBackupRestore(int nb_buckets, const char *sysfs_path, const char *persist_path, + const char *serial_path = ""); + void Restore(); + void Backup(int battery_level); + + private: + const char *kPersistSerial = "/persist/battery/serial_number"; + + int nb_buckets_; + int *sw_bins_; + int *hw_bins_; + int saved_soc_; + int soc_inc_; + std::string sysfs_path_; + std::string persist_path_; + std::string serial_path_; + + void Read(const std::string &path, int *bins); + void Write(int *bins, const std::string &path); + void UpdateAndSave(); + bool CheckSerial(); +}; + +} // namespace health +} // namespace bonito +} // namespace google +} // namespace device + +#endif // #ifndef DEVICE_GOOGLE_BONITO_HEALTH_CYCLECOUNTBACKUPRESTORE_H diff --git a/health/HealthService.cpp b/health/HealthService.cpp index 88103f81..db3730d0 100644 --- a/health/HealthService.cpp +++ b/health/HealthService.cpp @@ -30,6 +30,7 @@ #include #include "BatteryRechargingControl.h" +#include "CycleCountBackupRestore.h" namespace { @@ -37,8 +38,12 @@ using android::hardware::health::V2_0::DiskStats; using android::hardware::health::V2_0::StorageAttribute; using android::hardware::health::V2_0::StorageInfo; using ::device::google::bonito::health::BatteryRechargingControl; +using ::device::google::bonito::health::CycleCountBackupRestore; static BatteryRechargingControl battRechargingControl; +static CycleCountBackupRestore ccBackupRestoreBMS( + 8, "/sys/class/power_supply/bms/device/cycle_counts_bins", + "/persist/battery/qcom_cycle_counts_bins"); #define EMMC_DIR "/sys/devices/platform/soc/7c4000.sdhci" const std::string kEmmcHealthEol{EMMC_DIR "/health/eol"}; @@ -80,10 +85,12 @@ void fill_emmc_storage_attribute(StorageAttribute* attr) { } // anonymous namespace void healthd_board_init(struct healthd_config*) { + ccBackupRestoreBMS.Restore(); } int healthd_board_battery_update(struct android::BatteryProperties *props) { battRechargingControl.updateBatteryProperties(props); + ccBackupRestoreBMS.Backup(props->batteryLevel); return 0; } -- cgit v1.2.3