| // Copyright (c) 2012 The Chromium 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 "chromeos/dbus/power/power_manager_client.h" |
| |
| #include <stdint.h> |
| |
| #include <algorithm> |
| #include <memory> |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/command_line.h" |
| #include "base/format_macros.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/observer_list.h" |
| #include "base/power_monitor/power_monitor_device_source.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/threading/platform_thread.h" |
| #include "base/timer/timer.h" |
| #include "base/unguessable_token.h" |
| #include "chromeos/dbus/power/fake_power_manager_client.h" |
| #include "chromeos/dbus/power_manager/backlight.pb.h" |
| #include "chromeos/dbus/power_manager/idle.pb.h" |
| #include "chromeos/dbus/power_manager/input_event.pb.h" |
| #include "chromeos/dbus/power_manager/peripheral_battery_status.pb.h" |
| #include "chromeos/dbus/power_manager/switch_states.pb.h" |
| #include "components/device_event_log/device_event_log.h" |
| #include "dbus/bus.h" |
| #include "dbus/message.h" |
| #include "dbus/object_path.h" |
| #include "dbus/object_proxy.h" |
| |
| namespace chromeos { |
| |
| namespace { |
| |
| PowerManagerClient* g_instance = nullptr; |
| |
| // Maximum amount of time that the power manager will wait for Chrome to |
| // say that it's ready for the system to be suspended, in milliseconds. |
| const int kSuspendDelayTimeoutMs = 5000; |
| |
| // Human-readable description of Chrome's suspend delay. |
| const char kSuspendDelayDescription[] = "chrome"; |
| |
| // Returns a modified version of |proto| where fields are consistent. |
| power_manager::PowerSupplyProperties SanitizePowerSupplyProperties( |
| const power_manager::PowerSupplyProperties& proto) { |
| power_manager::PowerSupplyProperties sanitized = proto; |
| |
| if (sanitized.battery_state() == |
| power_manager::PowerSupplyProperties_BatteryState_FULL) { |
| sanitized.set_battery_percent(100.0); |
| } |
| |
| if (!sanitized.is_calculating_battery_time()) { |
| const bool on_line_power = |
| sanitized.external_power() != |
| power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED; |
| if ((on_line_power && sanitized.battery_time_to_full_sec() < 0) || |
| (!on_line_power && sanitized.battery_time_to_empty_sec() < 0)) { |
| sanitized.set_is_calculating_battery_time(true); |
| } |
| } |
| return sanitized; |
| } |
| |
| // Converts a LidState value from a power_manager::SwitchStates proto to the |
| // corresponding PowerManagerClient::LidState value. |
| PowerManagerClient::LidState GetLidStateFromProtoEnum( |
| power_manager::SwitchStates::LidState state) { |
| switch (state) { |
| case power_manager::SwitchStates_LidState_OPEN: |
| return PowerManagerClient::LidState::OPEN; |
| case power_manager::SwitchStates_LidState_CLOSED: |
| return PowerManagerClient::LidState::CLOSED; |
| case power_manager::SwitchStates_LidState_NOT_PRESENT: |
| return PowerManagerClient::LidState::NOT_PRESENT; |
| } |
| NOTREACHED() << "Unhandled lid state " << state; |
| return PowerManagerClient::LidState::NOT_PRESENT; |
| } |
| |
| // Converts a TabletMode value from a power_manager::SwitchStates proto to the |
| // corresponding PowerManagerClient::TabletMode value. |
| PowerManagerClient::TabletMode GetTabletModeFromProtoEnum( |
| power_manager::SwitchStates::TabletMode mode) { |
| switch (mode) { |
| case power_manager::SwitchStates_TabletMode_ON: |
| return PowerManagerClient::TabletMode::ON; |
| case power_manager::SwitchStates_TabletMode_OFF: |
| return PowerManagerClient::TabletMode::OFF; |
| case power_manager::SwitchStates_TabletMode_UNSUPPORTED: |
| return PowerManagerClient::TabletMode::UNSUPPORTED; |
| } |
| NOTREACHED() << "Unhandled tablet mode " << mode; |
| return PowerManagerClient::TabletMode::UNSUPPORTED; |
| } |
| |
| // Callback for D-Bus call made in |CreateArcTimers|. |
| void OnCreateArcTimersDBusMethod( |
| DBusMethodCallback<std::vector<PowerManagerClient::TimerId>> callback, |
| dbus::Response* response) { |
| if (response == nullptr) { |
| std::move(callback).Run(base::nullopt); |
| return; |
| } |
| |
| dbus::MessageReader reader(response); |
| dbus::MessageReader array_reader(nullptr); |
| if (!reader.PopArray(&array_reader)) { |
| POWER_LOG(ERROR) << "No timer ids returned"; |
| std::move(callback).Run(base::nullopt); |
| return; |
| } |
| |
| std::vector<PowerManagerClient::TimerId> timer_ids; |
| while (array_reader.HasMoreData()) { |
| int32_t timer_id; |
| if (!array_reader.PopInt32(&timer_id)) { |
| POWER_LOG(ERROR) << "Failed to pop timer id"; |
| std::move(callback).Run(base::nullopt); |
| return; |
| } |
| timer_ids.push_back(timer_id); |
| } |
| std::move(callback).Run(std::move(timer_ids)); |
| } |
| |
| // Callback for D-Bus call made in |StartArcTimer| and |DeleteArcTimers|. |
| void OnVoidDBusMethod(VoidDBusMethodCallback callback, |
| dbus::Response* response) { |
| std::move(callback).Run(response != nullptr); |
| } |
| |
| } // namespace |
| |
| // The PowerManagerClient implementation used in production. |
| class PowerManagerClientImpl : public PowerManagerClient { |
| public: |
| PowerManagerClientImpl() |
| : origin_thread_id_(base::PlatformThread::CurrentId()) {} |
| |
| ~PowerManagerClientImpl() override { |
| // Here we should unregister suspend notifications from powerd, |
| // however: |
| // - The lifetime of the PowerManagerClientImpl can extend past that of |
| // the objectproxy, |
| // - power_manager can already detect that the client is gone and |
| // unregister our suspend delay. |
| } |
| |
| void Init(dbus::Bus* bus) { |
| power_manager_proxy_ = bus->GetObjectProxy( |
| power_manager::kPowerManagerServiceName, |
| dbus::ObjectPath(power_manager::kPowerManagerServicePath)); |
| |
| power_manager_proxy_->SetNameOwnerChangedCallback( |
| base::Bind(&PowerManagerClientImpl::NameOwnerChangedReceived, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| power_manager_proxy_->WaitForServiceToBeAvailable( |
| base::BindOnce(&PowerManagerClientImpl::NotifyServiceBecameAvailable, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| // Listen to D-Bus signals emitted by powerd. |
| typedef void (PowerManagerClientImpl::*SignalMethod)(dbus::Signal*); |
| const std::map<const char*, SignalMethod> kSignalMethods = { |
| {power_manager::kScreenBrightnessChangedSignal, |
| &PowerManagerClientImpl::ScreenBrightnessChangedReceived}, |
| {power_manager::kKeyboardBrightnessChangedSignal, |
| &PowerManagerClientImpl::KeyboardBrightnessChangedReceived}, |
| {power_manager::kScreenIdleStateChangedSignal, |
| &PowerManagerClientImpl::ScreenIdleStateChangedReceived}, |
| {power_manager::kInactivityDelaysChangedSignal, |
| &PowerManagerClientImpl::InactivityDelaysChangedReceived}, |
| {power_manager::kPeripheralBatteryStatusSignal, |
| &PowerManagerClientImpl::PeripheralBatteryStatusReceived}, |
| {power_manager::kPowerSupplyPollSignal, |
| &PowerManagerClientImpl::PowerSupplyPollReceived}, |
| {power_manager::kInputEventSignal, |
| &PowerManagerClientImpl::InputEventReceived}, |
| {power_manager::kSuspendImminentSignal, |
| &PowerManagerClientImpl::SuspendImminentReceived}, |
| {power_manager::kSuspendDoneSignal, |
| &PowerManagerClientImpl::SuspendDoneReceived}, |
| {power_manager::kDarkSuspendImminentSignal, |
| &PowerManagerClientImpl::DarkSuspendImminentReceived}, |
| {power_manager::kScreenDimImminentSignal, |
| &PowerManagerClientImpl::ScreenDimImminentReceived}, |
| {power_manager::kIdleActionImminentSignal, |
| &PowerManagerClientImpl::IdleActionImminentReceived}, |
| {power_manager::kIdleActionDeferredSignal, |
| &PowerManagerClientImpl::IdleActionDeferredReceived}, |
| }; |
| for (const auto& it : kSignalMethods) { |
| power_manager_proxy_->ConnectToSignal( |
| power_manager::kPowerManagerInterface, it.first, |
| base::BindRepeating(it.second, weak_ptr_factory_.GetWeakPtr()), |
| base::BindOnce(&PowerManagerClientImpl::SignalConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| RegisterSuspendDelays(); |
| RequestStatusUpdate(); |
| } |
| |
| // PowerManagerClient overrides: |
| |
| void AddObserver(Observer* observer) override { |
| DCHECK(observer); // http://crbug.com/119976 |
| observers_.AddObserver(observer); |
| |
| if (service_available_) |
| observer->PowerManagerBecameAvailable(*service_available_); |
| } |
| |
| void RemoveObserver(Observer* observer) override { |
| observers_.RemoveObserver(observer); |
| } |
| |
| bool HasObserver(const Observer* observer) const override { |
| return observers_.HasObserver(observer); |
| } |
| |
| void SetRenderProcessManagerDelegate( |
| base::WeakPtr<RenderProcessManagerDelegate> delegate) override { |
| DCHECK(!render_process_manager_delegate_) |
| << "There can be only one! ...RenderProcessManagerDelegate"; |
| render_process_manager_delegate_ = delegate; |
| } |
| |
| void DecreaseScreenBrightness(bool allow_off) override { |
| dbus::MethodCall method_call( |
| power_manager::kPowerManagerInterface, |
| power_manager::kDecreaseScreenBrightnessMethod); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendBool(allow_off); |
| power_manager_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void IncreaseScreenBrightness() override { |
| SimpleMethodCallToPowerManager( |
| power_manager::kIncreaseScreenBrightnessMethod); |
| } |
| |
| void DecreaseKeyboardBrightness() override { |
| SimpleMethodCallToPowerManager( |
| power_manager::kDecreaseKeyboardBrightnessMethod); |
| } |
| |
| void IncreaseKeyboardBrightness() override { |
| SimpleMethodCallToPowerManager( |
| power_manager::kIncreaseKeyboardBrightnessMethod); |
| } |
| |
| const base::Optional<power_manager::PowerSupplyProperties>& GetLastStatus() |
| override { |
| return proto_; |
| } |
| |
| void SetScreenBrightness( |
| const power_manager::SetBacklightBrightnessRequest& request) override { |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| power_manager::kSetScreenBrightnessMethod); |
| if (!dbus::MessageWriter(&method_call).AppendProtoAsArrayOfBytes(request)) { |
| POWER_LOG(ERROR) << "Error serializing " |
| << power_manager::kSetScreenBrightnessMethod |
| << " request"; |
| return; |
| } |
| power_manager_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void GetScreenBrightnessPercent( |
| DBusMethodCallback<double> callback) override { |
| dbus::MethodCall method_call( |
| power_manager::kPowerManagerInterface, |
| power_manager::kGetScreenBrightnessPercentMethod); |
| power_manager_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce( |
| &PowerManagerClientImpl::OnGetScreenOrKeyboardBrightnessPercent, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void GetKeyboardBrightnessPercent( |
| DBusMethodCallback<double> callback) override { |
| dbus::MethodCall method_call( |
| power_manager::kPowerManagerInterface, |
| power_manager::kGetKeyboardBrightnessPercentMethod); |
| power_manager_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce( |
| &PowerManagerClientImpl::OnGetScreenOrKeyboardBrightnessPercent, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void RequestStatusUpdate() override { |
| POWER_LOG(USER) << "RequestStatusUpdate"; |
| dbus::MethodCall method_call( |
| power_manager::kPowerManagerInterface, |
| power_manager::kGetPowerSupplyPropertiesMethod); |
| power_manager_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce( |
| &PowerManagerClientImpl::OnGetPowerSupplyPropertiesMethod, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| void RequestSuspend() override { |
| POWER_LOG(USER) << "RequestSuspend"; |
| SimpleMethodCallToPowerManager(power_manager::kRequestSuspendMethod); |
| } |
| |
| void RequestRestart(power_manager::RequestRestartReason reason, |
| const std::string& description) override { |
| POWER_LOG(USER) << "RequestRestart: " << reason << " (" << description |
| << ")"; |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| power_manager::kRequestRestartMethod); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendInt32(reason); |
| writer.AppendString(description); |
| power_manager_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void RequestShutdown(power_manager::RequestShutdownReason reason, |
| const std::string& description) override { |
| POWER_LOG(USER) << "RequestShutdown: " << reason << " (" << description |
| << ")"; |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| power_manager::kRequestShutdownMethod); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendInt32(reason); |
| writer.AppendString(description); |
| power_manager_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void NotifyUserActivity(power_manager::UserActivityType type) override { |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| power_manager::kHandleUserActivityMethod); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendInt32(type); |
| |
| power_manager_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void NotifyVideoActivity(bool is_fullscreen) override { |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| power_manager::kHandleVideoActivityMethod); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendBool(is_fullscreen); |
| |
| power_manager_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void NotifyWakeNotification() override { |
| SimpleMethodCallToPowerManager( |
| power_manager::kHandleWakeNotificationMethod); |
| } |
| |
| void SetPolicy(const power_manager::PowerManagementPolicy& policy) override { |
| POWER_LOG(USER) << "SetPolicy"; |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| power_manager::kSetPolicyMethod); |
| dbus::MessageWriter writer(&method_call); |
| if (!writer.AppendProtoAsArrayOfBytes(policy)) { |
| POWER_LOG(ERROR) << "Error calling " << power_manager::kSetPolicyMethod; |
| return; |
| } |
| power_manager_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetIsProjecting(bool is_projecting) override { |
| POWER_LOG(USER) << "SetIsProjecting"; |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| power_manager::kSetIsProjectingMethod); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendBool(is_projecting); |
| power_manager_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| last_is_projecting_ = is_projecting; |
| } |
| |
| void SetPowerSource(const std::string& id) override { |
| POWER_LOG(USER) << "SetPowerSource: " << id; |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| power_manager::kSetPowerSourceMethod); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendString(id); |
| power_manager_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetBacklightsForcedOff(bool forced_off) override { |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| power_manager::kSetBacklightsForcedOffMethod); |
| dbus::MessageWriter(&method_call).AppendBool(forced_off); |
| power_manager_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void GetBacklightsForcedOff(DBusMethodCallback<bool> callback) override { |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| power_manager::kGetBacklightsForcedOffMethod); |
| power_manager_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&PowerManagerClientImpl::OnGetBacklightsForcedOff, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void GetSwitchStates(DBusMethodCallback<SwitchStates> callback) override { |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| power_manager::kGetSwitchStatesMethod); |
| power_manager_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&PowerManagerClientImpl::OnGetSwitchStates, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void GetInactivityDelays( |
| DBusMethodCallback<power_manager::PowerManagementPolicy::Delays> callback) |
| override { |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| power_manager::kGetInactivityDelaysMethod); |
| power_manager_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&PowerManagerClientImpl::OnGetInactivityDelays, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void BlockSuspend(const base::UnguessableToken& token, |
| const std::string& debug_info) override { |
| DCHECK(OnOriginThread()); |
| DCHECK(suspend_is_pending_); |
| DCHECK(token); |
| |
| suspend_readiness_registry_[token.ToString()] = { |
| pending_suspend_id_, suspending_from_dark_resume_, debug_info}; |
| } |
| |
| void UnblockSuspend(const base::UnguessableToken& token) override { |
| DCHECK(OnOriginThread()); |
| auto registration = suspend_readiness_registry_.find(token.ToString()); |
| |
| if (registration == suspend_readiness_registry_.end() || |
| registration->second.suspend_id != pending_suspend_id_ || |
| registration->second.suspending_from_dark_resume != |
| suspending_from_dark_resume_ || |
| !suspend_is_pending_) { |
| return; |
| } |
| |
| suspend_readiness_registry_.erase(registration); |
| MaybeReportSuspendReadiness(); |
| } |
| |
| void CreateArcTimers( |
| const std::string& tag, |
| std::vector<std::pair<clockid_t, base::ScopedFD>> arc_timer_requests, |
| DBusMethodCallback<std::vector<TimerId>> callback) override { |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| power_manager::kCreateArcTimersMethod); |
| |
| // Write mojo arguments i.e. client's tag and array of {int, fd} as a D-Bus |
| // message. |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendString(tag); |
| dbus::MessageWriter array_writer(nullptr); |
| writer.OpenArray("(ih)", &array_writer); |
| for (const auto& request : arc_timer_requests) { |
| dbus::MessageWriter struct_writer(nullptr); |
| array_writer.OpenStruct(&struct_writer); |
| struct_writer.AppendInt32(static_cast<int32_t>(request.first)); |
| // This dups the file descriptor and the original one stored as |
| // base::ScopedFD in |arc_timer_requests| will be closed when the function |
| // ends and it goes out of scope. |
| struct_writer.AppendFileDescriptor(request.second.get()); |
| array_writer.CloseContainer(&struct_writer); |
| } |
| writer.CloseContainer(&array_writer); |
| |
| power_manager_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&OnCreateArcTimersDBusMethod, std::move(callback))); |
| } |
| |
| void StartArcTimer(TimerId timer_id, |
| base::TimeTicks absolute_expiration_time, |
| VoidDBusMethodCallback callback) override { |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| power_manager::kStartArcTimerMethod); |
| |
| // Write clock id and 64-bit expiration time ticks value as a D-Bus message. |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendInt32(timer_id); |
| // The absolute ticks are still being sent because base::TimeTicks() returns |
| // 0. |
| writer.AppendInt64( |
| (absolute_expiration_time - base::TimeTicks()).InMicroseconds()); |
| |
| power_manager_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&OnVoidDBusMethod, std::move(callback))); |
| } |
| |
| void DeleteArcTimers(const std::string& tag, |
| VoidDBusMethodCallback callback) override { |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| power_manager::kDeleteArcTimersMethod); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendString(tag); |
| power_manager_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&OnVoidDBusMethod, std::move(callback))); |
| } |
| |
| void DeferScreenDim() override { |
| SimpleMethodCallToPowerManager(power_manager::kDeferScreenDimMethod); |
| } |
| |
| private: |
| // Returns true if the current thread is the origin thread. |
| bool OnOriginThread() { |
| return base::PlatformThread::CurrentId() == origin_thread_id_; |
| } |
| |
| // Called when a dbus signal is initially connected. |
| void SignalConnected(const std::string& interface_name, |
| const std::string& signal_name, |
| bool success) { |
| if (!success) |
| POWER_LOG(ERROR) << "Failed to connect to signal " << signal_name << "."; |
| } |
| |
| // Makes a method call to power manager with no arguments and no response. |
| void SimpleMethodCallToPowerManager(const std::string& method_name) { |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| method_name); |
| power_manager_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void NotifyServiceBecameAvailable(bool available) { |
| service_available_ = available; |
| for (auto& observer : observers_) |
| observer.PowerManagerBecameAvailable(available); |
| } |
| |
| void NameOwnerChangedReceived(const std::string& old_owner, |
| const std::string& new_owner) { |
| POWER_LOG(EVENT) << "Power manager restarted. Old owner: " |
| << (old_owner.empty() ? "[none]" : old_owner.c_str()) |
| << " New owner: " |
| << (new_owner.empty() ? "[none]" : new_owner.c_str()); |
| suspend_is_pending_ = false; |
| pending_suspend_id_ = -1; |
| suspending_from_dark_resume_ = false; |
| if (!new_owner.empty()) { |
| POWER_LOG(EVENT) << "Sending initial state to power manager"; |
| RegisterSuspendDelays(); |
| SetIsProjecting(last_is_projecting_); |
| for (auto& observer : observers_) |
| observer.PowerManagerRestarted(); |
| } |
| } |
| |
| void ScreenBrightnessChangedReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| power_manager::BacklightBrightnessChange proto; |
| if (!reader.PopArrayOfBytesAsProto(&proto)) { |
| POWER_LOG(ERROR) << "Unable to decode protocol buffer from " |
| << power_manager::kScreenBrightnessChangedSignal |
| << " signal"; |
| return; |
| } |
| POWER_LOG(DEBUG) << "Screen brightness changed to " << proto.percent() |
| << ": cause " << proto.cause(); |
| for (auto& observer : observers_) |
| observer.ScreenBrightnessChanged(proto); |
| } |
| |
| void KeyboardBrightnessChangedReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| power_manager::BacklightBrightnessChange proto; |
| if (!reader.PopArrayOfBytesAsProto(&proto)) { |
| POWER_LOG(ERROR) << "Unable to decode protocol buffer from " |
| << power_manager::kKeyboardBrightnessChangedSignal |
| << " signal"; |
| return; |
| } |
| POWER_LOG(DEBUG) << "Keyboard brightness changed to " << proto.percent() |
| << ": cause " << proto.cause(); |
| for (auto& observer : observers_) |
| observer.KeyboardBrightnessChanged(proto); |
| } |
| |
| void ScreenIdleStateChangedReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| power_manager::ScreenIdleState proto; |
| if (!reader.PopArrayOfBytesAsProto(&proto)) { |
| POWER_LOG(ERROR) << "Unable to decode protocol buffer from " |
| << power_manager::kScreenIdleStateChangedSignal |
| << " signal"; |
| return; |
| } |
| for (auto& observer : observers_) |
| observer.ScreenIdleStateChanged(proto); |
| } |
| |
| void InactivityDelaysChangedReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| power_manager::PowerManagementPolicy::Delays proto; |
| if (!reader.PopArrayOfBytesAsProto(&proto)) { |
| POWER_LOG(ERROR) << "Unable to decode protocol buffer from " |
| << power_manager::kInactivityDelaysChangedSignal |
| << " signal"; |
| return; |
| } |
| for (auto& observer : observers_) |
| observer.InactivityDelaysChanged(proto); |
| } |
| |
| void PeripheralBatteryStatusReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| power_manager::PeripheralBatteryStatus protobuf_status; |
| if (!reader.PopArrayOfBytesAsProto(&protobuf_status)) { |
| POWER_LOG(ERROR) << "Unable to decode protocol buffer from " |
| << power_manager::kPeripheralBatteryStatusSignal |
| << " signal"; |
| return; |
| } |
| |
| std::string path = protobuf_status.path(); |
| std::string name = protobuf_status.name(); |
| int level = protobuf_status.has_level() ? protobuf_status.level() : -1; |
| |
| POWER_LOG(DEBUG) << "Device battery status received " << level << " for " |
| << name << " at " << path; |
| |
| for (auto& observer : observers_) |
| observer.PeripheralBatteryStatusReceived(path, name, level); |
| } |
| |
| void PowerSupplyPollReceived(dbus::Signal* signal) { |
| POWER_LOG(DEBUG) << "Received power supply poll signal."; |
| dbus::MessageReader reader(signal); |
| power_manager::PowerSupplyProperties protobuf; |
| if (reader.PopArrayOfBytesAsProto(&protobuf)) { |
| HandlePowerSupplyProperties(protobuf); |
| } else { |
| POWER_LOG(ERROR) << "Unable to decode " |
| << power_manager::kPowerSupplyPollSignal << " signal"; |
| } |
| } |
| |
| void OnGetPowerSupplyPropertiesMethod(dbus::Response* response) { |
| if (!response) { |
| POWER_LOG(ERROR) << "Error calling " |
| << power_manager::kGetPowerSupplyPropertiesMethod; |
| return; |
| } |
| |
| dbus::MessageReader reader(response); |
| power_manager::PowerSupplyProperties protobuf; |
| if (reader.PopArrayOfBytesAsProto(&protobuf)) { |
| HandlePowerSupplyProperties(protobuf); |
| } else { |
| POWER_LOG(ERROR) << "Unable to decode " |
| << power_manager::kGetPowerSupplyPropertiesMethod |
| << " response"; |
| } |
| } |
| |
| void OnGetScreenOrKeyboardBrightnessPercent( |
| DBusMethodCallback<double> callback, |
| dbus::Response* response) { |
| if (!response) { |
| std::move(callback).Run(base::nullopt); |
| return; |
| } |
| dbus::MessageReader reader(response); |
| double percent = 0.0; |
| if (!reader.PopDouble(&percent)) { |
| POWER_LOG(ERROR) << "Error reading response from powerd: " |
| << response->ToString(); |
| std::move(callback).Run(base::nullopt); |
| return; |
| } |
| std::move(callback).Run(percent); |
| } |
| |
| void OnGetBacklightsForcedOff(DBusMethodCallback<bool> callback, |
| dbus::Response* response) { |
| if (!response) { |
| POWER_LOG(ERROR) << "Error calling " |
| << power_manager::kGetBacklightsForcedOffMethod; |
| std::move(callback).Run(base::nullopt); |
| return; |
| } |
| dbus::MessageReader reader(response); |
| bool state = false; |
| if (!reader.PopBool(&state)) { |
| POWER_LOG(ERROR) << "Error reading response from powerd: " |
| << response->ToString(); |
| std::move(callback).Run(base::nullopt); |
| return; |
| } |
| std::move(callback).Run(state); |
| } |
| |
| void OnGetSwitchStates(DBusMethodCallback<SwitchStates> callback, |
| dbus::Response* response) { |
| if (!response) { |
| POWER_LOG(ERROR) << "Error calling " |
| << power_manager::kGetSwitchStatesMethod; |
| std::move(callback).Run(base::nullopt); |
| return; |
| } |
| |
| dbus::MessageReader reader(response); |
| power_manager::SwitchStates proto; |
| if (!reader.PopArrayOfBytesAsProto(&proto)) { |
| POWER_LOG(ERROR) << "Error parsing response from " |
| << power_manager::kGetSwitchStatesMethod; |
| std::move(callback).Run(base::nullopt); |
| return; |
| } |
| std::move(callback).Run( |
| SwitchStates{GetLidStateFromProtoEnum(proto.lid_state()), |
| GetTabletModeFromProtoEnum(proto.tablet_mode())}); |
| } |
| |
| void OnGetInactivityDelays( |
| DBusMethodCallback<power_manager::PowerManagementPolicy::Delays> callback, |
| dbus::Response* response) { |
| if (!response) { |
| POWER_LOG(ERROR) << "Error calling " |
| << power_manager::kGetInactivityDelaysMethod; |
| std::move(callback).Run(base::nullopt); |
| return; |
| } |
| |
| dbus::MessageReader reader(response); |
| power_manager::PowerManagementPolicy::Delays proto; |
| if (!reader.PopArrayOfBytesAsProto(&proto)) { |
| POWER_LOG(ERROR) << "Error parsing response from " |
| << power_manager::kGetInactivityDelaysMethod; |
| std::move(callback).Run(base::nullopt); |
| return; |
| } |
| std::move(callback).Run(proto); |
| } |
| |
| void HandlePowerSupplyProperties( |
| const power_manager::PowerSupplyProperties& proto) { |
| proto_ = SanitizePowerSupplyProperties(proto); |
| for (auto& observer : observers_) |
| observer.PowerChanged(*proto_); |
| const bool on_battery = |
| proto_->external_power() == |
| power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED; |
| base::PowerMonitorDeviceSource::SetPowerSource(on_battery); |
| } |
| |
| void HandleRegisterSuspendDelayReply(bool dark_suspend, |
| const std::string& method_name, |
| dbus::Response* response) { |
| if (!response) { |
| POWER_LOG(ERROR) << "Error calling " << method_name; |
| return; |
| } |
| |
| dbus::MessageReader reader(response); |
| power_manager::RegisterSuspendDelayReply protobuf; |
| if (!reader.PopArrayOfBytesAsProto(&protobuf)) { |
| POWER_LOG(ERROR) << "Unable to parse reply from " << method_name; |
| return; |
| } |
| |
| if (dark_suspend) { |
| dark_suspend_delay_id_ = protobuf.delay_id(); |
| has_dark_suspend_delay_id_ = true; |
| POWER_LOG(EVENT) << "Registered dark suspend delay " |
| << dark_suspend_delay_id_; |
| } else { |
| suspend_delay_id_ = protobuf.delay_id(); |
| has_suspend_delay_id_ = true; |
| POWER_LOG(EVENT) << "Registered suspend delay " << suspend_delay_id_; |
| } |
| } |
| |
| void SuspendImminentReceived(dbus::Signal* signal) { |
| HandleSuspendImminent(false /* in_dark_resume */, signal); |
| } |
| |
| void DarkSuspendImminentReceived(dbus::Signal* signal) { |
| HandleSuspendImminent(true /* in_dark_resume */, signal); |
| } |
| |
| void HandleSuspendImminent(bool in_dark_resume, dbus::Signal* signal) { |
| std::string signal_name = signal->GetMember(); |
| if ((in_dark_resume && !has_dark_suspend_delay_id_) || |
| (!in_dark_resume && !has_suspend_delay_id_)) { |
| POWER_LOG(ERROR) << "Received unrequested " << signal_name << " signal"; |
| return; |
| } |
| |
| dbus::MessageReader reader(signal); |
| power_manager::SuspendImminent proto; |
| if (!reader.PopArrayOfBytesAsProto(&proto)) { |
| POWER_LOG(ERROR) << "Unable to decode protocol buffer from " |
| << signal_name << " signal"; |
| return; |
| } |
| |
| POWER_LOG(EVENT) << "Got " << signal_name |
| << " signal announcing suspend attempt " |
| << proto.suspend_id(); |
| |
| // If a previous suspend is pending from the same state we are currently in |
| // (fully powered on or in dark resume), then something's gone a little |
| // wonky. |
| if (suspend_is_pending_ && suspending_from_dark_resume_ == in_dark_resume) { |
| POWER_LOG(ERROR) << "Got " << signal_name |
| << " signal about pending suspend attempt " |
| << proto.suspend_id() |
| << " while still waiting on attempt " |
| << pending_suspend_id_; |
| } |
| |
| pending_suspend_id_ = proto.suspend_id(); |
| suspend_is_pending_ = true; |
| suspending_from_dark_resume_ = in_dark_resume; |
| suspend_readiness_registry_.clear(); |
| |
| // Record the fact that observers are being notified to ensure that we don't |
| // report readiness prematurely if one of them calls BlockSuspend() and then |
| // runs UnblockSuspend() synchonously instead of asynchronously. |
| notifying_observers_about_suspend_imminent_ = true; |
| if (suspending_from_dark_resume_) { |
| for (auto& observer : observers_) |
| observer.DarkSuspendImminent(); |
| } else { |
| for (auto& observer : observers_) |
| observer.SuspendImminent(proto.reason()); |
| } |
| notifying_observers_about_suspend_imminent_ = false; |
| |
| base::PowerMonitorDeviceSource::HandleSystemSuspending(); |
| MaybeReportSuspendReadiness(); |
| } |
| |
| void SuspendDoneReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| power_manager::SuspendDone proto; |
| if (!reader.PopArrayOfBytesAsProto(&proto)) { |
| POWER_LOG(ERROR) << "Unable to decode protocol buffer from " |
| << power_manager::kSuspendDoneSignal << " signal"; |
| return; |
| } |
| |
| const base::TimeDelta duration = |
| base::TimeDelta::FromInternalValue(proto.suspend_duration()); |
| POWER_LOG(EVENT) << "Got " << power_manager::kSuspendDoneSignal |
| << " signal:" |
| << " suspend_id=" << proto.suspend_id() |
| << " duration=" << duration.InSeconds() << " sec"; |
| |
| // RenderProcessManagerDelegate is only notified that suspend is imminent |
| // when readiness is being reported to powerd. If the suspend attempt was |
| // cancelled before then, we shouldn't notify the delegate about completion. |
| const bool cancelled_while_regular_suspend_pending = |
| suspend_is_pending_ && !suspending_from_dark_resume_; |
| if (render_process_manager_delegate_ && |
| !cancelled_while_regular_suspend_pending) |
| render_process_manager_delegate_->SuspendDone(); |
| |
| // powerd always pairs each SuspendImminent signal with SuspendDone before |
| // starting the next suspend attempt, so we should no longer report |
| // readiness for any in-progress suspend attempts. |
| pending_suspend_id_ = -1; |
| suspend_is_pending_ = false; |
| suspending_from_dark_resume_ = false; |
| |
| // powerd gives clients a limited amount of time to report suspend |
| // readiness. Log the stragglers within Chrome to aid in debugging. |
| for (const auto it : suspend_readiness_registry_) { |
| LOG(WARNING) << "Didn't report suspend readiness due to " |
| << it.second.debug_info; |
| } |
| suspend_readiness_registry_.clear(); |
| |
| for (auto& observer : observers_) |
| observer.SuspendDone(duration); |
| base::PowerMonitorDeviceSource::HandleSystemResumed(); |
| } |
| |
| void ScreenDimImminentReceived(dbus::Signal* signal) { |
| for (auto& observer : observers_) |
| observer.ScreenDimImminent(); |
| } |
| |
| void IdleActionImminentReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| power_manager::IdleActionImminent proto; |
| if (!reader.PopArrayOfBytesAsProto(&proto)) { |
| POWER_LOG(ERROR) << "Unable to decode protocol buffer from " |
| << power_manager::kIdleActionImminentSignal << " signal"; |
| return; |
| } |
| for (auto& observer : observers_) { |
| observer.IdleActionImminent( |
| base::TimeDelta::FromInternalValue(proto.time_until_idle_action())); |
| } |
| } |
| |
| void IdleActionDeferredReceived(dbus::Signal* signal) { |
| for (auto& observer : observers_) |
| observer.IdleActionDeferred(); |
| } |
| |
| void InputEventReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| power_manager::InputEvent proto; |
| if (!reader.PopArrayOfBytesAsProto(&proto)) { |
| POWER_LOG(ERROR) << "Unable to decode protocol buffer from " |
| << power_manager::kInputEventSignal << " signal"; |
| return; |
| } |
| |
| base::TimeTicks timestamp = |
| base::TimeTicks::FromInternalValue(proto.timestamp()); |
| POWER_LOG(USER) << "Got " << power_manager::kInputEventSignal << " signal:" |
| << " type=" << proto.type() |
| << " timestamp=" << proto.timestamp(); |
| switch (proto.type()) { |
| case power_manager::InputEvent_Type_POWER_BUTTON_DOWN: |
| case power_manager::InputEvent_Type_POWER_BUTTON_UP: { |
| const bool down = |
| (proto.type() == power_manager::InputEvent_Type_POWER_BUTTON_DOWN); |
| for (auto& observer : observers_) |
| observer.PowerButtonEventReceived(down, timestamp); |
| |
| // Tell powerd that Chrome has handled power button presses. |
| if (down) { |
| dbus::MethodCall method_call( |
| power_manager::kPowerManagerInterface, |
| power_manager::kHandlePowerButtonAcknowledgmentMethod); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendInt64(proto.timestamp()); |
| power_manager_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| break; |
| } |
| case power_manager::InputEvent_Type_LID_OPEN: |
| for (auto& observer : observers_) |
| observer.LidEventReceived(LidState::OPEN, timestamp); |
| break; |
| case power_manager::InputEvent_Type_LID_CLOSED: |
| for (auto& observer : observers_) |
| observer.LidEventReceived(LidState::CLOSED, timestamp); |
| break; |
| case power_manager::InputEvent_Type_TABLET_MODE_ON: |
| for (auto& observer : observers_) |
| observer.TabletModeEventReceived(TabletMode::ON, timestamp); |
| break; |
| case power_manager::InputEvent_Type_TABLET_MODE_OFF: |
| for (auto& observer : observers_) |
| observer.TabletModeEventReceived(TabletMode::OFF, timestamp); |
| break; |
| } |
| } |
| |
| void RegisterSuspendDelayImpl( |
| const std::string& method_name, |
| const power_manager::RegisterSuspendDelayRequest& protobuf_request, |
| dbus::ObjectProxy::ResponseCallback callback) { |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| method_name); |
| dbus::MessageWriter writer(&method_call); |
| |
| if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) { |
| POWER_LOG(ERROR) << "Error constructing message for " << method_name; |
| return; |
| } |
| |
| power_manager_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| std::move(callback)); |
| } |
| |
| // Registers suspend delays with the power manager. This is usually only |
| // called at startup, but if the power manager restarts, we need to create new |
| // delays. |
| void RegisterSuspendDelays() { |
| // Throw out any old delay that was registered. |
| suspend_delay_id_ = -1; |
| has_suspend_delay_id_ = false; |
| dark_suspend_delay_id_ = -1; |
| has_dark_suspend_delay_id_ = false; |
| |
| power_manager::RegisterSuspendDelayRequest protobuf_request; |
| base::TimeDelta timeout = |
| base::TimeDelta::FromMilliseconds(kSuspendDelayTimeoutMs); |
| protobuf_request.set_timeout(timeout.ToInternalValue()); |
| protobuf_request.set_description(kSuspendDelayDescription); |
| |
| RegisterSuspendDelayImpl( |
| power_manager::kRegisterSuspendDelayMethod, protobuf_request, |
| base::BindOnce(&PowerManagerClientImpl::HandleRegisterSuspendDelayReply, |
| weak_ptr_factory_.GetWeakPtr(), false, |
| power_manager::kRegisterSuspendDelayMethod)); |
| RegisterSuspendDelayImpl( |
| power_manager::kRegisterDarkSuspendDelayMethod, protobuf_request, |
| base::BindOnce(&PowerManagerClientImpl::HandleRegisterSuspendDelayReply, |
| weak_ptr_factory_.GetWeakPtr(), true, |
| power_manager::kRegisterDarkSuspendDelayMethod)); |
| } |
| |
| // Reports suspend readiness to powerd if no observers are still holding |
| // suspend readiness callbacks. |
| void MaybeReportSuspendReadiness() { |
| DCHECK(suspend_is_pending_); |
| |
| // Avoid reporting suspend readiness if some observers have yet to be |
| // notified about the pending attempt. |
| if (notifying_observers_about_suspend_imminent_) |
| return; |
| |
| if (!suspend_readiness_registry_.empty()) |
| return; |
| |
| std::string method_name; |
| int32_t delay_id = -1; |
| if (suspending_from_dark_resume_) { |
| method_name = power_manager::kHandleDarkSuspendReadinessMethod; |
| delay_id = dark_suspend_delay_id_; |
| } else { |
| method_name = power_manager::kHandleSuspendReadinessMethod; |
| delay_id = suspend_delay_id_; |
| } |
| |
| if (render_process_manager_delegate_ && !suspending_from_dark_resume_) |
| render_process_manager_delegate_->SuspendImminent(); |
| |
| dbus::MethodCall method_call(power_manager::kPowerManagerInterface, |
| method_name); |
| dbus::MessageWriter writer(&method_call); |
| |
| POWER_LOG(EVENT) << "Announcing readiness of suspend delay " << delay_id |
| << " for suspend attempt " << pending_suspend_id_; |
| power_manager::SuspendReadinessInfo protobuf_request; |
| protobuf_request.set_delay_id(delay_id); |
| protobuf_request.set_suspend_id(pending_suspend_id_); |
| |
| pending_suspend_id_ = -1; |
| suspend_is_pending_ = false; |
| |
| if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) { |
| POWER_LOG(ERROR) << "Error constructing message for " << method_name; |
| return; |
| } |
| power_manager_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| // Origin thread (i.e. the UI thread in production). |
| base::PlatformThreadId origin_thread_id_; |
| |
| dbus::ObjectProxy* power_manager_proxy_ = nullptr; |
| base::ObserverList<Observer>::Unchecked observers_; |
| |
| base::Optional<bool> service_available_; |
| |
| // The delay ID obtained from the RegisterSuspendDelay request. |
| int32_t suspend_delay_id_ = -1; |
| bool has_suspend_delay_id_ = false; |
| |
| // The delay ID obtained from the RegisterDarkSuspendDelay request. |
| int32_t dark_suspend_delay_id_ = -1; |
| bool has_dark_suspend_delay_id_ = false; |
| |
| // powerd-supplied ID corresponding to an imminent (either regular or dark) |
| // suspend attempt that is currently being delayed. |
| int32_t pending_suspend_id_ = -1; |
| bool suspend_is_pending_ = false; |
| |
| // Set to true when the suspend currently being delayed was triggered during a |
| // dark resume. Since |pending_suspend_id_| and |suspend_is_pending_| are |
| // both shared by normal and dark suspends, |suspending_from_dark_resume_| |
| // helps distinguish the context within which these variables are being used. |
| bool suspending_from_dark_resume_ = false; |
| |
| struct SuspendInfo { |
| int32_t suspend_id; |
| bool suspending_from_dark_resume; |
| std::string debug_info; |
| }; |
| |
| // A map that holds BlockSuspend() registrations. It maps from the token (in |
| // string form) to details about the suspend. |
| std::unordered_map<std::string, SuspendInfo> suspend_readiness_registry_; |
| |
| // Inspected by MaybeReportSuspendReadiness() to avoid prematurely notifying |
| // powerd about suspend readiness while |observers_|' SuspendImminent() |
| // methods are being called by HandleSuspendImminent(). |
| bool notifying_observers_about_suspend_imminent_ = false; |
| |
| // Last state passed to SetIsProjecting(). |
| bool last_is_projecting_ = false; |
| |
| // The last proto received from D-Bus; initially empty. |
| base::Optional<power_manager::PowerSupplyProperties> proto_; |
| |
| // The delegate used to manage the power consumption of Chrome's renderer |
| // processes. |
| base::WeakPtr<RenderProcessManagerDelegate> render_process_manager_delegate_; |
| |
| // Note: This should remain the last member so it'll be destroyed and |
| // invalidate its weak pointers before any other members are destroyed. |
| base::WeakPtrFactory<PowerManagerClientImpl> weak_ptr_factory_{this}; |
| |
| DISALLOW_COPY_AND_ASSIGN(PowerManagerClientImpl); |
| }; |
| |
| PowerManagerClient::PowerManagerClient() { |
| DCHECK(!g_instance); |
| g_instance = this; |
| } |
| |
| PowerManagerClient::~PowerManagerClient() { |
| DCHECK_EQ(g_instance, this); |
| g_instance = nullptr; |
| } |
| |
| // static |
| void PowerManagerClient::Initialize(dbus::Bus* bus) { |
| DCHECK(bus); |
| DCHECK(!g_instance); |
| auto* power_manager_client = new PowerManagerClientImpl(); |
| power_manager_client->Init(bus); |
| g_instance = power_manager_client; |
| } |
| |
| // static |
| void PowerManagerClient::InitializeFake() { |
| new FakePowerManagerClient(); |
| } |
| |
| // static |
| void PowerManagerClient::Shutdown() { |
| delete g_instance; |
| } |
| |
| // static |
| PowerManagerClient* PowerManagerClient::Get() { |
| return g_instance; |
| } |
| |
| } // namespace chromeos |