From dfd78a26629eb836c2e6e275ebe54d66f19d33e4 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 24 Aug 2019 12:41:18 -0700 Subject: [PATCH] Support platform independent sleep/wake notifications --- interface/src/Application.cpp | 36 +++++----- interface/src/MacHelper.cpp | 58 --------------- interface/src/MacHelper.h | 21 ------ .../shared/src/shared/PlatformHelper.cpp | 27 +++++++ libraries/shared/src/shared/PlatformHelper.h | 41 +++++++++++ .../src/shared/platform/AndroidHelper.cpp | 27 +++++++ .../src/shared/platform/LinuxHelper.cpp | 27 +++++++ .../shared/src/shared/platform/MacHelper.cpp | 70 +++++++++++++++++++ .../shared/src/shared/platform/WinHelper.cpp | 52 ++++++++++++++ 9 files changed, 263 insertions(+), 96 deletions(-) delete mode 100755 interface/src/MacHelper.cpp delete mode 100755 interface/src/MacHelper.h create mode 100644 libraries/shared/src/shared/PlatformHelper.cpp create mode 100644 libraries/shared/src/shared/PlatformHelper.h create mode 100644 libraries/shared/src/shared/platform/AndroidHelper.cpp create mode 100644 libraries/shared/src/shared/platform/LinuxHelper.cpp create mode 100644 libraries/shared/src/shared/platform/MacHelper.cpp create mode 100644 libraries/shared/src/shared/platform/WinHelper.cpp diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 062a8fa9c1..b81f303589 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -58,6 +58,7 @@ #include #include +#include #include #include #include @@ -257,10 +258,6 @@ extern "C" { } #endif -#ifdef Q_OS_MAC -#include "MacHelper.h" -#endif - #if defined(Q_OS_ANDROID) #include #include "AndroidHelper.h" @@ -552,13 +549,6 @@ public: return true; } - if (message->message == WM_POWERBROADCAST) { - if (message->wParam == PBT_APMRESUMEAUTOMATIC) { - qCInfo(interfaceapp) << "Waking up from sleep or hybernation."; - QMetaObject::invokeMethod(DependencyManager::get().data(), "noteAwakening", Qt::QueuedConnection); - } - } - if (message->message == WM_COPYDATA) { COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)(message->lParam); QUrl url = QUrl((const char*)(pcds->lpData)); @@ -964,9 +954,12 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); -#ifdef Q_OS_MAC - DependencyManager::set(); -#endif + PlatformHelper::setup(); + + QObject::connect(DependencyManager::get().get(), &PlatformHelper::systemWillWake, [] { + QMetaObject::invokeMethod(DependencyManager::get().data(), "noteAwakening", Qt::QueuedConnection); + }); + QString setBookmarkValue = getCmdOption(argc, constArgv, "--setBookmark"); if (!setBookmarkValue.isEmpty()) { @@ -1172,6 +1165,17 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo deadlockWatchdogThread->setMainThreadID(QThread::currentThreadId()); deadlockWatchdogThread->start(); + // Pause the deadlock watchdog when we sleep, or it might + // trigger a false positive when we wake back up + auto platformHelper = DependencyManager::get(); + + connect(platformHelper.get(), &PlatformHelper::systemWillSleep, [] { + DeadlockWatchdogThread::pause(); + }); + + connect(platformHelper.get(), &PlatformHelper::systemWillWake, [] { + DeadlockWatchdogThread::resume(); + }); // Main thread timer to keep the watchdog updated QTimer* watchdogUpdateTimer = new QTimer(this); @@ -2869,9 +2873,7 @@ Application::~Application() { _gameWorkload.shutdown(); DependencyManager::destroy(); -#ifdef Q_OS_MAC - DependencyManager::destroy(); -#endif + PlatformHelper::shutdown(); _entityClipboard->eraseAllOctreeElements(); _entityClipboard.reset(); diff --git a/interface/src/MacHelper.cpp b/interface/src/MacHelper.cpp deleted file mode 100755 index 8527f02918..0000000000 --- a/interface/src/MacHelper.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// -// MacHelper.h -// interface/src -// -// Created by Howard Stearns -// Copyright 2019 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "InterfaceLogging.h" -#include "MacHelper.h" -#include - -#ifdef Q_OS_MAC -#include -#include - -// The type definitions in these variables come from IOKit, which includes a definition of Duration that conflicts with ours. -// So... we include these definitions here rather than in the .h, as the .h is included in Application.cpp which -// uses Duration. -static io_connect_t root_port; -static IONotificationPortRef notifyPortRef; -static io_object_t notifierObject; -static void* refCon; - -static void sleepHandler(void* refCon, io_service_t service, natural_t messageType, void* messageArgument) { - if (messageType == kIOMessageSystemHasPoweredOn) { - qCInfo(interfaceapp) << "Waking up from sleep or hybernation."; - QMetaObject::invokeMethod(DependencyManager::get().data(), "noteAwakening", Qt::QueuedConnection); - } -} -#endif - -MacHelper::MacHelper() { -#ifdef Q_OS_MAC - root_port = IORegisterForSystemPower(refCon, ¬ifyPortRef, sleepHandler, ¬ifierObject); - if (root_port == 0) { - qCWarning(interfaceapp) << "IORegisterForSystemPower failed"; - return; - } - CFRunLoopAddSource(CFRunLoopGetCurrent(), - IONotificationPortGetRunLoopSource(notifyPortRef), - kCFRunLoopCommonModes); -#endif -} - -MacHelper::~MacHelper() { -#ifdef Q_OS_MAC - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), - IONotificationPortGetRunLoopSource(notifyPortRef), - kCFRunLoopCommonModes); - IODeregisterForSystemPower(¬ifierObject); - IOServiceClose(root_port); - IONotificationPortDestroy(notifyPortRef); -#endif -} diff --git a/interface/src/MacHelper.h b/interface/src/MacHelper.h deleted file mode 100755 index 52ad4d3e55..0000000000 --- a/interface/src/MacHelper.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// MacHelper.h -// interface/src -// -// Created by Howard Stearns -// Copyright 2019 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#pragma once - -#include "DependencyManager.h" - -class MacHelper : public Dependency { -public: - MacHelper(); - ~MacHelper(); -}; - diff --git a/libraries/shared/src/shared/PlatformHelper.cpp b/libraries/shared/src/shared/PlatformHelper.cpp new file mode 100644 index 0000000000..a1a1ef4125 --- /dev/null +++ b/libraries/shared/src/shared/PlatformHelper.cpp @@ -0,0 +1,27 @@ +// +// Created by Bradley Austin Davis on 2019/08/22 +// Copyright 2013-2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "PlatformHelper.h" + +void PlatformHelper::onSleep() { + if (_awake.exchange(false)) { + qInfo() << "Entering sleep or hibernation."; + emit systemWillSleep(); + } +} + +void PlatformHelper::onWake() { + if (!_awake.exchange(true)) { + qInfo() << "Waking up from sleep or hibernation."; + emit systemWillWake(); + } +} + +void PlatformHelper::shutdown() { + DependencyManager::destroy(); +} + diff --git a/libraries/shared/src/shared/PlatformHelper.h b/libraries/shared/src/shared/PlatformHelper.h new file mode 100644 index 0000000000..cdfff1b9fc --- /dev/null +++ b/libraries/shared/src/shared/PlatformHelper.h @@ -0,0 +1,41 @@ +// +// Created by Bradley Austin Davis on 2019/08/22 +// Copyright 2013-2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once +#ifndef hifi_shared_PlatformHelper_h +#define hifi_shared_PlatformHelper_h + +#include +#include +#include "../DependencyManager.h" + +class PlatformHelper : public QObject, public Dependency { + Q_OBJECT +public: + PlatformHelper() {} + virtual ~PlatformHelper() {} + + void onSleep(); + void onWake(); + +signals: + void systemWillSleep(); + void systemWillWake(); + +public: + // Run the per-platform code to instantiate a platform-dependent PlatformHelper dependency object + static void setup(); + // Run the per-platform code to cleanly shutdown a platform-dependent PlatformHelper dependency object + static void shutdown(); + + std::atomic _awake{ true }; +}; + + + +#endif diff --git a/libraries/shared/src/shared/platform/AndroidHelper.cpp b/libraries/shared/src/shared/platform/AndroidHelper.cpp new file mode 100644 index 0000000000..5194264e9e --- /dev/null +++ b/libraries/shared/src/shared/platform/AndroidHelper.cpp @@ -0,0 +1,27 @@ +// +// Created by Bradley Austin Davis on 2019/08/22 +// Copyright 2013-2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "../PlatformHelper.h" + +#if defined(Q_OS_ANDROID) + +// FIXME support sleep/wake notifications +class AndroidHelper : public PlatformHelper { +public: + AndroidHelper() { + } + + ~AndroidHelper() { + } +}; + +void PlatformHelper::setup() { + DependencyManager::set(); +} + +#endif diff --git a/libraries/shared/src/shared/platform/LinuxHelper.cpp b/libraries/shared/src/shared/platform/LinuxHelper.cpp new file mode 100644 index 0000000000..2bbdde5698 --- /dev/null +++ b/libraries/shared/src/shared/platform/LinuxHelper.cpp @@ -0,0 +1,27 @@ +// +// Created by Bradley Austin Davis on 2019/08/22 +// Copyright 2013-2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "../PlatformHelper.h" + +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_MAC) && !defined(Q_OS_WIN) + +// FIXME support sleep/wake notifications +class LinuxHelper : public PlatformHelper { +public: + LinuxHelper() { + } + + ~LinuxHelper() { + } +}; + +void PlatformHelper::setup() { + DependencyManager::set(); +} + +#endif diff --git a/libraries/shared/src/shared/platform/MacHelper.cpp b/libraries/shared/src/shared/platform/MacHelper.cpp new file mode 100644 index 0000000000..7bc10142ad --- /dev/null +++ b/libraries/shared/src/shared/platform/MacHelper.cpp @@ -0,0 +1,70 @@ +// +// Created by Bradley Austin Davis on 2019/08/22 +// Based on interface/src/MacHelper.cpp, created by Howard Stearns +// Copyright 2013-2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "../PlatformHelper.h" + +#if !defined(Q_OS_ANDROID) && defined(Q_OS_MAC) +#include +#include + +class MacHelper : public PlatformHelper { +public: + MacHelper() { + _rootPort = IORegisterForSystemPower(this, &_notifyPortRef, serviceInterestCallback, &_notifierObject); + if (_rootPort == 0) { + qWarning() << "IORegisterForSystemPower failed"; + return; + } + CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(_notifyPortRef), kCFRunLoopCommonModes); + } + + ~MacHelper() { + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(_notifyPortRef), kCFRunLoopCommonModes); + IODeregisterForSystemPower(&_notifierObject); + IOServiceClose(_rootPort); + IONotificationPortDestroy(_notifyPortRef); + } + +private: + void onServiceMessage(io_service_t, natural_t messageType, void* messageArgument) { + switch (messageType) { + case kIOMessageSystemHasPoweredOn: + onWake(); + break; + + case kIOMessageSystemWillSleep: + onSleep(); + // explicit fallthrough + + // Per the documentation for kIOMessageSystemWillSleep and kIOMessageCanSystemSleep, the receiver MUST respond + // https://developer.apple.com/documentation/iokit/1557114-ioregisterforsystempower?language=objc + case kIOMessageCanSystemSleep: + IOAllowPowerChange(_rootPort, (long)messageArgument); + break; + + default: + break; + } + } + + static void serviceInterestCallback(void* refCon, io_service_t service, natural_t messageType, void* messageArgument) { + static_cast(refCon)->onServiceMessage(service, messageType, messageArgument); + } + + io_connect_t _rootPort{ 0 }; + IONotificationPortRef _notifyPortRef{}; + io_object_t _notifierObject{}; +}; + +void PlatformHelper::setup() { + DependencyManager::set(); +} + +#endif + diff --git a/libraries/shared/src/shared/platform/WinHelper.cpp b/libraries/shared/src/shared/platform/WinHelper.cpp new file mode 100644 index 0000000000..3de82af087 --- /dev/null +++ b/libraries/shared/src/shared/platform/WinHelper.cpp @@ -0,0 +1,52 @@ +// +// Created by Bradley Austin Davis on 2019/08/22 +// Copyright 2013-2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "../PlatformHelper.h" + +#if !defined(Q_OS_ANDROID) && defined(Q_OS_WIN) + +#include +#include +#include + +class WinHelper : public PlatformHelper, public QAbstractNativeEventFilter { +public: + WinHelper() { + QAbstractEventDispatcher::instance()->installNativeEventFilter(this); + } + + ~WinHelper() { + auto eventDispatcher = QAbstractEventDispatcher::instance(); + if (eventDispatcher) { + eventDispatcher->removeNativeEventFilter(this); + } + } + + bool nativeEventFilter(const QByteArray& eventType, void* message, long*) override { + MSG* msg = static_cast(message); + if (msg->message == WM_POWERBROADCAST) { + switch (msg->wParam) { + case PBT_APMRESUMEAUTOMATIC: + case PBT_APMRESUMESUSPEND: + onWake(); + break; + + case PBT_APMSUSPEND: + onSleep(); + break; + } + } + return false; + } +}; + +void PlatformHelper::setup() { + DependencyManager::set(); +} + +#endif