• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright (C) 2018 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <pixelhealth/BatteryMetricsLogger.h>
19 #include <pixelhealth/HealthHelper.h>
20 #include <pixelhealth/StatsHelper.h>
21 
22 using aidl::android::hardware::health::BatteryStatus;
23 using aidl::android::hardware::health::HealthInfo;
24 
25 namespace hardware {
26 namespace google {
27 namespace pixel {
28 namespace health {
29 
toBatterySnapshotType(int type)30 VendorBatteryHealthSnapshot::BatterySnapshotType toBatterySnapshotType(int type) {
31     return static_cast<VendorBatteryHealthSnapshot::BatterySnapshotType>(type);
32 }
33 
BatteryMetricsLogger(const char * const batt_res,const char * const batt_ocv,const char * const batt_avg_res,int sample_period,int upload_period)34 BatteryMetricsLogger::BatteryMetricsLogger(const char *const batt_res, const char *const batt_ocv,
35                                            const char *const batt_avg_res, int sample_period,
36                                            int upload_period)
37     : kBatteryResistance(batt_res),
38       kBatteryOCV(batt_ocv),
39       kBatteryAvgResistance(batt_avg_res),
40       kSamplePeriod(sample_period),
41       kUploadPeriod(upload_period),
42       kMaxSamples(upload_period / sample_period) {
43     last_sample_ = 0;
44     last_upload_ = 0;
45     num_samples_ = 0;
46     num_res_samples_ = 0;
47     memset(min_, 0, sizeof(min_));
48     memset(max_, 0, sizeof(max_));
49 }
50 
getTime(void)51 int64_t BatteryMetricsLogger::getTime(void) {
52     return nanoseconds_to_seconds(systemTime(SYSTEM_TIME_BOOTTIME));
53 }
54 
uploadOutlierMetric(const std::shared_ptr<IStats> & stats_client,sampleType type)55 bool BatteryMetricsLogger::uploadOutlierMetric(const std::shared_ptr<IStats> &stats_client,
56                                                sampleType type) {
57     if (kStatsSnapshotType[type] < 0)
58         return false;
59 
60     VendorBatteryHealthSnapshot min_stats_ss;
61     min_stats_ss.set_type(toBatterySnapshotType(kStatsSnapshotType[type]));
62     min_stats_ss.set_temperature_deci_celsius(min_[type][TEMP]);
63     min_stats_ss.set_voltage_micro_volt(min_[type][VOLT]);
64     min_stats_ss.set_current_micro_amps(min_[type][CURR]);
65     min_stats_ss.set_open_circuit_micro_volt(min_[type][OCV]);
66     min_stats_ss.set_resistance_micro_ohm(min_[type][RES]);
67     min_stats_ss.set_level_percent(min_[type][SOC]);
68 
69     VendorBatteryHealthSnapshot max_stats_ss;
70     max_stats_ss.set_type(toBatterySnapshotType(kStatsSnapshotType[type] + 1));
71     max_stats_ss.set_temperature_deci_celsius(max_[type][TEMP]);
72     max_stats_ss.set_voltage_micro_volt(max_[type][VOLT]);
73     max_stats_ss.set_current_micro_amps(max_[type][CURR]);
74     max_stats_ss.set_open_circuit_micro_volt(max_[type][OCV]);
75     max_stats_ss.set_resistance_micro_ohm(max_[type][RES]);
76     max_stats_ss.set_level_percent(max_[type][SOC]);
77 
78     reportBatteryHealthSnapshot(stats_client, min_stats_ss);
79     reportBatteryHealthSnapshot(stats_client, max_stats_ss);
80 
81     return true;
82 }
83 
uploadAverageBatteryResistance(const std::shared_ptr<IStats> & stats_client)84 bool BatteryMetricsLogger::uploadAverageBatteryResistance(
85         const std::shared_ptr<IStats> &stats_client) {
86     if (strlen(kBatteryAvgResistance) == 0) {
87         LOG(INFO) << "Sysfs path for average battery resistance not specified";
88         return true;
89     }
90 
91     std::string file_content;
92     int32_t batt_avg_res;
93 
94     if (!android::base::ReadFileToString(kBatteryAvgResistance, &file_content)) {
95         LOG(ERROR) << "Can't read " << kBatteryAvgResistance;
96         return false;
97     }
98     std::stringstream ss(file_content);
99     if (!(ss >> batt_avg_res)) {
100         LOG(ERROR) << "Can't parse average battery resistance " << file_content;
101         return false;
102     }
103     // Upload average metric
104     VendorBatteryHealthSnapshot avg_res_ss_stats;
105     avg_res_ss_stats.set_type(VendorBatteryHealthSnapshot::BATTERY_SNAPSHOT_TYPE_AVG_RESISTANCE);
106     avg_res_ss_stats.set_temperature_deci_celsius(0);
107     avg_res_ss_stats.set_voltage_micro_volt(0);
108     avg_res_ss_stats.set_current_micro_amps(0);
109     avg_res_ss_stats.set_open_circuit_micro_volt(0);
110     avg_res_ss_stats.set_resistance_micro_ohm(batt_avg_res);
111     avg_res_ss_stats.set_level_percent(0);
112 
113     reportBatteryHealthSnapshot(stats_client, avg_res_ss_stats);
114     return true;
115 }
116 
uploadMetrics(void)117 bool BatteryMetricsLogger::uploadMetrics(void) {
118     int64_t time = getTime();
119 
120     if (last_sample_ == 0)
121         return false;
122 
123     LOG(INFO) << "Uploading metrics at time " << std::to_string(time) << " w/ "
124               << std::to_string(num_samples_) << " samples";
125 
126     std::shared_ptr<IStats> stats_client = getStatsService();
127     if (!stats_client) {
128         LOG(ERROR) << "Unable to connect to Stats service";
129         return false;
130     }
131 
132     // Only log and upload the min and max for metric types we want to upload
133     for (int metric = 0; metric < NUM_FIELDS; metric++) {
134         if ((metric == RES && num_res_samples_ == 0) || kStatsSnapshotType[metric] < 0)
135             continue;
136         std::string log_min = "min-" + std::to_string(metric) + " ";
137         std::string log_max = "max-" + std::to_string(metric) + " ";
138         for (int j = 0; j < NUM_FIELDS; j++) {
139             log_min += std::to_string(min_[metric][j]) + " ";
140             log_max += std::to_string(max_[metric][j]) + " ";
141         }
142         LOG(INFO) << log_min;
143         LOG(INFO) << log_max;
144         // Upload min/max metrics
145         uploadOutlierMetric(stats_client, static_cast<sampleType>(metric));
146     }
147 
148     uploadAverageBatteryResistance(stats_client);
149 
150     // Clear existing data
151     memset(min_, 0, sizeof(min_));
152     memset(max_, 0, sizeof(max_));
153     num_samples_ = 0;
154     num_res_samples_ = 0;
155     last_upload_ = time;
156     LOG(INFO) << "Finished uploading to tron";
157     return true;
158 }
159 
recordSample(const HealthInfo & health_info)160 bool BatteryMetricsLogger::recordSample(const HealthInfo &health_info) {
161     std::string resistance_str, ocv_str;
162     int32_t resistance, ocv;
163     int32_t time = getTime();
164 
165     LOG(INFO) << "Recording a sample at time " << std::to_string(time);
166 
167     if (!android::base::ReadFileToString(kBatteryResistance, &resistance_str)) {
168         LOG(ERROR) << "Can't read the battery resistance from " << kBatteryResistance;
169         resistance = -INT_MAX;
170     } else if (!(std::stringstream(resistance_str) >> resistance)) {
171         LOG(ERROR) << "Can't parse battery resistance value " << resistance_str;
172         resistance = -INT_MAX;
173     }
174 
175     if (!android::base::ReadFileToString(kBatteryOCV, &ocv_str)) {
176         LOG(ERROR) << "Can't read open-circuit voltage (ocv) value from " << kBatteryOCV;
177         ocv = -INT_MAX;
178     } else if (!(std::stringstream(ocv_str) >> ocv)) {
179         LOG(ERROR) << "Can't parse open-circuit voltage (ocv) value " << ocv_str;
180         ocv = -INT_MAX;
181     }
182 
183     int32_t sample[NUM_FIELDS] = {[TIME] = time,
184                                   [RES] = resistance,
185                                   [CURR] = health_info.batteryCurrentMicroamps,
186                                   [VOLT] = health_info.batteryVoltageMillivolts,
187                                   [TEMP] = health_info.batteryTemperatureTenthsCelsius,
188                                   [SOC] = health_info.batteryLevel,
189                                   [OCV] = ocv};
190     if (health_info.batteryStatus != BatteryStatus::CHARGING) {
191         num_res_samples_++;
192     }
193 
194     // Only calculate the min and max for metric types we want to upload
195     for (int metric = 0; metric < NUM_FIELDS; metric++) {
196         // Discard resistance min/max when charging
197         if ((metric == RES && health_info.batteryStatus == BatteryStatus::CHARGING) ||
198             kStatsSnapshotType[metric] < 0)
199             continue;
200         if (num_samples_ == 0 || (metric == RES && num_res_samples_ == 0) ||
201             sample[metric] < min_[metric][metric]) {
202             for (int i = 0; i < NUM_FIELDS; i++) {  // update new min with current sample
203                 min_[metric][i] = sample[i];
204             }
205         }
206         if (num_samples_ == 0 || (metric == RES && num_res_samples_ == 0) ||
207             sample[metric] > max_[metric][metric]) {
208             for (int i = 0; i < NUM_FIELDS; i++) {  // update new max with current sample
209                 max_[metric][i] = sample[i];
210             }
211         }
212     }
213 
214     num_samples_++;
215     last_sample_ = time;
216     return true;
217 }
218 
logBatteryProperties(const HealthInfo & health_info)219 void BatteryMetricsLogger::logBatteryProperties(const HealthInfo &health_info) {
220     int32_t time = getTime();
221     if (last_sample_ == 0 || time - last_sample_ >= kSamplePeriod)
222         recordSample(health_info);
223     if (last_sample_ - last_upload_ > kUploadPeriod || num_samples_ >= kMaxSamples)
224         uploadMetrics();
225 
226     return;
227 }
logBatteryProperties(struct android::BatteryProperties * props)228 void BatteryMetricsLogger::logBatteryProperties(struct android::BatteryProperties *props) {
229     logBatteryProperties(ToHealthInfo(props));
230 }
231 
232 }  // namespace health
233 }  // namespace pixel
234 }  // namespace google
235 }  // namespace hardware
236