/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// Remove any existing UserInstallation's extensions cache data remaining from // old installations. This addresses at least two problems: // // For one, apparently due to the old share/prereg/bundled mechanism (disabled // since 5c47e5f63a79a9e72ec4a100786b1bbf65137ed4 "fdo#51252 Disable copying // share/prereg/bundled to avoid startup crashes"), the user/extensions/bundled // cache could contain corrupted information (like a UNO component registered // twice, which got changed from active to passive registration in one LO // version, but the version of the corresponding bundled extension only // incremented in a later LO version). // // For another, UserInstallations have been seen in the wild where no extensions // were installed per-user (any longer), but user/uno_packages/cache/registry/ // com.sun.star.comp.deployment.component.PackageRegistryBackend/*.rdb files // contained data nevertheless. // // When a LO upgrade is detected (i.e., no user/extensions/buildid or one // containing an old build ID), then user/extensions and // user/uno_packages/cache/registry/ // com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc are // removed. That should prevent any problems starting the service manager due // to old junk. Later on in Desktop::SynchronizeExtensionRepositories, the // removed cache data is recreated. // // Multiple instances of soffice.bin can execute this code in parallel for a // single UserInstallation, as it is called before RequestHandler is set up. // Therefore, any errors here only lead to SAL_WARNs. // // At least in theory, this function could be removed again once no // UserInstallation can be poisoned by old junk any more. bool cleanExtensionCache() {
OUString buildId(
u"${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ":buildid}"_ustr);
rtl::Bootstrap::expandMacros(buildId); //TODO: detect failure
OUString extDir(
u"${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/user/extensions"_ustr);
rtl::Bootstrap::expandMacros(extDir); //TODO: detect failure
OUString buildIdFile(extDir + "/buildid");
osl::File fr(buildIdFile);
osl::FileBase::RC rc = fr.open(osl_File_OpenFlag_Read); switch (rc) { case osl::FileBase::E_None:
{
rtl::ByteSequence s1;
rc = fr.readLine(s1);
osl::FileBase::RC rc2 = fr.close();
SAL_WARN_IF(
rc2 != osl::FileBase::E_None, "desktop.app", "cannot close " << fr.getURL() << " after reading: " << +rc2); // readLine returns E_AGAIN for a zero-size file: if (rc != osl::FileBase::E_None && rc != osl::FileBase::E_AGAIN) {
SAL_WARN( "desktop.app", "cannot read from " << fr.getURL() << ": " << +rc); break;
}
OUString s2( reinterpret_cast< charconst * >(s1.getConstArray()),
s1.getLength(), RTL_TEXTENCODING_ISO_8859_1); // using ISO 8859-1 avoids any and all conversion errors; the // content should only be a subset of ASCII, anyway if (s2 == buildId) { returnfalse;
} break;
} case osl::FileBase::E_NOENT: break; default:
SAL_WARN( "desktop.app", "cannot open " << fr.getURL() << " for reading: " << +rc); break;
}
utl::removeTree(extDir);
OUString userRcFile(
u"$UNO_USER_PACKAGES_CACHE/registry/" "com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc"_ustr);
rtl::Bootstrap::expandMacros(userRcFile); //TODO: detect failure
rc = osl::File::remove(userRcFile);
SAL_WARN_IF(
rc != osl::FileBase::E_None && rc != osl::FileBase::E_NOENT, "desktop.app", "cannot remove file " << userRcFile << ": " << +rc);
rc = osl::Directory::createPath(extDir);
SAL_WARN_IF(
rc != osl::FileBase::E_None && rc != osl::FileBase::E_EXIST, "desktop.app", "cannot create path " << extDir << ": " << +rc);
osl::File fw(buildIdFile);
rc = fw.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create); if (rc != osl::FileBase::E_None) {
SAL_WARN( "desktop.app", "cannot open " << fw.getURL() << " for writing: " << +rc); returntrue;
}
OString buf(OUStringToOString(buildId, RTL_TEXTENCODING_UTF8)); // using UTF-8 avoids almost all conversion errors (and buildid // containing single surrogate halves should never happen, anyway); the // content should only be a subset of ASCII, anyway
sal_uInt64 n = 0;
rc = fw.write(buf.getStr(), buf.getLength(), n);
SAL_WARN_IF(
(rc != osl::FileBase::E_None
|| n != static_cast< sal_uInt32 >(buf.getLength())), "desktop.app", "cannot write to " << fw.getURL() << ": " << +rc << ", " << n);
rc = fw.close();
SAL_WARN_IF(
rc != osl::FileBase::E_None, "desktop.app", "cannot close " << fw.getURL() << " after writing: " << +rc); returntrue;
}
// shows a simple error box with the given message ... but exits from these process ! // Fatal errors can't be solved by the process ... nor any recovery can help. // Mostly the installation was damaged and must be repaired manually .. or by calling // setup again. // On the other side we must make sure that no further actions will be possible within // the current office process ! No pipe requests, no menu/toolbar/shortcut actions // are allowed. Otherwise we will force a "crash inside a crash". // That's why we have to use a special native message box here which does not use yield :-)
// We need to have service factory before going further, but see fdo#37195. // Doing this will mmap common.rdb, making it not overwritable on windows, // so this can't happen before the synchronization above. Let's rework this // so that the above is called *from* CreateApplicationServiceManager or // something to enforce this gotcha try
{
InitApplicationServiceManager();
} catch (css::uno::Exception & e)
{
HandleBootstrapErrors( BE_UNO_SERVICEMANAGER, e.Message );
std::abort();
}
// Check whether safe mode is enabled const CommandLineArgs& rCmdLineArgs = GetCommandLineArgs(); // Check if we are restarting from safe mode - in that case we don't want to enter it again if (sfx2::SafeMode::hasRestartFlag())
sfx2::SafeMode::removeRestartFlag(); elseif (rCmdLineArgs.IsSafeMode() || sfx2::SafeMode::hasFlag())
Application::EnableSafeMode();
// When we are in SafeMode we need to do changes before the configuration // gets read (langselect::prepareLocale() by UNO API -> Components::Components) // This may prepare SafeMode or restore from it by moving data in // the UserConfiguration directory
comphelper::BackupFileHelper::reactOnSafeMode(Application::IsSafeModeEnabled());
// tdf117100: do not try to re-install extensions after the requested restart if (officecfg::Setup::Office::OfficeRestartInProgress::get())
{ if (!officecfg::Office::Common::Misc::FirstRun::get())
GetCommandLineArgs().RemoveFilesFromOpenListEndingWith(u".oxt"_ustr);
}
// test code for ProfileSafeMode to allow testing the fail // of loading the office configuration initially. To use, // either set to true and compile, or set a breakpoint // in debugger and change the local bool staticbool bTryHardOfficeconfigBroken(false); // loplugin:constvars:ignore
if (bTryHardOfficeconfigBroken)
{
SetBootstrapError(BE_OFFICECONFIG_BROKEN, OUString());
}
// start ipc thread only for non-remote offices
RequestHandler::Status aStatus = RequestHandler::Enable(true); if ( aStatus == RequestHandler::IPC_STATUS_PIPE_ERROR )
{ #ifdefined(ANDROID) || defined(EMSCRIPTEN) // Ignore crack pipe errors on Android #else // Keep using this oddly named BE_PATHINFO_MISSING value // for pipe-related errors on other platforms. Of course // this crack with two (if not more) levels of our own // error codes hiding the actual system error code is // broken, but that is done all over the code, let's leave // reengineering that to another year.
SetBootstrapError( BE_PATHINFO_MISSING, OUString() ); #endif
} elseif ( aStatus == RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR )
{
SetBootstrapError( BE_PATHINFO_MISSING, OUString() );
} elseif ( aStatus == RequestHandler::IPC_STATUS_2ND_OFFICE )
{ // 2nd office startup should terminate after sending cmdlineargs through pipe if (rCmdLineArgs.IsTextCat() || rCmdLineArgs.IsScriptCat())
{
HandleBootstrapErrors( BE_2NDOFFICE_WITHCAT, OUString() );
}
SetBootstrapStatus(BS_TERMINATE);
} elseif ( !rCmdLineArgs.GetUnknown().isEmpty()
|| rCmdLineArgs.IsHelp() || rCmdLineArgs.IsVersion() )
{ // disable IPC thread in an instance that is just showing a help message
RequestHandler::Disable();
}
pSignalHandler = osl_addSignalHandler(SalMainPipeExchangeSignal_impl, nullptr);
#if HAVE_EMSCRIPTEN_PROXY_POSIX_SOCKETS
{ autoconst val = emscripten::val::module_property("uno_websocket_to_posix_socket_url"); if (val.isUndefined()) { throw std::runtime_error("Module.uno_websocket_to_posix_socket_url is undefined");
} else { autoconst url = val.as<std::string>(); if (url.find('\0') != std::string::npos) { throw std::runtime_error( "Module.uno_websocket_to_posix_socket_url contains embedded NUL");
}
SAL_INFO("desktop.app", "connecting to <" << url << ">"); staticautoconst socket = emscripten_init_websocket_to_posix_socket_bridge(
url.c_str()); // 0 is CONNECTING, 1 is OPEN, see // <https://websockets.spec.whatwg.org/#websocket-ready-state>: unsignedshort readyState = 0; do {
emscripten_websocket_get_ready_state(socket, &readyState);
emscripten_thread_sleep(100);
} while (readyState == 0); if (readyState != 1) { throw std::runtime_error("could not connect to <" + url + ">");
}
SAL_INFO("desktop.app", "connected to <" << url << ">");
}
} #endif
}
void Desktop::DeInit()
{ try { // instead of removing of the configManager just let it commit all the changes
utl::ConfigManager::storeConfigItems();
FlushConfiguration();
// close splashscreen if it's still open
CloseSplashScreen();
Reference< XComponent >(
comphelper::getProcessComponentContext(), UNO_QUERY_THROW )->
dispose(); // nobody should get a destroyed service factory...
::comphelper::setProcessServiceFactory( nullptr );
// clear lockfile
m_xLockfile.reset();
RequestHandler::Disable(); if( pSignalHandler )
osl_removeSignalHandler( pSignalHandler );
} catch (const RuntimeException&) { // someone threw an exception during shutdown // this will leave some garbage behind...
TOOLS_WARN_EXCEPTION("desktop.app", "exception throwing during shutdown, will leave some garbage behind");
}
}
if ( !bExit )
{
xPropertySet->setPropertyValue( SUSPEND_QUICKSTARTVETO, Any(false) );
} else
{
FlushConfiguration(); try
{ // it is no problem to call RequestHandler::Disable() more than once // it also looks to be threadsafe
RequestHandler::Disable();
} catch ( const RuntimeException& )
{
}
// Create an error message depending on bootstrap failure code and an optional file url
OUString Desktop::CreateErrorMsgString(
utl::Bootstrap::FailureCode nFailureCode, const OUString& aFileURL )
{
OUString aMsg; bool bFileInfo = true;
switch ( nFailureCode )
{ /// the shared installation directory could not be located case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY:
{
aMsg = DpResId(STR_BOOTSTRAP_ERR_PATH_INVALID);
bFileInfo = false;
} break;
/// the bootstrap INI file could not be found or read case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE: /// the version locator INI file could not be found or read case ::utl::Bootstrap::MISSING_VERSION_FILE:
{
aMsg = DpResId(STR_BOOTSTRAP_ERR_FILE_MISSING);
} break;
/// the bootstrap INI is missing a required entry /// the bootstrap INI contains invalid data case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY: case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY:
{
aMsg = DpResId(STR_BOOTSTRAP_ERR_FILE_CORRUPT);
} break;
/// the version locator INI has no entry for this version case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY:
{
aMsg = DpResId(STR_BOOTSTRAP_ERR_NO_SUPPORT);
} break;
/// the user installation directory does not exist case ::utl::Bootstrap::MISSING_USER_DIRECTORY:
{
aMsg = DpResId(STR_BOOTSTRAP_ERR_DIR_MISSING);
} break;
/// some bootstrap data was invalid in unexpected ways case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA:
{
aMsg = DpResId(STR_BOOTSTRAP_ERR_INTERNAL);
bFileInfo = false;
} break;
case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY:
{ // This needs to be improved, see #i67575#:
aMsg = "Invalid version file entry";
bFileInfo = false;
} break;
case ::utl::Bootstrap::NO_FAILURE:
{
OSL_ASSERT(false);
} break;
}
/// the bootstrap INI file could not be found or read /// the bootstrap INI is missing a required entry /// the bootstrap INI contains invalid data case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY: case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY: case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE:
{
OUString aBootstrapFileURL;
/// the version locator INI file could not be found or read /// the version locator INI has no entry for this version /// the version locator INI entry is not a valid directory URL case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY: case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY: case ::utl::Bootstrap::MISSING_VERSION_FILE:
{
OUString aVersionFileURL;
case ::utl::Bootstrap::NO_FAILURE:
{
OSL_ASSERT(false);
} break;
}
HandleBootstrapPathErrors( aBootstrapStatus, aErrorMsg );
}
} elseif ( aBootstrapError == BE_UNO_SERVICEMANAGER || aBootstrapError == BE_UNO_SERVICE_CONFIG_MISSING )
{ // UNO service manager is not available. VCL needs a UNO service manager to display a message box!!! // Currently we are not able to display a message box with a service manager due to this limitations inside VCL.
// When UNO is not properly initialized, all kinds of things can fail // and cause the process to crash. To give the user a hint even if // generating and displaying a message box below crashes, print a // hard-coded message on stderr first:
std::cerr
<< "The application cannot be started.\n" // STR_BOOTSTRAP_ERR_CANNOT_START
<< (aBootstrapError == BE_UNO_SERVICEMANAGER
? "The component manager is not available.\n" // STR_BOOTSTRAP_ERR_NO_SERVICE
: "The configuration service is not available.\n"); // STR_BOOTSTRAP_ERR_NO_CFG_SERVICE if ( !aErrorMessage.isEmpty() )
{
std::cerr << "(\"" << aErrorMessage << "\")\n";
}
// First sentence. We cannot bootstrap office further!
OUString aDiagnosticMessage = DpResId(STR_BOOTSTRAP_ERR_NO_CFG_SERVICE) + "\n"; if ( !aErrorMessage.isEmpty() )
{
aDiagnosticMessage += "(\"" + aErrorMessage + "\")\n";
}
// Due to the fact the we haven't a backup applicat.rdb file anymore it is not possible to // repair the installation with the setup executable besides the office executable. Now // we have to ask the user to start the setup on CD/installation directory manually!!
aDiagnosticMessage += DpResId(STR_ASK_START_SETUP_MANUALLY);
FatalError(MakeStartupErrorMessage(aDiagnosticMessage));
} elseif ( aBootstrapError == BE_OFFICECONFIG_BROKEN )
{ // set flag at BackupFileHelper to be able to know if _exit was called and // actions are executed after this. This method we are in will not return, // but end up in a _exit() call
comphelper::BackupFileHelper::setExitWasCalled();
// enter safe mode, too
sfx2::SafeMode::putFlag();
/** @short check if recovery must be started or not.
@param bCrashed [boolean ... out!] the office crashed last times. But may be there are no recovery data. Useful to trigger the error report tool without showing the recovery UI.
@param bRecoveryDataExists [boolean ... out!] there exists some recovery data.
@param bSessionDataExists [boolean ... out!] there exists some session data. Because the user may be logged out last time from its unix session...
*/ void impl_checkRecoveryState(bool& bCrashed , bool& bRecoveryDataExists, bool& bSessionDataExists )
{
bCrashed = officecfg::Office::Recovery::RecoveryInfo::Crashed::get() #if HAVE_FEATURE_BREAKPAD
|| CrashReporter::crashReportInfoExists(); #else
; #endif bool elements = officecfg::Office::Recovery::RecoveryList::get()->
hasElements(); bool session
= officecfg::Office::Recovery::RecoveryInfo::SessionData::get();
bRecoveryDataExists = elements && !session;
bSessionDataExists = elements && session;
}
// save all modified documents ... if it's allowed doing so. bool bRestart = false; bool bAllowRecoveryAndSessionManagement = (
( !rArgs.IsNoRestore() ) && // some use cases of office must work without recovery
( !rArgs.IsHeadless() ) &&
( nCategory != ExceptionCategory::UserInterface ) && // recovery can't work without UI ... but UI layer seems to be the reason for this crash
( Application::IsInExecute() ) // crashes during startup and shutdown should be ignored (they indicate a corrupted installation...)
); if ( bAllowRecoveryAndSessionManagement )
{ // Save all open documents so they will be reopened // the next time the application is started // returns true if at least one document could be saved... #if !ENABLE_WASM_STRIP_RECOVERYUI
bRestart = impl_callRecoveryUI( true , // force emergency save false); #endif
}
// Detect desktop environment - need to do this as early as possible
css::uno::setCurrentContext( new DesktopContext( css::uno::getCurrentContext() ) );
if (officecfg::Office::Common::Misc::PreloadJVM::get() && pExecGlobals)
{
SAL_INFO("desktop.app", "Preload JVM");
// pre-load JVM
pExecGlobals->xJVMloadThread = new JVMloadThread();
pExecGlobals->xJVMloadThread->launch();
}
recordTime(startT, "SetSplashScreenProgress(25): time = ");
#if HAVE_FEATURE_DESKTOP && !defined(EMSCRIPTEN) // check user installation directory for lockfile so we can be sure // there is no other instance using our data files from a remote host
#if HAVE_FEATURE_UPDATE_MAR if (!rCmdLineArgs.IsHeadless()
&& (officecfg::Office::Update::Update::Enabled::get()
|| std::getenv("LIBO_UPDATER_TEST_ENABLE")))
{ // check if we just updated bool bUpdateRunning = officecfg::Office::Update::Update::UpdateRunning::get()
|| std::getenv("LIBO_UPDATER_TEST_RUNNING"); if (bUpdateRunning)
{
OUString aSeeAlso = officecfg::Office::Update::Update::SeeAlso::get();
OUString aOldBuildID = officecfg::Office::Update::Update::OldBuildID::get();
OUString aBuildID = Updater::getBuildID(); if (aOldBuildID == aBuildID)
{
Updater::log("Old and new Build ID are the same. No Updating took place.");
} else
{ if (!aSeeAlso.isEmpty())
{
SAL_INFO("desktop.updater", "See also: " << aSeeAlso);
Reference< css::system::XSystemShellExecute > xSystemShell(
SystemShellExecute::create(::comphelper::getProcessComponentContext()) );
// reset all the configuration values, // all values need to be read before this code
std::shared_ptr< comphelper::ConfigurationChanges > batch(
comphelper::ConfigurationChanges::create());
officecfg::Office::Update::Update::UpdateRunning::set(false, batch);
officecfg::Office::Update::Update::SeeAlso::set(OUString(), batch);
officecfg::Office::Update::Update::OldBuildID::set(OUString(), batch);
batch->commit();
// make sure the change is written to the configuration before we start the update
css::uno::Reference<css::util::XFlushable> xFlushable(css::configuration::theDefaultProvider::get(xContext), UNO_QUERY);
xFlushable->flush(); // avoid the old oosplash staying around
CloseSplashScreen(); bool bSuccess = update(); if (bSuccess)
{
xDesktop->terminate(); return EXIT_SUCCESS;
}
} elseif (isTimeForUpdateCheck() || std::getenv("LIBO_UPDATER_TEST_UPDATE_CHECK"))
{
sal_uInt64 nNow = tools::Time::GetSystemTicks();
Updater::log("Update Check Time: " + OUString::number(nNow));
std::shared_ptr< comphelper::ConfigurationChanges > batch(
comphelper::ConfigurationChanges::create());
officecfg::Office::Update::Update::LastUpdateTime::set(nNow, batch);
batch->commit();
m_aUpdateThread = std::thread(update_checker);
}
} #endif
// create service for loading SFX (still needed in startup)
pExecGlobals->xGlobalBroadcaster = Reference < css::document::XDocumentEventListener >
( css::frame::theGlobalEventBroadcaster::get(xContext), UNO_SET_THROW );
/* ensure existence of a default window that messages can be dispatched to This is for the benefit of testtool which uses PostUserEvent extensively and else can deadlock while creating this window from another thread while the main thread is not yet in the event loop.
*/
Application::GetDefaultDevice();
#if HAVE_FEATURE_EXTENSIONS // Check if bundled or shared extensions were added /removed // and process those extensions (has to be done before checking // the extension dependencies!
SynchronizeExtensionRepositories(m_bCleanedExtensionCache, this); bool bAbort = CheckExtensionDependencies(); if ( bAbort ) return EXIT_FAILURE;
if (inst_fin == userinstall::CREATED)
{
Migration::migrateSettingsIfNecessary();
} #endif
// keep a language options instance...
pExecGlobals->pCTLLanguageOptions.reset( new SvtCTLOptions(true));
// Preload function depends on an initialized sfx application!
SetSplashScreenProgress(75);
recordTime(startT, "SetSplashScreenProgress(75): time = ");
// use system window dialogs
Application::SetSystemWindowMode( SystemWindowFlags::DIALOG );
SetSplashScreenProgress(80);
recordTime(startT, "SetSplashScreenProgress(80): time = ");
if ( !rCmdLineArgs.IsInvisible() &&
!rCmdLineArgs.IsNoQuickstart() )
InitializeQuickstartMode( xContext );
if ( xDesktop.is() )
xDesktop->addTerminateListener( new RequestHandlerController );
SetSplashScreenProgress(100);
recordTime(startT, "SetSplashScreenProgress(100): time = ");
// FIXME: move this somewhere sensible. #if HAVE_FEATURE_OPENCL
CheckOpenCLCompute(xDesktop); #endif
// Post user event to startup first application component window // We have to send this OpenClients message short before execute() to // minimize the risk that this message overtakes type detection construction!!
Application::PostUserEvent( LINK( this, Desktop, OpenClients_Impl ) );
// Post event to enable acceptors
Application::PostUserEvent( LINK( this, Desktop, EnableAcceptors_Impl) );
// call Application::Execute to process messages in vcl message loop #if HAVE_FEATURE_JAVA // The JavaContext contains an interaction handler which is used when // the creation of a Java Virtual Machine fails
css::uno::ContextLayer layer2( new svt::JavaContext( css::uno::getCurrentContext() ) ); #endif // check whether the shutdown is caused by restart just before entering the Execute
pExecGlobals->bRestartRequested = pExecGlobals->bRestartRequested ||
xRestartManager->isRestartRequested(true);
if ( !pExecGlobals->bRestartRequested )
{ // if this run of the office is triggered by restart, some additional actions should be done
DoRestartActionsIfNecessary( !rCmdLineArgs.IsInvisible() && !rCmdLineArgs.IsNoQuickstart() );
Execute();
}
} else
{ if (xDesktop.is())
xDesktop->terminate();
} // CAUTION: you do not necessarily get here e.g. on the Mac. // please put all deinitialization code into doShutdown return doShutdown();
}
int Desktop::doShutdown()
{ if( ! pExecGlobals ) return EXIT_SUCCESS;
if (m_aUpdateThread.joinable())
m_aUpdateThread.join();
if (pExecGlobals->xJVMloadThread.is())
{
pExecGlobals->xJVMloadThread->join();
pExecGlobals->xJVMloadThread.clear();
}
// flush evtl. configuration changes so that all config files in user // dir are written
FlushConfiguration();
if (pExecGlobals->bRestartRequested)
{ // tdf#128523
RemoveIconCacheDirectory();
// a restart is already requested, usually due to a configuration change // that needs a restart to get active. If this is the case, do not try // to use SecureUserConfig to safe this still untested new configuration
} else
{ // Test if SecureUserConfig is active. If yes and we are at this point, regular shutdown // is in progress and the currently used configuration was working. Try to secure this // working configuration for later eventually necessary restores
comphelper::BackupFileHelper aBackupFileHelper;
// The acceptors in the AcceptorMap must be released (in DeregisterServices) // with the solar mutex unlocked, to avoid deadlock:
{
SolarMutexReleaser aReleaser;
DeregisterServices(); #if HAVE_FEATURE_SCRIPTING
StarBASIC::DetachAllDocBasicItems(); #endif
}
// be sure that path/language options gets destroyed before // UCB is deinitialized
pExecGlobals->pCTLLanguageOptions.reset();
pExecGlobals->pPathOptions.reset();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.