blob: ef2f811f72ae93be07c92407071b12f5b0782482 [file] [log] [blame]
/*
* Copyright (C) 2022 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.
*/
#pragma once
#include <aidl/android/frameworks/stats/IStats.h>
#include <aidl/android/hardware/thermal/Temperature.h>
#include <android-base/chrono_utils.h>
#include <chrono>
#include <shared_mutex>
#include <string_view>
#include <unordered_map>
#include <vector>
#include "thermal_info.h"
namespace aidl {
namespace android {
namespace hardware {
namespace thermal {
namespace implementation {
using aidl::android::frameworks::stats::IStats;
using aidl::android::frameworks::stats::VendorAtomValue;
using ::android::base::boot_clock;
using std::chrono::system_clock;
using SystemTimePoint = std::chrono::time_point<std::chrono::system_clock>;
constexpr int kMaxStatsReportingFailCount = 3;
struct StatsRecord {
int cur_state; /* temperature / cdev state at current time */
boot_clock::time_point cur_state_start_time;
boot_clock::time_point last_stats_report_time = boot_clock::time_point::min();
std::vector<std::chrono::milliseconds> time_in_state_ms; /* stats array */
int report_fail_count = 0; /* Number of times failed to report stats */
explicit StatsRecord(const size_t &time_in_state_size, int state = 0)
: cur_state(state),
cur_state_start_time(boot_clock::now()),
last_stats_report_time(boot_clock::now()),
report_fail_count(0) {
time_in_state_ms = std::vector<std::chrono::milliseconds>(
time_in_state_size, std::chrono::milliseconds::zero());
}
StatsRecord() = default;
StatsRecord(const StatsRecord &) = default;
StatsRecord &operator=(const StatsRecord &) = default;
StatsRecord(StatsRecord &&) = default;
StatsRecord &operator=(StatsRecord &&) = default;
~StatsRecord() = default;
};
template <typename ValueType>
struct StatsByThreshold {
std::vector<ValueType> thresholds;
std::optional<std::string> logging_name;
StatsRecord stats_record;
explicit StatsByThreshold(ThresholdList<ValueType> threshold_list)
: thresholds(threshold_list.thresholds), logging_name(threshold_list.logging_name) {
// number of states = number of thresholds + 1
// e.g. threshold: [30, 50, 60]
// buckets: [MIN - 30, 30 - 50, 50-60, 60-MAX]
int time_in_state_size = threshold_list.thresholds.size() + 1;
stats_record = StatsRecord(time_in_state_size);
}
StatsByThreshold() = default;
StatsByThreshold(const StatsByThreshold &) = default;
StatsByThreshold &operator=(const StatsByThreshold &) = default;
StatsByThreshold(StatsByThreshold &&) = default;
StatsByThreshold &operator=(StatsByThreshold &&) = default;
~StatsByThreshold() = default;
};
template <typename ValueType>
struct ThermalStats {
std::vector<StatsByThreshold<ValueType>> stats_by_custom_threshold;
std::optional<StatsRecord> stats_by_default_threshold;
};
struct SensorTempStats : ThermalStats<float> {
float max_temp = std::numeric_limits<float>::min();
SystemTimePoint max_temp_timestamp = SystemTimePoint::min();
float min_temp = std::numeric_limits<float>::max();
SystemTimePoint min_temp_timestamp = SystemTimePoint::min();
};
class ThermalStatsHelper {
public:
ThermalStatsHelper() = default;
~ThermalStatsHelper() = default;
// Disallow copy and assign
ThermalStatsHelper(const ThermalStatsHelper &) = delete;
void operator=(const ThermalStatsHelper &) = delete;
bool 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_);
void updateSensorCdevRequestStats(std::string_view trigger_sensor, std::string_view cdev,
int new_state);
void updateSensorTempStatsBySeverity(std::string_view sensor,
const ThrottlingSeverity &severity);
void updateSensorTempStatsByThreshold(std::string_view sensor, float temperature);
/*
* Function to report all the stats by calling all specific stats reporting function.
* Returns:
* 0, if time_elapsed < kUpdateIntervalMs or if no failure in reporting
* -1, if failed to get AIDL stats services
* >0, count represents the number of stats failed to report.
*/
int reportStats();
// Get a snapshot of Thermal Stats Sensor Map till that point in time
std::unordered_map<std::string, SensorTempStats> GetSensorTempStatsSnapshot();
// Get a snapshot of Thermal Stats Sensor Map till that point in time
std::unordered_map<std::string, std::unordered_map<std::string, ThermalStats<int>>>
GetSensorCoolingDeviceRequestStatsSnapshot();
private:
static constexpr std::chrono::milliseconds kUpdateIntervalMs =
std::chrono::duration_cast<std::chrono::milliseconds>(24h);
boot_clock::time_point last_total_stats_report_time = boot_clock::time_point::min();
mutable std::shared_mutex sensor_temp_stats_map_mutex_;
// Temperature stats for each sensor being watched
std::unordered_map<std::string, SensorTempStats> sensor_temp_stats_map_;
mutable std::shared_mutex sensor_cdev_request_stats_map_mutex_;
// userVote request stat for the sensor to the corresponding cdev (sensor -> cdev ->
// StatsRecord)
std::unordered_map<std::string, std::unordered_map<std::string, ThermalStats<int>>>
sensor_cdev_request_stats_map_;
bool initializeSensorTempStats(
const StatsInfo<float> &sensor_stats_info,
const std::unordered_map<std::string, SensorInfo> &sensor_info_map_);
bool 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_);
void updateStatsRecord(StatsRecord *stats_record, int new_state);
int reportAllSensorTempStats(const std::shared_ptr<IStats> &stats_client);
bool reportSensorTempStats(const std::shared_ptr<IStats> &stats_client, std::string_view sensor,
const SensorTempStats &sensor_temp_stats, StatsRecord *stats_record);
int reportAllSensorCdevRequestStats(const std::shared_ptr<IStats> &stats_client);
bool reportSensorCdevRequestStats(const std::shared_ptr<IStats> &stats_client,
std::string_view sensor, std::string_view cdev,
StatsRecord *stats_record);
bool reportAtom(const std::shared_ptr<IStats> &stats_client, const int32_t &atom_id,
std::vector<VendorAtomValue> &&values);
std::vector<int64_t> processStatsRecordForReporting(StatsRecord *stats_record);
StatsRecord restoreStatsRecordOnFailure(StatsRecord &&stats_record_before_failure);
};
} // namespace implementation
} // namespace thermal
} // namespace hardware
} // namespace android
} // namespace aidl