• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 "thermal_stats_helper.h"
18 
19 #include <android-base/logging.h>
20 #include <android/binder_manager.h>
21 #include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
22 
23 #include <algorithm>
24 #include <numeric>
25 #include <string_view>
26 
27 namespace aidl {
28 namespace android {
29 namespace hardware {
30 namespace thermal {
31 namespace implementation {
32 
33 constexpr std::string_view kCustomThresholdSetSuffix("-TH-");
34 constexpr std::string_view kCompressedThresholdSuffix("-CMBN-TH");
35 
36 using aidl::android::frameworks::stats::VendorAtom;
37 namespace PixelAtoms = ::android::hardware::google::pixel::PixelAtoms;
38 
39 namespace {
40 static std::shared_ptr<IStats> stats_client = nullptr;
getStatsService()41 std::shared_ptr<IStats> getStatsService() {
42     static std::once_flag statsServiceFlag;
43     std::call_once(statsServiceFlag, []() {
44         const std::string instance = std::string() + IStats::descriptor + "/default";
45         bool isStatsDeclared = AServiceManager_isDeclared(instance.c_str());
46         if (!isStatsDeclared) {
47             LOG(ERROR) << "Stats service is not registered.";
48             return;
49         }
50         stats_client = IStats::fromBinder(
51                 ndk::SpAIBinder(AServiceManager_waitForService(instance.c_str())));
52     });
53     return stats_client;
54 }
55 
isRecordByDefaultThreshold(const std::variant<bool,std::unordered_set<std::string>> & record_by_default_threshold_all_or_name_set_,std::string_view name)56 bool isRecordByDefaultThreshold(const std::variant<bool, std::unordered_set<std::string>>
57                                         &record_by_default_threshold_all_or_name_set_,
58                                 std::string_view name) {
59     if (std::holds_alternative<bool>(record_by_default_threshold_all_or_name_set_)) {
60         return std::get<bool>(record_by_default_threshold_all_or_name_set_);
61     }
62     return std::get<std::unordered_set<std::string>>(record_by_default_threshold_all_or_name_set_)
63             .count(name.data());
64 }
65 
66 template <typename T>
calculateThresholdBucket(const std::vector<T> & thresholds,T value)67 int calculateThresholdBucket(const std::vector<T> &thresholds, T value) {
68     if (thresholds.empty()) {
69         LOG(VERBOSE) << "No threshold present, so bucket is " << value << " as int.";
70         return static_cast<int>(value);
71     }
72     auto threshold_idx = std::upper_bound(thresholds.begin(), thresholds.end(), value);
73     int bucket = (threshold_idx - thresholds.begin());
74     LOG(VERBOSE) << "For value: " << value << " bucket is: " << bucket;
75     return bucket;
76 }
77 
78 }  // namespace
79 
initializeStats(const Json::Value & config,const std::unordered_map<std::string,SensorInfo> & sensor_info_map_,const std::unordered_map<std::string,CdevInfo> & cooling_device_info_map_)80 bool ThermalStatsHelper::initializeStats(
81         const Json::Value &config,
82         const std::unordered_map<std::string, SensorInfo> &sensor_info_map_,
83         const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map_) {
84     StatsConfig stats_config;
85     if (!ParseStatsConfig(config, sensor_info_map_, cooling_device_info_map_, &stats_config)) {
86         LOG(ERROR) << "Failed to parse stats config";
87         return false;
88     }
89     bool is_initialized_ =
90             initializeSensorTempStats(stats_config.sensor_stats_info, sensor_info_map_) &&
91             initializeSensorCdevRequestStats(stats_config.cooling_device_request_info,
92                                              sensor_info_map_, cooling_device_info_map_);
93     if (is_initialized_) {
94         last_total_stats_report_time = boot_clock::now();
95         LOG(INFO) << "Thermal Stats Initialized Successfully";
96     }
97     return is_initialized_;
98 }
99 
initializeSensorCdevRequestStats(const StatsInfo<int> & request_stats_info,const std::unordered_map<std::string,SensorInfo> & sensor_info_map_,const std::unordered_map<std::string,CdevInfo> & cooling_device_info_map_)100 bool ThermalStatsHelper::initializeSensorCdevRequestStats(
101         const StatsInfo<int> &request_stats_info,
102         const std::unordered_map<std::string, SensorInfo> &sensor_info_map_,
103         const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map_) {
104     std::unique_lock<std::shared_mutex> _lock(sensor_cdev_request_stats_map_mutex_);
105     for (const auto &[sensor, sensor_info] : sensor_info_map_) {
106         for (const auto &binded_cdev_info_pair :
107              sensor_info.throttling_info->binded_cdev_info_map) {
108             const auto &cdev = binded_cdev_info_pair.first;
109             const auto &max_state =
110                     cooling_device_info_map_.at(binded_cdev_info_pair.first).max_state;
111             // Record by all state
112             if (isRecordByDefaultThreshold(
113                         request_stats_info.record_by_default_threshold_all_or_name_set_, cdev)) {
114                 // if the number of states is greater / equal(as state starts from 0) than
115                 // residency_buckets in atom combine the initial states
116                 if (max_state >= kMaxStatsResidencyCount) {
117                     // buckets = [max_state -kMaxStatsResidencyCount + 1, ...max_state]
118                     //     idx = [1, .. max_state - (max_state - kMaxStatsResidencyCount + 1) + 1]
119                     //     idx = [1, .. kMaxStatsResidencyCount]
120                     const auto starting_state = max_state - kMaxStatsResidencyCount + 1;
121                     std::vector<int> thresholds(kMaxStatsResidencyCount);
122                     std::iota(thresholds.begin(), thresholds.end(), starting_state);
123                     const auto logging_name = cdev + kCompressedThresholdSuffix.data();
124                     ThresholdList<int> threshold_list(logging_name, thresholds);
125                     sensor_cdev_request_stats_map_[sensor][cdev]
126                             .stats_by_custom_threshold.emplace_back(threshold_list);
127                 } else {
128                     // buckets = [0, 1, 2, 3, ...max_state]
129                     const auto default_threshold_time_in_state_size = max_state + 1;
130                     sensor_cdev_request_stats_map_[sensor][cdev].stats_by_default_threshold =
131                             StatsRecord(default_threshold_time_in_state_size);
132                 }
133                 LOG(INFO) << "Sensor Cdev user vote stats on basis of all state initialized for ["
134                           << sensor << "-" << cdev << "]";
135             }
136 
137             // Record by custom threshold
138             if (request_stats_info.record_by_threshold.count(cdev)) {
139                 for (const auto &threshold_list : request_stats_info.record_by_threshold.at(cdev)) {
140                     // check last threshold value(which is >= number of buckets as numbers in
141                     // threshold are strictly increasing from 0) is less than max_state
142                     if (threshold_list.thresholds.back() >= max_state) {
143                         LOG(ERROR) << "For sensor " << sensor << " bindedCdev: " << cdev
144                                    << "Invalid bindedCdev stats threshold: "
145                                    << threshold_list.thresholds.back() << " >= " << max_state;
146                         sensor_cdev_request_stats_map_.clear();
147                         return false;
148                     }
149                     sensor_cdev_request_stats_map_[sensor][cdev]
150                             .stats_by_custom_threshold.emplace_back(threshold_list);
151                     LOG(INFO)
152                             << "Sensor Cdev user vote stats on basis of threshold initialized for ["
153                             << sensor << "-" << cdev << "]";
154                 }
155             }
156         }
157     }
158     return true;
159 }
160 
initializeSensorTempStats(const StatsInfo<float> & sensor_stats_info,const std::unordered_map<std::string,SensorInfo> & sensor_info_map_)161 bool ThermalStatsHelper::initializeSensorTempStats(
162         const StatsInfo<float> &sensor_stats_info,
163         const std::unordered_map<std::string, SensorInfo> &sensor_info_map_) {
164     std::unique_lock<std::shared_mutex> _lock(sensor_temp_stats_map_mutex_);
165     const int severity_time_in_state_size = kThrottlingSeverityCount;
166     for (const auto &[sensor, sensor_info] : sensor_info_map_) {
167         // Record by severity
168         if (sensor_info.is_watch &&
169             isRecordByDefaultThreshold(
170                     sensor_stats_info.record_by_default_threshold_all_or_name_set_, sensor)) {
171             // number of buckets = number of severity
172             sensor_temp_stats_map_[sensor].stats_by_default_threshold =
173                     StatsRecord(severity_time_in_state_size);
174             LOG(INFO) << "Sensor temp stats on basis of severity initialized for [" << sensor
175                       << "]";
176         }
177 
178         // Record by custom threshold
179         if (sensor_stats_info.record_by_threshold.count(sensor)) {
180             for (const auto &threshold_list : sensor_stats_info.record_by_threshold.at(sensor)) {
181                 sensor_temp_stats_map_[sensor].stats_by_custom_threshold.emplace_back(
182                         threshold_list);
183                 LOG(INFO) << "Sensor temp stats on basis of threshold initialized for [" << sensor
184                           << "]";
185             }
186         }
187     }
188     return true;
189 }
190 
updateStatsRecord(StatsRecord * stats_record,int new_state)191 void ThermalStatsHelper::updateStatsRecord(StatsRecord *stats_record, int new_state) {
192     const auto now = boot_clock::now();
193     const auto cur_state_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
194             now - stats_record->cur_state_start_time);
195     LOG(VERBOSE) << "Adding duration " << cur_state_duration.count()
196                  << " for cur_state: " << stats_record->cur_state << " with value: "
197                  << stats_record->time_in_state_ms[stats_record->cur_state].count();
198     // Update last record end time
199     stats_record->time_in_state_ms[stats_record->cur_state] += cur_state_duration;
200     stats_record->cur_state_start_time = now;
201     stats_record->cur_state = new_state;
202 }
203 
updateSensorCdevRequestStats(std::string_view sensor,std::string_view cdev,int new_value)204 void ThermalStatsHelper::updateSensorCdevRequestStats(std::string_view sensor,
205                                                       std::string_view cdev, int new_value) {
206     std::unique_lock<std::shared_mutex> _lock(sensor_cdev_request_stats_map_mutex_);
207     if (!sensor_cdev_request_stats_map_.count(sensor.data()) ||
208         !sensor_cdev_request_stats_map_[sensor.data()].count(cdev.data())) {
209         return;
210     }
211     auto &request_stats = sensor_cdev_request_stats_map_[sensor.data()][cdev.data()];
212     for (auto &stats_by_threshold : request_stats.stats_by_custom_threshold) {
213         int value = calculateThresholdBucket(stats_by_threshold.thresholds, new_value);
214         if (value != stats_by_threshold.stats_record.cur_state) {
215             LOG(VERBOSE) << "Updating bindedCdev stats for sensor: " << sensor.data()
216                          << " , cooling_device: " << cdev.data() << " with new value: " << value;
217             updateStatsRecord(&stats_by_threshold.stats_record, value);
218         }
219     }
220 
221     if (request_stats.stats_by_default_threshold.has_value()) {
222         auto &stats_record = request_stats.stats_by_default_threshold.value();
223         if (new_value != stats_record.cur_state) {
224             LOG(VERBOSE) << "Updating bindedCdev stats for sensor: " << sensor.data()
225                          << " , cooling_device: " << cdev.data()
226                          << " with new value: " << new_value;
227             updateStatsRecord(&stats_record, new_value);
228         }
229     }
230 }
231 
updateSensorTempStatsByThreshold(std::string_view sensor,float temperature)232 void ThermalStatsHelper::updateSensorTempStatsByThreshold(std::string_view sensor,
233                                                           float temperature) {
234     std::unique_lock<std::shared_mutex> _lock(sensor_temp_stats_map_mutex_);
235     if (!sensor_temp_stats_map_.count(sensor.data())) {
236         return;
237     }
238     auto &sensor_temp_stats = sensor_temp_stats_map_[sensor.data()];
239     for (auto &stats_by_threshold : sensor_temp_stats.stats_by_custom_threshold) {
240         int value = calculateThresholdBucket(stats_by_threshold.thresholds, temperature);
241         if (value != stats_by_threshold.stats_record.cur_state) {
242             LOG(VERBOSE) << "Updating sensor stats for sensor: " << sensor.data()
243                          << " with value: " << value;
244             updateStatsRecord(&stats_by_threshold.stats_record, value);
245         }
246     }
247     if (temperature > sensor_temp_stats.max_temp) {
248         sensor_temp_stats.max_temp = temperature;
249         sensor_temp_stats.max_temp_timestamp = system_clock::now();
250     }
251     if (temperature < sensor_temp_stats.min_temp) {
252         sensor_temp_stats.min_temp = temperature;
253         sensor_temp_stats.min_temp_timestamp = system_clock::now();
254     }
255 }
256 
updateSensorTempStatsBySeverity(std::string_view sensor,const ThrottlingSeverity & severity)257 void ThermalStatsHelper::updateSensorTempStatsBySeverity(std::string_view sensor,
258                                                          const ThrottlingSeverity &severity) {
259     std::unique_lock<std::shared_mutex> _lock(sensor_temp_stats_map_mutex_);
260     if (sensor_temp_stats_map_.count(sensor.data()) &&
261         sensor_temp_stats_map_[sensor.data()].stats_by_default_threshold.has_value()) {
262         auto &stats_record =
263                 sensor_temp_stats_map_[sensor.data()].stats_by_default_threshold.value();
264         int value = static_cast<int>(severity);
265         if (value != stats_record.cur_state) {
266             LOG(VERBOSE) << "Updating sensor stats for sensor: " << sensor.data()
267                          << " with value: " << value;
268             updateStatsRecord(&stats_record, value);
269         }
270     }
271 }
272 
reportStats()273 int ThermalStatsHelper::reportStats() {
274     const auto curTime = boot_clock::now();
275     const auto since_last_total_stats_update_ms =
276             std::chrono::duration_cast<std::chrono::milliseconds>(curTime -
277                                                                   last_total_stats_report_time);
278     LOG(VERBOSE) << "Duration from last total stats update is: "
279                  << since_last_total_stats_update_ms.count();
280     if (since_last_total_stats_update_ms < kUpdateIntervalMs) {
281         LOG(VERBOSE) << "Time elapsed since last update less than " << kUpdateIntervalMs.count();
282         return 0;
283     }
284 
285     const std::shared_ptr<IStats> stats_client = getStatsService();
286     if (!stats_client) {
287         LOG(ERROR) << "Unable to get AIDL Stats service";
288         return -1;
289     }
290     int count_failed_reporting =
291             reportAllSensorTempStats(stats_client) + reportAllSensorCdevRequestStats(stats_client);
292     last_total_stats_report_time = curTime;
293     return count_failed_reporting;
294 }
295 
reportAllSensorTempStats(const std::shared_ptr<IStats> & stats_client)296 int ThermalStatsHelper::reportAllSensorTempStats(const std::shared_ptr<IStats> &stats_client) {
297     int count_failed_reporting = 0;
298     std::unique_lock<std::shared_mutex> _lock(sensor_temp_stats_map_mutex_);
299     for (auto &[sensor, temp_stats] : sensor_temp_stats_map_) {
300         for (size_t threshold_set_idx = 0;
301              threshold_set_idx < temp_stats.stats_by_custom_threshold.size(); threshold_set_idx++) {
302             auto &stats_by_threshold = temp_stats.stats_by_custom_threshold[threshold_set_idx];
303             std::string sensor_name = stats_by_threshold.logging_name.value_or(
304                     sensor + kCustomThresholdSetSuffix.data() + std::to_string(threshold_set_idx));
305             if (!reportSensorTempStats(stats_client, sensor_name, temp_stats,
306                                        &stats_by_threshold.stats_record)) {
307                 count_failed_reporting++;
308             }
309         }
310         if (temp_stats.stats_by_default_threshold.has_value()) {
311             if (!reportSensorTempStats(stats_client, sensor, temp_stats,
312                                        &temp_stats.stats_by_default_threshold.value())) {
313                 count_failed_reporting++;
314             }
315         }
316         // Reset temp stats after reporting
317         temp_stats.max_temp = std::numeric_limits<float>::min();
318         temp_stats.min_temp = std::numeric_limits<float>::max();
319     }
320     return count_failed_reporting;
321 }
322 
reportSensorTempStats(const std::shared_ptr<IStats> & stats_client,std::string_view sensor,const SensorTempStats & sensor_temp_stats,StatsRecord * stats_record)323 bool ThermalStatsHelper::reportSensorTempStats(const std::shared_ptr<IStats> &stats_client,
324                                                std::string_view sensor,
325                                                const SensorTempStats &sensor_temp_stats,
326                                                StatsRecord *stats_record) {
327     LOG(VERBOSE) << "Reporting sensor stats for " << sensor;
328     // maintain a copy in case reporting fails
329     StatsRecord thermal_stats_before_reporting = *stats_record;
330     std::vector<VendorAtomValue> values(2);
331     values[0].set<VendorAtomValue::stringValue>(sensor);
332     std::vector<int64_t> time_in_state_ms = processStatsRecordForReporting(stats_record);
333     const auto since_last_update_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
334             stats_record->cur_state_start_time - stats_record->last_stats_report_time);
335     values[1].set<VendorAtomValue::longValue>(since_last_update_ms.count());
336     VendorAtomValue tmp;
337     for (auto &time_in_state : time_in_state_ms) {
338         tmp.set<VendorAtomValue::longValue>(time_in_state);
339         values.push_back(tmp);
340     }
341     auto remaining_residency_buckets_count = kMaxStatsResidencyCount - time_in_state_ms.size();
342     if (remaining_residency_buckets_count > 0) {
343         tmp.set<VendorAtomValue::longValue>(0);
344         values.insert(values.end(), remaining_residency_buckets_count, tmp);
345     }
346     tmp.set<VendorAtomValue::floatValue>(sensor_temp_stats.max_temp);
347     values.push_back(tmp);
348     tmp.set<VendorAtomValue::longValue>(
349             system_clock::to_time_t(sensor_temp_stats.max_temp_timestamp));
350     values.push_back(tmp);
351     tmp.set<VendorAtomValue::floatValue>(sensor_temp_stats.min_temp);
352     values.push_back(tmp);
353     tmp.set<VendorAtomValue::longValue>(
354             system_clock::to_time_t(sensor_temp_stats.min_temp_timestamp));
355     values.push_back(tmp);
356 
357     if (!reportAtom(stats_client, PixelAtoms::Atom::kVendorTempResidencyStats, std::move(values))) {
358         LOG(ERROR) << "Unable to report VendorTempResidencyStats to Stats service for "
359                       "sensor: "
360                    << sensor;
361         *stats_record = restoreStatsRecordOnFailure(std::move(thermal_stats_before_reporting));
362         return false;
363     }
364     // Update last time of stats reporting
365     stats_record->last_stats_report_time = boot_clock::now();
366     return true;
367 }
368 
reportAllSensorCdevRequestStats(const std::shared_ptr<IStats> & stats_client)369 int ThermalStatsHelper::reportAllSensorCdevRequestStats(
370         const std::shared_ptr<IStats> &stats_client) {
371     int count_failed_reporting = 0;
372     std::unique_lock<std::shared_mutex> _lock(sensor_cdev_request_stats_map_mutex_);
373     for (auto &[sensor, cdev_request_stats_map] : sensor_cdev_request_stats_map_) {
374         for (auto &[cdev, request_stats] : cdev_request_stats_map) {
375             for (size_t threshold_set_idx = 0;
376                  threshold_set_idx < request_stats.stats_by_custom_threshold.size();
377                  threshold_set_idx++) {
378                 auto &stats_by_threshold =
379                         request_stats.stats_by_custom_threshold[threshold_set_idx];
380                 std::string cdev_name = stats_by_threshold.logging_name.value_or(
381                         cdev + kCustomThresholdSetSuffix.data() +
382                         std::to_string(threshold_set_idx));
383                 if (!reportSensorCdevRequestStats(stats_client, sensor, cdev_name,
384                                                   &stats_by_threshold.stats_record)) {
385                     count_failed_reporting++;
386                 }
387             }
388 
389             if (request_stats.stats_by_default_threshold.has_value()) {
390                 if (!reportSensorCdevRequestStats(
391                             stats_client, sensor, cdev,
392                             &request_stats.stats_by_default_threshold.value())) {
393                     count_failed_reporting++;
394                 }
395             }
396         }
397     }
398     return count_failed_reporting;
399 }
400 
reportSensorCdevRequestStats(const std::shared_ptr<IStats> & stats_client,std::string_view sensor,std::string_view cdev,StatsRecord * stats_record)401 bool ThermalStatsHelper::reportSensorCdevRequestStats(const std::shared_ptr<IStats> &stats_client,
402                                                       std::string_view sensor,
403                                                       std::string_view cdev,
404                                                       StatsRecord *stats_record) {
405     LOG(VERBOSE) << "Reporting bindedCdev stats for sensor: " << sensor
406                  << " cooling_device: " << cdev;
407     // maintain a copy in case reporting fails
408     StatsRecord thermal_stats_before_reporting = *stats_record;
409     std::vector<VendorAtomValue> values(3);
410     values[0].set<VendorAtomValue::stringValue>(sensor);
411     values[1].set<VendorAtomValue::stringValue>(cdev);
412     std::vector<int64_t> time_in_state_ms = processStatsRecordForReporting(stats_record);
413     const auto since_last_update_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
414             stats_record->cur_state_start_time - stats_record->last_stats_report_time);
415     values[2].set<VendorAtomValue::longValue>(since_last_update_ms.count());
416     VendorAtomValue tmp;
417     for (auto &time_in_state : time_in_state_ms) {
418         tmp.set<VendorAtomValue::longValue>(time_in_state);
419         values.push_back(tmp);
420     }
421 
422     if (!reportAtom(stats_client, PixelAtoms::Atom::kVendorSensorCoolingDeviceStats,
423                     std::move(values))) {
424         LOG(ERROR) << "Unable to report VendorSensorCoolingDeviceStats to Stats "
425                       "service for sensor: "
426                    << sensor << " cooling_device: " << cdev;
427         *stats_record = restoreStatsRecordOnFailure(std::move(thermal_stats_before_reporting));
428         return false;
429     }
430     // Update last time of stats reporting
431     stats_record->last_stats_report_time = boot_clock::now();
432     return true;
433 }
434 
processStatsRecordForReporting(StatsRecord * stats_record)435 std::vector<int64_t> ThermalStatsHelper::processStatsRecordForReporting(StatsRecord *stats_record) {
436     // update the last unclosed entry and start new record with same state
437     updateStatsRecord(stats_record, stats_record->cur_state);
438     std::vector<std::chrono::milliseconds> &time_in_state_ms = stats_record->time_in_state_ms;
439     // convert std::chrono::milliseconds time_in_state to int64_t vector for reporting
440     std::vector<int64_t> stats_residency(time_in_state_ms.size());
441     std::transform(time_in_state_ms.begin(), time_in_state_ms.end(), stats_residency.begin(),
442                    [](std::chrono::milliseconds time_ms) { return time_ms.count(); });
443     // clear previous stats
444     std::fill(time_in_state_ms.begin(), time_in_state_ms.end(), std::chrono::milliseconds::zero());
445     return stats_residency;
446 }
447 
reportAtom(const std::shared_ptr<IStats> & stats_client,const int32_t & atom_id,std::vector<VendorAtomValue> && values)448 bool ThermalStatsHelper::reportAtom(const std::shared_ptr<IStats> &stats_client,
449                                     const int32_t &atom_id, std::vector<VendorAtomValue> &&values) {
450     LOG(VERBOSE) << "Reporting thermal stats for atom_id " << atom_id;
451     // Send vendor atom to IStats HAL
452     VendorAtom event = {.reverseDomainName = "", .atomId = atom_id, .values = std::move(values)};
453     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
454     return ret.isOk();
455 }
456 
restoreStatsRecordOnFailure(StatsRecord && stats_record_before_failure)457 StatsRecord ThermalStatsHelper::restoreStatsRecordOnFailure(
458         StatsRecord &&stats_record_before_failure) {
459     stats_record_before_failure.report_fail_count += 1;
460     // If consecutive count of failure is high, reset stat to avoid overflow
461     if (stats_record_before_failure.report_fail_count >= kMaxStatsReportingFailCount) {
462         return StatsRecord(stats_record_before_failure.time_in_state_ms.size(),
463                            stats_record_before_failure.cur_state);
464     } else {
465         return stats_record_before_failure;
466     }
467 }
468 
GetSensorTempStatsSnapshot()469 std::unordered_map<std::string, SensorTempStats> ThermalStatsHelper::GetSensorTempStatsSnapshot() {
470     auto sensor_temp_stats_snapshot = sensor_temp_stats_map_;
471     for (auto &sensor_temp_stats_pair : sensor_temp_stats_snapshot) {
472         for (auto &temp_stats : sensor_temp_stats_pair.second.stats_by_custom_threshold) {
473             // update the last unclosed entry and start new record with same state
474             updateStatsRecord(&temp_stats.stats_record, temp_stats.stats_record.cur_state);
475         }
476         if (sensor_temp_stats_pair.second.stats_by_default_threshold.has_value()) {
477             auto &stats_by_default_threshold =
478                     sensor_temp_stats_pair.second.stats_by_default_threshold.value();
479             // update the last unclosed entry and start new record with same state
480             updateStatsRecord(&stats_by_default_threshold, stats_by_default_threshold.cur_state);
481         }
482     }
483     return sensor_temp_stats_snapshot;
484 }
485 
486 std::unordered_map<std::string, std::unordered_map<std::string, ThermalStats<int>>>
GetSensorCoolingDeviceRequestStatsSnapshot()487 ThermalStatsHelper::GetSensorCoolingDeviceRequestStatsSnapshot() {
488     auto sensor_cdev_request_stats_snapshot = sensor_cdev_request_stats_map_;
489     for (auto &sensor_cdev_request_stats_pair : sensor_cdev_request_stats_snapshot) {
490         for (auto &cdev_request_stats_pair : sensor_cdev_request_stats_pair.second) {
491             for (auto &request_stats : cdev_request_stats_pair.second.stats_by_custom_threshold) {
492                 // update the last unclosed entry and start new record with same state
493                 updateStatsRecord(&request_stats.stats_record,
494                                   request_stats.stats_record.cur_state);
495             }
496             if (cdev_request_stats_pair.second.stats_by_default_threshold.has_value()) {
497                 auto &stats_by_default_threshold =
498                         cdev_request_stats_pair.second.stats_by_default_threshold.value();
499                 // update the last unclosed entry and start new record with same state
500                 updateStatsRecord(&stats_by_default_threshold,
501                                   stats_by_default_threshold.cur_state);
502             }
503         }
504     }
505     return sensor_cdev_request_stats_snapshot;
506 }
507 
508 }  // namespace implementation
509 }  // namespace thermal
510 }  // namespace hardware
511 }  // namespace android
512 }  // namespace aidl
513