| // Copyright 2019 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/system/wakeup_source_identifier.h" |
| |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "power_manager/powerd/system/udev.h" |
| #include "power_manager/powerd/system/wakeup_device.h" |
| |
| namespace power_manager { |
| namespace system { |
| |
| WakeupSourceIdentifier::WakeupSourceIdentifier(UdevInterface* udev) { |
| DCHECK(udev); |
| udev_ = udev; |
| udev_->AddSubsystemObserver(kInputUdevSubsystem, this); |
| |
| std::vector<UdevDeviceInfo> input_device_list; |
| if (udev_->GetSubsystemDevices(kInputUdevSubsystem, &input_device_list)) { |
| for (const auto& input_device : input_device_list) |
| HandleAddedInput(input_device.sysname, input_device.wakeup_device_path); |
| } else { |
| LOG(ERROR) << "Cannot monitor event counts of input devices. Dark resume " |
| "might not work properly"; |
| } |
| } |
| |
| WakeupSourceIdentifier::~WakeupSourceIdentifier() { |
| udev_->RemoveSubsystemObserver(kInputUdevSubsystem, this); |
| } |
| |
| void WakeupSourceIdentifier::PrepareForSuspendRequest() { |
| for (const auto& mp : monitored_paths_) |
| mp.second->PrepareForSuspend(); |
| } |
| |
| void WakeupSourceIdentifier::HandleResume() { |
| for (const auto& mp : monitored_paths_) |
| mp.second->HandleResume(); |
| } |
| |
| bool WakeupSourceIdentifier::InputDeviceCausedLastWake() const { |
| for (const auto& mp : monitored_paths_) { |
| if (mp.second->CausedLastWake()) |
| return true; |
| } |
| return false; |
| } |
| |
| void WakeupSourceIdentifier::OnUdevEvent(const UdevEvent& event) { |
| DCHECK_EQ(event.device_info.subsystem, kInputUdevSubsystem); |
| |
| if (event.action == UdevEvent::Action::ADD) { |
| HandleAddedInput(event.device_info.sysname, |
| event.device_info.wakeup_device_path); |
| } else if (event.action == UdevEvent::Action::REMOVE) { |
| // wakeup_device_path is not populated in the |event| during |
| // UdevEvent::Action::REMOVE event. Thus this code only depends on |
| // sysname while processing UdevEvent::Action::REMOVE. |
| HandleRemovedInput(event.device_info.sysname); |
| } |
| } |
| |
| void WakeupSourceIdentifier::HandleAddedInput( |
| const std::string& input_name, const base::FilePath& wakeup_device_path) { |
| if (wakeup_device_path.empty()) { |
| LOG(INFO) << "Input device " << input_name << " is not wake-capable"; |
| return; |
| } |
| |
| bool already_monitoring = wakeup_devices_.count(wakeup_device_path) > 0; |
| |
| wakeup_devices_[wakeup_device_path].insert(input_name); |
| |
| if (already_monitoring) |
| return; |
| |
| std::unique_ptr<WakeupDeviceInterface> wakeup_device = |
| WakeupDevice::CreateWakeupDevice(wakeup_device_path); |
| |
| if (!wakeup_device) |
| return; |
| |
| monitored_paths_[wakeup_device_path] = std::move(wakeup_device); |
| LOG(INFO) << "Monitoring wakeup path " << wakeup_device_path.value() |
| << " for wake events"; |
| } |
| |
| void WakeupSourceIdentifier::HandleRemovedInput(const std::string& input_name) { |
| base::FilePath input_device_wakeup_path; |
| |
| for (auto it = wakeup_devices_.begin(); it != wakeup_devices_.end(); it++) { |
| if (it->second.count(input_name)) { |
| it->second.erase(input_name); |
| input_device_wakeup_path = it->first; |
| } |
| } |
| |
| // We were not monitoring this input for wakeup counts at all. |
| if (input_device_wakeup_path.empty()) |
| return; |
| |
| if (!wakeup_devices_[input_device_wakeup_path].empty()) { |
| // This wake path is monitored to identify wakes from other inputs too. So |
| // nothing to do as of now. |
| return; |
| } |
| |
| wakeup_devices_.erase(input_device_wakeup_path); |
| |
| bool erase_successful = monitored_paths_.erase(input_device_wakeup_path); |
| DCHECK(erase_successful) |
| << "state mismatch between wakeup_devices_ and monitored_paths_"; |
| |
| LOG(INFO) << "Stopped monitoring wakeup path " |
| << input_device_wakeup_path.value() << " for wake events"; |
| } |
| |
| } // namespace system |
| } // namespace power_manager |