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 
17 #include <pixelhealth/CycleCountBackupRestore.h>
18 
19 namespace hardware {
20 namespace google {
21 namespace pixel {
22 namespace health {
23 
24 static constexpr int kBackupTrigger = 20;
25 
CycleCountBackupRestore(int nb_buckets,const char * sysfs_path,const char * persist_path,const char * serial_path)26 CycleCountBackupRestore::CycleCountBackupRestore(int nb_buckets, const char *sysfs_path,
27                                                  const char *persist_path, const char *serial_path)
28     : nb_buckets_(nb_buckets),
29       saved_soc_(-1),
30       soc_inc_(0),
31       sysfs_path_(sysfs_path),
32       persist_path_(persist_path),
33       serial_path_(serial_path) {
34     sw_bins_ = new int[nb_buckets]();
35     hw_bins_ = new int[nb_buckets]();
36 }
37 
Restore()38 void CycleCountBackupRestore::Restore() {
39     if (CheckSerial()) {
40         Read(persist_path_, sw_bins_);
41     }
42     Read(sysfs_path_, hw_bins_);
43     UpdateAndSave();
44 }
45 
CheckSerial()46 bool CycleCountBackupRestore::CheckSerial() {
47     std::string device_battery_serial;
48     std::string persist_battery_serial;
49 
50     if (serial_path_.empty())
51         return true;
52 
53     if (!android::base::ReadFileToString(serial_path_, &device_battery_serial)) {
54         LOG(ERROR) << "Failed to read " << serial_path_;
55         return true;
56     }
57 
58     if (!android::base::ReadFileToString(kPersistSerial, &persist_battery_serial)) {
59         LOG(ERROR) << "Failed to read " << kPersistSerial;
60     }
61 
62     if (device_battery_serial != persist_battery_serial) {
63         // Battery pack has been changed or first time,
64         // cycle counts on the pack are the ones to save
65         if (!android::base::WriteStringToFile(device_battery_serial, kPersistSerial)) {
66             LOG(ERROR) << "Write to " << kPersistSerial << " error: " << strerror(errno);
67         }
68         return false;
69     }
70 
71     return true;
72 }
73 
Backup(int battery_level)74 void CycleCountBackupRestore::Backup(int battery_level) {
75     if (saved_soc_ == -1) {
76         saved_soc_ = battery_level;
77         return;
78     }
79     // Cycle counts only increases on increasing level
80     if (battery_level > saved_soc_) {
81         soc_inc_ += battery_level - saved_soc_;
82     }
83     saved_soc_ = battery_level;
84     // To avoid writting file too often just rate limit it
85     if (soc_inc_ >= kBackupTrigger) {
86         Read(sysfs_path_, hw_bins_);
87         UpdateAndSave();
88         soc_inc_ = 0;
89     }
90 }
91 
Read(const std::string & path,int * bins)92 void CycleCountBackupRestore::Read(const std::string &path, int *bins) {
93     std::string buffer;
94 
95     if (!android::base::ReadFileToString(path, &buffer)) {
96         LOG(ERROR) << "Failed to read " << path;
97         return;
98     }
99 
100     buffer = ::android::base::Trim(buffer);
101     std::vector<std::string> counts = android::base::Split(buffer, " ");
102     if (counts.size() != (size_t)nb_buckets_) {
103         LOG(ERROR) << "data format \"" << buffer << "\" is wrong in " << path;
104     } else {
105         LOG(INFO) << "Read: \"" << buffer << "\" from " << path;
106         for (int i = 0; i < nb_buckets_; ++i) {
107             bins[i] = std::stoi(counts[i]);
108         }
109     }
110 }
111 
Write(int * bins,const std::string & path)112 void CycleCountBackupRestore::Write(int *bins, const std::string &path) {
113     std::string str_data = "";
114 
115     for (int i = 0; i < nb_buckets_; ++i) {
116         if (i) {
117             str_data += " ";
118         }
119         str_data += std::to_string(bins[i]);
120     }
121 
122     LOG(INFO) << "Write: \"" << str_data << "\" to " << path;
123     if (!android::base::WriteStringToFile(str_data, path))
124         LOG(ERROR) << "Write to " << path << " error: " << strerror(errno);
125 }
126 
UpdateAndSave()127 void CycleCountBackupRestore::UpdateAndSave() {
128     bool backup = false;
129     bool restore = false;
130     for (int i = 0; i < nb_buckets_; i++) {
131         if (hw_bins_[i] < sw_bins_[i]) {
132             hw_bins_[i] = sw_bins_[i];
133             restore = true;
134         } else if (hw_bins_[i] > sw_bins_[i]) {
135             sw_bins_[i] = hw_bins_[i];
136             backup = true;
137         }
138     }
139     if (restore)
140         Write(hw_bins_, sysfs_path_);
141     if (backup)
142         Write(sw_bins_, persist_path_);
143 }
144 
145 }  // namespace health
146 }  // namespace pixel
147 }  // namespace google
148 }  // namespace hardware
149