149 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			149 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * 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
 |