diff options
Diffstat (limited to 'indra/newview/llappviewer.cpp')
-rw-r--r-- | indra/newview/llappviewer.cpp | 621 |
1 files changed, 530 insertions, 91 deletions
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index ba14c248aa..e92042bcd4 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -30,6 +30,7 @@ // Viewer includes #include "llversioninfo.h" +#include "llversionviewer.h" #include "llfeaturemanager.h" #include "lluictrlfactory.h" #include "lltexteditor.h" @@ -79,9 +80,12 @@ #include "llfeaturemanager.h" #include "llurlmatch.h" #include "lltextutil.h" +#include "lllogininstance.h" +#include "llprogressview.h" #include "llweb.h" #include "llsecondlifeurls.h" +#include "llupdaterservice.h" // Linden library includes #include "llavatarnamecache.h" @@ -190,11 +194,14 @@ #include "llparcel.h" #include "llavatariconctrl.h" #include "llgroupiconctrl.h" +#include "llviewerassetstats.h" // Include for security api initialization #include "llsecapi.h" #include "llmachineid.h" +#include "llmainlooprepeater.h" + // *FIX: These extern globals should be cleaned up. // The globals either represent state/config/resource-storage of either // this app, or another 'component' of the viewer. App globals should be @@ -332,6 +339,14 @@ static std::string gWindowTitle; LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ; +//---------------------------------------------------------------------------- +// Metrics logging control constants +//---------------------------------------------------------------------------- +static const F32 METRICS_INTERVAL_DEFAULT = 600.0; +static const F32 METRICS_INTERVAL_QA = 30.0; +static F32 app_metrics_interval = METRICS_INTERVAL_DEFAULT; +static bool app_metrics_qa_mode = false; + void idle_afk_check() { // check idle timers @@ -501,6 +516,9 @@ static void settings_modify() gSavedSettings.setBOOL("VectorizeEnable", FALSE ); gSavedSettings.setU32("VectorizeProcessor", 0 ); gSavedSettings.setBOOL("VectorizeSkin", FALSE); + + // disable fullscreen mode, unsupported + gSavedSettings.setBOOL("WindowFullScreen", FALSE); #endif } @@ -509,16 +527,10 @@ class LLFastTimerLogThread : public LLThread public: std::string mFile; - LLFastTimerLogThread() : LLThread("fast timer log") + LLFastTimerLogThread(std::string& test_name) : LLThread("fast timer log") { - if(LLFastTimer::sLog) - { - mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance.slp"); - } - if(LLFastTimer::sMetricLog) - { - mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric.slp"); - } + std::string file_name = test_name + std::string(".slp"); + mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name); } void run() @@ -534,6 +546,7 @@ public: os.close(); } + }; //virtual @@ -580,7 +593,8 @@ LLAppViewer::LLAppViewer() : mAgentRegionLastAlive(false), mRandomizeFramerate(LLCachedControl<bool>(gSavedSettings,"Randomize Framerate", FALSE)), mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)), - mFastTimerLogThread(NULL) + mFastTimerLogThread(NULL), + mUpdater(new LLUpdaterService()) { if(NULL != sInstance) { @@ -590,10 +604,14 @@ LLAppViewer::LLAppViewer() : setupErrorHandling(); sInstance = this; gLoggedInTime.stop(); + + LLLoginInstance::instance().setUpdaterService(mUpdater.get()); } LLAppViewer::~LLAppViewer() { + LLLoginInstance::instance().setUpdaterService(0); + destroyMainloopTimeout(); // If we got to this destructor somehow, the app didn't hang. @@ -652,14 +670,32 @@ bool LLAppViewer::init() // Called before threads are created. LLCurl::initClass(); LLMachineID::init(); + + { + // Viewer metrics initialization + static LLCachedControl<bool> metrics_submode(gSavedSettings, + "QAModeMetrics", + false, + "Enables QA features (logging, faster cycling) for metrics collector"); + + if (metrics_submode) + { + app_metrics_qa_mode = true; + app_metrics_interval = METRICS_INTERVAL_QA; + } + LLViewerAssetStatsFF::init(); + } initThreads(); writeSystemInfo(); - // Build a string representing the current version number. - gCurrentVersion = llformat("%s %s", - gSavedSettings.getString("VersionChannelName").c_str(), - LLVersionInfo::getVersion().c_str()); + // Initialize updater service (now that we have an io pump) + initUpdater(); + if(isQuitting()) + { + // Early out here because updater set the quitting flag. + return true; + } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -803,6 +839,9 @@ bool LLAppViewer::init() return 1; } + // Initialize the repeater service. + LLMainLoopRepeater::instance().start(); + // // Initialize the window // @@ -817,16 +856,22 @@ bool LLAppViewer::init() gGLManager.getGLInfo(gDebugInfo); gGLManager.printGLInfoString(); - //load key settings - bind_keyboard_functions(); - // Load Default bindings - if (!gViewerKeyboard.loadBindings(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"keys.ini"))) + std::string key_bindings_file = gDirUtilp->findFile("keys.xml", + gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""), + gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + + + if (!gViewerKeyboard.loadBindingsXML(key_bindings_file)) { - LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL; + std::string key_bindings_file = gDirUtilp->findFile("keys.ini", + gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""), + gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + if (!gViewerKeyboard.loadBindings(key_bindings_file)) + { + LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL; + } } - // Load Custom bindings (override defaults) - gViewerKeyboard.loadBindings(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"custom_keys.ini")); // If we don't have the right GL requirements, exit. if (!gGLManager.mHasRequirements && !gNoRender) @@ -899,7 +944,8 @@ bool LLAppViewer::init() gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString(); // Save the current version to the prefs file - gSavedSettings.setString("LastRunVersion", gCurrentVersion); + gSavedSettings.setString("LastRunVersion", + LLVersionInfo::getChannelAndVersion()); gSimLastTime = gRenderStartTime.getElapsedTimeF32(); gSimFrames = (F32)gFrameCount; @@ -974,13 +1020,14 @@ bool LLAppViewer::mainLoop() gServicePump = new LLPumpIO(gAPRPoolp); LLHTTPClient::setPump(*gServicePump); LLCurl::setCAFile(gDirUtilp->getCAFile()); - + // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated. LLVoiceChannel::initClass(); LLVoiceClient::getInstance()->init(gServicePump); LLTimer frameTimer,idleTimer; LLTimer debugTime; + LLFrameTimer memCheckTimer; LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); joystick->setNeedsReset(true); @@ -991,11 +1038,29 @@ bool LLAppViewer::mainLoop() // point of posting. LLSD newFrame; + const F32 memory_check_interval = 1.0f ; //second + // Handle messages while (!LLApp::isExiting()) { LLFastTimer::nextFrame(); // Should be outside of any timer instances + //clear call stack records + llclearcallstacks; + + //check memory availability information + { + if(memory_check_interval < memCheckTimer.getElapsedTimeF32()) + { + memCheckTimer.reset() ; + + //update the availability of memory + LLMemoryInfo::getAvailableMemoryKB(mAvailPhysicalMemInKB, mAvailVirtualMemInKB) ; + } + llcallstacks << "Available physical mem(KB): " << mAvailPhysicalMemInKB << llcallstacksendl ; + llcallstacks << "Available virtual mem(KB): " << mAvailVirtualMemInKB << llcallstacksendl ; + } + try { pingMainloopTimeout("Main:MiscNativeWindowEvents"); @@ -1222,11 +1287,20 @@ bool LLAppViewer::mainLoop() resumeMainloopTimeout(); pingMainloopTimeout("Main:End"); - } - + } } catch(std::bad_alloc) { + { + llinfos << "Availabe physical memory(KB) at the beginning of the frame: " << mAvailPhysicalMemInKB << llendl ; + llinfos << "Availabe virtual memory(KB) at the beginning of the frame: " << mAvailVirtualMemInKB << llendl ; + + LLMemoryInfo::getAvailableMemoryKB(mAvailPhysicalMemInKB, mAvailVirtualMemInKB) ; + + llinfos << "Current availabe physical memory(KB): " << mAvailPhysicalMemInKB << llendl ; + llinfos << "Current availabe virtual memory(KB): " << mAvailVirtualMemInKB << llendl ; + } + //stop memory leaking simulation LLFloaterMemLeak* mem_leak_instance = LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking"); @@ -1275,6 +1349,21 @@ bool LLAppViewer::mainLoop() return true; } +void LLAppViewer::flushVFSIO() +{ + while (1) + { + S32 pending = LLVFSThread::updateClass(0); + pending += LLLFSThread::updateClass(0); + if (!pending) + { + break; + } + llinfos << "Waiting for pending IO to finish: " << pending << llendflush; + ms_sleep(100); + } +} + bool LLAppViewer::cleanup() { // workaround for DEV-35406 crash on shutdown @@ -1329,11 +1418,14 @@ bool LLAppViewer::cleanup() llinfos << "Cleaning Up" << llendflush; // Must clean up texture references before viewer window is destroyed. - LLHUDManager::getInstance()->updateEffects(); - LLHUDObject::updateAll(); - LLHUDManager::getInstance()->cleanupEffects(); - LLHUDObject::cleanupHUDObjects(); - llinfos << "HUD Objects cleaned up" << llendflush; + if(LLHUDManager::instanceExists()) + { + LLHUDManager::getInstance()->updateEffects(); + LLHUDObject::updateAll(); + LLHUDManager::getInstance()->cleanupEffects(); + LLHUDObject::cleanupHUDObjects(); + llinfos << "HUD Objects cleaned up" << llendflush; + } LLKeyframeDataCache::clear(); @@ -1345,8 +1437,10 @@ bool LLAppViewer::cleanup() // Note: this is where gWorldMap used to be deleted. // Note: this is where gHUDManager used to be deleted. - LLHUDManager::getInstance()->shutdownClass(); - + if(LLHUDManager::instanceExists()) + { + LLHUDManager::getInstance()->shutdownClass(); + } delete gAssetStorage; gAssetStorage = NULL; @@ -1409,17 +1503,7 @@ bool LLAppViewer::cleanup() llinfos << "Cache files removed" << llendflush; // Wait for any pending VFS IO - while (1) - { - S32 pending = LLVFSThread::updateClass(0); - pending += LLLFSThread::updateClass(0); - if (!pending) - { - break; - } - llinfos << "Waiting for pending IO to finish: " << pending << llendflush; - ms_sleep(100); - } + flushVFSIO(); llinfos << "Shutting down Views" << llendflush; // Destroy the UI @@ -1614,22 +1698,16 @@ bool LLAppViewer::cleanup() { llinfos << "Analyzing performance" << llendl; - if(LLFastTimer::sLog) - { - LLFastTimerView::doAnalysis( - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance_baseline.slp"), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance.slp"), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance_report.csv")); - } - if(LLFastTimer::sMetricLog) - { - LLFastTimerView::doAnalysis( - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric_baseline.slp"), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric.slp"), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric_report.csv")); - } + std::string baseline_name = LLFastTimer::sLogName + "_baseline.slp"; + std::string current_name = LLFastTimer::sLogName + ".slp"; + std::string report_name = LLFastTimer::sLogName + "_report.csv"; + + LLFastTimerView::doAnalysis( + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name), + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, current_name), + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, report_name)); } - LLMetricPerformanceTester::cleanClass() ; + LLMetricPerformanceTesterBasic::cleanClass() ; llinfos << "Cleaning up Media and Textures" << llendflush; @@ -1648,7 +1726,10 @@ bool LLAppViewer::cleanup() #ifndef LL_RELEASE_FOR_DOWNLOAD llinfos << "Auditing VFS" << llendl; - gVFS->audit(); + if(gVFS) + { + gVFS->audit(); + } #endif llinfos << "Misc Cleanup" << llendflush; @@ -1666,6 +1747,8 @@ bool LLAppViewer::cleanup() LLWatchdog::getInstance()->cleanup(); + LLViewerAssetStatsFF::cleanup(); + llinfos << "Shutting down message system" << llendflush; end_messaging_system(); @@ -1689,6 +1772,8 @@ bool LLAppViewer::cleanup() llinfos << "File launched." << llendflush; } + LLMainLoopRepeater::instance().stop(); + ll_close_fail_log(); llinfos << "Goodbye!" << llendflush; @@ -1730,13 +1815,16 @@ bool LLAppViewer::initThreads() // Image decoding LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true); LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true); - LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), sImageDecodeThread, enable_threads && true); + LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), + sImageDecodeThread, + enable_threads && true, + app_metrics_qa_mode); LLImage::initClass(); if (LLFastTimer::sLog || LLFastTimer::sMetricLog) { LLFastTimer::sLogLock = new LLMutex(NULL); - mFastTimerLogThread = new LLFastTimerLogThread(); + mFastTimerLogThread = new LLFastTimerLogThread(LLFastTimer::sLogName); mFastTimerLogThread->start(); } @@ -1935,8 +2023,6 @@ bool LLAppViewer::initConfiguration() gSavedSettings.setString("ClientSettingsFile", gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global"))); - gSavedSettings.setString("VersionChannelName", LLVersionInfo::getChannel()); - #ifndef LL_RELEASE_FOR_DOWNLOAD // provide developer build only overrides for these control variables that are not // persisted to settings.xml @@ -2019,6 +2105,15 @@ bool LLAppViewer::initConfiguration() // - apply command line settings clp.notify(); + // Register the core crash option as soon as we can + // if we want gdb post-mortem on cores we need to be up and running + // ASAP or we might miss init issue etc. + if(clp.hasOption("disablecrashlogger")) + { + llwarns << "Crashes will be handled by system, stack trace logs and crash logger are both disabled" << llendl; + LLAppViewer::instance()->disableCrashlogger(); + } + // Handle initialization from settings. // Start up the debugging console before handling other options. if (gSavedSettings.getBOOL("ShowConsoleWindow")) @@ -2068,6 +2163,11 @@ bool LLAppViewer::initConfiguration() } } + if(clp.hasOption("channel")) + { + LLVersionInfo::resetChannel(clp.getOption("channel")[0]); + } + // If we have specified crash on startup, set the global so we'll trigger the crash at the right time if(clp.hasOption("crashonstartup")) @@ -2078,11 +2178,25 @@ bool LLAppViewer::initConfiguration() if (clp.hasOption("logperformance")) { LLFastTimer::sLog = TRUE; + LLFastTimer::sLogName = std::string("performance"); } - if(clp.hasOption("logmetrics")) + if (clp.hasOption("logmetrics")) { LLFastTimer::sMetricLog = TRUE ; + // '--logmetrics' can be specified with a named test metric argument so the data gathering is done only on that test + // In the absence of argument, every metric is gathered (makes for a rather slow run and hard to decipher report...) + std::string test_name = clp.getOption("logmetrics")[0]; + llinfos << "'--logmetrics' argument : " << test_name << llendl; + if (test_name == "") + { + llwarns << "No '--logmetrics' argument given, will output all metrics to " << DEFAULT_METRIC_NAME << llendl; + LLFastTimer::sLogName = DEFAULT_METRIC_NAME; + } + else + { + LLFastTimer::sLogName = test_name; + } } if (clp.hasOption("graphicslevel")) @@ -2131,7 +2245,7 @@ bool LLAppViewer::initConfiguration() if (clp.hasOption("nonotifications")) { - gSavedSettings.setBOOL("IgnoreAllNotifications", TRUE); + gSavedSettings.getControl("IgnoreAllNotifications")->setValue(true, false); } if (clp.hasOption("debugsession")) @@ -2178,8 +2292,8 @@ bool LLAppViewer::initConfiguration() if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString()) { // hack to force the skin to default. - //gDirUtilp->setSkinFolder(skinfolder->getValue().asString()); - gDirUtilp->setSkinFolder("default"); + gDirUtilp->setSkinFolder(skinfolder->getValue().asString()); + //gDirUtilp->setSkinFolder("default"); } mYieldTime = gSavedSettings.getS32("YieldTime"); @@ -2323,6 +2437,155 @@ bool LLAppViewer::initConfiguration() return true; // Config was successful. } +namespace { + // *TODO - decide if there's a better place for these functions. + // do we need a file llupdaterui.cpp or something? -brad + + void apply_update_callback(LLSD const & notification, LLSD const & response) + { + lldebugs << "LLUpdate user response: " << response << llendl; + if(response["OK_okcancelbuttons"].asBoolean()) + { + llinfos << "LLUpdate restarting viewer" << llendl; + static const bool install_if_ready = true; + // *HACK - this lets us launch the installer immediately for now + LLUpdaterService().startChecking(install_if_ready); + } + } + + void apply_update_ok_callback(LLSD const & notification, LLSD const & response) + { + llinfos << "LLUpdate restarting viewer" << llendl; + static const bool install_if_ready = true; + // *HACK - this lets us launch the installer immediately for now + LLUpdaterService().startChecking(install_if_ready); + } + + void on_update_downloaded(LLSD const & data) + { + std::string notification_name; + void (*apply_callback)(LLSD const &, LLSD const &) = NULL; + + if(data["required"].asBoolean()) + { + apply_callback = &apply_update_ok_callback; + if(LLStartUp::getStartupState() <= STATE_LOGIN_WAIT) + { + // The user never saw the progress bar. + notification_name = "RequiredUpdateDownloadedVerboseDialog"; + } + else + { + notification_name = "RequiredUpdateDownloadedDialog"; + } + } + else + { + apply_callback = &apply_update_callback; + if(LLStartUp::getStartupState() < STATE_STARTED) + { + // CHOP-262 we need to use a different notification + // method prior to login. + notification_name = "DownloadBackgroundDialog"; + } + else + { + notification_name = "DownloadBackgroundTip"; + } + } + + LLSD substitutions; + substitutions["VERSION"] = data["version"]; + + // truncate version at the rightmost '.' + std::string version_short(data["version"]); + size_t short_length = version_short.rfind('.'); + if (short_length != std::string::npos) + { + version_short.resize(short_length); + } + + LLUIString relnotes_url("[RELEASE_NOTES_BASE_URL][CHANNEL_URL]/[VERSION_SHORT]"); + relnotes_url.setArg("[VERSION_SHORT]", version_short); + + // *TODO thread the update service's response through to this point + std::string const & channel = LLVersionInfo::getChannel(); + boost::shared_ptr<char> channel_escaped(curl_escape(channel.c_str(), channel.size()), &curl_free); + + relnotes_url.setArg("[CHANNEL_URL]", channel_escaped.get()); + relnotes_url.setArg("[RELEASE_NOTES_BASE_URL]", LLTrans::getString("RELEASE_NOTES_BASE_URL")); + substitutions["RELEASE_NOTES_FULL_URL"] = relnotes_url.getString(); + + LLNotificationsUtil::add(notification_name, substitutions, LLSD(), apply_callback); + } + + void install_error_callback(LLSD const & notification, LLSD const & response) + { + LLAppViewer::instance()->forceQuit(); + } + + bool notify_update(LLSD const & evt) + { + std::string notification_name; + switch (evt["type"].asInteger()) + { + case LLUpdaterService::DOWNLOAD_COMPLETE: + on_update_downloaded(evt); + break; + case LLUpdaterService::INSTALL_ERROR: + if(evt["required"].asBoolean()) { + LLNotificationsUtil::add("FailedRequiredUpdateInstall", LLSD(), LLSD(), &install_error_callback); + } else { + LLNotificationsUtil::add("FailedUpdateInstall"); + } + break; + default: + break; + } + + // let others also handle this event by default + return false; + } + + bool on_bandwidth_throttle(LLUpdaterService * updater, LLSD const & evt) + { + updater->setBandwidthLimit(evt.asInteger() * (1024/8)); + return false; // Let others receive this event. + }; +}; + +void LLAppViewer::initUpdater() +{ + // Initialize the updater service. + // Generate URL to the udpater service + // Get Channel + // Get Version + std::string url = gSavedSettings.getString("UpdaterServiceURL"); + std::string channel = LLVersionInfo::getChannel(); + std::string version = LLVersionInfo::getVersion(); + std::string protocol_version = gSavedSettings.getString("UpdaterServiceProtocolVersion"); + std::string service_path = gSavedSettings.getString("UpdaterServicePath"); + U32 check_period = gSavedSettings.getU32("UpdaterServiceCheckPeriod"); + + mUpdater->setAppExitCallback(boost::bind(&LLAppViewer::forceQuit, this)); + mUpdater->initialize(protocol_version, + url, + service_path, + channel, + version); + mUpdater->setCheckPeriod(check_period); + mUpdater->setBandwidthLimit((int)gSavedSettings.getF32("UpdaterMaximumBandwidth") * (1024/8)); + gSavedSettings.getControl("UpdaterMaximumBandwidth")->getSignal()-> + connect(boost::bind(&on_bandwidth_throttle, mUpdater.get(), _2)); + if(gSavedSettings.getU32("UpdaterServiceSetting")) + { + bool install_if_ready = true; + mUpdater->startChecking(install_if_ready); + } + + LLEventPump & updater_pump = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()); + updater_pump.listen("notify_update", ¬ify_update); +} void LLAppViewer::checkForCrash(void) { @@ -2382,7 +2645,7 @@ bool LLAppViewer::initWindow() VIEWER_WINDOW_CLASSNAME, gSavedSettings.getS32("WindowX"), gSavedSettings.getS32("WindowY"), gSavedSettings.getS32("WindowWidth"), gSavedSettings.getS32("WindowHeight"), - FALSE, ignorePixelDepth); + gSavedSettings.getBOOL("WindowFullScreen"), ignorePixelDepth); // Need to load feature table before cheking to start watchdog. const S32 NEVER_SUBMIT_REPORT = 2; @@ -2483,15 +2746,18 @@ void LLAppViewer::cleanupSavedSettings() // save window position if not maximized // as we don't track it in callbacks - BOOL maximized = gViewerWindow->mWindow->getMaximized(); - if (!maximized) + if(NULL != gViewerWindow) { - LLCoordScreen window_pos; - - if (gViewerWindow->mWindow->getPosition(&window_pos)) + BOOL maximized = gViewerWindow->mWindow->getMaximized(); + if (!maximized) { - gSavedSettings.setS32("WindowX", window_pos.mX); - gSavedSettings.setS32("WindowY", window_pos.mY); + LLCoordScreen window_pos; + + if (gViewerWindow->mWindow->getPosition(&window_pos)) + { + gSavedSettings.setS32("WindowX", window_pos.mX); + gSavedSettings.setS32("WindowY", window_pos.mY); + } } } @@ -2514,7 +2780,7 @@ void LLAppViewer::writeSystemInfo() { gDebugInfo["SLLog"] = LLError::logFileName(); - gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName"); + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel(); gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor(); gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor(); gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch(); @@ -2595,6 +2861,11 @@ void LLAppViewer::handleViewerCrash() abort(); } + if (LLApp::isCrashloggerDisabled()) + { + abort(); + } + // Returns whether a dialog was shown. // Only do the logic in here once if (pApp->mReportedCrash) @@ -2612,7 +2883,7 @@ void LLAppViewer::handleViewerCrash() //We already do this in writeSystemInfo(), but we do it again here to make /sure/ we have a version //to check against no matter what - gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName"); + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel(); gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor(); gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor(); @@ -2733,8 +3004,10 @@ void LLAppViewer::handleViewerCrash() pApp->removeMarkerFile(false); } +#if LL_SEND_CRASH_REPORTS // Call to pure virtual, handled by platform specific llappviewer instance. pApp->handleCrashReporting(); +#endif return; } @@ -2869,6 +3142,23 @@ void LLAppViewer::forceQuit() LLApp::setQuitting(); } +//TODO: remove +void LLAppViewer::fastQuit(S32 error_code) +{ + // finish pending transfers + flushVFSIO(); + // let sim know we're logging out + sendLogoutRequest(); + // flush network buffers by shutting down messaging system + end_messaging_system(); + // figure out the error code + S32 final_error_code = error_code ? error_code : (S32)isError(); + // this isn't a crash + removeMarkerFile(); + // get outta here + _exit(final_error_code); +} + void LLAppViewer::requestQuit() { llinfos << "requestQuit" << llendl; @@ -2877,11 +3167,21 @@ void LLAppViewer::requestQuit() if( (LLStartUp::getStartupState() < STATE_STARTED) || !region ) { + // If we have a region, make some attempt to send a logout request first. + // This prevents the halfway-logged-in avatar from hanging around inworld for a couple minutes. + if(region) + { + sendLogoutRequest(); + } + // Quit immediately forceQuit(); return; } + // Try to send metrics back to the grid + metricsSend(!gDisconnected); + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); effectp->setPositionGlobal(gAgent.getPositionGlobal()); effectp->setColor(LLColor4U(gAgent.getEffectColor())); @@ -2918,7 +3218,7 @@ static LLNotificationFunctorRegistration finish_quit_reg("ConfirmQuit", finish_q void LLAppViewer::userQuit() { - if (gDisconnected) + if (gDisconnected || gViewerWindow->getProgressView()->getVisible()) { requestQuit(); } @@ -2941,12 +3241,12 @@ void LLAppViewer::earlyExit(const std::string& name, const LLSD& substitutions) LLNotificationsUtil::add(name, substitutions, LLSD(), finish_early_exit); } -void LLAppViewer::forceExit(S32 arg) +// case where we need the viewer to exit without any need for notifications +void LLAppViewer::earlyExitNoNotify() { - removeMarkerFile(); - - // *FIX:Mani - This kind of exit hardly seems appropriate. - exit(arg); + llwarns << "app_early_exit with no notification: " << llendl; + gDoDisconnect = TRUE; + finish_early_exit( LLSD(), LLSD() ); } void LLAppViewer::abortQuit() @@ -2990,7 +3290,7 @@ void LLAppViewer::migrateCacheDirectory() S32 file_count = 0; std::string file_name; std::string mask = delimiter + "*.*"; - while (gDirUtilp->getNextFileInDir(old_cache_dir, mask, file_name, false)) + while (gDirUtilp->getNextFileInDir(old_cache_dir, mask, file_name)) { if (file_name == "." || file_name == "..") continue; std::string source_path = old_cache_dir + delimiter + file_name; @@ -3209,7 +3509,7 @@ bool LLAppViewer::initCache() dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""); std::string found_file; - if (gDirUtilp->getNextFileInDir(dir, mask, found_file, false)) + if (gDirUtilp->getNextFileInDir(dir, mask, found_file)) { old_vfs_data_file = dir + gDirUtilp->getDirDelimiter() + found_file; @@ -3434,6 +3734,7 @@ void LLAppViewer::loadNameCache() // display names cache std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); + LL_INFOS("AvNameCache") << filename << LL_ENDL; llifstream name_cache_stream(filename); if(name_cache_stream.is_open()) { @@ -3542,6 +3843,18 @@ void LLAppViewer::idle() } } + // debug setting to quit after N seconds of being AFK - 0 to never do this + F32 qas_afk = gSavedSettings.getF32("QuitAfterSecondsOfAFK"); + if (qas_afk > 0.f) + { + // idle time is more than setting + if ( gAwayTriggerTimer.getElapsedTimeF32() > qas_afk ) + { + // go ahead and just quit gracefully + LLAppViewer::instance()->requestQuit(); + } + } + // Must wait until both have avatar object and mute list, so poll // here. request_initial_instant_messages(); @@ -3647,6 +3960,11 @@ void LLAppViewer::idle() llinfos << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << llendl; gObjectList.mNumUnknownUpdates = 0; } + + // ViewerMetrics FPS piggy-backing on the debug timer. + // The 5-second interval is nice for this purpose. If the object debug + // bit moves or is disabled, please give this a suitable home. + LLViewerAssetStatsFF::record_fps_main(gFPSClamped); } } @@ -3689,6 +4007,18 @@ void LLAppViewer::idle() gInventory.idleNotifyObservers(); } + // Metrics logging (LLViewerAssetStats, etc.) + { + static LLTimer report_interval; + + // *TODO: Add configuration controls for this + if (report_interval.getElapsedTimeF32() >= app_metrics_interval) + { + metricsSend(! gDisconnected); + report_interval.reset(); + } + } + if (gDisconnected) { return; @@ -3978,7 +4308,10 @@ void LLAppViewer::sendLogoutRequest() gLogoutMaxTime = LOGOUT_REQUEST_TIME; mLogoutRequestSent = TRUE; - LLVoiceClient::getInstance()->leaveChannel(); + if(LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->leaveChannel(); + } //Set internal status variables and marker files gLogoutInProgress = TRUE; @@ -4225,7 +4558,10 @@ void LLAppViewer::disconnectViewer() // This is where we used to call gObjectList.destroy() and then delete gWorldp. // Now we just ask the LLWorld singleton to cleanly shut down. - LLWorld::getInstance()->destroyClass(); + if(LLWorld::instanceExists()) + { + LLWorld::getInstance()->destroyClass(); + } // call all self-registered classes LLDestroyClassList::instance().fireCallbacks(); @@ -4339,7 +4675,7 @@ void LLAppViewer::handleLoginComplete() initMainloopTimeout("Mainloop Init"); // Store some data to DebugInfo in case of a freeze. - gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName"); + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel(); gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor(); gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor(); @@ -4399,6 +4735,35 @@ void LLAppViewer::loadEventHostModule(S32 listen_port) return; } + LL_INFOS("eventhost") << "Found lleventhost at '" << dso_path << "'" << LL_ENDL; +#if ! defined(LL_WINDOWS) + { + std::string outfile("/tmp/lleventhost.file.out"); + std::string command("file '" + dso_path + "' > '" + outfile + "' 2>&1"); + int rc = system(command.c_str()); + if (rc != 0) + { + LL_WARNS("eventhost") << command << " ==> " << rc << ':' << LL_ENDL; + } + else + { + LL_INFOS("eventhost") << command << ':' << LL_ENDL; + } + { + std::ifstream reader(outfile.c_str()); + std::string line; + while (std::getline(reader, line)) + { + size_t len = line.length(); + if (len && line[len-1] == '\n') + line.erase(len-1); + LL_INFOS("eventhost") << line << LL_ENDL; + } + } + remove(outfile.c_str()); + } +#endif // LL_WINDOWS + apr_dso_handle_t * eventhost_dso_handle = NULL; apr_pool_t * eventhost_dso_memory_pool = NULL; @@ -4407,13 +4772,13 @@ void LLAppViewer::loadEventHostModule(S32 listen_port) apr_status_t rv = apr_dso_load(&eventhost_dso_handle, dso_path.c_str(), eventhost_dso_memory_pool); - ll_apr_assert_status(rv); + llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle)); llassert_always(eventhost_dso_handle != NULL); int (*ll_plugin_start_func)(LLSD const &) = NULL; rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_start_func, eventhost_dso_handle, "ll_plugin_start"); - ll_apr_assert_status(rv); + llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle)); llassert_always(ll_plugin_start_func != NULL); LLSD args; @@ -4445,7 +4810,7 @@ void LLAppViewer::launchUpdater() // *TODO change userserver to be grid on both viewer and sim, since // userserver no longer exists. query_map["userserver"] = LLGridManager::getInstance()->getGridLabel(); - query_map["channel"] = gSavedSettings.getString("VersionChannelName"); + query_map["channel"] = LLVersionInfo::getChannel(); // *TODO constantize this guy // *NOTE: This URL is also used in win_setup/lldownloader.cpp LLURI update_url = LLURI::buildHTTP("secondlife.com", 80, "update.php", query_map); @@ -4513,6 +4878,8 @@ void LLAppViewer::launchUpdater() LLAppViewer::sUpdaterInfo->mUpdateExePath += update_url.asString(); LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" -name \""; LLAppViewer::sUpdaterInfo->mUpdateExePath += LLAppViewer::instance()->getSecondLifeTitle(); + LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" -bundleid \""; + LLAppViewer::sUpdaterInfo->mUpdateExePath += LL_VERSION_BUNDLE_ID; LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" &"; LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << LL_ENDL; @@ -4583,3 +4950,75 @@ bool LLAppViewer::getMasterSystemAudioMute() { return gSavedSettings.getBOOL("MuteAudio"); } + +//---------------------------------------------------------------------------- +// Metrics-related methods (static and otherwise) +//---------------------------------------------------------------------------- + +/** + * LLViewerAssetStats collects data on a per-region (as defined by the agent's + * location) so we need to tell it about region changes which become a kind of + * hidden variable/global state in the collectors. For collectors not running + * on the main thread, we need to send a message to move the data over safely + * and cheaply (amortized over a run). + */ +void LLAppViewer::metricsUpdateRegion(U64 region_handle) +{ + if (0 != region_handle) + { + LLViewerAssetStatsFF::set_region_main(region_handle); + if (LLAppViewer::sTextureFetch) + { + // Send a region update message into 'thread1' to get the new region. + LLAppViewer::sTextureFetch->commandSetRegion(region_handle); + } + else + { + // No 'thread1', a.k.a. TextureFetch, so update directly + LLViewerAssetStatsFF::set_region_thread1(region_handle); + } + } +} + + +/** + * Attempts to start a multi-threaded metrics report to be sent back to + * the grid for consumption. + */ +void LLAppViewer::metricsSend(bool enable_reporting) +{ + if (! gViewerAssetStatsMain) + return; + + if (LLAppViewer::sTextureFetch) + { + LLViewerRegion * regionp = gAgent.getRegion(); + + if (enable_reporting && regionp) + { + std::string caps_url = regionp->getCapability("ViewerMetrics"); + + // Make a copy of the main stats to send into another thread. + // Receiving thread takes ownership. + LLViewerAssetStats * main_stats(new LLViewerAssetStats(*gViewerAssetStatsMain)); + + // Send a report request into 'thread1' to get the rest of the data + // and provide some additional parameters while here. + LLAppViewer::sTextureFetch->commandSendMetrics(caps_url, + gAgentSessionID, + gAgentID, + main_stats); + main_stats = 0; // Ownership transferred + } + else + { + LLAppViewer::sTextureFetch->commandDataBreak(); + } + } + + // Reset even if we can't report. Rather than gather up a huge chunk of + // data, we'll keep to our sampling interval and retain the data + // resolution in time. + gViewerAssetStatsMain->reset(); +} + |