diff --git a/atom/browser/api/atom_api_power_monitor.h b/atom/browser/api/atom_api_power_monitor.h index 94717e4c9089..1a5f1ec6bd3b 100644 --- a/atom/browser/api/atom_api_power_monitor.h +++ b/atom/browser/api/atom_api_power_monitor.h @@ -6,8 +6,8 @@ #define ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_ #include "atom/browser/api/trackable_object.h" +#include "atom/browser/lib/power_observer.h" #include "base/compiler_specific.h" -#include "base/power_monitor/power_observer.h" #include "native_mate/handle.h" namespace atom { @@ -15,7 +15,7 @@ namespace atom { namespace api { class PowerMonitor : public mate::TrackableObject, - public base::PowerObserver { + public PowerObserver { public: static v8::Local Create(v8::Isolate* isolate); diff --git a/atom/browser/lib/power_observer.h b/atom/browser/lib/power_observer.h new file mode 100644 index 000000000000..0935b221e33d --- /dev/null +++ b/atom/browser/lib/power_observer.h @@ -0,0 +1,26 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_LIB_POWER_OBSERVER_H_ +#define ATOM_BROWSER_LIB_POWER_OBSERVER_H_ + +#include "base/macros.h" + +#if defined(OS_LINUX) +#include "atom/browser/lib/power_observer_linux.h" +#else +#include "base/power_monitor/power_observer.h" +#endif // defined(OS_LINUX) + +namespace atom { + +#if defined(OS_LINUX) +typedef PowerObserverLinux PowerObserver; +#else +typedef base::PowerObserver PowerObserver; +#endif // defined(OS_LINUX) + +} // namespace atom + +#endif // ATOM_BROWSER_LIB_POWER_OBSERVER_H_ diff --git a/atom/browser/lib/power_observer_linux.cc b/atom/browser/lib/power_observer_linux.cc new file mode 100644 index 000000000000..da4b8ea82a7b --- /dev/null +++ b/atom/browser/lib/power_observer_linux.cc @@ -0,0 +1,109 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. +#include "atom/browser/lib/power_observer_linux.h" + +#include +#include +#include + +#include "base/bind.h" +#include "device/bluetooth/dbus/dbus_thread_manager_linux.h" + +namespace { + +const char kLogindServiceName[] = "org.freedesktop.login1"; +const char kLogindObjectPath[] = "/org/freedesktop/login1"; +const char kLogindManagerInterface[] = "org.freedesktop.login1.Manager"; + +std::string get_executable_basename() { + char buf[4096]; + size_t buf_size = sizeof(buf); + std::string rv("electron"); + if (!uv_exepath(buf, &buf_size)) { + rv = strrchr(static_cast(buf), '/') + 1; + } + return std::move(rv); +} + +} // namespace + +namespace atom { + +PowerObserverLinux::PowerObserverLinux() + : lock_owner_name_(get_executable_basename()), weak_ptr_factory_(this) { + auto dbus_thread_manager = bluez::DBusThreadManagerLinux::Get(); + if (dbus_thread_manager) { + bus_ = dbus_thread_manager->GetSystemBus(); + if (bus_) { + logind_ = bus_->GetObjectProxy(kLogindServiceName, + dbus::ObjectPath(kLogindObjectPath)); + logind_->WaitForServiceToBeAvailable( + base::Bind(&PowerObserverLinux::OnLoginServiceAvailable, + weak_ptr_factory_.GetWeakPtr())); + } else { + LOG(WARNING) << "Failed to get system bus connection"; + } + } else { + LOG(WARNING) << "DBusThreadManagerLinux instance isn't available"; + } +} + +void PowerObserverLinux::OnLoginServiceAvailable(bool service_available) { + if (!service_available) { + LOG(WARNING) << kLogindServiceName << " not available"; + return; + } + // listen sleep + logind_->ConnectToSignal(kLogindManagerInterface, "PrepareForSleep", + base::Bind(&PowerObserverLinux::OnPrepareForSleep, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&PowerObserverLinux::OnSignalConnected, + weak_ptr_factory_.GetWeakPtr())); + TakeSleepLock(); +} + +void PowerObserverLinux::TakeSleepLock() { + dbus::MethodCall sleep_inhibit_call(kLogindManagerInterface, "Inhibit"); + dbus::MessageWriter inhibit_writer(&sleep_inhibit_call); + inhibit_writer.AppendString("sleep"); // what + // Use the executable name as the lock owner, which will list rebrands of the + // electron executable as separate entities. + inhibit_writer.AppendString(lock_owner_name_); // who + inhibit_writer.AppendString("Application cleanup before suspend"); // why + inhibit_writer.AppendString("delay"); // mode + logind_->CallMethod(&sleep_inhibit_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&PowerObserverLinux::OnInhibitResponse, + weak_ptr_factory_.GetWeakPtr(), &sleep_lock_)); +} + +void PowerObserverLinux::OnInhibitResponse(base::ScopedFD* scoped_fd, + dbus::Response* response) { + dbus::MessageReader reader(response); + reader.PopFileDescriptor(scoped_fd); +} + +void PowerObserverLinux::OnPrepareForSleep(dbus::Signal* signal) { + dbus::MessageReader reader(signal); + bool status; + if (!reader.PopBool(&status)) { + LOG(ERROR) << "Invalid signal: " << signal->ToString(); + return; + } + if (status) { + OnSuspend(); + sleep_lock_.reset(); + } else { + TakeSleepLock(); + OnResume(); + } +} + +void PowerObserverLinux::OnSignalConnected(const std::string& interface, + const std::string& signal, + bool success) { + LOG_IF(WARNING, !success) << "Failed to connect to " << signal; +} + +} // namespace atom diff --git a/atom/browser/lib/power_observer_linux.h b/atom/browser/lib/power_observer_linux.h new file mode 100644 index 000000000000..60691f721183 --- /dev/null +++ b/atom/browser/lib/power_observer_linux.h @@ -0,0 +1,42 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_LIB_POWER_OBSERVER_LINUX_H_ +#define ATOM_BROWSER_LIB_POWER_OBSERVER_LINUX_H_ + +#include + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/power_monitor/power_observer.h" +#include "dbus/bus.h" +#include "dbus/message.h" +#include "dbus/object_proxy.h" + +namespace atom { + +class PowerObserverLinux : public base::PowerObserver { + public: + PowerObserverLinux(); + + private: + void TakeSleepLock(); + void OnLoginServiceAvailable(bool available); + void OnInhibitResponse(base::ScopedFD* scoped_fd, dbus::Response* response); + void OnPrepareForSleep(dbus::Signal* signal); + void OnSignalConnected(const std::string& interface, + const std::string& signal, + bool success); + + scoped_refptr bus_; + scoped_refptr logind_; + std::string lock_owner_name_; + base::ScopedFD sleep_lock_; + base::WeakPtrFactory weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(PowerObserverLinux); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_LIB_POWER_OBSERVER_LINUX_H_ diff --git a/filenames.gypi b/filenames.gypi index b2ab8a36103f..e9f0f43b97ec 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -218,6 +218,9 @@ 'atom/browser/javascript_environment.h', 'atom/browser/lib/bluetooth_chooser.cc', 'atom/browser/lib/bluetooth_chooser.h', + 'atom/browser/lib/power_observer.h', + 'atom/browser/lib/power_observer_linux.h', + 'atom/browser/lib/power_observer_linux.cc', 'atom/browser/loader/layered_resource_handler.cc', 'atom/browser/loader/layered_resource_handler.h', 'atom/browser/login_handler.cc',