blob: 9b5b1006116bb66ced75a50984277fd09fd3ea62 [file] [log] [blame]
/*
* 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