blob: 9115c83b91d30f5955417ba73e809b586e2e6212 [file] [log] [blame]
// Copyright 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <unistd.h>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/at_exit.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_executor.h"
#include "base/time/time.h"
#include "brillo/flag_helper.h"
#include "brillo/syslog_logging.h"
#include "metrics/metrics_library.h"
#include "thermald/ath10k_temperature_sensor.h"
#include "thermald/config_parser.h"
#include "thermald/configuration.h"
#include "thermald/fake_temperature_sensor.h"
#include "thermald/hwmon_temperature_sensor.h"
#include "thermald/iio_temperature_sensor.h"
#include "thermald/key_value_publisher.h"
#include "thermald/metrics_reporter.h"
#include "thermald/temperature_sensor_interface.h"
#include "thermald/temperature_sensor_monitor.h"
#include "thermald/thermal_output_processor.h"
#include "thermald/thermal_zone.h"
#include "thermald/thermal_zone_controller.h"
#include "thermald/thermal_zone_temperature_sensor.h"
using std::make_pair;
using std::map;
using std::string;
using std::unique_ptr;
using std::vector;
namespace thermald {
static const int kMetricsReportingPeriodInSeconds = 5;
struct ThermaldContext {
unique_ptr<Configuration> cfg;
std::vector<std::unique_ptr<TemperatureSensorInterface>> temperature_sensors;
map<string, unique_ptr<TemperatureMonitorInterface>> temperature_monitors;
KeyValuePublisher output_publisher;
std::vector<std::unique_ptr<ThermalZone>> thermal_zones;
std::vector<std::unique_ptr<ThermalZoneController>> thermal_zone_controllers;
MetricsLibrary metrics_lib;
unique_ptr<MetricsReporter> metrics_reporter;
};
static bool CreateTemperatureMonitors(ThermaldContext *context) {
for (const auto &it : context->cfg->sensors) {
const SensorCfg &sensor_cfg = *it.second;
std::unique_ptr<TemperatureSensorInterface> sensor;
if (sensor_cfg.type == kAth10kSensor) {
sensor = std::make_unique<Ath10kTemperatureSensor>(
sensor_cfg.ath10k_sensor.wlan_interface, sensor_cfg.name);
} else if (sensor_cfg.type == kHwmonSensor) {
sensor = std::make_unique<HwmonTemperatureSensor>(
sensor_cfg.hwmon_sensor.chip_id, sensor_cfg.hwmon_sensor.sensor_id,
sensor_cfg.name);
} else if (sensor_cfg.type == kThermalZoneSensor) {
sensor = std::make_unique<ThermalZoneTemperatureSensor>(
sensor_cfg.thermal_zone_sensor.zone_id, sensor_cfg.name);
} else if (sensor_cfg.type == kIioSensor) {
sensor = IioTemperatureSensor::Get(sensor_cfg.name,
sensor_cfg.iio_sensor.iio_device_name,
sensor_cfg.iio_sensor.iio_sensor_name);
if (sensor == NULL) {
return false;
}
} else if (sensor_cfg.type == kFakeSensor) {
sensor = std::make_unique<FakeTemperatureSensor>(
base::FilePath(sensor_cfg.fake_sensor.fake_data_file),
sensor_cfg.name);
} else {
LOG(ERROR) << "Unknown sensor type " << sensor_cfg.type;
return false;
}
auto monitor = std::make_unique<TemperatureSensorMonitor>(
sensor.get(),
base::TimeDelta::FromMilliseconds(sensor_cfg.sampling_period));
context->temperature_sensors.push_back(std::move(sensor));
context->temperature_monitors.insert(
make_pair(sensor_cfg.name, std::move(monitor)));
}
return true;
}
static bool SetupMetricsReporter(ThermaldContext *context) {
context->metrics_reporter.reset(new MetricsReporter(
context->cfg->uma_metric_prefix,
&context->output_publisher, &context->metrics_lib,
base::TimeDelta::FromSeconds(kMetricsReportingPeriodInSeconds)));
for (auto &it : context->temperature_monitors) {
context->metrics_reporter->AddTemperature(it.first, it.second.get());
}
return true;
}
static bool CreateThermalZones(ThermaldContext *context) {
for (const auto &it : context->cfg->zones) {
const ThermalZoneCfg &zone_cfg = *it.second;
std::unique_ptr<ThermalZone> zone = std::make_unique<ThermalZone>();
zone->name = zone_cfg.name;
// Create states in reverse order, the thermal state engine expects the
// states to be ordered from higher to lower temperatures/criticality.
for (auto it2 = zone_cfg.states.rbegin(); it2 != zone_cfg.states.rend();
it2++) {
const ThermalStateCfg *state_cfg = it2->get();
std::unique_ptr<ThermalState> state = std::make_unique<ThermalState>();
state->id = state_cfg->id;
state->thresholds = state_cfg->thresholds;
state->outputs = state_cfg->outputs;
zone->states.push_back(std::move(state));
}
context->thermal_zones.push_back(std::move(zone));
}
return true;
}
static bool CreateThermalZoneControllers(ThermaldContext *context) {
for (auto &zone : context->thermal_zones) {
vector<TemperatureMonitorInterface *> temperature_monitors;
const ThermalZoneCfg &zone_cfg = *context->cfg->zones[zone->name];
for (const string &sensor : zone_cfg.sensors) {
temperature_monitors.push_back(
context->temperature_monitors[sensor].get());
}
context->thermal_zone_controllers.push_back(
std::make_unique<ThermalZoneController>(
zone.get(), &context->output_publisher, temperature_monitors));
}
return true;
}
} // namespace thermald
int main(int argc, char *argv[]) {
base::AtExitManager exit_manager;
brillo::FlagHelper::Init(argc, argv, "Thermal daemon");
brillo::InitLog(brillo::kLogToSyslog | brillo::kLogToStderr);
base::SingleThreadTaskExecutor main_loop;
base::RunLoop run_loop;
thermald::ThermaldContext context;
thermald::ThermalOutputProcessor
thermal_output_processor(&context.output_publisher);
base::FilePath config_file("/etc/thermald.cfg");
if (!base::PathExists(config_file)) {
LOG(WARNING) << "Configuration file '" << config_file.value()
<< "' does not exist. Exiting";
return 0;
}
context.cfg.reset(thermald::ConfigParser::ParseFile(config_file));
if (!context.cfg.get()) {
return -1;
}
if (!thermald::CreateTemperatureMonitors(&context)) {
return -1;
}
if (!thermald::CreateThermalZones(&context)) {
return -1;
}
if (!thermald::CreateThermalZoneControllers(&context)) {
return -1;
}
SetupMetricsReporter(&context);
for (auto &controller : context.thermal_zone_controllers) {
controller->Start();
}
context.metrics_reporter->Start();
run_loop.Run();
}