From cf20fde0a632888ab6189b7dc9689c8c4991025b Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Tue, 18 Aug 2015 13:46:11 +0200 Subject: [PATCH 1/2] [launcherlib] Remove some dead code. This is unused since the switch from single daemon to library-plus-multiple-processes. Closes #33. --- src/launcherlib/daemon.cpp | 297 +------------------------------------ src/launcherlib/daemon.h | 9 -- 2 files changed, 8 insertions(+), 298 deletions(-) diff --git a/src/launcherlib/daemon.cpp b/src/launcherlib/daemon.cpp index b461b41..453ab5d 100644 --- a/src/launcherlib/daemon.cpp +++ b/src/launcherlib/daemon.cpp @@ -96,7 +96,6 @@ Daemon::Daemon(int & argc, char * argv[]) : m_boosterPid(0), m_socketManager(new SocketManager), m_singleInstance(new SingleInstance), - m_reExec(false), m_notifySystemd(false), m_booster(0) { @@ -125,21 +124,16 @@ Daemon::Daemon(int & argc, char * argv[]) : // Parse arguments parseArgs(ArgVect(argv, argv + argc)); - if (m_reExec) - { - restoreState(); - } - // Store arguments list m_initialArgv = argv; m_initialArgc = argc; - if (!m_reExec && socketpair(AF_UNIX, SOCK_DGRAM, 0, m_boosterLauncherSocket) == -1) + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, m_boosterLauncherSocket) == -1) { throw std::runtime_error("Daemon: Creating a socket pair for boosters failed!\n"); } - if (!m_reExec && pipe(m_sigPipeFd) == -1) + if (pipe(m_sigPipeFd) == -1) { throw std::runtime_error("Daemon: Creating a pipe for Unix signals failed!\n"); } @@ -167,22 +161,13 @@ void Daemon::run(Booster *booster) // dlopen single-instance loadSingleInstancePlugin(); - if (m_reExec) - { - // Reap dead booster processes and restart them - // Note: this cannot be done before booster plugins have been loaded - reapZombies(); - } - else - { - // Create socket for the booster - Logger::logDebug("Daemon: initing socket: %s", booster->boosterType().c_str()); - m_socketManager->initSocket(booster->boosterType()); + // Create socket for the booster + Logger::logDebug("Daemon: initing socket: %s", booster->boosterType().c_str()); + m_socketManager->initSocket(booster->boosterType()); - // Fork each booster for the first time - Logger::logDebug("Daemon: forking booster: %s", booster->boosterType().c_str()); - forkBooster(); - } + // Fork each booster for the first time + Logger::logDebug("Daemon: forking booster: %s", booster->boosterType().c_str()); + forkBooster(); // Notify systemd that init is done if (m_notifySystemd) { @@ -251,14 +236,6 @@ void Daemon::run(Booster *booster) Logger::logDebug("Daemon: SIGPIPE received."); break; - case SIGHUP: - Logger::logDebug("Daemon: SIGHUP received."); - reExec(); - - // not reached if re-exec successful - break; - - default: break; } @@ -600,10 +577,6 @@ void Daemon::parseArgs(const ArgVect & args) { usage(args[0].c_str(), EXIT_SUCCESS); } - else if ((*i) == "--re-exec") - { - m_reExec = true; - } else if ((*i) == "--systemd") { m_notifySystemd = true; @@ -727,257 +700,3 @@ Daemon::~Daemon() Logger::closeLog(); } -void Daemon::reExec() -{ - Logger::logInfo("Daemon: Re-exec requested."); - - struct stat st; - if (stat(m_stateDir.c_str(), &st) != 0) - { - Logger::logDebug("Daemon: State saving directory %s does not exist", m_stateDir.c_str()); - Logger::logDebug("Daemon: Attempting to create it"); - - if (mkdir(m_stateDir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR) != 0) - { - Logger::logDebug("Daemon: Failed to create directory, re-exec failed, exiting."); - _exit(1); - } - } - - if (stat(m_stateDir.c_str(), &st) != 0) - { - Logger::logDebug("Daemon: Directory vanished, re-exec failed, exiting."); - _exit(1); - } - if (!S_ISDIR(st.st_mode)) - { - Logger::logDebug("Daemon: %s exists but it is not a directory, re-exec failed, exiting.", m_stateDir.c_str()); - _exit(1); - } - - try { - std::ofstream ss(m_stateFile.c_str()); - ss.exceptions (std::ifstream::failbit | std::ifstream::badbit); - - // dump the pid to double check that the state file is from this process - ss << "my-pid " << getpid() << std::endl; - - // Save debug mode first, restoring it will enable debug logging. - // This way we get debug output from the re-execed daemon as early - // as possible. - ss << "debug-mode " << m_debugMode << std::endl; - - // The pids of the dead boosters are also passed as children, but - // this causes no harm. - for(PidVect::iterator it = m_children.begin(); it != m_children.end(); it++) - { - ss << "child " << *it << std::endl; - } - - for(PidMap::iterator it = m_boosterPidToInvokerPid.begin(); it != m_boosterPidToInvokerPid.end(); it++) - { - ss << "booster-invoker-pid " << it->first << " " << it->second << std::endl; - } - - for(FdMap::iterator it = m_boosterPidToInvokerFd.begin(); it != m_boosterPidToInvokerFd.end(); it++) - { - ss << "booster-invoker-fd " << it->first << " " << it->second << std::endl; - } - - ss << "booster-pid " << m_boosterPid << std::endl; - - ss << "launcher-socket " << m_boosterLauncherSocket[0] << " " << m_boosterLauncherSocket[1] << std::endl; - - ss << "sigpipe-fd " << m_sigPipeFd[0] << " " << m_sigPipeFd[1] << std::endl; - - ss << "boot-mode " << m_bootMode << std::endl; - - SocketManager::SocketHash s = m_socketManager->getState(); - for(SocketManager::SocketHash::iterator it = s.begin(); it != s.end(); it++) - { - ss << "socket-hash " << it->first << " " << it->second << std::endl; - } - - // when the new applauncherd reads this, - // it knows state saving was successful. - ss << "end" << std::endl; - ss.close(); - } - catch (std::ofstream::failure e) - { - Logger::logError("Daemon: Failed to save state, re-exec failed, exiting."); - _exit(1); - } - - char* argv[] = { const_cast("/usr/bin/applauncherd.bin"), - const_cast("--re-exec"), - const_cast(" "), - NULL}; - - // The boosters have state which will become stale, so kill them. - // The dead boosters will be reaped when the re-execed applauncherd - // calls reapZombies after it has initialized. - killBoosters(); - - // Signal handlers are reset at exec(), so we will lose - // the SIGHUP handling. However, ignoring a signal is preserved - // over exec(), so start ignoring SIGHUP to prevent applauncherd - // dying if we receive multiple SIGHUPs. - signal(SIGHUP, SIG_IGN); - - Logger::logDebug("Daemon: configuration saved succesfully, call execve() "); - execve(argv[0], argv, environ); - - // Not reached. - Logger::logDebug("Daemon: Failed to execute execve(), re-exec failed, exiting."); - _exit(1); -} - -void Daemon::restoreState() -{ - try - { - // We have saved state, try to restore it. - std::ifstream ss(m_stateFile.c_str()); - ss.exceptions (std::ifstream::failbit | std::ifstream::badbit); - - std::string token; - - ss >> token; - - // Bit of defensive programming. Read the pid of the process - // that left the state file. If it is different from my pid, - // then something is wrong, and we better exit. - if (token != "my-pid") - { - throw "Daemon: malformed state file, exiting."; - } - else - { - int pid; - ss >> pid; - if (pid != getpid()) - { - throw "Daemon: stale state file, exiting."; - } - } - - // Do not check for eof, instead trigger an exception - // if reading past end of file. When state restore is - // successful we read the "end" token and return from - // this method. - while (true) - { - ss >> token; - - if (token == "end") - { - // successfully restored state - ss.close(); - - // In debug mode it is better to leave the file there - // so it can be examined. - if (!m_debugMode && remove(m_stateFile.c_str()) == -1) - { - Logger::logError("Daemon: could not remove state file %s", m_stateFile.c_str()); - } - Logger::logDebug("Daemon: state restore completed"); - return; - } - else if (token == "child") - { - int arg1; - ss >> arg1; - Logger::logDebug("Daemon: restored child %d", arg1); - m_children.push_back(arg1); - } - else if (token == "booster-invoker-pid") - { - int arg1, arg2; - ss >> arg1; - ss >> arg2; - Logger::logDebug("Daemon: restored m_boosterPidToInvokerPid[%d] = %d", arg1, arg2); - m_boosterPidToInvokerPid[arg1] = arg2; - } - else if (token == "booster-invoker-fd") - { - int arg1, arg2; - ss >> arg1; - ss >> arg2; - Logger::logDebug("Daemon: restored m_boosterPidToInvokerFd[%d] = %d", arg1, arg2); - m_boosterPidToInvokerFd[arg1] = arg2; - } - else if (token == "booster-pid") - { - int arg1; - ss >> arg1; - Logger::logDebug("Daemon: restored m_boosterPid = %d", arg1); - - m_boosterPid = arg1; - } - else if (token == "launcher-socket") - { - int arg1, arg2; - ss >> arg1; - ss >> arg2; - Logger::logDebug("Daemon: restored m_boosterLauncherSocket[] = {%d, %d}", arg1, arg2); - m_boosterLauncherSocket[0] = arg1; - m_boosterLauncherSocket[1] = arg2; - } - else if (token == "sigpipe-fd") - { - int arg1, arg2; - ss >> arg1; - ss >> arg2; - Logger::logDebug("Daemon: restored m_sigPipeFd[] = {%d, %d}", arg1, arg2); - m_sigPipeFd[0] = arg1; - m_sigPipeFd[1] = arg2; - } - else if (token == "socket-hash") - { - std::string arg1; - int arg2; - ss >> arg1; - ss >> arg2; - m_socketManager->addMapping(arg1, arg2); - Logger::logDebug("Daemon: restored socketHash[%s] = %d", arg1.c_str(), arg2); - } - else if (token == "debug-mode") - { - bool arg1; - ss >> arg1; - m_debugMode = arg1; - Logger::setDebugMode(m_debugMode); - Logger::logDebug("Daemon: restored m_debugMode = %d", arg1); - } - else if (token == "boot-mode") - { - bool arg1; - ss >> arg1; - m_bootMode = arg1; - Logger::logDebug("Daemon: restored m_bootMode = %d", arg1); - } - } - } - catch (std::ifstream::failure e) - { - // Ran out of saved state before "end" token - // or there was some other error in restoring the sate. - Logger::logError("Daemon: Failed to restore saved state, exiting."); - } - catch (char *err) - { - // Some other error, e.g. stale state file - Logger::logError(err); - } - - // In debug mode it is better to leave the file there - // so it can be examined. - if (!m_debugMode && remove(m_stateFile.c_str()) == -1) - { - Logger::logError("Daemon: could not remove state file %s", m_stateFile.c_str()); - } - - // This is only reached if state restore was unsuccessful. - _exit(1); -} diff --git a/src/launcherlib/daemon.h b/src/launcherlib/daemon.h index 502a14e..2c969ee 100644 --- a/src/launcherlib/daemon.h +++ b/src/launcherlib/daemon.h @@ -144,12 +144,6 @@ private: //! Prints the usage and exits with given status void usage(const char *name, int status); - //! Re-exec applauncherd.bin - void reExec(); - - //! Restore state. - void restoreState(); - //! Daemonize flag (--fork). Daemon forks if true. bool m_daemon; @@ -208,9 +202,6 @@ private: typedef map SigHandlerMap; SigHandlerMap m_originalSigHandlers; - //! True if re-execing - bool m_reExec; - //! True if systemd needs to be notified bool m_notifySystemd; From 0ee65f7fa9fa3472d8fb792e579efc2d1f6ac9ee Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Tue, 18 Aug 2015 13:52:05 +0200 Subject: [PATCH 2/2] [README] Update to match reality a little closer. --- README | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/README b/README index 0964d5e..b52d32b 100644 --- a/README +++ b/README @@ -2,12 +2,12 @@ What is applauncherd? ============================== Applauncherd is a daemon that helps to launch applications faster by -preloading dynamically linked libraries and caching stuff (MComponentCache). It also saves memory, because all launched -applications share certain resources. +preloading dynamically linked libraries and caching stuff. +It also saves memory, because all launched applications share certain resources. Applauncherd also provides support for fast single instance launches. -Some technical details are explained below. +Some technical details are explained below. Install applauncherd-doc for the Doxygen-based user documentation. See INSTALL on how to build applauncherd and the documentation. @@ -23,17 +23,15 @@ Building Technical overview ============================== -The applauncherd daemon is started by UpStart as part of XSession, that -is, at the same level as the desktop (MeeGo Touch homescreen). -Applauncherd forks the will-be-application process, "booster", before -knowing which application is going to be launched next. There can be +Booster daemons (written using the provided library) are started as part of the +user session. The booster is responsible for forking the will-be-application +before knowing which application is going to be launched next. There can be different kinds of boosters optimized for different kinds of -applications, e.g. Qt or QML. +applications, e.g. Qt or QML. -In the current architecture boosters are loaded as plugins. Applauncherd -searches for plugin libraries in /usr/lib/applaucherd/lib*booster.so and -forks a new process for each booster to wait for launch commands from the -user. +In the current architecture boosters are implemented as seperate processes, +using the provided support library. Each booster process waits for launch +commands. The user uses the launcher always through a special invoker program. The invoker (/usr/bin/invoker) tells booster process to load an application @@ -47,21 +45,12 @@ In that case exec() is used. Technical details ============================== -Before loading, booster process changes its security credentials so that -the code in the application binary will be executed with the correct credentials. Loading the binary is done with dlopen(), and therefore the +Loading the binary is done with dlopen(), and therefore the application needs to be compiled and linked as a shared library or a position independent executable. The booster process also sets the environment variables. Finally, it finds the main function in the application binary with dlsym() and calls the main() with the command -line arguments given by the invoker. - -The launcher itself is a library that is loaded by a small C-program (/usr/bin/applauncherd.bin). Idea behind this is to avoid linking the -launcher binary to any libraries. This allows us to fully control how -(with which flags) the preloaded libraries are opened with dlopen(). - -Each application type (currently Qt or QtDeclarative) has its own booster -process. When booster launches the application by calling the "main()" -function, applauncherd will create new booster process of that type. +line arguments given by the invoker. Booster processes do some initializations that cannot be shared among other processes and therefore have to be done after forking. This allows, @@ -73,6 +62,12 @@ launched. Contributors ============================== +People who have contributed to mapplauncherd: + +Robin Burchell +John Brooks +Thomas Perl + People who have contributed to meegotouch-applauncherd: Olli Leppänen