[mapplauncherd] Remove applauncherd and refactor boosters into independent processes

Having a single applauncherd process with boosters as plugins is a
flawed idea: most notably, it's not possible to have two boosters with
conflicting libraries, like Qt4 and Qt5.

A much cleaner solution is to turn libapplauncherd into a support
library for boosters, and have each booster run as an independent
process.
pull/1/head
John Brooks 14 years ago
parent 34c64fdf1a
commit b6e9aa171b

@ -24,12 +24,8 @@ endif ($ENV{DEBUG_BUILD})
# Set the program name defines. Must be at this level due to unit tests.
add_definitions(-DPROG_NAME_INVOKER="invoker")
add_definitions(-DPROG_NAME_LAUNCHER="applauncherd")
add_definitions(-DPROG_NAME_SINGLE_INSTANCE="single-instance")
# applauncherd will find lib*booster.so from here
add_definitions(-DBOOSTER_PLUGIN_DIR="/usr/lib/applauncherd")
# applauncherd will try to load single-instance using this path
add_definitions(-DSINGLE_INSTANCE_PATH="/usr/bin/single-instance")
@ -69,9 +65,3 @@ install(DIRECTORY doc/implementation-documentation DESTINATION /usr/share/doc/ap
install(DIRECTORY doc/user-documentation DESTINATION /usr/share/doc/applauncherd OPTIONAL)
install(DIRECTORY doc/mdeclarativecache-documentation DESTINATION /usr/share/doc/applauncherd OPTIONAL)
# Install startup script
if ($ENV{DEBUG_BUILD})
install(PROGRAMS src/scripts/applauncherd-debug DESTINATION /usr/bin/ RENAME applauncherd)
else ($ENV{DEBUG_BUILD})
install(PROGRAMS src/scripts/applauncherd DESTINATION /usr/bin/)
endif ($ENV{DEBUG_BUILD})

@ -1,12 +0,0 @@
[Unit]
Description=MTF app launcher daemon
After=xorg.target
Requires=dbus.socket xorg.target
[Service]
Type=notify
ExecStart=/usr/bin/applauncherd --systemd
[Install]
# For compatibility
Alias=meegotouch-applauncherd.service

@ -15,7 +15,6 @@ Group: System/Daemons
License: LGPLv2+
URL: https://github.com/nemomobile/mapplauncherd/
Source0: %{name}-%{version}.tar.bz2
Source1: mapplauncherd.service
Source100: mapplauncherd.yaml
Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig
@ -95,12 +94,8 @@ rm -rf %{buildroot}
# >> install pre
# << install pre
%make_install
mkdir -p %{buildroot}%{_libdir}/systemd/user/
cp -a %{SOURCE1} %{buildroot}%{_libdir}/systemd/user/
# >> install post
(cd %{buildroot}%{_libdir}/systemd/user; ln -s mapplauncherd.service meegotouch-applauncherd.service)
# rpmlint complains about installing binaries in /usr/share, so
# move them elsewhere and leave a symlink in place.
@ -119,12 +114,9 @@ rm -f %{buildroot}/usr/share/fala_images/fala_qml_helloworld
%defattr(-,root,root,-)
%{_bindir}/invoker
%{_libdir}/libapplauncherd.so*
%{_libdir}/applauncherd/libebooster.so
%{_bindir}/applauncherd.bin
%{_bindir}/applauncherd
%{_libexecdir}/mapplauncherd/ebooster
%{_libdir}/systemd/user/booster-e.service
%{_bindir}/single-instance
%{_libdir}/systemd/user/mapplauncherd.service
%{_libdir}/systemd/user/meegotouch-applauncherd.service
# >> files
# << files
@ -155,17 +147,11 @@ rm -f %{buildroot}/usr/share/fala_images/fala_qml_helloworld
%{_libdir}/applauncherd-tests/tests.xml
%{_libdir}/applauncherd-tests/ut_booster
%{_libdir}/applauncherd-tests/ut_daemon
%{_libdir}/applauncherd-tests/ut_ebooster
%{_libdir}/applauncherd-tests/ut_connection
%{_libdir}/applauncherd-tests/ut_socketmanager
%{_libdir}/applauncherd-tests/libutplugin.so
%{_libdir}/applauncherd-tests/libutwithcreate.so
%{_libdir}/applauncherd-tests/libutwithcreatetype.so
%{_libdir}/applauncherd-tests/libutwithcreatetypesocketname.so
%{_libdir}/applauncherd-tests/libutwithlock.so
%{_libdir}/applauncherd-tests/libutwithlockunlock.so
%{_libdir}/applauncherd-tests/ut_appdata
%{_libdir}/applauncherd-tests/ut_boosterpluginregistry
%{_libdir}/applauncherd-tests/ut_logger
%{_libdir}/applauncherd-tests/ut_singleinstance
%{_datadir}/applauncherd-M-testscripts/check_pipes.py

@ -7,8 +7,6 @@ License: LGPLv2+
URL: https://github.com/nemomobile/mapplauncherd/
Sources:
- "%{name}-%{version}.tar.bz2"
ExtraSources:
- mapplauncherd.service;%{_libdir}/systemd/user/
Description: |
Application invoker and launcher daemon that speed up
application startup time and share memory. Provides also
@ -34,13 +32,9 @@ Builder: make
Files:
- "%{_bindir}/invoker"
- "%{_libdir}/libapplauncherd.so*"
- "%{_libdir}/applauncherd/libebooster.so"
- "%{_bindir}/applauncherd.bin"
- "%{_bindir}/applauncherd"
- "%{_libexecdir}/mapplauncherd/ebooster"
- "%{_libdir}/systemd/user/booster-e.service"
- "%{_bindir}/single-instance"
- "%{_libdir}/systemd/user/mapplauncherd.service"
# For compatibility
- "%{_libdir}/systemd/user/meegotouch-applauncherd.service"
SubPackages:
- Name: devel
Group: Development/Tools
@ -85,17 +79,11 @@ SubPackages:
- "%{_libdir}/applauncherd-tests/tests.xml"
- "%{_libdir}/applauncherd-tests/ut_booster"
- "%{_libdir}/applauncherd-tests/ut_daemon"
- "%{_libdir}/applauncherd-tests/ut_ebooster"
- "%{_libdir}/applauncherd-tests/ut_connection"
- "%{_libdir}/applauncherd-tests/ut_socketmanager"
- "%{_libdir}/applauncherd-tests/libutplugin.so"
- "%{_libdir}/applauncherd-tests/libutwithcreate.so"
- "%{_libdir}/applauncherd-tests/libutwithcreatetype.so"
- "%{_libdir}/applauncherd-tests/libutwithcreatetypesocketname.so"
- "%{_libdir}/applauncherd-tests/libutwithlock.so"
- "%{_libdir}/applauncherd-tests/libutwithlockunlock.so"
- "%{_libdir}/applauncherd-tests/ut_appdata"
- "%{_libdir}/applauncherd-tests/ut_boosterpluginregistry"
- "%{_libdir}/applauncherd-tests/ut_logger"
- "%{_libdir}/applauncherd-tests/ut_singleinstance"
- "%{_datadir}/applauncherd-M-testscripts/check_pipes.py"

@ -1,9 +1,6 @@
# Sub build: invoker
add_subdirectory(invoker)
# Sub build: launcher
add_subdirectory(launcher)
# Sub build: launcher library
add_subdirectory(launcherlib)

@ -7,14 +7,15 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${COMMON} ${LAUNCHER})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
# Set sources
set(SRC ebooster.cpp pluginfactory.cpp)
set(SRC ebooster.cpp)
# Set libraries to be linked.
link_libraries("-L../launcherlib -lapplauncherd" ${LIBDL})
# Set executable
add_library(ebooster MODULE ${SRC} ${MOC_SRC})
add_executable(ebooster ${SRC} ${MOC_SRC})
add_dependencies(ebooster applauncherd)
# Add install rule
install(TARGETS ebooster DESTINATION /usr/lib/applauncherd/)
install(TARGETS ebooster DESTINATION /usr/libexec/mapplauncherd/)
install(FILES booster-e.service DESTINATION /usr/lib/systemd/user/)

@ -0,0 +1,8 @@
[Unit]
Description=Generic application launch booster
After=xorg.target
Requires=dbus.socket xorg.target
[Service]
Type=notify
ExecStart=/usr/libexec/mapplauncherd/ebooster --systemd

@ -18,10 +18,11 @@
****************************************************************************/
#include "ebooster.h"
#include "launcherlib.h"
#include "daemon.h"
#include "logger.h"
#include <errno.h>
#include <string.h>
#include "coverage.h"
const string EBooster::m_socketId = "/tmp/booste";
const string EBooster::m_temporaryProcessName = "booster-e";
@ -31,22 +32,12 @@ const string & EBooster::socketId() const
return m_socketId;
}
const string & EBooster::socketName()
{
return m_socketId;
}
const string & EBooster::temporaryProcessName()
{
return m_temporaryProcessName;
}
const string & EBooster::boosterTemporaryProcessName() const
{
return temporaryProcessName();
return m_temporaryProcessName;
}
char EBooster::type()
char EBooster::boosterType() const
{
return 'e';
}
@ -79,3 +70,12 @@ int EBooster::launchProcess()
return EXIT_FAILURE;
}
int main(int argc, char **argv)
{
EBooster *booster = new EBooster;
Daemon d(argc, argv);
d.run(booster);
}

@ -26,39 +26,20 @@
\class EBooster
\brief EBooster is a "booster" that only exec()'s the given binary.
This can be used with e.g. splash screen to launch any application.
This can be used to launch any application.
*/
class EBooster : public Booster
{
public:
//! \brief Constructor
EBooster() {}
//! \brief Destructor
virtual ~EBooster() {}
/*!
* \brief Return the socket name common to all EBooster objects.
* \return Path to the socket file.
*/
static const string & socketName();
//! Return the process name to be used when booster is not
//! yet transformed into a running application
static const string & temporaryProcessName();
//! \reimp
virtual const string & boosterTemporaryProcessName() const;
virtual const string &boosterTemporaryProcessName() const;
//! \reimp
virtual char boosterType() const { return type(); }
/*!
* \brief Return a unique character ('e') represtenting the type of EBoosters.
* \return Type character.
*/
static char type();
virtual char boosterType() const;
//! \reimp
virtual const string & socketId() const;

@ -1,46 +0,0 @@
/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of applauncherd
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#include "ebooster.h"
#define DECL_EXPORT __attribute__((visibility("default")))
extern "C"
{
// Create a new plugin instance.
DECL_EXPORT void * create()
{
return new EBooster;
}
DECL_EXPORT char type()
{
return EBooster::type();
}
DECL_EXPORT const char * socketName()
{
return EBooster::socketName().c_str();
}
DECL_EXPORT const char * temporaryProcessName()
{
return EBooster::temporaryProcessName().c_str();
}
}

@ -394,7 +394,7 @@ static void usage(int status)
{
printf("\nUsage: %s [options] [--type=TYPE] [file] [args]\n\n"
"Launch applications compiled as a shared library (-shared) or\n"
"a position independent executable (-pie) through %s.\n\n"
"a position independent executable (-pie) through mapplauncherd.\n\n"
"TYPE chooses the type of booster used. Qt-booster may be used to\n"
"launch anything. Possible values for TYPE:\n"
" q (or qt) Launch a Qt application.\n"
@ -423,7 +423,7 @@ static void usage(int status)
" -T, --test-mode Invoker test mode. Also control file in root home should be in place.\n"
" -h, --help Print this help.\n\n"
"Example: %s --type=m /usr/bin/helloworld\n\n",
PROG_NAME_INVOKER, PROG_NAME_LAUNCHER, EXIT_DELAY, RESPAWN_DELAY, MAX_RESPAWN_DELAY, PROG_NAME_INVOKER);
PROG_NAME_INVOKER, EXIT_DELAY, RESPAWN_DELAY, MAX_RESPAWN_DELAY, PROG_NAME_INVOKER);
exit(status);
}

@ -1,38 +0,0 @@
# Generate list of libraries for preload.h
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/preload-h-libraries.h
COMMAND python ${CMAKE_HOME_DIRECTORY}/scripts/library-helper.py --preload-h-libraries
DEPENDS ${CMAKE_HOME_DIRECTORY}/scripts/library-helper.py
)
# Generate linker command line fragment
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/additional-linked-libraries.ld
COMMAND python ${CMAKE_HOME_DIRECTORY}/scripts/library-helper.py --linker-flags
DEPENDS ${CMAKE_HOME_DIRECTORY}/scripts/library-helper.py
)
# Set sources
set(SRC launcher.c)
# Set include dirs
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/src/common ${CMAKE_CURRENT_BINARY_DIR})
# Set C flags
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -D_POSIX_C_SOURCE=200112L -Wl,--no-as-needed -Wl,@additional-linked-libraries.ld")
# Set precompiler flags
add_definitions(-DLIBRARIES_CONFIG_FILE="/etc/applauncherd.conf")
add_definitions(-DLAUNCHER_LIBRARY="/usr/lib/libapplauncherd.so.0")
link_libraries(${LIBDL})
# Set target
add_executable(applauncherd.bin
${SRC}
${CMAKE_CURRENT_BINARY_DIR}/preload-h-libraries.h
${CMAKE_CURRENT_BINARY_DIR}/additional-linked-libraries.ld)
# Add install rule
install(PROGRAMS applauncherd.bin DESTINATION /usr/bin/)

@ -1,188 +0,0 @@
/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of applauncherd
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
#include <string.h>
#include <malloc.h>
#include "preload.h"
typedef int (*entry_t)(int, char **);
int g_debugPrinting;
//! Load libraries from the given array
static void loadLibraries(const char * const libs[], unsigned int numLibs)
{
for (unsigned int i = 0; i < numLibs; i++)
{
const char * lib = libs[i];
int len = strlen(lib);
if (lib[0] != '#' && len > 1)
{
int flags = 0;
int skipChar = 0;
// "now"
if (lib[0] == 'N')
{
skipChar = 1;
flags = RTLD_NOW | RTLD_GLOBAL;
}
// "lazy"
else if (lib[0] == 'L')
{
skipChar = 1;
flags = RTLD_LAZY | RTLD_GLOBAL;
}
// "deep"
else if (lib[0] == 'D')
{
skipChar = 1;
flags = RTLD_DEEPBIND | RTLD_GLOBAL;
}
// "default"
else
{
skipChar = 0;
flags = RTLD_NOW | RTLD_GLOBAL;
}
// Open the library. Print possible errors only in debug mode.
dlerror();
// coverity[leaked_storage : FALSE]
if (!dlopen(lib + skipChar, flags) && g_debugPrinting)
{
fprintf(stderr, "Warning: can't preload %s\n", lib + skipChar);
}
}
}
}
/*! Invoke launcher daemon library and run main()
*
* Note that argv must have enough dummy space so that
* the argument vector can be altered afterwards.
*
* See e.g. Booster::renameProcess(int parentArgc, char** parentArgv)
* in launcherlib/booster.cpp
*/
static int invokeLauncherLib(int argc, char ** argv)
{
// Clear any existing error
dlerror();
void * handle = dlopen(LAUNCHER_LIBRARY, RTLD_LAZY | RTLD_LOCAL);
if (handle)
{
char * error = NULL;
// Clear any existing error
dlerror();
// Find out address of main
entry_t entry = (entry_t)dlsym(handle, "main");
// Check error
if ((error = dlerror()) != NULL)
{
fprintf(stderr, "%s\n", error);
dlclose(handle);
return 0;
}
entry(argc, argv);
dlclose(handle);
return 1;
}
else
{
fprintf(stderr, "%s\n", dlerror());
return 0;
}
return 1;
}
//! Entry point
int main(int argc, char ** argv)
{
// Exit if DISPLAY is missing. This would result in dying
// boosters and applauncherd would keep on re-starting them.
if (!getenv("DISPLAY"))
{
fprintf(stderr, "FATAL!!: DISPLAY environment variable not set.\n");
return EXIT_FAILURE;
}
// Parse command line
g_debugPrinting = 0;
int helpWanted = 0;
for (int i = 1; i < argc; ++i)
{
if (strcmp(argv[i], "--debug") == 0)
g_debugPrinting = 1;
if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
helpWanted = 1;
}
// Set environment. Because applauncherd is usually a privileged
// process, TMPDIR variable might be unset by the C library. In
// case it's not set, we set it to /var/tmp, which usually is not
// a RAM disk.
setenv("TMPDIR", "/var/tmp", 0);
// Since this application is classified as suid application due to it's credentials
// the environment variables below are not processed by eglibc
// so we're processing this to set correct memory options
char* s = NULL;
if((s = getenv("MALLOC_TRIM_THRESHOLD_")))
mallopt(M_TRIM_THRESHOLD, atoi(s));
if((s = getenv("MALLOC_TOP_PAD_")))
mallopt(M_TOP_PAD, atoi(s));
if((s = getenv("MALLOC_PERTURB_")))
mallopt(M_PERTURB, atoi(s));
if((s = getenv("MALLOC_MMAP_THRESHOLD_")))
mallopt(M_MMAP_THRESHOLD, atoi(s));
if((s = getenv("MALLOC_MMAP_MAX_")))
mallopt(M_MMAP_MAX, atoi(s));
// Preload libraries
if (!helpWanted)
loadLibraries(gLibs, sizeof(gLibs) / sizeof(char *));
// Start the real applauncherd.
if (!invokeLauncherLib(argc, argv))
{
fprintf(stderr, "FATAL!!: Failed to load the launcher library\n");
return EXIT_FAILURE;
}
#ifdef WITH_COVERAGE
__gcov_flush();
#endif
return EXIT_SUCCESS;
}

@ -1,32 +0,0 @@
/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of applauncherd
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#ifndef PRELOAD_H
#define PRELOAD_H
const char * const gLibs[] =
{
// Include the generated set of libraries.
#include "preload-h-libraries.h"
"/usr/bin/single-instance"
};
#endif // PRELOAD_H

@ -2,19 +2,20 @@ set(COMMON ${CMAKE_HOME_DIRECTORY}/src/common)
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${COMMON})
# Find X11
include(FindPkgConfig)
pkg_check_modules(X11 x11 REQUIRED)
add_definitions(-DUSE_X11)
# Hide all symbols except the ones explicitly exported in the code (like main())
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
# Set sources
set(SRC appdata.cpp booster.cpp boosterfactory.cpp boosterpluginregistry.cpp
connection.cpp daemon.cpp logger.cpp main.cpp
set(SRC appdata.cpp booster.cpp connection.cpp daemon.cpp logger.cpp
singleinstance.cpp socketmanager.cpp)
set(HEADERS appdata.h booster.h boosterfactory.h boosterpluginregistry.h
connection.h daemon.h logger.h launcherlib.h singleinstance.h socketmanager.h
${COMMON}/protocol.h)
set(HEADERS appdata.h booster.h connection.h daemon.h logger.h launcherlib.h
singleinstance.h socketmanager.h ${COMMON}/protocol.h)
# Set libraries to be linked. Shared libraries to be preloaded are not linked in anymore,
# but dlopen():ed and listed in src/launcher/preload.h instead.

@ -1,34 +0,0 @@
/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of applauncherd
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#include "boosterfactory.h"
#include "boosterpluginregistry.h"
#include "booster.h"
Booster * BoosterFactory::create(char type)
{
if (BoosterPluginEntry * plugin = BoosterPluginRegistry::pluginEntry(type))
{
return static_cast<Booster *>(plugin->createFunc());
}
else
{
return NULL;
}
}

@ -1,45 +0,0 @@
/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of applauncherd
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#ifndef BOOSTERFACTORY_H
#define BOOSTERFACTORY_H
class Booster;
/*!
* \class BoosterFactory
* \brief BoosterFactory creates a new booster of given type.
*/
// TODO: Could be a namespace instead of a class.
class BoosterFactory
{
public:
/*! \brief Creates a new booster.
* \param type Wanted booster type: 'q' = Qt, 'm' = MeeGo Touch.
* \return Pointer to Booster on success, NULL if failed
*/
static Booster * create(char type);
private:
//! Hidden constructor
BoosterFactory() {};
};
#endif // BOOSTERFACTORY_H

@ -1,121 +0,0 @@
/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of applauncherd
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#include "boosterpluginregistry.h"
#include <dlfcn.h>
BoosterPluginRegistry::RegistryType BoosterPluginRegistry::m_registry;
char BoosterPluginRegistry::validateAndRegisterPlugin(void * handle)
{
// Check if create() is there
dlerror();
create_func_t create = (create_func_t)dlsym(handle, "create");
// Check error
char * error = NULL;
if ((error = dlerror()) != NULL)
{
return 0;
}
// Check if type() is there
dlerror();
type_func_t type = (type_func_t)dlsym(handle, "type");
// Check error
if ((error = dlerror()) != NULL)
{
return 0;
}
// Check if socketName() is there
dlerror();
sn_func_t socketName = (sn_func_t)dlsym(handle, "socketName");
// Check error
if ((error = dlerror()) != NULL)
{
return 0;
}
// Check if temporaryProcessName() is there
dlerror();
tpn_func_t temporaryProcessName = (tpn_func_t)dlsym(handle, "temporaryProcessName");
// Check error
if ((error = dlerror()) != NULL)
{
return 0;
}
registerPlugin(type(), create, socketName, temporaryProcessName);
return type();
}
void BoosterPluginRegistry::registerPlugin(char type,
create_func_t createFunc,
sn_func_t socketNameFunc,
tpn_func_t temporaryProcessNameFunc)
{
BoosterPluginEntry * entry = pluginEntry(type);
if (!entry)
{
entry = new BoosterPluginEntry;
m_registry.push_back(shared_ptr<BoosterPluginEntry>(entry));
}
entry->type = type;
entry->createFunc = createFunc;
entry->socketNameFunc = socketNameFunc;
entry->temporaryProcessNameFunc = temporaryProcessNameFunc;
}
int BoosterPluginRegistry::pluginCount()
{
return m_registry.size();
}
BoosterPluginEntry * BoosterPluginRegistry::pluginEntry(int index)
{
if (index < 0 || index >= static_cast<int>(m_registry.size()))
{
return NULL;
}
return m_registry.at(index).get();
}
BoosterPluginEntry * BoosterPluginRegistry::pluginEntry(char type)
{
BoosterPluginRegistry::RegistryType::const_iterator i = m_registry.begin();
while (i != m_registry.end())
{
if ((*i).get()->type == type)
{
return (*i).get();
}
i++;
}
return NULL;
}

@ -1,101 +0,0 @@
/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of applauncherd
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#ifndef BOOSTERPLUGINREGISTRY_H
#define BOOSTERPLUGINREGISTRY_H
#include <vector>
using std::vector;
#include <tr1/memory>
using std::tr1::shared_ptr;
// Function pointer type for Booster::type()
typedef char (*type_func_t)();
// Function pointer type for Booster::create()
typedef void * (*create_func_t)();
// Function pointer type for Booster::socketName()
typedef const char * (*sn_func_t)();
// Function pointer type for Booster::temporaryProcessName()
typedef const char * (*tpn_func_t)();
//! Item in the registry
struct BoosterPluginEntry
{
//! Booster type
char type;
//! Create function
create_func_t createFunc;
//! Socket name function
sn_func_t socketNameFunc;
//! Temporary process name function
tpn_func_t temporaryProcessNameFunc;
};
/*! \class BoosterPluginRegistry
* \brief BoosterPluginRegistry holds needed data for registered plugins.
*/
class BoosterPluginRegistry
{
public:
/*! Validate given plugin library handle and register to
* BoosterPluginRegistry. Returns the type of the registered
* plugin or 0 if failed.
*/
static char validateAndRegisterPlugin(void * handle);
//! Return number of registered plugins
static int pluginCount();
//! Return pointer to given booster plugin. NULL if not found.
static BoosterPluginEntry * pluginEntry(int index);
//! Return pointer to given booster plugin. NULL if not found.
static BoosterPluginEntry * pluginEntry(char type);
private:
//! Hidden constructor
BoosterPluginRegistry() {};
//! Register a booster plugin
static void registerPlugin(char type,
create_func_t createFunc,
sn_func_t socketNameFunc,
tpn_func_t temporaryProcessNameFunc);
//! Registry
typedef vector<shared_ptr<BoosterPluginEntry> > RegistryType;
static RegistryType m_registry;
#ifdef UNIT_TEST
friend class Ut_BoosterPluginRegistry;
#endif
};
#endif // BOOSTERPLUGINREGISTRY_H

@ -21,8 +21,6 @@
#include "logger.h"
#include "connection.h"
#include "booster.h"
#include "boosterfactory.h"
#include "boosterpluginregistry.h"
#include "singleinstance.h"
#include "socketmanager.h"
@ -49,21 +47,71 @@
extern char ** environ;
Daemon * Daemon::m_instance = NULL;
int Daemon::m_lockFd = -1;
const int Daemon::m_boosterSleepTime = 2;
const std::string Daemon::m_stateDir = std::string(getenv("XDG_RUNTIME_DIR"))+"/applauncherd";
const std::string Daemon::m_stateFile = Daemon::m_stateDir + "/saved-state";
static void sigChldHandler(int)
{
char v = SIGCHLD;
write(Daemon::instance()->sigPipeFd(), &v, 1);
}
static void sigTermHandler(int)
{
char v = SIGTERM;
write(Daemon::instance()->sigPipeFd(), &v, 1);
}
static void sigUsr1Handler(int)
{
char v = SIGUSR1;
write(Daemon::instance()->sigPipeFd(), &v, 1);
}
static void sigUsr2Handler(int)
{
char v = SIGUSR2;
write(Daemon::instance()->sigPipeFd(), &v, 1);
}
static void sigPipeHandler(int)
{
char v = SIGPIPE;
write(Daemon::instance()->sigPipeFd(), &v, 1);
}
static void sigHupHandler(int)
{
char v = SIGHUP;
write(Daemon::instance()->sigPipeFd(), &v, 1);
}
Daemon::Daemon(int & argc, char * argv[]) :
m_daemon(false),
m_debugMode(false),
m_bootMode(false),
m_boosterPid(0),
m_socketManager(new SocketManager),
m_singleInstance(new SingleInstance),
m_reExec(false),
m_notifySystemd(false)
m_notifySystemd(false),
m_booster(0)
{
// Open the log
Logger::openLog(argc > 0 ? argv[0] : "booster");
Logger::logDebug("starting..");
// Install signal handlers. The original handlers are saved
// in the daemon instance so that they can be restored in boosters.
setUnixSignalHandler(SIGCHLD, sigChldHandler); // reap zombies
setUnixSignalHandler(SIGTERM, sigTermHandler); // exit launcher
setUnixSignalHandler(SIGUSR1, sigUsr1Handler); // enter normal mode from boot mode
setUnixSignalHandler(SIGUSR2, sigUsr2Handler); // enter boot mode (same as --boot-mode)
setUnixSignalHandler(SIGPIPE, sigPipeHandler); // broken invoker's pipe
setUnixSignalHandler(SIGHUP, sigHupHandler); // re-exec
if (!Daemon::m_instance)
{
Daemon::m_instance = this;
@ -107,78 +155,14 @@ Daemon * Daemon::instance()
return Daemon::m_instance;
}
bool Daemon::lock()
{
struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 1;
std::stringstream lock_file;
lock_file << getenv("XDG_RUNTIME_DIR") << "/applauncherd.lock";
if((m_lockFd = open(lock_file.str().c_str(), O_WRONLY | O_CREAT, 0666)) == -1)
return false;
if(fcntl(m_lockFd, F_SETLK, &fl) == -1)
return false;
// write pid into the lock file
std::stringstream ss;
ss << getpid();
write(m_lockFd, ss.str().c_str(), ss.str().length());
return true;
}
void Daemon::unlock()
{
if (m_lockFd != -1)
{
close(m_lockFd);
m_lockFd = -1;
}
}
void Daemon::initBoosterSockets()
{
const int numBoosters = BoosterPluginRegistry::pluginCount();
for (int i = 0; i < numBoosters; i++)
{
BoosterPluginEntry * plugin = BoosterPluginRegistry::pluginEntry(i);
if (plugin)
{
Logger::logDebug("Daemon: initing socket: %s", plugin->socketNameFunc());
m_socketManager->initSocket(plugin->socketNameFunc());
}
}
}
void Daemon::forkBoosters()
void Daemon::run(Booster *booster)
{
const int numBoosters = BoosterPluginRegistry::pluginCount();
for (int i = 0; i < numBoosters; i++)
{
BoosterPluginEntry * plugin = BoosterPluginRegistry::pluginEntry(i);
if (plugin)
{
Logger::logDebug("Daemon: forking booster: '%c'", plugin->type);
forkBooster(plugin->type);
}
}
}
m_booster = booster;
void Daemon::run()
{
// Make sure that LD_BIND_NOW does not prevent dynamic linker to
// use lazy binding in later dlopen() calls.
unsetenv("LD_BIND_NOW");
// dlopen() booster plugins
loadBoosterPlugins();
// dlopen single-instance
loadSingleInstancePlugin();
@ -190,11 +174,13 @@ void Daemon::run()
}
else
{
// Create sockets for each of the boosters
initBoosterSockets();
// Create socket for the booster
Logger::logDebug("Daemon: initing socket: %s", booster->socketId().c_str());
m_socketManager->initSocket(booster->socketId());
// Fork each booster for the first time
forkBoosters();
Logger::logDebug("Daemon: forking booster: '%c'", booster->boosterType());
forkBooster();
}
// Notify systemd that init is done
@ -313,15 +299,14 @@ void Daemon::readFromBoosterSocket(int fd)
{
// Store booster - invoker pid pair
// Store booster - invoker socket pair
pid_t boosterPid = boosterPidForType(booster);
if (boosterPid)
if (m_boosterPid)
{
cmsg = CMSG_FIRSTHDR(&msg);
int newFd;
memcpy(&newFd, CMSG_DATA(cmsg), sizeof(int));
Logger::logDebug("Daemon: socket file descriptor: %d\n", newFd);
m_boosterPidToInvokerPid[boosterPid] = invokerPid;
m_boosterPidToInvokerFd[boosterPid] = newFd;
m_boosterPidToInvokerPid[m_boosterPid] = invokerPid;
m_boosterPidToInvokerFd[m_boosterPid] = newFd;
}
}
}
@ -338,7 +323,7 @@ void Daemon::readFromBoosterSocket(int fd)
// to start up before forking new booster. Not doing this would
// slow down the start-up significantly on single core CPUs.
forkBooster(booster, delay);
forkBooster(delay);
}
void Daemon::killProcess(pid_t pid, int signal) const
@ -375,66 +360,17 @@ void Daemon::loadSingleInstancePlugin()
}
}
void Daemon::loadBoosterPlugins()
{
const char* PATTERN = "lib*booster*.so";
const unsigned int BUF_LEN = 256;
if (strlen(PATTERN) + strlen(BOOSTER_PLUGIN_DIR) + 2 > BUF_LEN)
{
Logger::logError("Daemon: path to plugins too long");
return;
}
char buffer[BUF_LEN];
memset(buffer, 0, BUF_LEN);
strcpy(buffer, BOOSTER_PLUGIN_DIR);
strcat(buffer, "/");
strcat(buffer, PATTERN);
// get full path to all plugins
glob_t globbuf;
if (glob(buffer, 0, NULL, &globbuf) == 0)
{
for (__size_t i = 0; i < globbuf.gl_pathc; i++)
{
void *handle = dlopen(globbuf.gl_pathv[i], RTLD_NOW | RTLD_GLOBAL);
if (!handle)
{
Logger::logWarning("Daemon: dlopening booster failed: %s", dlerror());
}
else
{
char newType = BoosterPluginRegistry::validateAndRegisterPlugin(handle);
if (newType)
{
Logger::logDebug("Daemon: Booster of type '%c' loaded.'", newType);
}
else
{
Logger::logWarning("Daemon: Invalid booster plugin: '%s'", buffer);
}
}
}
globfree(&globbuf);
}
else
{
Logger::logError("Daemon: can't find booster plugins");
}
}
void Daemon::forkBooster(char type, int sleepTime)
void Daemon::forkBooster(int sleepTime)
{
if (!BoosterPluginRegistry::pluginEntry(type)) {
Logger::logError("Daemon: Unknown booster type '%c'\n",type);
if (!m_booster) {
// Critical error unknown booster type. Exiting applauncherd.
_exit(EXIT_FAILURE);
}
char type = m_booster->boosterType();
// Invalidate current booster pid for the given type
setPidToBooster(type, 0);
m_boosterPid = 0;
// Fork a new process
pid_t newPid = fork();
@ -457,12 +393,6 @@ void Daemon::forkBooster(char type, int sleepTime)
close(m_sigPipeFd[0]);
close(m_sigPipeFd[1]);
// Close unused sockets inherited from daemon
closeUnusedSockets(type);
// Close lock file, it's not needed in the booster
Daemon::unlock();
// Close socket file descriptors
FdMap::iterator i(m_boosterPidToInvokerFd.begin());
while (i != m_boosterPidToInvokerFd.end())
@ -485,29 +415,20 @@ void Daemon::forkBooster(char type, int sleepTime)
Logger::logDebug("Daemon: Running a new Booster of type '%c'", type);
// Create a new booster, initialize and run it
Booster * booster = BoosterFactory::create(type);
if (booster)
{
// Initialize and wait for commands from invoker
booster->initialize(m_initialArgc, m_initialArgv, m_boosterLauncherSocket[1],
m_socketManager->findSocket(booster->socketId().c_str()),
m_singleInstance, m_bootMode);
// Initialize and wait for commands from invoker
m_booster->initialize(m_initialArgc, m_initialArgv, m_boosterLauncherSocket[1],
m_socketManager->findSocket(m_booster->socketId().c_str()),
m_singleInstance, m_bootMode);
// Run the current Booster
int retval = booster->run(m_socketManager);
// Run the current Booster
int retval = m_booster->run(m_socketManager);
// Finish
delete booster;
// Finish
delete m_booster;
// _exit() instead of exit() to avoid situation when destructors
// for static objects may be run incorrectly
_exit(retval);
}
else
{
throw std::runtime_error(std::string("Daemon: Unknown booster type '") + type + "'");
}
// _exit() instead of exit() to avoid situation when destructors
// for static objects may be run incorrectly
_exit(retval);
}
else /* Parent process */
{
@ -516,7 +437,7 @@ void Daemon::forkBooster(char type, int sleepTime)
// Set current process ID globally to the given booster type
// so that we now which booster to restart when booster exits.
setPidToBooster(type, newPid);
m_boosterPid = newPid;
}
}
@ -581,10 +502,9 @@ void Daemon::reapZombies()
}
// Check if pid belongs to a booster and restart the dead booster if needed
char type = boosterTypeForPid(pid);
if (type != 0)
if (pid == m_boosterPid)
{
forkBooster(type, m_boosterSleepTime);
forkBooster(m_boosterSleepTime);
}
}
else
@ -594,46 +514,6 @@ void Daemon::reapZombies()
}
}
void Daemon::setPidToBooster(char type, pid_t pid)
{
m_boosterTypeToPid[type] = pid;
}
char Daemon::boosterTypeForPid(pid_t pid) const
{
TypeMap::const_iterator i = m_boosterTypeToPid.begin();
while (i != m_boosterTypeToPid.end())
{
if (i->second == pid)
{
return i->first;
}
i++;
}
return 0;
}
pid_t Daemon::boosterPidForType(char type) const
{
TypeMap::const_iterator i = m_boosterTypeToPid.find(type);
return i == m_boosterTypeToPid.end() ? 0 : i->second;
}
void Daemon::closeUnusedSockets(char type)
{
const int numBoosters = BoosterPluginRegistry::pluginCount();
for (int i = 0; i < numBoosters; i++)
{
BoosterPluginEntry * plugin = BoosterPluginRegistry::pluginEntry(i);
if (plugin && (plugin->type != type))
{
m_socketManager->closeSocket(plugin->socketNameFunc());
}
}
}
void Daemon::daemonize()
{
// Our process ID and Session ID
@ -661,11 +541,6 @@ void Daemon::daemonize()
exit(EXIT_SUCCESS);
}
// Check the lock
// Note: file locking must be done after forking, otherwise lock belongs to parent process
if(!Daemon::lock())
throw std::runtime_error(std::string(PROG_NAME_LAUNCHER) + " is already running\n");
// Change the file mode mask
umask(0);
@ -723,7 +598,7 @@ void Daemon::parseArgs(const ArgVect & args)
}
else if ((*i) == "--help" || (*i) == "-h")
{
usage(EXIT_SUCCESS);
usage(args[0].c_str(), EXIT_SUCCESS);
}
else if ((*i) == "--re-exec")
{
@ -736,13 +611,13 @@ void Daemon::parseArgs(const ArgVect & args)
else
{
if ((*i).find_first_not_of(' ') != string::npos)
usage(EXIT_FAILURE);
usage(args[0].c_str(), EXIT_FAILURE);
}
}
}
// Prints the usage and exits with given status
void Daemon::usage(int status)
void Daemon::usage(const char *name, int status)
{
printf("\nUsage: %s [options]\n\n"
"Start the application launcher daemon.\n\n"
@ -758,7 +633,7 @@ void Daemon::usage(int status)
" --systemd Notify systemd when initialization is done\n"
" --debug Enable debug messages and log everything also to stdout.\n"
" -h, --help Print this help.\n\n",
PROG_NAME_LAUNCHER, PROG_NAME_LAUNCHER, PROG_NAME_LAUNCHER);
name, name, name);
exit(status);
}
@ -804,14 +679,10 @@ void Daemon::enterBootMode()
void Daemon::killBoosters()
{
TypeMap::iterator iter(m_boosterTypeToPid.begin());
while (iter != m_boosterTypeToPid.end())
{
killProcess(iter->second, SIGTERM);
iter++;
}
if (m_boosterPid)
killProcess(m_boosterPid, SIGTERM);
// NOTE!!: m_boosterTypeToPid must not be cleared
// NOTE!!: m_boosterPid must not be cleared
// in order to automatically start new boosters.
}
@ -853,9 +724,7 @@ Daemon::~Daemon()
delete m_socketManager;
delete m_singleInstance;
#ifdef WITH_COVERAGE
__gcov_flush();
#endif
Logger::closeLog();
}
void Daemon::reExec()
@ -915,10 +784,7 @@ void Daemon::reExec()
ss << "booster-invoker-fd " << it->first << " " << it->second << std::endl;
}
for(TypeMap::iterator it = m_boosterTypeToPid.begin(); it != m_boosterTypeToPid.end(); it++)
{
ss << "booster-type " << (it->first) << " " << it->second << std::endl;
}
ss << "booster-pid " << m_boosterPid << std::endl;
ss << "launcher-socket " << m_boosterLauncherSocket[0] << " " << m_boosterLauncherSocket[1] << std::endl;
@ -926,8 +792,6 @@ void Daemon::reExec()
ss << "boot-mode " << m_bootMode << std::endl;
ss << "lock-file " << m_lockFd << std::endl;
SocketManager::SocketHash s = m_socketManager->getState();
for(SocketManager::SocketHash::iterator it = s.begin(); it != s.end(); it++)
{
@ -1043,15 +907,13 @@ void Daemon::restoreState()
Logger::logDebug("Daemon: restored m_boosterPidToInvokerFd[%d] = %d", arg1, arg2);
m_boosterPidToInvokerFd[arg1] = arg2;
}
else if (token == "booster-type")
else if (token == "booster-pid")
{
std::string arg1;
int arg2;
int arg1;
ss >> arg1;
ss >> arg2;
Logger::logDebug("Daemon: restored m_boosterTypeToPid[%c] = %d", arg1[0], arg2);
Logger::logDebug("Daemon: restored m_boosterPid = %d", arg1);
m_boosterTypeToPid[arg1[0]] = arg2;
m_boosterPid = arg1;
}
else if (token == "launcher-socket")
{
@ -1071,13 +933,6 @@ void Daemon::restoreState()
m_sigPipeFd[0] = arg1;
m_sigPipeFd[1] = arg2;
}
else if (token == "lock-file")
{
int arg1;
ss >> arg1;
Logger::logDebug("Daemon: restored m_lockFd = %d", arg1);
Daemon::m_lockFd = arg1;
}
else if (token == "socket-hash")
{
std::string arg1;

@ -20,6 +20,8 @@
#ifndef DAEMON_H
#define DAEMON_H
#include "launcherlib.h"
#include <string>
using std::string;
@ -53,7 +55,7 @@ class SingleInstance;
* application, listens connections from the invoker and forks Booster
* processes.
*/
class Daemon
class DECL_EXPORT Daemon
{
public:
@ -74,7 +76,7 @@ public:
/*!
* \brief Run main loop and fork Boosters.
*/
void run();
void run(Booster *booster);
/*! \brief Return the one-and-only Daemon instance.
* \return Pointer to the Daemon instance.
@ -84,12 +86,6 @@ public:
//! \brief Reapes children processes gone zombies (finished Boosters).
void reapZombies();
//! Lock file to prevent launch of second instance
static bool lock();
//! Unlock file (lock is not needed in boosters)
static void unlock();
/*!
* Get fd to which signal handler writes the number
* of an arriving Unix signal.
@ -125,35 +121,14 @@ private:
void forkKiller();
//! Forks and initializes a new Booster
void forkBooster(char type, int sleepTime = 0);
//! Init sockects used to communicate with boosters
void initBoosterSockets();
//! Fork all registered boosters
void forkBoosters();
void forkBooster(int sleepTime = 0);
//! Kill given pid with SIGKILL by default
void killProcess(pid_t pid, int signal = SIGKILL) const;
//! Load (dlopen()) booster plugins
void loadBoosterPlugins();
//! Load single-instance plugin
void loadSingleInstancePlugin();
//! Assign given pid to given booster
void setPidToBooster(char type, pid_t pid);
//! Return booster type for given pid. Return 0 if fails.
char boosterTypeForPid(pid_t pid) const;
//! Return pid for given booster type. Return 0 if fails.
pid_t boosterPidForType(char type) const;
//! Close all sockets NOT used by the given booster type.
void closeUnusedSockets(char type);
//! Read and process data from a booster pipe
void readFromBoosterSocket(int fd);
@ -167,7 +142,7 @@ private:
void killBoosters();
//! Prints the usage and exits with given status
void usage(int status);
void usage(const char *name, int status);
//! Re-exec applauncherd.bin
void reExec();
@ -201,9 +176,8 @@ private:
typedef map<pid_t, pid_t> FdMap;
FdMap m_boosterPidToInvokerFd;
//! Mapping for booster type <-> pid
typedef map<char, pid_t> TypeMap;
TypeMap m_boosterTypeToPid;
//! Current booster pid
pid_t m_boosterPid;
//! Socket pair used to tell the parent that a new booster is needed +
//! some parameters.
@ -221,9 +195,6 @@ private:
//! Singleton Daemon instance
static Daemon * m_instance;
//! File descriptor of the lock file
static int m_lockFd;
//! Time to sleep before forking a new booster
static const int m_boosterSleepTime;
@ -243,6 +214,9 @@ private:
//! True if systemd needs to be notified
bool m_notifySystemd;
//! Booster instance
Booster * m_booster;
//! Name of the state saving directory and file
static const std::string m_stateDir;
static const std::string m_stateFile;

@ -32,7 +32,7 @@ bool Logger::m_debugMode = false;
void Logger::openLog(const char * progName)
{
if (!progName)
progName = PROG_NAME_LAUNCHER;
progName = "mapplauncherd";
if (Logger::m_isOpened)
{

@ -1,123 +0,0 @@
/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of applauncherd
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#include "daemon.h"
#include "logger.h"
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <signal.h>
#include <fcntl.h>
#include <sys/file.h>
#include <stdexcept>
int g_sigPipeFd = -1;
char g_pipeDataSigChld = SIGCHLD;
char g_pipeDataSigTerm = SIGTERM;
char g_pipeDataSigUsr1 = SIGUSR1;
char g_pipeDataSigUsr2 = SIGUSR2;
char g_pipeDataSigPipe = SIGPIPE;
char g_pipeDataSigHup = SIGHUP;
static void sigChldHandler(int)
{
write(g_sigPipeFd, &g_pipeDataSigChld, 1);
}
static void sigTermHandler(int)
{
write(g_sigPipeFd, &g_pipeDataSigTerm, 1);
}
static void sigUsr1Handler(int)
{
write(g_sigPipeFd, &g_pipeDataSigUsr1, 1);
}
static void sigUsr2Handler(int)
{
write(g_sigPipeFd, &g_pipeDataSigUsr2, 1);
}
static void sigPipeHandler(int)
{
write(g_sigPipeFd, &g_pipeDataSigPipe, 1);
}
static void sigHupHandler(int)
{
write(g_sigPipeFd, &g_pipeDataSigHup, 1);
}
//! Main function
extern "C" DECL_EXPORT int main(int argc, char * argv[])
{
// Open the log
Logger::openLog(PROG_NAME_LAUNCHER);
Logger::logDebug("%s starting..", PROG_NAME_LAUNCHER);
// Check that an instance of launcher is not already running already
// here if we are not going to fork. In that case the lock should be
// checked after fork() is done in Daemon::daemonize
std::vector<std::string> args(argv, argv + argc);
if (find(args.begin(), args.end(), "-d") == args.end() &&
find(args.begin(), args.end(), "--daemon") == args.end())
{
if(!Daemon::lock())
{
Logger::logError("%s is already running \n", PROG_NAME_LAUNCHER);
return EXIT_FAILURE;
}
}
try
{
// Create main daemon instance
Daemon myDaemon(argc, argv);
// Get fd for signal pipe.
g_sigPipeFd = myDaemon.sigPipeFd();
// Install signal handlers. The original handlers are saved
// in the daemon instance so that they can be restored in boosters.
myDaemon.setUnixSignalHandler(SIGCHLD, sigChldHandler); // reap zombies
myDaemon.setUnixSignalHandler(SIGTERM, sigTermHandler); // exit launcher
myDaemon.setUnixSignalHandler(SIGUSR1, sigUsr1Handler); // enter normal mode from boot mode
myDaemon.setUnixSignalHandler(SIGUSR2, sigUsr2Handler); // enter boot mode (same as --boot-mode)
myDaemon.setUnixSignalHandler(SIGPIPE, sigPipeHandler); // broken invoker's pipe
myDaemon.setUnixSignalHandler(SIGHUP, sigHupHandler); // re-exec
// Run the main loop
myDaemon.run();
// Close the log
Logger::closeLog();
}
catch (std::runtime_error & e)
{
Logger::logError(e.what());
std::cout << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

@ -1,9 +0,0 @@
#!/bin/sh
# Use 50 chars long dummy parameter to reserve place for application
# name and parameters so that we get some space to modify the argument
# list seen in /proc/[PID]/cmdline.
# If the length of the application name with parameters is longer than space
# available, parameters will be cut off. The main function will still always
# get the complete argument list.
exec /usr/bin/applauncherd.bin $@ " "

@ -1,9 +0,0 @@
#!/bin/sh
# Use 50 chars long dummy parameter to reserve place for application
# name and parameters so that we get some space to modify the argument
# list seen in /proc/[PID]/cmdline.
# If the length of the application name with parameters is longer than space
# available, parameters will be cut off. The main function will still always
# get the complete argument list.
exec /usr/bin/applauncherd.bin --debug $@ " "

@ -8,10 +8,8 @@ endif (${QTVERSION} VERSION_LESS 4.6.0)
add_subdirectory(ut_booster)
add_subdirectory(ut_connection)
add_subdirectory(ut_daemon)
add_subdirectory(ut_ebooster)
add_subdirectory(ut_socketmanager)
add_subdirectory(ut_singleinstance)
add_subdirectory(ut_boosterpluginregistry)
add_subdirectory(ut_appdata)
add_subdirectory(ut_logger)

@ -34,10 +34,6 @@
<step expected_result="0">/usr/share/applauncherd-tests/ut_booster</step>
</case>
<case name="EBooster" type="Functional" description="Unit tests for EBooster class" level="Component" timeout="20">
<step expected_result="0">su - user -c 'source /tmp/session_bus_address.user &amp;&amp; DISPLAY=:0 /usr/share/applauncherd-tests/ut_ebooster'</step>
</case>
<environments>
<scratchbox>true</scratchbox>
<hardware>true</hardware>
@ -62,21 +58,6 @@
</get-->
</set>
<set name="boosterpluginregistry-test" description="BoosterPluginRegistry unit tests" feature="AF BoosterPluginRegistry for Launcher daemon" requirement="1131430" >
<case name="BoosterPluginRegistry" type="Functional" description="Unit tests for BoosterPluginRegistry class" level="Component" timeout="20">
<step expected_result="0">su - user -c 'source /tmp/session_bus_address.user &amp;&amp; DISPLAY=:0 /usr/share/applauncherd-tests/ut_boosterpluginregistry'</step>
</case>
<environments>
<scratchbox>true</scratchbox>
<hardware>true</hardware>
</environments>
<!--get>
</get-->
</set>
<set name="logger-test" description="Logger unit tests" feature="AF Logger for Launcher daemon" requirement="1131430" >
<case name="Logger" type="Functional" description="Unit tests for Logger class" level="Component" timeout="20">

@ -1,37 +0,0 @@
set(LAUNCHER ${CMAKE_HOME_DIRECTORY}/src/launcherlib)
set(DESTINATION "/usr/share/applauncherd-tests/")
add_definitions(-DTEST_LIB_CREATE_PATH="${DESTINATION}libutwithcreate.so")
add_definitions(-DTEST_LIB_CREATETYPE_PATH="${DESTINATION}libutwithcreatetype.so")
add_definitions(-DTEST_LIB_CREATETYPESOCKETNAME_PATH="${DESTINATION}libutwithcreatetypesocketname.so")
add_definitions(-DTEST_LIB_PLUGIN_PATH="${DESTINATION}libutplugin.so")
# Set sources
set(SRC ut_boosterpluginregistry.cpp ${LAUNCHER}/boosterpluginregistry.cpp)
# Set moc headers
set(MOC_HDRS ut_boosterpluginregistry.h)
# Run moc
qt4_wrap_cpp(MOC_SRC ${MOC_HDRS})
# Enable test library
set(QT_USE_QTTEST TRUE)
# Set include paths
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${LAUNCHER})
link_libraries(${QT_QTCORE_LIBRARY} ${QT_QTTEST_LIBRARY} -ldl)
# Enable Qt (may not be needed, because already defined on higher level)
include(${QT_USE_FILE})
add_executable(ut_boosterpluginregistry ${SRC} ${MOC_SRC})
add_library(utwithcreate MODULE ut_library_withcreate.cpp)
add_library(utwithcreatetype MODULE ut_library_withcreatetype.cpp)
add_library(utwithcreatetypesocketname MODULE ut_library_withcreatetypesocketName.cpp)
add_library(utplugin MODULE ut_library_plugin.cpp)
# Install
install(PROGRAMS ut_boosterpluginregistry DESTINATION ${DESTINATION})
install(FILES libutwithcreate.so libutwithcreatetype.so libutwithcreatetypesocketname.so libutplugin.so DESTINATION ${DESTINATION})

@ -1,110 +0,0 @@
/***************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of applauncherd
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#include "ut_boosterpluginregistry.h"
#include "boosterpluginregistry.h"
#include <dlfcn.h>
Ut_BoosterPluginRegistry::Ut_BoosterPluginRegistry()
{}
Ut_BoosterPluginRegistry::~Ut_BoosterPluginRegistry()
{}
void Ut_BoosterPluginRegistry::initTestCase()
{}
void Ut_BoosterPluginRegistry::cleanupTestCase()
{}
void Ut_BoosterPluginRegistry::testValidateAndRegisterPlugin()
{
void * handle = NULL;
//positive
handle = dlopen(TEST_LIB_PLUGIN_PATH, RTLD_NOW);
QVERIFY(handle);
char pluginType = BoosterPluginRegistry::validateAndRegisterPlugin(handle);
QVERIFY(pluginType == 'z');
//negative invalid handle
handle = NULL;
QVERIFY(BoosterPluginRegistry::validateAndRegisterPlugin(handle) == false);
//negative no "type" symbol in the plugin (only create)
handle = dlopen(TEST_LIB_CREATE_PATH, RTLD_NOW);
QVERIFY(handle);
QVERIFY(BoosterPluginRegistry::validateAndRegisterPlugin(handle) == false);
//negative no "socketName" symbol in the plugin (only create and type)
handle = dlopen(TEST_LIB_CREATETYPE_PATH, RTLD_NOW);
QVERIFY(handle);
QVERIFY(BoosterPluginRegistry::validateAndRegisterPlugin(handle) == false);
//negative no "temporaryProcessName" symbol in the plugin (only create, type and sockeName)
handle = dlopen(TEST_LIB_CREATETYPESOCKETNAME_PATH, RTLD_NOW);
QVERIFY(handle);
QVERIFY(BoosterPluginRegistry::validateAndRegisterPlugin(handle) == false);
}
void Ut_BoosterPluginRegistry::testRegisterPlugin()
{
void * handle = dlopen(TEST_LIB_PLUGIN_PATH, RTLD_NOW);
QVERIFY(handle);
dlerror();
create_func_t createFunc = (create_func_t)dlsym(handle, "create");
QVERIFY(dlerror() == NULL);
sn_func_t socketNameFunc = (sn_func_t)dlsym(handle, "socketName");
QVERIFY(dlerror() == NULL);
tpn_func_t temporaryProcessNameFunc = (tpn_func_t)dlsym(handle, "temporaryProcessName");
QVERIFY(dlerror() == NULL);
BoosterPluginRegistry::registerPlugin('0', createFunc, socketNameFunc, temporaryProcessNameFunc); //register new plugin with type '0'
BoosterPluginEntry * pluginEntry = BoosterPluginRegistry::pluginEntry('0');
QVERIFY(pluginEntry);
QVERIFY(pluginEntry->type == '0');
}
void Ut_BoosterPluginRegistry::testPluginEntry()
{
//positive
void * handle = dlopen(TEST_LIB_PLUGIN_PATH, RTLD_NOW);
QVERIFY(handle);
BoosterPluginRegistry::validateAndRegisterPlugin(handle);
BoosterPluginEntry * pluginEntry = BoosterPluginRegistry::pluginEntry('z');
QVERIFY(pluginEntry);
QVERIFY(pluginEntry->type == 'z');
//negative with negative index for int type constructor
QVERIFY(BoosterPluginRegistry::pluginEntry(-100) == false);
//negative with index larger then registered plugins count
int index;
index = BoosterPluginRegistry::pluginCount() + 1;
QVERIFY(BoosterPluginRegistry::pluginEntry(index) == false);
//negative with unregistered plugin type
QVERIFY(BoosterPluginRegistry::pluginEntry('1') == false);
}
QTEST_APPLESS_MAIN(Ut_BoosterPluginRegistry)

@ -1,47 +0,0 @@
/***************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of applauncherd
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#ifndef UT_BOOSTERPLUGINREGISTRY_H
#define UT_BOOSTERPLUGINREGISTRY_H
#include<QtTest/QtTest>
#include<QObject>
#define UNIT_TEST
class BoosterPluginRegistry;
class Ut_BoosterPluginRegistry : public QObject
{
Q_OBJECT
public:
Ut_BoosterPluginRegistry();
virtual ~Ut_BoosterPluginRegistry();
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
void testValidateAndRegisterPlugin();
void testRegisterPlugin();
void testPluginEntry();
};
#endif // UT_BOOSTERPLUGINREGISTRY_H

@ -1,42 +0,0 @@
/***************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of applauncherd
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#define DECL_EXPORT extern "C" __attribute__ ((__visibility__("default")))
extern "C"
{
DECL_EXPORT void create()
{
}
DECL_EXPORT char type()
{
return 'z';
}
DECL_EXPORT const char * socketName()
{
return 0;
}
DECL_EXPORT const char * temporaryProcessName()
{
return 0;
}
}

@ -1,26 +0,0 @@
/***************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of applauncherd
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#define DECL_EXPORT extern "C" __attribute__ ((__visibility__("default")))
extern "C"
{
DECL_EXPORT void create()
{
}
}

@ -1,31 +0,0 @@
/***************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of applauncherd
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#define DECL_EXPORT extern "C" __attribute__ ((__visibility__("default")))
extern "C"
{
DECL_EXPORT void create()
{
}
DECL_EXPORT void type()
{
}
}

@ -1,35 +0,0 @@
/***************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of applauncherd
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#define DECL_EXPORT extern "C" __attribute__ ((__visibility__("default")))
extern "C"
{
DECL_EXPORT void create()
{
}
DECL_EXPORT void type()
{
}
DECL_EXPORT void socketName()
{
}
}

@ -2,7 +2,6 @@ set(LAUNCHER ${CMAKE_HOME_DIRECTORY}/src/launcherlib)
# Set sources
set(SRC ut_connection.cpp ${LAUNCHER}/appdata.cpp ${LAUNCHER}/booster.cpp
${LAUNCHER}/boosterfactory.cpp ${LAUNCHER}/boosterpluginregistry.cpp
${LAUNCHER}/daemon.cpp ${LAUNCHER}/connection.cpp ${LAUNCHER}/logger.cpp
${LAUNCHER}/singleinstance.cpp ${LAUNCHER}/socketmanager.cpp)

@ -2,7 +2,7 @@
set(LAUNCHER ${CMAKE_HOME_DIRECTORY}/src/launcherlib)
set(COMMON "${CMAKE_HOME_DIRECTORY}/src/common")
set(SRC ut_daemon.cpp ${LAUNCHER}/appdata.cpp ${LAUNCHER}/booster.cpp ${LAUNCHER}/boosterfactory.cpp ${LAUNCHER}/boosterpluginregistry.cpp ${LAUNCHER}/daemon.cpp
set(SRC ut_daemon.cpp ${LAUNCHER}/appdata.cpp ${LAUNCHER}/booster.cpp ${LAUNCHER}/daemon.cpp
${LAUNCHER}/connection.cpp ${LAUNCHER}/logger.cpp
${LAUNCHER}/singleinstance.cpp ${LAUNCHER}/socketmanager.cpp)

@ -86,39 +86,13 @@ void Ut_Daemon::testReapZombies()
QVERIFY(m_subject->m_children.size() == 0);
}
void Ut_Daemon::testSetPidToBooster()
{
m_subject->setPidToBooster('a', 2);
m_subject->setPidToBooster('b', 1);
QVERIFY(m_subject->boosterTypeForPid(2) == 'a');
QVERIFY(m_subject->boosterPidForType('a') == 2);
QVERIFY(m_subject->boosterTypeForPid(1) == 'b');
QVERIFY(m_subject->boosterPidForType('b') == 1);
QVERIFY(m_subject->boosterTypeForPid(3) == 0);
QVERIFY(m_subject->boosterPidForType('c') == 0);
}
void Ut_Daemon::testLock()
{
//negative testcase with already locked soket (it's locked by running applauncherd)
QVERIFY(Daemon::lock() == false);
//negative testcase with wrong lock file descriptor
Daemon::unlock();
m_subject->m_lockFd = -1;
QVERIFY(Daemon::lock() == false);
}
void Ut_Daemon::testForkBooster()
{
//negative testcase for unregistered booster type '0'
pid_t pid = fork();
if (pid == 0) { // child
// Code only executed by child process
m_subject->forkBooster('0');
m_subject->forkBooster();
QFAIL("Not exited on invalid booster type");
_exit(0); //exit from child if something goes wrong
} else if (pid < 0) { // failed to fork

@ -44,8 +44,6 @@ private Q_SLOTS:
void testParseArgs();
void testVerifyInstance();
void testReapZombies();
void testSetPidToBooster();
void testLock();
void testForkBooster();
void testReadFromBoosterSocket();

@ -1,32 +0,0 @@
set(LAUNCHER ${CMAKE_HOME_DIRECTORY}/src/launcherlib)
set(EBOOSTER ${CMAKE_HOME_DIRECTORY}/src/ebooster)
set(COMMON "${CMAKE_HOME_DIRECTORY}/src/common")
# Set sources
set(SRC ut_ebooster.cpp ${LAUNCHER}/appdata.cpp ${LAUNCHER}/booster.cpp
${LAUNCHER}/connection.cpp
${LAUNCHER}/logger.cpp ${EBOOSTER}/ebooster.cpp
${LAUNCHER}/singleinstance.cpp ${LAUNCHER}/socketmanager.cpp)
# Set moc headers
set(MOC_HDRS ut_ebooster.h)
# Run moc
qt4_wrap_cpp(MOC_SRC ${MOC_HDRS})
# Enable test library
set(QT_USE_QTTEST TRUE)
# Set include paths
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/src/common ${LAUNCHER} ${EBOOSTER})
link_libraries(${QT_QTCORE_LIBRARY} ${QT_QTTEST_LIBRARY} ${X11_LIBRARIES} -ldl)
# Enable Qt (may not be needed, because already defined on higher level)
include(${QT_USE_FILE})
add_executable(ut_ebooster ${SRC} ${MOC_SRC} )
# Install
install(PROGRAMS ut_ebooster DESTINATION /usr/share/applauncherd-tests/)

@ -1,67 +0,0 @@
/***************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of applauncherd
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#include "ut_ebooster.h"
#include "ebooster.h"
#include <errno.h>
Ut_EBooster::Ut_EBooster() :
m_subject(new EBooster)
{}
Ut_EBooster::~Ut_EBooster()
{}
void Ut_EBooster::initTestCase()
{}
void Ut_EBooster::cleanupTestCase()
{}
void Ut_EBooster::testSocketName()
{
QVERIFY(EBooster::socketName() == EBooster::m_socketId);
QVERIFY(m_subject->socketId() == EBooster::m_socketId);
}
void Ut_EBooster::testType()
{
QVERIFY(EBooster::type() == 'e');
QVERIFY(m_subject->boosterType() == 'e');
}
void Ut_EBooster::testPreload()
{
QVERIFY(m_subject->preload());
}
void Ut_EBooster::testTemporaryProcessName()
{
QVERIFY(EBooster::temporaryProcessName() == EBooster::m_temporaryProcessName);
QVERIFY(m_subject->temporaryProcessName() == EBooster::m_temporaryProcessName);
QVERIFY(m_subject->boosterTemporaryProcessName() == EBooster::m_temporaryProcessName);
}
void Ut_EBooster::testLaunchProcessWithBadArg()
{
QVERIFY(m_subject->launchProcess() == EXIT_FAILURE);
}
QTEST_APPLESS_MAIN(Ut_EBooster);

@ -1,53 +0,0 @@
/***************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of applauncherd
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#ifndef UT_EBOOSTER_H
#define UT_EBOOSTER_H
#include<QtTest/QtTest>
#include<QObject>
#include <tr1/memory>
#define UNIT_TEST
class EBooster;
class Ut_EBooster : public QObject
{
Q_OBJECT
public:
Ut_EBooster();
virtual ~Ut_EBooster();
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
void testSocketName();
void testType();
void testPreload();
void testTemporaryProcessName();
void testLaunchProcessWithBadArg();
private:
std::tr1::shared_ptr<EBooster> m_subject;
};
#endif // UT_EBOOSTER_H
Loading…
Cancel
Save