| /* |
| * 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 <pixelhealth/CycleCountBackupRestore.h> |
| |
| namespace hardware { |
| namespace google { |
| namespace pixel { |
| 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](); |
| hw_bins_ = new int[nb_buckets](); |
| } |
| |
| 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<std::string> 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 pixel |
| } // namespace google |
| } // namespace hardware |