| // Copyright 2020 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 "power_manager/powerd/policy/thermal_event_handler.h" |
| |
| #include <algorithm> |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/check.h> |
| #include <base/logging.h> |
| #include <chromeos/dbus/service_constants.h> |
| #include <dbus/message.h> |
| |
| #include "power_manager/common/clock.h" |
| #include "power_manager/common/power_constants.h" |
| #include "power_manager/powerd/system/dbus_wrapper.h" |
| #include "power_manager/powerd/system/thermal/device_thermal_state.h" |
| #include "power_manager/powerd/system/thermal/thermal_device.h" |
| #include "power_manager/powerd/system/thermal/thermal_device_observer.h" |
| #include "power_manager/proto_bindings/thermal.pb.h" |
| |
| namespace power_manager { |
| namespace policy { |
| |
| namespace { |
| |
| system::DeviceThermalState max(system::DeviceThermalState a, |
| system::DeviceThermalState b) { |
| return static_cast<int>(a) >= static_cast<int>(b) ? a : b; |
| } |
| |
| } // namespace |
| |
| ThermalEventHandler::ThermalEventHandler( |
| std::vector<system::ThermalDeviceInterface*> thermal_devices, |
| system::DBusWrapperInterface* dbus_wrapper) |
| : dbus_wrapper_(dbus_wrapper), |
| thermal_devices_(thermal_devices), |
| clock_(std::make_unique<Clock>()), |
| last_state_(system::DeviceThermalState::kUnknown), |
| power_source_(PowerSource::AC), |
| weak_ptr_factory_(this) { |
| for (auto& device : thermal_devices) { |
| DCHECK(device); |
| device->AddObserver(this); |
| } |
| } |
| |
| ThermalEventHandler::~ThermalEventHandler() { |
| for (auto& device : thermal_devices_) { |
| device->RemoveObserver(this); |
| } |
| } |
| |
| bool ThermalEventHandler::Init() { |
| // Send current state to Chrome on Init. |
| OnThermalChanged(nullptr); |
| dbus_wrapper_->ExportMethod( |
| kGetThermalStateMethod, |
| base::Bind(&ThermalEventHandler::OnGetThermalStateMethodCall, |
| weak_ptr_factory_.GetWeakPtr())); |
| return true; |
| } |
| |
| void ThermalEventHandler::OnGetThermalStateMethodCall( |
| dbus::MethodCall* method_call, |
| dbus::ExportedObject::ResponseSender response_sender) { |
| ThermalEvent protobuf; |
| protobuf.set_thermal_state(DeviceThermalStateToProto(last_state_)); |
| protobuf.set_timestamp(clock_->GetCurrentTime().ToInternalValue()); |
| std::unique_ptr<dbus::Response> response = |
| dbus::Response::FromMethodCall(method_call); |
| dbus::MessageWriter writer(response.get()); |
| writer.AppendProtoAsArrayOfBytes(protobuf); |
| std::move(response_sender).Run(std::move(response)); |
| } |
| |
| void ThermalEventHandler::OnThermalChanged( |
| system::ThermalDeviceInterface* device) { |
| if (device && device->GetThermalState() == last_state_) |
| return; |
| |
| // Query all devices and send max_state. |
| system::DeviceThermalState new_state = system::DeviceThermalState::kUnknown; |
| for (const auto& thermal_device : thermal_devices_) { |
| auto state = thermal_device->GetThermalState(); |
| // Charger cooling device may report bogus thermal state when device is on |
| // battery, ignore it in this case. |
| if (power_source_ == PowerSource::BATTERY && |
| thermal_device->GetType() == |
| system::ThermalDeviceType::kChargerCooling) { |
| state = system::DeviceThermalState::kUnknown; |
| } |
| new_state = max(new_state, state); |
| } |
| if (new_state == last_state_) |
| return; |
| |
| ThermalEvent proto; |
| proto.set_thermal_state(DeviceThermalStateToProto(new_state)); |
| proto.set_timestamp(clock_->GetCurrentTime().ToInternalValue()); |
| dbus_wrapper_->EmitSignalWithProtocolBuffer(kThermalEventSignal, proto); |
| |
| last_state_ = new_state; |
| } |
| |
| void ThermalEventHandler::HandlePowerSourceChange(PowerSource source) { |
| if (source == power_source_) |
| return; |
| |
| power_source_ = source; |
| |
| // No need to recalculate thermal state if it is already at nominal. |
| if (last_state_ == system::DeviceThermalState::kNominal || |
| last_state_ == system::DeviceThermalState::kUnknown) |
| return; |
| |
| OnThermalChanged(nullptr); |
| } |
| |
| } // namespace policy |
| } // namespace power_manager |