//// Application.cpp// interface/src//// Created by Andrzej Kapolka on 5/10/13.// Copyright 2013 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 "Application.h" #include <chrono>#include <thread> #include <glm/glm.hpp>#include <glm/gtx/component_wise.hpp>#include <glm/gtx/quaternion.hpp>#include <glm/gtx/vector_angle.hpp>#include <glm/gtc/type_ptr.hpp> #include <gl/Config.h> #include <QtCore/QResource>#include <QtCore/QAbstractNativeEventFilter>#include <QtCore/QCommandLineParser>#include <QtCore/QMimeData>#include <QtCore/QThreadPool>#include <QtCore/QFileSelector>#include <QtConcurrent/QtConcurrentRun> #include <QtGui/QClipboard>#include <QtGui/QScreen>#include <QtGui/QWindow>#include <QtGui/QDesktopServices> #include <QtNetwork/QLocalSocket>#include <QtNetwork/QLocalServer>#include <QtQml/QQmlContext>#include <QtQml/QQmlEngine>#include <QtQuick/QQuickWindow> #include <QtWidgets/QDesktopWidget>#include <QtWidgets/QMessageBox> #include <QtMultimedia/QMediaPlayer> #include <QFontDatabase>#include <QProcessEnvironment>#include <QTemporaryDir> #include <gl/QOpenGLContextWrapper.h>#include <gl/GLWindow.h>#include <gl/GLHelpers.h> #include <shared/FileUtils.h>#include <shared/QtHelpers.h>#include <shared/GlobalAppProperties.h>#include <StatTracker.h>#include <Trace.h>#include <ResourceScriptingInterface.h>#include <AccountManager.h>#include <AddressManager.h>#include <AnimDebugDraw.h>#include <BuildInfo.h>#include <AnimationCacheScriptingInterface.h>#include <AssetClient.h>#include <AssetUpload.h>#include <AutoUpdater.h>#include <Midi.h>#include <AudioInjectorManager.h>#include <AvatarBookmarks.h>#include <CursorManager.h>#include <VirtualPadManager.h>#include <DebugDraw.h>#include <DeferredLightingEffect.h>#include <EntityScriptClient.h>#include <EntityScriptServerLogClient.h>#include <EntityScriptingInterface.h>#include "ui/overlays/ContextOverlayInterface.h"#include <ErrorDialog.h>#include <FileScriptingInterface.h>#include <Finally.h>#include <FingerprintUtils.h>#include <FramebufferCache.h>#include <gpu/Batch.h>#include <gpu/Context.h>#include <InfoView.h>#include <input-plugins/InputPlugin.h>#include <controllers/UserInputMapper.h>#include <controllers/InputRecorder.h>#include <controllers/ScriptingInterface.h>#include <controllers/StateController.h>#include <UserActivityLoggerScriptingInterface.h>#include <LogHandler.h>#include "LocationBookmarks.h"#include <LocationScriptingInterface.h>#include <MainWindow.h>#include <MappingRequest.h>#include <MessagesClient.h>#include <hfm/ModelFormatRegistry.h>#include <model-networking/ModelCacheScriptingInterface.h>#include <material-networking/TextureCacheScriptingInterface.h>#include <ModelEntityItem.h>#include <NetworkAccessManager.h>#include <NetworkingConstants.h>#include <ObjectMotionState.h>#include <OctalCode.h>#include <OctreeSceneStats.h>#include <OffscreenUi.h>#include <gl/OffscreenGLCanvas.h>#include <ui/OffscreenQmlSurfaceCache.h>#include <PathUtils.h>#include <PerfStat.h>#include <PhysicsEngine.h>#include <PhysicsHelpers.h>#include <plugins/CodecPlugin.h>#include <plugins/PluginManager.h>#include <plugins/PluginUtils.h>#include <plugins/SteamClientPlugin.h>#include <plugins/OculusPlatformPlugin.h>#include <plugins/InputConfiguration.h>#include <RecordingScriptingInterface.h>#include <render/EngineStats.h>#include <SecondaryCamera.h>#include <ResourceCache.h>#include <ResourceRequest.h>#include <SandboxUtils.h>#include <SceneScriptingInterface.h>#include <ScriptEngines.h>#include <ScriptCache.h>#include <ShapeEntityItem.h>#include <SoundCacheScriptingInterface.h>#include <ui/TabletScriptingInterface.h>#include <ui/ToolbarScriptingInterface.h>#include <InteractiveWindow.h>#include <Tooltip.h>#include <udt/PacketHeaders.h>#include <UserActivityLogger.h>#include <UsersScriptingInterface.h>#include <recording/ClipCache.h>#include <recording/Deck.h>#include <recording/Recorder.h>#include <shared/StringHelpers.h>#include <QmlWebWindowClass.h>#include <QmlFragmentClass.h>#include <Preferences.h>#include <display-plugins/CompositorHelper.h>#include <display-plugins/hmd/HmdDisplayPlugin.h>#include <trackers/EyeTracker.h>#include <avatars-renderer/ScriptAvatar.h>#include <RenderableEntityItem.h>#include <RenderableTextEntityItem.h>#include <RenderableWebEntityItem.h>#include <material-networking/MaterialCache.h>#include "recording/ClipCache.h" #include "AudioClient.h"#include "audio/AudioScope.h"#include "avatar/AvatarManager.h"#include "avatar/MyHead.h"#include "avatar/AvatarPackager.h"#include "avatar/MyCharacterController.h"#include "CrashRecoveryHandler.h"#include "CrashHandler.h"#include "devices/DdeFaceTracker.h"#include "DiscoverabilityManager.h"#include "GLCanvas.h"#include "InterfaceDynamicFactory.h"#include "InterfaceLogging.h"#include "LODManager.h"#include "ModelPackager.h"#include "scripting/Audio.h"#include "networking/CloseEventSender.h"#include "scripting/TestScriptingInterface.h"#include "scripting/PlatformInfoScriptingInterface.h"#include "scripting/AssetMappingsScriptingInterface.h"#include "scripting/ClipboardScriptingInterface.h"#include "scripting/DesktopScriptingInterface.h"#include "scripting/AccountServicesScriptingInterface.h"#include "scripting/HMDScriptingInterface.h"#include "scripting/MenuScriptingInterface.h"#include "graphics-scripting/GraphicsScriptingInterface.h"#include "scripting/SettingsScriptingInterface.h"#include "scripting/WindowScriptingInterface.h"#include "scripting/ControllerScriptingInterface.h"#include "scripting/RatesScriptingInterface.h"#include "scripting/SelectionScriptingInterface.h"#include "scripting/WalletScriptingInterface.h"#include "scripting/TTSScriptingInterface.h"#include "scripting/KeyboardScriptingInterface.h" #if defined(Q_OS_MAC) || defined(Q_OS_WIN)#include "SpeechRecognizer.h"#endif#include "ui/ResourceImageItem.h"#include "ui/AddressBarDialog.h"#include "ui/AvatarInputs.h"#include "ui/DialogsManager.h"#include "ui/LoginDialog.h"#include "ui/Snapshot.h"#include "ui/SnapshotAnimated.h"#include "ui/StandAloneJSConsole.h"#include "ui/Stats.h"#include "ui/AnimStats.h"#include "ui/UpdateDialog.h"#include "ui/DomainConnectionModel.h"#include "ui/Keyboard.h"#include "Util.h"#include "InterfaceParentFinder.h"#include "ui/OctreeStatsProvider.h" #include "avatar/GrabManager.h" #include <GPUIdent.h>#include <gl/GLHelpers.h>#include <src/scripting/GooglePolyScriptingInterface.h>#include <EntityScriptClient.h>#include <ModelScriptingInterface.h> #include <PickManager.h>#include <PointerManager.h>#include <raypick/RayPickScriptingInterface.h>#include <raypick/LaserPointerScriptingInterface.h>#include <raypick/PickScriptingInterface.h>#include <raypick/PointerScriptingInterface.h>#include <raypick/RayPick.h>#include <raypick/MouseTransformNode.h> #include <FadeEffect.h> #include "commerce/Ledger.h"#include "commerce/Wallet.h"#include "commerce/QmlCommerce.h"#include "commerce/QmlMarketplace.h"#include "ResourceRequestObserver.h" #include "webbrowser/WebBrowserSuggestionsEngine.h"#include <DesktopPreviewProvider.h> #include "AboutUtil.h" #include <DisableDeferred.h> #if defined(Q_OS_WIN)#include <VersionHelpers.h> #ifdef DEBUG_EVENT_QUEUE// This is a HACK that uses private headers included with the qt source distrubution.// To use this feature you need to add these directores to your include path:// E:/Qt/5.10.1/Src/qtbase/include/QtCore/5.10.1/QtCore// E:/Qt/5.10.1/Src/qtbase/include/QtCore/5.10.1#define QT_BOOTSTRAPPED#include <private/qthread_p.h>#include <private/qobject_p.h>#undef QT_BOOTSTRAPPED#endif // On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU// FIXME seems to be broken.extern "C" { _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;}#endif #if defined(Q_OS_ANDROID)#include <android/log.h>#include "AndroidHelper.h"#endif #include "graphics/RenderEventHandler.h" Q_LOGGING_CATEGORY(trace_app_input_mouse, "trace.app.input.mouse") using namespace std; static QTimer locationUpdateTimer;static QTimer identityPacketTimer;static QTimer pingTimer; #if defined(Q_OS_ANDROID)static bool DISABLE_WATCHDOG = true;#elsestatic const QString DISABLE_WATCHDOG_FLAG{ "HIFI_DISABLE_WATCHDOG" };static bool DISABLE_WATCHDOG = nsightActive() || QProcessEnvironment::systemEnvironment().contains(DISABLE_WATCHDOG_FLAG);#endif #if !defined(Q_OS_ANDROID)static const uint32_t MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16;#elsestatic const uint32_t MAX_CONCURRENT_RESOURCE_DOWNLOADS = 4;#endif // For processing on QThreadPool, we target a number of threads after reserving some// based on how many are being consumed by the application and the display plugin. However,// we will never drop below the 'min' valuestatic const int MIN_PROCESSING_THREAD_POOL_SIZE = 1; static const QString SNAPSHOT_EXTENSION = ".jpg";static const QString JPG_EXTENSION = ".jpg";static const QString PNG_EXTENSION = ".png";static const QString SVO_EXTENSION = ".svo";static const QString SVO_JSON_EXTENSION = ".svo.json";static const QString JSON_GZ_EXTENSION = ".json.gz";static const QString JSON_EXTENSION = ".json";static const QString JS_EXTENSION = ".js";static const QString FST_EXTENSION = ".fst";static const QString FBX_EXTENSION = ".fbx";static const QString OBJ_EXTENSION = ".obj";static const QString AVA_JSON_EXTENSION = ".ava.json";static const QString WEB_VIEW_TAG = "noDownload=true";static const QString ZIP_EXTENSION = ".zip";static const QString CONTENT_ZIP_EXTENSION = ".content.zip"; static const float MIRROR_FULLSCREEN_DISTANCE = 0.789f; static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS_PER_SECOND; static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html";static const QString INFO_HELP_PATH = "html/tabletHelp.html"; static const unsigned int THROTTLED_SIM_FRAMERATE = 15;static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;static const int ENTITY_SERVER_ADDED_TIMEOUT = 5000;static const int ENTITY_SERVER_CONNECTION_TIMEOUT = 5000; static const float INITIAL_QUERY_RADIUS = 10.0f; // priority radius for entities before physics enabled static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); Setting::Handle<int> maxOctreePacketsPerSecond{"maxOctreePPS", DEFAULT_MAX_OCTREE_PPS}; Setting::Handle<bool> loginDialogPoppedUp{"loginDialogPoppedUp", false}; static const QUrl AVATAR_INPUTS_BAR_QML = PathUtils::qmlUrl("AvatarInputsBar.qml");static const QUrl MIC_BAR_APPLICATION_QML = PathUtils::qmlUrl("hifi/audio/MicBarApplication.qml");static const QUrl BUBBLE_ICON_QML = PathUtils::qmlUrl("BubbleIcon.qml"); static const QString STANDARD_TO_ACTION_MAPPING_NAME = "Standard to Action";static const QString NO_MOVEMENT_MAPPING_NAME = "Standard to Action (No Movement)";static const QString NO_MOVEMENT_MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/standard_nomovement.json"; static const QString MARKETPLACE_CDN_HOSTNAME = "mpassets.highfidelity.com";static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // millisecondsstatic const QString DESKTOP_DISPLAY_PLUGIN_NAME = "Desktop";static const QString ACTIVE_DISPLAY_PLUGIN_SETTING_NAME = "activeDisplayPlugin";static const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system";static const QString KEEP_ME_LOGGED_IN_SETTING_NAME = "keepMeLoggedIn"; static const float FOCUS_HIGHLIGHT_EXPANSION_FACTOR = 1.05f; #if defined(Q_OS_ANDROID)static const QString TESTER_FILE = "/sdcard/_hifi_test_device.txt";#endifconst std::vector<std::pair<QString, Application::AcceptURLMethod>> Application::_acceptedExtensions { { SVO_EXTENSION, &Application::importSVOFromURL }, { SVO_JSON_EXTENSION, &Application::importSVOFromURL }, { AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl }, { JSON_EXTENSION, &Application::importJSONFromURL }, { JS_EXTENSION, &Application::askToLoadScript }, { FST_EXTENSION, &Application::askToSetAvatarUrl }, { JSON_GZ_EXTENSION, &Application::askToReplaceDomainContent }, { CONTENT_ZIP_EXTENSION, &Application::askToReplaceDomainContent }, { ZIP_EXTENSION, &Application::importFromZIP }, { JPG_EXTENSION, &Application::importImage }, { PNG_EXTENSION, &Application::importImage }}; class DeadlockWatchdogThread : public QThread {public: static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1; static const unsigned long MAX_HEARTBEAT_AGE_USECS = 120 * USECS_PER_SECOND; // 2 mins with no checkin probably a deadlock static const int WARNING_ELAPSED_HEARTBEAT = 500 * USECS_PER_MSEC; // warn if elapsed heartbeat average is large static const int HEARTBEAT_SAMPLES = 100000; // ~5 seconds worth of samples // Set the heartbeat on launch DeadlockWatchdogThread() { setObjectName("Deadlock Watchdog"); // Give the heartbeat an initial value _heartbeat = usecTimestampNow(); _paused = false; connect(qApp, &QCoreApplication::aboutToQuit, [this] { _quit = true; }); } void setMainThreadID(Qt::HANDLE threadID) { _mainThreadID = threadID; } static void updateHeartbeat() { auto now = usecTimestampNow(); auto elapsed = now - _heartbeat; _movingAverage.addSample(elapsed); _heartbeat = now; } void deadlockDetectionCrash() { setCrashAnnotation("_mod_faulting_tid", std::to_string((uint64_t)_mainThreadID)); setCrashAnnotation("deadlock", "1"); uint32_t* crashTrigger = nullptr; *crashTrigger = 0xDEAD10CC; } static void withPause(const std::function<void()>& lambda) { pause(); lambda(); resume(); } static void pause() { _paused = true; } static void resume() { // Update the heartbeat BEFORE resuming the checks updateHeartbeat(); _paused = false; } void run() override { while (!_quit) { QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS); // Don't do heartbeat detection under nsight if (_paused) { continue; } uint64_t lastHeartbeat = _heartbeat; // sample atomic _heartbeat, because we could context switch away and have it updated on us uint64_t now = usecTimestampNow(); auto lastHeartbeatAge = (now > lastHeartbeat) ? now - lastHeartbeat : 0; auto elapsedMovingAverage = _movingAverage.getAverage(); if (elapsedMovingAverage > _maxElapsedAverage) { qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:" << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage << "maxElapsed:" << _maxElapsed << "PREVIOUS maxElapsedAverage:" << _maxElapsedAverage << "NEW maxElapsedAverage:" << elapsedMovingAverage << "** NEW MAX ELAPSED AVERAGE **" << "samples:" << _movingAverage.getSamples(); _maxElapsedAverage = elapsedMovingAverage; } if (lastHeartbeatAge > _maxElapsed) { qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:" << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage << "PREVIOUS maxElapsed:" << _maxElapsed << "NEW maxElapsed:" << lastHeartbeatAge << "** NEW MAX ELAPSED **" << "maxElapsedAverage:" << _maxElapsedAverage << "samples:" << _movingAverage.getSamples(); _maxElapsed = lastHeartbeatAge; } if (elapsedMovingAverage > WARNING_ELAPSED_HEARTBEAT) { qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:" << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage << "** OVER EXPECTED VALUE **" << "maxElapsed:" << _maxElapsed << "maxElapsedAverage:" << _maxElapsedAverage << "samples:" << _movingAverage.getSamples(); } if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) { qCDebug(interfaceapp_deadlock) << "DEADLOCK DETECTED -- " << "lastHeartbeatAge:" << lastHeartbeatAge << "[ lastHeartbeat :" << lastHeartbeat << "now:" << now << " ]" << "elapsedMovingAverage:" << elapsedMovingAverage << "maxElapsed:" << _maxElapsed << "maxElapsedAverage:" << _maxElapsedAverage << "samples:" << _movingAverage.getSamples(); // Don't actually crash in debug builds, in case this apparent deadlock is simply from // the developer actively debugging code #ifdef NDEBUG deadlockDetectionCrash(); #endif } } } static std::atomic<bool> _paused; static std::atomic<uint64_t> _heartbeat; static std::atomic<uint64_t> _maxElapsed; static std::atomic<int> _maxElapsedAverage; static ThreadSafeMovingAverage<int, HEARTBEAT_SAMPLES> _movingAverage; bool _quit { false }; Qt::HANDLE _mainThreadID = nullptr;}; std::atomic<bool> DeadlockWatchdogThread::_paused;std::atomic<uint64_t> DeadlockWatchdogThread::_heartbeat;std::atomic<uint64_t> DeadlockWatchdogThread::_maxElapsed;std::atomic<int> DeadlockWatchdogThread::_maxElapsedAverage;Lines 1–500 of 9323. Load more
// // Application.cpp // interface/src // // Created by Andrzej Kapolka on 5/10/13. // Copyright 2013 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 "Application.h" #include <chrono> #include <thread> #include <glm/glm.hpp> #include <glm/gtx/component_wise.hpp> #include <glm/gtx/quaternion.hpp> #include <glm/gtx/vector_angle.hpp> #include <glm/gtc/type_ptr.hpp> #include <gl/Config.h> #include <QtCore/QResource> #include <QtCore/QAbstractNativeEventFilter> #include <QtCore/QCommandLineParser> #include <QtCore/QMimeData> #include <QtCore/QThreadPool> #include <QtCore/QFileSelector> #include <QtConcurrent/QtConcurrentRun> #include <QtGui/QClipboard> #include <QtGui/QScreen> #include <QtGui/QWindow> #include <QtGui/QDesktopServices> #include <QtNetwork/QLocalSocket> #include <QtNetwork/QLocalServer> #include <QtQml/QQmlContext> #include <QtQml/QQmlEngine> #include <QtQuick/QQuickWindow> #include <QtWidgets/QDesktopWidget> #include <QtWidgets/QMessageBox> #include <QtMultimedia/QMediaPlayer> #include <QFontDatabase> #include <QProcessEnvironment> #include <QTemporaryDir> #include <gl/QOpenGLContextWrapper.h> #include <gl/GLWindow.h> #include <gl/GLHelpers.h> #include <shared/FileUtils.h> #include <shared/QtHelpers.h> #include <shared/GlobalAppProperties.h> #include <StatTracker.h> #include <Trace.h> #include <ResourceScriptingInterface.h> #include <AccountManager.h> #include <AddressManager.h> #include <AnimDebugDraw.h> #include <BuildInfo.h> #include <AnimationCacheScriptingInterface.h> #include <AssetClient.h> #include <AssetUpload.h> #include <AutoUpdater.h> #include <Midi.h> #include <AudioInjectorManager.h> #include <AvatarBookmarks.h> #include <CursorManager.h> #include <VirtualPadManager.h> #include <DebugDraw.h> #include <DeferredLightingEffect.h> #include <EntityScriptClient.h> #include <EntityScriptServerLogClient.h> #include <EntityScriptingInterface.h> #include "ui/overlays/ContextOverlayInterface.h" #include <ErrorDialog.h> #include <FileScriptingInterface.h> #include <Finally.h> #include <FingerprintUtils.h> #include <FramebufferCache.h> #include <gpu/Batch.h> #include <gpu/Context.h> #include <InfoView.h> #include <input-plugins/InputPlugin.h> #include <controllers/UserInputMapper.h> #include <controllers/InputRecorder.h> #include <controllers/ScriptingInterface.h> #include <controllers/StateController.h> #include <UserActivityLoggerScriptingInterface.h> #include <LogHandler.h> #include "LocationBookmarks.h" #include <LocationScriptingInterface.h> #include <MainWindow.h> #include <MappingRequest.h> #include <MessagesClient.h> #include <hfm/ModelFormatRegistry.h> #include <model-networking/ModelCacheScriptingInterface.h> #include <material-networking/TextureCacheScriptingInterface.h> #include <ModelEntityItem.h> #include <NetworkAccessManager.h> #include <NetworkingConstants.h> #include <ObjectMotionState.h> #include <OctalCode.h> #include <OctreeSceneStats.h> #include <OffscreenUi.h> #include <gl/OffscreenGLCanvas.h> #include <ui/OffscreenQmlSurfaceCache.h> #include <PathUtils.h> #include <PerfStat.h> #include <PhysicsEngine.h> #include <PhysicsHelpers.h> #include <plugins/CodecPlugin.h> #include <plugins/PluginManager.h> #include <plugins/PluginUtils.h> #include <plugins/SteamClientPlugin.h> #include <plugins/OculusPlatformPlugin.h> #include <plugins/InputConfiguration.h> #include <RecordingScriptingInterface.h> #include <render/EngineStats.h> #include <SecondaryCamera.h> #include <ResourceCache.h> #include <ResourceRequest.h> #include <SandboxUtils.h> #include <SceneScriptingInterface.h> #include <ScriptEngines.h> #include <ScriptCache.h> #include <ShapeEntityItem.h> #include <SoundCacheScriptingInterface.h> #include <ui/TabletScriptingInterface.h> #include <ui/ToolbarScriptingInterface.h> #include <InteractiveWindow.h> #include <Tooltip.h> #include <udt/PacketHeaders.h> #include <UserActivityLogger.h> #include <UsersScriptingInterface.h> #include <recording/ClipCache.h> #include <recording/Deck.h> #include <recording/Recorder.h> #include <shared/StringHelpers.h> #include <QmlWebWindowClass.h> #include <QmlFragmentClass.h> #include <Preferences.h> #include <display-plugins/CompositorHelper.h> #include <display-plugins/hmd/HmdDisplayPlugin.h> #include <trackers/EyeTracker.h> #include <avatars-renderer/ScriptAvatar.h> #include <RenderableEntityItem.h> #include <RenderableTextEntityItem.h> #include <RenderableWebEntityItem.h> #include <material-networking/MaterialCache.h> #include "recording/ClipCache.h" #include "AudioClient.h" #include "audio/AudioScope.h" #include "avatar/AvatarManager.h" #include "avatar/MyHead.h" #include "avatar/AvatarPackager.h" #include "avatar/MyCharacterController.h" #include "CrashRecoveryHandler.h" #include "CrashHandler.h" #include "devices/DdeFaceTracker.h" #include "DiscoverabilityManager.h" #include "GLCanvas.h" #include "InterfaceDynamicFactory.h" #include "InterfaceLogging.h" #include "LODManager.h" #include "ModelPackager.h" #include "scripting/Audio.h" #include "networking/CloseEventSender.h" #include "scripting/TestScriptingInterface.h" #include "scripting/PlatformInfoScriptingInterface.h" #include "scripting/AssetMappingsScriptingInterface.h" #include "scripting/ClipboardScriptingInterface.h" #include "scripting/DesktopScriptingInterface.h" #include "scripting/AccountServicesScriptingInterface.h" #include "scripting/HMDScriptingInterface.h" #include "scripting/MenuScriptingInterface.h" #include "graphics-scripting/GraphicsScriptingInterface.h" #include "scripting/SettingsScriptingInterface.h" #include "scripting/WindowScriptingInterface.h" #include "scripting/ControllerScriptingInterface.h" #include "scripting/RatesScriptingInterface.h" #include "scripting/SelectionScriptingInterface.h" #include "scripting/WalletScriptingInterface.h" #include "scripting/TTSScriptingInterface.h" #include "scripting/KeyboardScriptingInterface.h" #if defined(Q_OS_MAC) || defined(Q_OS_WIN) #include "SpeechRecognizer.h" #endif #include "ui/ResourceImageItem.h" #include "ui/AddressBarDialog.h" #include "ui/AvatarInputs.h" #include "ui/DialogsManager.h" #include "ui/LoginDialog.h" #include "ui/Snapshot.h" #include "ui/SnapshotAnimated.h" #include "ui/StandAloneJSConsole.h" #include "ui/Stats.h" #include "ui/AnimStats.h" #include "ui/UpdateDialog.h" #include "ui/DomainConnectionModel.h" #include "ui/Keyboard.h" #include "Util.h" #include "InterfaceParentFinder.h" #include "ui/OctreeStatsProvider.h" #include "avatar/GrabManager.h" #include <GPUIdent.h> #include <gl/GLHelpers.h> #include <src/scripting/GooglePolyScriptingInterface.h> #include <EntityScriptClient.h> #include <ModelScriptingInterface.h> #include <PickManager.h> #include <PointerManager.h> #include <raypick/RayPickScriptingInterface.h> #include <raypick/LaserPointerScriptingInterface.h> #include <raypick/PickScriptingInterface.h> #include <raypick/PointerScriptingInterface.h> #include <raypick/RayPick.h> #include <raypick/MouseTransformNode.h> #include <FadeEffect.h> #include "commerce/Ledger.h" #include "commerce/Wallet.h" #include "commerce/QmlCommerce.h" #include "commerce/QmlMarketplace.h" #include "ResourceRequestObserver.h" #include "webbrowser/WebBrowserSuggestionsEngine.h" #include <DesktopPreviewProvider.h> #include "AboutUtil.h" #include <DisableDeferred.h> #if defined(Q_OS_WIN) #include <VersionHelpers.h> #ifdef DEBUG_EVENT_QUEUE // This is a HACK that uses private headers included with the qt source distrubution. // To use this feature you need to add these directores to your include path: // E:/Qt/5.10.1/Src/qtbase/include/QtCore/5.10.1/QtCore // E:/Qt/5.10.1/Src/qtbase/include/QtCore/5.10.1 #define QT_BOOTSTRAPPED #include <private/qthread_p.h> #include <private/qobject_p.h> #undef QT_BOOTSTRAPPED #endif // On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. extern "C" { _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; } #endif #if defined(Q_OS_ANDROID) #include <android/log.h> #include "AndroidHelper.h" #endif #include "graphics/RenderEventHandler.h" Q_LOGGING_CATEGORY(trace_app_input_mouse, "trace.app.input.mouse") using namespace std; static QTimer locationUpdateTimer; static QTimer identityPacketTimer; static QTimer pingTimer; #if defined(Q_OS_ANDROID) static bool DISABLE_WATCHDOG = true; #else static const QString DISABLE_WATCHDOG_FLAG{ "HIFI_DISABLE_WATCHDOG" }; static bool DISABLE_WATCHDOG = nsightActive() || QProcessEnvironment::systemEnvironment().contains(DISABLE_WATCHDOG_FLAG); #endif #if !defined(Q_OS_ANDROID) static const uint32_t MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16; #else static const uint32_t MAX_CONCURRENT_RESOURCE_DOWNLOADS = 4; #endif // For processing on QThreadPool, we target a number of threads after reserving some // based on how many are being consumed by the application and the display plugin. However, // we will never drop below the 'min' value static const int MIN_PROCESSING_THREAD_POOL_SIZE = 1; static const QString SNAPSHOT_EXTENSION = ".jpg"; static const QString JPG_EXTENSION = ".jpg"; static const QString PNG_EXTENSION = ".png"; static const QString SVO_EXTENSION = ".svo"; static const QString SVO_JSON_EXTENSION = ".svo.json"; static const QString JSON_GZ_EXTENSION = ".json.gz"; static const QString JSON_EXTENSION = ".json"; static const QString JS_EXTENSION = ".js"; static const QString FST_EXTENSION = ".fst"; static const QString FBX_EXTENSION = ".fbx"; static const QString OBJ_EXTENSION = ".obj"; static const QString AVA_JSON_EXTENSION = ".ava.json"; static const QString WEB_VIEW_TAG = "noDownload=true"; static const QString ZIP_EXTENSION = ".zip"; static const QString CONTENT_ZIP_EXTENSION = ".content.zip"; static const float MIRROR_FULLSCREEN_DISTANCE = 0.789f; static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS_PER_SECOND; static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html"; static const QString INFO_HELP_PATH = "html/tabletHelp.html"; static const unsigned int THROTTLED_SIM_FRAMERATE = 15; static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE; static const int ENTITY_SERVER_ADDED_TIMEOUT = 5000; static const int ENTITY_SERVER_CONNECTION_TIMEOUT = 5000; static const float INITIAL_QUERY_RADIUS = 10.0f; // priority radius for entities before physics enabled static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); Setting::Handle<int> maxOctreePacketsPerSecond{"maxOctreePPS", DEFAULT_MAX_OCTREE_PPS}; Setting::Handle<bool> loginDialogPoppedUp{"loginDialogPoppedUp", false}; static const QUrl AVATAR_INPUTS_BAR_QML = PathUtils::qmlUrl("AvatarInputsBar.qml"); static const QUrl MIC_BAR_APPLICATION_QML = PathUtils::qmlUrl("hifi/audio/MicBarApplication.qml"); static const QUrl BUBBLE_ICON_QML = PathUtils::qmlUrl("BubbleIcon.qml"); static const QString STANDARD_TO_ACTION_MAPPING_NAME = "Standard to Action"; static const QString NO_MOVEMENT_MAPPING_NAME = "Standard to Action (No Movement)"; static const QString NO_MOVEMENT_MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/standard_nomovement.json"; static const QString MARKETPLACE_CDN_HOSTNAME = "mpassets.highfidelity.com"; static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // milliseconds static const QString DESKTOP_DISPLAY_PLUGIN_NAME = "Desktop"; static const QString ACTIVE_DISPLAY_PLUGIN_SETTING_NAME = "activeDisplayPlugin"; static const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system"; static const QString KEEP_ME_LOGGED_IN_SETTING_NAME = "keepMeLoggedIn"; static const float FOCUS_HIGHLIGHT_EXPANSION_FACTOR = 1.05f; #if defined(Q_OS_ANDROID) static const QString TESTER_FILE = "/sdcard/_hifi_test_device.txt"; #endif const std::vector<std::pair<QString, Application::AcceptURLMethod>> Application::_acceptedExtensions { { SVO_EXTENSION, &Application::importSVOFromURL }, { SVO_JSON_EXTENSION, &Application::importSVOFromURL }, { AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl }, { JSON_EXTENSION, &Application::importJSONFromURL }, { JS_EXTENSION, &Application::askToLoadScript }, { FST_EXTENSION, &Application::askToSetAvatarUrl }, { JSON_GZ_EXTENSION, &Application::askToReplaceDomainContent }, { CONTENT_ZIP_EXTENSION, &Application::askToReplaceDomainContent }, { ZIP_EXTENSION, &Application::importFromZIP }, { JPG_EXTENSION, &Application::importImage }, { PNG_EXTENSION, &Application::importImage } }; class DeadlockWatchdogThread : public QThread { public: static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1; static const unsigned long MAX_HEARTBEAT_AGE_USECS = 120 * USECS_PER_SECOND; // 2 mins with no checkin probably a deadlock static const int WARNING_ELAPSED_HEARTBEAT = 500 * USECS_PER_MSEC; // warn if elapsed heartbeat average is large static const int HEARTBEAT_SAMPLES = 100000; // ~5 seconds worth of samples // Set the heartbeat on launch DeadlockWatchdogThread() { setObjectName("Deadlock Watchdog"); // Give the heartbeat an initial value _heartbeat = usecTimestampNow(); _paused = false; connect(qApp, &QCoreApplication::aboutToQuit, [this] { _quit = true; }); } void setMainThreadID(Qt::HANDLE threadID) { _mainThreadID = threadID; } static void updateHeartbeat() { auto now = usecTimestampNow(); auto elapsed = now - _heartbeat; _movingAverage.addSample(elapsed); _heartbeat = now; } void deadlockDetectionCrash() { setCrashAnnotation("_mod_faulting_tid", std::to_string((uint64_t)_mainThreadID)); setCrashAnnotation("deadlock", "1"); uint32_t* crashTrigger = nullptr; *crashTrigger = 0xDEAD10CC; } static void withPause(const std::function<void()>& lambda) { pause(); lambda(); resume(); } static void pause() { _paused = true; } static void resume() { // Update the heartbeat BEFORE resuming the checks updateHeartbeat(); _paused = false; } void run() override { while (!_quit) { QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS); // Don't do heartbeat detection under nsight if (_paused) { continue; } uint64_t lastHeartbeat = _heartbeat; // sample atomic _heartbeat, because we could context switch away and have it updated on us uint64_t now = usecTimestampNow(); auto lastHeartbeatAge = (now > lastHeartbeat) ? now - lastHeartbeat : 0; auto elapsedMovingAverage = _movingAverage.getAverage(); if (elapsedMovingAverage > _maxElapsedAverage) { qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:" << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage << "maxElapsed:" << _maxElapsed << "PREVIOUS maxElapsedAverage:" << _maxElapsedAverage << "NEW maxElapsedAverage:" << elapsedMovingAverage << "** NEW MAX ELAPSED AVERAGE **" << "samples:" << _movingAverage.getSamples(); _maxElapsedAverage = elapsedMovingAverage; } if (lastHeartbeatAge > _maxElapsed) { qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:" << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage << "PREVIOUS maxElapsed:" << _maxElapsed << "NEW maxElapsed:" << lastHeartbeatAge << "** NEW MAX ELAPSED **" << "maxElapsedAverage:" << _maxElapsedAverage << "samples:" << _movingAverage.getSamples(); _maxElapsed = lastHeartbeatAge; } if (elapsedMovingAverage > WARNING_ELAPSED_HEARTBEAT) { qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:" << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage << "** OVER EXPECTED VALUE **" << "maxElapsed:" << _maxElapsed << "maxElapsedAverage:" << _maxElapsedAverage << "samples:" << _movingAverage.getSamples(); } if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) { qCDebug(interfaceapp_deadlock) << "DEADLOCK DETECTED -- " << "lastHeartbeatAge:" << lastHeartbeatAge << "[ lastHeartbeat :" << lastHeartbeat << "now:" << now << " ]" << "elapsedMovingAverage:" << elapsedMovingAverage << "maxElapsed:" << _maxElapsed << "maxElapsedAverage:" << _maxElapsedAverage << "samples:" << _movingAverage.getSamples(); // Don't actually crash in debug builds, in case this apparent deadlock is simply from // the developer actively debugging code #ifdef NDEBUG deadlockDetectionCrash(); #endif } } } static std::atomic<bool> _paused; static std::atomic<uint64_t> _heartbeat; static std::atomic<uint64_t> _maxElapsed; static std::atomic<int> _maxElapsedAverage; static ThreadSafeMovingAverage<int, HEARTBEAT_SAMPLES> _movingAverage; bool _quit { false }; Qt::HANDLE _mainThreadID = nullptr; }; std::atomic<bool> DeadlockWatchdogThread::_paused; std::atomic<uint64_t> DeadlockWatchdogThread::_heartbeat; std::atomic<uint64_t> DeadlockWatchdogThread::_maxElapsed; std::atomic<int> DeadlockWatchdogThread::_maxElapsedAverage;