summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSergio Ahumada <sergio.ahumada@nokia.com>2012-01-31 18:52:45 +0100
committerSergio Ahumada <sergio.ahumada@nokia.com>2012-01-31 18:52:45 +0100
commit0fc5c9bc9f113d8783e2b44b6686b5b5a1cba7c7 (patch)
treec859b20fc2770548d60ec7137a180fae70678dec
Long live Qt Process Manager!
-rw-r--r--.gitignore11
-rw-r--r--config.pri5
-rw-r--r--doc/doc.pri9
-rw-r--r--doc/images/process_structs.pngbin0 -> 10306 bytes
-rw-r--r--doc/images/processbackend_hierarchy.pngbin0 -> 9517 bytes
-rw-r--r--doc/images/processbackendfactory_hierarchy.pngbin0 -> 12219 bytes
-rw-r--r--doc/processmanager.qdocconf78
-rw-r--r--doc/src/basicpm.qdoc118
-rw-r--r--doc/src/index.qdoc62
-rw-r--r--doc/src/intro.qdoc54
-rw-r--r--doc/src/namespace.qdoc69
-rw-r--r--doc/src/processinfo.qdoc73
-rw-r--r--doc/src/qmlpm.qdoc72
-rw-r--r--doc/src/standardpm.qdoc167
-rw-r--r--doc/style/style.css146
-rwxr-xr-xinclude/qtprocessmanager/syncheaders.sh13
-rw-r--r--processmanager.pro14
-rw-r--r--src/core/core-lib.pri52
-rw-r--r--src/core/core.pri10
-rw-r--r--src/core/core.pro16
-rw-r--r--src/core/gdbprocessbackendfactory.cpp95
-rw-r--r--src/core/gdbprocessbackendfactory.h60
-rw-r--r--src/core/memorystatistics_p.h73
-rw-r--r--src/core/pipeprocessbackendfactory.cpp213
-rw-r--r--src/core/pipeprocessbackendfactory.h76
-rw-r--r--src/core/prelaunchprocessbackend.cpp228
-rw-r--r--src/core/prelaunchprocessbackend.h91
-rw-r--r--src/core/prelaunchprocessbackendfactory.cpp160
-rw-r--r--src/core/prelaunchprocessbackendfactory.h77
-rw-r--r--src/core/process.cpp107
-rw-r--r--src/core/process.h64
-rw-r--r--src/core/processbackend.cpp464
-rw-r--r--src/core/processbackend.h117
-rw-r--r--src/core/processbackendfactory.cpp118
-rw-r--r--src/core/processbackendfactory.h74
-rw-r--r--src/core/processbackendmanager.cpp154
-rw-r--r--src/core/processbackendmanager.h78
-rw-r--r--src/core/processfrontend.cpp525
-rw-r--r--src/core/processfrontend.h146
-rw-r--r--src/core/processinfo.cpp551
-rw-r--r--src/core/processinfo.h149
-rw-r--r--src/core/processmanager-global.h70
-rw-r--r--src/core/processmanager.cpp292
-rw-r--r--src/core/processmanager.h104
-rw-r--r--src/core/procutils.cpp142
-rw-r--r--src/core/procutils.h65
-rw-r--r--src/core/remoteprocessbackend.cpp296
-rw-r--r--src/core/remoteprocessbackend.h88
-rw-r--r--src/core/remoteprocessbackendfactory.cpp174
-rw-r--r--src/core/remoteprocessbackendfactory.h75
-rw-r--r--src/core/socketprocessbackendfactory.cpp131
-rw-r--r--src/core/socketprocessbackendfactory.h72
-rw-r--r--src/core/standardprocessbackend.cpp115
-rw-r--r--src/core/standardprocessbackend.h66
-rw-r--r--src/core/standardprocessbackendfactory.cpp83
-rw-r--r--src/core/standardprocessbackendfactory.h61
-rw-r--r--src/core/unixprocessbackend.cpp332
-rw-r--r--src/core/unixprocessbackend.h99
-rw-r--r--src/core/unixsandboxprocess.cpp85
-rw-r--r--src/core/unixsandboxprocess.h66
-rw-r--r--src/declarative/.gitignore1
-rw-r--r--src/declarative/declarative-lib.pri12
-rw-r--r--src/declarative/declarative.pri12
-rw-r--r--src/declarative/declarative.pro25
-rw-r--r--src/declarative/declarativeprocess.cpp100
-rw-r--r--src/declarative/declarativeprocess.h37
-rw-r--r--src/declarative/declarativeprocessmanager.cpp280
-rw-r--r--src/declarative/declarativeprocessmanager.h92
-rw-r--r--src/declarative/plugin.cpp28
-rw-r--r--src/declarative/processinfotemplate.cpp507
-rw-r--r--src/declarative/processinfotemplate.h130
-rw-r--r--src/declarative/qmldir1
-rw-r--r--src/launcher/launcher-lib.pri14
-rw-r--r--src/launcher/launcher.pri13
-rw-r--r--src/launcher/launcher.pro20
-rw-r--r--src/launcher/launcherclient.cpp213
-rw-r--r--src/launcher/launcherclient.h80
-rw-r--r--src/launcher/main.cpp53
-rw-r--r--src/launcher/pipelauncher.cpp141
-rw-r--r--src/launcher/pipelauncher.h74
-rw-r--r--src/launcher/socketlauncher.cpp140
-rw-r--r--src/launcher/socketlauncher.h75
-rw-r--r--src/src.pri10
-rw-r--r--src/src.pro17
-rw-r--r--tests/auto/auto.pro2
-rw-r--r--tests/auto/declarative/.gitignore2
-rw-r--r--tests/auto/declarative/data/testfrontend.qml37
-rw-r--r--tests/auto/declarative/declarative.pri1
-rw-r--r--tests/auto/declarative/declarative.pro3
-rw-r--r--tests/auto/declarative/test/test.pro18
-rw-r--r--tests/auto/declarative/testDeclarative/.gitignore1
-rw-r--r--tests/auto/declarative/testDeclarative/main.cpp96
-rw-r--r--tests/auto/declarative/testDeclarative/testDeclarative.pro9
-rw-r--r--tests/auto/declarative/tst_declarative.cpp204
-rw-r--r--tests/auto/processmanager/.gitignore2
-rw-r--r--tests/auto/processmanager/data/testfrontend.qml19
-rw-r--r--tests/auto/processmanager/processmanager.pri1
-rw-r--r--tests/auto/processmanager/processmanager.pro3
-rw-r--r--tests/auto/processmanager/test/test.pro19
-rw-r--r--tests/auto/processmanager/testClient/.gitignore1
-rw-r--r--tests/auto/processmanager/testClient/main.cpp96
-rw-r--r--tests/auto/processmanager/testClient/testClient.pro11
-rw-r--r--tests/auto/processmanager/testPipeLauncher/.gitignore1
-rw-r--r--tests/auto/processmanager/testPipeLauncher/main.cpp52
-rw-r--r--tests/auto/processmanager/testPipeLauncher/testPipeLauncher.pro12
-rw-r--r--tests/auto/processmanager/testPrelaunch/.gitignore1
-rw-r--r--tests/auto/processmanager/testPrelaunch/main.cpp116
-rw-r--r--tests/auto/processmanager/testPrelaunch/testPrelaunch.pro12
-rw-r--r--tests/auto/processmanager/testSocketLauncher/.gitignore1
-rw-r--r--tests/auto/processmanager/testSocketLauncher/main.cpp53
-rw-r--r--tests/auto/processmanager/testSocketLauncher/testSocketLauncher.pro12
-rw-r--r--tests/auto/processmanager/tst_processmanager.cpp854
-rw-r--r--tests/tests.pro2
113 files changed, 10721 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..485265a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,11 @@
+*~
+*.o
+*.a
+*#
+moc_*
+*.dylib
+doc/html
+.DS_Store
+Makefile
+TAGS
+include/qtprocessmanager/*.h
diff --git a/config.pri b/config.pri
new file mode 100644
index 0000000..cae9c04
--- /dev/null
+++ b/config.pri
@@ -0,0 +1,5 @@
+isEmpty(INSTALLBASE): INSTALLBASE = $$(INSTALLBASE)
+isEmpty(INSTALLBASE) {
+ INSTALLBASE=/usr
+ message("No INSTALLBASE specified, defaulting to $$INSTALLBASE")
+}
diff --git a/doc/doc.pri b/doc/doc.pri
new file mode 100644
index 0000000..5d18bc3
--- /dev/null
+++ b/doc/doc.pri
@@ -0,0 +1,9 @@
+OTHER_FILES += \
+ $$PWD/processmanager.qdocconf
+
+docs_target.target = docs
+docs_target.commands = qdoc3 $$PWD/processmanager.qdocconf
+
+QMAKE_EXTRA_TARGETS = docs_target
+QMAKE_CLEAN += \
+ "-r $$PWD/html"
diff --git a/doc/images/process_structs.png b/doc/images/process_structs.png
new file mode 100644
index 0000000..e3b112d
--- /dev/null
+++ b/doc/images/process_structs.png
Binary files differ
diff --git a/doc/images/processbackend_hierarchy.png b/doc/images/processbackend_hierarchy.png
new file mode 100644
index 0000000..be8334f
--- /dev/null
+++ b/doc/images/processbackend_hierarchy.png
Binary files differ
diff --git a/doc/images/processbackendfactory_hierarchy.png b/doc/images/processbackendfactory_hierarchy.png
new file mode 100644
index 0000000..2b106ec
--- /dev/null
+++ b/doc/images/processbackendfactory_hierarchy.png
Binary files differ
diff --git a/doc/processmanager.qdocconf b/doc/processmanager.qdocconf
new file mode 100644
index 0000000..396c6d9
--- /dev/null
+++ b/doc/processmanager.qdocconf
@@ -0,0 +1,78 @@
+# Name of the project.
+project = ProcessManager
+
+# Directories in which to search for files to document.
+# Paths are relative to the location of this file.
+exampledirs += ../examples
+headerdirs += ./src ../src/core ../src/declarative ../src/launcher
+imagedirs += images
+sourcedirs += ./src ../src/core ../src/declarative ../src/launcher
+
+Cpp.ignoretokens = \
+ QT_BEGIN_HEADER \
+ QT_END_HEADER \
+ Q_INVOKABLE \
+ Q_ENUMS \
+ QT_BEGIN_NAMESPACE_PROCESSMANAGER \
+ QT_END_NAMESPACE_PROCESSMANAGER \
+ Q_ADDON_PROCESSMANAGER_EXPORT
+
+# The following parameters are for creating a qhp file, the qhelpgenerator
+# program can convert the qhp file into a qch file which can be opened in
+# Qt Assistant and/or Qt Creator.
+
+# Defines the name of the project. You cannot use operators (+, =, -) in
+# the name. Properties for this project are set using a qhp.<projectname>.property
+# format.
+qhp.projects = ProcessManager
+
+# Sets the name of the output qhp file.
+qhp.ProcessManager.file = ProcessManager.qhp
+
+# Namespace for the output file. This namespace is used to distinguish between
+# different documentation files in Creator/Assistant. The namespace ends with
+# a version being a number containing a major, minor and revision element.
+# E.g. version 1.0 becomes 100.
+qhp.ProcessManager.namespace = com.nokia.processmanager.100
+
+# Title for the package, will be the main title for the package in
+# Assistant/Creator.
+qhp.ProcessManager.indexTitle = Process Manager Reference Documentation
+
+# Extra files to add to the output which are not linked to from anywhere
+# using a qdoc \l command.
+qhp.ProcessManager.extraFiles = style/style.css \
+ index.html
+
+# Only update the name of the project for the next variables.
+qhp.ProcessManager.virtualFolder = qdoc
+qhp.ProcessManager.subprojects = classes
+qhp.ProcessManager.subprojects.classes.title = Classes
+qhp.ProcessManager.subprojects.classes.selectors = class fake:headerfile
+qhp.ProcessManager.subprojects.classes.sortPages = true
+
+
+# Do NOT change the variables after this line unless you know what you are doing.
+
+outputdir = html
+outputformats = HTML
+
+examples.fileextensions = "*.cpp *.h *.js *.svg *.xml *.ui *.qml"
+examples.imageextensions = "*.png *.jpeg *.jpg *.gif *.mng"
+headers.fileextensions = "*.h *.ch *.h++ *.hh *.hpp *.hxx"
+sources.fileextensions = "*.cpp *.qdoc *.mm *.qml"
+
+HTML.nobreadcrumbs = "true"
+
+HTML.templatedir = .
+HTML.stylesheets = style/style.css
+
+HTML.headerstyles = " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/style.css\" />\n"
+HTML.endheader = "</head>\n"
+
+HTML.postheader = \
+ " <div class=\"header\">\n" \
+ " <div id=\"nav-logo\">\n" \
+ " <a href=\"index.html\">Process Manager Reference</a>" \
+ " </div>\n" \
+ " </div>\n"
diff --git a/doc/src/basicpm.qdoc b/doc/src/basicpm.qdoc
new file mode 100644
index 0000000..45238c2
--- /dev/null
+++ b/doc/src/basicpm.qdoc
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of ProcessManager
+**
+** $QT_BEGIN_LICENSE:FDL$
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms
+** and conditions contained in a signed written agreement between you
+** and Nokia.
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\page basicpm.html
+\previouspage Understanding ProcessInfo
+\contentspage {Backend Process Manager} {Contents}
+\nextpage Standard Process Manager
+
+\title Backend Process Manager
+
+The basic C++ API for controlling processes uses the ProcessBackendManager.
+The ProcessBackendManager contains an ordered list of ProcessBackendFactory objects,
+which are used to convert ProcessInfo objects into executable processes.
+
+The ProcessBackendManager can be used as follows:
+
+\code
+ ProcessBackendManager *manager = new ProcessBackendManager;
+ manager->add(new UnixProcessBackendFactory);
+
+ ProcessInfo info;
+ info.setName("lstest");
+ info.setProgram("/bin/ls");
+ info.setWorkingDirectory("/root");
+
+ ProcessBackend *backend = manager->create(info);
+ if (backend) {
+ connect(backend, SIGNAL(started()), this, SLOT(processStarted()));
+ connect(backend, SIGNAL(finished(int, QProcess::ExitStatus)),
+ this, SLOT(processFinished(int, QProcess::ExitStatus)));
+ backend->start();
+ }
+\endcode
+
+The first step of initializing the ProcessBackendManager is to assign
+ProcessBackendFactory objects. The order of the factories is important.
+The ProcessBackendManager::create() function asks each factory in turn
+if it can handle the ProcessInfo object. The first factory to match
+is the one that creates the ProcessBackend object.
+The backend object behaves similarly to a QProcess object; one normally
+attaches a few signal handlers and then starts the backend running.
+Please note the it is the user's responsibility to correctly delete
+the backend object.
+
+In the following example, we've added a GdbProcessBackendFactory.
+The GdbProcessBackendFactory will match any
+that has a "gdb" property set to "true" in the ProcessInfo record. When
+it matches, it rewrites the ProcessInfo record to execute the gdb
+program with the appropriate command line arguments.
+
+\code
+ ProcessBackendManager *manager = new ProcessBackendManager;
+ manager->add(new GdbProcessBackendFactory);
+ manager->add(new UnixProcessBackendFactory);
+
+ ProcessInfo info;
+ info.setName("lstest");
+ info.setProgram("/bin/ls");
+ info.setWorkingDirectory("/root");
+ info.setValue("gdb", "true");
+
+ ProcessBackend *backend = manager->create(info);
+ if (backend) {
+ connect(backend, SIGNAL(started()), this, SLOT(processStarted()));
+ connect(backend, SIGNAL(finished(int, QProcess::ExitStatus)),
+ this, SLOT(processFinished(int, QProcess::ExitStatus)));
+ backend->start();
+ }
+\endcode
+
+\section1 Inheritence Hierarchy
+
+\image processbackend_hierarchy.png {Process Backend Hierarchy}
+\caption \i{Process Backend Hierarchy}
+
+The virtual ProcessBackend object hierarchy is divided into two
+sections: the UnixProcessBackend objects contain a QProcess internally
+and the RemoteProcessBackend objects communicate with a separate process
+"launcher" program. It may sound odd that a process manager would not
+launch its own processes, but this mechanism allows the process
+manager to not run with setuid privileges.
+
+\image processbackendfactory_hierarchy.png
+\caption \i{Process Backend Factory Hierarchy}
+
+The ProcessBackendFactory hierarchy closely matches the ProcessBackend
+hierarchy. The standard and prelaunch subclasses create standard and
+prelaunch process backend objects. The remote subclass is divided
+by how it connects to the remote "launcher" program; either over a
+pipe connection or a socket connection.
+
+*/
diff --git a/doc/src/index.qdoc b/doc/src/index.qdoc
new file mode 100644
index 0000000..e1f20e1
--- /dev/null
+++ b/doc/src/index.qdoc
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of ProcessManager
+**
+** $QT_BEGIN_LICENSE:FDL$
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms
+** and conditions contained in a signed written agreement between you
+** and Nokia.
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\title Process Manager Reference
+\page index.html
+
+The Process Manager is used to start and stop
+a collection of child processes. It includes monitoring tools to
+measure process memory and CPU use. It
+has hooks to create Pipe applications which can be used to
+accelerate the launching of certain types of processes. It exposes a
+QML-appropriate API so that process manager logic can be controlled
+from QML.
+
+The process manager API has three layers: a basic C++ API for generic
+process management, an enhanced C++ API that allows process objects
+to be subclassed, and a QML API.
+
+Table of contents:
+
+\list
+\o \l {Introduction}
+\o \l {Understanding ProcessInfo}
+\o \l {Backend Process Manager}
+\o \l {Standard Process Manager}
+\o \l {Declarative Process Manager}
+\endlist
+
+
+\section1 C++ Classes
+
+\generatelist annotatedclasses
+
+\section1 QML Elements
+
+\generatelist qmlclasses
+*/
diff --git a/doc/src/intro.qdoc b/doc/src/intro.qdoc
new file mode 100644
index 0000000..65b5132
--- /dev/null
+++ b/doc/src/intro.qdoc
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of ProcessManager
+**
+** $QT_BEGIN_LICENSE:FDL$
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms
+** and conditions contained in a signed written agreement between you
+** and Nokia.
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\page intro.html
+\contentspage {Introduction} {Contents}
+\nextpage Understanding ProcessInfo
+
+\title Introduction
+
+
+\section1 Basic Concepts
+
+There are four basic types of objects to work with in the process manager.
+
+\list
+ \o ProcessInfo objects specify what program to run, environment variables
+ to pass to the program, working directory, and permissions.
+ \o ProcessBackendFactory objects convert ProcessInfo objects into executing
+ processes.
+ \o ProcessFrontend / ProcessBackend objects wrap executing processes. They
+ bear a strong resemblence to QProcess objects, but in fact may not
+ contain a QProcess.
+ \o ProcessManager / ProcessBackendManager are singleton objects that
+ hold a list of factories and provide convenience interfaces for interacting
+ with ProcessFrontend/ProcessBackend objects.
+\endlist
+
+*/
diff --git a/doc/src/namespace.qdoc b/doc/src/namespace.qdoc
new file mode 100644
index 0000000..883df6d
--- /dev/null
+++ b/doc/src/namespace.qdoc
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of ProcessManager
+**
+** $QT_BEGIN_LICENSE:FDL$
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms
+** and conditions contained in a signed written agreement between you
+** and Nokia.
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \macro QT_USE_NAMESPACE_PROCESSMANAGER
+ \inmodule ProcessManager
+
+ This macro expands to using processmanager namespace and makes processmanager namespace
+ visible to C++ source code.
+
+ \code
+ #include <processmanager-global.h>
+ QT_USE_NAMESPACE_PROCESSMANAGER
+ \endcode
+
+ To declare the class without including the declaration of the class:
+
+ \code
+ #include <processmanager-global.h>
+ QT_BEGIN_NAMESPACE_PROCESSMANAGER
+ class ProcessManager;
+ QT_END_NAMESPACE_PROCESSMANAGER
+ QT_USE_NAMESPACE_PROCESSMANAGER
+ \endcode
+*/
+
+/*!
+ \macro QT_BEGIN_NAMESPACE_PROCESSMANAGER
+ \inmodule ProcessManager
+
+ This macro begins a ProcessManager namespace. All forward declarations of ProcessManager classes need to
+ be wrapped in \c QT_BEGIN_NAMESPACE_PROCESSMANAGER and \c QT_END_NAMESPACE_PROCESSMANAGER.
+
+ \sa QT_USE_NAMESPACE_PROCESSMANAGER, QT_END_NAMESPACE_PROCESSMANAGER
+*/
+
+/*!
+ \macro QT_END_NAMESPACE_PROCESSMANAGER
+ \inmodule ProcessManager
+
+ This macro ends a ProcessManager namespace. All forward declarations of ProcessManager classes need to
+ be wrapped in \c QT_BEGIN_NAMESPACE_PROCESSMANAGER and \c QT_END_NAMESPACE_PROCESSMANAGER.
+
+ \sa QT_USE_NAMESPACE_PROCESSMANAGER, QT_BEGIN_NAMESPACE_PROCESSMANAGER
+*/
diff --git a/doc/src/processinfo.qdoc b/doc/src/processinfo.qdoc
new file mode 100644
index 0000000..b501173
--- /dev/null
+++ b/doc/src/processinfo.qdoc
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of ProcessManager
+**
+** $QT_BEGIN_LICENSE:FDL$
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms
+** and conditions contained in a signed written agreement between you
+** and Nokia.
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\page understandprocessinfo.html
+\previouspage Introduction
+\contentspage {Understanding ProcessInfo} {Contents}
+\nextpage Backend Process Manager
+
+\title Understanding ProcessInfo
+
+An individual Unix process has a large number of properties that can be
+set upon process creation. The ProcessInfo object is a ligthweight wrapper
+for a QVariantMap containing the more common properties including:
+
+\list
+ \o Common name assigned to the object. This name is used when creating
+ a process identifier.
+ \o Application to execute
+ \o Arguments to pass on the command line
+ \o Working directory
+ \o User ID (UID) and Group ID (GID)
+ \o Environment variables
+ \o Linux-specific \l {http://linux.die.net/man/7/capabilities} {capabilities}
+ \o Linux-specific \l
+ {http://www.kernel.org/doc/Documentation/cgroups/cgroups.txt}
+ {cgroups}
+ \o The priority level of the process (agents run at lower priority levels)
+ \o The OOM killer adjustment score (ranges from -1000 to +1000)
+ \l {http://www.kernel.org/doc/Documentation/filesystems/proc.txt} {[/proc/<pid>/oom_score_adj]}
+ \o Output text patterns to match to determing if the process has finished initializing.
+ \o Other machine-specific ways of limiting process
+ memory/CPU/resource use.
+\endlist
+
+The ProcessInfo object provides accessor functions for accessing the
+more common properties along with named string constants. Because it is
+based on a QVariantMap, additional properties can be easily added to the
+structure. From C++ code, a ProcessInfo object is typically created as follows:
+
+\code
+ ProcessInfo info;
+ info.setName("myprocess");
+ info.setProgram("/bin/ls");
+ info.setWorkingDirectory("/root");
+\endcode
+
+*/
diff --git a/doc/src/qmlpm.qdoc b/doc/src/qmlpm.qdoc
new file mode 100644
index 0000000..dff3e78
--- /dev/null
+++ b/doc/src/qmlpm.qdoc
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of ProcessManager
+**
+** $QT_BEGIN_LICENSE:FDL$
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms
+** and conditions contained in a signed written agreement between you
+** and Nokia.
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\page qmlpm.html
+\previouspage Standard Process Manager
+\contentspage {Declarative Process Manager} {Contents}
+
+\title Declarative Process Manager
+
+The declarative process manager is a ProcessManager object with
+appropriate declarations so that it can be used from QML. Sample
+use:
+
+\qml
+ import QtQuick 2.0
+ import ProcessManager 1.0
+
+ DeclarativeProcessManager {
+ id: myManager
+
+ factories: [
+ GdbProcessBackendFactory,
+ StandardProcessBackendFactory
+ ]
+
+ onProcessStarted: console.log("Process "+identifier+" started");
+ onProcessFinished: console.log("Process "+identifier+" finished");
+
+ function make(info) {
+ var process = create(info);
+ return process.identifier;
+ }
+
+ function start(id) {
+ var process = processForIdentifier(id);
+ process.start();
+ }
+
+ function stop(id) {
+ var process = processForIdentifier(id);
+ process.stop();
+ }
+ }
+\endqml
+
+*/
diff --git a/doc/src/standardpm.qdoc b/doc/src/standardpm.qdoc
new file mode 100644
index 0000000..fef2b46
--- /dev/null
+++ b/doc/src/standardpm.qdoc
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of ProcessManager
+**
+** $QT_BEGIN_LICENSE:FDL$
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms
+** and conditions contained in a signed written agreement between you
+** and Nokia.
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\page standardpm.html
+\previouspage Backend Process Manager
+\contentspage {Standard Process Manager} {Contents}
+\nextpage Declarative Process Manager
+
+\title Standard Process Manager
+
+The standard ProcessManager object wraps the ProcessBackendManager
+object, creates ProcessFrontend objects to wrap each ProcessBackend
+object, and assigns unique string identifiers to each process.
+This approach provides several advantages. First, the ProcessManager can
+maintain a list of running processes indexed by identifier. Second, the
+ProcessFrontend objects can be subclassed. This provides a convenient
+way of adding convenience functions to the ProcessFrontend objects. Third,
+instead of connecting to signals from each process, one can subclass
+the ProcessManager itself and override the handler functions.
+
+The unique identifier assigned to each process created takes the form
+of "NAME-NUMBER", where NAME comes from the ProcessInfo.name attribute
+and NUMBER is a unique integer assigned at process creation.
+
+\section2 Directly using the ProcessManager
+
+You can directly use the ProcessManager in your code.
+\code
+void MyClass::setup()
+{
+ ProcessManager *manager = new ProcessManager;
+ manager->addFactory(new UnixProcessBackendFactory);
+ m_manager = manager;
+}
+
+void MyClass::start(ProcessInfo info)
+{
+ ProcessFrontend *frontend = m_manager->start(info);
+ connect(frontend, SIGNAL(started()), SLOT(started()));
+ connect(frontend, SIGNAL(finished(int, QProcess::ExitStatus)),
+ SLOT(finished(int, QProcess::ExitStatus)));
+}
+
+void MyClass::started()
+{
+ ProcessFrontend *frontend = qobject_cast<ProcessFrontend *>(sender());
+ if (frontend)
+ qDebug() << "Process" << identifier << "started with pid=" << frontend->pid();
+}
+
+void MyClass::finished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ ProcessFrontend *frontend = qobject_cast<ProcessFrontend *>(sender());
+ if (frontend)
+ qDebug() << "Process" << identifier << "stopped with" << exitCode << exitStatus;
+}
+\endcode
+
+
+\section2 Subclassing ProcessManager
+
+You can subclass the process manager to gain more control. This
+avoids connecting signals to every process you create.
+
+\code
+class Example : public ProcessManager
+{
+ Q_OBJECT
+public:
+ Example(QObject *parent=0);
+
+protected slots:
+ void processFrontendStarted();
+ void processFrontendFinished(int, QProcess::ExitStatus);
+};
+
+void Example::Example(QObject *parent)
+ : ProcessManager(parent)
+{
+ addFactory(new UnixProcessBackendFactory);
+}
+
+void Example::processFrontendStarted()
+{
+ ProcessManager::processFrontendStarted();
+ ProcessFrontend *frontend = qobject_cast<ProcessFrontend *>(sender());
+ qDebug() << "Process" << frontend->identifier() << "has started";
+}
+
+void Example::processFrontendFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ ProcessManager::processFrontendFinished(exitCode, exitStatus);
+ ProcessFrontend *frontend = qobject_cast<ProcessFrontend *>(sender());
+ qDebug() << "Process" << frontend->identifier() << "has finished" << exitCode << exitStatus;
+}
+
+\endcode
+
+\section2 Subclass ProcessFrontend objects
+
+To subclass ProcessFrontend objects, override the \l
+{ProcessManager::} {createFrontend()} function and return an object
+that derived from ProcessFrontend. For example:
+
+\code
+
+class MyFrontend : public ProcessFrontend {
+ Q_OBJECT
+public:
+ MyFrontend(ProcessBackend *backend) : ProcessFrontend(backend) {}
+protected:
+ void handleStateChanged(QProcess::ProcessState);
+signals:
+ void stopped();
+};
+
+void MyFrontend::handleStateChanged(QProcess::ProcessState state)
+{
+ if (state == QProcess::NotRunning)
+ emit stopped();
+}
+
+class MyManager : public ProcessManager
+{
+ Q_OBJECT
+public:
+ MyManager(QObject *parent=0) : ProcessManager(parent) {}
+protected :
+ ProcessFrontend *createFrontend(ProcessBackend *backend) {
+ return new MyFrontend(backend);
+ }
+};
+
+\endcode
+
+In the above example, the custom \c MyFrontend class raises a new \c
+stopped() signal when the child process stops running. The \c
+MyManager class reimplements \l {ProcessManager::} {createFrontend()}
+to return a \c MyFrontend objects for each created process.
+
+*/
diff --git a/doc/style/style.css b/doc/style/style.css
new file mode 100644
index 0000000..24b0e0e
--- /dev/null
+++ b/doc/style/style.css
@@ -0,0 +1,146 @@
+a:link, a:visited {
+ color: #00732F;
+ text-decoration: none;
+ font-weight: bold;
+}
+
+body {
+ font: normal 400 14px/1.2 Arial;
+# margin-top: 85px;
+}
+
+h1 {
+ margin: 0;
+}
+
+h2 {
+ font: 500 20px/1.2 Arial;
+}
+
+h3.fn, span.fn {
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ background-color: #F6F6F6;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #E6E6E6;
+ word-spacing: 3px;
+ padding: 3px 5px;
+}
+
+table, pre {
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ background-color: #F6F6F6;
+ border: 1px solid #E6E6E6;
+ border-collapse: separate;
+ font-size: 12px;
+ line-height: 1.2;
+ margin-bottom: 25px;
+ margin-left: 15px;
+}
+
+table td {
+ padding: 3px 15px 3px 20px;
+}
+
+table tr.even {
+ background-color: white;
+ color: #66666E;
+}
+
+table tr.odd {
+ background-color: #F6F6F6;
+ color: #66666E;
+}
+
+li {
+ margin-bottom: 10px;
+ padding-left: 12px;
+}
+
+.cpp {
+ display: block;
+ margin: 10;
+ overflow: hidden;
+ overflow-x: hidden;
+ overflow-y: hidden;
+ padding: 20px 0 20px 0;
+}
+
+.footer {
+ margin-top: 50px;
+}
+
+.memItemLeft {
+ padding-right: 3px;
+}
+
+.memItemRight {
+ padding: 3px 15px 3px 0;
+}
+
+.qml {
+ display: block;
+ margin: 10;
+ overflow: hidden;
+ overflow-x: hidden;
+ overflow-y: hidden;
+ padding: 20px 0 20px 0;
+}
+
+.qmldefault {
+ padding-left: 5px;
+ float: right;
+ color: red;
+}
+
+.qmlreadonly {
+ padding-left: 5px;
+ float: right;
+ color: #254117;
+}
+
+.rightAlign {
+ padding: 3px 5px 3px 10px;
+ text-align: right;
+}
+
+.header {
+ background-color: #F6F6F6;
+ border: 1px solid #DDD;
+ padding: 5px 5px;
+ margin: 5px 5px;
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+}
+
+.title {
+ background-color: white;
+ color: #44A51C;
+ font-family: Verdana;
+ font-size: 35px;
+ font-weight: normal;
+ left: 0;
+ padding-bottom: 5px;
+ padding-left: 16px;
+ padding-top: 5px;
+# position: absolute;
+ right: 0;
+ top: 0;
+}
+
+.toc {
+ float: right;
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ background-color: #F6F6F6;
+ border: 1px solid #DDD;
+ margin: 0 20px 10px 10px;
+ padding: 20px 15px 20px 20px;
+ height: auto;
+ width: 200px;
+}
diff --git a/include/qtprocessmanager/syncheaders.sh b/include/qtprocessmanager/syncheaders.sh
new file mode 100755
index 0000000..a76cde8
--- /dev/null
+++ b/include/qtprocessmanager/syncheaders.sh
@@ -0,0 +1,13 @@
+#!/bin/sh -e
+
+DIR="$(cd $(dirname $0); echo $PWD)"
+for i in `ls -1 $DIR/../../src/core/*.h` ; do
+ header=`basename $i`
+ echo "#include \"../../src/core/$header\"" > $DIR/$header
+done
+
+for i in `ls -1 $DIR/../../src/declarative/*.h` ; do
+ header=`basename $i`
+ echo "#include \"../../src/declarative/$header\"" > $DIR/$header
+done
+
diff --git a/processmanager.pro b/processmanager.pro
new file mode 100644
index 0000000..777225d
--- /dev/null
+++ b/processmanager.pro
@@ -0,0 +1,14 @@
+TEMPLATE = subdirs
+
+module_processmanager_src.subdir = src
+module_processmanager_src.target = module-processmanager-src
+
+module_processmanager_tests.subdir = tests
+module_processmanager_tests.target = module-processmanager-tests
+module_processmanager_tests.depends += module-processmanager-src
+
+SUBDIRS += module_processmanager_src #module_processmanager_tests
+
+include(doc/doc.pri)
+
+system($$PWD/include/qtprocessmanager/syncheaders.sh)
diff --git a/src/core/core-lib.pri b/src/core/core-lib.pri
new file mode 100644
index 0000000..361c8c8
--- /dev/null
+++ b/src/core/core-lib.pri
@@ -0,0 +1,52 @@
+QT += network
+
+INCLUDEPATH += $$PWD
+
+PUBLIC_HEADERS += \
+ $$PWD/process.h \
+ $$PWD/processfrontend.h \
+ $$PWD/processbackend.h \
+ $$PWD/processbackendfactory.h \
+ $$PWD/processbackendmanager.h \
+ $$PWD/processinfo.h \
+ $$PWD/processmanager.h \
+ $$PWD/gdbprocessbackendfactory.h \
+ $$PWD/standardprocessbackendfactory.h \
+ $$PWD/prelaunchprocessbackendfactory.h \
+ $$PWD/remoteprocessbackendfactory.h \
+ $$PWD/pipeprocessbackendfactory.h \
+ $$PWD/socketprocessbackendfactory.h \
+ $$PWD/unixprocessbackend.h \
+ $$PWD/standardprocessbackend.h \
+ $$PWD/prelaunchprocessbackend.h \
+ $$PWD/remoteprocessbackend.h \
+ $$PWD/processmanager-global.h
+
+*linux* {
+ PUBLIC_HEADERS += $$PWD/procutils.h
+ SOURCES += $$PWD/procutils.cpp
+}
+
+HEADERS += \
+ $$PUBLIC_HEADERS \
+ $$PWD/unixsandboxprocess.h
+
+SOURCES += \
+ $$PWD/process.cpp \
+ $$PWD/gdbprocessbackendfactory.cpp \
+ $$PWD/processfrontend.cpp \
+ $$PWD/processbackend.cpp \
+ $$PWD/processbackendfactory.cpp \
+ $$PWD/processbackendmanager.cpp \
+ $$PWD/processinfo.cpp \
+ $$PWD/processmanager.cpp \
+ $$PWD/unixprocessbackend.cpp \
+ $$PWD/standardprocessbackendfactory.cpp \
+ $$PWD/standardprocessbackend.cpp \
+ $$PWD/unixsandboxprocess.cpp \
+ $$PWD/prelaunchprocessbackendfactory.cpp \
+ $$PWD/prelaunchprocessbackend.cpp \
+ $$PWD/remoteprocessbackend.cpp \
+ $$PWD/remoteprocessbackendfactory.cpp \
+ $$PWD/pipeprocessbackendfactory.cpp \
+ $$PWD/socketprocessbackendfactory.cpp
diff --git a/src/core/core.pri b/src/core/core.pri
new file mode 100644
index 0000000..f934acc
--- /dev/null
+++ b/src/core/core.pri
@@ -0,0 +1,10 @@
+CONFIG += network
+
+INCLUDEPATH += $$PWD
+LIBS += -L$$PWD -lprocessmanager-core
+
+mac|unix {
+ CONFIG += rpath_libdirs
+ QMAKE_RPATHDIR += $$PWD
+ QMAKE_LFLAGS += "-Wl,-rpath $$PWD"
+}
diff --git a/src/core/core.pro b/src/core/core.pro
new file mode 100644
index 0000000..343572a
--- /dev/null
+++ b/src/core/core.pro
@@ -0,0 +1,16 @@
+TEMPLATE = lib
+TARGET = processmanager-core
+
+include($$PWD/../../config.pri)
+include($$PWD/core-lib.pri)
+
+mac {
+ QMAKE_POST_LINK = install_name_tool -id $$PWD/${TARGET} ${TARGET}
+}
+
+target.path = $$INSTALLBASE/lib
+
+headers.path = $$INSTALLBASE/include/qtprocessmanager
+headers.files = $$PUBLIC_HEADERS
+
+INSTALLS += target headers
diff --git a/src/core/gdbprocessbackendfactory.cpp b/src/core/gdbprocessbackendfactory.cpp
new file mode 100644
index 0000000..5b25715
--- /dev/null
+++ b/src/core/gdbprocessbackendfactory.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "gdbprocessbackendfactory.h"
+#include "processinfo.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \class GdbProcessBackendFactory
+ \brief The GdbProcessBackendFactory class creates UnixProcessBackend objects
+
+ This is a simple example class showing how to create a custom factory.
+ The GdbProcessBackendFactory matches ProcessInfo records with a "gdb"
+ attribute of "true" (the string, not the boolean value). It rewrites the
+ process arguments to launch gdb with the passed application.
+
+ In the future this class will be replaced with a general "rewriting"
+ frontend to modify ProcessInfo arguments.
+*/
+
+/*!
+ Construct a GdbProcessBackendFactory with optional \a parent
+*/
+
+GdbProcessBackendFactory::GdbProcessBackendFactory(QObject *parent)
+ : StandardProcessBackendFactory(parent)
+{
+}
+
+/*!
+ GdbProcessBackendFactory will match ProcessInfo \a info objects
+ with a "gdb" attribute containing the string "true".
+*/
+
+bool GdbProcessBackendFactory::canCreate(const ProcessInfo& info) const
+{
+ return (info.value("gdb").toString() == "true");
+}
+
+/*!
+ Construct a UnixProcessBackend from a ProcessInfo \a info record and \a parent,
+ but change the program name to "gdb" and pass the original
+ program as an argument.
+*/
+
+ProcessBackend * GdbProcessBackendFactory::create(const ProcessInfo& info, QObject *parent)
+{
+ ProcessInfo i = info;
+ QStringList args = i.arguments();
+ args.prepend(i.program());
+ args.prepend("--");
+ i.setProgram("gdb");
+ return StandardProcessBackendFactory::create(i, parent);
+}
+
+#include "moc_gdbprocessbackendfactory.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/gdbprocessbackendfactory.h b/src/core/gdbprocessbackendfactory.h
new file mode 100644
index 0000000..4ea99ab
--- /dev/null
+++ b/src/core/gdbprocessbackendfactory.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GDB_PROCESS_BACKEND_FACTORY_H
+#define GDB_PROCESS_BACKEND_FACTORY_H
+
+#include "standardprocessbackendfactory.h"
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class GdbProcessBackendFactory : public StandardProcessBackendFactory
+{
+ Q_OBJECT
+
+public:
+ GdbProcessBackendFactory(QObject *parent=0);
+ virtual bool canCreate(const ProcessInfo& info) const;
+ virtual ProcessBackend *create(const ProcessInfo& info, QObject *parent);
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // GDB_PROCESS_BACKEND_FACTORY_H
diff --git a/src/core/memorystatistics_p.h b/src/core/memorystatistics_p.h
new file mode 100644
index 0000000..4d1d9a1
--- /dev/null
+++ b/src/core/memorystatistics_p.h
@@ -0,0 +1,73 @@
+#ifndef MEMORYMANAGER_P_H
+#define MEMORYMANAGER_P_H
+
+#include <QString>
+
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class MappedRegion {
+public:
+ quint64 addressStart;
+ quint64 addressEnd;
+ quint64 rssSize;
+ quint64 pssSize;
+ quint64 privateSize;
+ QString pathname;
+
+ static QString libBaseName(const QString &pathName);
+ QString libBaseName() const;
+};
+
+// proc/pid/stat
+class stat {
+public:
+ stat()
+ : ppid(0)
+ , pgrp(0)
+ , session(0)
+ , it_real_value(0)
+ , start_time(0)
+ , vsize(0)
+ , rss(0) {}
+ QByteArray comm;
+ char state;
+ int ppid;
+ int pgrp;
+ int session;
+ int tty_nr;
+ int tty_pgrp;
+ ulong flags;
+ ulong min_flt;
+ ulong cmin_flt;
+ ulong maj_flt;
+ ulong cmaj_flt;
+ ulong tms_utime;
+ ulong tms_stime;
+ long tms_cutime;
+ long tms_cstime;
+ long priority;
+ long nice;
+
+ long it_real_value;
+ ulong start_time;
+ ulong vsize;
+ long rss; /* you might want to shift this left 3 */
+ ulong rlim;
+ ulong start_code;
+ ulong end_code;
+ ulong start_stack;
+ ulong esp;
+ ulong eip;
+
+ ulong wchan;
+ ulong nswap;
+ ulong cnswap;
+ int exit_signal;
+ int processor;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // MEMORYMANAGER_P_H
diff --git a/src/core/pipeprocessbackendfactory.cpp b/src/core/pipeprocessbackendfactory.cpp
new file mode 100644
index 0000000..39ea8ea
--- /dev/null
+++ b/src/core/pipeprocessbackendfactory.cpp
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pipeprocessbackendfactory.h"
+#include "remoteprocessbackend.h"
+
+#include <QDebug>
+#include <QJsonDocument>
+#include <QFileInfo>
+#include <QtEndian>
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+const int kPipeTimerInterval = 1000;
+
+/*!
+ \class PipeProcessBackendFactory
+ \brief The PipeProcessBackendFactory class forks a new process to launch applications.
+
+ The PipeProcessBackendFactory launches a persistent pipe process.
+ The factory communicates with the pipe process by sending and receiving
+ messages over stdin/stdout.
+*/
+
+/*!
+ Construct a PipeProcessBackendFactory with optional \a parent.
+ The \a info ProcessInfo is used to start the pipe process.
+ The \a program is used to match program names for create() requests.
+*/
+
+PipeProcessBackendFactory::PipeProcessBackendFactory(const ProcessInfo& info,
+ const QString& program,
+ QObject *parent)
+ : RemoteProcessBackendFactory(parent)
+ , m_process(NULL)
+ , m_program(program)
+{
+ m_process = new QProcess; // Note that we do NOT own the pipe process
+ m_process->setReadChannel(QProcess::StandardOutput);
+ connect(m_process, SIGNAL(readyReadStandardOutput()),
+ this, SLOT(pipeReadyReadStandardOutput()));
+ connect(m_process, SIGNAL(readyReadStandardError()),
+ this, SLOT(pipeReadyReadStandardError()));
+ connect(m_process, SIGNAL(started()), this, SLOT(pipeStarted()));
+ connect(m_process,SIGNAL(error(QProcess::ProcessError)),
+ this,SLOT(pipeError(QProcess::ProcessError)));
+ connect(m_process,SIGNAL(finished(int, QProcess::ExitStatus)),
+ this,SLOT(pipeFinished(int, QProcess::ExitStatus)));
+ connect(m_process, SIGNAL(stateChanged(QProcess::ProcessState)),
+ this,SLOT(pipeStateChanged(QProcess::ProcessState)));
+
+ QProcessEnvironment env;
+ QMapIterator<QString, QVariant> it(info.environment());
+ while (it.hasNext()) {
+ it.next();
+ env.insert(it.key(), it.value().toString());
+ }
+ m_process->setProcessEnvironment(env);
+ m_process->setWorkingDirectory(info.workingDirectory());
+ m_process->start(info.program(), info.arguments());
+}
+
+/*!
+ Destroy this and child objects.
+*/
+
+PipeProcessBackendFactory::~PipeProcessBackendFactory()
+{
+ // ### Note: The m_process process is NOT a child of the
+ // factory to avoid stranding grandchildren
+ // However, we do send it a "stop" message before we exit
+ if (m_process) {
+ QJsonObject object;
+ object.insert(QLatin1String("remote"), QLatin1String("stop"));
+ m_process->write(QJsonDocument(object).toBinaryData());
+ m_process->waitForBytesWritten(); // Block until they have been written
+ m_process = NULL;
+ }
+}
+
+/*!
+ The PipeProcessBackendFactory will match the ProcessInfo \a info
+ if there is a \c info.pipe attribute set to "true" (the string) and
+ if the \c info.program attribute matches the program original specified
+ when creating the factory.
+*/
+
+bool PipeProcessBackendFactory::canCreate(const ProcessInfo& info) const
+{
+ QString program = QFileInfo(info.program()).fileName();
+ return (m_process &&
+ m_process->state() == QProcess::Running &&
+ info.value("pipe").toString() == "true" &&
+ program == m_program);
+}
+
+/*!
+ If there is a pipe process running, it will be returned here.
+ */
+
+QList<Q_PID> PipeProcessBackendFactory::internalProcesses()
+{
+ QList<Q_PID> list;
+ if (m_process)
+ list << m_process->pid();
+ return list;
+}
+
+/*!
+ Send \a message to a pipe process.
+ */
+bool PipeProcessBackendFactory::send(const QJsonObject& message)
+{
+ qDebug() << Q_FUNC_INFO << message;
+
+ if (m_process->state() != QProcess::Running) {
+ qCritical("Pipe process not running");
+ return false;
+ }
+ if (m_process->write(QJsonDocument(message).toBinaryData()) == -1) {
+ qCritical("Unable to write to pipe process");
+ return false;
+ }
+ return true;
+}
+
+
+void PipeProcessBackendFactory::pipeReadyReadStandardOutput()
+{
+ m_buffer.append(m_process->readAllStandardOutput());
+ while (m_buffer.size() >= 12) { // QJsonDocuments are at least this large
+ if (QJsonDocument::BinaryFormatTag != *((uint *) m_buffer.data()))
+ qFatal("ERROR in receive buffer: %s", m_buffer.data());
+ qint32 message_size = qFromLittleEndian(((qint32 *)m_buffer.data())[2]) + 8;
+ if (m_buffer.size() < message_size)
+ break;
+ QByteArray msg = m_buffer.left(message_size);
+ m_buffer = m_buffer.mid(message_size);
+ receive(QJsonDocument::fromBinaryData(msg).object());
+ }
+}
+
+void PipeProcessBackendFactory::pipeReadyReadStandardError()
+{
+ const QByteArray byteArray = m_process->readAllStandardError();
+ QList<QByteArray> lines = byteArray.split('\n');
+ foreach (const QByteArray& line, lines) {
+ if (line.size())
+ qDebug() << "PIPE STDERR" << line;
+ }
+}
+
+void PipeProcessBackendFactory::pipeStarted()
+{
+ qDebug() << "Pipe process started";
+}
+
+void PipeProcessBackendFactory::pipeError(QProcess::ProcessError error)
+{
+ qWarning("Pipe process error: %d", error);
+}
+
+void PipeProcessBackendFactory::pipeFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ qCritical("Pipe process died, exit code=%d status=%d", exitCode, exitStatus);
+ delete m_process;
+ m_process = NULL;
+}
+
+void PipeProcessBackendFactory::pipeStateChanged(QProcess::ProcessState state)
+{
+ qDebug() << "Pipe process state change" << state;
+}
+
+#include "moc_pipeprocessbackendfactory.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/pipeprocessbackendfactory.h b/src/core/pipeprocessbackendfactory.h
new file mode 100644
index 0000000..20f461b
--- /dev/null
+++ b/src/core/pipeprocessbackendfactory.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PIPE_PROCESS_BACKEND_FACTORY_H
+#define PIPE_PROCESS_BACKEND_FACTORY_H
+
+#include "remoteprocessbackendfactory.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class PipeProcessBackendFactory : public RemoteProcessBackendFactory
+{
+ Q_OBJECT
+public:
+ PipeProcessBackendFactory(const ProcessInfo& info, const QString& program, QObject *parent = 0);
+ virtual ~PipeProcessBackendFactory();
+
+ virtual bool canCreate(const ProcessInfo& info) const;
+ virtual QList<Q_PID> internalProcesses();
+
+protected:
+ virtual bool send(const QJsonObject&);
+
+private slots:
+ void pipeReadyReadStandardOutput();
+ void pipeReadyReadStandardError();
+ void pipeStarted();
+ void pipeError(QProcess::ProcessError error);
+ void pipeFinished(int exitCode, QProcess::ExitStatus exitStatus);
+ void pipeStateChanged(QProcess::ProcessState state);
+
+private:
+ QProcess *m_process;
+ QString m_program;
+ QByteArray m_buffer;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // PIPE_PROCESS_BACKEND_FACTORY_H
diff --git a/src/core/prelaunchprocessbackend.cpp b/src/core/prelaunchprocessbackend.cpp
new file mode 100644
index 0000000..5408aa5
--- /dev/null
+++ b/src/core/prelaunchprocessbackend.cpp
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "prelaunchprocessbackend.h"
+
+#include <qjsondocument.h>
+#include <QUuid>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \class PrelaunchProcessBackend
+ \brief The PrelaunchProcessBackend class encapsulates a process that is started and later told what to run.
+
+ The PrelaunchProcessBackend class contains an internal QProcess object that is
+ "prelaunched" by the PrelaunchProcessBackendFactory object. When the factory
+ is asked to create a new process, the prelaunched backend is returned. When start() is
+ called, the prelaunched process is passed a ProcessInfo record encoded in QBinaryJson
+ document format (a serialized JSON object). This record should be used by the
+ prelaunched process to transform itself into the correctly running application.
+ */
+
+/*!
+ Construct a PrelaunchProcessBackend with ProcessInfo \a info and optional \a parent.
+ The \a info ProcessInfo is used to start the internal QProcess. This is different
+ from the final ProcessInfo which will be directly passed to the running QProcess.
+ */
+
+PrelaunchProcessBackend::PrelaunchProcessBackend(const ProcessInfo &info, QObject *parent)
+ : UnixProcessBackend(info, parent)
+ , m_started(false)
+{
+}
+
+/*!
+ Destroy this and child objects
+*/
+
+PrelaunchProcessBackend::~PrelaunchProcessBackend()
+{
+}
+
+/*!
+ Starts the internal QProcess with the prelaunch information.
+ */
+
+void PrelaunchProcessBackend::prestart()
+{
+ if (createProcess())
+ startProcess();
+}
+
+/*!
+ Switch the stored ProcessInfo to the final \a info object.
+ This function also updates the identifier of the process.
+ */
+
+void PrelaunchProcessBackend::setInfo(const ProcessInfo& info)
+{
+ m_info = info;
+ createName();
+}
+
+/*!
+ Pretend to start the prelaunched process.
+ The stored ProcessInfo record is written to the internal QProcess as a serialized
+ JSON object (the internal QProcess receives it from stdin).
+ Then emit all queued signals that were captured from the QProcess.
+ */
+
+void PrelaunchProcessBackend::start()
+{
+ if (m_started) {
+ qWarning() << "Can't restart prelaunched process";
+ return;
+ }
+
+ m_started = true;
+ // Pass the actual process info to the child process
+ QByteArray byteArray = QJsonDocument::fromVariant(m_info.toMap()).toBinaryData();
+ write(byteArray.data(), byteArray.size());
+
+ while (m_queue.size()) {
+ QueuedSignal s = m_queue.takeFirst();
+ switch (s.name) {
+ case QueuedSignal::StateChanged:
+ emit stateChanged(s.n.state);
+ break;
+ case QueuedSignal::Started:
+ emit started();
+ break;
+ case QueuedSignal::Error:
+ emit error(s.n.error);
+ break;
+ case QueuedSignal::Finished:
+ emit finished(s.n.f.exitCode, s.n.f.exitStatus);
+ break;
+ }
+ }
+}
+
+/*!
+ Return the current process state. Until the process has been
+ officially "started", the state has to be NotRunning.
+ */
+
+QProcess::ProcessState PrelaunchProcessBackend::state() const
+{
+ if (m_started)
+ return UnixProcessBackend::state();
+ else
+ return QProcess::NotRunning;
+}
+
+/*!
+ \internal
+*/
+void PrelaunchProcessBackend::handleProcessStarted()
+{
+ UnixProcessBackend::handleProcessStarted();
+ if (m_started)
+ emit started();
+ else {
+ QueuedSignal s;
+ s.name = QueuedSignal::Started;
+ m_queue << s;
+ }
+}
+
+/*!
+ \internal
+*/
+void PrelaunchProcessBackend::handleProcessError(QProcess::ProcessError processError)
+{
+ UnixProcessBackend::handleProcessError(processError);
+ if (m_started)
+ emit error(processError);
+ else {
+ QueuedSignal s;
+ s.name = QueuedSignal::Error;
+ s.n.error = processError;
+ m_queue << s;
+ }
+}
+
+/*!
+ \internal
+*/
+void PrelaunchProcessBackend::handleProcessFinished(int exitCode, QProcess::ExitStatus status)
+{
+ UnixProcessBackend::handleProcessFinished(exitCode, status);
+ if (m_started)
+ emit finished(exitCode, status);
+ else {
+ QueuedSignal s;
+ s.name = QueuedSignal::Finished;
+ s.n.f.exitCode = exitCode;
+ s.n.f.exitStatus = status;
+ m_queue << s;
+ }
+}
+
+/*!
+ \internal
+*/
+void PrelaunchProcessBackend::handleProcessStateChanged(QProcess::ProcessState state)
+{
+ UnixProcessBackend::handleProcessStateChanged(state);
+ if (m_started)
+ emit stateChanged(state);
+ else {
+ QueuedSignal s;
+ s.name = QueuedSignal::StateChanged;
+ s.n.state = state;
+ m_queue << s;
+ }
+}
+
+/*!
+ \class QueuedSignal
+ \internal
+ */
+
+/*!
+ \enum QueuedSignal::SignalName
+ \internal
+ */
+
+#include "moc_prelaunchprocessbackend.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/prelaunchprocessbackend.h b/src/core/prelaunchprocessbackend.h
new file mode 100644
index 0000000..ab21da6
--- /dev/null
+++ b/src/core/prelaunchprocessbackend.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PRELAUNCHPROCESSBACKEND_H
+#define PRELAUNCHPROCESSBACKEND_H
+
+#include "unixprocessbackend.h"
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class QueuedSignal
+{
+public:
+ enum SignalName { StateChanged, Started, Error, Finished };
+
+ SignalName name;
+ union {
+ QProcess::ProcessError error;
+ struct {
+ int exitCode;
+ QProcess::ExitStatus exitStatus;
+ } f;
+ QProcess::ProcessState state;
+ } n;
+};
+
+class PrelaunchProcessBackend : public UnixProcessBackend
+{
+ Q_OBJECT
+
+public:
+ PrelaunchProcessBackend(const ProcessInfo& info, QObject *parent);
+ virtual ~PrelaunchProcessBackend();
+
+ void prestart();
+ void setInfo(const ProcessInfo& info);
+
+ virtual void start();
+ virtual QProcess::ProcessState state() const;
+
+private slots:
+ void handleProcessStarted();
+ void handleProcessError(QProcess::ProcessError error);
+ void handleProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
+ void handleProcessStateChanged(QProcess::ProcessState state);
+
+private:
+ QList<QueuedSignal> m_queue;
+ bool m_started;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // PRELAUNCHPROCESSBACKEND_H
diff --git a/src/core/prelaunchprocessbackendfactory.cpp b/src/core/prelaunchprocessbackendfactory.cpp
new file mode 100644
index 0000000..c65dcc3
--- /dev/null
+++ b/src/core/prelaunchprocessbackendfactory.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDebug>
+
+#include "prelaunchprocessbackendfactory.h"
+#include "prelaunchprocessbackend.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+const int kPrelaunchTimerInterval = 1000;
+
+/*!
+ \class PrelaunchProcessBackendFactory
+ \brief The PrelaunchProcessBackendFactory class creates PrelaunchProcessBackend objects
+
+ The PrelaunchProcessBackendFactory starts up a PrelaunchProcessBackend using
+ information passed in the constructor.
+*/
+
+/*!
+ Construct a PrelaunchProcessBackendFactory with optional \a parent.
+ The \a info ProcessInfo is used to start the prelaunched process. This is
+ different from the final ProcessInfo which will be passed to the prelaunched
+ process as a QBinaryJson document.
+*/
+
+PrelaunchProcessBackendFactory::PrelaunchProcessBackendFactory(const ProcessInfo& info, QObject *parent)
+ : ProcessBackendFactory(parent)
+ , m_prelaunch(NULL)
+ , m_info(info)
+{
+ connect(&m_timer, SIGNAL(timeout()), SLOT(timeout()));
+ m_timer.setSingleShot(true);
+ m_timer.setInterval(kPrelaunchTimerInterval);
+ m_timer.start();
+}
+
+/*!
+ Destroy this and child objects.
+*/
+
+PrelaunchProcessBackendFactory::~PrelaunchProcessBackendFactory()
+{
+}
+
+/*!
+ The PrelaunchProcessBackendFactory will match the ProcessInfo \a info
+ if there is a \c info.prelaunch attribute set to "true" (the string) and
+ if the \c info.program attribute matches the program attribute of the
+ original ProcessInfo record used to create the PrelaunchProcessBackendFactory.
+*/
+
+bool PrelaunchProcessBackendFactory::canCreate(const ProcessInfo& info) const
+{
+ return (info.value("prelaunch").toString() == "true" &&
+ info.program() == m_info.program());
+}
+
+/*!
+ Construct a PrelaunchProcessBackend from a ProcessInfo \a info record with \a parent.
+*/
+
+ProcessBackend * PrelaunchProcessBackendFactory::create(const ProcessInfo& info, QObject *parent)
+{
+ PrelaunchProcessBackend *prelaunch = m_prelaunch;
+
+ if ( prelaunch && prelaunch->state() != QProcess::NotRunning) {
+ m_prelaunch = NULL;
+ m_timer.start();
+ prelaunch->setInfo(info);
+ prelaunch->setParent(parent);
+ return prelaunch;
+ }
+
+ qDebug() << "Creating prelaunch from scratch";
+ prelaunch = new PrelaunchProcessBackend(m_info, parent);
+ prelaunch->prestart();
+ prelaunch->setInfo(info);
+ return prelaunch;
+}
+
+/*!
+ If there is a prelaunched process running, it will be return here.
+ */
+
+QList<Q_PID> PrelaunchProcessBackendFactory::internalProcesses()
+{
+ QList<Q_PID> list;
+ if (m_prelaunch)
+ list << m_prelaunch->pid();
+ return list;
+}
+
+/*!
+ Under memory restriction, terminate the prelaunch process.
+ */
+
+void PrelaunchProcessBackendFactory::handleMemoryRestrictionChange()
+{
+ if ( m_memoryRestricted ) {
+ m_timer.stop();
+ if (m_prelaunch) {
+ delete m_prelaunch; // This will kill the child process as well
+ m_prelaunch = NULL;
+ }
+ } else {
+ Q_ASSERT(m_prelaunch == NULL);
+ m_timer.start();
+ }
+}
+
+void PrelaunchProcessBackendFactory::timeout()
+{
+ Q_ASSERT(m_prelaunch == NULL);
+ Q_ASSERT(!m_memoryRestricted);
+
+ m_prelaunch = new PrelaunchProcessBackend(m_info, this);
+ m_prelaunch->prestart();
+}
+
+#include "moc_prelaunchprocessbackendfactory.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/prelaunchprocessbackendfactory.h b/src/core/prelaunchprocessbackendfactory.h
new file mode 100644
index 0000000..c066026
--- /dev/null
+++ b/src/core/prelaunchprocessbackendfactory.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PRELAUNCH_PROCESS_BACKEND_FACTORY_H
+#define PRELAUNCH_PROCESS_BACKEND_FACTORY_H
+
+#include "processbackendfactory.h"
+#include "processinfo.h"
+#include "processmanager-global.h"
+#include <QTimer>
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class PrelaunchProcessBackend;
+
+class PrelaunchProcessBackendFactory : public ProcessBackendFactory
+{
+ Q_OBJECT
+public:
+ PrelaunchProcessBackendFactory(const ProcessInfo& info, QObject *parent = 0);
+ virtual ~PrelaunchProcessBackendFactory();
+ virtual bool canCreate(const ProcessInfo& info) const;
+ virtual ProcessBackend *create(const ProcessInfo& info, QObject *parent);
+
+ virtual QList<Q_PID> internalProcesses();
+
+protected:
+ virtual void handleMemoryRestrictionChange();
+
+private slots:
+ void timeout();
+
+private:
+ PrelaunchProcessBackend *m_prelaunch;
+ ProcessInfo m_info;
+ QTimer m_timer;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // PRELAUNCH_PROCESS_BACKEND_FACTORY_H
diff --git a/src/core/process.cpp b/src/core/process.cpp
new file mode 100644
index 0000000..f838dc9
--- /dev/null
+++ b/src/core/process.cpp
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "process.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \class Process
+ \brief The Process class contains common enumaration definitions for the process manager.
+*/
+
+/*!
+ \enum Process::ProcessError
+
+ This enum is an exact match for QProcess::ProcessError. It
+ has been duplicated here so that it can be exposed to QML.
+
+ \value FailedToStart The process failed to start. Either the
+ invoked program is missing, or you may have insufficient
+ permissions to invoke the program.
+
+ \value Crashed The process crashed some time after starting
+ successfully.
+
+ \value Timedout The last waitFor...() function timed out. The
+ state of QProcess is unchanged, and you can try calling
+ waitFor...() again.
+
+ \value WriteError An error occurred when attempting to write to the
+ process. For example, the process may not be running, or it may
+ have closed its input channel.
+
+ \value ReadError An error occurred when attempting to read from
+ the process. For example, the process may not be running.
+
+ \value UnknownError An unknown error occurred. This is the default
+ return value of error().
+*/
+
+/*!
+ \enum Process::ProcessState
+
+ This enum is an exact match for QProcess::ProcessState. It
+ has been duplicated here so that it can be exposed to QML.
+
+ \value NotRunning The process is not running.
+
+ \value Starting The process is starting, but the program has not
+ yet been invoked.
+
+ \value Running The process is running and is ready for reading and
+ writing.
+*/
+
+/*!
+ \enum Process::ExitStatus
+
+ This enum is an exact match for QProcess::ExitStatus. It
+ has been duplicated here so that it can be exposed to QML.
+
+ \value NormalExit The process exited normally.
+
+ \value CrashExit The process crashed.
+*/
+
+
+#include "moc_process.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/process.h b/src/core/process.h
new file mode 100644
index 0000000..7f0a751
--- /dev/null
+++ b/src/core/process.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef _PROCESS_H
+#define _PROCESS_H
+
+#include "processmanager-global.h"
+#include <QObject>
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class Process : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum ProcessError { FailedToStart, Crashed, Timedout, ReadError, WriteError, UnknownError };
+ enum ProcessState { NotRunning, Starting, Running };
+ enum ExitStatus { NormalExit, CrashExit };
+
+ Q_ENUMS(ProcessError)
+ Q_ENUMS(ProcessState)
+ Q_ENUMS(ExitStatus)
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // _PROCESS_H
diff --git a/src/core/processbackend.cpp b/src/core/processbackend.cpp
new file mode 100644
index 0000000..c3da1a1
--- /dev/null
+++ b/src/core/processbackend.cpp
@@ -0,0 +1,464 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "processbackend.h"
+
+#include <QDateTime>
+#include <QUuid>
+#include <QDebug>
+#include <QFile>
+#include <QByteArray>
+#include <stdio.h>
+
+/***************************************************************************************/
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \class ProcessBackend
+ \brief The ProcessBackend class is a generalized representation of a process.
+
+ The ProcessBackend class encapsulates a process whose lifecycle is controlled by the process manager.
+ It is a generalized representation - in actuality, subclasses of the ProcessBackend class are used
+ to control processes. These subclasses are used to accelerate process launching, wrap
+ processes with additional arguments and settings, or fake the existence of a process.
+ The ProcessBackend class itself cannot be instantiated.
+
+ A ProcessBackend object always contains a ProcessInfo object, which is the static information
+ used to start and execute the process.
+
+ Because ProcessBackends represent actual or fake processes, they can only
+ modify a few of the process properties. Currently the ProcessBackend can
+ only modify the process priority (or niceness) and the oomAdjustment score (for Linux
+ systems). All other process properties (such as UID, GID, program name) can
+ be considered fixed.
+
+ Furthermore, please note that setting these dynamic values can take time -
+ for example, they may require some intra-application communication. For example,
+ if the process manager has delegated starting applications to some kind of
+ pipe process, then the process manager itself may not be running with
+ sufficient permissions to change the priority or oomAdjustment value to the
+ desired setting. In this case, the process manager must request that the pipe
+ process make the changes, which will result in some time delay before the
+ changes are real. In this case, the actualPriority() and desiredPriority()
+ functions will return different values until the IPC has completed.
+*/
+
+/*!
+ \internal
+ Constructs a ProcessBackend instance with ProcessInfo \a info and optional \a parent
+*/
+ProcessBackend::ProcessBackend(const ProcessInfo& info, QObject *parent)
+ : QObject(parent)
+ , m_info(info)
+ , m_echo(ProcessBackend::EchoStdoutStderr)
+{
+ static int backend_count = 0;
+ m_id = ++backend_count;
+ createName();
+}
+
+/*!
+ Destroy this process object.
+*/
+
+ProcessBackend::~ProcessBackend()
+{
+}
+
+/*!
+ Return the process name
+*/
+
+QString ProcessBackend::name() const
+{
+ return m_name;
+}
+
+/*!
+ Return the process identifier
+*/
+
+QString ProcessBackend::identifier() const
+{
+ return m_info.identifier();
+}
+
+/*!
+ Return the process program
+*/
+
+QString ProcessBackend::program() const
+{
+ return m_info.program();
+}
+
+/*!
+ Return the process arguments
+*/
+
+QStringList ProcessBackend::arguments() const
+{
+ return m_info.arguments();
+}
+
+/*!
+ Return the process environment
+*/
+
+QVariantMap ProcessBackend::environment() const
+{
+ return m_info.environment();
+}
+
+/*!
+ Return the process working directory
+*/
+
+QString ProcessBackend::workingDirectory() const
+{
+ return m_info.workingDirectory();
+}
+
+/*!
+ Return the process UID
+*/
+
+qint64 ProcessBackend::uid() const
+{
+ return 0;
+}
+
+/*!
+ Return the process GID
+*/
+
+qint64 ProcessBackend::gid() const
+{
+ return 0;
+}
+
+/*!
+ Returns the PID of this process. If the process has not started up yet properly, its PID will be 0.
+*/
+Q_PID ProcessBackend::pid() const
+{
+ return 0;
+}
+
+/*!
+ Return the desired process priority. This may not be
+ the same as the actual priority
+*/
+
+qint32 ProcessBackend::desiredPriority() const
+{
+ return m_info.priority();
+}
+
+/*!
+ Return the actual process priority. This should be
+ overriden by a subclass.
+*/
+
+qint32 ProcessBackend::actualPriority() const
+{
+ return 0;
+}
+
+/*!
+ Set the process priority to \a priority.
+ The base class updates the ProcessInfo object
+ Subclasses should should override this function.
+*/
+
+void ProcessBackend::setDesiredPriority(qint32 priority)
+{
+ m_info.setPriority(priority);
+}
+
+/*!
+ Return the desired process oomAdjustment
+*/
+
+qint32 ProcessBackend::desiredOomAdjustment() const
+{
+ return m_info.oomAdjustment();
+}
+
+/*!
+ Return the actual process oomAdjustment
+ Override this in a subclass that actual touches the oomAdjustment
+*/
+
+qint32 ProcessBackend::actualOomAdjustment() const
+{
+ return 0;
+}
+
+/*!
+ Set the process desired \a oomAdjustment.
+ The base class updates the ProcessInfo object
+ Subclasses should override this function.
+
+ Please note that there is no guarantee that the actual
+ oomAdjustment will match the desired oomAdjustment.
+*/
+
+void ProcessBackend::setDesiredOomAdjustment(qint32 oomAdjustment)
+{
+ m_info.setOomAdjustment(oomAdjustment);
+}
+
+/*!
+ \fn QProcess::ProcessState ProcessBackend::state() const
+
+ Returns the state of the process.
+*/
+
+/*!
+ \fn void ProcessBackend::start()
+ \brief Starts the process.
+
+ After the process is started, the started() signal is emitted.
+ If a process fails to start (e.g. because it doesn't give any output until timeout) then
+ the (partly) started process is killed and error(QProcess::FailedToStart) is emitted.
+
+ This function must be overridden in subclasses.
+
+ \sa started()
+ \sa error()
+*/
+
+/*!
+ \fn void ProcessBackend::stop(int timeout)
+
+ Attempts to stop a process by giving it a \a timeout time to die, measured in milliseconds.
+ If the process does not die in the given time limit, it is killed.
+
+ \sa finished()
+*/
+
+/*!
+ Writes at most \a maxSize bytes of data from \a data to the process.
+ Returns the number of bytes that were actually written, or -1 if an error occurred.
+*/
+
+qint64 ProcessBackend::write(const char *data, qint64 maxSize)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(maxSize);
+ return -1;
+}
+
+/*!
+ Writes \a data from a zero-terminated string of 8-bit characters to the process.
+ Returns the number of bytes that were actually written, or -1 if an error occurred.
+ This is equivalent to
+
+\code
+ ProcessFrontend::write(data, qstrlen(data));
+\endcode
+ */
+
+qint64 ProcessBackend::write(const char *data)
+{
+ return write(data, qstrlen(data));
+}
+
+/*!
+ Writes the content of \a byteArray to the process.
+ Returns the number of bytes that were actually written, or -1 if an error occurred.
+ */
+
+qint64 ProcessBackend::write(const QByteArray& byteArray)
+{
+ return write(byteArray.data(), byteArray.length());
+}
+
+/*!
+ \enum ProcessBackend::EchoOutput
+
+ This enum is used to control if data should be copied from an individual
+ process stdout/stderr to the global stdout/stderr. By default, it is
+ set to \c ProcessBackend::EchoStdoutStderr, which means that all data
+ from the child process will be copied to stdout and stderr.
+
+ \value EchoNone No data will be displayed
+ \value EchoStdoutOnly Data from the child's stdout will be displayed
+ \value EchoStderrOnly Data from the child's stderr will be displayed
+ \value EchoStdoutStderr All data will be displayed.
+ */
+
+/*!
+ Return the current echo setting.
+ */
+
+ProcessBackend::EchoOutput ProcessBackend::echo() const
+{
+ return m_echo;
+}
+
+/*!
+ Set the \a echo setting
+ */
+
+void ProcessBackend::setEcho( ProcessBackend::EchoOutput echo )
+{
+ m_echo = echo;
+}
+
+/*!
+ Return a copy of the current ProcessInfo
+ */
+
+ProcessInfo ProcessBackend::processInfo() const
+{
+ return m_info;
+}
+
+/*!
+ \internal
+ */
+
+static void _writeByteArrayToFd(const QByteArray& data, const QByteArray& prefix, FILE *fh)
+{
+ QList<QByteArray> lines = data.split('\n');
+ if (lines.isEmpty())
+ return;
+
+ // If the last item was a separator, there will be an extra blank item at the end
+ if (lines.last().isEmpty())
+ lines.removeLast();
+
+ if (!lines.isEmpty()) {
+ QFile f;
+ f.open(fh, QIODevice::WriteOnly);
+ foreach (const QByteArray& line, lines) {
+ f.write(prefix);
+ f.write(line);
+ f.write("\n");
+ }
+ f.close();
+ }
+}
+
+/*!
+ Handler for standard output \a byteArray, read from the running process.
+
+ Reimplement this method to provide handling for standard output.
+*/
+void ProcessBackend::handleStandardOutput(const QByteArray &byteArray)
+{
+ if (m_echo == EchoStdoutOnly || m_echo == EchoStdoutStderr) {
+ QByteArray prefix = QString("%1 [%2]: ").arg(m_name).arg(pid()).toLocal8Bit();
+ _writeByteArrayToFd( byteArray, prefix, stderr );
+ }
+ emit standardOutput(byteArray);
+}
+
+/*!
+ Handler for standard error \a byteArray, read from the running process.
+
+ Reimplement this method to provide handling for standard error output.
+*/
+void ProcessBackend::handleStandardError(const QByteArray &byteArray)
+{
+ if (m_echo == EchoStderrOnly || m_echo == EchoStdoutStderr) {
+ QByteArray prefix = QString("%1 [%2] ERR: ").arg(m_name).arg(pid()).toLocal8Bit();
+ _writeByteArrayToFd( byteArray, prefix, stderr );
+ }
+ emit standardError(byteArray);
+}
+
+/*!
+ This function set the name of the process to be "NAME-ID".
+ If you need to change the name of the process (for example, from a prelaunch backend),
+ then call this function after changing the name.
+ */
+
+void ProcessBackend::createName()
+{
+ m_name = QString("%1-%2").arg(m_info.identifier().isEmpty()
+ ? QString("process")
+ : m_info.identifier()).arg(m_id);
+}
+
+/*!
+ \fn void ProcessBackend::started()
+ This signal is emitted when the proces has started successfully.
+*/
+
+/*!
+ \fn void ProcessBackend::error(QProcess::ProcessError error)
+ This signal is emitted on a process error. The \a error argument
+ is the error emitted by the internal QProcess.
+*/
+
+/*!
+ \fn void ProcessBackend::finished(int exitCode, QProcess::ExitStatus exitStatus)
+ This signal is emitted when the process has stopped and its execution is over.
+ The \a exitStatus tells you how the process exited; the \a exitCode is the
+ return value of the process.
+
+ Please note: The \a exitStatus will be QProcess::CrashExit only if the
+ ProcessManager stops the process externally. A normal process that crashes
+ will have an \a exitStatus of QProcess::NormalExit with a non-zero \a exitCode.
+*/
+
+/*!
+ \fn void ProcessBackend::stateChanged(QProcess::ProcessState newState)
+ This signal is emitted whenever the state of QProcess changes. The \a newState argument
+ is the state the internal QProcess changed to.
+*/
+
+/*!
+ \fn void ProcessBackend::standardOutput(const QByteArray& data)
+ This signal is emitted whenever standard output \a data is received from the child.
+*/
+
+/*!
+ \fn void ProcessBackend::standardError(const QByteArray& data)
+ This signal is emitted whenever standard error \a data is received from the child
+*/
+
+#include "moc_processbackend.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/processbackend.h b/src/core/processbackend.h
new file mode 100644
index 0000000..87fdff8
--- /dev/null
+++ b/src/core/processbackend.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PROCESS_BACKEND_H
+#define PROCESS_BACKEND_H
+
+#include <QObject>
+#include "processinfo.h"
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class ProcessBackend : public QObject
+{
+ Q_OBJECT
+
+protected:
+ ProcessBackend(const ProcessInfo& info, QObject *parent);
+
+public:
+ virtual ~ProcessBackend();
+
+ virtual QString name() const;
+ virtual QString identifier() const;
+ virtual QString program() const;
+ virtual QStringList arguments() const;
+ virtual QVariantMap environment() const;
+ virtual QString workingDirectory() const;
+
+ virtual qint64 uid() const;
+ virtual qint64 gid() const;
+ virtual Q_PID pid() const;
+
+ virtual qint32 actualPriority() const;
+ virtual qint32 desiredPriority() const;
+ virtual void setDesiredPriority(qint32);
+
+ virtual qint32 actualOomAdjustment() const;
+ virtual qint32 desiredOomAdjustment() const;
+ virtual void setDesiredOomAdjustment(qint32);
+
+ virtual QProcess::ProcessState state() const = 0;
+ virtual void start() = 0;
+ virtual void stop(int timeout = 500) = 0;
+ virtual qint64 write(const char *data, qint64 maxSize);
+
+ qint64 write(const char *data);
+ qint64 write(const QByteArray& byteArray);
+
+ enum EchoOutput { EchoNone, EchoStdoutOnly, EchoStderrOnly, EchoStdoutStderr };
+ EchoOutput echo() const;
+ void setEcho(EchoOutput);
+
+ ProcessInfo processInfo() const;
+
+protected:
+ virtual void handleStandardOutput(const QByteArray &output);
+ virtual void handleStandardError(const QByteArray &output);
+
+ void createName();
+
+signals:
+ void started();
+ void error(QProcess::ProcessError error);
+ void finished(int, QProcess::ExitStatus);
+ void stateChanged(QProcess::ProcessState);
+ void standardOutput(const QByteArray&);
+ void standardError(const QByteArray&);
+
+protected:
+ QString m_name;
+ int m_id;
+ ProcessInfo m_info;
+ EchoOutput m_echo;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE_PROCESSMANAGER(ProcessBackend)*)
+
+#endif // PROCESS_BACKEND_H
diff --git a/src/core/processbackendfactory.cpp b/src/core/processbackendfactory.cpp
new file mode 100644
index 0000000..3fcf710
--- /dev/null
+++ b/src/core/processbackendfactory.cpp
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "processbackendfactory.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \class ProcessBackendFactory
+ \brief The ProcessBackendFactory class is a virtual class for creating processes.
+
+ Subclass this class to create particular types of processes.
+*/
+
+/*!
+ Construct a ProcessBackendFactory with an optional \a parent.
+*/
+
+ProcessBackendFactory::ProcessBackendFactory(QObject *parent)
+ : QObject(parent)
+ , m_memoryRestricted(false)
+{
+}
+
+/*!
+ Destroy a process factory
+*/
+
+ProcessBackendFactory::~ProcessBackendFactory()
+{
+}
+
+/*!
+ Control memory restrictions. Setting \a memoryRestricted to
+ true requests the factory to free up as much memory as possible.
+*/
+
+void ProcessBackendFactory::setMemoryRestricted(bool memoryRestricted)
+{
+ if (memoryRestricted != m_memoryRestricted) {
+ m_memoryRestricted = memoryRestricted;
+ handleMemoryRestrictionChange();
+ }
+}
+
+/*!
+ Override this is subclasses to return a list of internal
+ processes that are contained in this factory. The default
+ class returns an empty list.
+ */
+
+QList<Q_PID> ProcessBackendFactory::internalProcesses()
+{
+ return QList<Q_PID>();
+}
+
+/*!
+ Override this in subclasses to handle memory restriction changes
+*/
+
+void ProcessBackendFactory::handleMemoryRestrictionChange()
+{
+}
+
+/*!
+ \fn bool ProcessBackendFactory::canCreate(const ProcessInfo& info) const
+
+ Return true if this ProcessBackendFactory matches the ProcessInfo \a info
+ process binding and can create an appropriate process.
+
+ This virtual function must be overridden.
+*/
+
+/*!
+ \fn ProcessBackend * ProcessBackendFactory::create(const ProcessInfo& info, QObject *parent)
+
+ Create a ProcessBackend object based on the ProcessInfo \a info and \a parent.
+*/
+
+#include "moc_processbackendfactory.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/processbackendfactory.h b/src/core/processbackendfactory.h
new file mode 100644
index 0000000..9130ce1
--- /dev/null
+++ b/src/core/processbackendfactory.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PROCESS_BACKEND_FACTORY_H
+#define PROCESS_BACKEND_FACTORY_H
+
+#include <QObject>
+#include <QProcessEnvironment>
+
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class ProcessBackend;
+class ProcessInfo;
+
+class ProcessBackendFactory : public QObject
+{
+ Q_OBJECT
+public:
+ ProcessBackendFactory(QObject *parent = 0);
+ virtual ~ProcessBackendFactory();
+ virtual bool canCreate(const ProcessInfo& info) const = 0;
+ virtual ProcessBackend *create(const ProcessInfo& info, QObject *parent) = 0;
+
+ void setMemoryRestricted(bool);
+ virtual QList<Q_PID> internalProcesses();
+
+protected:
+ virtual void handleMemoryRestrictionChange();
+
+protected:
+ bool m_memoryRestricted;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // PROCESS_BACKEND_FACTORY_H
diff --git a/src/core/processbackendmanager.cpp b/src/core/processbackendmanager.cpp
new file mode 100644
index 0000000..9df3506
--- /dev/null
+++ b/src/core/processbackendmanager.cpp
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "processbackendmanager.h"
+#include "processbackendfactory.h"
+#include "processbackend.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \class ProcessBackendManager
+ \brief The ProcessBackendManager class contains a list of ProcessBackendFactory
+ objects and is used to create ProcessBackend objects.
+
+ The ProcessBackendManager class is a standalone class for creating ProcessBackend
+ objects from factories. Typical use for the backend manager is like:
+
+ \code
+ ProcessBackendManager *bm = new ProcessBackendManager;
+ ProcessInfo info;
+ info.setProgram("/home/me/myprogram");
+ bm->add(new PrelaunchProcessBackendFactory(info);
+ pm->add(new StandardProcessBackendFactory);
+
+ // ...
+
+ ProcessInfo i;
+ i.setProgram("/home/me/myprogram");
+ i.setWorkingDirectory("/root");
+ ProcessBackend *backend = bm->create(i);
+ \endcode
+
+ The backend manager does not get involved in starting or tracking
+ the lifetime of a process. In general, you should use the
+ ProcessManager class for processes, which contains a backend manager object.
+*/
+
+/*!
+ Construct a ProcessBackendManager with an optional \a parent
+*/
+
+ProcessBackendManager::ProcessBackendManager(QObject *parent)
+ : QObject(parent)
+ , m_memoryRestricted(false)
+{
+}
+
+/*!
+ Delete the ProcessBackendManager and terminate all factory processes.
+*/
+
+ProcessBackendManager::~ProcessBackendManager()
+{
+}
+
+/*!
+ Create a new ProcessBackend based on ProcessInfo \a info and \a parent.
+*/
+
+ProcessBackend *ProcessBackendManager::create(const ProcessInfo& info, QObject *parent)
+{
+ foreach (ProcessBackendFactory *factory, m_factories) {
+ if (factory->canCreate(info))
+ return factory->create(info, parent);
+ }
+ return NULL;
+}
+
+/*!
+ Add a ProcessBackendFactory \a factory to the end of the Factory list.
+ The factory becomes a child of the backend manager.
+*/
+
+void ProcessBackendManager::addFactory(ProcessBackendFactory *factory)
+{
+ m_factories.append(factory);
+ factory->setParent(this);
+ factory->setMemoryRestricted(m_memoryRestricted);
+}
+
+/*!
+ Return a list of all internal processes being used by factories
+*/
+
+QList<Q_PID> ProcessBackendManager::internalProcesses()
+{
+ QList<Q_PID> list;
+ foreach (ProcessBackendFactory *factory, m_factories)
+ list.append(factory->internalProcesses());
+ return list;
+}
+
+/*!
+ Set memory restrictions. If \a memoryRestricted is true
+ all factories are requested to minimize memory use.
+*/
+
+void ProcessBackendManager::setMemoryRestricted(bool memoryRestricted)
+{
+ if (m_memoryRestricted != memoryRestricted) {
+ m_memoryRestricted = memoryRestricted;
+ foreach (ProcessBackendFactory *factory, m_factories)
+ factory->setMemoryRestricted(memoryRestricted);
+ }
+}
+
+/*!
+ Return current memory restriction setting
+*/
+
+bool ProcessBackendManager::memoryRestricted() const
+{
+ return m_memoryRestricted;
+}
+
+#include "moc_processbackendmanager.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/processbackendmanager.h b/src/core/processbackendmanager.h
new file mode 100644
index 0000000..6c0d993
--- /dev/null
+++ b/src/core/processbackendmanager.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PROCESS_BACKEND_MANAGER_H
+#define PROCESS_BACKEND_MANAGER_H
+
+#include <QObject>
+#include <QHash>
+#include <QProcessEnvironment>
+
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class ProcessFrontend;
+class ProcessInfo;
+class ProcessBackendFactory;
+class ProcessBackend;
+
+class ProcessBackendManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit ProcessBackendManager(QObject *parent = 0);
+ virtual ~ProcessBackendManager();
+
+ ProcessBackend *create(const ProcessInfo& info, QObject *parent=0);
+ void addFactory(ProcessBackendFactory *factory);
+ QList<Q_PID> internalProcesses();
+
+ void setMemoryRestricted(bool);
+ bool memoryRestricted() const;
+
+private:
+ QList<ProcessBackendFactory*> m_factories;
+ bool m_memoryRestricted;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // PROCESS_BACKEND_MANAGER_H
diff --git a/src/core/processfrontend.cpp b/src/core/processfrontend.cpp
new file mode 100644
index 0000000..4d0b946
--- /dev/null
+++ b/src/core/processfrontend.cpp
@@ -0,0 +1,525 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "processfrontend.h"
+#include "processbackend.h"
+
+#include <QDateTime>
+
+/***************************************************************************************/
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \class ProcessFrontend
+ \brief The ProcessFrontend class is a generalized representation of a process.
+
+ The ProcessFrontend class encapsulates a process whose lifecycle is controlled by the process manager.
+ It is a generalized representation - in actuality, subclasses of the ProcessFrontend class are used
+ to control processes. These subclasses are used to accelerate process launching, wrap
+ processes with additional arguments and settings, or fake the existence of a process.
+ The ProcessFrontend class itself cannot be instantiated.
+
+ A process object always contains a ProcessInfo object, which is the static information
+ used to start and execute the process.
+*/
+
+/*!
+ \property ProcessFrontend::identifier
+ \brief the application identifier of the process.
+*/
+
+/*!
+ \property ProcessFrontend::name
+ \brief the application name of the process.
+*/
+
+/*!
+ \property ProcessFrontend::program
+ \brief the filename of the binary executable that is launched to start up the process.
+*/
+
+/*!
+ \property ProcessFrontend::arguments
+ \brief the arguments that will be passed to the program upon process startup
+*/
+
+/*!
+ \property ProcessFrontend::environment
+ \brief a map of the environment variables that will be used by the process
+*/
+
+/*!
+ \property ProcessFrontend::workingDirectory
+ \brief the directory that will be switched to before launching the process
+*/
+
+/*!
+ \property ProcessFrontend::uid
+ \brief the user id (uid) of the process.
+*/
+
+/*!
+ \property ProcessFrontend::gid
+ \brief the group id (gid) of the process.
+*/
+
+/*!
+ \property ProcessFrontend::pid
+ \brief the process id (PID) of the process.
+
+ Returns 0 if the process has not been started or if this is a "fake" process.
+*/
+
+/*!
+ \property ProcessFrontend::startTime
+ \brief the start time of the process, measured in milliseconds since the epoch (1st Jan 1970 00:00).
+
+ Returns 0 if process has not been started.
+*/
+
+/*!
+ \property ProcessFrontend::priority
+ \brief The Unix process priority (niceness).
+
+ Returns the current process priority if the process is running. Otherwise,
+ it returns the ProcessFrontend priority setting. You can only set the priority once the
+ process is running.
+*/
+
+/*!
+ \property ProcessFrontend::oomAdjustment
+ \brief The Unix process /proc/<pid>/oom_score_adj (likelihood of being killed)
+
+ Returns the current OOM adjustment score if the process is running. Otherwise,
+ it returns the ProcessFrontend OOM adjustment score setting. You can only set the OOM adjustment
+ score when the process is running.
+*/
+
+/*!
+ \internal
+ Constructs a ProcessFrontend instance with ProcessBackend \a process and optional \a parent
+ The ProcessFrontend takes ownership of the ProcessBackend.
+*/
+ProcessFrontend::ProcessFrontend(ProcessBackend *backend, QObject *parent)
+ : QObject(parent)
+ , m_startTimeSinceEpoch(0)
+ , m_backend(backend)
+{
+ Q_ASSERT(backend);
+ backend->setParent(this);
+ connect(backend, SIGNAL(started()), SLOT(handleStarted()));
+ connect(backend, SIGNAL(error(QProcess::ProcessError)), SLOT(handleError(QProcess::ProcessError)));
+ connect(backend, SIGNAL(finished(int, QProcess::ExitStatus)),
+ SLOT(handleFinished(int, QProcess::ExitStatus)));
+ connect(backend, SIGNAL(stateChanged(QProcess::ProcessState)),
+ SLOT(handleStateChanged(QProcess::ProcessState)));
+ connect(backend, SIGNAL(standardOutput(const QByteArray&)),
+ SLOT(handleStandardOutput(const QByteArray&)));
+ connect(backend, SIGNAL(standardError(const QByteArray&)),
+ SLOT(handleStandardError(const QByteArray&)));
+}
+
+/*!
+ Destroy this process object.
+*/
+
+ProcessFrontend::~ProcessFrontend()
+{
+}
+
+/*!
+ Return the process identifier
+*/
+
+QString ProcessFrontend::identifier() const
+{
+ Q_ASSERT(m_backend);
+ return m_backend->identifier();
+}
+
+/*!
+ Return the process name
+*/
+
+QString ProcessFrontend::name() const
+{
+ Q_ASSERT(m_backend);
+ return m_backend->name();
+}
+
+/*!
+ Return the process program
+*/
+
+QString ProcessFrontend::program() const
+{
+ Q_ASSERT(m_backend);
+ return m_backend->program();
+}
+
+/*!
+ Return the process arguments
+*/
+
+QStringList ProcessFrontend::arguments() const
+{
+ Q_ASSERT(m_backend);
+ return m_backend->arguments();
+}
+
+/*!
+ Return the process environment
+*/
+
+QVariantMap ProcessFrontend::environment() const
+{
+ Q_ASSERT(m_backend);
+ return m_backend->environment();
+}
+
+/*!
+ Return the process working directory
+*/
+
+QString ProcessFrontend::workingDirectory() const
+{
+ Q_ASSERT(m_backend);
+ return m_backend->workingDirectory();
+}
+
+/*!
+ Return the process UID
+*/
+
+qint64 ProcessFrontend::uid() const
+{
+ Q_ASSERT(m_backend);
+ return m_backend->uid();
+}
+
+/*!
+ Return the process GID
+*/
+
+qint64 ProcessFrontend::gid() const
+{
+ Q_ASSERT(m_backend);
+ return m_backend->gid();
+}
+
+/*!
+ Returns the PID of this process. If the process has not started up yet properly, its PID will be 0.
+*/
+Q_PID ProcessFrontend::pid() const
+{
+ Q_ASSERT(m_backend);
+ return m_backend->pid();
+}
+
+/*!
+ Return the current process priority.
+ This may be different than the desired process priority.
+*/
+
+qint32 ProcessFrontend::priority() const
+{
+ Q_ASSERT(m_backend);
+ return m_backend->actualPriority();
+}
+
+/*!
+ Set the process priority
+*/
+
+void ProcessFrontend::setPriority(qint32 priority)
+{
+ Q_ASSERT(m_backend);
+ if (priority != m_backend->desiredPriority()) {
+ m_backend->setDesiredPriority(priority);
+ emit priorityChanged();
+ }
+}
+
+/*!
+ Return the process actual oomAdjustment
+*/
+
+qint32 ProcessFrontend::oomAdjustment() const
+{
+ Q_ASSERT(m_backend);
+ return m_backend->actualOomAdjustment();
+}
+
+/*!
+ Set the process desired oomAdjustment.
+ This may be different than the actual process oomAdjustment
+*/
+
+void ProcessFrontend::setOomAdjustment(qint32 oomAdjustment)
+{
+ Q_ASSERT(m_backend);
+ if (oomAdjustment != m_backend->desiredOomAdjustment()) {
+ m_backend->setDesiredOomAdjustment(oomAdjustment);
+ emit oomAdjustmentChanged();
+ }
+}
+
+/*!
+ Returns the state of the process.
+ The base class always returns NotRunning.
+*/
+QProcess::ProcessState ProcessFrontend::state() const
+{
+ Q_ASSERT(m_backend);
+ return m_backend->state();
+}
+
+/*!
+ \brief Starts the process.
+
+ After the process is started, the started() signal is emitted.
+ If a process fails to start (e.g. because it doesn't give any output until timeout) then
+ the (partly) started process is killed and error() is emitted.
+
+ This function must be overridden in subclasses.
+
+ \sa started()
+ \sa error()
+*/
+void ProcessFrontend::start()
+{
+ if (state() == QProcess::NotRunning) {
+ Q_ASSERT(m_backend);
+ emit aboutToStart();
+ m_startTimeSinceEpoch = QDateTime::currentMSecsSinceEpoch();
+ m_backend->start();
+ }
+}
+
+/*!
+ Attempts to stop a process by giving it a \a timeout time to die, measured in milliseconds.
+
+ If the process does not die in the given time limit, it is killed.
+
+ \sa finished()
+*/
+void ProcessFrontend::stop(int timeout)
+{
+ Q_ASSERT(m_backend);
+ emit aboutToStop();
+ m_backend->stop(timeout);
+}
+
+/*!
+ Writes at most \a maxSize bytes of data from \a data to the process.
+ Returns the number of bytes that were actually written, or -1 if an error occurred.
+ */
+
+qint64 ProcessFrontend::write(const char *data, qint64 maxSize)
+{
+ return m_backend->write(data, maxSize);
+}
+
+/*!
+ Writes \a data from a zero-terminated string of 8-bit characters to the process.
+ Returns the number of bytes that were actually written, or -1 if an error occurred.
+ This is equivalent to
+
+\code
+ ProcessFrontend::write(data, qstrlen(data));
+\endcode
+ */
+
+qint64 ProcessFrontend::write(const char *data)
+{
+ return m_backend->write(data, qstrlen(data));
+}
+
+/*!
+ Writes the content of \a byteArray to the process.
+ Returns the number of bytes that were actually written, or -1 if an error occurred.
+ */
+
+qint64 ProcessFrontend::write(const QByteArray& byteArray)
+{
+ return m_backend->write(byteArray.data(), byteArray.length());
+}
+
+/*!
+ Returns the start time of the process, measured in milliseconds since the epoch (1st Jan 1970 00:00).
+*/
+qint64 ProcessFrontend::startTime() const
+{
+ return m_startTimeSinceEpoch;
+}
+
+/*!
+ Returns the ProcessInfo object as a QVariantMap.
+
+ If you use this method to retrieve the ProcessInfo content from the C++ side, you can
+ wrap it around ProcessInfo() object for convenience.
+*/
+QVariantMap ProcessFrontend::processInfo() const
+{
+ return m_backend->processInfo().toMap();
+}
+
+/*!
+ Handle a started() signal from the backend.
+ The default implementation emits the started() signal.
+ */
+void ProcessFrontend::handleStarted()
+{
+ emit started();
+}
+
+/*!
+ Handle an error() signal from the backend with \a processError.
+ The default implementation emits the error signal.
+ */
+void ProcessFrontend::handleError(QProcess::ProcessError processError)
+{
+ emit error(processError);
+}
+
+/*!
+ Handle a finished() signal from the backend with \a exitCode and \a exitStatus.
+ The default implementation emits the finished() signal
+ */
+void ProcessFrontend::handleFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ emit finished(exitCode, exitStatus);
+}
+
+/*!
+ Handle a stateChange() signal from the backend with \a state.
+ The default implementation emits the stateChanged() signal
+ */
+void ProcessFrontend::handleStateChanged(QProcess::ProcessState state)
+{
+ emit stateChanged(state);
+}
+
+/*!
+ Handle stdout \a data received from the process.
+ */
+void ProcessFrontend::handleStandardOutput(const QByteArray& data)
+{
+ emit standardOutput(data);
+}
+
+/*!
+ Handle stderr \a data received from the process.
+ */
+void ProcessFrontend::handleStandardError(const QByteArray& data)
+{
+ emit standardError(data);
+}
+
+/*!
+ Returns the backend object for this process.
+*/
+ProcessBackend *ProcessFrontend::backend() const
+{
+ return m_backend;
+}
+
+
+/*!
+ \fn void ProcessFrontend::aboutToStart()
+ This signal is emitted by start() just before the process starts running.
+*/
+
+/*!
+ \fn void ProcessFrontend::aboutToStop()
+ This signal is emitted by stop() just before the process is stopped.
+*/
+
+/*!
+ \fn void ProcessFrontend::started()
+ This signal is emitted when the proces has started successfully.
+*/
+
+/*!
+ \fn void ProcessFrontend::error(QProcess::ProcessError error)
+ This signal is emitted when the process has failed to start or has another \a error.
+*/
+
+/*!
+ \fn void ProcessFrontend::finished(int exitCode, QProcess::ExitStatus exitStatus)
+ This signal is emitted when the process has stopped and its execution is over.
+ The \a exitStatus tells you how the process exited; the \a exitCode is the
+ return value of the process.
+
+ Please note: The \a exitStatus will be QProcess::CrashExit only if the
+ ProcessManager stops the process externally. A normal process that crashes
+ will have an \a exitStatus of QProcess::NormalExit with a non-zero \a exitCode.
+*/
+
+/*!
+ \fn void ProcessFrontend::stateChanged(QProcess::ProcessState newState)
+ This signal is emitted whenever the state of QProcess changes. The \a newState argument
+ is the state the internal QProcess changed to.
+*/
+
+/*!
+ \fn void ProcessFrontend::standardOutput(const QByteArray& data)
+ This signal is emitted whenever \a data is received from the stdout of the process.
+*/
+
+/*!
+ \fn void ProcessFrontend::standardError(const QByteArray& data)
+ This signal is emitted whenever \a data is received from the stderr of the process.
+*/
+
+/*!
+ \fn void ProcessFrontend::priorityChanged()
+ This signal is emitted when the process priority has been changed for a running process.
+*/
+
+/*!
+ \fn void ProcessFrontend::oomAdjustmentChanged()
+ This signal is emitted when the process oomAdjustment has been changed for a running process.
+ Only applicable under Linux.
+*/
+
+#include "moc_processfrontend.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/processfrontend.h b/src/core/processfrontend.h
new file mode 100644
index 0000000..a7a8a6a
--- /dev/null
+++ b/src/core/processfrontend.h
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef PROCESS_FRONTEND_H
+#define PROCESS_FRONTEND_H
+
+#include <QObject>
+#include "processinfo.h"
+
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class ProcessBackend;
+
+class ProcessFrontend : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString identifier READ identifier CONSTANT)
+ Q_PROPERTY(QString name READ name CONSTANT)
+ Q_PROPERTY(QString program READ program CONSTANT)
+ Q_PROPERTY(QStringList arguments READ arguments CONSTANT)
+ Q_PROPERTY(QVariantMap environment READ environment CONSTANT)
+ Q_PROPERTY(QString workingDirectory READ workingDirectory CONSTANT)
+ Q_PROPERTY(qint64 uid READ uid NOTIFY started)
+ Q_PROPERTY(qint64 gid READ gid NOTIFY started)
+
+ Q_PROPERTY(qint64 pid READ pid NOTIFY started)
+ Q_PROPERTY(qint64 startTime READ startTime NOTIFY started)
+
+ Q_PROPERTY(int priority READ priority WRITE setPriority NOTIFY priorityChanged)
+ Q_PROPERTY(int oomAdjustment READ oomAdjustment WRITE setOomAdjustment NOTIFY oomAdjustmentChanged)
+
+public:
+ virtual ~ProcessFrontend();
+
+ QString identifier() const;
+ QString name() const;
+ QString program() const;
+ QStringList arguments() const;
+ QVariantMap environment() const;
+ QString workingDirectory() const;
+
+ qint64 uid() const;
+ qint64 gid() const;
+ Q_PID pid() const;
+
+ qint32 priority() const;
+ void setPriority(qint32);
+
+ qint32 oomAdjustment() const;
+ void setOomAdjustment(qint32);
+
+ QProcess::ProcessState state() const;
+ Q_INVOKABLE virtual void start();
+ Q_INVOKABLE virtual void stop(int timeout = 500);
+
+ qint64 write(const char *data, qint64 maxSize);
+ qint64 write(const char *data);
+ qint64 write(const QByteArray& byteArray);
+
+ qint64 startTime() const;
+
+ Q_INVOKABLE QVariantMap processInfo() const;
+
+signals:
+ void aboutToStart();
+ void aboutToStop();
+
+ void started();
+ void error(QProcess::ProcessError);
+ void finished(int, QProcess::ExitStatus);
+ void stateChanged(QProcess::ProcessState);
+ void standardOutput(const QByteArray&);
+ void standardError(const QByteArray&);
+
+ void priorityChanged();
+ void oomAdjustmentChanged();
+
+protected slots:
+ void handleStarted();
+ void handleError(QProcess::ProcessError);
+ void handleFinished(int, QProcess::ExitStatus);
+ void handleStateChanged(QProcess::ProcessState);
+
+protected:
+ ProcessFrontend(ProcessBackend *backend, QObject *parent=0);
+ ProcessBackend *backend() const;
+
+private slots:
+ void handleStandardOutput(const QByteArray&);
+ void handleStandardError(const QByteArray&);
+
+protected:
+ qint64 m_startTimeSinceEpoch;
+
+private:
+ ProcessBackend *m_backend;
+
+ friend class ProcessManager;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE_PROCESSMANAGER(ProcessFrontend)*)
+Q_DECLARE_METATYPE(const QT_PREPEND_NAMESPACE_PROCESSMANAGER(ProcessFrontend)*)
+
+#endif // PROCESS_FRONTEND_H
diff --git a/src/core/processinfo.cpp b/src/core/processinfo.cpp
new file mode 100644
index 0000000..1f16954
--- /dev/null
+++ b/src/core/processinfo.cpp
@@ -0,0 +1,551 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "processinfo.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \namespace ProcessInfoConstants
+ \target ProcessInfoConstants Namespace
+
+ \brief The ProcessInfoConstants namespace contains constant strings for ProcessInfo.
+*/
+
+/*!
+ \class ProcessInfo
+ \brief The ProcessInfo class is the set of information necessary to start a new process running.
+
+ The ProcessInfo is internally implemented as a simple QVariantMap with a set of pre-defined
+ keys. This intentionally allows the ProcessInfo to be extended by the user without
+ changing the API. The predefined keys are:
+
+ \list
+ \o Identifier
+ \o Program
+ \o Arguments
+ \o Environment
+ \o WorkingDirectory
+ \o UID
+ \o GID
+ \o Priority
+ \o OomAdjustment
+ \endlist
+*/
+
+/*!
+ \property ProcessInfo::identifier
+ \brief the application identifier of the process. The identifier is used to construct
+ a unique name.
+*/
+
+/*!
+ \property ProcessInfo::program
+ \brief the filename of the binary executable that is launched to start up the process.
+*/
+
+/*!
+ \property ProcessInfo::arguments
+ \brief the arguments that will be passed to the program upon process startup
+*/
+
+/*!
+ \property ProcessInfo::environment
+ \brief a map of the environment variables that will be used by the process
+*/
+
+/*!
+ \property ProcessInfo::workingDirectory
+ \brief the directory that will be switched to before launching the process
+*/
+
+/*!
+ \property ProcessInfo::uid
+ \brief the user id (uid) of the process.
+*/
+
+/*!
+ \property ProcessInfo::gid
+ \brief the group id (gid) of the process.
+*/
+
+/*!
+ \property ProcessInfo::priority
+ \brief the Unix priority "niceness" that the program will run at.
+*/
+
+/*!
+ \property ProcessInfo::oomAdjustment
+ \brief the Unix OOM adjustment that programs run at (+1000 = kill me first)
+*/
+/*!
+ \property ProcessInfo::startOutputPattern
+ \brief the start output pattern is QByteArray of a line to match.
+*/
+
+
+/*!
+ Constructs a ProcessInfo instance with optional \a parent.
+*/
+
+ProcessInfo::ProcessInfo(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ Copy constructor for ProcessInfo from \a other
+*/
+
+ProcessInfo::ProcessInfo(const ProcessInfo &other)
+ : QObject(other.parent())
+ , m_info(other.m_info)
+{
+}
+
+/*!
+ Copy constructor for ProcessInfo from \a map
+*/
+
+ProcessInfo::ProcessInfo(const QVariantMap& map)
+ : m_info(map)
+{
+}
+
+/*!
+ Assignment constructor for ProcessInfo from \a other
+*/
+
+ProcessInfo &ProcessInfo::operator =(const ProcessInfo &other)
+{
+ m_info = other.m_info;
+ return *this;
+}
+
+/*!
+ Returns the application identifier of the process. The identifier
+ is used to construct a unique name for the process.
+*/
+
+QString ProcessInfo::identifier() const
+{
+ return m_info.value(ProcessInfoConstants::Identifier).toString();
+}
+
+/*!
+ Set the application identifier of this process.
+*/
+
+void ProcessInfo::setIdentifier(const QString &identifier)
+{
+ setValue(ProcessInfoConstants::Identifier, identifier);
+}
+
+/*!
+ Returns the filename of the binary executable that is launched.
+*/
+
+QString ProcessInfo::program() const
+{
+ return m_info.value(ProcessInfoConstants::Program).toString();
+}
+
+/*!
+ Set the filename of the binary executable to be launched.
+*/
+
+void ProcessInfo::setProgram(const QString &program)
+{
+ m_info.insert(ProcessInfoConstants::Program, program);
+}
+
+/*!
+ Return the argument list.
+*/
+
+QStringList ProcessInfo::arguments() const
+{
+ return m_info.value(ProcessInfoConstants::Arguments).toStringList();
+}
+
+/*!
+ Set the argument list to be passed to the program
+*/
+
+void ProcessInfo::setArguments(const QStringList &argumentList)
+{
+ setValue(ProcessInfoConstants::Arguments, argumentList);
+}
+
+/*!
+ Return the environment map
+*/
+
+QVariantMap ProcessInfo::environment() const
+{
+ return m_info.value(ProcessInfoConstants::Environment).toMap();
+}
+
+/*!
+ Set the environment map
+*/
+
+void ProcessInfo::setEnvironment(const QVariantMap &environmentToSet)
+{
+ setValue(ProcessInfoConstants::Environment, environmentToSet);
+}
+
+/*!
+ Set the environment map using a QProcessEnvironment
+*/
+
+void ProcessInfo::setEnvironment(const QProcessEnvironment &environment)
+{
+ QVariantMap env;
+ QStringList keys = environment.keys();
+
+ foreach (const QString &envKey, keys) {
+ env.insert(envKey, environment.value(envKey));
+ }
+
+ setValue(ProcessInfoConstants::Environment, env);
+}
+
+/*!
+ Return the process working directory
+*/
+
+QString ProcessInfo::workingDirectory() const
+{
+ return m_info.value(ProcessInfoConstants::WorkingDirectory).toString();
+}
+
+/*!
+ Set the process working directory
+*/
+
+void ProcessInfo::setWorkingDirectory(const QString &workingDir)
+{
+ setValue(ProcessInfoConstants::WorkingDirectory, workingDir);
+}
+
+/*!
+ Return the process UID
+
+ Initializing this value to -1 will result in it being set to the process manager's uid.
+*/
+
+qint64 ProcessInfo::uid() const
+{
+ return m_info.value(ProcessInfoConstants::Uid).toLongLong();
+}
+
+/*!
+ Set the process UID
+*/
+
+void ProcessInfo::setUid(qint64 newUid)
+{
+ setValue(ProcessInfoConstants::Uid, newUid);
+}
+
+/*!
+ Return the process GID
+
+ Initializing this value to -1 (or leaving it uninitialized) will result in it being
+ set to the process manager's gid.
+*/
+
+qint64 ProcessInfo::gid() const
+{
+ return m_info.value(ProcessInfoConstants::Priority).toLongLong();
+}
+
+/*!
+ Set the process GID
+*/
+
+void ProcessInfo::setGid(qint64 newGid)
+{
+ setValue(ProcessInfoConstants::Gid, newGid);
+}
+
+/*!
+ Return the process priority
+*/
+
+int ProcessInfo::priority() const
+{
+ return m_info.value(ProcessInfoConstants::Priority).toDouble();
+}
+
+/*!
+ Return the OOM adjustment value
+*/
+
+int ProcessInfo::oomAdjustment() const
+{
+ return m_info.value(ProcessInfoConstants::OomAdjustment).toDouble();
+}
+
+/*!
+ Set the process priority.
+
+ Normally the priority ranges from -20 to +19, but that
+ can vary based on the type of Unix system. A priority of -20
+ delivers most of the CPU to this process; a priority of +19
+ is the lowest and means that this process will be starved unless
+ nothing else is going on in the sytem.
+
+ We do not do any checking on the value set for process priority.
+*/
+
+void ProcessInfo::setPriority(int newPriority)
+{
+ if (newPriority != priority()) {
+ setValue(ProcessInfoConstants::Priority, newPriority);
+ emit priorityChanged();
+ }
+}
+
+/*!
+ Set the process OOM adjustment.
+
+ In modern Linux kernels, the /proc/<pid>/oom_score_adj value
+ may range from -1000 to +1000. A -1000 value represents a process
+ that will never be killed; a 0 is a process that follows normal
+ OOM killer values, and a +1000 represents a process that will
+ always be killed first.
+
+ We do not do any checking on the value set for process priority.
+*/
+
+void ProcessInfo::setOomAdjustment(int newOomAdjustment)
+{
+ if (newOomAdjustment != oomAdjustment()) {
+ setValue(ProcessInfoConstants::OomAdjustment, newOomAdjustment);
+ emit oomAdjustmentChanged();
+ }
+}
+
+/*!
+ Returns the start output pattern.
+
+ \sa setStartOutputPattern
+*/
+QByteArray ProcessInfo::startOutputPattern() const
+{
+ return m_info.value(ProcessInfoConstants::StartOutputPattern).toByteArray();
+}
+
+/*!
+ Sets the start output pattern to \a outputPattern.
+
+ The start output pattern is a string that the process should print when
+ it considers itself ready. Typically, a process is ready after it has
+ started up and performed its initialization successfully.
+*/
+void ProcessInfo::setStartOutputPattern(const QByteArray &outputPattern)
+{
+ setValue(ProcessInfoConstants::StartOutputPattern, outputPattern);
+}
+
+/*!
+ Returns the keys for which values have been set in this ProcessInfo object.
+*/
+QStringList ProcessInfo::keys() const
+{
+ return m_info.keys();
+}
+
+/*!
+ Return true if a value has been set for this \a key
+*/
+
+bool ProcessInfo::contains(const QString &key) const
+{
+ return m_info.contains(key);
+}
+
+/*!
+ Return the value of this \a key
+*/
+
+QVariant ProcessInfo::value(const QString &key) const
+{
+ return m_info.value(key);
+}
+
+/*!
+ Set \a key to \a value and emit appropriate change signals
+*/
+
+void ProcessInfo::setValue(const QString &key, const QVariant &value)
+{
+ if (key.isEmpty())
+ return;
+
+ QVariant oldValue = m_info.value(key);
+ if (oldValue != value) {
+ m_info.insert(key, value);
+ emitChangeSignal(key);
+ }
+}
+
+/*!
+ Sets the data provided by this ProcessInfo object to \a data.
+
+ Overwrites all existing values.
+*/
+void ProcessInfo::setData(const QVariantMap &data)
+{
+ m_info = data;
+}
+
+/*!
+ Applies data provided by \a data on top of the existing data.
+
+ Overwrites existing values if \a data contains the same keys as the
+ original data. Leaves existing values with keys not contained by \a data
+ untouched.
+*/
+void ProcessInfo::insert(const QVariantMap &data)
+{
+ QStringList keys = data.keys();
+ foreach (const QString &key, keys) {
+ m_info.insert(key, data.value(key));
+ }
+}
+
+/*!
+ Return the ProcessInfo object as a QVariantMap
+*/
+QVariantMap ProcessInfo::toMap() const
+{
+ return m_info;
+}
+
+/*!
+ \internal
+*/
+
+void ProcessInfo::emitChangeSignal(const QString &key)
+{
+ if (key == ProcessInfoConstants::Identifier) {
+ emit identifierChanged();
+ } else if (key == ProcessInfoConstants::Program) {
+ emit programChanged();
+ } else if (key == ProcessInfoConstants::Arguments) {
+ emit argumentsChanged();
+ } else if (key == ProcessInfoConstants::Environment) {
+ emit environmentChanged();
+ } else if (key == ProcessInfoConstants::WorkingDirectory) {
+ emit workingDirectoryChanged();
+ } else if (key == ProcessInfoConstants::Uid) {
+ emit uidChanged();
+ } else if (key == ProcessInfoConstants::Gid) {
+ emit gidChanged();
+ } else if (key == ProcessInfoConstants::Priority) {
+ emit priorityChanged();
+ } else if (key == ProcessInfoConstants::OomAdjustment) {
+ emit oomAdjustmentChanged();
+ } else if (key == ProcessInfoConstants::StartOutputPattern) {
+ emit startOutputPatternChanged();
+ }
+}
+
+/*!
+ Add \a newEnvironment to the current environment settings.
+*/
+
+void ProcessInfo::insertEnvironment(const QVariantMap &newEnvironment)
+{
+ QVariantMap env = environment();
+ QMapIterator<QString, QVariant> it(newEnvironment);
+ while (it.hasNext()) {
+ it.next();
+ env.insert(it.key(), it.value());
+ }
+ setEnvironment(env);
+}
+
+/*!
+ \fn void ProcessInfo::identifierChanged()
+ This signal is emitted when the process Identifier has been changed
+*/
+/*!
+ \fn void ProcessInfo::programChanged()
+ This signal is emitted when the process Program has been changed
+*/
+/*!
+ \fn void ProcessInfo::argumentsChanged()
+ This signal is emitted when the process Arguments has been changed
+*/
+/*!
+ \fn void ProcessInfo::environmentChanged()
+ This signal is emitted when the process Environment has been changed
+*/
+/*!
+ \fn void ProcessInfo::workingDirectoryChanged()
+ This signal is emitted when the process WorkingDirectory has been changed
+*/
+/*!
+ \fn void ProcessInfo::uidChanged()
+ This signal is emitted when the process UID has been changed
+*/
+/*!
+ \fn void ProcessInfo::gidChanged()
+ This signal is emitted when the process GID has been changed
+*/
+/*!
+ \fn void ProcessInfo::priorityChanged()
+ This signal is emitted when the process Priority has been changed
+*/
+/*!
+ \fn void ProcessInfo::oomAdjustmentChanged()
+ This signal is emitted when the process OOM adjustment has been changed
+*/
+/*!
+ \fn void ProcessInfo::startOutputPatternChanged()
+ This signal is emitted when the startOutputPattern has been changed.
+*/
+
+#include "moc_processinfo.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/processinfo.h b/src/core/processinfo.h
new file mode 100644
index 0000000..cae23b3
--- /dev/null
+++ b/src/core/processinfo.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PROCESSINFO_H
+#define PROCESSINFO_H
+
+#include <QObject>
+#include <QVariant>
+#include <QStringList>
+#include <QProcessEnvironment>
+
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+namespace ProcessInfoConstants {
+const QLatin1String Identifier = QLatin1String("identifier");
+const QLatin1String Program = QLatin1String("program");
+const QLatin1String Arguments = QLatin1String("arguments");
+const QLatin1String Environment = QLatin1String("environment");
+const QLatin1String WorkingDirectory = QLatin1String("workingDirectory");
+const QLatin1String Uid = QLatin1String("uid");
+const QLatin1String Gid = QLatin1String("gid");
+const QLatin1String Priority = QLatin1String("priority");
+const QLatin1String OomAdjustment = QLatin1String("oomAdjustment");
+const QLatin1String StartOutputPattern = QLatin1String("startOutputPattern");
+}
+
+class ProcessInfo : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString identifier READ identifier WRITE setIdentifier NOTIFY identifierChanged)
+ Q_PROPERTY(QString program READ program WRITE setProgram NOTIFY programChanged)
+ Q_PROPERTY(QStringList arguments READ arguments WRITE setArguments NOTIFY argumentsChanged)
+ Q_PROPERTY(QVariantMap environment READ environment WRITE setEnvironment NOTIFY environmentChanged)
+ Q_PROPERTY(QString workingDirectory READ workingDirectory WRITE setWorkingDirectory NOTIFY workingDirectoryChanged)
+ Q_PROPERTY(qint64 uid READ uid WRITE setUid NOTIFY uidChanged)
+ Q_PROPERTY(qint64 gid READ gid WRITE setGid NOTIFY gidChanged)
+ Q_PROPERTY(int priority READ priority WRITE setPriority NOTIFY priorityChanged)
+ Q_PROPERTY(int oomAdjustment READ oomAdjustment WRITE setOomAdjustment NOTIFY oomAdjustmentChanged)
+ Q_PROPERTY(QByteArray startOutputPattern READ startOutputPattern WRITE setStartOutputPattern NOTIFY startOutputPatternChanged)
+public:
+ explicit ProcessInfo(QObject *parent = 0);
+ ProcessInfo(const ProcessInfo &other);
+ ProcessInfo(const QVariantMap& map);
+ ProcessInfo &operator =(const ProcessInfo &other);
+
+ QString identifier() const;
+ void setIdentifier(const QString &identifier);
+
+ QString program() const;
+ void setProgram(const QString &program);
+
+ QStringList arguments() const;
+ void setArguments(const QStringList &arguments);
+
+ QVariantMap environment() const;
+ void setEnvironment(const QProcessEnvironment &environment);
+ Q_INVOKABLE void setEnvironment(const QVariantMap &environment);
+ Q_INVOKABLE void insertEnvironment(const QVariantMap &environment);
+
+ QString workingDirectory() const;
+ void setWorkingDirectory(const QString &workingDir);
+
+ qint64 uid() const;
+ void setUid(qint64 uid);
+
+ qint64 gid() const;
+ void setGid(qint64 gid);
+
+ int priority() const;
+ void setPriority(int priority);
+
+ int oomAdjustment() const;
+ void setOomAdjustment(int oomAdjustment);
+
+ QByteArray startOutputPattern() const;
+ void setStartOutputPattern(const QByteArray &outputPattern);
+
+ Q_INVOKABLE QStringList keys() const;
+ Q_INVOKABLE bool contains(const QString &key) const;
+ Q_INVOKABLE QVariant value(const QString &key) const;
+ Q_INVOKABLE void setValue(const QString &key, const QVariant &value);
+ Q_INVOKABLE void setData(const QVariantMap &data);
+ Q_INVOKABLE void insert(const QVariantMap &data);
+ QVariantMap toMap() const;
+
+signals:
+ void identifierChanged();
+ void programChanged();
+ void argumentsChanged();
+ void environmentChanged();
+ void workingDirectoryChanged();
+ void uidChanged();
+ void gidChanged();
+ void priorityChanged();
+ void oomAdjustmentChanged();
+ void startOutputPatternChanged();
+
+public slots:
+
+protected:
+ virtual void emitChangeSignal(const QString &key);
+
+private:
+ QVariantMap m_info;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE_PROCESSMANAGER(ProcessInfo)*)
+
+#endif // PROCESSINFO_H
diff --git a/src/core/processmanager-global.h b/src/core/processmanager-global.h
new file mode 100644
index 0000000..34a6144
--- /dev/null
+++ b/src/core/processmanager-global.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.ProcessManager module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef PROCESSMANAGER_GLOBAL_H
+#define PROCESSMANAGER_GLOBAL_H
+
+#include "qglobal.h"
+
+#if defined(QT_ADDON_PROCESSMANAGER_LIB)
+# define Q_ADDON_PROCESSMANAGER_EXPORT Q_DECL_EXPORT
+#else
+# define Q_ADDON_PROCESSMANAGER_EXPORT Q_DECL_IMPORT
+#endif
+
+#if defined(QT_NAMESPACE)
+# define QT_BEGIN_NAMESPACE_PROCESSMANAGER namespace QT_NAMESPACE { namespace QtAddOn { namespace ProcessManager {
+# define QT_END_NAMESPACE_PROCESSMANAGER } } }
+# define QT_USE_NAMESPACE_PROCESSMANAGER using namespace QT_NAMESPACE::QtAddOn::ProcessManager;
+# define QT_PREPEND_NAMESPACE_PROCESSMANAGER(name) ::QT_NAMESPACE::QtAddOn::ProcessManager::name
+#else
+# define QT_BEGIN_NAMESPACE_PROCESSMANAGER namespace QtAddOn { namespace ProcessManager {
+# define QT_END_NAMESPACE_PROCESSMANAGER } }
+# define QT_USE_NAMESPACE_PROCESSMANAGER using namespace QtAddOn::ProcessManager;
+# define QT_PREPEND_NAMESPACE_PROCESSMANAGER(name) ::QtAddOn::ProcessManager::name
+#endif
+
+// a workaround for moc - if there is a header file that doesn't use processmanager
+// namespace, we still force moc to do "using namespace" but the namespace have to
+// be defined, so let's define an empty namespace here
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // PROCESSMANAGER_GLOBAL_H
diff --git a/src/core/processmanager.cpp b/src/core/processmanager.cpp
new file mode 100644
index 0000000..d4af3b1
--- /dev/null
+++ b/src/core/processmanager.cpp
@@ -0,0 +1,292 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "processmanager.h"
+#include "processfrontend.h"
+#include "processbackendfactory.h"
+#include "processbackendmanager.h"
+#include "processbackend.h"
+
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \class ProcessManager
+ \brief The ProcessManager class encapsulates ways of creating and tracking processes.
+*/
+
+/*!
+ \property ProcessManager::memoryRestricted
+ \brief the current setting of memory restriction
+*/
+
+/*!
+ Construct a ProcessManager with an optional \a parent
+*/
+
+ProcessManager::ProcessManager(QObject *parent)
+ : QObject(parent)
+{
+ m_backend = new ProcessBackendManager(this);
+}
+
+/*!
+ Delete the ProcessManager and terminate all processes
+ The ProcessManager is the parent of all factories and process frontends.
+*/
+
+ProcessManager::~ProcessManager()
+{
+}
+
+/*!
+ Create a new ProcessFrontend based on ProcessInfo \a info
+ The parent of the ProcessFrontend is the ProcessManager.
+*/
+
+ProcessFrontend *ProcessManager::create(const ProcessInfo& info)
+{
+ ProcessBackend *backend = m_backend->create(info);
+ if (!backend)
+ return NULL;
+ ProcessFrontend *frontend = createFrontend(backend);
+ frontend->setParent(this);
+ m_processlist.append(frontend);
+ connect(frontend, SIGNAL(aboutToStart()), SLOT(processFrontendAboutToStart()));
+ connect(frontend, SIGNAL(aboutToStop()), SLOT(processFrontendAboutToStop()));
+ connect(frontend, SIGNAL(started()), SLOT(processFrontendStarted()));
+ connect(frontend, SIGNAL(error(QProcess::ProcessError)), SLOT(processFrontendError(QProcess::ProcessError)));
+ connect(frontend, SIGNAL(finished(int, QProcess::ExitStatus)),
+ SLOT(processFrontendFinished(int, QProcess::ExitStatus)));
+ connect(frontend, SIGNAL(stateChanged(QProcess::ProcessState)),
+ SLOT(processFrontendStateChanged(QProcess::ProcessState)));
+ connect(frontend, SIGNAL(destroyed()), SLOT(processFrontendDestroyed()));
+ return frontend;
+}
+
+/*!
+ Create a new ProcessFrontend based on QVariantMap \a info
+ (which should look a lot like ProcessInfo).
+*/
+
+ProcessFrontend *ProcessManager::create(const QVariantMap& info)
+{
+ return create(ProcessInfo(info));
+}
+
+/*!
+ Create a new ProcessFrontend for a \a backend.
+ Override this function if you need to subclass ProcessFrontend to
+ store additional process information or functions.
+*/
+
+ProcessFrontend *ProcessManager::createFrontend(ProcessBackend *backend)
+{
+ return new ProcessFrontend(backend);
+}
+
+/*!
+ Returns a process that matches the name \a name.
+
+ Each process started with the ProcessManager has uniqut application name.
+ If the method returns 0,
+ the name is either invalid or the process has been killed.
+*/
+ProcessFrontend *ProcessManager::processForName(const QString &name) const
+{
+ foreach (ProcessFrontend *frontend, m_processlist)
+ if (frontend->name() == name)
+ return frontend;
+ return NULL;
+}
+
+/*!
+ Returns a process that matches the process id \a pid. Returns NULL if no such process was found.
+ Returns NULL if \a pid is 0.
+ If more than one process matches the same ID, this method will return the first one find.
+*/
+
+ProcessFrontend *ProcessManager::processForPID(qint64 pid) const
+{
+ if (!pid)
+ return NULL;
+
+ foreach (ProcessFrontend *frontend, m_processlist)
+ if (frontend->pid() == pid)
+ return frontend;
+ return NULL;
+}
+
+/*!
+ Returns the number of processes.
+*/
+
+int ProcessManager::size() const
+{
+ return m_processlist.size();
+}
+
+/*!
+ Add a ProcessBackendFactory \a factory to the end of the Factory list.
+*/
+
+void ProcessManager::addBackendFactory(ProcessBackendFactory *factory)
+{
+ m_backend->addFactory(factory);
+}
+
+/*!
+ Return a list of current process names
+*/
+
+QStringList ProcessManager::names() const
+{
+ QStringList result;
+ foreach (ProcessFrontend *frontend, m_processlist)
+ result << frontend->name();
+ return result;
+}
+
+/*!
+ Return a list of all internal processes being used by factories
+*/
+
+QList<Q_PID> ProcessManager::internalProcesses()
+{
+ return m_backend->internalProcesses();
+}
+
+/*!
+ Set memory restrictions. If \a memoryRestricted is true
+ all factories are requested to minimize memory use.
+*/
+
+void ProcessManager::setMemoryRestricted(bool memoryRestricted)
+{
+ m_backend->setMemoryRestricted(memoryRestricted);
+ emit memoryRestrictedChanged();
+}
+
+/*!
+ Return current memory restriction setting
+*/
+
+bool ProcessManager::memoryRestricted() const
+{
+ return m_backend->memoryRestricted();
+}
+
+/*!
+ Raise the processAboutToStart() signal.
+*/
+
+void ProcessManager::processFrontendAboutToStart()
+{
+}
+
+/*!
+ Raise the processAboutToStop() signal.
+*/
+
+void ProcessManager::processFrontendAboutToStop()
+{
+}
+
+/*!
+ Raise the processStarted() signal.
+*/
+
+void ProcessManager::processFrontendStarted()
+{
+}
+
+/*!
+ Raise the processError() signal.
+ Pass through the \a error value.
+*/
+
+void ProcessManager::processFrontendError(QProcess::ProcessError error)
+{
+ Q_UNUSED(error);
+}
+
+/*!
+ Raise the processFinished() signal. Pass through the
+ \a exitCode and \a exitStatus values.
+*/
+
+void ProcessManager::processFrontendFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ Q_UNUSED(exitCode);
+ Q_UNUSED(exitStatus);
+}
+
+/*!
+ Raise the processStateChanged() signal. Pass through the
+ \a state value.
+*/
+
+void ProcessManager::processFrontendStateChanged(QProcess::ProcessState state)
+{
+ Q_UNUSED(state);
+}
+
+/*!
+ Track a process being destroyed. Remote this process from our
+ list of valid process. Also emit the processDestroyed() signal.
+ If you override this function in a subclass, be sure to call
+ the parent function.
+*/
+
+void ProcessManager::processFrontendDestroyed()
+{
+ ProcessFrontend *frontend = static_cast<ProcessFrontend *>(sender());
+ if (frontend)
+ m_processlist.removeAll(frontend);
+}
+
+/*!
+ \fn void ProcessManager::memoryRestrictedChanged()
+ This signal is emitted when the memory restriction is changed
+*/
+
+#include "moc_processmanager.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/processmanager.h b/src/core/processmanager.h
new file mode 100644
index 0000000..ff3020a
--- /dev/null
+++ b/src/core/processmanager.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PROCESSMANAGER_H
+#define PROCESSMANAGER_H
+
+#include <QObject>
+#include <QHash>
+#include <QProcessEnvironment>
+
+#include "processmanager-global.h"
+#include "process.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class ProcessFrontend;
+class ProcessInfo;
+class ProcessBackendFactory;
+class ProcessBackendManager;
+class ProcessBackend;
+
+class ProcessManager : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool memoryRestricted READ memoryRestricted
+ WRITE setMemoryRestricted NOTIFY memoryRestrictedChanged)
+public:
+ explicit ProcessManager(QObject *parent = 0);
+ virtual ~ProcessManager();
+
+ Q_INVOKABLE ProcessFrontend *create(const ProcessInfo& info);
+ Q_INVOKABLE ProcessFrontend *create(const QVariantMap& info);
+
+ Q_INVOKABLE QStringList names() const;
+
+ Q_INVOKABLE ProcessFrontend *processForName(const QString &name) const;
+ Q_INVOKABLE ProcessFrontend *processForPID(qint64 PID) const;
+ Q_INVOKABLE int size() const;
+
+ Q_INVOKABLE void addBackendFactory(ProcessBackendFactory *factory);
+ Q_INVOKABLE QList<Q_PID> internalProcesses();
+
+ void setMemoryRestricted(bool);
+ bool memoryRestricted() const;
+
+signals:
+ void memoryRestrictedChanged();
+
+protected slots:
+ virtual void processFrontendAboutToStart();
+ virtual void processFrontendAboutToStop();
+ virtual void processFrontendStarted();
+ virtual void processFrontendError(QProcess::ProcessError);
+ virtual void processFrontendFinished(int, QProcess::ExitStatus);
+ virtual void processFrontendStateChanged(QProcess::ProcessState);
+ virtual void processFrontendDestroyed();
+
+protected:
+ virtual ProcessFrontend *createFrontend(ProcessBackend *backend);
+
+protected:
+ QList<ProcessFrontend*> m_processlist;
+ ProcessBackendManager *m_backend;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // PROCESSMANAGER_H
diff --git a/src/core/procutils.cpp b/src/core/procutils.cpp
new file mode 100644
index 0000000..f6965b3
--- /dev/null
+++ b/src/core/procutils.cpp
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "procutils.h"
+
+#include <cstdio>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <QFile>
+#include <QFileInfo>
+#include <QLocalSocket>
+
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+ProcUtils::ProcUtils()
+{
+}
+
+QString ProcUtils::execNameForPid(qint64 pid)
+{
+ enum { BUFFERSIZE = 1024 };
+ char buf[BUFFERSIZE];
+ QString fn = QLatin1String("/proc/") + QString::number(pid).toLatin1() + QLatin1String("/exe");
+ ssize_t len = readlink(fn.toLatin1(), buf, sizeof(buf) - 1);
+
+ if (len != -1) {
+ buf[len] = '\0';
+ } else {
+ return QString();
+ }
+
+ return QString(buf);
+}
+
+qint64 ProcUtils::ppidForPid(pid_t pid)
+{
+ QFile statFile(QLatin1String("/proc/") + QString::number(pid) + "/stat");
+ statFile.open(QIODevice::ReadOnly);
+
+ QByteArray contents = statFile.readAll();
+ statFile.close();
+ // 954 (ofono-jdb-daemo) S 1
+ int readPid = 0;
+ int ppid = 0;
+ char strDummy[64];
+ char state;
+ sscanf(contents.constData(), "%d %s %c %d %s", &readPid, strDummy, &state, &ppid, strDummy);
+ return ppid;
+}
+
+qint64 ProcUtils::pidForFilename(const QString &filename)
+{
+ QFile file(filename);
+ if (!file.exists())
+ return 0;
+ QFileInfo fileInfo(file);
+
+ DIR *d = opendir(QLatin1String("/proc").latin1());
+ if (!d) {
+ qWarning() << "failed to open proc";
+ return 0;
+ }
+
+ while (dirent *dirent = readdir(d)) {
+ QString dirname = QString::fromLatin1(dirent->d_name);
+ bool ok = false;
+ qint64 pid = dirname.toLongLong(&ok, 10);
+ if (ok) {
+ const QString execFilename = execNameForPid(pid);
+ if (execFilename == fileInfo.fileName())
+ return pid;
+ }
+ }
+ closedir(d);
+ return 0;
+}
+
+qint64 ProcUtils::pidForLocalSocket(const QLocalSocket *socket)
+{
+ if (socket) {
+ struct ucred cr;
+ socklen_t len = sizeof(struct ucred);
+ int r = ::getsockopt(socket->socketDescriptor(), SOL_SOCKET, SO_PEERCRED, &cr, &len);
+ if (r == 0) {
+ return (qint64)cr.pid;
+ }
+ }
+ return 0;
+}
+
+QByteArray ProcUtils::cmdlineForPid(qint64 pid)
+{
+ QByteArray cmdline;
+ if (pid) {
+ QFile file(QLatin1String("/proc/") + QString::number(pid) + QLatin1String("/cmdline"));
+ file.open(QIODevice::ReadOnly);
+ cmdline = file.readAll();
+ }
+ return cmdline;
+}
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/procutils.h b/src/core/procutils.h
new file mode 100644
index 0000000..4fe5d6f
--- /dev/null
+++ b/src/core/procutils.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PROCUTILS_H
+#define PROCUTILS_H
+
+#include <QString>
+
+QT_FORWARD_DECLARE_CLASS(QLocalSocket)
+
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class ProcUtils
+{
+ ProcUtils();
+ Q_DISABLE_COPY(ProcUtils)
+public:
+ static QString execNameForPid(qint64 pid);
+ static qint64 ppidForPid(pid_t pid);
+ static qint64 pidForFilename(const QString &filename);
+ static qint64 pidForLocalSocket(const QLocalSocket *socket);
+ static QByteArray cmdlineForPid(qint64 pid);
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // PROCUTILS_H
diff --git a/src/core/remoteprocessbackend.cpp b/src/core/remoteprocessbackend.cpp
new file mode 100644
index 0000000..ce6db11
--- /dev/null
+++ b/src/core/remoteprocessbackend.cpp
@@ -0,0 +1,296 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "remoteprocessbackend.h"
+#include <sys/resource.h>
+#include <errno.h>
+#include <signal.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+static const QLatin1String kCommand("command");
+static const QLatin1String kId("id");
+static const QLatin1String kSignal("signal");
+
+/*!
+ \class RemoteProcessBackend
+
+ \brief The RemoteProcessBackend class handles a process started by another process.
+
+ The RemoteProcessBackend is used to control a process that was started by
+ a separate "controller" process. The RemoteProcessBackendFactory object handles
+ the pipe or socket communication with the remote controller. Communication is
+ carried over serialized JSON messages.
+*/
+
+/*!
+ Construct a RemoteProcessBackend with ProcessInfo \a info, \a factory,
+ \a id, and optional \a parent.
+*/
+
+RemoteProcessBackend::RemoteProcessBackend(const ProcessInfo& info,
+ RemoteProcessBackendFactory *factory,
+ int id,
+ QObject *parent)
+ : ProcessBackend(info, parent)
+ , m_factory(factory)
+ , m_state(QProcess::NotRunning)
+ , m_pid(-1)
+ , m_id(id)
+{
+ Q_ASSERT(factory);
+}
+
+/*!
+ Destroy this process object.
+*/
+
+RemoteProcessBackend::~RemoteProcessBackend()
+{
+ if (m_factory)
+ m_factory->backendDestroyed(m_id);
+}
+
+/*!
+ Returns the PID of this process if it is starting or running.
+ Return the default value if it is not.
+*/
+
+Q_PID RemoteProcessBackend::pid() const
+{
+ if (m_pid != -1)
+ return m_pid;
+ return ProcessBackend::pid();
+}
+
+/*!
+ Return the actual process priority (if running)
+*/
+
+qint32 RemoteProcessBackend::actualPriority() const
+{
+ if (m_pid != -1) {
+ errno = 0; // getpriority can return -1, so we clear errno
+ int result = getpriority(PRIO_PROCESS, m_pid);
+ if (!errno)
+ return result;
+ }
+ return ProcessBackend::actualPriority();
+}
+
+/*!
+ Set the process priority to \a priority
+*/
+
+void RemoteProcessBackend::setDesiredPriority(qint32 priority)
+{
+ ProcessBackend::setDesiredPriority(priority);
+ if (m_factory && m_pid != -1) {
+ QJsonObject object;
+ object.insert(kCommand, QLatin1String("set"));
+ object.insert(kId, m_id);
+ object.insert("key", QLatin1String("priority"));
+ object.insert("value", priority);
+ m_factory->send(object);
+ }
+}
+
+#if defined(Q_OS_LINUX)
+
+/*!
+ Return the process oomAdjustment
+*/
+
+qint32 RemoteProcessBackend::actualOomAdjustment() const
+{
+ if (m_pid != -1) {
+ // ### TODO: Read correctly from /proc/<pid>/oom_score_adj
+ }
+ return ProcessBackend::actualOomAdjustment();
+}
+
+/*!
+ Set the process /proc/<pid>/oom_score_adj to \a oomAdjustment
+*/
+
+void RemoteProcessBackend::setDesiredOomAdjustment(qint32 oomAdjustment)
+{
+ ProcessBackend::setDesiredOomAdjustment(oomAdjustment);
+ if (m_factory && m_pid != -1) {
+ QJsonObject object;
+ object.insert(kCommand, QLatin1String("set"));
+ object.insert(kId, m_id);
+ object.insert("key", QLatin1String("oomAdjustment"));
+ object.insert("value", oomAdjustment);
+ m_factory->send(object);
+ }
+}
+
+#endif // defined(Q_OS_LINUX)
+
+
+/*!
+ Returns the state of the process.
+*/
+QProcess::ProcessState RemoteProcessBackend::state() const
+{
+ return m_state;
+}
+
+/*!
+ Start the process running
+*/
+
+void RemoteProcessBackend::start()
+{
+ if (m_factory) {
+ QJsonObject object;
+ object.insert(kCommand, QLatin1String("start"));
+ object.insert(kId, m_id);
+ object.insert(QLatin1String("info"), QJsonValue::fromVariant(m_info.toMap()));
+ m_factory->send(object);
+ }
+}
+
+/*!
+ Attempts to stop a process by giving it a \a timeout time to die, measured in milliseconds.
+ If the process does not die in the given time limit, it is killed.
+ \sa finished()
+*/
+
+void RemoteProcessBackend::stop(int timeout)
+{
+ if (m_factory) {
+ QJsonObject object;
+ object.insert(kCommand, QLatin1String("stop"));
+ object.insert(kId, m_id);
+ object.insert(QLatin1String("timeout"), timeout);
+ }
+}
+
+/*!
+ Writes at most \a maxSize bytes of data from \a data to the device.
+ Returns the number of bytes that were actually written, or -1 if an error occurred.
+
+ This function isn't quite correct, because we have a JSON encoding problem.
+ For the moment we'll pretend that any data sent is actually something in
+ standard ASCII.
+*/
+qint64 RemoteProcessBackend::write(const char *data, qint64 maxSize)
+{
+ if (m_factory) {
+ QJsonObject object;
+ object.insert(kCommand, QLatin1String("write"));
+ object.insert(kId, m_id);
+ object.insert(QLatin1String("data"), QString::fromLocal8Bit(data, maxSize));
+ if (m_factory->send(object))
+ return maxSize;
+ }
+ return -1;
+}
+
+
+/*!
+ Message received from the remote.
+ The \a message is encoded in JSON format.
+*/
+
+void RemoteProcessBackend::receive(const QJsonObject& message)
+{
+ QString event = message.value("event").toString();
+ qDebug() << Q_FUNC_INFO << message;
+ if (event == "started") {
+ m_pid = message.value("pid").toDouble();
+ emit started();
+ }
+ else if (event == "error") {
+ emit error(static_cast<QProcess::ProcessError>(message.value("error").toDouble()));
+ }
+ else if (event == "finished") {
+ emit finished(message.value("exitCode").toDouble(),
+ static_cast<QProcess::ExitStatus>(message.value("exitStatus").toDouble()));
+ }
+ else if (event == "stateChanged") {
+ m_state = static_cast<QProcess::ProcessState>(message.value("stateChanged").toDouble());
+ emit stateChanged(m_state);
+ }
+ else if (event == "output") {
+ if (message.contains("stdout")) {
+ handleStandardOutput(message.value("stdout").toString().toLocal8Bit());
+ }
+ if (message.contains("stderr")) {
+ handleStandardError(message.value("stderr").toString().toLocal8Bit());
+ }
+ }
+ else
+ qDebug() << Q_FUNC_INFO << "unrecognized message";
+}
+
+/*!
+ \internal
+*/
+
+void RemoteProcessBackend::killTimeout()
+{
+ if (m_factory) {
+ QJsonObject object;
+ object.insert(kCommand, kSignal);
+ object.insert(kId, m_id);
+ object.insert(kSignal, SIGKILL);
+ m_factory->send(object);
+ }
+}
+
+/*!
+ \internal
+*/
+
+void RemoteProcessBackend::factoryDestroyed()
+{
+ m_factory = NULL;
+ if (m_state != QProcess::NotRunning) {
+ m_state = QProcess::NotRunning;
+ emit error(QProcess::UnknownError);
+ }
+}
+
+#include "moc_remoteprocessbackend.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/remoteprocessbackend.h b/src/core/remoteprocessbackend.h
new file mode 100644
index 0000000..371047a
--- /dev/null
+++ b/src/core/remoteprocessbackend.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef REMOTE_PROCESS_BACKEND_H
+#define REMOTE_PROCESS_BACKEND_H
+
+#include <QJsonObject>
+
+#include "processmanager-global.h"
+#include "processbackend.h"
+#include "remoteprocessbackendfactory.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class RemoteProcessBackend : public ProcessBackend
+{
+ Q_OBJECT
+
+public:
+ RemoteProcessBackend(const ProcessInfo& info, RemoteProcessBackendFactory *factory,
+ int id, QObject *parent);
+ virtual ~RemoteProcessBackend();
+
+ virtual Q_PID pid() const;
+ virtual qint32 actualPriority() const;
+ virtual void setDesiredPriority(qint32);
+#if defined(Q_OS_LINUX)
+ virtual qint32 actualOomAdjustment() const;
+ virtual void setDesiredOomAdjustment(qint32);
+#endif
+
+ virtual QProcess::ProcessState state() const;
+ virtual void start();
+ virtual void stop(int timeout = 500);
+ virtual qint64 write(const char *data, qint64 maxSize);
+
+private:
+ friend class RemoteProcessBackendFactory;
+ void killTimeout();
+ void receive(const QJsonObject&);
+ void factoryDestroyed();
+
+private:
+ RemoteProcessBackendFactory *m_factory;
+ QProcess::ProcessState m_state;
+ Q_PID m_pid;
+ qint32 m_id;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // REMOTE_PROCESS_BACKEND_H
diff --git a/src/core/remoteprocessbackendfactory.cpp b/src/core/remoteprocessbackendfactory.cpp
new file mode 100644
index 0000000..149effb
--- /dev/null
+++ b/src/core/remoteprocessbackendfactory.cpp
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "remoteprocessbackendfactory.h"
+#include "remoteprocessbackend.h"
+
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+const int kRemoteTimerInterval = 1000;
+
+/*!
+ \class RemoteProcessBackendFactory
+ \brief The RemoteProcessBackendFactory class creates RemoteProcessBackend objects
+
+ The RemoteProcessBackendFactory communicates with a remote process to control
+ other, child processes.
+ The factory communicates with the remote process by sending and receiving
+ JSON-formated messages. The remote process should respond to the following
+ commands:
+
+ \table
+ \header
+ \o Command
+ \o Action
+ \row
+ \o \c{{ "command": "start", "id": NUM, "info": PROCESSINFO }}
+ \o Start a new process running. The \bold{token} attribute will
+ be used to refer to this process in the future.
+ \row
+ \o \c{{ "command": "stop", "id": NUM, "timeout": NUM }}
+ \o Stop the remote process with an optional timeout.
+ The remote process should be sent a SIGTERM, followed by
+ a SIGKILL after 'timeout' milliseconds
+ \row
+ \o \c{{ "command": "set", "id": NUM, "key": STRING, "value": NUM }}
+ \o Set a process key/value pair. Currently the \bold{key} can be
+ either "priority" or "oomAdjustment".
+ \row
+ \o \c{{ "command": "write", "id": NUM, "data": STRING }}
+ \o Write a data string to the remote process. We assume that the
+ data string is a valid local 8 bit string.
+ \endtable
+
+ The following are events that are sent by the remote process
+ to the RemoteProcessBackendFactory:
+
+ \table
+ \header
+ \o Event
+ \o Description
+ \row
+ \o \c{{ "event": "started", "id": NUM, "pid": NUM }}
+ \o This process has started. This maps to the QProcess::started()
+ signal, but also includes the PID of the new process. This should
+ be the first event returned after a \bold{start} command
+ \row
+ \o \c{{ "event": "finished", "id": NUM, "exitCode": NUM, "exitStatus": NUM }}
+ \o The process has exited. This is the last event returned for a given
+ process number.
+ \row
+ \o \c{{ "event": "error", "id": NUM, "error": NUM }}
+ \o The process has an error that maps to QProcess::ProcessError
+ \row
+ \o \c{{ "event": "stateChanged", "id": NUM, "state": NUM }}
+ \o The process has an event that maps to a QProcess::ProcessState change.
+ \row
+ \o \c{{ "event": "output", "id": NUM, "stdout": STRING, "stderr": STRING }}
+ \o The process has written data to stdout and/or stderr.
+ \endtable
+*/
+
+/*!
+ Construct a RemoteProcessBackendFactory with optional \a parent.
+*/
+
+RemoteProcessBackendFactory::RemoteProcessBackendFactory(QObject *parent)
+ : ProcessBackendFactory(parent)
+ , m_idCount(100)
+{
+}
+
+/*!
+ Destroy this and child objects.
+*/
+
+RemoteProcessBackendFactory::~RemoteProcessBackendFactory()
+{
+ foreach (RemoteProcessBackend *backend, m_backendMap)
+ backend->factoryDestroyed();
+}
+
+/*!
+ Construct a RemoteProcessBackend from a ProcessInfo \a info record with \a parent.
+*/
+
+ProcessBackend * RemoteProcessBackendFactory::create(const ProcessInfo& info, QObject *parent)
+{
+ int id = m_idCount++;
+ RemoteProcessBackend *backend = new RemoteProcessBackend(info, this, id, parent);
+ m_backendMap.insert(id, backend);
+ return backend;
+}
+
+/*!
+ Receive a remote \a message and dispatch it to the correct recipient.
+ Call this function from your subclass to properly dispatch messages.
+ */
+
+void RemoteProcessBackendFactory::receive(const QJsonObject& message)
+{
+ qDebug() << Q_FUNC_INFO << message;
+ int id = message.value(QLatin1String("id")).toDouble();
+ if (m_backendMap.contains(id))
+ m_backendMap.value(id)->receive(message);
+}
+
+/*!
+ \fn bool RemoteProcessBackendFactory::send(const QJsonObject& message)
+
+ Send a \a message to the remote process. This method must be implemented in a
+ child process. Return true if the message can be sent.
+ */
+
+/*!
+ \internal
+ */
+
+void RemoteProcessBackendFactory::backendDestroyed(int id)
+{
+ if (m_backendMap.remove(id) != 1)
+ qCritical("Missing remote process backend");
+}
+
+#include "moc_remoteprocessbackendfactory.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/remoteprocessbackendfactory.h b/src/core/remoteprocessbackendfactory.h
new file mode 100644
index 0000000..82c4fb0
--- /dev/null
+++ b/src/core/remoteprocessbackendfactory.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef REMOTE_PROCESS_BACKEND_FACTORY_H
+#define REMOTE_PROCESS_BACKEND_FACTORY_H
+
+#include "processbackendfactory.h"
+#include <QJsonObject>
+#include <QMap>
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class RemoteProcessBackend;
+
+class RemoteProcessBackendFactory : public ProcessBackendFactory
+{
+ Q_OBJECT
+public:
+ RemoteProcessBackendFactory(QObject *parent = 0);
+ virtual ~RemoteProcessBackendFactory();
+
+ virtual ProcessBackend *create(const ProcessInfo& info, QObject *parent);
+
+protected:
+ virtual bool send(const QJsonObject&) = 0;
+ void receive(const QJsonObject&);
+
+private:
+ void backendDestroyed(int);
+ friend class RemoteProcessBackend;
+
+protected:
+ int m_idCount;
+ QMap<int, RemoteProcessBackend*> m_backendMap;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // REMOTE_PROCESS_BACKEND_FACTORY_H
diff --git a/src/core/socketprocessbackendfactory.cpp b/src/core/socketprocessbackendfactory.cpp
new file mode 100644
index 0000000..a87ffdd
--- /dev/null
+++ b/src/core/socketprocessbackendfactory.cpp
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDebug>
+#include <QLocalSocket>
+#include <QJsonDocument>
+#include <QtEndian>
+
+#include "socketprocessbackendfactory.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \class SocketProcessBackendFactory
+ \brief The SocketProcessBackendFactory class creates RemoteProcessBackend objects
+
+ The SocketProcessBackendFactory connects over a Unix local socket to
+ an already-running "launcher" server.
+*/
+
+/*!
+ Construct a SocketProcessBackendFactory with optional \a parent.
+ Connect to an application launcher listening on Unix local socket \a socketname
+*/
+
+SocketProcessBackendFactory::SocketProcessBackendFactory(const QString& socketname,
+ QObject *parent)
+ : RemoteProcessBackendFactory(parent)
+{
+ m_socket = new QLocalSocket(this);
+ connect(m_socket, SIGNAL(disconnected()), SLOT(disconnected()));
+ connect(m_socket, SIGNAL(readyRead()), SLOT(readyRead()));
+ m_socket->connectToServer(socketname);
+}
+
+/*!
+ Destroy this and child objects.
+*/
+
+SocketProcessBackendFactory::~SocketProcessBackendFactory()
+{
+}
+
+/*!
+ The SocketProcessBackendFactory will match the ProcessInfo \a info
+ if there is a \c info.launcher attribute set to "true" (the string) and
+ if the \c info.program attribute matches the program original specified
+ when creating the factory.
+*/
+
+bool SocketProcessBackendFactory::canCreate(const ProcessInfo& info) const
+{
+ Q_UNUSED(info);
+ return m_socket->isValid();
+}
+
+/*!
+ Read data from the socket
+*/
+
+void SocketProcessBackendFactory::readyRead()
+{
+ m_buffer.append(m_socket->readAll());
+ while (m_buffer.size() >= 12) { // QJsonDocuments are at least this large
+ qint32 message_size = qFromLittleEndian(((qint32 *)m_buffer.data())[2]) + 8;
+ if (m_buffer.size() < message_size)
+ break;
+ QByteArray msg = m_buffer.left(message_size);
+ m_buffer = m_buffer.mid(message_size);
+ receive(QJsonDocument::fromBinaryData(msg).object());
+ }
+}
+
+/*!
+ \internal
+ */
+
+void SocketProcessBackendFactory::disconnected()
+{
+ qWarning("Launcher process socket disconnected");
+}
+
+/*!
+ \internal
+ */
+
+bool SocketProcessBackendFactory::send(const QJsonObject& message)
+{
+ return (m_socket->isValid() &&
+ m_socket->write(QJsonDocument(message).toBinaryData()) != -1);
+}
+
+#include "moc_socketprocessbackendfactory.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/socketprocessbackendfactory.h b/src/core/socketprocessbackendfactory.h
new file mode 100644
index 0000000..ac7ad19
--- /dev/null
+++ b/src/core/socketprocessbackendfactory.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SOCKET_PROCESS_BACKEND_FACTORY_H
+#define SOCKET_PROCESS_BACKEND_FACTORY_H
+
+#include "remoteprocessbackendfactory.h"
+
+class QLocalSocket;
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class SocketProcessBackendFactory : public RemoteProcessBackendFactory
+{
+ Q_OBJECT
+public:
+ SocketProcessBackendFactory(const QString& socketname, QObject *parent = 0);
+ virtual ~SocketProcessBackendFactory();
+
+ virtual bool canCreate(const ProcessInfo& info) const;
+
+protected:
+ virtual bool send(const QJsonObject&);
+
+private slots:
+ void readyRead();
+ void disconnected();
+
+private:
+ QLocalSocket *m_socket;
+ QByteArray m_buffer;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // SOCKET_PROCESS_BACKEND_FACTORY_H
diff --git a/src/core/standardprocessbackend.cpp b/src/core/standardprocessbackend.cpp
new file mode 100644
index 0000000..94d7c90
--- /dev/null
+++ b/src/core/standardprocessbackend.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "standardprocessbackend.h"
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \class StandardProcessBackend
+ \brief The StandardProcessBackend class wraps a single QProcess object
+*/
+
+/*!
+ Construct a StandardProcessBackend with ProcessInfo \a info and optional \a parent
+*/
+
+StandardProcessBackend::StandardProcessBackend(const ProcessInfo& info, QObject *parent)
+ : UnixProcessBackend(info, parent)
+{
+}
+
+/*!
+ \brief Starts the process.
+
+ After the process is started, the started() signal is emitted or
+ an error(QProcess::FailedToStart) will be emitted.
+*/
+
+void StandardProcessBackend::start()
+{
+ if (createProcess())
+ startProcess();
+}
+
+/*!
+ Calls the parent class function and emits the started() signal.
+*/
+
+void StandardProcessBackend::handleProcessStarted()
+{
+ UnixProcessBackend::handleProcessStarted();
+ emit started();
+}
+
+/*!
+ Calls the parent class function and emits the error() signal with \a err.
+*/
+
+void StandardProcessBackend::handleProcessError(QProcess::ProcessError err)
+{
+ UnixProcessBackend::handleProcessError(err);
+ emit error(err);
+}
+
+/*!
+ Calls the parent class function and emits the finished() signal with
+ the \a exitCode and \a exitStatus.
+*/
+
+void StandardProcessBackend::handleProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ UnixProcessBackend::handleProcessFinished(exitCode, exitStatus);
+ emit finished(exitCode, exitStatus);
+}
+
+/*!
+ Calls the parent class function and emits the stateChanged() signal with \a state.
+*/
+
+void StandardProcessBackend::handleProcessStateChanged(QProcess::ProcessState state)
+{
+ UnixProcessBackend::handleProcessStateChanged(state);
+ emit stateChanged(state);
+}
+
+#include "moc_standardprocessbackend.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/standardprocessbackend.h b/src/core/standardprocessbackend.h
new file mode 100644
index 0000000..452d192
--- /dev/null
+++ b/src/core/standardprocessbackend.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef STANDARD_PROCESS_BACKEND_H
+#define STANDARD_PROCESS_BACKEND_H
+
+#include "unixprocessbackend.h"
+
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class StandardProcessBackend : public UnixProcessBackend
+{
+ Q_OBJECT
+
+public:
+ StandardProcessBackend(const ProcessInfo& info, QObject *parent);
+ virtual void start();
+
+protected:
+ virtual void handleProcessStarted();
+ virtual void handleProcessError(QProcess::ProcessError error);
+ virtual void handleProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
+ virtual void handleProcessStateChanged(QProcess::ProcessState state);
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // STANDARD_PROCESS_BACKEND_H
diff --git a/src/core/standardprocessbackendfactory.cpp b/src/core/standardprocessbackendfactory.cpp
new file mode 100644
index 0000000..5e6ad0e
--- /dev/null
+++ b/src/core/standardprocessbackendfactory.cpp
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "standardprocessbackendfactory.h"
+#include "standardprocessbackend.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \class StandardProcessBackendFactory
+ \brief The StandardProcessBackendFactory class creates StandardProcessBackend objects
+*/
+
+/*!
+ Construct a StandardProcessBackendFactory with optional \a parent
+*/
+
+StandardProcessBackendFactory::StandardProcessBackendFactory(QObject *parent)
+ : ProcessBackendFactory(parent)
+{
+}
+
+/*!
+ StandardProcessBackendFactory can create any type of process
+ using the ProcessInfo \a info record.
+*/
+
+bool StandardProcessBackendFactory::canCreate(const ProcessInfo& info) const
+{
+ Q_UNUSED(info);
+ return true;
+}
+
+/*!
+ Construct a StandardProcessBackend from a ProcessInfo \a info record
+ with \a parent.
+*/
+
+ProcessBackend * StandardProcessBackendFactory::create(const ProcessInfo& info, QObject *parent)
+{
+ return new StandardProcessBackend(info, parent);
+}
+
+#include "moc_standardprocessbackendfactory.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/standardprocessbackendfactory.h b/src/core/standardprocessbackendfactory.h
new file mode 100644
index 0000000..98a7526
--- /dev/null
+++ b/src/core/standardprocessbackendfactory.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef STANDARD_PROCESS_BACKEND_FACTORY_H
+#define STANDARD_PROCESS_BACKEND_FACTORY_H
+
+#include "processbackendfactory.h"
+
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class StandardProcessBackendFactory : public ProcessBackendFactory
+{
+ Q_OBJECT
+
+public:
+ StandardProcessBackendFactory(QObject *parent=0);
+ virtual bool canCreate(const ProcessInfo& info) const;
+ virtual ProcessBackend *create(const ProcessInfo& info, QObject *parent);
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // STANDARD_PROCESS_BACKEND_FACTORY_H
diff --git a/src/core/unixprocessbackend.cpp b/src/core/unixprocessbackend.cpp
new file mode 100644
index 0000000..c9bf3d6
--- /dev/null
+++ b/src/core/unixprocessbackend.cpp
@@ -0,0 +1,332 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+
+#include "unixprocessbackend.h"
+#include "unixsandboxprocess.h"
+#include <sys/resource.h>
+#include <errno.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \class UnixProcessBackend
+ \brief The UnixProcessBackend class wraps a QProcess object
+*/
+
+/*!
+ Construct a UnixProcessBackend with ProcessInfo \a info and optional \a parent
+*/
+
+UnixProcessBackend::UnixProcessBackend(const ProcessInfo& info, QObject *parent)
+ : ProcessBackend(info, parent)
+ , m_process(0)
+{
+}
+
+/*!
+ Destroy this process object.
+ Any created QProcess is a child of this object, so it will be automatically terminated.
+*/
+
+UnixProcessBackend::~UnixProcessBackend()
+{
+}
+
+/*!
+ Returns the PID of this process. If the process has not started up yet properly, its PID will be 0.
+*/
+Q_PID UnixProcessBackend::pid() const
+{
+ if (m_process)
+ return m_process->pid();
+ return 0;
+}
+
+/*!
+ Return the actual process priority (if running)
+*/
+
+qint32 UnixProcessBackend::actualPriority() const
+{
+ if (m_process) {
+ errno = 0; // getpriority can return -1, so we clear errno
+ int result = getpriority(PRIO_PROCESS, m_process->pid());
+ if (!errno)
+ return result;
+ }
+ return ProcessBackend::actualPriority();
+}
+
+/*!
+ Set the process priority to \a priority
+*/
+
+void UnixProcessBackend::setDesiredPriority(qint32 priority)
+{
+ ProcessBackend::setDesiredPriority(priority);
+ if (m_process) {
+ if (setpriority(PRIO_PROCESS, m_process->pid(), priority))
+ qWarning() << "Failed to set process priority from " << actualPriority() <<
+ "to" << priority << " : errno = " << errno;
+ }
+}
+
+#if defined(Q_OS_LINUX)
+
+/*!
+ Return the process oomAdjustment
+*/
+
+qint32 UnixProcessBackend::actualOomAdjustment() const
+{
+ if (m_process) {
+ // ### TODO: Read correctly from /proc/<pid>/oom_score_adj
+ }
+ return ProcessBackend::actualOomAdjustment();
+}
+
+/*!
+ Set the process /proc/<pid>/oom_score_adj to \a oomAdjustment
+*/
+
+void UnixProcessBackend::setDesiredOomAdjustment(qint32 oomAdjustment)
+{
+ ProcessBackend::setDesiredOomAdjustment(oomAdjustment);
+ if (m_process) {
+ // ### Write to /proc/<pid>/oom_score_adj
+ }
+}
+
+#endif // defined(Q_OS_LINUX)
+
+/*!
+ Returns the state of the process.
+ The base class always returns NotRunning.
+*/
+QProcess::ProcessState UnixProcessBackend::state() const
+{
+ return m_process ? m_process->state() : QProcess::NotRunning;
+}
+
+/*!
+ Internal function to create the QProcess.
+ Returns true if a process was created.
+*/
+bool UnixProcessBackend::createProcess()
+{
+ if (m_process) {
+ qWarning() << "Can't restart process!";
+ return false;
+ }
+
+ if (m_info.contains(ProcessInfoConstants::Uid) || m_info.contains(ProcessInfoConstants::Gid))
+ m_process = new UnixSandboxProcess(m_info.uid(), m_info.gid(), this);
+ else
+ m_process = new QProcess(this);
+
+ m_process->setReadChannel(QProcess::StandardOutput);
+ connect(m_process, SIGNAL(readyReadStandardOutput()),
+ this, SLOT(readyReadStandardOutput()));
+ connect(m_process, SIGNAL(readyReadStandardError()),
+ this, SLOT(readyReadStandardError()));
+ connect(&m_killTimer, SIGNAL(timeout()), this, SLOT(killTimeout()));
+
+ connect(m_process, SIGNAL(started()), this, SLOT(unixProcessStarted()));
+ connect(m_process,SIGNAL(error(QProcess::ProcessError)),
+ this,SLOT(unixProcessError(QProcess::ProcessError)));
+ connect(m_process,SIGNAL(finished(int, QProcess::ExitStatus)),
+ this,SLOT(unixProcessFinished(int, QProcess::ExitStatus)));
+ connect(m_process, SIGNAL(stateChanged(QProcess::ProcessState)),
+ this,SLOT(unixProcessStateChanged(QProcess::ProcessState)));
+ return true;
+}
+
+/*!
+ Internal function to start the QProcess running.
+*/
+
+void UnixProcessBackend::startProcess()
+{
+ QProcessEnvironment env;
+ QMapIterator<QString, QVariant> it(m_info.environment());
+ while (it.hasNext()) {
+ it.next();
+ env.insert(it.key(), it.value().toString());
+ }
+ m_process->setProcessEnvironment(env);
+ m_process->setWorkingDirectory(m_info.workingDirectory());
+ m_process->start(m_info.program(), m_info.arguments());
+}
+
+/*!
+ Attempts to stop a process by giving it a \a timeout time to die, measured in milliseconds.
+
+ If the process does not die in the given time limit, it is killed.
+
+ \sa finished()
+*/
+
+void UnixProcessBackend::stop(int timeout)
+{
+ Q_ASSERT(m_process);
+
+ if (m_process->state() != QProcess::NotRunning) {
+ if (timeout > 0) {
+ m_process->terminate();
+ m_killTimer.start(timeout);
+ }
+ else
+ m_process->kill();
+ }
+}
+
+/*!
+ Writes at most \a maxSize bytes of data from \a data to the device.
+ Returns the number of bytes that were actually written, or -1 if an error occurred.
+*/
+qint64 UnixProcessBackend::write(const char *data, qint64 maxSize)
+{
+ if (m_process)
+ return m_process->write(data, maxSize);
+ return 0;
+}
+
+/*!
+ Override this in subclasses. Make sure you call the parent class.
+ Your subclass should emit \sa started()
+*/
+void UnixProcessBackend::handleProcessStarted()
+{
+ if (m_info.contains("priority") && setpriority(PRIO_PROCESS, m_process->pid(), m_info.priority()))
+ qWarning() << "Failed to set process priority at startup from " << actualPriority() <<
+ "to" << m_info.priority() << " : errno = " << errno;
+}
+/*!
+ Override this in subclasses. Make sure you call the parent class with \a error.
+ Your subclass should emit \sa error()
+*/
+void UnixProcessBackend::handleProcessError(QProcess::ProcessError error)
+{
+ Q_UNUSED(error);
+}
+
+/*!
+ Override this in subclasses. Make sure you call the parent class with \a exitCode
+ and \a exitStatus. Your subclass should emit \sa finished()
+*/
+void UnixProcessBackend::handleProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ Q_UNUSED(exitCode);
+ Q_UNUSED(exitStatus);
+ m_killTimer.stop();
+}
+
+/*!
+ Override this in subclasses. Make sure you call the parent class with \a state.
+ Your subclass should emit \sa stateChanged()
+*/
+void UnixProcessBackend::handleProcessStateChanged(QProcess::ProcessState state)
+{
+ Q_UNUSED(state);
+ m_killTimer.stop();
+}
+
+/*!
+ \internal
+*/
+void UnixProcessBackend::unixProcessStarted()
+{
+ handleProcessStarted();
+}
+
+/*!
+ \internal
+*/
+void UnixProcessBackend::unixProcessError(QProcess::ProcessError error)
+{
+ handleProcessError(error);
+}
+
+/*!
+ \internal
+*/
+void UnixProcessBackend::unixProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ handleProcessFinished(exitCode, exitStatus);
+}
+
+/*!
+ \internal
+*/
+void UnixProcessBackend::unixProcessStateChanged(QProcess::ProcessState state)
+{
+ handleProcessStateChanged(state);
+}
+
+/*!
+ \internal
+*/
+void UnixProcessBackend::killTimeout()
+{
+ if (m_process && m_process->state() == QProcess::Running)
+ m_process->kill();
+}
+
+/*!
+ \internal
+*/
+void UnixProcessBackend::readyReadStandardOutput()
+{
+ handleStandardOutput(m_process->readAllStandardOutput());
+}
+
+/*!
+ \internal
+*/
+void UnixProcessBackend::readyReadStandardError()
+{
+ handleStandardError(m_process->readAllStandardError());
+}
+
+#include "moc_unixprocessbackend.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/unixprocessbackend.h b/src/core/unixprocessbackend.h
new file mode 100644
index 0000000..ae68ffb
--- /dev/null
+++ b/src/core/unixprocessbackend.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef UNIX_PROCESS_BACKEND_H
+#define UNIX_PROCESS_BACKEND_H
+
+#include "processbackend.h"
+#include <QTimer>
+
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class UnixProcessBackend : public ProcessBackend
+{
+ Q_OBJECT
+
+public:
+ UnixProcessBackend(const ProcessInfo& info, QObject *parent=0);
+ virtual ~UnixProcessBackend();
+
+ virtual Q_PID pid() const;
+
+ virtual qint32 actualPriority() const;
+ virtual void setDesiredPriority(qint32);
+
+#if defined(Q_OS_LINUX)
+ virtual qint32 actualOomAdjustment() const;
+ virtual void setDesiredOomAdjustment(qint32);
+#endif
+
+ virtual QProcess::ProcessState state() const;
+ virtual void stop(int timeout = 500);
+
+ virtual qint64 write(const char *data, qint64 maxSize);
+
+protected:
+ bool createProcess();
+ void startProcess();
+
+ virtual void handleProcessStarted();
+ virtual void handleProcessError(QProcess::ProcessError error);
+ virtual void handleProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
+ virtual void handleProcessStateChanged(QProcess::ProcessState state);
+
+private slots:
+ void unixProcessStarted();
+ void unixProcessError(QProcess::ProcessError error);
+ void unixProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
+ void unixProcessStateChanged(QProcess::ProcessState state);
+
+ void killTimeout();
+ void readyReadStandardOutput();
+ void readyReadStandardError();
+
+protected:
+ QProcess *m_process;
+ QTimer m_killTimer;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // UNIX_PROCESS_BACKEND_H
diff --git a/src/core/unixsandboxprocess.cpp b/src/core/unixsandboxprocess.cpp
new file mode 100644
index 0000000..c7c8889
--- /dev/null
+++ b/src/core/unixsandboxprocess.cpp
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "unixsandboxprocess.h"
+#include <sys/stat.h>
+
+#if defined(Q_OS_LINUX)
+#include <sys/types.h>
+#include <unistd.h>
+#include <grp.h>
+#endif
+
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \class UnixSandboxProcess
+ \brief The UnixSandboxProcess class sets the UID and GID on a Unix process
+*/
+
+/*!
+ Construct a UnixProcessBackend with \a uid, \a gid, and optional \a parent.
+*/
+
+UnixSandboxProcess::UnixSandboxProcess(qint64 uid, qint64 gid, QObject *parent)
+ : QProcess(parent)
+ , m_uid(uid)
+ , m_gid(gid)
+{
+}
+
+/*!
+ \internal Set up the user and group id
+*/
+
+void UnixSandboxProcess::setupChildProcess()
+{
+ qDebug() << "Setting up child process" << m_uid << m_gid;
+ ::setgroups(0,0);
+ ::setgid(m_gid);
+ ::setuid(m_uid);
+ ::umask(S_IWGRP | S_IWOTH);
+}
+
+#include "moc_unixsandboxprocess.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/unixsandboxprocess.h b/src/core/unixsandboxprocess.h
new file mode 100644
index 0000000..797bc34
--- /dev/null
+++ b/src/core/unixsandboxprocess.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef UNIX_SANDBOX_PROCESS_H
+#define UNIX_SANDBOX_PROCESS_H
+
+#include <QProcess>
+
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class UnixSandboxProcess : public QProcess
+{
+ Q_OBJECT
+
+public:
+ UnixSandboxProcess(qint64 uid, qint64 gid, QObject *parent=0);
+
+protected:
+ void setupChildProcess();
+
+private:
+ qint64 m_uid;
+ qint64 m_gid;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // UNIX_SANDBOX_PROCESS_H
diff --git a/src/declarative/.gitignore b/src/declarative/.gitignore
new file mode 100644
index 0000000..0ff1d61
--- /dev/null
+++ b/src/declarative/.gitignore
@@ -0,0 +1 @@
+plugin.moc
diff --git a/src/declarative/declarative-lib.pri b/src/declarative/declarative-lib.pri
new file mode 100644
index 0000000..8c253e8
--- /dev/null
+++ b/src/declarative/declarative-lib.pri
@@ -0,0 +1,12 @@
+QT += declarative
+CONFIG += network
+
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/declarativeprocessmanager.h \
+ $$PWD/processinfotemplate.h
+
+SOURCES += \
+ $$PWD/declarativeprocessmanager.cpp \
+ $$PWD/processinfotemplate.cpp
diff --git a/src/declarative/declarative.pri b/src/declarative/declarative.pri
new file mode 100644
index 0000000..34a2ab1
--- /dev/null
+++ b/src/declarative/declarative.pri
@@ -0,0 +1,12 @@
+include(../core/core.pri)
+
+CONFIG += network
+
+INCLUDEPATH += $$PWD
+LIBS += -L$$PWD -lprocessmanager-declarative
+
+mac|unix {
+ CONFIG += rpath_libdirs
+ QMAKE_RPATHDIR += $$PWD
+ QMAKE_LFLAGS += "-Wl,-rpath $$PWD"
+}
diff --git a/src/declarative/declarative.pro b/src/declarative/declarative.pro
new file mode 100644
index 0000000..051ef27
--- /dev/null
+++ b/src/declarative/declarative.pro
@@ -0,0 +1,25 @@
+TEMPLATE = lib
+TARGET = processmanager-declarative
+
+LIBS += -L../core
+
+include($$PWD/../../config.pri)
+include(../core/core.pri)
+include(declarative-lib.pri)
+
+SOURCES += \
+ plugin.cpp
+
+mac:!staticlib {
+ QMAKE_POST_LINK = install_name_tool -id $$PWD/${TARGET} ${TARGET}
+}
+
+qmldir.path = $$INSTALLBASE/imports/com/nokia/QtProcessManager
+qmldir.files += $$PWD/qmldir
+
+headers.path = $$INSTALLBASE/include/qtprocessmanager
+headers.files = $$HEADERS
+
+target.path = $$INSTALLBASE/lib
+
+INSTALLS += target headers qmldir
diff --git a/src/declarative/declarativeprocess.cpp b/src/declarative/declarativeprocess.cpp
new file mode 100644
index 0000000..47e3524
--- /dev/null
+++ b/src/declarative/declarativeprocess.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation
+ */
+
+#include "declarativeprocess.h"
+
+#include <QDateTime>
+
+/***************************************************************************************/
+
+/*!
+ \class DeclarativeProcess
+ \brief The DeclarativeProcess class is a generalized representation of a process.
+*/
+
+/*!
+ \property DeclarativeProcess::identifier
+ \brief the application identifier of the process.
+*/
+
+/*!
+ \property DeclarativeProcess::program
+ \brief the filename of the binary executable that is launched to start up the process.
+*/
+
+/*!
+ \property DeclarativeProcess::arguments
+ \brief the arguments that will be passed to the program upon process startup
+*/
+
+/*!
+ \property DeclarativeProcess::environment
+ \brief a map of the environment variables that will be used by the process
+*/
+
+/*!
+ \property DeclarativeProcess::workingDirectory
+ \brief the directory that will be switched to before launching the process
+*/
+
+/*!
+ \property DeclarativeProcess::uid
+ \brief the user id (uid) of the process.
+*/
+
+/*!
+ \property DeclarativeProcess::gid
+ \brief the group id (gid) of the process.
+*/
+
+/*!
+ \property DeclarativeProcess::pid
+ \brief the process id (PID) of the process.
+
+ Returns 0 if the process has not been started or if this is a "fake" process.
+*/
+
+/*!
+ \property DeclarativeProcess::startTime
+ \brief the start time of the process, measured in milliseconds since the epoch (1st Jan 1970 00:00).
+
+ Returns 0 if process has not been started.
+*/
+
+/*!
+ \property DeclarativeProcess::priority
+ \brief The Unix process priority (niceness).
+
+ Returns the current process priority if the process is running. Otherwise,
+ it returns the DeclarativeProcess priority setting. You can only set the priority once the
+ process is running.
+*/
+
+#if defined(Q_OS_LINUX)
+/*!
+ \property DeclarativeProcess::oomAdjustment
+ \brief The Unix process /proc/<pid>/oom_score_adj (likelihood of being killed)
+
+ Returns the current OOM adjustment score if the process is running. Otherwise,
+ it returns the DeclarativeProcess OOM adjustment score setting. You can only set the OOM adjustment
+ score when the process is running.
+*/
+#endif
+
+/*!
+ \internal
+ Constructs a DeclarativeProcess instance with DeclarativeProcess \a info and optional \a parent
+*/
+DeclarativeProcess::DeclarativeProcess(ProcessBackend *process, QObject *parent)
+ : ProcessFrontend(process, parent)
+{
+}
+
+/*!
+ Destroy this process object.
+*/
+
+DeclarativeProcess::~DeclarativeProcess()
+{
+}
diff --git a/src/declarative/declarativeprocess.h b/src/declarative/declarativeprocess.h
new file mode 100644
index 0000000..296ae3e
--- /dev/null
+++ b/src/declarative/declarativeprocess.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation
+ */
+
+#ifndef DECLARATIVE_PROCESS_H
+#define DECLARATIVE_PROCESS_H
+
+#include "processfrontend.h"
+
+class DeclarativeProcess : public ProcessFrontend
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString identifier READ identifier CONSTANT)
+ Q_PROPERTY(QString program READ program CONSTANT)
+ Q_PROPERTY(QStringList arguments READ arguments CONSTANT)
+ Q_PROPERTY(QVariantMap environment READ environment CONSTANT)
+ Q_PROPERTY(QString workingDirectory READ workingDirectory CONSTANT)
+ Q_PROPERTY(qint64 uid READ uid CONSTANT)
+ Q_PROPERTY(qint64 gid READ gid CONSTANT)
+
+ Q_PROPERTY(qint64 pid READ pid NOTIFY started)
+ Q_PROPERTY(qint64 startTime READ startTime NOTIFY started)
+
+ Q_PROPERTY(int priority READ priority WRITE setPriority NOTIFY priorityChanged)
+#if defined(Q_OS_LINUX)
+ Q_PROPERTY(int oomAdjustment READ oomAdjustment WRITE setOomAdjustment NOTIFY oomAdjustmentChanged)
+#endif
+
+public:
+ DeclarativeProcess(ProcessBackend *process, QObject *parent=0);
+ virtual ~DeclarativeProcess();
+};
+
+Q_DECLARE_METATYPE(DeclarativeProcess*)
+
+#endif // DECLARATIVE_PROCESS_H
diff --git a/src/declarative/declarativeprocessmanager.cpp b/src/declarative/declarativeprocessmanager.cpp
new file mode 100644
index 0000000..2f43a7b
--- /dev/null
+++ b/src/declarative/declarativeprocessmanager.cpp
@@ -0,0 +1,280 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "declarativeprocessmanager.h"
+#include "processbackendfactory.h"
+#include "processfrontend.h"
+
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \qmlclass ProcessManager DeclarativeProcessManager
+ \brief The ProcessManager class encapsulates ways of creating and tracking processes.
+
+ Only a single ProcessManager class should be loaded at one time.
+
+ Typical use of the ProcessManager class is as follows:
+
+ \code
+ import QtQuick 2.0
+ import ProcessManager 1.0
+
+ ProcessManager {
+ id: myProcessManager
+
+ factories: [
+ GdbProcessBackendFactory {},
+ StandardProcessBackendFactory {}
+ ]
+ }
+ \endcode
+
+*/
+
+/*!
+ \qmlproperty list<ProcessBackendFactory> ProcessManager::factories
+ \brief The factories assigned to this process manager
+
+ The factories property is an ordered list of ProcessBackendFactory objects.
+*/
+
+
+/*!
+ Construct a DeclarativeProcessManager with an optional \a parent
+*/
+
+DeclarativeProcessManager::DeclarativeProcessManager(QObject *parent)
+ : ProcessManager(parent)
+{
+}
+
+/*!
+ \internal
+*/
+void DeclarativeProcessManager::classBegin()
+{
+}
+
+/*!
+ \internal
+*/
+void DeclarativeProcessManager::componentComplete()
+{
+}
+
+/*!
+ \internal
+*/
+void append_factory(QDeclarativeListProperty<ProcessBackendFactory> *list,
+ ProcessBackendFactory *value)
+{
+ DeclarativeProcessManager *manager = static_cast<DeclarativeProcessManager *>(list->object);
+ ProcessBackendFactory *factory = qobject_cast<ProcessBackendFactory *>(value);
+ if (factory)
+ manager->addBackendFactory(factory);
+}
+
+/*!
+ \internal
+ */
+
+QDeclarativeListProperty<ProcessBackendFactory> DeclarativeProcessManager::factories()
+{
+ return QDeclarativeListProperty<ProcessBackendFactory>(this, NULL, append_factory);
+}
+
+/*!
+ Raise the processAboutToStart() signal.
+*/
+
+void DeclarativeProcessManager::processFrontendAboutToStart()
+{
+ ProcessFrontend *frontend = static_cast<ProcessFrontend *>(sender());
+ if (frontend)
+ emit processAboutToStart(frontend->name());
+ ProcessManager::processFrontendAboutToStart();
+}
+
+/*!
+ Raise the processAboutToStop() signal.
+*/
+
+void DeclarativeProcessManager::processFrontendAboutToStop()
+{
+ ProcessFrontend *frontend = static_cast<ProcessFrontend *>(sender());
+ if (frontend)
+ emit processAboutToStop(frontend->name());
+ ProcessManager::processFrontendAboutToStop();
+}
+
+/*!
+ Raise the processStarted() signal.
+*/
+
+void DeclarativeProcessManager::processFrontendStarted()
+{
+ ProcessFrontend *frontend = static_cast<ProcessFrontend *>(sender());
+ if (frontend)
+ emit processStarted(frontend->name());
+ ProcessManager::processFrontendStarted();
+}
+
+/*!
+ Raise the processError() signal.
+ Pass through the \a error value.
+*/
+
+void DeclarativeProcessManager::processFrontendError(QProcess::ProcessError error)
+{
+ ProcessFrontend *frontend = static_cast<ProcessFrontend *>(sender());
+ if (frontend)
+ emit processError(frontend->name(), static_cast<int>(error));
+ ProcessManager::processFrontendError(error);
+}
+
+/*!
+ Raise the processFinished() signal. Pass through the
+ \a exitCode and \a exitStatus values.
+*/
+
+void DeclarativeProcessManager::processFrontendFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ ProcessFrontend *frontend = static_cast<ProcessFrontend *>(sender());
+ if (frontend)
+ emit processFinished(frontend->name(), exitCode, exitStatus);
+ ProcessManager::processFrontendFinished(exitCode, exitStatus);
+}
+
+/*!
+ Raise the processStateChanged() signal. Pass through the
+ \a state value.
+*/
+
+void DeclarativeProcessManager::processFrontendStateChanged(QProcess::ProcessState state)
+{
+ ProcessFrontend *frontend = static_cast<ProcessFrontend *>(sender());
+ if (frontend)
+ emit processStateChanged(frontend->name(), state);
+ ProcessManager::processFrontendStateChanged(state);
+}
+
+/*!
+ Raise the processFrontendDestroyed() signal.
+*/
+
+void DeclarativeProcessManager::processFrontendDestroyed()
+{
+ ProcessFrontend *frontend = static_cast<ProcessFrontend *>(sender());
+ if (frontend)
+ emit processDestroyed(frontend->name());
+ ProcessManager::processFrontendDestroyed();
+}
+
+/*!
+ \fn void DeclarativeProcessManager::processAboutToStart(const QString& name)
+ This signal is emitted when a process is about to start.
+ The \a name may be used to retrieve the ProcessFrontend
+ object.
+
+ \sa processForName()
+*/
+
+/*!
+ \fn void DeclarativeProcessManager::processAboutToStop(const QString& name)
+ This signal is emitted when a process is about to stop
+ The \a name may be used to retrieve the ProcessFrontend
+ object.
+
+ \sa processForName()
+*/
+
+/*!
+ \fn void DeclarativeProcessManager::processStarted(const QString& name)
+ This signal is emitted once a process has started.
+ The \a name may be used to retrieve the ProcessFrontend
+ object.
+
+ \sa processForName()
+*/
+
+/*!
+ \fn void DeclarativeProcessManager::processError(const QString& name, int error)
+ This signal is emitted when a process experiences an \a error.
+ The \a name may be used to retrieve the ProcessFrontend
+ object. The \a error value can be compared to the QProcess::ProcessError
+ enumeration (it has been cast to an integer to resolve a QML issue).
+
+ \sa processForName()
+*/
+
+/*!
+ \fn void DeclarativeProcessManager::processFinished(const QString& name, int exitCode, int exitStatus)
+ This signal is emitted when a process finishes. The \a exitCode
+ and \a exitStatus match the QProcess values.
+ The \a name may be used to retrieve the ProcessFrontend
+ object. The \a exitStatus value can be compared with a QProcess::ExitStatus
+ enumeration (it has been cast to an integer to resolve a QML issue).
+
+ \sa processForName()
+*/
+
+/*!
+ \fn void DeclarativeProcessManager::processStateChanged(const QString& name, int state)
+ This signal is emitted when a process has a state change to \a state.
+ The \a name may be used to retrieve the ProcessFrontend
+ object. The \a state value can be compared with QProcess::ProcessState values
+ (it has been cast to an integer to resolve a QML issue).
+
+ \sa processForName()
+*/
+
+/*!
+ \fn void DeclarativeProcessManager::processDestroyed(const QString &name)
+ This signal is emitted when a process has been destroyed
+ The \a name cannot be used to retrieve the ProcessFrontend
+ object because it no longer exists.
+*/
+
+
+
+#include "moc_declarativeprocessmanager.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/declarative/declarativeprocessmanager.h b/src/declarative/declarativeprocessmanager.h
new file mode 100644
index 0000000..51c38ca
--- /dev/null
+++ b/src/declarative/declarativeprocessmanager.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DECLARATIVE_PROCESS_MANAGER_H
+#define DECLARATIVE_PROCESS_MANAGER_H
+
+#include "processmanager.h"
+#include <QDeclarativeListProperty>
+#include <QDeclarativeParserStatus>
+#include <qdeclarative.h>
+
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class DeclarativeProcessManager : public ProcessManager, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QDeclarativeParserStatus)
+ Q_PROPERTY(QDeclarativeListProperty<ProcessBackendFactory> factories READ factories)
+
+public:
+ DeclarativeProcessManager(QObject *parent=0);
+ QDeclarativeListProperty<ProcessBackendFactory> factories();
+
+ void classBegin();
+ void componentComplete();
+
+signals:
+ void processAboutToStart(const QString& name);
+ void processAboutToStop(const QString& name);
+ void processStarted(const QString& name);
+ void processError(const QString& name, int error);
+ void processFinished(const QString& name, int exitCode, int exitStatus);
+ void processStateChanged(const QString& name, int state);
+ void processDestroyed(const QString &name);
+
+protected slots:
+ virtual void processFrontendAboutToStart();
+ virtual void processFrontendAboutToStop();
+ virtual void processFrontendStarted();
+ virtual void processFrontendError(QProcess::ProcessError);
+ virtual void processFrontendFinished(int, QProcess::ExitStatus);
+ virtual void processFrontendStateChanged(QProcess::ProcessState);
+ virtual void processFrontendDestroyed();
+
+private:
+ friend void append_factory(QDeclarativeListProperty<ProcessBackendFactory>*,
+ ProcessBackendFactory*);
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+QML_DECLARE_TYPE(QT_PREPEND_NAMESPACE_PROCESSMANAGER(DeclarativeProcessManager))
+
+#endif // DECLARATIVE_PROCESS_MANAGER_H
diff --git a/src/declarative/plugin.cpp b/src/declarative/plugin.cpp
new file mode 100644
index 0000000..93a7a4c
--- /dev/null
+++ b/src/declarative/plugin.cpp
@@ -0,0 +1,28 @@
+#include "processinfotemplate.h"
+#include "declarativeprocessmanager.h"
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/QDeclarativeExtensionPlugin>
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class ProcessManagerPlugin : public QDeclarativeExtensionPlugin
+{
+ Q_OBJECT
+public:
+ void registerTypes(const char *uri) {
+ qmlRegisterType<ProcessInfoTemplate>(uri, 1, 0, "ProcessInfoTemplate");
+ qmlRegisterType<DeclarativeProcessManager>(uri, 1, 0, "ProcessManager");
+ }
+
+ void initializeEngine(QDeclarativeEngine *engine, const char *uri) {
+ Q_UNUSED(engine);
+ Q_UNUSED(uri);
+ }
+};
+
+#include "plugin.moc"
+
+Q_EXPORT_PLUGIN2(processmanagertemplateplugin, ProcessManagerPlugin)
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/declarative/processinfotemplate.cpp b/src/declarative/processinfotemplate.cpp
new file mode 100644
index 0000000..8afd3c0
--- /dev/null
+++ b/src/declarative/processinfotemplate.cpp
@@ -0,0 +1,507 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "processinfotemplate.h"
+#include "processinfo.h"
+
+#include <QtDeclarative/QDeclarativeExpression>
+
+#include <QFileInfo>
+#include <QDir>
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+const QString ProcessInfoTemplate::kCustomValuesStr = QString::fromLatin1("_customValues");
+
+/*!
+ \class ProcessInfoTemplate
+ \brief The ProcessInfoTemplate class stores template information used to create ProcessInfo objects
+
+ ProcessInfoTemplate is a declarative class used to store template information that will be used to
+ create ProcessInfo objects. These objects are created by calling \l createProcessInfo().
+
+ Values stored in the template properties are not evaluated until \l createProcessInfo() is executed.
+ Values can use \l bind() to bind to values that are contained in a dictionary that is specified when
+ \l createProcessInfo() is executed.
+*/
+
+/*!
+ \property ProcessInfoTemplate::identifier
+ \brief unique identifier for this template
+
+ Specifies a unique identifier for this template.
+*/
+
+/*!
+ \property ProcessInfoTemplate::programName
+ \brief unique programName for this template
+
+ Specifies a unique programName for this template.
+*/
+
+/*!
+ \property ProcessInfoTemplate::uid
+ \brief unique uid for this template
+
+ Specifies a unique uid for this template.
+*/
+
+/*!
+ \property ProcessInfoTemplate::gid
+ \brief unique gid for this template
+
+ Specifies a unique gid for this template.
+*/
+
+/*!
+ \property ProcessInfoTemplate::workingDirectory
+ \brief unique workingDirectory for this template
+
+ Specifies a unique workingDirectory for this template.
+*/
+
+/*!
+ \property ProcessInfoTemplate::environment
+ \brief unique environment for this template
+
+ Specifies a unique environment for this template.
+*/
+
+/*!
+ \property ProcessInfoTemplate::arguments
+ \brief unique arguments for this template
+
+ Specifies a unique arguments for this template.
+*/
+
+/*!
+ \property ProcessInfoTemplate::startOutputPattern
+ \brief unique startOutputPattern for this template
+
+ Specifies a unique startOutputPattern for this template.
+*/
+
+/*!
+ \property ProcessInfoTemplate::priority
+ \brief unique priority for this template
+
+ Specifies a unique priority for this template.
+*/
+
+/*!
+ \property ProcessInfoTemplate::customValues
+ \brief unique customValues for this template
+
+ Specifies a unique customValues for this template.
+*/
+
+/*!
+ Constructs a ProcessInfoTemplate with optional \a parent.
+ */
+
+ProcessInfoTemplate::ProcessInfoTemplate(QObject *parent) :
+ QObject(parent)
+{
+}
+
+/*!
+ Return the template identifier
+*/
+
+QString ProcessInfoTemplate::identifier() const
+{
+ return m_templateData.value(ProcessInfoConstants::Identifier).toString();
+}
+
+/*!
+ Return the template programName
+*/
+
+QDeclarativeScriptString ProcessInfoTemplate::programName() const
+{
+ return scriptString(ProcessInfoConstants::Program);
+}
+
+/*!
+ Return the template uid
+*/
+
+QDeclarativeScriptString ProcessInfoTemplate::uid() const
+{
+ return scriptString(ProcessInfoConstants::Uid);
+}
+
+/*!
+ Return the template gid
+*/
+
+QDeclarativeScriptString ProcessInfoTemplate::gid() const
+{
+ return scriptString(ProcessInfoConstants::Gid);
+}
+
+/*!
+ Return the template workingDirectory
+*/
+
+QDeclarativeScriptString ProcessInfoTemplate::workingDirectory() const
+{
+ return scriptString(ProcessInfoConstants::WorkingDirectory);
+}
+
+/*!
+ Return the template environment
+*/
+
+QDeclarativeScriptString ProcessInfoTemplate::environment() const
+{
+ return scriptString(ProcessInfoConstants::Environment);
+}
+
+/*!
+ Return the template arguments
+*/
+
+QDeclarativeScriptString ProcessInfoTemplate::arguments() const
+{
+ return scriptString(ProcessInfoConstants::Arguments);
+}
+
+/*!
+ Return the template startOutputPattern
+*/
+
+QDeclarativeScriptString ProcessInfoTemplate::startOutputPattern() const
+{
+ return scriptString(ProcessInfoConstants::StartOutputPattern);
+}
+
+/*!
+ Return the template priority
+*/
+
+QDeclarativeScriptString ProcessInfoTemplate::priority() const
+{
+ return scriptString(ProcessInfoConstants::Priority);
+}
+
+/*!
+ Return the template customValues
+*/
+
+QDeclarativeScriptString ProcessInfoTemplate::customValues() const
+{
+ return scriptString(kCustomValuesStr);
+}
+
+/*!
+ Set the template \a identifier
+*/
+
+void ProcessInfoTemplate::setIdentifier(const QString &identifier)
+{
+ m_templateData.insert(ProcessInfoConstants::Identifier, QVariant(identifier));
+ emit identifierChanged();
+}
+
+/*!
+ Set the template \a programName
+*/
+
+void ProcessInfoTemplate::setProgramName(const QDeclarativeScriptString &programName)
+{
+ setScriptString(ProcessInfoConstants::Program, programName);
+ emit programNameChanged();
+}
+
+/*!
+ Set the template \a uid
+*/
+
+void ProcessInfoTemplate::setUid(const QDeclarativeScriptString &uid)
+{
+ setScriptString(ProcessInfoConstants::Uid, uid);
+ emit uidChanged();
+}
+
+/*!
+ Set the template \a gid
+*/
+
+void ProcessInfoTemplate::setGid(const QDeclarativeScriptString &gid)
+{
+ setScriptString(ProcessInfoConstants::Gid, gid);
+ emit gidChanged();
+}
+
+/*!
+ Set the template \a workingDirectory
+*/
+
+void ProcessInfoTemplate::setWorkingDirectory(const QDeclarativeScriptString &workingDirectory)
+{
+ setScriptString(ProcessInfoConstants::WorkingDirectory, workingDirectory);
+ emit workingDirectoryChanged();
+}
+
+/*!
+ Set the template \a env environment
+*/
+
+void ProcessInfoTemplate::setEnvironment(QDeclarativeScriptString environment)
+{
+ setScriptString(ProcessInfoConstants::Environment, environment);
+ emit environmentChanged();
+}
+
+/*!
+ Set the template \a arguments
+*/
+
+void ProcessInfoTemplate::setArguments(const QDeclarativeScriptString &arguments)
+{
+ setScriptString(ProcessInfoConstants::Arguments, arguments);
+ emit argumentsChanged();
+}
+
+/*!
+ Set the template \a startOutputPattern
+*/
+
+void ProcessInfoTemplate::setStartOutputPattern(const QDeclarativeScriptString &startOutputPattern)
+{
+ setScriptString(ProcessInfoConstants::StartOutputPattern, startOutputPattern);
+ emit startOutputPatternChanged();
+}
+
+/*!
+ Set the template \a priority
+*/
+
+void ProcessInfoTemplate::setPriority(const QDeclarativeScriptString &priority)
+{
+ setScriptString(ProcessInfoConstants::Priority, priority);
+ emit priorityChanged();
+}
+
+/*!
+ Set the template \a customValues
+*/
+
+void ProcessInfoTemplate::setCustomValues(const QDeclarativeScriptString &customValues)
+{
+ setScriptString(kCustomValuesStr, customValues);
+ emit customValuesChanged();
+}
+
+/*!
+ * Attempts to bind \a tag to a value in a previously specified dictionary. Returns the
+ * bound value, or \a defaultValue if a binding for \a tag does not exist in the dictionary.
+ * This method is intended to be used in QML when specifying properties for the template.
+ *
+ * \sa createProcessInfo()
+ */
+
+QVariant ProcessInfoTemplate::bind(const QString &tag, const QVariant &defaultValue)
+{
+ return m_dict.value(tag, defaultValue);
+}
+
+/*!
+ Creates and returns a new ProcessInfo object. All property value scripts are evaluated
+ (bound) with \a dict.
+ */
+ProcessInfo *ProcessInfoTemplate::createProcessInfo(const QVariantMap &dict)
+{
+ QVariantMap boundData = bindData(dict);
+ ProcessInfo *processInfo = new ProcessInfo(boundData);
+ return processInfo;
+}
+
+/*!
+ Return the script string bound to \a name
+ */
+
+QDeclarativeScriptString ProcessInfoTemplate::scriptString(const QString &name) const
+{
+ QVariant var = m_templateData.value(name);
+ if (var.canConvert<QDeclarativeScriptString>())
+ return var.value<QDeclarativeScriptString>();
+ else
+ return QDeclarativeScriptString();
+}
+
+/*!
+ Set the script string \a script to value \a name
+ */
+
+void ProcessInfoTemplate::setScriptString(const QString &name, const QDeclarativeScriptString &script)
+{
+ m_templateData.insert(name, QVariant::fromValue<QDeclarativeScriptString>(script));
+}
+
+/*!
+ Returns the evaluated expression using \a script data.
+ */
+
+QVariant ProcessInfoTemplate::bindScript(const QDeclarativeScriptString &script)
+{
+ if (script.context() && !script.script().isEmpty()) {
+ // This is necessary because QDeclarativeExpression tries to return any JS array script
+ // as a QList<QObject *>, and that type is not useful to us (the returned JS array will
+ // only contain null values. So we wrap everything in a simple JSON object, and then pick
+ // out the real value after evaluating it.
+
+ QString scriptStr = "script";
+ QString jsonWrapper = QString("{\"%1\": %2}").arg(scriptStr).arg(script.script());
+ QDeclarativeExpression expr(script.context(), this, jsonWrapper);
+
+ return expr.evaluate().toMap().value(scriptStr);
+ }
+ else
+ return QVariant();
+}
+
+/*!
+ Returns the bindScript value evaluated from slot \a name
+ */
+
+QVariant ProcessInfoTemplate::bindValue(const QString &name)
+{
+ return bindScript(scriptString(name));
+}
+
+/*!
+ Set the template dictionary to \a dict
+*/
+
+void ProcessInfoTemplate::setDict(const QVariantMap &dict)
+{
+ m_dict = dict;
+}
+
+
+/*!
+ Returns the absolute file path that consists of \a url and \a filename.
+
+ If \a filename is an absolute path by itself, \a url is ignored.
+ If \a url is empty, only filename is used to resolve the path.
+*/
+QString ProcessInfoTemplate::absoluteFilePath(const QString &url, const QString &filename) const
+{
+ if (url.isEmpty())
+ return QFileInfo(filename).absoluteFilePath();
+ return QFileInfo(QDir(QUrl(url).toLocalFile()), filename).absoluteFilePath();
+}
+
+/*!
+ Returns the boundData from binding \a dict.
+ */
+
+QVariantMap ProcessInfoTemplate::bindData(const QVariantMap &dict)
+{
+ setDict(dict);
+
+ QVariantMap boundData;
+ QMapIterator<QString, QVariant> it(m_templateData);
+ while (it.hasNext()) {
+ it.next();
+ QVariant value = it.value();
+ if (value.canConvert<QDeclarativeScriptString>()) {
+ boundData.insert(it.key(), bindScript(value.value<QDeclarativeScriptString>()));
+ } else {
+ boundData.insert(it.key(), value.toString());
+ }
+ }
+ return boundData;
+}
+
+/*!
+ \fn void ProcessInfoTemplate::identifierChanged()
+ Emitted when the template identifier changes
+*/
+
+/*!
+ \fn void ProcessInfoTemplate::programNameChanged()
+ Emitted when the template programName changes
+*/
+
+/*!
+ \fn void ProcessInfoTemplate::uidChanged()
+ Emitted when the template uid changes
+*/
+
+/*!
+ \fn void ProcessInfoTemplate::gidChanged()
+ Emitted when the template gid changes
+*/
+
+/*!
+ \fn void ProcessInfoTemplate::workingDirectoryChanged()
+ Emitted when the template workingDirectory changes
+*/
+
+/*!
+ \fn void ProcessInfoTemplate::environmentChanged()
+ Emitted when the template environment changes
+*/
+
+/*!
+ \fn void ProcessInfoTemplate::argumentsChanged()
+ Emitted when the template arguments change
+*/
+
+/*!
+ \fn void ProcessInfoTemplate::startOutputPatternChanged()
+ Emitted when the template startOutputPattern changes
+*/
+
+/*!
+ \fn void ProcessInfoTemplate::priorityChanged()
+ Emitted when the template priority changes
+*/
+
+/*!
+ \fn void ProcessInfoTemplate::customValuesChanged()
+ Emitted when the template customValues change
+*/
+
+#include "moc_processinfotemplate.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/declarative/processinfotemplate.h b/src/declarative/processinfotemplate.h
new file mode 100644
index 0000000..0183929
--- /dev/null
+++ b/src/declarative/processinfotemplate.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PROCESSINFOTEMPLATE_H
+#define PROCESSINFOTEMPLATE_H
+
+#include <QObject>
+#include <QVariant>
+#include <QVariantMap>
+#include <QtDeclarative/QDeclarativeScriptString>
+
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class ProcessInfo;
+
+class ProcessInfoTemplate : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString identifier READ identifier WRITE setIdentifier NOTIFY identifierChanged)
+ Q_PROPERTY(QDeclarativeScriptString programName READ programName WRITE setProgramName NOTIFY programNameChanged)
+ Q_PROPERTY(QDeclarativeScriptString uid READ uid WRITE setUid NOTIFY uidChanged)
+ Q_PROPERTY(QDeclarativeScriptString gid READ gid WRITE setGid NOTIFY gidChanged)
+ Q_PROPERTY(QDeclarativeScriptString workingDirectory READ workingDirectory WRITE setWorkingDirectory NOTIFY workingDirectoryChanged)
+ Q_PROPERTY(QDeclarativeScriptString environment READ environment WRITE setEnvironment NOTIFY environmentChanged)
+ Q_PROPERTY(QDeclarativeScriptString arguments READ arguments WRITE setArguments NOTIFY argumentsChanged)
+ Q_PROPERTY(QDeclarativeScriptString startOutputPattern READ startOutputPattern WRITE setStartOutputPattern NOTIFY startOutputPatternChanged)
+ Q_PROPERTY(QDeclarativeScriptString priority READ priority WRITE setPriority NOTIFY priorityChanged)
+ Q_PROPERTY(QDeclarativeScriptString customValues READ customValues WRITE setCustomValues NOTIFY customValuesChanged)
+public:
+ ProcessInfoTemplate(QObject *parent = 0);
+
+ QString identifier() const;
+ QDeclarativeScriptString programName() const;
+ QDeclarativeScriptString uid() const;
+ QDeclarativeScriptString gid() const;
+ QDeclarativeScriptString workingDirectory() const;
+ QDeclarativeScriptString environment() const;
+ QDeclarativeScriptString arguments() const;
+ QDeclarativeScriptString startOutputPattern() const;
+ QDeclarativeScriptString priority() const;
+ QDeclarativeScriptString customValues() const;
+
+ Q_INVOKABLE virtual ProcessInfo *createProcessInfo(const QVariantMap &dict);
+
+ Q_INVOKABLE QVariant bind(const QString &tag, const QVariant &defaultValue = QVariant());
+ Q_INVOKABLE QString absoluteFilePath(const QString &url, const QString &filename = QString()) const;
+
+public slots:
+ void setIdentifier(const QString &identifier);
+ void setProgramName(const QDeclarativeScriptString &programName);
+ void setUid(const QDeclarativeScriptString &uid);
+ void setGid(const QDeclarativeScriptString &gid);
+ void setWorkingDirectory(const QDeclarativeScriptString &dir);
+ void setEnvironment(QDeclarativeScriptString env);
+ void setArguments(const QDeclarativeScriptString &args);
+ void setStartOutputPattern(const QDeclarativeScriptString &startOutputPattern);
+ void setPriority(const QDeclarativeScriptString &value);
+ void setCustomValues(const QDeclarativeScriptString &vals);
+
+signals:
+ void identifierChanged();
+ void programNameChanged();
+ void uidChanged();
+ void gidChanged();
+ void workingDirectoryChanged();
+ void environmentChanged();
+ void argumentsChanged();
+ void startOutputPatternChanged();
+ void priorityChanged();
+ void customValuesChanged();
+
+protected:
+ virtual QVariantMap bindData(const QVariantMap &dict);
+
+ QDeclarativeScriptString scriptString(const QString &name) const;
+ void setScriptString(const QString &name, const QDeclarativeScriptString &script);
+
+ QVariant bindScript(const QDeclarativeScriptString &script);
+ Q_INVOKABLE QVariant bindValue(const QString &name);
+ Q_INVOKABLE void setDict(const QVariantMap &dict);
+
+ static const QString kCustomValuesStr;
+
+private:
+ QVariantMap m_templateData;
+ QVariantMap m_dict;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // PROCESSINFOTEMPLATE_H
diff --git a/src/declarative/qmldir b/src/declarative/qmldir
new file mode 100644
index 0000000..e6c5423
--- /dev/null
+++ b/src/declarative/qmldir
@@ -0,0 +1 @@
+plugin processmanager
diff --git a/src/launcher/launcher-lib.pri b/src/launcher/launcher-lib.pri
new file mode 100644
index 0000000..23be8fe
--- /dev/null
+++ b/src/launcher/launcher-lib.pri
@@ -0,0 +1,14 @@
+QT += network
+CONFIG += network
+
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/launcherclient.h \
+ $$PWD/pipelauncher.h \
+ $$PWD/socketlauncher.h
+
+SOURCES += \
+ $$PWD/launcherclient.cpp \
+ $$PWD/pipelauncher.cpp \
+ $$PWD/socketlauncher.cpp
diff --git a/src/launcher/launcher.pri b/src/launcher/launcher.pri
new file mode 100644
index 0000000..1a7ddf9
--- /dev/null
+++ b/src/launcher/launcher.pri
@@ -0,0 +1,13 @@
+include(../core/core.pri)
+
+CONFIG += network
+QT += jsonstream
+
+INCLUDEPATH += $$PWD
+LIBS += -L$$PWD -lprocessmanager-launcher
+
+mac|unix {
+ CONFIG += rpath_libdirs
+ QMAKE_RPATHDIR += $$PWD
+ QMAKE_LFLAGS += "-Wl,-rpath $$PWD"
+}
diff --git a/src/launcher/launcher.pro b/src/launcher/launcher.pro
new file mode 100644
index 0000000..9070918
--- /dev/null
+++ b/src/launcher/launcher.pro
@@ -0,0 +1,20 @@
+TEMPLATE = lib
+TARGET = processmanager-launcher
+
+QT += jsonstream
+LIBS += -L../core
+
+include($$PWD/../../config.pri)
+include(../core/core.pri)
+include(launcher-lib.pri)
+
+mac:!staticlib {
+ QMAKE_POST_LINK = install_name_tool -id $$PWD/${TARGET} ${TARGET}
+}
+
+headers.path = $$INSTALLBASE/include/qtprocessmanager
+headers.files = $$HEADERS
+
+target.path = $$INSTALLBASE/lib
+
+INSTALLS += target headers
diff --git a/src/launcher/launcherclient.cpp b/src/launcher/launcherclient.cpp
new file mode 100644
index 0000000..e56dfd1
--- /dev/null
+++ b/src/launcher/launcherclient.cpp
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDebug>
+
+#include "launcherclient.h"
+#include "processbackend.h"
+#include "processbackendmanager.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \class LauncherClient
+ \brief The LauncherClient class handles a single Launcher client.
+ */
+
+/*!
+ Create a new LauncherClient with ProcessBackendManager \a manager
+ */
+
+LauncherClient::LauncherClient(ProcessBackendManager *manager)
+ : QObject(manager)
+ , m_manager(manager)
+{
+}
+
+/*!
+ Process an incoming \a message
+ */
+
+void LauncherClient::receive(const QJsonObject& message)
+{
+ qDebug() << Q_FUNC_INFO << message;
+ QString cmd = message.value("command").toString();
+ int id = message.value("id").toDouble();
+ if ( cmd == "start" ) {
+ ProcessInfo info(message.value("info").toObject().toVariantMap());
+ ProcessBackend *backend = m_manager->create(info, this);
+ if (backend) {
+ connect(backend, SIGNAL(started()), SLOT(started()));
+ connect(backend, SIGNAL(finished(int, QProcess::ExitStatus)),
+ SLOT(finished(int, QProcess::ExitStatus)));
+ connect(backend, SIGNAL(error(QProcess::ProcessError)), SLOT(error(QProcess::ProcessError)));
+ connect(backend, SIGNAL(stateChanged(QProcess::ProcessState)),
+ SLOT(stateChanged(QProcess::ProcessState)));
+ connect(backend, SIGNAL(standardOutput(const QByteArray&)),
+ SLOT(standardOutput(const QByteArray&)));
+ connect(backend, SIGNAL(standardError(const QByteArray&)),
+ SLOT(standardError(const QByteArray&)));
+ m_idToBackend.insert(id, backend);
+ m_backendToId.insert(backend, id);
+ backend->start();
+ }
+ }
+ else if ( cmd == "stop" ) {
+ ProcessBackend *backend = m_idToBackend.value(id);
+ if (backend) {
+ int timeout = message.value("timeout").toDouble();
+ backend->stop(timeout);
+ }
+ }
+ else if ( cmd == "set" ) {
+ ProcessBackend *backend = m_idToBackend.value(id);
+ if (backend) {
+ QString key = message.value("key").toString();
+ int value = message.value("value").toDouble();
+ if (key == "priority")
+ backend->setDesiredPriority(value);
+ else if (key == "oomAdjustment")
+ backend->setDesiredOomAdjustment(value);
+ }
+ }
+ else if ( cmd == "write" ) {
+ QByteArray data = message.value("data").toString().toLocal8Bit();
+ ProcessBackend *backend = m_idToBackend.value(id);
+ if (backend)
+ backend->write(data);
+ }
+}
+
+static const QLatin1String kEvent("event");
+static const QLatin1String kId("id");
+
+/*!
+ \internal
+ */
+
+void LauncherClient::started()
+{
+ ProcessBackend *backend = qobject_cast<ProcessBackend *>(sender());
+ QJsonObject msg;
+ msg.insert(kEvent, QLatin1String("started"));
+ msg.insert(kId, m_backendToId.value(backend));
+ msg.insert("pid", (double) backend->pid());
+ emit send(msg);
+}
+
+/*!
+ \internal
+ */
+
+void LauncherClient::finished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ ProcessBackend *backend = qobject_cast<ProcessBackend *>(sender());
+ QJsonObject msg;
+ msg.insert(kEvent, QLatin1String("finished"));
+ msg.insert(kId, m_backendToId.value(backend));
+ msg.insert("exitCode", exitCode);
+ msg.insert("exitStatus", exitStatus);
+ emit send(msg);
+}
+
+/*!
+ \internal
+ */
+
+void LauncherClient::error(QProcess::ProcessError err)
+{
+ ProcessBackend *backend = qobject_cast<ProcessBackend *>(sender());
+ QJsonObject msg;
+ msg.insert(kEvent, QLatin1String("error"));
+ msg.insert(kId, m_backendToId.value(backend));
+ msg.insert("error", err);
+ emit send(msg);
+}
+
+/*!
+ \internal
+ */
+
+void LauncherClient::stateChanged(QProcess::ProcessState state)
+{
+ ProcessBackend *backend = qobject_cast<ProcessBackend *>(sender());
+ QJsonObject msg;
+ msg.insert(kEvent, QLatin1String("stateChanged"));
+ msg.insert(kId, m_backendToId.value(backend));
+ msg.insert("stateChanged", state);
+ emit send(msg);
+}
+
+/*!
+ \internal
+ */
+
+void LauncherClient::standardOutput(const QByteArray& data)
+{
+ ProcessBackend *backend = qobject_cast<ProcessBackend *>(sender());
+ QJsonObject msg;
+ msg.insert(kEvent, QLatin1String("standardOutput"));
+ msg.insert(kId, m_backendToId.value(backend));
+ msg.insert(QLatin1String("data"), QString::fromLocal8Bit(data.data(), data.size()));
+ emit send(msg);
+}
+
+/*!
+ \internal
+ */
+
+void LauncherClient::standardError(const QByteArray& data)
+{
+ ProcessBackend *backend = qobject_cast<ProcessBackend *>(sender());
+ QJsonObject msg;
+ msg.insert(kEvent, QLatin1String("standardError"));
+ msg.insert(kId, m_backendToId.value(backend));
+ msg.insert(QLatin1String("data"), QString::fromLocal8Bit(data.data(), data.size()));
+ emit send(msg);
+}
+
+/*!
+ \fn void LauncherClient::send(const QJsonObject& message)
+
+ Send a \a message to the remote controller.
+*/
+
+#include "moc_launcherclient.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/launcher/launcherclient.h b/src/launcher/launcherclient.h
new file mode 100644
index 0000000..13dd8e8
--- /dev/null
+++ b/src/launcher/launcherclient.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef _LAUNCHER_CLIENT_H
+#define _LAUNCHER_CLIENT_H
+
+#include <QObject>
+#include <QJsonObject>
+#include <QProcess>
+#include <QMap>
+
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class ProcessBackend;
+class ProcessBackendManager;
+
+class LauncherClient : public QObject {
+ Q_OBJECT
+public:
+ LauncherClient(ProcessBackendManager *manager);
+ void receive(const QJsonObject& message);
+
+signals:
+ void send(const QJsonObject& message);
+
+private slots:
+ void started();
+ void finished(int, QProcess::ExitStatus);
+ void error(QProcess::ProcessError);
+ void stateChanged(QProcess::ProcessState);
+ void standardOutput(const QByteArray&);
+ void standardError(const QByteArray&);
+
+private:
+ ProcessBackendManager *m_manager;
+ QMap<int, ProcessBackend *> m_idToBackend;
+ QMap<ProcessBackend *, int> m_backendToId;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // _LAUNCHER_CLIENT_H
diff --git a/src/launcher/main.cpp b/src/launcher/main.cpp
new file mode 100644
index 0000000..db32f14
--- /dev/null
+++ b/src/launcher/main.cpp
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include "socketlauncher.h"
+#include "standardprocessbackendfactory.h"
+
+QT_USE_NAMESPACE_PROCESSMANAGER
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+ SocketLauncher launcher;
+ launcher.addFactory(new StandardProcessBackendFactory);
+ launcher.listen("/tmp/launcher");
+ return app.exec();
+}
diff --git a/src/launcher/pipelauncher.cpp b/src/launcher/pipelauncher.cpp
new file mode 100644
index 0000000..6060c8e
--- /dev/null
+++ b/src/launcher/pipelauncher.cpp
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <signal.h>
+#include <QDebug>
+#include <QtEndian>
+#include <QJsonDocument>
+
+#include "pipelauncher.h"
+#include "launcherclient.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \class PipeLauncher
+ \brief The PipeLauncher class accepts input from STDIN and writes data to STDOUT
+ */
+
+/*!
+ Construct a PipeLauncher with optional \a parent.
+ The PipeLauncher reads JSON-formatted messages from stdin and
+ writes replies on stdout.
+*/
+
+PipeLauncher::PipeLauncher(QObject *parent)
+ : ProcessBackendManager(parent)
+{
+ m_in = new QSocketNotifier( STDIN_FILENO, QSocketNotifier::Read, this );
+ connect(m_in, SIGNAL(activated(int)), SLOT(inReady(int)));
+ m_in->setEnabled(true);
+ m_out = new QSocketNotifier( STDOUT_FILENO, QSocketNotifier::Write, this );
+ connect(m_out, SIGNAL(activated(int)), SLOT(outReady(int)));
+ m_out->setEnabled(false);
+
+ m_client = new LauncherClient(this);
+ connect(m_client, SIGNAL(send(const QJsonObject&)),
+ SLOT(send(const QJsonObject&)));
+}
+
+/*!
+ \internal
+ */
+void PipeLauncher::inReady(int fd)
+{
+ qDebug() << Q_FUNC_INFO;
+ m_in->setEnabled(false);
+ const int bufsize = 1024;
+ uint oldSize = m_inbuf.size();
+ m_inbuf.resize(oldSize + bufsize);
+ int n = ::read(fd, m_inbuf.data()+oldSize, bufsize);
+ if (n > 0)
+ m_inbuf.resize(oldSize+n);
+ else
+ m_inbuf.resize(oldSize);
+ // Could check for an error here
+ // Check for a complete JSON object
+ while (m_inbuf.size() >= 12) {
+ qint32 message_size = qFromLittleEndian(((qint32 *)m_inbuf.data())[2]) + 8;
+ if (m_inbuf.size() < message_size)
+ break;
+ QByteArray msg = m_inbuf.left(message_size);
+ m_inbuf = m_inbuf.mid(message_size);
+ QJsonObject message = QJsonDocument::fromBinaryData(msg).object();
+ if (message.value("remote").toString() == "stop")
+ deleteLater();
+ m_client->receive(message);
+ }
+ m_in->setEnabled(true);
+}
+
+/*!
+ \internal
+ */
+void PipeLauncher::outReady(int fd)
+{
+ qDebug() << Q_FUNC_INFO;
+ m_out->setEnabled(false);
+ if (m_outbuf.size()) {
+ int n = ::write(fd, m_outbuf.data(), m_outbuf.size());
+ if (n == -1) {
+ qDebug() << "Failed to write to stdout";
+ exit(-1);
+ }
+ if (n < m_outbuf.size())
+ m_outbuf = m_outbuf.mid(n);
+ else
+ m_outbuf.clear();
+ }
+ if (m_outbuf.size())
+ m_out->setEnabled(true);
+}
+
+/*!
+ \internal
+ */
+void PipeLauncher::send(const QJsonObject& object)
+{
+ QByteArray data = QJsonDocument(object).toBinaryData();
+ m_outbuf.append(data);
+ m_out->setEnabled(true);
+}
+
+#include "moc_pipelauncher.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/launcher/pipelauncher.h b/src/launcher/pipelauncher.h
new file mode 100644
index 0000000..765449d
--- /dev/null
+++ b/src/launcher/pipelauncher.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PIPE_LAUNCHER_H
+#define PIPE_LAUNCHER_H
+
+#include <QObject>
+#include <QJsonObject>
+#include <QSocketNotifier>
+
+#include "processbackendmanager.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class LauncherClient;
+
+class PipeLauncher : public ProcessBackendManager {
+ Q_OBJECT
+
+public:
+ PipeLauncher(QObject *parent=0);
+
+private slots:
+ void inReady(int fd);
+ void outReady(int fd);
+ void send(const QJsonObject& object);
+
+private:
+ QSocketNotifier *m_in;
+ QSocketNotifier *m_out;
+ QByteArray m_inbuf;
+ QByteArray m_outbuf;
+ LauncherClient *m_client;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // PIPE_LAUNCHER_H
diff --git a/src/launcher/socketlauncher.cpp b/src/launcher/socketlauncher.cpp
new file mode 100644
index 0000000..bb6561f
--- /dev/null
+++ b/src/launcher/socketlauncher.cpp
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <signal.h>
+
+#include "socketlauncher.h"
+#include "launcherclient.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+/*!
+ \class SocketLauncher
+ \brief The SocketLauncher class accepts incoming socket connections and starts processes.
+
+ The SocketLauncher class accepts incoming socket connections and starts and stops
+ processes based on JSON-formatted messages. Each connection gets its own set of
+ processes. When a connection is dropped, all processes associated with that connection
+ are killed.
+ */
+
+/*!
+ Construct a SocketLauncher with optional \a parent.
+ The socket launcher opens a JsonServer object.
+ */
+SocketLauncher::SocketLauncher(QObject *parent)
+ : ProcessBackendManager(parent)
+{
+ m_server = new QtAddOn::JsonStream::JsonServer(this);
+
+ connect(m_server, SIGNAL(messageReceived(const QString&, const QJsonObject&)),
+ SLOT(messageReceived(const QString&, const QJsonObject&)));
+ connect(m_server, SIGNAL(connectionAdded(const QString&)),
+ SLOT(connectionAdded(const QString&)));
+ connect(m_server, SIGNAL(connectionRemoved(const QString&)),
+ SLOT(connectionRemoved(const QString&)));
+}
+
+/*!
+ Listen to TCP socket connections on \a port.
+ The optional \a authority object is used to authenticate incoming connections.
+ Return true if the port can be used.
+*/
+bool SocketLauncher::listen(int port, QtAddOn::JsonStream::JsonAuthority *authority)
+{
+ return m_server->listen(port, authority);
+}
+
+/*!
+ Listen to Unix local socket connections on \a socketname.
+ The optional \a authority object is used to authenticate incoming connections.
+ Return true if the server can be started.
+*/
+bool SocketLauncher::listen(const QString& socketname, QtAddOn::JsonStream::JsonAuthority *authority)
+{
+ return m_server->listen(socketname, authority);
+}
+
+/*!
+ \internal
+*/
+void SocketLauncher::connectionAdded(const QString& identifier)
+{
+ LauncherClient *client = new LauncherClient(this);
+ connect(client, SIGNAL(send(const QJsonObject&)), SLOT(send(const QJsonObject&)));
+ m_idToClient.insert(identifier, client);
+ m_clientToId.insert(client, identifier);
+}
+
+/*!
+ \internal
+*/
+void SocketLauncher::connectionRemoved(const QString& identifier)
+{
+ LauncherClient *client = m_idToClient.take(identifier);
+ if (client) {
+ m_clientToId.take(client);
+ delete client;
+ }
+}
+
+/*!
+ \internal
+*/
+void SocketLauncher::messageReceived(const QString& identifier, const QJsonObject& message)
+{
+ LauncherClient *client = m_idToClient.value(identifier);
+ if (client)
+ client->receive(message);
+}
+
+/*!
+ \internal
+*/
+void SocketLauncher::send(const QJsonObject& message)
+{
+ LauncherClient *client = qobject_cast<LauncherClient *>(sender());
+ Q_ASSERT(client);
+ Q_ASSERT(m_server);
+ m_server->send(m_clientToId.value(client), message);
+}
+
+#include "moc_socketlauncher.cpp"
+
+QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/launcher/socketlauncher.h b/src/launcher/socketlauncher.h
new file mode 100644
index 0000000..2d6ac74
--- /dev/null
+++ b/src/launcher/socketlauncher.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SOCKET_LAUNCHER_H
+#define SOCKET_LAUNCHER_H
+
+#include <QObject>
+#include <QJsonObject>
+#include <jsonserver.h>
+
+#include "processbackendmanager.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+class LauncherClient;
+
+class SocketLauncher : public ProcessBackendManager {
+ Q_OBJECT
+
+public:
+ SocketLauncher(QObject *parent=0);
+ bool listen(int port, QtAddOn::JsonStream::JsonAuthority *authority = 0);
+ bool listen(const QString& socketname, QtAddOn::JsonStream::JsonAuthority *authority=0);
+
+private slots:
+ void connectionAdded(const QString& identifier);
+ void connectionRemoved(const QString& identifier);
+ void messageReceived(const QString& identifier, const QJsonObject& message);
+ void send(const QJsonObject& message);
+
+private:
+ QtAddOn::JsonStream::JsonServer *m_server;
+ QMap<QString, LauncherClient*> m_idToClient;
+ QMap<LauncherClient*, QString> m_clientToId;
+};
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // SOCKET_LAUNCHER_H
diff --git a/src/src.pri b/src/src.pri
new file mode 100644
index 0000000..f934acc
--- /dev/null
+++ b/src/src.pri
@@ -0,0 +1,10 @@
+CONFIG += network
+
+INCLUDEPATH += $$PWD
+LIBS += -L$$PWD -lprocessmanager-core
+
+mac|unix {
+ CONFIG += rpath_libdirs
+ QMAKE_RPATHDIR += $$PWD
+ QMAKE_LFLAGS += "-Wl,-rpath $$PWD"
+}
diff --git a/src/src.pro b/src/src.pro
new file mode 100644
index 0000000..8daef63
--- /dev/null
+++ b/src/src.pro
@@ -0,0 +1,17 @@
+TEMPLATE = subdirs
+
+module_processmanager_core.subdir = core
+module_processmanager_core.target = module-processmanager-core
+
+module_processmanager_declarative.subdir = declarative
+module_processmanager_declarative.target = module-processmanager-declarative
+module_processmanager_declarative.depends += module-processmanager-core
+
+module_processmanager_launcher.subdir = launcher
+module_processmanager_launcher.target = module-processmanager-launcher
+module_processmanager_launcher.depends += module-processmanager-core
+
+SUBDIRS += \
+ module_processmanager_core \
+ module_processmanager_declarative \
+ module_processmanager_launcher
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
new file mode 100644
index 0000000..fc983ed
--- /dev/null
+++ b/tests/auto/auto.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = processmanager declarative
diff --git a/tests/auto/declarative/.gitignore b/tests/auto/declarative/.gitignore
new file mode 100644
index 0000000..55e4154
--- /dev/null
+++ b/tests/auto/declarative/.gitignore
@@ -0,0 +1,2 @@
+tst_declarative
+*.moc
diff --git a/tests/auto/declarative/data/testfrontend.qml b/tests/auto/declarative/data/testfrontend.qml
new file mode 100644
index 0000000..ec6a07d
--- /dev/null
+++ b/tests/auto/declarative/data/testfrontend.qml
@@ -0,0 +1,37 @@
+import QtQuick 2.0
+import Test 1.0
+
+DeclarativeProcessManager {
+ id: foo
+
+ factories: [
+ StandardProcessBackendFactory { id: foo2 }
+ ]
+
+ onProcessStarted: console.log("Process started "+name)
+ onProcessStateChanged: {
+ function stateToString(s) {
+ if (s == Process.NotRunning) return "Not running";
+ if (s == Process.Running) return "Running";
+ if (s == Process.Starting) return "Starting";
+ return "Unknown";
+ }
+ console.log("state changed for "+name+" to "+stateToString(state));
+ }
+
+ function makeProcess() {
+ var a = create({"program": "testDeclarative/testDeclarative","name": "test-client"});
+ return a.name;
+ }
+
+ function startProcess(name) {
+ var p = processForName(name);
+ console.log("Starting process '"+name+"' ="+p);
+ p.start();
+ }
+
+ function stopProcess(name) {
+ var p = processForName(name);
+ p.stop();
+ }
+}
diff --git a/tests/auto/declarative/declarative.pri b/tests/auto/declarative/declarative.pri
new file mode 100644
index 0000000..d797178
--- /dev/null
+++ b/tests/auto/declarative/declarative.pri
@@ -0,0 +1 @@
+TESTCASE_NAME = tst_declarative
diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro
new file mode 100644
index 0000000..f331ac2
--- /dev/null
+++ b/tests/auto/declarative/declarative.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS = testDeclarative test
diff --git a/tests/auto/declarative/test/test.pro b/tests/auto/declarative/test/test.pro
new file mode 100644
index 0000000..58bd541
--- /dev/null
+++ b/tests/auto/declarative/test/test.pro
@@ -0,0 +1,18 @@
+CONFIG += testcase
+macx:CONFIG -= app_bundle
+
+QT += core network declarative testlib
+
+LIBS += -L../../../../src/core -L../../../../src/declarative
+
+include(../declarative.pri)
+include(../../../../src/declarative/declarative.pri)
+
+SOURCES = ../tst_declarative.cpp
+TARGET = ../$$TESTCASE_NAME
+
+OTHER_FILES +=
+
+testDataFiles.files = data
+testDataFiles.path = .
+DEPLOYMENT += testDatafiles
diff --git a/tests/auto/declarative/testDeclarative/.gitignore b/tests/auto/declarative/testDeclarative/.gitignore
new file mode 100644
index 0000000..89af73b
--- /dev/null
+++ b/tests/auto/declarative/testDeclarative/.gitignore
@@ -0,0 +1 @@
+testDeclarative
diff --git a/tests/auto/declarative/testDeclarative/main.cpp b/tests/auto/declarative/testDeclarative/main.cpp
new file mode 100644
index 0000000..d61b1ad
--- /dev/null
+++ b/tests/auto/declarative/testDeclarative/main.cpp
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <string.h>
+
+const int kBufSize = 100;
+
+ssize_t writeline(char *buffer, int len)
+{
+ char *b = buffer;
+ while ( len > 0 ) {
+ ssize_t r = write(STDOUT_FILENO, b, len);
+ if (r < 0)
+ return r;
+ b += r;
+ len -= r;
+ }
+ return 0;
+}
+
+ssize_t readline(char *buffer, int max_len)
+{
+ int len = 0;
+ char c = 0;
+ while (len < max_len && c != '\r' && c != '\n') {
+ ssize_t count = read(STDIN_FILENO, &c, 1);
+ if (count <= 0)
+ return count;
+ *buffer++ = c;
+ len++;
+ }
+ *buffer = 0;
+ return len;
+}
+
+int
+main(int argc, char **argv)
+{
+ char buffer[kBufSize+1];
+
+ while (1) {
+ ssize_t count = readline(buffer, kBufSize);
+ if (count < 0)
+ return 1;
+ if (count == 0)
+ return 0;
+
+ if (strncmp("stop", buffer, 4) == 0)
+ return 0;
+ if (strncmp("crash", buffer, 5) == 0)
+ return 2;
+
+ ssize_t result = writeline(buffer, count);
+ if (result < 0)
+ return 2;
+ }
+}
diff --git a/tests/auto/declarative/testDeclarative/testDeclarative.pro b/tests/auto/declarative/testDeclarative/testDeclarative.pro
new file mode 100644
index 0000000..f7b5f57
--- /dev/null
+++ b/tests/auto/declarative/testDeclarative/testDeclarative.pro
@@ -0,0 +1,9 @@
+CONFIG -= app_bundle
+include(../declarative.pri)
+
+DESTDIR = ./
+SOURCES = main.cpp
+TARGET = testDeclarative
+
+target.path = $$[QT_INSTALL_TESTS]/$$TESTCASE_NAME/testDeclarative
+INSTALLS += target
diff --git a/tests/auto/declarative/tst_declarative.cpp b/tests/auto/declarative/tst_declarative.cpp
new file mode 100644
index 0000000..bb106e6
--- /dev/null
+++ b/tests/auto/declarative/tst_declarative.cpp
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest>
+#include <QtCore/QMetaType>
+#include <QFileInfo>
+#include <QDeclarativeEngine>
+#include <QDeclarativeComponent>
+#include <QDeclarativeProperty>
+
+#include "declarativeprocessmanager.h"
+#include "standardprocessbackendfactory.h"
+#include "processfrontend.h"
+#include "process.h"
+
+QT_USE_NAMESPACE_PROCESSMANAGER
+
+Q_DECLARE_METATYPE(QProcess::ExitStatus);
+Q_DECLARE_METATYPE(QProcess::ProcessState);
+Q_DECLARE_METATYPE(QProcess::ProcessError);
+
+// QML_DECLARE_TYPE(ProcessBackendFactory)
+// QML_DECLARE_TYPE(StandardProcessBackendFactory)
+
+class tst_DeclarativeProcessManager : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+
+ void basic();
+};
+
+
+void tst_DeclarativeProcessManager::initTestCase()
+{
+ qDebug() << "Registering types";
+ const char *uri = "Test";
+ qmlRegisterType<ProcessBackendFactory>();
+ qmlRegisterType<StandardProcessBackendFactory>(uri, 1, 0, "StandardProcessBackendFactory");
+ qmlRegisterType<ProcessFrontend>();
+ qmlRegisterType<DeclarativeProcessManager>(uri, 1, 0, "DeclarativeProcessManager");
+ qmlRegisterUncreatableType<Process>(uri, 1, 0, "Process", "Don't try to make this");
+
+ qRegisterMetaType<QProcess::ProcessState>();
+ qRegisterMetaType<QProcess::ExitStatus>();
+ qRegisterMetaType<QProcess::ProcessError>();
+}
+
+
+class Spy {
+public:
+ Spy(ProcessFrontend *process)
+ : stateSpy(process, SIGNAL(stateChanged(QProcess::ProcessState)))
+ , startSpy(process, SIGNAL(started()))
+ , errorSpy(process, SIGNAL(error(QProcess::ProcessError)))
+ , finishedSpy(process, SIGNAL(finished(int, QProcess::ExitStatus))) {}
+
+ void check( int startCount, int errorCount, int finishedCount, int stateCount ) {
+ QVERIFY(startSpy.count() == startCount);
+ QVERIFY(errorSpy.count() == errorCount);
+ QVERIFY(finishedSpy.count() == finishedCount);
+ QVERIFY(stateSpy.count() == stateCount);
+ bool failedToStart = false;
+ for (int i = 0 ; i < errorSpy.count() ; i++)
+ if (qVariantValue<QProcess::ProcessError>(errorSpy.at(i).at(0)) == QProcess::FailedToStart)
+ failedToStart = true;
+
+ if (failedToStart)
+ QVERIFY(stateCount <=2);
+ if (stateCount > 0)
+ QCOMPARE(qVariantValue<QProcess::ProcessState>(stateSpy.at(0).at(0)), QProcess::Starting);
+ if (stateCount > 1)
+ QCOMPARE(qVariantValue<QProcess::ProcessState>(stateSpy.at(1).at(0)),
+ (failedToStart ? QProcess::NotRunning : QProcess::Running));
+ if (stateCount > 2)
+ QCOMPARE(qVariantValue<QProcess::ProcessState>(stateSpy.at(2).at(0)), QProcess::NotRunning);
+ }
+
+ void waitStart(int timeout=5000) {
+ stopWatch.restart();
+ forever {
+ if (startSpy.count())
+ break;
+ QTestEventLoop::instance().enterLoop(1);
+ if (stopWatch.elapsed() >= timeout)
+ QFAIL("Timed out");
+ }
+ }
+
+ void waitFailedStart(int timeout=5000) {
+ stopWatch.restart();
+ forever {
+ QTestEventLoop::instance().enterLoop(1);
+ if (stopWatch.elapsed() >= timeout)
+ QFAIL("Timed out");
+ if (errorSpy.count())
+ break;
+ }
+ }
+
+ void waitFinished(int timeout=5000) {
+ stopWatch.restart();
+ forever {
+ QTestEventLoop::instance().enterLoop(1);
+ if (stopWatch.elapsed() >= timeout)
+ QFAIL("Timed out");
+ if (finishedSpy.count())
+ break;
+ }
+ }
+
+ void checkExitCode(int exitCode) {
+ QVERIFY(finishedSpy.count() == 1);
+ QCOMPARE(qVariantValue<int>(finishedSpy.at(0).at(0)), exitCode);
+ }
+
+ void checkExitStatus(QProcess::ExitStatus exitStatus) {
+ QVERIFY(finishedSpy.count() == 1);
+ QCOMPARE(qVariantValue<QProcess::ExitStatus>(finishedSpy.at(0).at(1)), exitStatus);
+ }
+
+ void checkErrors(const QList<QProcess::ProcessError>& list) {
+ QCOMPARE(errorSpy.count(), list.count());
+ for (int i = 0 ; i < errorSpy.count() ; i++)
+ QCOMPARE(qVariantValue<QProcess::ProcessError>(errorSpy.at(i).at(0)), list.at(i));
+ }
+
+ QTime stopWatch;
+ QSignalSpy stateSpy;
+ QSignalSpy startSpy;
+ QSignalSpy errorSpy;
+ QSignalSpy finishedSpy;
+};
+
+void tst_DeclarativeProcessManager::basic()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl::fromLocalFile("data/testfrontend.qml"));
+ if (component.isError())
+ qWarning() << component.errors();
+ DeclarativeProcessManager *manager = qobject_cast<DeclarativeProcessManager*>(component.create());
+ QVERIFY(manager != NULL);
+
+ QVariant name;
+ QVERIFY(QMetaObject::invokeMethod(manager, "makeProcess", Q_RETURN_ARG(QVariant, name)));
+ ProcessFrontend *frontend = manager->processForName(name.toString());
+ QVERIFY(frontend);
+ qDebug() << "Internal frontend object" << frontend;
+
+ Spy spy(frontend);
+ QVERIFY(QMetaObject::invokeMethod(manager, "startProcess", Q_ARG(QVariant, name)));
+ spy.waitStart();
+ return;
+
+ QVERIFY(QMetaObject::invokeMethod(manager, "stopProcess", Q_ARG(QVariant, name)));
+ spy.waitFinished();
+ spy.check(1, 1, 1, 3);
+ spy.checkExitCode(0);
+ spy.checkExitStatus(QProcess::CrashExit);
+ spy.checkErrors(QList<QProcess::ProcessError>() << QProcess::Crashed);
+}
+
+
+QTEST_MAIN(tst_DeclarativeProcessManager)
+
+#include "tst_declarative.moc"
diff --git a/tests/auto/processmanager/.gitignore b/tests/auto/processmanager/.gitignore
new file mode 100644
index 0000000..d2adfd1
--- /dev/null
+++ b/tests/auto/processmanager/.gitignore
@@ -0,0 +1,2 @@
+tst_processmanager
+*.moc
diff --git a/tests/auto/processmanager/data/testfrontend.qml b/tests/auto/processmanager/data/testfrontend.qml
new file mode 100644
index 0000000..ecf73c6
--- /dev/null
+++ b/tests/auto/processmanager/data/testfrontend.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+import Test 1.0
+
+TestManager {
+ id: foo
+ magic: "fuzzy"
+
+ function makeProcess() {
+ var a = create({"program": "testClient/testClient","identifier": "a"});
+ console.log("Type="+typeof(a));
+ var p = processForIdentifier("a");
+ console.log("Process: "+p);
+ p.onStarted.connect(foo.itStarted);
+ }
+
+ function itStarted() {
+ console.log("It started");
+ }
+}
diff --git a/tests/auto/processmanager/processmanager.pri b/tests/auto/processmanager/processmanager.pri
new file mode 100644
index 0000000..fb3dc7a
--- /dev/null
+++ b/tests/auto/processmanager/processmanager.pri
@@ -0,0 +1 @@
+TESTCASE_NAME = tst_processmanager
diff --git a/tests/auto/processmanager/processmanager.pro b/tests/auto/processmanager/processmanager.pro
new file mode 100644
index 0000000..864fbf9
--- /dev/null
+++ b/tests/auto/processmanager/processmanager.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS = testClient testPrelaunch testPipeLauncher testSocketLauncher test
diff --git a/tests/auto/processmanager/test/test.pro b/tests/auto/processmanager/test/test.pro
new file mode 100644
index 0000000..0f2cb6e
--- /dev/null
+++ b/tests/auto/processmanager/test/test.pro
@@ -0,0 +1,19 @@
+CONFIG += testcase
+macx:CONFIG -= app_bundle
+
+QT += core network declarative testlib
+QT -= gui
+
+LIBS += -L../../../../src/core
+
+include(../processmanager.pri)
+include(../../../../src/launcher/launcher.pri)
+
+SOURCES = ../tst_processmanager.cpp
+TARGET = ../$$TESTCASE_NAME
+
+OTHER_FILES +=
+
+testDataFiles.files = data
+testDataFiles.path = .
+DEPLOYMENT += testDatafiles
diff --git a/tests/auto/processmanager/testClient/.gitignore b/tests/auto/processmanager/testClient/.gitignore
new file mode 100644
index 0000000..9640c79
--- /dev/null
+++ b/tests/auto/processmanager/testClient/.gitignore
@@ -0,0 +1 @@
+testClient
diff --git a/tests/auto/processmanager/testClient/main.cpp b/tests/auto/processmanager/testClient/main.cpp
new file mode 100644
index 0000000..d61b1ad
--- /dev/null
+++ b/tests/auto/processmanager/testClient/main.cpp
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <string.h>
+
+const int kBufSize = 100;
+
+ssize_t writeline(char *buffer, int len)
+{
+ char *b = buffer;
+ while ( len > 0 ) {
+ ssize_t r = write(STDOUT_FILENO, b, len);
+ if (r < 0)
+ return r;
+ b += r;
+ len -= r;
+ }
+ return 0;
+}
+
+ssize_t readline(char *buffer, int max_len)
+{
+ int len = 0;
+ char c = 0;
+ while (len < max_len && c != '\r' && c != '\n') {
+ ssize_t count = read(STDIN_FILENO, &c, 1);
+ if (count <= 0)
+ return count;
+ *buffer++ = c;
+ len++;
+ }
+ *buffer = 0;
+ return len;
+}
+
+int
+main(int argc, char **argv)
+{
+ char buffer[kBufSize+1];
+
+ while (1) {
+ ssize_t count = readline(buffer, kBufSize);
+ if (count < 0)
+ return 1;
+ if (count == 0)
+ return 0;
+
+ if (strncmp("stop", buffer, 4) == 0)
+ return 0;
+ if (strncmp("crash", buffer, 5) == 0)
+ return 2;
+
+ ssize_t result = writeline(buffer, count);
+ if (result < 0)
+ return 2;
+ }
+}
diff --git a/tests/auto/processmanager/testClient/testClient.pro b/tests/auto/processmanager/testClient/testClient.pro
new file mode 100644
index 0000000..27abe70
--- /dev/null
+++ b/tests/auto/processmanager/testClient/testClient.pro
@@ -0,0 +1,11 @@
+CONFIG -= app_bundle
+include(../processmanager.pri)
+
+LIBS += -L../../../../src/core
+
+DESTDIR = ./
+SOURCES = main.cpp
+TARGET = testClient
+
+target.path = $$[QT_INSTALL_TESTS]/$$TESTCASE_NAME/testClient
+INSTALLS += target
diff --git a/tests/auto/processmanager/testPipeLauncher/.gitignore b/tests/auto/processmanager/testPipeLauncher/.gitignore
new file mode 100644
index 0000000..74e89f1
--- /dev/null
+++ b/tests/auto/processmanager/testPipeLauncher/.gitignore
@@ -0,0 +1 @@
+testPipeLauncher
diff --git a/tests/auto/processmanager/testPipeLauncher/main.cpp b/tests/auto/processmanager/testPipeLauncher/main.cpp
new file mode 100644
index 0000000..44ebccc
--- /dev/null
+++ b/tests/auto/processmanager/testPipeLauncher/main.cpp
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include "pipelauncher.h"
+#include "standardprocessbackendfactory.h"
+
+QT_USE_NAMESPACE_PROCESSMANAGER
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+ PipeLauncher launcher;
+ launcher.addFactory(new StandardProcessBackendFactory);
+ return app.exec();
+}
diff --git a/tests/auto/processmanager/testPipeLauncher/testPipeLauncher.pro b/tests/auto/processmanager/testPipeLauncher/testPipeLauncher.pro
new file mode 100644
index 0000000..ed72ecf
--- /dev/null
+++ b/tests/auto/processmanager/testPipeLauncher/testPipeLauncher.pro
@@ -0,0 +1,12 @@
+CONFIG -= app_bundle
+LIBS += -L../../../../src/core
+
+include(../processmanager.pri)
+include(../../../../src/launcher/launcher.pri)
+
+DESTDIR = ./
+SOURCES += main.cpp
+TARGET = testPipeLauncher
+
+target.path = $$[QT_INSTALL_TESTS]/$$TESTCASE_NAME/testPipeLauncher
+INSTALLS += target
diff --git a/tests/auto/processmanager/testPrelaunch/.gitignore b/tests/auto/processmanager/testPrelaunch/.gitignore
new file mode 100644
index 0000000..d6d4098
--- /dev/null
+++ b/tests/auto/processmanager/testPrelaunch/.gitignore
@@ -0,0 +1 @@
+testPrelaunch
diff --git a/tests/auto/processmanager/testPrelaunch/main.cpp b/tests/auto/processmanager/testPrelaunch/main.cpp
new file mode 100644
index 0000000..08a2279
--- /dev/null
+++ b/tests/auto/processmanager/testPrelaunch/main.cpp
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QSocketNotifier>
+#include <QTimer>
+#include <QDebug>
+#include "qjsondocument.h"
+#include "processinfo.h"
+
+QT_USE_NAMESPACE_PROCESSMANAGER
+
+class Container : public QObject
+{
+ Q_OBJECT
+
+public:
+ Container() : count(0) {
+ notifier = new QSocketNotifier( STDIN_FILENO, QSocketNotifier::Read, this );
+ connect(notifier, SIGNAL(activated(int)), SLOT(dataReady()));
+ notifier->setEnabled(true);
+ }
+
+ void handleMessage(const QVariantMap& map) {
+ if (!count) {
+ ProcessInfo info(map);
+ qDebug() << "Received process info" << info.toMap();
+ }
+ else {
+ QString cmd = map.value("command").toString();
+ qDebug() << "Received command" << cmd;
+ if (cmd == "stop") {
+ qDebug() << "Stopping";
+ exit(0);
+ }
+ }
+ count++;
+ }
+
+public slots:
+ void dataReady() {
+ qDebug() << Q_FUNC_INFO;
+ notifier->setEnabled(false);
+ const int bufsize = 1024;
+ uint oldSize = buffer.size();
+ buffer.resize(oldSize + bufsize);
+ int n = ::read( STDIN_FILENO, buffer.data()+oldSize, bufsize);
+ if (n > 0)
+ buffer.resize(oldSize+n);
+ else
+ buffer.resize(oldSize);
+ // Could check for an error here
+ // Check for a complete JSON object
+ while (buffer.size() >= 12) {
+ qint32 message_size = ((qint32 *)buffer.data())[2] + 8; // Should use 'sizeof(Header)'
+ if (buffer.size() < message_size)
+ break;
+ QByteArray msg = buffer.left(message_size);
+ buffer = buffer.mid(message_size);
+ handleMessage(QJsonDocument::fromBinaryData(msg).toVariant().toMap());
+ }
+ notifier->setEnabled(true);
+ }
+
+private:
+ QSocketNotifier *notifier;
+ QByteArray buffer;
+ int count;
+};
+
+int
+main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+ Container c;
+ qDebug() << "testPrelaunch running";
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/tests/auto/processmanager/testPrelaunch/testPrelaunch.pro b/tests/auto/processmanager/testPrelaunch/testPrelaunch.pro
new file mode 100644
index 0000000..f9be8ca
--- /dev/null
+++ b/tests/auto/processmanager/testPrelaunch/testPrelaunch.pro
@@ -0,0 +1,12 @@
+CONFIG -= app_bundle
+include(../processmanager.pri)
+include(../../../../src/core/core.pri)
+
+LIBS += -L../../../../src/core
+
+DESTDIR = ./
+SOURCES = main.cpp
+TARGET = testPrelaunch
+
+target.path = $$[QT_INSTALL_TESTS]/$$TESTCASE_NAME/testPrelaunch
+INSTALLS += target
diff --git a/tests/auto/processmanager/testSocketLauncher/.gitignore b/tests/auto/processmanager/testSocketLauncher/.gitignore
new file mode 100644
index 0000000..9064b8c
--- /dev/null
+++ b/tests/auto/processmanager/testSocketLauncher/.gitignore
@@ -0,0 +1 @@
+testSocketLauncher
diff --git a/tests/auto/processmanager/testSocketLauncher/main.cpp b/tests/auto/processmanager/testSocketLauncher/main.cpp
new file mode 100644
index 0000000..33b1bab
--- /dev/null
+++ b/tests/auto/processmanager/testSocketLauncher/main.cpp
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include "socketlauncher.h"
+#include "standardprocessbackendfactory.h"
+
+QT_USE_NAMESPACE_PROCESSMANAGER
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+ SocketLauncher launcher;
+ launcher.addFactory(new StandardProcessBackendFactory);
+ launcher.listen("/tmp/socketlauncher");
+ return app.exec();
+}
diff --git a/tests/auto/processmanager/testSocketLauncher/testSocketLauncher.pro b/tests/auto/processmanager/testSocketLauncher/testSocketLauncher.pro
new file mode 100644
index 0000000..d971606
--- /dev/null
+++ b/tests/auto/processmanager/testSocketLauncher/testSocketLauncher.pro
@@ -0,0 +1,12 @@
+CONFIG -= app_bundle
+LIBS += -L../../../../src/core
+
+include(../processmanager.pri)
+include(../../../../src/launcher/launcher.pri)
+
+DESTDIR = ./
+SOURCES += main.cpp
+TARGET = testSocketLauncher
+
+target.path = $$[QT_INSTALL_TESTS]/$$TESTCASE_NAME/testSocketLauncher
+INSTALLS += target
diff --git a/tests/auto/processmanager/tst_processmanager.cpp b/tests/auto/processmanager/tst_processmanager.cpp
new file mode 100644
index 0000000..1f440ff
--- /dev/null
+++ b/tests/auto/processmanager/tst_processmanager.cpp
@@ -0,0 +1,854 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used 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. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest>
+#include <QtCore/QMetaType>
+#include <QFileInfo>
+#include <QDeclarativeEngine>
+#include <QDeclarativeComponent>
+#include <QDeclarativeProperty>
+
+#include "process.h"
+#include "processbackendmanager.h"
+#include "processmanager.h"
+#include "processinfo.h"
+#include "prelaunchprocessbackendfactory.h"
+#include "standardprocessbackendfactory.h"
+#include "processbackend.h"
+#include "processfrontend.h"
+#include "qjsondocument.h"
+#include "pipeprocessbackendfactory.h"
+#include "socketprocessbackendfactory.h"
+
+QT_USE_NAMESPACE_PROCESSMANAGER
+
+Q_DECLARE_METATYPE(QProcess::ExitStatus);
+Q_DECLARE_METATYPE(QProcess::ProcessState);
+Q_DECLARE_METATYPE(QProcess::ProcessError);
+
+class tst_ProcessManager : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+
+ void startAndKill();
+ void failToStart();
+ void startAndStop();
+ void startAndCrash();
+ void echo();
+ void priorityChangeBeforeStart();
+ void priorityChangeAfterStart();
+ void prelaunch();
+ void prelaunchRestricted();
+ void pipeLauncher();
+ void pipeLauncherCrash();
+ void socketLauncher();
+ void socketLauncherCrash();
+ void frontend();
+ void subclassFrontend();
+};
+
+const char *exitStatusToString[] = {
+ "NormalExit",
+ "CrashExit"
+};
+
+const char *stateToString[] = {
+ "NotRunning",
+ "Starting",
+ "Running"
+};
+
+const char *errorToString[] = {
+ "FailedToStart",
+ "Crashed",
+ "Timedout",
+ "WriteError",
+ "ReadError",
+ "UnknownError"
+};
+
+class Spy {
+public:
+ Spy(ProcessBackend *process)
+ : stateSpy(process, SIGNAL(stateChanged(QProcess::ProcessState)))
+ , startSpy(process, SIGNAL(started()))
+ , errorSpy(process, SIGNAL(error(QProcess::ProcessError)))
+ , finishedSpy(process, SIGNAL(finished(int, QProcess::ExitStatus)))
+ , stdoutSpy(process, SIGNAL(standardOutput(const QByteArray&)))
+ , stderrSpy(process, SIGNAL(standardError(const QByteArray&))) {}
+
+ Spy(ProcessFrontend *process)
+ : stateSpy(process, SIGNAL(stateChanged(QProcess::ProcessState)))
+ , startSpy(process, SIGNAL(started()))
+ , errorSpy(process, SIGNAL(error(QProcess::ProcessError)))
+ , finishedSpy(process, SIGNAL(finished(int, QProcess::ExitStatus)))
+ , stdoutSpy(process, SIGNAL(standardOutput(const QByteArray&)))
+ , stderrSpy(process, SIGNAL(standardError(const QByteArray&))) {}
+
+ void check( int startCount, int errorCount, int finishedCount, int stateCount ) {
+ QVERIFY(startSpy.count() == startCount);
+ QVERIFY(errorSpy.count() == errorCount);
+ QVERIFY(finishedSpy.count() == finishedCount);
+ QVERIFY(stateSpy.count() == stateCount);
+ bool failedToStart = false;
+ for (int i = 0 ; i < errorSpy.count() ; i++)
+ if (qVariantValue<QProcess::ProcessError>(errorSpy.at(i).at(0)) == QProcess::FailedToStart)
+ failedToStart = true;
+
+ if (failedToStart)
+ QVERIFY(stateCount <=2);
+ if (stateCount > 0)
+ QCOMPARE(qVariantValue<QProcess::ProcessState>(stateSpy.at(0).at(0)), QProcess::Starting);
+ if (stateCount > 1)
+ QCOMPARE(qVariantValue<QProcess::ProcessState>(stateSpy.at(1).at(0)),
+ (failedToStart ? QProcess::NotRunning : QProcess::Running));
+ if (stateCount > 2)
+ QCOMPARE(qVariantValue<QProcess::ProcessState>(stateSpy.at(2).at(0)), QProcess::NotRunning);
+ }
+
+ void checkStdout(const QByteArray s) {
+ qDebug() << "Checking stdout for" << s;
+ for (int i = 0 ; i < stdoutSpy.count() ; i++) {
+ QByteArray b = stdoutSpy.at(i).at(0).toByteArray();
+ if (b == s)
+ return;
+ }
+ QFAIL("String not found");
+ }
+
+ void waitStart(int timeout=5000) {
+ stopWatch.restart();
+ forever {
+ QTestEventLoop::instance().enterLoop(1);
+ if (stopWatch.elapsed() >= timeout)
+ QFAIL("Timed out");
+ if (startSpy.count())
+ break;
+ }
+ }
+
+ void waitFailedStart(int timeout=5000) {
+ stopWatch.restart();
+ forever {
+ QTestEventLoop::instance().enterLoop(1);
+ if (stopWatch.elapsed() >= timeout)
+ QFAIL("Timed out");
+ if (errorSpy.count())
+ break;
+ }
+ }
+
+ void waitFinished(int timeout=5000) {
+ stopWatch.restart();
+ forever {
+ QTestEventLoop::instance().enterLoop(1);
+ if (stopWatch.elapsed() >= timeout)
+ QFAIL("Timed out");
+ if (finishedSpy.count())
+ break;
+ }
+ }
+
+ void waitStdout(int timeout=5000) {
+ stopWatch.restart();
+ int count = stdoutSpy.count();
+ forever {
+ QTestEventLoop::instance().enterLoop(1);
+ if (stopWatch.elapsed() >= timeout)
+ QFAIL("Timed out");
+ if (stdoutSpy.count() != count) {
+ break;
+ }
+ }
+ }
+
+ void checkExitCode(int exitCode) {
+ QVERIFY(finishedSpy.count() == 1);
+ QCOMPARE(qVariantValue<int>(finishedSpy.at(0).at(0)), exitCode);
+ }
+
+ void checkExitStatus(QProcess::ExitStatus exitStatus) {
+ QVERIFY(finishedSpy.count() == 1);
+ QCOMPARE(qVariantValue<QProcess::ExitStatus>(finishedSpy.at(0).at(1)), exitStatus);
+ }
+
+ void checkErrors(const QList<QProcess::ProcessError>& list) {
+ QCOMPARE(errorSpy.count(), list.count());
+ for (int i = 0 ; i < errorSpy.count() ; i++)
+ QCOMPARE(qVariantValue<QProcess::ProcessError>(errorSpy.at(i).at(0)), list.at(i));
+ }
+
+ void dump() {
+ qDebug() << "================================ SPY DUMP ==============================";
+ qDebug() << "Start count=" << startSpy.count();
+ qDebug() << "Finished count=" << finishedSpy.count();
+ for (int i = 0 ; i < finishedSpy.count() ; i++) {
+ qDebug() << "....(" << qvariant_cast<int>(finishedSpy.at(i).at(0))
+ << ")" << exitStatusToString[qvariant_cast<QProcess::ExitStatus>(finishedSpy.at(i).at(0))];
+ }
+ qDebug() << "State count=" << stateSpy.count();
+ for (int i = 0 ; i < stateSpy.count() ; i++) {
+ qDebug() << "...." << stateToString[qvariant_cast<QProcess::ProcessState>(stateSpy.at(i).at(0))];
+ }
+ qDebug() << "Error count=" << errorSpy.count();
+ for (int i = 0 ; i < errorSpy.count() ; i++) {
+ qDebug() << "...." << errorToString[qvariant_cast<QProcess::ProcessError>(errorSpy.at(i).at(0))];
+ }
+ qDebug() << "================================ ======== ==============================";
+ }
+
+ QTime stopWatch;
+ QSignalSpy stateSpy;
+ QSignalSpy startSpy;
+ QSignalSpy errorSpy;
+ QSignalSpy finishedSpy;
+ QSignalSpy stdoutSpy;
+ QSignalSpy stderrSpy;
+};
+
+bool canCheckProcessState()
+{
+ QFileInfo finfo("/bin/ps");
+ return finfo.exists();
+}
+
+bool isProcessRunning(Q_PID pid)
+{
+ QProcess p;
+ p.start("ps", QStringList() << "-o" << "pid=" << "-p" << QString::number(pid));
+ if (p.waitForStarted() && p.waitForFinished())
+ return p.readAll().split('\n').at(0).toDouble() == pid;
+
+ return false;
+}
+
+bool isProcessStopped(Q_PID pid)
+{
+ QProcess p;
+ p.start("/bin/ps", QStringList() << "-o" << "pid=" << "-p" << QString::number(pid));
+ if (p.waitForStarted() && p.waitForFinished()) {
+ QList<QByteArray> plist = p.readAll().split('\n');
+ return plist.size() == 1 && !plist.at(0).size();
+ }
+ return false;
+}
+
+/*********/
+
+void tst_ProcessManager::initTestCase()
+{
+ qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus");
+ qRegisterMetaType<QProcess::ProcessState>("QProcess::ProcessState");
+ qRegisterMetaType<QProcess::ProcessState>("QProcess::ProcessError");
+}
+
+void tst_ProcessManager::startAndKill()
+{
+ QString socketname = "/tmp/tst_socket";
+ ProcessBackendManager *manager = new ProcessBackendManager;
+ manager->addFactory(new StandardProcessBackendFactory);
+
+ ProcessInfo info;
+ info.setValue("program", "testClient/testClient");
+ ProcessBackend *process = manager->create(info);
+ QVERIFY(process);
+
+ Spy spy(process);
+ process->start();
+ spy.waitStart();
+ process->stop();
+ spy.waitFinished();
+ spy.check(1, 1, 1, 3);
+ spy.checkExitCode(0);
+ spy.checkExitStatus(QProcess::CrashExit);
+ spy.checkErrors(QList<QProcess::ProcessError>() << QProcess::Crashed);
+
+ QVERIFY(process->parent() == NULL);
+ delete process;
+ delete manager;
+}
+
+
+void tst_ProcessManager::failToStart()
+{
+ QString socketname = "/tmp/tst_socket";
+ ProcessBackendManager *manager = new ProcessBackendManager;
+ manager->addFactory(new StandardProcessBackendFactory);
+
+ ProcessInfo info;
+ info.setValue("program", "thisProgramDoesntExist");
+ ProcessBackend *process = manager->create(info);
+ QVERIFY(process);
+
+ Spy spy(process);
+ process->start();
+ spy.waitFailedStart();
+ spy.check(0,1,0,2);
+
+ QVERIFY(process->parent() == NULL);
+ delete process;
+ delete manager;
+}
+
+
+void tst_ProcessManager::startAndStop()
+{
+ QString socketname = "/tmp/tst_socket";
+ ProcessBackendManager *manager = new ProcessBackendManager;
+ manager->addFactory(new StandardProcessBackendFactory);
+
+ ProcessInfo info;
+ info.setValue("program", "testClient/testClient");
+ ProcessBackend *process = manager->create(info);
+ QVERIFY(process);
+
+ Spy spy(process);
+ process->start();
+ spy.waitStart();
+ spy.check(1,0,0,2);
+
+ process->write("echo\n");
+
+ // Now send a "stop" message
+ process->write("stop\n");
+ spy.waitFinished();
+ spy.check(1,0,1,3);
+ spy.checkExitCode(0);
+ spy.checkExitStatus(QProcess::NormalExit);
+
+ QVERIFY(process->parent() == NULL);
+ delete process;
+ delete manager;
+}
+
+void tst_ProcessManager::startAndCrash()
+{
+ QString socketname = "/tmp/tst_socket";
+ ProcessBackendManager *manager = new ProcessBackendManager;
+ manager->addFactory(new StandardProcessBackendFactory);
+
+ ProcessInfo info;
+ info.setValue("program", "testClient/testClient");
+ ProcessBackend *process = manager->create(info);
+ QVERIFY(process);
+
+ Spy spy(process);
+ process->start();
+ spy.waitStart();
+ spy.check(1,0,0,2);
+
+ process->write("crash\n");
+ spy.waitFinished();
+ spy.check(1,0,1,3);
+ spy.checkExitCode(2);
+ spy.checkExitStatus(QProcess::NormalExit);
+
+ QVERIFY(process->parent() == NULL);
+ delete process;
+ delete manager;
+}
+
+void tst_ProcessManager::echo()
+{
+ QString socketname = "/tmp/tst_socket";
+ ProcessBackendManager *manager = new ProcessBackendManager;
+ manager->addFactory(new StandardProcessBackendFactory);
+
+ ProcessInfo info;
+ info.setValue("program", "testClient/testClient");
+ ProcessBackend *process = manager->create(info);
+ QVERIFY(process);
+
+ Spy spy(process);
+ process->start();
+ spy.waitStart();
+
+ process->write("echotest\n");
+ spy.waitStdout();
+ spy.checkStdout("echotest\n");
+
+ process->write("stop\n");
+ spy.waitFinished();
+ spy.check(1,0,1,3);
+ spy.checkExitCode(0);
+ spy.checkExitStatus(QProcess::NormalExit);
+
+ QVERIFY(process->parent() == NULL);
+ delete process;
+ delete manager;
+}
+
+void tst_ProcessManager::priorityChangeBeforeStart()
+{
+ QString socketname = "/tmp/tst_socket";
+ ProcessBackendManager *manager = new ProcessBackendManager;
+ manager->addFactory(new StandardProcessBackendFactory);
+
+ ProcessInfo info;
+ info.setValue("program", "testClient/testClient");
+ info.setValue("priority", 19);
+ ProcessBackend *process = manager->create(info);
+ QVERIFY(process);
+
+ Spy spy(process);
+ process->start();
+ spy.waitStart();
+
+ QVERIFY(process->actualPriority() == 19);
+
+ process->write("stop\n");
+ spy.waitFinished();
+ spy.check(1,0,1,3);
+ spy.checkExitCode(0);
+ spy.checkExitStatus(QProcess::NormalExit);
+
+ QVERIFY(process->parent() == NULL);
+ delete process;
+ delete manager;
+}
+
+void tst_ProcessManager::priorityChangeAfterStart()
+{
+ QString socketname = "/tmp/tst_socket";
+ ProcessBackendManager *manager = new ProcessBackendManager;
+ manager->addFactory(new StandardProcessBackendFactory);
+
+ ProcessInfo info;
+ info.setValue("program", "testClient/testClient");
+ ProcessBackend *process = manager->create(info);
+ QVERIFY(process);
+
+ Spy spy(process);
+ process->start();
+ spy.waitStart();
+
+ process->setDesiredPriority(19);
+ QVERIFY(process->actualPriority() == 19);
+
+ process->write("stop\n");
+ spy.waitFinished();
+ spy.check(1,0,1,3);
+ spy.checkExitCode(0);
+ spy.checkExitStatus(QProcess::NormalExit);
+
+ QVERIFY(process->parent() == NULL);
+ delete process;
+ delete manager;
+}
+
+void tst_ProcessManager::prelaunch()
+{
+ QString socketname = "/tmp/tst_socket";
+ ProcessBackendManager *manager = new ProcessBackendManager;
+ ProcessInfo info;
+ info.setValue("program", "testPrelaunch/testPrelaunch");
+ manager->addFactory(new PrelaunchProcessBackendFactory(info));
+
+ // The factory should not have launched a prelaunch yet
+ QVERIFY(manager->memoryRestricted() == false);
+ QVERIFY(manager->internalProcesses().count() == 0);
+
+ qDebug() << "Waiting for 2 seconds";
+ QTime waitTime;
+ waitTime.start();
+ while (waitTime.elapsed() < 2000)
+ QTestEventLoop::instance().enterLoop(1);
+
+ // Verify that there is a prelaunched process
+ QVERIFY(manager->memoryRestricted() == false);
+ QVERIFY(manager->internalProcesses().count() == 1);
+
+ info.setValue("prelaunch", "true");
+ ProcessBackend *process = manager->create(info);
+ QVERIFY(process);
+ QVERIFY(process->state() == QProcess::NotRunning);
+
+ Spy spy(process);
+ process->start();
+ spy.waitStart();
+ spy.check(1,0,0,2);
+
+ QVERIFY(process->state() == QProcess::Running);
+
+ QVariantMap map;
+ map.insert("command", "stop");
+ process->write(QJsonDocument::fromVariant(map).toBinaryData());
+ spy.waitFinished();
+ spy.check(1,0,1,3);
+ spy.checkExitCode(0);
+ spy.checkExitStatus(QProcess::NormalExit);
+
+ QVERIFY(process->parent() == NULL);
+ delete process;
+ delete manager;
+}
+
+void tst_ProcessManager::prelaunchRestricted()
+{
+ QString socketname = "/tmp/tst_socket";
+ ProcessBackendManager *manager = new ProcessBackendManager;
+ manager->setMemoryRestricted(true);
+
+ ProcessInfo info;
+ info.setValue("program", "testPrelaunch/testPrelaunch");
+ manager->addFactory(new PrelaunchProcessBackendFactory(info));
+
+ // The factory should not have launched a prelaunch yet
+ QVERIFY(manager->memoryRestricted() == true);
+ QVERIFY(manager->internalProcesses().count() == 0);
+
+ qDebug() << "Waiting for 2 seconds";
+ QTime waitTime;
+ waitTime.start();
+ while (waitTime.elapsed() < 2000)
+ QTestEventLoop::instance().enterLoop(1);
+
+ // The factory should still not have prelaunched anything
+ QVERIFY(manager->memoryRestricted() == true);
+ QVERIFY(manager->internalProcesses().count() == 0);
+
+ info.setValue("prelaunch", "true");
+ ProcessBackend *process = manager->create(info);
+ QVERIFY(process);
+
+ Spy spy(process);
+ process->start();
+ spy.waitStart();
+ spy.check(1,0,0,2);
+
+ QVariantMap map;
+ map.insert("command", "stop");
+ process->write(QJsonDocument::fromVariant(map).toBinaryData());
+ spy.waitFinished();
+ spy.check(1,0,1,3);
+ spy.checkExitCode(0);
+ spy.checkExitStatus(QProcess::NormalExit);
+
+ QVERIFY(process->parent() == NULL);
+ delete process;
+ delete manager;
+}
+
+void tst_ProcessManager::pipeLauncher()
+{
+ ProcessBackendManager *manager = new ProcessBackendManager;
+ ProcessInfo info;
+ info.setValue("program", "testPipeLauncher/testPipeLauncher");
+ manager->addFactory(new PipeProcessBackendFactory(info, "testClient"));
+
+ qDebug() << "Waiting for 500 ms let pipe start";
+ QTime waitTime;
+ waitTime.start();
+ while (waitTime.elapsed() < 500)
+ QTestEventLoop::instance().enterLoop(1);
+
+ // The factory should have launched a pipe by now
+ QVERIFY(manager->internalProcesses().count() == 1);
+
+ ProcessInfo info2;
+ info2.setValue("program", "testClient/testClient");
+ info2.setValue("pipe", "true");
+ ProcessBackend *process = manager->create(info2);
+ QVERIFY(process);
+
+ Spy spy(process);
+ process->start();
+ spy.waitStart();
+
+ qDebug() << "Checking post started";
+ spy.check(1,0,0,2);
+
+ qDebug() << "Sending echo command";
+ process->write("echo\n");
+
+ qDebug() << "Sending stop command";
+ process->write("stop\n");
+
+ qDebug() << "Waiting for finished";
+ spy.waitFinished();
+ spy.check(1,0,1,3);
+ spy.checkExitCode(0);
+ spy.checkExitStatus(QProcess::NormalExit);
+
+ QVERIFY(process->parent() == NULL);
+ delete process;
+ delete manager;
+}
+
+
+void tst_ProcessManager::pipeLauncherCrash()
+{
+ QString socketname = "/tmp/tst_socket";
+ ProcessBackendManager *manager = new ProcessBackendManager;
+ ProcessInfo info;
+ info.setValue("program", "testPipeLauncher/testPipeLauncher");
+ manager->addFactory(new PipeProcessBackendFactory(info, "testClient"));
+
+ qDebug() << "Waiting for 500 ms let pipe start";
+ QTime waitTime;
+ waitTime.start();
+ while (waitTime.elapsed() < 500)
+ QTestEventLoop::instance().enterLoop(1);
+
+ // The factory should have launched a pipe by now
+ QVERIFY(manager->internalProcesses().count() == 1);
+
+ ProcessInfo info2;
+ info2.setValue("program", "testClient/testClient");
+ info2.setValue("pipe", "true");
+ ProcessBackend *process = manager->create(info2);
+ QVERIFY(process);
+
+ Spy spy(process);
+ process->start();
+ spy.waitStart();
+
+ qDebug() << "Checking post started";
+ spy.check(1,0,0,2);
+
+ QList<Q_PID> plist = manager->internalProcesses();
+ QCOMPARE(plist.count(), 1);
+
+ if (canCheckProcessState()) {
+ qDebug() << "Verifying that all processes are running";
+ foreach (Q_PID pid, plist)
+ QVERIFY(isProcessRunning(pid));
+ }
+
+ qDebug() << "Deleting manager process";
+ delete manager;
+
+ qDebug() << "Waiting for 1000 ms to let the pipe stop";
+ waitTime.restart();
+ while (waitTime.elapsed() < 1000)
+ QTestEventLoop::instance().enterLoop(1);
+
+ if (canCheckProcessState()) {
+ foreach (Q_PID pid, plist) {
+ qDebug() << "Checking process" << pid;
+ QVERIFY(isProcessStopped(pid));
+ }
+ }
+
+ delete process;
+ qDebug() << "Deleted process";
+}
+
+
+void tst_ProcessManager::socketLauncher()
+{
+ QProcess *remote = new QProcess;
+ remote->setProcessChannelMode(QProcess::ForwardedChannels);
+ remote->start("testSocketLauncher/testSocketLauncher");
+ QVERIFY(remote->waitForStarted());
+
+ qDebug() << "Waiting for 500 ms to let testSocketLauncher start";
+ QTime waitTime;
+ waitTime.start();
+ while (waitTime.elapsed() < 500)
+ QTestEventLoop::instance().enterLoop(1);
+
+ ProcessBackendManager *manager = new ProcessBackendManager;
+ manager->addFactory(new SocketProcessBackendFactory("/tmp/socketlauncher"));
+
+ ProcessInfo info;
+ info.setValue("program", "testClient/testClient");
+ ProcessBackend *process = manager->create(info);
+ QVERIFY(process);
+
+ Spy spy(process);
+ process->start();
+ spy.waitStart();
+
+ qDebug() << "Checking post started";
+ spy.check(1,0,0,2);
+
+ qDebug() << "Sending echo command";
+ process->write("echo\n");
+
+ qDebug() << "Sending stop command";
+ process->write("stop\n");
+
+ qDebug() << "Waiting for finished";
+ spy.waitFinished();
+ spy.check(1,0,1,3);
+ spy.checkExitCode(0);
+ spy.checkExitStatus(QProcess::NormalExit);
+
+ QVERIFY(process->parent() == NULL);
+ delete process;
+ delete manager;
+ delete remote;
+}
+
+void tst_ProcessManager::socketLauncherCrash()
+{
+ QProcess *remote = new QProcess;
+ remote->setProcessChannelMode(QProcess::ForwardedChannels);
+ remote->start("testSocketLauncher/testSocketLauncher");
+ QVERIFY(remote->waitForStarted());
+
+ qDebug() << "Waiting for 500 ms to let testSocketLauncher start";
+ QTime waitTime;
+ waitTime.start();
+ while (waitTime.elapsed() < 500)
+ QTestEventLoop::instance().enterLoop(1);
+
+ ProcessBackendManager *manager = new ProcessBackendManager;
+ manager->addFactory(new SocketProcessBackendFactory("/tmp/socketlauncher"));
+
+ ProcessInfo info;
+ info.setValue("program", "testClient/testClient");
+ ProcessBackend *process = manager->create(info);
+ QVERIFY(process);
+
+ Spy spy(process);
+ process->start();
+ spy.waitStart();
+ spy.check(1,0,0,2);
+
+ process->write("crash\n");
+ spy.waitFinished();
+ spy.check(1,0,1,3);
+ spy.checkExitCode(2);
+ spy.checkExitStatus(QProcess::NormalExit);
+
+ QVERIFY(process->parent() == NULL);
+ delete process;
+ delete manager;
+ delete remote;
+}
+
+
+void tst_ProcessManager::frontend()
+{
+ QString socketname = "/tmp/tst_socket";
+ ProcessManager *manager = new ProcessManager;
+ manager->addBackendFactory(new StandardProcessBackendFactory);
+
+ ProcessInfo info;
+ info.setValue("program", "testClient/testClient");
+ ProcessFrontend *process = manager->create(info);
+ QVERIFY(process);
+
+ Spy spy(process);
+ process->start();
+ spy.waitStart();
+ spy.check(1,0,0,2);
+
+ // Now send a "stop" message
+ process->write("stop\n");
+ spy.waitFinished();
+ spy.check(1,0,1,3);
+ spy.checkExitCode(0);
+ spy.checkExitStatus(QProcess::NormalExit);
+
+ QCOMPARE(manager->size(), 1);
+ delete process;
+ QCOMPARE(manager->size(), 0);
+ delete manager;
+}
+
+
+class TestProcess : public ProcessFrontend {
+ Q_OBJECT
+ Q_PROPERTY(QString magic READ magic WRITE setMagic NOTIFY magicChanged)
+public:
+ TestProcess(ProcessBackend *backend, QObject *parent=0) : ProcessFrontend(backend, parent) {}
+
+ QString magic() const { return m_magic; }
+ void setMagic(const QString&s) { if (m_magic != s) { m_magic=s; emit magicChanged(); }}
+signals:
+ void magicChanged();
+private:
+ QString m_magic;
+};
+
+class TestManager : public ProcessManager {
+ Q_OBJECT
+ Q_PROPERTY(QString magic READ magic WRITE setMagic NOTIFY magicChanged)
+public:
+ TestManager(QObject *parent=0) : ProcessManager(parent) {}
+ virtual Q_INVOKABLE TestProcess *createFrontend(ProcessBackend *backend) {return new TestProcess(backend);}
+ QString magic() const { return m_magic; }
+ void setMagic(const QString&s) { if (m_magic != s) { m_magic=s; emit magicChanged(); }}
+signals:
+ void magicChanged();
+private:
+ QString m_magic;
+};
+
+void tst_ProcessManager::subclassFrontend()
+{
+ QString socketname = "/tmp/tst_socket";
+ TestManager *manager = new TestManager;
+ manager->addBackendFactory(new StandardProcessBackendFactory);
+
+ ProcessInfo info;
+ info.setValue("program", "testClient/testClient");
+ ProcessFrontend *process = manager->create(info);
+ QVERIFY(process);
+
+ QVERIFY(process->setProperty("magic", 42));
+ QCOMPARE(process->property("magic").toDouble(), 42.0);
+
+ Spy spy(process);
+ process->start();
+ spy.waitStart();
+ spy.check(1,0,0,2);
+
+ // Now send a "stop" message
+ process->write("stop\n");
+ spy.waitFinished();
+ spy.check(1,0,1,3);
+ spy.checkExitCode(0);
+ spy.checkExitStatus(QProcess::NormalExit);
+
+ QCOMPARE(manager->size(), 1);
+ delete process;
+ QCOMPARE(manager->size(), 0);
+ delete manager;
+}
+
+QTEST_MAIN(tst_ProcessManager)
+
+#include "tst_processmanager.moc"
diff --git a/tests/tests.pro b/tests/tests.pro
new file mode 100644
index 0000000..7fbc8a9
--- /dev/null
+++ b/tests/tests.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = auto