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