From 1d85d8e706cd2f0af3731d71781caaa8d528dc68 Mon Sep 17 00:00:00 2001
From: Christian Kandeler <christian.kandeler@nokia.com>
Date: Thu, 26 Jul 2012 09:02:34 +0200
Subject: [PATCH] ProjectExplorer: Introduce generic application runner.

This class aims to be a flexible worker class for SSH-based
run controls. It supersedes AbstractRemoteLinuxApplicationRunner
as well as all of its derived classes, while having no
RemoteLinux dependencies itself.

Change-Id: If24f03a32126b36fc3d0b253a1615ad0af5f2b46
Reviewed-by: hjk <qthjk@ovi.com>
---
 src/plugins/madde/madde.pro                   |  12 +-
 src/plugins/madde/madde.qbs                   |  10 +-
 .../maemoapplicationrunnerhelperactions.cpp   | 148 +++++
 ... => maemoapplicationrunnerhelperactions.h} |  62 ++-
 src/plugins/madde/maemodebugsupport.cpp       |  54 --
 src/plugins/madde/maemodebugsupport.h         |  56 --
 src/plugins/madde/maemoremotemounter.h        |   2 +-
 src/plugins/madde/maemorunconfiguration.cpp   |  26 -
 src/plugins/madde/maemorunconfiguration.h     |   2 -
 src/plugins/madde/maemoruncontrol.cpp         |  66 ---
 src/plugins/madde/maemoruncontrol.h           |  64 ---
 src/plugins/madde/maemorunfactories.cpp       |  22 +-
 src/plugins/madde/maemosshrunner.cpp          | 215 --------
 .../devicesupport/deviceapplicationrunner.cpp | 339 ++++++++++++
 .../devicesupport/deviceapplicationrunner.h   | 104 ++++
 .../projectexplorer/projectexplorer.pro       |   6 +-
 .../projectexplorer/projectexplorer.qbs       |   4 +-
 src/plugins/qmlprofiler/qmlprofilerengine.cpp |   2 +
 .../remotelinuxqmlprofilerrunner.cpp          | 125 ++---
 .../remotelinuxqmlprofilerrunner.h            |  29 +-
 src/plugins/qnx/qnx.pro                       |   2 -
 src/plugins/qnx/qnxapplicationrunner.cpp      |  85 ---
 src/plugins/qnx/qnxapplicationrunner.h        |  69 ---
 src/plugins/qnx/qnxdebugsupport.cpp           |  66 ++-
 src/plugins/qnx/qnxdebugsupport.h             |  27 +-
 src/plugins/qnx/qnxruncontrol.cpp             |  17 +-
 src/plugins/qnx/qnxruncontrol.h               |   9 +-
 src/plugins/qnx/qnxutils.cpp                  |   8 +
 src/plugins/qnx/qnxutils.h                    |   1 +
 src/plugins/remotelinux/remotelinux.pro       |   2 -
 src/plugins/remotelinux/remotelinux.qbs       |   2 -
 .../remotelinuxapplicationrunner.cpp          | 508 ------------------
 .../remotelinuxapplicationrunner.h            | 145 -----
 .../remotelinux/remotelinuxdebugsupport.cpp   | 207 ++++---
 .../remotelinux/remotelinuxdebugsupport.h     |  44 +-
 .../remotelinux/remotelinuxruncontrol.cpp     | 121 ++---
 .../remotelinux/remotelinuxruncontrol.h       |  38 +-
 .../remotelinuxruncontrolfactory.cpp          |   6 +-
 src/plugins/remotelinux/remotelinuxutils.cpp  |   9 +-
 src/plugins/remotelinux/remotelinuxutils.h    |   2 +-
 40 files changed, 1013 insertions(+), 1703 deletions(-)
 create mode 100644 src/plugins/madde/maemoapplicationrunnerhelperactions.cpp
 rename src/plugins/madde/{maemosshrunner.h => maemoapplicationrunnerhelperactions.h} (55%)
 delete mode 100644 src/plugins/madde/maemodebugsupport.cpp
 delete mode 100644 src/plugins/madde/maemodebugsupport.h
 delete mode 100644 src/plugins/madde/maemoruncontrol.cpp
 delete mode 100644 src/plugins/madde/maemoruncontrol.h
 delete mode 100644 src/plugins/madde/maemosshrunner.cpp
 create mode 100644 src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.cpp
 create mode 100644 src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.h
 delete mode 100644 src/plugins/qnx/qnxapplicationrunner.cpp
 delete mode 100644 src/plugins/qnx/qnxapplicationrunner.h
 delete mode 100644 src/plugins/remotelinux/remotelinuxapplicationrunner.cpp
 delete mode 100644 src/plugins/remotelinux/remotelinuxapplicationrunner.h

diff --git a/src/plugins/madde/madde.pro b/src/plugins/madde/madde.pro
index f545b98ac9a..178e2f3e4bb 100644
--- a/src/plugins/madde/madde.pro
+++ b/src/plugins/madde/madde.pro
@@ -11,7 +11,6 @@ HEADERS += \
     debianmanager.h \
     maemoconstants.h \
     maemorunconfigurationwidget.h \
-    maemoruncontrol.h \
     maemorunfactories.h \
     maemosettingspages.h \
     maemopackagecreationstep.h \
@@ -20,8 +19,6 @@ HEADERS += \
     maemoqemumanager.h \
     maemodeploystepfactory.h \
     maemoglobal.h \
-    maemosshrunner.h \
-    maemodebugsupport.h \
     maemoremotemountsmodel.h \
     maemomountspecification.h \
     maemoremotemounter.h \
@@ -52,13 +49,13 @@ HEADERS += \
     maddedevicetester.h \
     maddedeviceconfigurationfactory.h \
     maddedevice.h \
-    rpmmanager.h
+    rpmmanager.h \
+    maemoapplicationrunnerhelperactions.h
 
 SOURCES += \
     maddeplugin.cpp \
     debianmanager.cpp \
     maemorunconfigurationwidget.cpp \
-    maemoruncontrol.cpp \
     maemorunfactories.cpp \
     maemosettingspages.cpp \
     maemopackagecreationstep.cpp \
@@ -67,8 +64,6 @@ SOURCES += \
     maemoqemumanager.cpp \
     maemodeploystepfactory.cpp \
     maemoglobal.cpp \
-    maemosshrunner.cpp \
-    maemodebugsupport.cpp \
     maemoremotemountsmodel.cpp \
     maemomountspecification.cpp \
     maemoremotemounter.cpp \
@@ -98,7 +93,8 @@ SOURCES += \
     maddedevicetester.cpp \
     maemorunconfiguration.cpp \
     maddedevice.cpp \
-    rpmmanager.cpp
+    rpmmanager.cpp \
+    maemoapplicationrunnerhelperactions.cpp
 
 FORMS += \
     maemopackagecreationwidget.ui \
diff --git a/src/plugins/madde/madde.qbs b/src/plugins/madde/madde.qbs
index 4bf5ad8c0d8..7cac61e3994 100644
--- a/src/plugins/madde/madde.qbs
+++ b/src/plugins/madde/madde.qbs
@@ -31,8 +31,6 @@ QtcPlugin {
         "maddeuploadandinstallpackagesteps.cpp",
         "maddeuploadandinstallpackagesteps.h",
         "maemoconstants.h",
-        "maemodebugsupport.cpp",
-        "maemodebugsupport.h",
         "maemodeploybymountsteps.cpp",
         "maemodeploybymountsteps.h",
         "maemodeployconfigurationwidget.cpp",
@@ -108,14 +106,10 @@ QtcPlugin {
         "maemorunconfiguration.h",
         "maemorunconfigurationwidget.cpp",
         "maemorunconfigurationwidget.h",
-        "maemoruncontrol.cpp",
-        "maemoruncontrol.h",
         "maemorunfactories.cpp",
         "maemorunfactories.h",
         "maemosettingspages.cpp",
         "maemosettingspages.h",
-        "maemosshrunner.cpp",
-        "maemosshrunner.h",
         "qt-maemo.qrc",
         "qt4maemodeployconfiguration.cpp",
         "qt4maemodeployconfiguration.h",
@@ -124,6 +118,8 @@ QtcPlugin {
         "debianmanager.h",
         "debianmanager.cpp",
         "rpmmanager.h",
-        "rpmmanager.cpp"
+        "rpmmanager.cpp",
+        "maemoapplicationrunnerhelperactions.h",
+        "maemoapplicationrunnerhelperactions.cpp"
     ]
 }
diff --git a/src/plugins/madde/maemoapplicationrunnerhelperactions.cpp b/src/plugins/madde/maemoapplicationrunnerhelperactions.cpp
new file mode 100644
index 00000000000..2f82e7a5453
--- /dev/null
+++ b/src/plugins/madde/maemoapplicationrunnerhelperactions.cpp
@@ -0,0 +1,148 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: http://www.qt-project.org/
+**
+**
+** 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.
+**
+** 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.
+**
+**
+**************************************************************************/
+#include "maemoapplicationrunnerhelperactions.h"
+
+#include "maemomountspecification.h"
+#include "maemoremotemounter.h"
+
+#include <utils/qtcassert.h>
+
+using namespace ProjectExplorer;
+using namespace Utils;
+
+namespace Madde {
+namespace Internal {
+
+MaemoPreRunAction::MaemoPreRunAction(const IDevice::ConstPtr &device, const FileName &maddeRoot,
+        const QList<MaemoMountSpecification> &mountSpecs, QObject *parent)
+    : DeviceApplicationHelperAction(parent), m_mounter(new MaemoRemoteMounter(this))
+{
+    m_mounter->setParameters(device, maddeRoot);
+    foreach (const MaemoMountSpecification &m, mountSpecs)
+        m_mounter->addMountSpecification(m, false);
+}
+
+void MaemoPreRunAction::handleMounted()
+{
+    QTC_ASSERT(m_isRunning, return);
+
+    setFinished(true);
+}
+
+void MaemoPreRunAction::handleError(const QString &message)
+{
+    if (!m_isRunning)
+        return;
+
+    emit reportError(message);
+    setFinished(false);
+}
+
+void MaemoPreRunAction::start()
+{
+    QTC_ASSERT(!m_isRunning, return);
+
+    connect(m_mounter, SIGNAL(debugOutput(QString)), SIGNAL(reportProgress(QString)));
+    connect(m_mounter, SIGNAL(reportProgress(QString)), SIGNAL(reportProgress(QString)));
+    connect(m_mounter, SIGNAL(mounted()), SLOT(handleMounted()));
+    connect(m_mounter, SIGNAL(error(QString)), SLOT(handleError(QString)));
+    m_isRunning = true;
+    m_mounter->mount();
+}
+
+void MaemoPreRunAction::stop()
+{
+    QTC_ASSERT(m_isRunning, return);
+
+    m_mounter->stop();
+    setFinished(false);
+}
+
+void MaemoPreRunAction::setFinished(bool success)
+{
+    QTC_ASSERT(m_isRunning, return);
+
+    m_mounter->disconnect(this);
+    m_isRunning = false;
+    emit finished(success);
+}
+
+MaemoPostRunAction::MaemoPostRunAction(MaemoRemoteMounter *mounter, QObject *parent)
+        : DeviceApplicationHelperAction(parent), m_mounter(mounter)
+{
+}
+
+void MaemoPostRunAction::handleUnmounted()
+{
+    QTC_ASSERT(m_isRunning, return);
+
+    setFinished(true);
+}
+
+void MaemoPostRunAction::handleError(const QString &message)
+{
+    if (!m_isRunning)
+        return;
+
+    emit reportError(message);
+    setFinished(false);
+}
+
+void MaemoPostRunAction::start()
+{
+    QTC_ASSERT(!m_isRunning, return);
+
+    connect(m_mounter, SIGNAL(debugOutput(QString)), SIGNAL(reportProgress(QString)));
+    connect(m_mounter, SIGNAL(reportProgress(QString)), SIGNAL(reportProgress(QString)));
+    connect(m_mounter, SIGNAL(unmounted()), SLOT(handleUnmounted()));
+    connect(m_mounter, SIGNAL(error(QString)), SLOT(handleError(QString)));
+    m_isRunning = true;
+    m_mounter->unmount();
+}
+
+void MaemoPostRunAction::stop()
+{
+    QTC_ASSERT(m_isRunning, return);
+
+    m_mounter->stop();
+    setFinished(false);
+}
+
+void MaemoPostRunAction::setFinished(bool success)
+{
+    QTC_ASSERT(m_isRunning, return);
+
+    m_mounter->disconnect(this);
+    m_isRunning = false;
+    emit finished(success);
+}
+
+} // namespace Internal
+} // namespace Madde
diff --git a/src/plugins/madde/maemosshrunner.h b/src/plugins/madde/maemoapplicationrunnerhelperactions.h
similarity index 55%
rename from src/plugins/madde/maemosshrunner.h
rename to src/plugins/madde/maemoapplicationrunnerhelperactions.h
index 6e9bd37d225..532ad9ac4b6 100644
--- a/src/plugins/madde/maemosshrunner.h
+++ b/src/plugins/madde/maemoapplicationrunnerhelperactions.h
@@ -6,6 +6,7 @@
 **
 ** Contact: http://www.qt-project.org/
 **
+**
 ** GNU Lesser General Public License Usage
 **
 ** This file may be used under the terms of the GNU Lesser General Public
@@ -26,54 +27,65 @@
 **
 **
 **************************************************************************/
+#ifndef MAEMOAPPLICATIONRUNNERHELPERACTIONS_H
+#define MAEMOAPPLICATIONRUNNERHELPERACTIONS_H
 
-#ifndef MAEMOSSHRUNNER_H
-#define MAEMOSSHRUNNER_H
+#include <projectexplorer/devicesupport/deviceapplicationrunner.h>
 
-#include "maemomountspecification.h"
+#include <QList>
 
-#include <remotelinux/remotelinuxapplicationrunner.h>
+namespace Utils { class FileName; }
 
 namespace Madde {
 namespace Internal {
+class MaemoMountSpecification;
 class MaemoRemoteMounter;
-class MaemoRunConfiguration;
 
-class MaemoSshRunner : public RemoteLinux::AbstractRemoteLinuxApplicationRunner
+class MaemoPreRunAction : public ProjectExplorer::DeviceApplicationHelperAction
 {
     Q_OBJECT
-
 public:
-    MaemoSshRunner(QObject *parent, MaemoRunConfiguration *runConfig);
+    MaemoPreRunAction(const ProjectExplorer::IDevice::ConstPtr &device,
+            const Utils::FileName &maddeRoot, const QList<MaemoMountSpecification> &mountSpecs,
+            QObject *parent = 0);
 
-signals:
-    void mountDebugOutput(const QString &output);
+    MaemoRemoteMounter *mounter() const { return m_mounter; }
 
 private slots:
     void handleMounted();
-    void handleUnmounted();
-    void handleMounterError(const QString &errorMsg);
+    void handleError(const QString &message);
 
 private:
-    enum MountState { InactiveMountState, InitialUnmounting, Mounting, Mounted, PostRunUnmounting };
+    void start();
+    void stop();
+
+    void setFinished(bool success);
 
-    bool canRun(QString &whyNot) const;
-    void doDeviceSetup();
-    void doAdditionalInitialCleanup();
-    void doAdditionalInitializations();
-    void doPostRunCleanup();
-    void doAdditionalConnectionErrorHandling();
+    MaemoRemoteMounter * const m_mounter;
+    bool m_isRunning;
+};
+
+class MaemoPostRunAction : public ProjectExplorer::DeviceApplicationHelperAction
+{
+    Q_OBJECT
+public:
+    MaemoPostRunAction(MaemoRemoteMounter *mounter, QObject *parent = 0);
+
+private slots:
+    void handleUnmounted();
+    void handleError(const QString &message);
+
+private:
+    void start();
+    void stop();
 
-    void mount();
-    void unmount();
+    void setFinished(bool success);
 
     MaemoRemoteMounter * const m_mounter;
-    QList<MaemoMountSpecification> m_mountSpecs;
-    MountState m_mountState;
-    int m_qtId;
+    bool m_isRunning;
 };
 
 } // namespace Internal
 } // namespace Madde
 
-#endif // MAEMOSSHRUNNER_H
+#endif // MAEMOAPPLICATIONRUNNERHELPERACTIONS_H
diff --git a/src/plugins/madde/maemodebugsupport.cpp b/src/plugins/madde/maemodebugsupport.cpp
deleted file mode 100644
index 7ff522f0697..00000000000
--- a/src/plugins/madde/maemodebugsupport.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: http://www.qt-project.org/
-**
-** 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.
-**
-** 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.
-**
-**
-**************************************************************************/
-#include "maemodebugsupport.h"
-
-#include "maemorunconfiguration.h"
-#include "maemosshrunner.h"
-
-#include <remotelinux/linuxdeviceconfiguration.h>
-
-using namespace RemoteLinux;
-
-namespace Madde {
-namespace Internal {
-
-MaemoDebugSupport::MaemoDebugSupport(MaemoRunConfiguration *runConfig, Debugger::DebuggerEngine *engine)
-    : AbstractRemoteLinuxDebugSupport(runConfig, engine),
-      m_runner(new MaemoSshRunner(this, runConfig))
-{
-}
-
-MaemoDebugSupport::~MaemoDebugSupport()
-{
-}
-
-AbstractRemoteLinuxApplicationRunner *MaemoDebugSupport::runner() const { return m_runner; }
-
-} // namespace Internal
-} // namespace Madde
diff --git a/src/plugins/madde/maemodebugsupport.h b/src/plugins/madde/maemodebugsupport.h
deleted file mode 100644
index 0aab12532a2..00000000000
--- a/src/plugins/madde/maemodebugsupport.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: http://www.qt-project.org/
-**
-** 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.
-**
-** 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.
-**
-**
-**************************************************************************/
-
-#ifndef MAEMODEBUGSUPPORT_H
-#define MAEMODEBUGSUPPORT_H
-
-#include <remotelinux/remotelinuxdebugsupport.h>
-
-namespace Madde {
-namespace Internal {
-class MaemoRunConfiguration;
-class MaemoSshRunner;
-
-class MaemoDebugSupport : public RemoteLinux::AbstractRemoteLinuxDebugSupport
-{
-    Q_OBJECT
-public:
-    MaemoDebugSupport(MaemoRunConfiguration *runConfig, Debugger::DebuggerEngine *engine);
-    ~MaemoDebugSupport();
-
-private:
-    RemoteLinux::AbstractRemoteLinuxApplicationRunner *runner() const;
-
-    MaemoSshRunner * const m_runner;
-};
-
-} // namespace Internal
-} // namespace Madde
-
-#endif // MAEMODEBUGSUPPORT_H
diff --git a/src/plugins/madde/maemoremotemounter.h b/src/plugins/madde/maemoremotemounter.h
index dcd2e39eb33..0814e846702 100644
--- a/src/plugins/madde/maemoremotemounter.h
+++ b/src/plugins/madde/maemoremotemounter.h
@@ -59,7 +59,7 @@ public:
     ~MaemoRemoteMounter();
 
     void setParameters(const ProjectExplorer::IDevice::ConstPtr &devConf,
-            const Utils::FileName &fileName);
+            const Utils::FileName &maddeRoot);
     void addMountSpecification(const MaemoMountSpecification &mountSpec,
         bool mountAsRoot);
     bool hasValidMountSpecifications() const;
diff --git a/src/plugins/madde/maemorunconfiguration.cpp b/src/plugins/madde/maemorunconfiguration.cpp
index 6bfbd257486..32ce32763b8 100644
--- a/src/plugins/madde/maemorunconfiguration.cpp
+++ b/src/plugins/madde/maemorunconfiguration.cpp
@@ -135,32 +135,6 @@ Utils::PortList MaemoRunConfiguration::freePorts() const
     return MaemoGlobal::freePorts(target()->profile());
 }
 
-QString MaemoRunConfiguration::localDirToMountForRemoteGdb() const
-{
-    const QString projectDir
-        = QDir::fromNativeSeparators(QDir::cleanPath(activeBuildConfiguration()
-            ->target()->project()->projectDirectory()));
-    const QString execDir
-        = QDir::fromNativeSeparators(QFileInfo(localExecutableFilePath()).path());
-    const int length = qMin(projectDir.length(), execDir.length());
-    int lastSeparatorPos = 0;
-    for (int i = 0; i < length; ++i) {
-        if (projectDir.at(i) != execDir.at(i))
-            return projectDir.left(lastSeparatorPos);
-        if (projectDir.at(i) == QLatin1Char('/'))
-            lastSeparatorPos = i;
-    }
-    return projectDir.length() == execDir.length()
-        ? projectDir : projectDir.left(lastSeparatorPos);
-}
-
-QString MaemoRunConfiguration::remoteProjectSourcesMountPoint() const
-{
-    return MaemoGlobal::homeDirOnDevice(DeviceProfileInformation::device(target()->profile())->sshParameters().userName)
-        + QLatin1String("/gdbSourcesDir_")
-        + QFileInfo(localExecutableFilePath()).fileName();
-}
-
 bool MaemoRunConfiguration::hasEnoughFreePorts(RunMode mode) const
 {
     const int freePortCount = freePorts().count();
diff --git a/src/plugins/madde/maemorunconfiguration.h b/src/plugins/madde/maemorunconfiguration.h
index dacc187cf12..b816f6682df 100644
--- a/src/plugins/madde/maemorunconfiguration.h
+++ b/src/plugins/madde/maemorunconfiguration.h
@@ -53,8 +53,6 @@ public:
 
     Internal::MaemoRemoteMountsModel *remoteMounts() const { return m_remoteMounts; }
     bool hasEnoughFreePorts(ProjectExplorer::RunMode mode) const;
-    QString localDirToMountForRemoteGdb() const;
-    QString remoteProjectSourcesMountPoint() const;
 
 signals:
     void remoteMountsChanged();
diff --git a/src/plugins/madde/maemoruncontrol.cpp b/src/plugins/madde/maemoruncontrol.cpp
deleted file mode 100644
index 74d242bc295..00000000000
--- a/src/plugins/madde/maemoruncontrol.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: http://www.qt-project.org/
-**
-** 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.
-**
-** 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.
-**
-**
-**************************************************************************/
-
-#include "maemoruncontrol.h"
-
-#include "maemoglobal.h"
-#include "maemorunconfiguration.h"
-#include "maemosshrunner.h"
-
-namespace Madde {
-namespace Internal {
-
-using namespace RemoteLinux;
-using ProjectExplorer::RunConfiguration;
-
-MaemoRunControl::MaemoRunControl(RunConfiguration *rc)
-    : AbstractRemoteLinuxRunControl(rc)
-    , m_runner(new MaemoSshRunner(this, qobject_cast<MaemoRunConfiguration *>(rc)))
-{
-}
-
-MaemoRunControl::~MaemoRunControl()
-{
-}
-
-void MaemoRunControl::start()
-{
-    AbstractRemoteLinuxRunControl::start();
-    connect(m_runner, SIGNAL(mountDebugOutput(QString)), SLOT(handleMountDebugOutput(QString)));
-}
-
-void MaemoRunControl::handleMountDebugOutput(const QString &output)
-{
-    appendMessage(output, Utils::StdErrFormatSameLine);
-}
-
-AbstractRemoteLinuxApplicationRunner *MaemoRunControl::runner() const { return m_runner; }
-
-} // namespace Internal
-} // namespace Madde
diff --git a/src/plugins/madde/maemoruncontrol.h b/src/plugins/madde/maemoruncontrol.h
deleted file mode 100644
index 92d94324295..00000000000
--- a/src/plugins/madde/maemoruncontrol.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: http://www.qt-project.org/
-**
-** 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.
-**
-** 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.
-**
-**
-**************************************************************************/
-
-#ifndef MAEMORUNCONTROL_H
-#define MAEMORUNCONTROL_H
-
-#include <remotelinux/remotelinuxruncontrol.h>
-
-namespace RemoteLinux {
-class RemoteLinuxRunConfiguration;
-}
-
-namespace Madde {
-namespace Internal {
-class MaemoSshRunner;
-
-class MaemoRunControl : public RemoteLinux::AbstractRemoteLinuxRunControl
-{
-    Q_OBJECT
-public:
-    explicit MaemoRunControl(ProjectExplorer::RunConfiguration *runConfig);
-    virtual ~MaemoRunControl();
-
-    void start();
-
-private slots:
-    void handleMountDebugOutput(const QString &output);
-
-private:
-    virtual RemoteLinux::AbstractRemoteLinuxApplicationRunner *runner() const;
-
-    MaemoSshRunner * const m_runner;
-};
-
-} // namespace Internal
-} // namespace Madde
-
-#endif // MAEMORUNCONTROL_H
diff --git a/src/plugins/madde/maemorunfactories.cpp b/src/plugins/madde/maemorunfactories.cpp
index 022b0d79d9f..02b084b96b2 100644
--- a/src/plugins/madde/maemorunfactories.cpp
+++ b/src/plugins/madde/maemorunfactories.cpp
@@ -28,11 +28,11 @@
 **************************************************************************/
 #include "maemorunfactories.h"
 
+#include "maemoapplicationrunnerhelperactions.h"
 #include "maemoconstants.h"
-#include "maemodebugsupport.h"
+#include "maemoglobal.h"
 #include "maemoremotemountsmodel.h"
 #include "maemorunconfiguration.h"
-#include "maemoruncontrol.h"
 
 #include <debugger/debuggerconstants.h>
 #include <debugger/debuggerstartparameters.h>
@@ -44,6 +44,8 @@
 #include <qt4projectmanager/qt4nodes.h>
 #include <qt4projectmanager/qt4project.h>
 #include <qtsupport/customexecutablerunconfiguration.h>
+#include <remotelinux/remotelinuxdebugsupport.h>
+#include <remotelinux/remotelinuxruncontrol.h>
 
 using namespace Debugger;
 using namespace ProjectExplorer;
@@ -169,7 +171,6 @@ QList<RunConfiguration *> MaemoRunConfigurationFactory::runConfigurationsForNode
     return result;
 }
 
-// #pragma mark -- MaemoRunControlFactory
 
 MaemoRunControlFactory::MaemoRunControlFactory(QObject *parent)
     : IRunControlFactory(parent)
@@ -197,14 +198,21 @@ RunControl* MaemoRunControlFactory::create(RunConfiguration *runConfig, RunMode
     Q_ASSERT(rc);
 
     if (mode == NormalRunMode)
-        return new MaemoRunControl(rc);
+        return new RemoteLinuxRunControl(rc);
 
-    const DebuggerStartParameters params
-        = AbstractRemoteLinuxDebugSupport::startParameters(rc);
+    const DebuggerStartParameters params = LinuxDeviceDebugSupport::startParameters(rc);
     DebuggerRunControl * const runControl = DebuggerPlugin::createDebugger(params, rc);
     if (!runControl)
         return 0;
-    MaemoDebugSupport *debugSupport = new MaemoDebugSupport(rc, runControl->engine());
+    LinuxDeviceDebugSupport * const debugSupport
+            = new LinuxDeviceDebugSupport(rc, runControl->engine());
+    const Profile * const profile = runConfig->target()->profile();
+    MaemoPreRunAction * const preRunAction = new MaemoPreRunAction(
+            DeviceProfileInformation::device(profile), MaemoGlobal::maddeRoot(profile),
+            rc->remoteMounts()->mountSpecs(), rc);
+    MaemoPostRunAction * const postRunAction = new MaemoPostRunAction(preRunAction->mounter(), rc);
+    debugSupport->setApplicationRunnerPreRunAction(preRunAction);
+    debugSupport->setApplicationRunnerPostRunAction(postRunAction);
     connect(runControl, SIGNAL(finished()), debugSupport, SLOT(handleDebuggingFinished()));
     return runControl;
 }
diff --git a/src/plugins/madde/maemosshrunner.cpp b/src/plugins/madde/maemosshrunner.cpp
deleted file mode 100644
index 260596b551f..00000000000
--- a/src/plugins/madde/maemosshrunner.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: http://www.qt-project.org/
-**
-** 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.
-**
-** 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.
-**
-**
-**************************************************************************/
-#include "maemosshrunner.h"
-
-#include "maemoglobal.h"
-#include "maemoqemumanager.h"
-#include "maemoremotemounter.h"
-#include "maemoremotemountsmodel.h"
-#include "maemorunconfiguration.h"
-
-#include <projectexplorer/buildconfiguration.h>
-#include <projectexplorer/target.h>
-#include <qtsupport/qtprofileinformation.h>
-#include <utils/qtcassert.h>
-#include <ssh/sshconnection.h>
-
-using namespace ProjectExplorer;
-using namespace QSsh;
-using namespace RemoteLinux;
-
-namespace Madde {
-namespace Internal {
-
-MaemoSshRunner::MaemoSshRunner(QObject *parent, MaemoRunConfiguration *runConfig)
-    : AbstractRemoteLinuxApplicationRunner(runConfig, parent),
-      m_mounter(new MaemoRemoteMounter(this)),
-      m_mountSpecs(runConfig->remoteMounts()->mountSpecs()),
-      m_mountState(InactiveMountState)
-{
-    const BuildConfiguration * const bc = runConfig->target()->activeBuildConfiguration();
-    Profile *profile  = bc ? bc->target()->profile() : 0;
-    m_qtId = QtSupport::QtProfileInformation::qtVersionId(profile);
-    m_mounter->setParameters(devConfig(), MaemoGlobal::maddeRoot(profile));
-    connect(m_mounter, SIGNAL(mounted()), this, SLOT(handleMounted()));
-    connect(m_mounter, SIGNAL(unmounted()), this, SLOT(handleUnmounted()));
-    connect(m_mounter, SIGNAL(error(QString)), this,
-        SLOT(handleMounterError(QString)));
-    connect(m_mounter, SIGNAL(reportProgress(QString)), this,
-        SIGNAL(reportProgress(QString)));
-    connect(m_mounter, SIGNAL(debugOutput(QString)), this,
-        SIGNAL(mountDebugOutput(QString)));
-}
-
-bool MaemoSshRunner::canRun(QString &whyNot) const
-{
-    if (!AbstractRemoteLinuxApplicationRunner::canRun(whyNot))
-        return false;
-
-    if (devConfig()->machineType() == IDevice::Emulator
-            && !MaemoQemuManager::instance().qemuIsRunning()) {
-        MaemoQemuRuntime rt;
-        if (MaemoQemuManager::instance().runtimeForQtVersion(m_qtId, &rt)) {
-            MaemoQemuManager::instance().startRuntime();
-            whyNot = tr("Qemu was not running. It has now been started up for you, but it will "
-                "take a bit of time until it is ready. Please try again then.");
-        } else {
-            whyNot = tr("You want to run on Qemu, but it is not enabled for this Qt version.");
-        }
-        return false;
-    }
-
-    return true;
-}
-
-void MaemoSshRunner::doDeviceSetup()
-{
-    QTC_ASSERT(m_mountState == InactiveMountState, return);
-
-    handleDeviceSetupDone(true);
-}
-
-void MaemoSshRunner::doAdditionalInitialCleanup()
-{
-    QTC_ASSERT(m_mountState == InactiveMountState, return);
-
-    m_mounter->resetMountSpecifications();
-    for (int i = 0; i < m_mountSpecs.count(); ++i)
-        m_mounter->addMountSpecification(m_mountSpecs.at(i), false);
-    m_mountState = InitialUnmounting;
-    unmount();
-}
-
-void MaemoSshRunner::doAdditionalInitializations()
-{
-    mount();
-}
-
-void MaemoSshRunner::doPostRunCleanup()
-{
-    QTC_ASSERT(m_mountState == Mounted, return);
-
-    m_mountState = PostRunUnmounting;
-    unmount();
-}
-
-void MaemoSshRunner::handleUnmounted()
-{
-    QTC_ASSERT(m_mountState == InitialUnmounting || m_mountState == PostRunUnmounting, return);
-
-    switch (m_mountState) {
-    case InitialUnmounting:
-        m_mountState = InactiveMountState;
-        handleInitialCleanupDone(true);
-        break;
-    case PostRunUnmounting:
-        m_mountState = InactiveMountState;
-        handlePostRunCleanupDone();
-        break;
-    default:
-        break;
-    }
-    m_mountState = InactiveMountState;
-}
-
-void MaemoSshRunner::doAdditionalConnectionErrorHandling()
-{
-    m_mountState = InactiveMountState;
-}
-
-void MaemoSshRunner::handleMounted()
-{
-    QTC_ASSERT(m_mountState == Mounting, return);
-
-    if (m_mountState == Mounting) {
-        m_mountState = Mounted;
-        handleInitializationsDone(true);
-    }
-}
-
-void MaemoSshRunner::handleMounterError(const QString &errorMsg)
-{
-    QTC_ASSERT(m_mountState == InitialUnmounting || m_mountState == Mounting
-        || m_mountState == PostRunUnmounting, return);
-
-    const MountState oldMountState = m_mountState;
-    m_mountState = InactiveMountState;
-    emit error(errorMsg);
-    switch (oldMountState) {
-    case InitialUnmounting:
-        handleInitialCleanupDone(false);
-        break;
-    case Mounting:
-        handleInitializationsDone(false);
-        break;
-    case PostRunUnmounting:
-        handlePostRunCleanupDone();
-        break;
-    default:
-        break;
-    }
-}
-
-void MaemoSshRunner::mount()
-{
-    m_mountState = Mounting;
-    if (m_mounter->hasValidMountSpecifications()) {
-        emit reportProgress(tr("Mounting host directories..."));
-        m_mounter->mount();
-    } else {
-        handleMounted();
-    }
-}
-
-void MaemoSshRunner::unmount()
-{
-    QTC_ASSERT(m_mountState == InitialUnmounting || m_mountState == PostRunUnmounting, return);
-
-    if (m_mounter->hasValidMountSpecifications()) {
-        QString message;
-        switch (m_mountState) {
-        case InitialUnmounting:
-            message = tr("Potentially unmounting left-over host directory mounts...");
-            break;
-        case PostRunUnmounting:
-            message = tr("Unmounting host directories...");
-            break;
-        default:
-            break;
-        }
-        emit reportProgress(message);
-        m_mounter->unmount();
-    } else {
-        handleUnmounted();
-    }
-}
-
-} // namespace Internal
-} // namespace Madde
-
diff --git a/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.cpp b/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.cpp
new file mode 100644
index 00000000000..0638b9a7ba5
--- /dev/null
+++ b/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.cpp
@@ -0,0 +1,339 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: http://www.qt-project.org/
+**
+**
+** 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.
+**
+** 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.
+**
+**
+**************************************************************************/
+#include "deviceapplicationrunner.h"
+
+#include <ssh/sshconnection.h>
+#include <ssh/sshconnectionmanager.h>
+#include <ssh/sshremoteprocess.h>
+#include <utils/qtcassert.h>
+
+#include <QTimer>
+
+using namespace QSsh;
+
+namespace ProjectExplorer {
+
+namespace {
+enum State { Inactive, Connecting, PreRun, Run, PostRun };
+} // anonymous namespace
+
+class DeviceApplicationRunner::DeviceApplicationRunnerPrivate
+{
+public:
+    SshConnection *connection;
+    DeviceApplicationHelperAction *preRunAction;
+    DeviceApplicationHelperAction *postRunAction;
+    IDevice::ConstPtr device;
+    SshRemoteProcess::Ptr remoteApp;
+    QTimer stopTimer;
+    QByteArray commandLine;
+    State state;
+    bool stopRequested;
+    bool success;
+};
+
+
+DeviceApplicationHelperAction::DeviceApplicationHelperAction(QObject *parent) : QObject(parent)
+{
+}
+
+DeviceApplicationHelperAction::~DeviceApplicationHelperAction()
+{
+}
+
+
+DeviceApplicationRunner::DeviceApplicationRunner(QObject *parent) :
+    QObject(parent), d(new DeviceApplicationRunnerPrivate)
+{
+    d->preRunAction = 0;
+    d->postRunAction = 0;
+    d->connection = 0;
+    d->state = Inactive;
+
+    d->stopTimer.setSingleShot(true);
+    connect(&d->stopTimer, SIGNAL(timeout()), SLOT(handleStopTimeout()));
+}
+
+DeviceApplicationRunner::~DeviceApplicationRunner()
+{
+    setFinished();
+    delete d;
+}
+
+void DeviceApplicationRunner::start(const IDevice::ConstPtr &device,
+        const QByteArray &commandLine)
+{
+    QTC_ASSERT(d->state == Inactive, return);
+
+    d->device = device;
+    d->commandLine = commandLine;
+    d->stopRequested = false;
+    d->success = true;
+
+    connectToServer();
+}
+
+void DeviceApplicationRunner::stop(const QByteArray &stopCommand)
+{
+    QTC_ASSERT(d->state != Inactive, return);
+
+    if (d->stopRequested)
+        return;
+    d->stopRequested = true;
+    d->success = false;
+    emit reportProgress(tr("User requested stop. Shutting down..."));
+    switch (d->state) {
+    case Connecting:
+        setFinished();
+        break;
+    case PreRun:
+        d->preRunAction->stop();
+        break;
+    case Run:
+        d->stopTimer.start(10000);
+        d->connection->createRemoteProcess(stopCommand)->start();
+        break;
+    case PostRun:
+        d->postRunAction->stop();
+        break;
+    case Inactive:
+        break;
+    }
+}
+
+void DeviceApplicationRunner::setPreRunAction(DeviceApplicationHelperAction *action)
+{
+    addAction(d->preRunAction, action);
+}
+
+void DeviceApplicationRunner::setPostRunAction(DeviceApplicationHelperAction *action)
+{
+    addAction(d->postRunAction, action);
+}
+
+void DeviceApplicationRunner::connectToServer()
+{
+    QTC_CHECK(!d->connection);
+
+    d->state = Connecting;
+
+    if (!d->device) {
+        emit reportError(tr("Cannot run: No device."));
+        setFinished();
+        return;
+    }
+
+    d->connection = SshConnectionManager::instance().acquireConnection(d->device->sshParameters());
+    connect(d->connection, SIGNAL(error(QSsh::SshError)), SLOT(handleConnectionFailure()));
+    if (d->connection->state() == SshConnection::Connected) {
+        handleConnected();
+    } else {
+        emit reportProgress(tr("Connecting to device..."));
+        connect(d->connection, SIGNAL(connected()), SLOT(handleConnected()));
+        if (d->connection->state() == QSsh::SshConnection::Unconnected)
+            d->connection->connectToHost();
+    }
+}
+
+void DeviceApplicationRunner::executePreRunAction()
+{
+    QTC_ASSERT(d->state == Connecting, return);
+
+    d->state = PreRun;
+    if (d->preRunAction)
+        d->preRunAction->start();
+    else
+        runApplication();
+}
+
+void DeviceApplicationRunner::executePostRunAction()
+{
+    QTC_ASSERT(d->state == PreRun || d->state == Run, return);
+
+    d->state = PostRun;
+    if (d->postRunAction)
+        d->postRunAction->start();
+    else
+        setFinished();
+}
+
+void DeviceApplicationRunner::setFinished()
+{
+    if (d->state == Inactive)
+        return;
+
+    if (d->remoteApp) {
+        d->remoteApp->disconnect(this);
+        d->remoteApp->close();
+        d->remoteApp.clear();
+    }
+    if (d->connection) {
+        d->connection->disconnect(this);
+        SshConnectionManager::instance().releaseConnection(d->connection);
+        d->connection = 0;
+    }
+
+    d->state = Inactive;
+    emit finished(d->success);
+}
+
+void DeviceApplicationRunner::handleConnected()
+{
+    QTC_ASSERT(d->state == Connecting, return);
+
+    if (d->stopRequested) {
+        setFinished();
+        return;
+    }
+
+    executePreRunAction();
+}
+
+void DeviceApplicationRunner::handleConnectionFailure()
+{
+    QTC_ASSERT(d->state != Inactive, return);
+
+    emit reportError(tr("SSH connection failed: %1").arg(d->connection->errorString()));
+    d->success = false;
+    switch (d->state) {
+    case Inactive:
+        break; // Can't happen.
+    case Connecting:
+        setFinished();
+        break;
+    case PreRun:
+        d->preRunAction->stop();
+        break;
+    case Run:
+        d->stopTimer.stop();
+        d->remoteApp->disconnect(this);
+        executePostRunAction();
+        break;
+    case PostRun:
+        d->postRunAction->stop();
+        break;
+    }
+}
+
+void DeviceApplicationRunner::handleHelperActionFinished(bool success)
+{
+    switch (d->state) {
+    case Inactive:
+        break;
+    case PreRun:
+        if (success && d->success) {
+            runApplication();
+        } else if (success && !d->success) {
+            executePostRunAction();
+        } else {
+            d->success = false;
+            setFinished();
+        }
+        break;
+    case PostRun:
+        if (!success)
+            d->success = false;
+        setFinished();
+        break;
+    default:
+        QTC_CHECK(false);
+    }
+}
+
+void DeviceApplicationRunner::addAction(DeviceApplicationHelperAction *&target,
+        DeviceApplicationHelperAction *source)
+{
+    QTC_ASSERT(d->state == Inactive, return);
+
+    if (target)
+        disconnect(target, 0, this, 0);
+    target = source;
+    if (target) {
+        connect(target, SIGNAL(finished(bool)), SLOT(handleHelperActionFinished(bool)));
+        connect(target, SIGNAL(reportProgress(QString)), SIGNAL(reportProgress(QString)));
+        connect(target, SIGNAL(reportError(QString)), SIGNAL(reportError(QString)));
+    }
+}
+
+void DeviceApplicationRunner::handleStopTimeout()
+{
+    QTC_ASSERT(d->stopRequested && d->state == Run, return);
+
+    emit reportError(tr("Application did not finish in time, aborting."));
+    d->success = false;
+    setFinished();
+}
+
+void DeviceApplicationRunner::handleApplicationFinished(int exitStatus)
+{
+    QTC_ASSERT(d->state == Run, return);
+
+    d->stopTimer.stop();
+    if (exitStatus == SshRemoteProcess::CrashExit) {
+        emit reportError(tr("Remote application crashed: %1").arg(d->remoteApp->errorString()));
+        d->success = false;
+    } else {
+        const int exitCode = d->remoteApp->exitCode();
+        if (exitCode != 0) {
+            emit reportError(tr("Remote application finished with exit code %1.").arg(exitCode));
+            d->success = false;
+        } else {
+            emit reportProgress(tr("Remote application finished with exit code 0."));
+        }
+    }
+    executePostRunAction();
+}
+
+void DeviceApplicationRunner::handleRemoteStdout()
+{
+    QTC_ASSERT(d->state == Run, return);
+    emit remoteStdout(d->remoteApp->readAllStandardOutput());
+}
+
+void DeviceApplicationRunner::handleRemoteStderr()
+{
+    QTC_ASSERT(d->state == Run, return);
+    emit remoteStderr(d->remoteApp->readAllStandardError());
+}
+
+void DeviceApplicationRunner::runApplication()
+{
+    QTC_ASSERT(d->state == PreRun, return);
+
+    d->state = Run;
+    d->remoteApp = d->connection->createRemoteProcess(d->commandLine);
+    connect(d->remoteApp.data(), SIGNAL(started()), SIGNAL(remoteProcessStarted()));
+    connect(d->remoteApp.data(), SIGNAL(readyReadStandardOutput()), SLOT(handleRemoteStdout()));
+    connect(d->remoteApp.data(), SIGNAL(readyReadStandardError()), SLOT(handleRemoteStderr()));
+    connect(d->remoteApp.data(), SIGNAL(closed(int)), SLOT(handleApplicationFinished(int)));
+    d->remoteApp->start();
+}
+
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.h b/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.h
new file mode 100644
index 00000000000..2b19f0783ca
--- /dev/null
+++ b/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.h
@@ -0,0 +1,104 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: http://www.qt-project.org/
+**
+**
+** 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.
+**
+** 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.
+**
+**
+**************************************************************************/
+#ifndef ONDEVICEAPPLICATIONRUNNER_H
+#define ONDEVICEAPPLICATIONRUNNER_H
+
+#include "idevice.h"
+
+#include "../projectexplorer_export.h"
+
+#include <QObject>
+
+namespace ProjectExplorer {
+
+class PROJECTEXPLORER_EXPORT DeviceApplicationHelperAction : public QObject
+{
+    Q_OBJECT
+public:
+    ~DeviceApplicationHelperAction();
+    virtual void start() = 0;
+    virtual void stop() = 0;
+signals:
+    void reportProgress(const QString &progressOutput);
+    void reportError(const QString &errorOutput);
+    void finished(bool success);
+
+protected:
+    DeviceApplicationHelperAction(QObject *parent = 0);
+};
+
+class PROJECTEXPLORER_EXPORT DeviceApplicationRunner : public QObject
+{
+    Q_OBJECT
+public:
+    explicit DeviceApplicationRunner(QObject *parent = 0);
+    virtual ~DeviceApplicationRunner();
+
+    void start(const IDevice::ConstPtr &device, const QByteArray &commandLine);
+    void stop(const QByteArray &stopCommand);
+
+    // Use these if you need to do something before and after the application is run, respectively.
+    // Typically, the post-run action reverts the effects of the pre-run action.
+    // If you only have a pre-run action, you probably want a deploy step instead.
+    void setPreRunAction(DeviceApplicationHelperAction *action);
+    void setPostRunAction(DeviceApplicationHelperAction *action);
+
+signals:
+    void remoteStdout(const QByteArray &output);
+    void remoteStderr(const QByteArray &output);
+    void reportProgress(const QString &progressOutput);
+    void reportError(const QString &errorOutput);
+    void remoteProcessStarted();
+    void finished(bool success);
+
+private slots:
+    void handleConnected();
+    void handleConnectionFailure();
+    void handleHelperActionFinished(bool success);
+    void handleStopTimeout();
+    void handleApplicationFinished(int exitStatus);
+    void handleRemoteStdout();
+    void handleRemoteStderr();
+
+private:
+    void addAction(DeviceApplicationHelperAction *&target, DeviceApplicationHelperAction *source);
+    void connectToServer();
+    void executePreRunAction();
+    void executePostRunAction();
+    void runApplication();
+    void setFinished();
+
+    class DeviceApplicationRunnerPrivate;
+    DeviceApplicationRunnerPrivate * const d;
+};
+
+} // namespace ProjectExplorer
+
+#endif // ONDEVICEAPPLICATIONRUNNER_H
diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro
index cd8a533557f..d27b13f22c4 100644
--- a/src/plugins/projectexplorer/projectexplorer.pro
+++ b/src/plugins/projectexplorer/projectexplorer.pro
@@ -125,7 +125,8 @@ HEADERS += projectexplorer.h \
     devicesupport/deviceprocessesdialog.h \
     devicesupport/devicesettingswidget.h \
     devicesupport/devicesettingspage.h \
-    devicesupport/deviceusedportsgatherer.h
+    devicesupport/deviceusedportsgatherer.h \
+    devicesupport/deviceapplicationrunner.h
 
 SOURCES += projectexplorer.cpp \
     abi.cpp \
@@ -227,7 +228,8 @@ SOURCES += projectexplorer.cpp \
     devicesupport/deviceprocessesdialog.cpp \
     devicesupport/devicesettingswidget.cpp \
     devicesupport/devicesettingspage.cpp \
-    devicesupport/deviceusedportsgatherer.cpp
+    devicesupport/deviceusedportsgatherer.cpp \
+    devicesupport/deviceapplicationrunner.cpp
 
 FORMS += processstep.ui \
     editorsettingspropertiespage.ui \
diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs
index 0e5dbeeae56..10234f3ab56 100644
--- a/src/plugins/projectexplorer/projectexplorer.qbs
+++ b/src/plugins/projectexplorer/projectexplorer.qbs
@@ -308,7 +308,9 @@ QtcPlugin {
         "devicesupport/deviceusedportsgatherer.h",
         "devicesupport/idevicewidget.h",
         "devicesupport/idevicefactory.cpp",
-        "devicesupport/idevicefactory.h"
+        "devicesupport/idevicefactory.h",
+        "devicesupport/deviceapplicationrunner.cpp",
+        "devicesupport/deviceapplicationrunner.h"
     ]
 
     Group {
diff --git a/src/plugins/qmlprofiler/qmlprofilerengine.cpp b/src/plugins/qmlprofiler/qmlprofilerengine.cpp
index 7149c5a42b6..32a667242d8 100644
--- a/src/plugins/qmlprofiler/qmlprofilerengine.cpp
+++ b/src/plugins/qmlprofiler/qmlprofilerengine.cpp
@@ -45,6 +45,7 @@
 #include <qt4projectmanager/qt-s60/s60devicedebugruncontrol.h>
 #include <qt4projectmanager/qt-s60/s60devicerunconfiguration.h>
 #include <qmldebug/qmloutputparser.h>
+#include <remotelinux/remotelinuxrunconfiguration.h>
 
 #include <QMainWindow>
 #include <QMessageBox>
@@ -370,6 +371,7 @@ void QmlProfilerEngine::profilerStateChanged()
     case QmlProfilerStateManager::Idle : {
         // When all the profiling is done, delete the profiler runner
         // (a new one will be created at start)
+        d->m_noDebugOutputTimer.stop();
         if (d->m_runner) {
             delete d->m_runner;
             d->m_runner = 0;
diff --git a/src/plugins/qmlprofiler/remotelinuxqmlprofilerrunner.cpp b/src/plugins/qmlprofiler/remotelinuxqmlprofilerrunner.cpp
index 9c5a3483ff8..695e65eaab2 100644
--- a/src/plugins/qmlprofiler/remotelinuxqmlprofilerrunner.cpp
+++ b/src/plugins/qmlprofiler/remotelinuxqmlprofilerrunner.cpp
@@ -27,15 +27,18 @@
 **
 **
 **************************************************************************/
-
 #include "remotelinuxqmlprofilerrunner.h"
-#include <extensionsystem/pluginmanager.h>
+
+#include <projectexplorer/devicesupport/deviceapplicationrunner.h>
+#include <projectexplorer/devicesupport/deviceusedportsgatherer.h>
+#include <projectexplorer/profileinformation.h>
 #include <projectexplorer/projectexplorerconstants.h>
-#include <remotelinux/remotelinuxapplicationrunner.h>
+#include <projectexplorer/target.h>
+#include <remotelinux/remotelinuxrunconfiguration.h>
+#include <remotelinux/remotelinuxutils.h>
 #include <utils/portlist.h>
 #include <utils/qtcassert.h>
 
-using namespace ExtensionSystem;
 using namespace ProjectExplorer;
 using namespace QmlProfiler::Internal;
 using namespace RemoteLinux;
@@ -43,55 +46,43 @@ using namespace RemoteLinux;
 RemoteLinuxQmlProfilerRunner::RemoteLinuxQmlProfilerRunner(
     RemoteLinuxRunConfiguration *runConfiguration, QObject *parent)
     : AbstractQmlProfilerRunner(parent)
+    , m_portsGatherer(new DeviceUsedPortsGatherer(this))
+    , m_runner(new DeviceApplicationRunner(this))
+    , m_device(DeviceProfileInformation::device(runConfiguration->target()->profile()))
+    , m_remoteExecutable(runConfiguration->remoteExecutableFilePath())
+    , m_arguments(runConfiguration->arguments())
+    , m_commandPrefix(runConfiguration->commandPrefix())
     , m_port(0)
-    , m_runControl(0)
 {
-    // find run control factory
-    IRunControlFactory *runControlFactory = 0;
-    QList<IRunControlFactory*> runControlFactories
-            = PluginManager::getObjects<IRunControlFactory>();
-
-    foreach (IRunControlFactory *factory, runControlFactories) {
-        if (factory->canRun(runConfiguration, NormalRunMode)) {
-            runControlFactory = factory;
-            break;
-        }
-    }
-
-    QTC_ASSERT(runControlFactory, return);
-
-    // create run control
-    RunControl *runControl = runControlFactory->create(runConfiguration, NormalRunMode);
-
-    m_runControl = qobject_cast<AbstractRemoteLinuxRunControl*>(runControl);
-    QTC_ASSERT(m_runControl, return);
-
-    connect(runner(), SIGNAL(readyForExecution()), this, SLOT(getPorts()));
-    connect(runner(), SIGNAL(error(QString)), this, SLOT(handleError(QString)));
-    connect(runner(), SIGNAL(remoteErrorOutput(QByteArray)), this, SLOT(handleStdErr(QByteArray)));
-    connect(runner(), SIGNAL(remoteOutput(QByteArray)), this, SLOT(handleStdOut(QByteArray)));
-
-    connect(runner(), SIGNAL(remoteProcessStarted()), this, SLOT(handleRemoteProcessStarted()));
-    connect(runner(), SIGNAL(remoteProcessFinished(qint64)),
-            this, SLOT(handleRemoteProcessFinished(qint64)));
-    connect(runner(), SIGNAL(reportProgress(QString)), this, SLOT(handleProgressReport(QString)));
+    connect(m_runner, SIGNAL(reportError(QString)), this, SLOT(handleError(QString)));
+    connect(m_runner, SIGNAL(remoteStderr(QByteArray)), this, SLOT(handleStdErr(QByteArray)));
+    connect(m_runner, SIGNAL(remoteStdout(QByteArray)), this, SLOT(handleStdOut(QByteArray)));
+    connect(m_runner, SIGNAL(finished(bool)), SLOT(handleRemoteProcessFinished(bool)));
+    connect(m_runner, SIGNAL(reportProgress(QString)), this, SLOT(handleProgressReport(QString)));
+    connect(m_portsGatherer, SIGNAL(error(QString)), SLOT(handlePortsGathererError(QString)));
+    connect(m_portsGatherer, SIGNAL(portListReady()), SLOT(handlePortListReady()));
 }
 
 RemoteLinuxQmlProfilerRunner::~RemoteLinuxQmlProfilerRunner()
 {
-    delete m_runControl;
+    stop();
 }
 
 void RemoteLinuxQmlProfilerRunner::start()
 {
-    QTC_ASSERT(runner(), return);
-    runner()->start();
+    QTC_ASSERT(m_port == 0, return);
+
+    m_portsGatherer->start(m_device);
+    emit started();
 }
 
 void RemoteLinuxQmlProfilerRunner::stop()
 {
-    QTC_ASSERT(runner(), return);
-    runner()->stop();
+    if (m_port == 0)
+        m_portsGatherer->stop();
+    else
+        m_runner->stop(RemoteLinuxUtils::killApplicationCommandLine(m_remoteExecutable).toUtf8());
+    m_port = 0;
 }
 
 quint16 RemoteLinuxQmlProfilerRunner::debugPort() const
@@ -99,26 +90,37 @@ quint16 RemoteLinuxQmlProfilerRunner::debugPort() const
     return m_port;
 }
 
+void RemoteLinuxQmlProfilerRunner::handlePortsGathererError(const QString &message)
+{
+    emit appendMessage(tr("Gathering ports failed: %1").arg(message), Utils::ErrorMessageFormat);
+    m_port = 0;
+    emit stopped();
+}
+
+void RemoteLinuxQmlProfilerRunner::handlePortListReady()
+{
+    getPorts();
+}
+
 void RemoteLinuxQmlProfilerRunner::getPorts()
 {
-    QTC_ASSERT(runner(), return);
-    m_port = runner()->freePorts()->getNext();
-    if (m_port == 0) {
+    Utils::PortList portList = m_device->freePorts();
+    m_port = m_portsGatherer->getNextFreePort(&portList);
+
+    if (m_port == -1) {
         emit appendMessage(tr("Not enough free ports on device for analyzing.\n"),
                            Utils::ErrorMessageFormat);
-        runner()->stop();
+        m_port = 0;
+        emit stopped();
     } else {
         emit appendMessage(tr("Starting remote process ...\n"), Utils::NormalMessageFormat);
-
-        QString arguments = runner()->arguments();
+        QString arguments = m_arguments;
         if (!arguments.isEmpty())
             arguments.append(QLatin1Char(' '));
         arguments.append(QString::fromLatin1("-qmljsdebugger=port:%1,block").arg(m_port));
-
-        runner()->startExecution(QString::fromLatin1("%1 %2 %3")
-                                 .arg(runner()->commandPrefix())
-                                 .arg(runner()->remoteExecutable())
-                                 .arg(arguments).toUtf8());
+        const QString commandLine = QString::fromLatin1("%1 %2 %3")
+                .arg(m_commandPrefix, m_remoteExecutable, arguments);
+        m_runner->start(m_device, commandLine.toUtf8());
     }
 }
 
@@ -137,18 +139,11 @@ void RemoteLinuxQmlProfilerRunner::handleStdOut(const QByteArray &msg)
     emit appendMessage(QString::fromUtf8(msg), Utils::StdOutFormat);
 }
 
-void RemoteLinuxQmlProfilerRunner::handleRemoteProcessStarted()
+void RemoteLinuxQmlProfilerRunner::handleRemoteProcessFinished(bool success)
 {
-    emit started();
-}
-
-void RemoteLinuxQmlProfilerRunner::handleRemoteProcessFinished(qint64 exitCode)
-{
-    if (exitCode != AbstractRemoteLinuxApplicationRunner::InvalidExitCode) {
-        appendMessage(tr("Finished running remote process. Exit code was %1.\n")
-                      .arg(exitCode), Utils::NormalMessageFormat);
-    }
-
+    if (!success)
+        appendMessage(tr("Failure running remote process."), Utils::NormalMessageFormat);
+    m_port = 0;
     emit stopped();
 }
 
@@ -156,11 +151,3 @@ void RemoteLinuxQmlProfilerRunner::handleProgressReport(const QString &progressS
 {
     appendMessage(progressString + QLatin1Char('\n'), Utils::NormalMessageFormat);
 }
-
-AbstractRemoteLinuxApplicationRunner *RemoteLinuxQmlProfilerRunner::runner() const
-{
-    if (!m_runControl)
-        return 0;
-    return m_runControl->runner();
-}
-
diff --git a/src/plugins/qmlprofiler/remotelinuxqmlprofilerrunner.h b/src/plugins/qmlprofiler/remotelinuxqmlprofilerrunner.h
index 5f178edc422..6d0a766aff8 100644
--- a/src/plugins/qmlprofiler/remotelinuxqmlprofilerrunner.h
+++ b/src/plugins/qmlprofiler/remotelinuxqmlprofilerrunner.h
@@ -32,8 +32,16 @@
 #define REMOTELINUXQMLPROFILERRUNNER_H
 
 #include "abstractqmlprofilerrunner.h"
-#include <remotelinux/remotelinuxrunconfiguration.h>
-#include <remotelinux/remotelinuxruncontrol.h>
+
+#include <projectexplorer/devicesupport/idevice.h>
+
+#include <QString>
+
+namespace ProjectExplorer {
+class DeviceApplicationRunner;
+class DeviceUsedPortsGatherer;
+}
+namespace RemoteLinux { class RemoteLinuxRunConfiguration; }
 
 namespace QmlProfiler {
 namespace Internal {
@@ -54,19 +62,24 @@ public:
     virtual quint16 debugPort() const;
 
 private slots:
-    void getPorts();
     void handleError(const QString &msg);
     void handleStdErr(const QByteArray &msg);
     void handleStdOut(const QByteArray &msg);
-    void handleRemoteProcessStarted();
-    void handleRemoteProcessFinished(qint64);
+    void handleRemoteProcessFinished(bool success);
     void handleProgressReport(const QString &progressString);
+    void handlePortsGathererError(const QString &message);
+    void handlePortListReady();
 
 private:
-    RemoteLinux::AbstractRemoteLinuxApplicationRunner *runner() const;
+    void getPorts();
 
-    quint16 m_port;
-    RemoteLinux::AbstractRemoteLinuxRunControl *m_runControl;
+    ProjectExplorer::DeviceUsedPortsGatherer * const m_portsGatherer;
+    ProjectExplorer::DeviceApplicationRunner * const m_runner;
+    const ProjectExplorer::IDevice::ConstPtr m_device;
+    const QString m_remoteExecutable;
+    const QString m_arguments;
+    const QString m_commandPrefix;
+    int m_port;
 };
 
 } // namespace Internal
diff --git a/src/plugins/qnx/qnx.pro b/src/plugins/qnx/qnx.pro
index af0f672ff40..ed729e954f8 100644
--- a/src/plugins/qnx/qnx.pro
+++ b/src/plugins/qnx/qnx.pro
@@ -41,7 +41,6 @@ SOURCES += qnxplugin.cpp \
     qnxrunconfiguration.cpp \
     qnxruncontrolfactory.cpp \
     qnxdebugsupport.cpp \
-    qnxapplicationrunner.cpp \
     qnxdeploystepfactory.cpp \
     qnxdeployconfigurationfactory.cpp \
     qnxrunconfigurationfactory.cpp \
@@ -91,7 +90,6 @@ HEADERS += qnxplugin.h\
     qnxrunconfiguration.h \
     qnxruncontrolfactory.h \
     qnxdebugsupport.h \
-    qnxapplicationrunner.h \
     qnxdeploystepfactory.h \
     qnxdeployconfigurationfactory.h \
     qnxrunconfigurationfactory.h \
diff --git a/src/plugins/qnx/qnxapplicationrunner.cpp b/src/plugins/qnx/qnxapplicationrunner.cpp
deleted file mode 100644
index 2156f059aac..00000000000
--- a/src/plugins/qnx/qnxapplicationrunner.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-**
-** Contact: Research In Motion (blackberry-qt@qnx.com)
-** Contact: KDAB (info@kdab.com)
-**
-**
-** 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.
-**
-** 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.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at info@qt.nokia.com.
-**
-**************************************************************************/
-
-#include "qnxapplicationrunner.h"
-#include "qnxrunconfiguration.h"
-#include "qnxconstants.h"
-
-using namespace Qnx;
-using namespace Qnx::Internal;
-
-QnxApplicationRunner::QnxApplicationRunner(QnxRunConfiguration *runConfig, QObject *parent)
-    : RemoteLinux::AbstractRemoteLinuxApplicationRunner(runConfig, parent)
-    , m_debugMode(false)
-{
-    usedPortsGatherer()->setCommand(QLatin1String(Constants::QNX_PORT_GATHERER_COMMAND));
-}
-
-void QnxApplicationRunner::setDebugMode(bool debugMode)
-{
-    m_debugMode = debugMode;
-}
-
-void QnxApplicationRunner::doDeviceSetup()
-{
-    handleDeviceSetupDone(true);
-}
-
-void QnxApplicationRunner::doAdditionalInitialCleanup()
-{
-    handleInitialCleanupDone(true);
-}
-
-void QnxApplicationRunner::doAdditionalInitializations()
-{
-    handleInitializationsDone(true);
-}
-
-void QnxApplicationRunner::doPostRunCleanup()
-{
-    handlePostRunCleanupDone();
-}
-
-void QnxApplicationRunner::doAdditionalConnectionErrorHandling()
-{
-}
-
-QString QnxApplicationRunner::killApplicationCommandLine() const
-{
-    QString executable = m_debugMode ? QLatin1String(Constants::QNX_DEBUG_EXECUTABLE) : remoteExecutable();
-    executable.replace(QLatin1String("/"), QLatin1String("\\/"));
-    return QString::fromLatin1("for PID in $(ps -f -o pid,comm | grep %1 | awk '/%1/ {print $1}'); "
-                                          "do "
-                                              "kill $PID; sleep 1; kill -9 $PID; "
-                                          "done").arg(executable);
-}
diff --git a/src/plugins/qnx/qnxapplicationrunner.h b/src/plugins/qnx/qnxapplicationrunner.h
deleted file mode 100644
index bcd861954ff..00000000000
--- a/src/plugins/qnx/qnxapplicationrunner.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-**
-** Contact: Research In Motion (blackberry-qt@qnx.com)
-** Contact: KDAB (info@kdab.com)
-**
-**
-** 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.
-**
-** 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.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at info@qt.nokia.com.
-**
-**************************************************************************/
-
-#ifndef QNX_INTERNAL_QNXAPPLICATIONRUNNER_H
-#define QNX_INTERNAL_QNXAPPLICATIONRUNNER_H
-
-#include <remotelinux/remotelinuxapplicationrunner.h>
-
-namespace Qnx {
-namespace Internal {
-
-class QnxRunConfiguration;
-
-class QnxApplicationRunner : public RemoteLinux::AbstractRemoteLinuxApplicationRunner
-{
-    Q_OBJECT
-public:
-    explicit QnxApplicationRunner(QnxRunConfiguration *runConfig,
-                                  QObject *parent = 0);
-
-    void setDebugMode(bool debugMode);
-
-protected:
-    void doDeviceSetup();
-    void doAdditionalInitialCleanup();
-    void doAdditionalInitializations();
-    void doPostRunCleanup();
-    void doAdditionalConnectionErrorHandling();
-
-private:
-    QString killApplicationCommandLine() const;
-
-    bool m_debugMode;
-};
-
-} // namespace Internal
-} // namespace Qnx
-
-#endif // QNX_INTERNAL_QNXAPPLICATIONRUNNER_H
diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp
index afda2edac5b..766a06c9bf0 100644
--- a/src/plugins/qnx/qnxdebugsupport.cpp
+++ b/src/plugins/qnx/qnxdebugsupport.cpp
@@ -32,22 +32,46 @@
 **************************************************************************/
 
 #include "qnxdebugsupport.h"
-#include "qnxapplicationrunner.h"
 #include "qnxconstants.h"
+#include "qnxrunconfiguration.h"
+#include "qnxutils.h"
 
 #include <debugger/debuggerengine.h>
+#include <projectexplorer/devicesupport/deviceapplicationrunner.h>
+#include <projectexplorer/devicesupport/deviceusedportsgatherer.h>
+#include <projectexplorer/profileinformation.h>
+#include <projectexplorer/target.h>
+#include <utils/portlist.h>
 #include <utils/qtcassert.h>
 
+using namespace ProjectExplorer;
+using namespace RemoteLinux;
+
+using namespace Qnx;
 using namespace Qnx::Internal;
 
 QnxDebugSupport::QnxDebugSupport(QnxRunConfiguration *runConfig, Debugger::DebuggerEngine *engine)
     : QObject(engine)
+    , m_executable(QLatin1String(Constants::QNX_DEBUG_EXECUTABLE))
+    , m_commandPrefix(runConfig->commandPrefix())
+    , m_arguments(runConfig->arguments())
+    , m_device(DeviceProfileInformation::device(runConfig->target()->profile()))
     , m_engine(engine)
     , m_port(-1)
     , m_state(Inactive)
 {
-    m_runner = new QnxApplicationRunner(runConfig, this);
-    m_runner->setDebugMode(true);
+    m_runner = new DeviceApplicationRunner(this);
+    m_portsGatherer = new DeviceUsedPortsGatherer(this);
+    m_portsGatherer->setCommand(QLatin1String(Constants::QNX_PORT_GATHERER_COMMAND));
+
+    connect(m_portsGatherer, SIGNAL(error(QString)), SLOT(handleError(QString)));
+    connect(m_portsGatherer, SIGNAL(portListReady()), SLOT(handlePortListReady()));
+
+    connect(m_runner, SIGNAL(reportError(QString)), SLOT(handleError(QString)));
+    connect(m_runner, SIGNAL(remoteProcessStarted()),        this, SLOT(handleRemoteProcessStarted()));
+    connect(m_runner, SIGNAL(finished(bool)), SLOT(handleRemoteProcessFinished(qint64)));
+    connect(m_runner, SIGNAL(reportProgress(QString)),       this, SLOT(handleProgressReport(QString)));
+    connect(m_runner, SIGNAL(remoteStdout(QByteArray)),      this, SLOT(handleRemoteOutput(QByteArray)));
 
     connect(m_engine, SIGNAL(requestRemoteSetup()), this, SLOT(handleAdapterSetupRequested()));
 }
@@ -56,18 +80,16 @@ void QnxDebugSupport::handleAdapterSetupRequested()
 {
     QTC_ASSERT(m_state == Inactive, return);
 
-    m_state = StartingRunner;
+    m_state = GatheringPorts;
     if (m_engine)
         m_engine->showMessage(tr("Preparing remote side...\n"), Debugger::AppStuff);
+    m_portsGatherer->start(m_device);
+}
 
-    connect(m_runner, SIGNAL(error(QString)),                this, SLOT(handleSshError(QString)));
-    connect(m_runner, SIGNAL(readyForExecution()),           this, SLOT(startExecution()));
-    connect(m_runner, SIGNAL(remoteProcessStarted()),        this, SLOT(handleRemoteProcessStarted()));
-    connect(m_runner, SIGNAL(remoteProcessFinished(qint64)), this, SLOT(handleRemoteProcessFinished(qint64)));
-    connect(m_runner, SIGNAL(reportProgress(QString)),       this, SLOT(handleProgressReport(QString)));
-    connect(m_runner, SIGNAL(remoteOutput(QByteArray)),      this, SLOT(handleRemoteOutput(QByteArray)));
-
-    m_runner->start();
+void QnxDebugSupport::handlePortListReady()
+{
+    QTC_ASSERT(m_state == GatheringPorts, return);
+    startExecution();
 }
 
 void QnxDebugSupport::startExecution()
@@ -75,13 +97,13 @@ void QnxDebugSupport::startExecution()
     if (m_state == Inactive)
         return;
 
-    QTC_ASSERT(m_state == StartingRunner, return);
-
     m_state = StartingRemoteProcess;
-    m_port = m_runner->usedPortsGatherer()->getNextFreePort(m_runner->freePorts());
+    Utils::PortList portList = m_device->freePorts();
+    m_port = m_portsGatherer->getNextFreePort(&portList);
 
-    const QString remoteCommandLine = QString::fromLatin1("%1 %2 %3").arg(m_runner->commandPrefix()).arg(QLatin1String(Constants::QNX_DEBUG_EXECUTABLE)).arg(m_port);
-    m_runner->startExecution(remoteCommandLine.toUtf8());
+    const QString remoteCommandLine = QString::fromLatin1("%1 %2 %3")
+            .arg(m_commandPrefix, m_executable).arg(m_port);
+    m_runner->start(m_device, remoteCommandLine.toUtf8());
 }
 
 void QnxDebugSupport::handleRemoteProcessStarted()
@@ -90,17 +112,17 @@ void QnxDebugSupport::handleRemoteProcessStarted()
         m_engine->notifyEngineRemoteSetupDone(m_port, -1);
 }
 
-void QnxDebugSupport::handleRemoteProcessFinished(qint64 exitCode)
+void QnxDebugSupport::handleRemoteProcessFinished(bool success)
 {
     if (m_engine || m_state == Inactive)
         return;
 
     if (m_state == Debugging) {
-        if (exitCode != 0)
+        if (!success)
             m_engine->notifyInferiorIll();
 
     } else {
-        const QString errorMsg = tr("The %1 process closed unexpectedly.").arg(QLatin1String(Constants::QNX_DEBUG_EXECUTABLE));
+        const QString errorMsg = tr("The %1 process closed unexpectedly.").arg(m_executable);
         m_engine->notifyEngineRemoteSetupFailed(errorMsg);
     }
 }
@@ -113,7 +135,7 @@ void QnxDebugSupport::handleDebuggingFinished()
 void QnxDebugSupport::setFinished()
 {
     m_state = Inactive;
-    m_runner->stop();
+    m_runner->stop(QnxUtils::applicationKillCommand(m_executable).toUtf8());
 }
 
 void QnxDebugSupport::handleProgressReport(const QString &progressOutput)
@@ -130,7 +152,7 @@ void QnxDebugSupport::handleRemoteOutput(const QByteArray &output)
         m_engine->showMessage(QString::fromUtf8(output), Debugger::AppOutput);
 }
 
-void QnxDebugSupport::handleSshError(const QString &error)
+void QnxDebugSupport::handleError(const QString &error)
 {
     if (m_state == Debugging) {
         if (m_engine) {
diff --git a/src/plugins/qnx/qnxdebugsupport.h b/src/plugins/qnx/qnxdebugsupport.h
index f2a9dd2b06e..a97796546c7 100644
--- a/src/plugins/qnx/qnxdebugsupport.h
+++ b/src/plugins/qnx/qnxdebugsupport.h
@@ -34,16 +34,20 @@
 #ifndef QNX_INTERNAL_QNXDEBUGSUPPORT_H
 #define QNX_INTERNAL_QNXDEBUGSUPPORT_H
 
+#include <projectexplorer/devicesupport/idevice.h>
+
 #include <QObject>
+#include <QString>
 
-namespace Debugger {
-class DebuggerEngine;
+namespace Debugger { class DebuggerEngine; }
+namespace ProjectExplorer {
+class DeviceApplicationRunner;
+class DeviceUsedPortsGatherer;
 }
 
 namespace Qnx {
 namespace Internal {
 
-class QnxApplicationRunner;
 class QnxRunConfiguration;
 
 class QnxDebugSupport : public QObject
@@ -59,25 +63,30 @@ public slots:
 private slots:
     void handleAdapterSetupRequested();
 
-    void startExecution();
     void handleRemoteProcessStarted();
-    void handleRemoteProcessFinished(qint64 exitCode);
+    void handleRemoteProcessFinished(bool success);
     void handleProgressReport(const QString &progressOutput);
     void handleRemoteOutput(const QByteArray &output);
-    void handleSshError(const QString &error);
+    void handleError(const QString &error);
+    void handlePortListReady();
 
 private:
+    void startExecution();
     void setFinished();
 
     enum State {
         Inactive,
-        StartingRunner,
+        GatheringPorts,
         StartingRemoteProcess,
         Debugging
     };
 
-    QnxApplicationRunner *m_runner;
-
+    const QString m_executable;
+    const QString m_commandPrefix;
+    const QString m_arguments;
+    ProjectExplorer::IDevice::ConstPtr m_device;
+    ProjectExplorer::DeviceApplicationRunner *m_runner;
+    ProjectExplorer::DeviceUsedPortsGatherer * m_portsGatherer;
     Debugger::DebuggerEngine *m_engine;
     int m_port;
 
diff --git a/src/plugins/qnx/qnxruncontrol.cpp b/src/plugins/qnx/qnxruncontrol.cpp
index 187317fe118..f3cb262c56e 100644
--- a/src/plugins/qnx/qnxruncontrol.cpp
+++ b/src/plugins/qnx/qnxruncontrol.cpp
@@ -32,21 +32,22 @@
 **************************************************************************/
 
 #include "qnxruncontrol.h"
-#include "qnxapplicationrunner.h"
 #include "qnxrunconfiguration.h"
+#include "qnxutils.h"
 
 #include <projectexplorer/runconfiguration.h>
+#include <remotelinux/remotelinuxrunconfiguration.h>
 
 using namespace Qnx;
 using namespace Qnx::Internal;
+using namespace RemoteLinux;
 
 QnxRunControl::QnxRunControl(ProjectExplorer::RunConfiguration *runConfig)
-    : RemoteLinux::AbstractRemoteLinuxRunControl(runConfig)
-    , m_runner(new QnxApplicationRunner(qobject_cast<QnxRunConfiguration *>(runConfig), this))
+        : RemoteLinuxRunControl(runConfig)
 {
-}
-
-RemoteLinux::AbstractRemoteLinuxApplicationRunner *QnxRunControl::runner() const
-{
-    return m_runner;
+    const RemoteLinuxRunConfiguration * const rc
+            = qobject_cast<RemoteLinuxRunConfiguration *>(runConfig);
+    QString executable = rc->remoteExecutableFilePath();
+    executable.replace(QLatin1String("/"), QLatin1String("\\/"));
+    overrideStopCommandLine(QnxUtils::applicationKillCommand(executable).toUtf8());
 }
diff --git a/src/plugins/qnx/qnxruncontrol.h b/src/plugins/qnx/qnxruncontrol.h
index f96ac525d09..d90b27debfe 100644
--- a/src/plugins/qnx/qnxruncontrol.h
+++ b/src/plugins/qnx/qnxruncontrol.h
@@ -39,18 +39,11 @@
 namespace Qnx {
 namespace Internal {
 
-class QnxApplicationRunner;
-
-class QnxRunControl : public RemoteLinux::AbstractRemoteLinuxRunControl
+class QnxRunControl : public RemoteLinux::RemoteLinuxRunControl
 {
     Q_OBJECT
 public:
     explicit QnxRunControl(ProjectExplorer::RunConfiguration *runConfig);
-
-    RemoteLinux::AbstractRemoteLinuxApplicationRunner *runner() const;
-
-private:
-    QnxApplicationRunner * const m_runner;
 };
 
 } // namespace Internal
diff --git a/src/plugins/qnx/qnxutils.cpp b/src/plugins/qnx/qnxutils.cpp
index 4ef95137c97..d96b50649a0 100644
--- a/src/plugins/qnx/qnxutils.cpp
+++ b/src/plugins/qnx/qnxutils.cpp
@@ -75,3 +75,11 @@ QStringList QnxUtils::searchPaths(QnxAbstractQtVersion *qtVersion)
 
     return searchPaths;
 }
+
+QString QnxUtils::applicationKillCommand(const QString &applicationFilePath)
+{
+    return QString::fromLatin1("for PID in $(ps -f -o pid,comm | grep %1 | awk '/%1/ {print $1}'); "
+            "do "
+            "kill $PID; sleep 1; kill -9 $PID; "
+            "done").arg(applicationFilePath);
+}
diff --git a/src/plugins/qnx/qnxutils.h b/src/plugins/qnx/qnxutils.h
index 1195f87c579..82d63de8413 100644
--- a/src/plugins/qnx/qnxutils.h
+++ b/src/plugins/qnx/qnxutils.h
@@ -49,6 +49,7 @@ public:
     static QString addQuotes(const QString &string);
     static Qnx::QnxArchitecture cpudirToArch(const QString &cpuDir);
     static QStringList searchPaths(QnxAbstractQtVersion *qtVersion);
+    static QString applicationKillCommand(const QString &applicationFilePath);
 };
 
 } // namespace Internal
diff --git a/src/plugins/remotelinux/remotelinux.pro b/src/plugins/remotelinux/remotelinux.pro
index 898f7cdf456..ed18ddd839f 100644
--- a/src/plugins/remotelinux/remotelinux.pro
+++ b/src/plugins/remotelinux/remotelinux.pro
@@ -17,7 +17,6 @@ HEADERS += \
     genericlinuxdeviceconfigurationfactory.h \
     remotelinuxrunconfigurationwidget.h \
     remotelinuxrunconfigurationfactory.h \
-    remotelinuxapplicationrunner.h \
     remotelinuxruncontrol.h \
     remotelinuxruncontrolfactory.h \
     remotelinuxdebugsupport.h \
@@ -65,7 +64,6 @@ SOURCES += \
     genericlinuxdeviceconfigurationfactory.cpp \
     remotelinuxrunconfigurationwidget.cpp \
     remotelinuxrunconfigurationfactory.cpp \
-    remotelinuxapplicationrunner.cpp \
     remotelinuxruncontrol.cpp \
     remotelinuxruncontrolfactory.cpp \
     remotelinuxdebugsupport.cpp \
diff --git a/src/plugins/remotelinux/remotelinux.qbs b/src/plugins/remotelinux/remotelinux.qbs
index 2236fe1511b..7c353ea2fcf 100644
--- a/src/plugins/remotelinux/remotelinux.qbs
+++ b/src/plugins/remotelinux/remotelinux.qbs
@@ -64,8 +64,6 @@ QtcPlugin {
         "remotelinux.qrc",
         "remotelinux_constants.h",
         "remotelinux_export.h",
-        "remotelinuxapplicationrunner.cpp",
-        "remotelinuxapplicationrunner.h",
         "remotelinuxcustomcommanddeploymentstep.h",
         "remotelinuxcustomcommanddeployservice.cpp",
         "remotelinuxcustomcommanddeployservice.h",
diff --git a/src/plugins/remotelinux/remotelinuxapplicationrunner.cpp b/src/plugins/remotelinux/remotelinuxapplicationrunner.cpp
deleted file mode 100644
index 1d73d77cf56..00000000000
--- a/src/plugins/remotelinux/remotelinuxapplicationrunner.cpp
+++ /dev/null
@@ -1,508 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: http://www.qt-project.org/
-**
-** 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.
-**
-** 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.
-**
-**
-**************************************************************************/
-
-#include "remotelinuxapplicationrunner.h"
-
-#include "linuxdeviceconfiguration.h"
-#include "remotelinuxrunconfiguration.h"
-
-#include <projectexplorer/target.h>
-#include <projectexplorer/profileinformation.h>
-#include <projectexplorer/devicesupport/deviceusedportsgatherer.h>
-
-#include <utils/portlist.h>
-#include <utils/qtcassert.h>
-#include <ssh/sshconnection.h>
-#include <ssh/sshconnectionmanager.h>
-#include <ssh/sshremoteprocess.h>
-
-#include <limits>
-
-using namespace ProjectExplorer;
-using namespace QSsh;
-using namespace Utils;
-
-namespace RemoteLinux {
-namespace Internal {
-namespace {
-
-enum State {
-    Inactive, SettingUpDevice, Connecting, PreRunCleaning, AdditionalPreRunCleaning,
-    GatheringPorts, AdditionalInitializing, ReadyForExecution, ProcessStarting, ProcessStarted,
-    PostRunCleaning
-};
-
-} // anonymous namespace
-
-class AbstractRemoteLinuxApplicationRunnerPrivate
-{
-public:
-    AbstractRemoteLinuxApplicationRunnerPrivate(const RemoteLinuxRunConfiguration *runConfig)
-        : devConfig(DeviceProfileInformation::device(runConfig->target()->profile())),
-          remoteExecutable(runConfig->remoteExecutableFilePath()),
-          appArguments(runConfig->arguments()),
-          commandPrefix(runConfig->commandPrefix()),
-          initialFreePorts(devConfig->freePorts()),
-          connection(0),
-          stopRequested(false),
-          state(Inactive)
-    { }
-
-    DeviceUsedPortsGatherer portsGatherer;
-    IDevice::ConstPtr devConfig;
-    const QString remoteExecutable;
-    const QString appArguments;
-    const QString commandPrefix;
-    const PortList initialFreePorts;
-
-    QSsh::SshConnection *connection;
-    QSsh::SshRemoteProcess::Ptr runner;
-    QSsh::SshRemoteProcess::Ptr cleaner;
-
-    PortList freePorts;
-    int exitStatus;
-    bool stopRequested;
-    State state;
-
-};
-} // namespace Internal
-
-
-using namespace Internal;
-
-AbstractRemoteLinuxApplicationRunner::AbstractRemoteLinuxApplicationRunner(RemoteLinuxRunConfiguration *runConfig,
-        QObject *parent)
-    : QObject(parent), d(new AbstractRemoteLinuxApplicationRunnerPrivate(runConfig))
-{
-    connect(&d->portsGatherer, SIGNAL(error(QString)), SLOT(handlePortsGathererError(QString)));
-    connect(&d->portsGatherer, SIGNAL(portListReady()), SLOT(handleUsedPortsAvailable()));
-}
-
-AbstractRemoteLinuxApplicationRunner::~AbstractRemoteLinuxApplicationRunner()
-{
-    delete d;
-}
-
-SshConnection *AbstractRemoteLinuxApplicationRunner::connection() const
-{
-    return d->connection;
-}
-
-IDevice::ConstPtr AbstractRemoteLinuxApplicationRunner::devConfig() const
-{
-    return d->devConfig;
-}
-
-DeviceUsedPortsGatherer *AbstractRemoteLinuxApplicationRunner::usedPortsGatherer() const
-{
-    return &d->portsGatherer;
-}
-
-PortList *AbstractRemoteLinuxApplicationRunner::freePorts()
-{
-    return &d->freePorts;
-}
-
-QString AbstractRemoteLinuxApplicationRunner::remoteExecutable() const
-{
-    return d->remoteExecutable;
-}
-
-QString AbstractRemoteLinuxApplicationRunner::arguments() const
-{
-    return d->appArguments;
-}
-
-QString AbstractRemoteLinuxApplicationRunner::commandPrefix() const
-{
-    return d->commandPrefix;
-}
-
-void AbstractRemoteLinuxApplicationRunner::start()
-{
-    QTC_ASSERT(!d->stopRequested && d->state == Inactive, return);
-
-    QString errorMsg;
-    if (!canRun(errorMsg)) {
-        emitError(tr("Cannot run: %1").arg(errorMsg), true);
-        return;
-    }
-
-    d->state = SettingUpDevice;
-    doDeviceSetup();
-}
-
-void AbstractRemoteLinuxApplicationRunner::stop()
-{
-    if (d->stopRequested)
-        return;
-
-    switch (d->state) {
-    case Connecting:
-        setInactive();
-        emit remoteProcessFinished(InvalidExitCode);
-        break;
-    case GatheringPorts:
-        d->portsGatherer.stop();
-        setInactive();
-        emit remoteProcessFinished(InvalidExitCode);
-        break;
-    case SettingUpDevice:
-    case PreRunCleaning:
-    case AdditionalPreRunCleaning:
-    case AdditionalInitializing:
-    case ProcessStarting:
-    case PostRunCleaning:
-        d->stopRequested = true; // TODO: We might need stopPreRunCleaning() etc. for the subclasses
-        break;
-    case ReadyForExecution:
-        d->stopRequested = true;
-        d->state = PostRunCleaning;
-        doPostRunCleanup();
-        break;
-    case ProcessStarted:
-        d->stopRequested = true;
-        cleanup();
-        break;
-    case Inactive:
-        break;
-    }
-}
-
-void AbstractRemoteLinuxApplicationRunner::handleConnected()
-{
-    QTC_ASSERT(d->state == Connecting, return);
-
-    if (d->stopRequested) {
-        emit remoteProcessFinished(InvalidExitCode);
-        setInactive();
-    } else {
-        d->state = PreRunCleaning;
-        cleanup();
-    }
-}
-
-void AbstractRemoteLinuxApplicationRunner::handleConnectionFailure()
-{
-    QTC_ASSERT(d->state != Inactive, return);
-
-    if (d->state != Connecting || d->state != PreRunCleaning)
-        doAdditionalConnectionErrorHandling();
-
-    const QString errorMsg = d->state == Connecting
-        ? tr("Could not connect to host: %1") : tr("Connection error: %1");
-    emitError(errorMsg.arg(d->connection->errorString()));
-}
-
-void AbstractRemoteLinuxApplicationRunner::cleanup()
-{
-    QTC_ASSERT(d->state == PreRunCleaning
-        || (d->state == ProcessStarted && d->stopRequested), return);
-
-    emit reportProgress(tr("Killing remote process(es)..."));
-    d->cleaner = d->connection->createRemoteProcess(killApplicationCommandLine().toUtf8());
-    connect(d->cleaner.data(), SIGNAL(closed(int)), SLOT(handleCleanupFinished(int)));
-    d->cleaner->start();
-}
-
-void AbstractRemoteLinuxApplicationRunner::handleCleanupFinished(int exitStatus)
-{
-    Q_ASSERT(exitStatus == SshRemoteProcess::FailedToStart
-        || exitStatus == SshRemoteProcess::CrashExit
-        || exitStatus == SshRemoteProcess::NormalExit);
-
-    QTC_ASSERT(d->state == PreRunCleaning
-        || (d->state == ProcessStarted && d->stopRequested) || d->state == Inactive, return);
-
-    if (d->state == Inactive)
-        return;
-    if (d->stopRequested && d->state == PreRunCleaning) {
-        setInactive();
-        emit remoteProcessFinished(InvalidExitCode);
-        return;
-    }
-    if (d->stopRequested) {
-        d->state = PostRunCleaning;
-        doPostRunCleanup();
-        return;
-    }
-
-    if (exitStatus != SshRemoteProcess::NormalExit) {
-        emitError(tr("Initial cleanup failed: %1").arg(d->cleaner->errorString()));
-        emit remoteProcessFinished(InvalidExitCode);
-        return;
-    }
-
-    d->state = AdditionalPreRunCleaning;
-    doAdditionalInitialCleanup();
-}
-
-void AbstractRemoteLinuxApplicationRunner::startExecution(const QByteArray &remoteCall)
-{
-    QTC_ASSERT(d->state == ReadyForExecution, return);
-
-    if (d->stopRequested)
-        return;
-
-    d->runner = d->connection->createRemoteProcess(remoteCall);
-    connect(d->runner.data(), SIGNAL(started()), SLOT(handleRemoteProcessStarted()));
-    connect(d->runner.data(), SIGNAL(closed(int)), SLOT(handleRemoteProcessFinished(int)));
-    connect(d->runner.data(), SIGNAL(readyReadStandardOutput()), SLOT(handleRemoteStdout()));
-    connect(d->runner.data(), SIGNAL(readyReadStandardError()), SLOT(handleRemoteStderr()));
-    d->state = ProcessStarting;
-    d->runner->start();
-}
-
-void AbstractRemoteLinuxApplicationRunner::handleRemoteProcessStarted()
-{
-    QTC_ASSERT(d->state == ProcessStarting, return);
-
-    d->state = ProcessStarted;
-    if (d->stopRequested) {
-        cleanup();
-        return;
-    }
-
-    emit reportProgress(tr("Remote process started."));
-    emit remoteProcessStarted();
-}
-
-void AbstractRemoteLinuxApplicationRunner::handleRemoteProcessFinished(int exitStatus)
-{
-    Q_ASSERT(exitStatus == SshRemoteProcess::FailedToStart
-        || exitStatus == SshRemoteProcess::CrashExit
-        || exitStatus == SshRemoteProcess::NormalExit);
-    QTC_ASSERT(d->state == ProcessStarted || d->state == Inactive, return);
-
-    d->exitStatus = exitStatus;
-    if (!d->stopRequested && d->state != Inactive) {
-        d->state = PostRunCleaning;
-        doPostRunCleanup();
-    }
-}
-
-void AbstractRemoteLinuxApplicationRunner::setInactive()
-{
-    d->portsGatherer.stop();
-    if (d->connection) {
-        disconnect(d->connection, 0, this, 0);
-        SshConnectionManager::instance().releaseConnection(d->connection);
-        d->connection = 0;
-    }
-    if (d->cleaner)
-        disconnect(d->cleaner.data(), 0, this, 0);
-    d->stopRequested = false;
-    d->state = Inactive;
-}
-
-void AbstractRemoteLinuxApplicationRunner::emitError(const QString &errorMsg, bool force)
-{
-    if (d->state != Inactive) {
-        setInactive();
-        emit error(errorMsg);
-    } else if (force) {
-        emit error(errorMsg);
-    }
-}
-
-void AbstractRemoteLinuxApplicationRunner::handlePortsGathererError(const QString &errorMsg)
-{
-    if (d->state != Inactive) {
-        if (connection()->errorState() != SshNoError) {
-            emitError(errorMsg);
-        } else {
-            emit reportProgress(tr("Gathering ports failed: %1\nContinuing anyway.").arg(errorMsg));
-            handleUsedPortsAvailable();
-        }
-    }
-}
-
-void AbstractRemoteLinuxApplicationRunner::handleUsedPortsAvailable()
-{
-    QTC_ASSERT(d->state == GatheringPorts, return);
-
-    if (d->stopRequested) {
-        setInactive();
-        emit remoteProcessFinished(InvalidExitCode);
-        return;
-    }
-
-    d->state = AdditionalInitializing;
-    doAdditionalInitializations();
-}
-
-void AbstractRemoteLinuxApplicationRunner::handleRemoteStdout()
-{
-    emit remoteOutput(d->runner->readAllStandardOutput());
-}
-
-void AbstractRemoteLinuxApplicationRunner::handleRemoteStderr()
-{
-    emit remoteErrorOutput(d->runner->readAllStandardError());
-}
-
-bool AbstractRemoteLinuxApplicationRunner::canRun(QString &whyNot) const
-{
-    if (d->remoteExecutable.isEmpty()) {
-        whyNot = tr("No remote executable set.");
-        return false;
-    }
-
-    if (!d->devConfig) {
-        whyNot = tr("No device configuration set.");
-        return false;
-    }
-
-    return true;
-}
-
-void AbstractRemoteLinuxApplicationRunner::handleDeviceSetupDone(bool success)
-{
-    QTC_ASSERT(d->state == SettingUpDevice, return);
-
-    if (!success || d->stopRequested) {
-        setInactive();
-        emit remoteProcessFinished(InvalidExitCode);
-        return;
-    }
-
-    d->connection = SshConnectionManager::instance().acquireConnection(d->devConfig->sshParameters());
-    d->state = Connecting;
-    d->exitStatus = -1;
-    d->freePorts = d->initialFreePorts;
-    connect(d->connection, SIGNAL(connected()), SLOT(handleConnected()));
-    connect(d->connection, SIGNAL(error(QSsh::SshError)),
-        SLOT(handleConnectionFailure()));
-    if (d->connection->state() == SshConnection::Connected) {
-        handleConnected();
-    } else {
-        emit reportProgress(tr("Connecting to device..."));
-        if (d->connection->state() == QSsh::SshConnection::Unconnected)
-            d->connection->connectToHost();
-    }
-}
-
-void AbstractRemoteLinuxApplicationRunner::handleInitialCleanupDone(bool success)
-{
-    QTC_ASSERT(d->state == AdditionalPreRunCleaning, return);
-
-    if (!success || d->stopRequested) {
-        setInactive();
-        emit remoteProcessFinished(InvalidExitCode);
-        return;
-    }
-
-    d->state = GatheringPorts;
-    d->portsGatherer.start(d->devConfig);
-}
-
-void AbstractRemoteLinuxApplicationRunner::handleInitializationsDone(bool success)
-{
-    QTC_ASSERT(d->state == AdditionalInitializing, return);
-
-    if (!success) {
-        setInactive();
-        emit remoteProcessFinished(InvalidExitCode);
-        return;
-    }
-    if (d->stopRequested) {
-        d->state = PostRunCleaning;
-        doPostRunCleanup();
-        return;
-    }
-
-    d->state = ReadyForExecution;
-    emit readyForExecution();
-}
-
-void AbstractRemoteLinuxApplicationRunner::handlePostRunCleanupDone()
-{
-    QTC_ASSERT(d->state == PostRunCleaning, return);
-
-    const bool wasStopRequested = d->stopRequested;
-    setInactive();
-    if (wasStopRequested)
-        emit remoteProcessFinished(InvalidExitCode);
-    else if (d->exitStatus == SshRemoteProcess::NormalExit)
-        emit remoteProcessFinished(d->runner->exitCode());
-    else
-        emit error(tr("Error running remote process: %1").arg(d->runner->errorString()));
-}
-
-QString AbstractRemoteLinuxApplicationRunner::killApplicationCommandLine() const
-{
-    return QString::fromLatin1("cd /proc; for pid in `ls -d [0123456789]*`; "
-        "do "
-            "if [ \"`readlink /proc/$pid/exe`\" = \"%1\" ]; then "
-            "    kill $pid; sleep 1; kill -9 $pid; "
-            "fi; "
-        "done").arg(remoteExecutable());
-}
-
-
-const qint64 AbstractRemoteLinuxApplicationRunner::InvalidExitCode = std::numeric_limits<qint64>::min();
-
-
-GenericRemoteLinuxApplicationRunner::GenericRemoteLinuxApplicationRunner(RemoteLinuxRunConfiguration *runConfig,
-        QObject *parent)
-    : AbstractRemoteLinuxApplicationRunner(runConfig, parent)
-{
-}
-
-GenericRemoteLinuxApplicationRunner::~GenericRemoteLinuxApplicationRunner()
-{
-}
-
-
-void GenericRemoteLinuxApplicationRunner::doDeviceSetup()
-{
-    handleDeviceSetupDone(true);
-}
-
-void GenericRemoteLinuxApplicationRunner::doAdditionalInitialCleanup()
-{
-    handleInitialCleanupDone(true);
-}
-
-void GenericRemoteLinuxApplicationRunner::doAdditionalInitializations()
-{
-    handleInitializationsDone(true);
-}
-
-void GenericRemoteLinuxApplicationRunner::doPostRunCleanup()
-{
-    handlePostRunCleanupDone();
-}
-
-void GenericRemoteLinuxApplicationRunner::doAdditionalConnectionErrorHandling()
-{
-}
-
-} // namespace RemoteLinux
-
diff --git a/src/plugins/remotelinux/remotelinuxapplicationrunner.h b/src/plugins/remotelinux/remotelinuxapplicationrunner.h
deleted file mode 100644
index 1b0d850bca5..00000000000
--- a/src/plugins/remotelinux/remotelinuxapplicationrunner.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: http://www.qt-project.org/
-**
-** 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.
-**
-** 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.
-**
-**
-**************************************************************************/
-
-#ifndef REMOTELINUXAPPLICATIONRUNNER_H
-#define REMOTELINUXAPPLICATIONRUNNER_H
-
-#include "remotelinux_export.h"
-
-#include <projectexplorer/devicesupport/idevice.h>
-#include <projectexplorer/devicesupport/deviceusedportsgatherer.h>
-
-namespace QSsh { class SshConnection; }
-namespace Utils { class PortList; }
-
-namespace RemoteLinux {
-class RemoteLinuxRunConfiguration;
-
-namespace Internal { class AbstractRemoteLinuxApplicationRunnerPrivate; }
-
-class REMOTELINUX_EXPORT AbstractRemoteLinuxApplicationRunner : public QObject
-{
-    Q_OBJECT
-    Q_DISABLE_COPY(AbstractRemoteLinuxApplicationRunner)
-public:
-    AbstractRemoteLinuxApplicationRunner(RemoteLinuxRunConfiguration *runConfig,
-        QObject *parent = 0);
-    ~AbstractRemoteLinuxApplicationRunner();
-
-    void start();
-    void stop();
-
-    void startExecution(const QByteArray &remoteCall);
-
-    ProjectExplorer::IDevice::ConstPtr devConfig() const;
-    QSsh::SshConnection *connection() const;
-    ProjectExplorer::DeviceUsedPortsGatherer *usedPortsGatherer() const;
-    Utils::PortList *freePorts();
-    QString remoteExecutable() const;
-    QString arguments() const;
-    QString commandPrefix() const;
-
-    static const qint64 InvalidExitCode;
-
-signals:
-    void error(const QString &error);
-    void readyForExecution();
-    void remoteOutput(const QByteArray &output);
-    void remoteErrorOutput(const QByteArray &output);
-    void reportProgress(const QString &progressOutput);
-    void remoteProcessStarted();
-    void remoteProcessFinished(qint64 exitCode);
-
-protected:
-    // Override to to additional checks.
-    virtual bool canRun(QString &whyNot) const;
-
-    void handleDeviceSetupDone(bool success);
-    void handleInitialCleanupDone(bool success);
-    void handleInitializationsDone(bool success);
-    void handlePostRunCleanupDone();
-
-private slots:
-    void handleConnected();
-    void handleConnectionFailure();
-    void handleCleanupFinished(int exitStatus);
-    void handleRemoteProcessStarted();
-    void handleRemoteProcessFinished(int exitStatus);
-    void handlePortsGathererError(const QString &errorMsg);
-    void handleUsedPortsAvailable();
-    void handleRemoteStdout();
-    void handleRemoteStderr();
-
-private:
-
-    virtual QString killApplicationCommandLine() const;
-
-    // Implement to do custom setup of the device *before* connecting.
-    // Call handleDeviceSetupDone() afterwards.
-    virtual void doDeviceSetup() = 0;
-
-    // Implement to do additional pre-run cleanup and call handleInitialCleanupDone().
-    virtual void doAdditionalInitialCleanup() = 0;
-
-    // Implement to do additional initializations right before the application is ready.
-    // Call handleInitializationsDone() afterwards.
-    virtual void doAdditionalInitializations() = 0;
-
-    // Implement to do cleanups after application exit and call handlePostRunCleanupDone();
-    virtual void doPostRunCleanup() = 0;
-
-    virtual void doAdditionalConnectionErrorHandling() = 0;
-
-    void setInactive();
-    void emitError(const QString &errorMsg, bool force = false);
-    void cleanup();
-
-    Internal::AbstractRemoteLinuxApplicationRunnerPrivate * const d;
-};
-
-
-class REMOTELINUX_EXPORT GenericRemoteLinuxApplicationRunner : public AbstractRemoteLinuxApplicationRunner
-{
-    Q_OBJECT
-public:
-    GenericRemoteLinuxApplicationRunner(RemoteLinuxRunConfiguration *runConfig,
-        QObject *parent = 0);
-    ~GenericRemoteLinuxApplicationRunner();
-
-protected:
-    void doDeviceSetup();
-    void doAdditionalInitialCleanup();
-    void doAdditionalInitializations();
-    void doPostRunCleanup();
-    void doAdditionalConnectionErrorHandling();
-};
-
-} // namespace RemoteLinux
-
-#endif // REMOTELINUXAPPLICATIONRUNNER_H
diff --git a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp
index 30dd23fe660..e9d299db943 100644
--- a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp
+++ b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp
@@ -29,8 +29,8 @@
 
 #include "remotelinuxdebugsupport.h"
 
-#include "remotelinuxapplicationrunner.h"
 #include "remotelinuxrunconfiguration.h"
+#include "remotelinuxutils.h"
 
 #include <debugger/debuggerengine.h>
 #include <debugger/debuggerstartparameters.h>
@@ -42,6 +42,8 @@
 #include <projectexplorer/project.h>
 #include <projectexplorer/target.h>
 #include <projectexplorer/toolchain.h>
+#include <projectexplorer/devicesupport/deviceapplicationrunner.h>
+#include <utils/portlist.h>
 #include <utils/qtcassert.h>
 
 #include <QPointer>
@@ -54,19 +56,23 @@ using namespace ProjectExplorer;
 namespace RemoteLinux {
 namespace Internal {
 namespace {
-enum State { Inactive, StartingRunner, StartingRemoteProcess, Debugging };
+enum State { Inactive, GatheringPorts, StartingRunner, Debugging };
 } // anonymous namespace
 
-class AbstractRemoteLinuxDebugSupportPrivate
+class LinuxDeviceDebugSupportPrivate
 {
 public:
-    AbstractRemoteLinuxDebugSupportPrivate(RunConfiguration *runConfig,
+    LinuxDeviceDebugSupportPrivate(const RemoteLinuxRunConfiguration *runConfig,
             DebuggerEngine *engine)
         : engine(engine),
           qmlDebugging(runConfig->debuggerAspect()->useQmlDebugger()),
           cppDebugging(runConfig->debuggerAspect()->useCppDebugger()),
           state(Inactive),
-          gdbServerPort(-1), qmlPort(-1)
+          gdbServerPort(-1), qmlPort(-1),
+          device(DeviceProfileInformation::device(runConfig->target()->profile())),
+          remoteFilePath(runConfig->remoteExecutableFilePath()),
+          arguments(runConfig->arguments()),
+          commandPrefix(runConfig->commandPrefix())
     {
     }
 
@@ -77,21 +83,20 @@ public:
     State state;
     int gdbServerPort;
     int qmlPort;
-};
-
-class RemoteLinuxDebugSupportPrivate
-{
-public:
-    RemoteLinuxDebugSupportPrivate(RemoteLinuxRunConfiguration *runConfig) : runner(runConfig) {}
-
-    GenericRemoteLinuxApplicationRunner runner;
+    DeviceApplicationRunner appRunner;
+    DeviceUsedPortsGatherer portsGatherer;
+    const ProjectExplorer::IDevice::ConstPtr device;
+    Utils::PortList portList;
+    const QString remoteFilePath;
+    const QString arguments;
+    const QString commandPrefix;
 };
 
 } // namespace Internal
 
 using namespace Internal;
 
-DebuggerStartParameters AbstractRemoteLinuxDebugSupport::startParameters(const RemoteLinuxRunConfiguration *runConfig)
+DebuggerStartParameters LinuxDeviceDebugSupport::startParameters(const RemoteLinuxRunConfiguration *runConfig)
 {
     DebuggerStartParameters params;
     Target *target = runConfig->target();
@@ -130,92 +135,101 @@ DebuggerStartParameters AbstractRemoteLinuxDebugSupport::startParameters(const R
     return params;
 }
 
-AbstractRemoteLinuxDebugSupport::AbstractRemoteLinuxDebugSupport(RunConfiguration *runConfig,
+LinuxDeviceDebugSupport::LinuxDeviceDebugSupport(RunConfiguration *runConfig,
         DebuggerEngine *engine)
-    : QObject(engine), d(new AbstractRemoteLinuxDebugSupportPrivate(runConfig, engine))
+    : QObject(engine),
+      d(new LinuxDeviceDebugSupportPrivate(static_cast<RemoteLinuxRunConfiguration *>(runConfig), engine))
 {
     connect(d->engine, SIGNAL(requestRemoteSetup()), this, SLOT(handleRemoteSetupRequested()));
 }
 
-AbstractRemoteLinuxDebugSupport::~AbstractRemoteLinuxDebugSupport()
+LinuxDeviceDebugSupport::~LinuxDeviceDebugSupport()
 {
     setFinished();
     delete d;
 }
 
-void AbstractRemoteLinuxDebugSupport::showMessage(const QString &msg, int channel)
+void LinuxDeviceDebugSupport::setApplicationRunnerPreRunAction(DeviceApplicationHelperAction *action)
 {
-    if (d->engine)
+    d->appRunner.setPreRunAction(action);
+}
+
+void LinuxDeviceDebugSupport::setApplicationRunnerPostRunAction(DeviceApplicationHelperAction *action)
+{
+    d->appRunner.setPostRunAction(action);
+}
+
+void LinuxDeviceDebugSupport::showMessage(const QString &msg, int channel)
+{
+    if (d->state != Inactive && d->engine)
         d->engine->showMessage(msg, channel);
 }
 
-void AbstractRemoteLinuxDebugSupport::handleRemoteSetupRequested()
+void LinuxDeviceDebugSupport::handleRemoteSetupRequested()
 {
     QTC_ASSERT(d->state == Inactive, return);
 
-    d->state = StartingRunner;
-    showMessage(tr("Preparing remote side...\n"), AppStuff);
-    disconnect(runner(), 0, this, 0);
-    connect(runner(), SIGNAL(error(QString)), this, SLOT(handleSshError(QString)));
-    connect(runner(), SIGNAL(readyForExecution()), this, SLOT(startExecution()));
-    connect(runner(), SIGNAL(reportProgress(QString)), this, SLOT(handleProgressReport(QString)));
-    runner()->start();
+    d->state = GatheringPorts;
+    showMessage(tr("Checking available ports...\n"), LogStatus);
+    connect(&d->portsGatherer, SIGNAL(error(QString)), SLOT(handlePortsGathererError(QString)));
+    connect(&d->portsGatherer, SIGNAL(portListReady()), SLOT(handlePortListReady()));
+    d->portsGatherer.start(d->device);
 }
 
-void AbstractRemoteLinuxDebugSupport::handleSshError(const QString &error)
+void LinuxDeviceDebugSupport::handlePortsGathererError(const QString &message)
 {
-    if (d->state == Debugging) {
-        showMessage(error, AppError);
-        if (d->engine)
-            d->engine->notifyInferiorIll();
-    } else if (d->state != Inactive) {
-        handleAdapterSetupFailed(error);
-    }
+    QTC_ASSERT(d->state == GatheringPorts, return);
+    handleAdapterSetupFailed(message);
 }
 
-void AbstractRemoteLinuxDebugSupport::startExecution()
+void LinuxDeviceDebugSupport::handlePortListReady()
 {
-    if (d->state == Inactive)
-        return;
+    QTC_ASSERT(d->state == GatheringPorts, return);
 
-    QTC_ASSERT(d->state == StartingRunner, return);
+    d->portList = d->device->freePorts();
+    startExecution();
+}
+
+void LinuxDeviceDebugSupport::startExecution()
+{
+    QTC_ASSERT(d->state == GatheringPorts, return);
 
     if (d->cppDebugging && !setPort(d->gdbServerPort))
         return;
     if (d->qmlDebugging && !setPort(d->qmlPort))
             return;
 
-    d->state = StartingRemoteProcess;
+    d->state = StartingRunner;
     d->gdbserverOutput.clear();
-    connect(runner(), SIGNAL(remoteErrorOutput(QByteArray)), this,
-        SLOT(handleRemoteErrorOutput(QByteArray)));
-    connect(runner(), SIGNAL(remoteOutput(QByteArray)), this,
-        SLOT(handleRemoteOutput(QByteArray)));
-    if (d->qmlDebugging && !d->cppDebugging) {
-        connect(runner(), SIGNAL(remoteProcessStarted()),
-            SLOT(handleRemoteProcessStarted()));
-    }
-    const QString &remoteExe = runner()->remoteExecutable();
-    QString args = runner()->arguments();
-    if (d->qmlDebugging) {
-        args += QString::fromLatin1(" -qmljsdebugger=port:%1,block")
-            .arg(d->qmlPort);
-    }
 
-    const QHostAddress peerAddress = runner()->connection()->connectionInfo().peerAddress;
-    QString peerAddressString = peerAddress.toString();
-    if (peerAddress.protocol() == QAbstractSocket::IPv6Protocol)
-        peerAddressString.prepend(QLatin1Char('[')).append(QLatin1Char(']'));
+    connect(&d->appRunner, SIGNAL(remoteStderr(QByteArray)),
+            SLOT(handleRemoteErrorOutput(QByteArray)));
+    connect(&d->appRunner, SIGNAL(remoteStdout(QByteArray)), SLOT(handleRemoteOutput(QByteArray)));
+    if (d->qmlDebugging && !d->cppDebugging)
+        connect(&d->appRunner, SIGNAL(remoteProcessStarted()), SLOT(handleRemoteProcessStarted()));
+    QString args = d->arguments;
+    if (d->qmlDebugging)
+        args += QString::fromLocal8Bit(" -qmljsdebugger=port:%1,block").arg(d->qmlPort);
     const QString remoteCommandLine = (d->qmlDebugging && !d->cppDebugging)
-        ? QString::fromLatin1("%1 %2 %3").arg(runner()->commandPrefix()).arg(remoteExe).arg(args)
-        : QString::fromLatin1("%1 gdbserver %5:%2 %3 %4").arg(runner()->commandPrefix())
-              .arg(d->gdbServerPort).arg(remoteExe).arg(args).arg(peerAddressString);
-    connect(runner(), SIGNAL(remoteProcessFinished(qint64)),
-        SLOT(handleRemoteProcessFinished(qint64)));
-    runner()->startExecution(remoteCommandLine.toUtf8());
+        ? QString::fromLatin1("%1 %2 %3").arg(d->commandPrefix).arg(d->remoteFilePath).arg(args)
+        : QString::fromLatin1("%1 gdbserver :%2 %3 %4").arg(d->commandPrefix)
+              .arg(d->gdbServerPort).arg(d->remoteFilePath).arg(args);
+    connect(&d->appRunner, SIGNAL(finished(bool)), SLOT(handleAppRunnerFinished(bool)));
+    d->appRunner.start(d->device, remoteCommandLine.toUtf8());
 }
 
-void AbstractRemoteLinuxDebugSupport::handleRemoteProcessFinished(qint64 exitCode)
+void LinuxDeviceDebugSupport::handleAppRunnerError(const QString &error)
+{
+    if (d->state == Debugging) {
+        showMessage(error, AppError);
+        if (d->engine)
+            d->engine->notifyInferiorIll();
+    } else if (d->state != Inactive) {
+        handleAdapterSetupFailed(error);
+    }
+}
+
+void LinuxDeviceDebugSupport::handleAppRunnerFinished(bool success)
 {
     if (!d->engine || d->state == Inactive)
         return;
@@ -224,39 +238,35 @@ void AbstractRemoteLinuxDebugSupport::handleRemoteProcessFinished(qint64 exitCod
         // The QML engine does not realize on its own that the application has finished.
         if (d->qmlDebugging && !d->cppDebugging)
             d->engine->quitDebugger();
-        else if (exitCode != 0)
+        else if (!success)
             d->engine->notifyInferiorIll();
 
     } else {
-        const QString errorMsg = (d->qmlDebugging && !d->cppDebugging)
-            ? tr("Remote application failed with exit code %1.").arg(exitCode)
-            : tr("The gdbserver process closed unexpectedly.");
-        d->engine->notifyEngineRemoteSetupFailed(errorMsg);
+        d->engine->notifyEngineRemoteSetupFailed(tr("Debugging failed."));
     }
 }
 
-void AbstractRemoteLinuxDebugSupport::handleDebuggingFinished()
+void LinuxDeviceDebugSupport::handleDebuggingFinished()
 {
     setFinished();
 }
 
-void AbstractRemoteLinuxDebugSupport::handleRemoteOutput(const QByteArray &output)
+void LinuxDeviceDebugSupport::handleRemoteOutput(const QByteArray &output)
 {
     QTC_ASSERT(d->state == Inactive || d->state == Debugging, return);
 
     showMessage(QString::fromUtf8(output), AppOutput);
 }
 
-void AbstractRemoteLinuxDebugSupport::handleRemoteErrorOutput(const QByteArray &output)
+void LinuxDeviceDebugSupport::handleRemoteErrorOutput(const QByteArray &output)
 {
-    QTC_ASSERT(d->state == Inactive || d->state == StartingRemoteProcess || d->state == Debugging,
-        return);
+    QTC_ASSERT(d->state != GatheringPorts, return);
 
     if (!d->engine)
         return;
 
-    showMessage(QString::fromUtf8(output), AppOutput);
-    if (d->state == StartingRemoteProcess && d->cppDebugging) {
+    showMessage(QString::fromUtf8(output), AppError);
+    if (d->state == StartingRunner && d->cppDebugging) {
         d->gdbserverOutput += output;
         if (d->gdbserverOutput.contains("Listening on port")) {
             handleAdapterSetupDone();
@@ -265,42 +275,45 @@ void AbstractRemoteLinuxDebugSupport::handleRemoteErrorOutput(const QByteArray &
     }
 }
 
-void AbstractRemoteLinuxDebugSupport::handleProgressReport(const QString &progressOutput)
+void LinuxDeviceDebugSupport::handleProgressReport(const QString &progressOutput)
 {
-    showMessage(progressOutput + QLatin1Char('\n'), AppStuff);
+    showMessage(progressOutput + QLatin1Char('\n'), LogStatus);
 }
 
-void AbstractRemoteLinuxDebugSupport::handleAdapterSetupFailed(const QString &error)
+void LinuxDeviceDebugSupport::handleAdapterSetupFailed(const QString &error)
 {
     setFinished();
     d->engine->notifyEngineRemoteSetupFailed(tr("Initial setup failed: %1").arg(error));
 }
 
-void AbstractRemoteLinuxDebugSupport::handleAdapterSetupDone()
+void LinuxDeviceDebugSupport::handleAdapterSetupDone()
 {
     d->state = Debugging;
     d->engine->notifyEngineRemoteSetupDone(d->gdbServerPort, d->qmlPort);
 }
 
-void AbstractRemoteLinuxDebugSupport::handleRemoteProcessStarted()
+void LinuxDeviceDebugSupport::handleRemoteProcessStarted()
 {
-    Q_ASSERT(d->qmlDebugging && !d->cppDebugging);
-    QTC_ASSERT(d->state == StartingRemoteProcess, return);
+    QTC_ASSERT(d->qmlDebugging && !d->cppDebugging, return);
+    QTC_ASSERT(d->state == StartingRunner, return);
 
     handleAdapterSetupDone();
 }
 
-void AbstractRemoteLinuxDebugSupport::setFinished()
+void LinuxDeviceDebugSupport::setFinished()
 {
     if (d->state == Inactive)
         return;
+    d->portsGatherer.disconnect(this);
+    d->appRunner.disconnect(this);
+    if (d->state == StartingRunner)
+        d->appRunner.stop(RemoteLinuxUtils::killApplicationCommandLine(d->remoteFilePath).toUtf8());
     d->state = Inactive;
-    runner()->stop();
 }
 
-bool AbstractRemoteLinuxDebugSupport::setPort(int &port)
+bool LinuxDeviceDebugSupport::setPort(int &port)
 {
-    port = runner()->usedPortsGatherer()->getNextFreePort(runner()->freePorts());
+    port = d->portsGatherer.getNextFreePort(&d->portList);
     if (port == -1) {
         handleAdapterSetupFailed(tr("Not enough free ports on device for debugging."));
         return false;
@@ -308,22 +321,4 @@ bool AbstractRemoteLinuxDebugSupport::setPort(int &port)
     return true;
 }
 
-
-RemoteLinuxDebugSupport::RemoteLinuxDebugSupport(RemoteLinuxRunConfiguration *runConfig,
-        DebuggerEngine *engine)
-    : AbstractRemoteLinuxDebugSupport(runConfig, engine),
-      d(new RemoteLinuxDebugSupportPrivate(runConfig))
-{
-}
-
-RemoteLinuxDebugSupport::~RemoteLinuxDebugSupport()
-{
-    delete d;
-}
-
-AbstractRemoteLinuxApplicationRunner *RemoteLinuxDebugSupport::runner() const
-{
-    return &d->runner;
-}
-
 } // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/remotelinuxdebugsupport.h b/src/plugins/remotelinux/remotelinuxdebugsupport.h
index cee77a14209..6643835c503 100644
--- a/src/plugins/remotelinux/remotelinuxdebugsupport.h
+++ b/src/plugins/remotelinux/remotelinuxdebugsupport.h
@@ -40,65 +40,49 @@ class DebuggerStartParameters;
 }
 
 namespace ProjectExplorer {
-class RunControl;
+class DeviceApplicationHelperAction;
 class RunConfiguration;
 }
 
 namespace RemoteLinux {
 class RemoteLinuxRunConfiguration;
-class AbstractRemoteLinuxApplicationRunner;
 
-namespace Internal {
-class AbstractRemoteLinuxDebugSupportPrivate;
-class RemoteLinuxDebugSupportPrivate;
-} // namespace Internal
+namespace Internal { class LinuxDeviceDebugSupportPrivate; }
 
-class REMOTELINUX_EXPORT AbstractRemoteLinuxDebugSupport : public QObject
+class REMOTELINUX_EXPORT LinuxDeviceDebugSupport : public QObject
 {
     Q_OBJECT
-    Q_DISABLE_COPY(AbstractRemoteLinuxDebugSupport)
 public:
     static Debugger::DebuggerStartParameters startParameters(const RemoteLinuxRunConfiguration *runConfig);
 
-    AbstractRemoteLinuxDebugSupport(ProjectExplorer::RunConfiguration *runConfig,
-                                    Debugger::DebuggerEngine *engine);
-    ~AbstractRemoteLinuxDebugSupport();
+    LinuxDeviceDebugSupport(ProjectExplorer::RunConfiguration *runConfig,
+            Debugger::DebuggerEngine *engine);
+    ~LinuxDeviceDebugSupport();
+
+    void setApplicationRunnerPreRunAction(ProjectExplorer::DeviceApplicationHelperAction *action);
+    void setApplicationRunnerPostRunAction(ProjectExplorer::DeviceApplicationHelperAction *action);
 
 private slots:
     void handleRemoteSetupRequested();
-    void handleSshError(const QString &error);
+    void handleAppRunnerError(const QString &error);
     void startExecution();
     void handleDebuggingFinished();
     void handleRemoteOutput(const QByteArray &output);
     void handleRemoteErrorOutput(const QByteArray &output);
     void handleProgressReport(const QString &progressOutput);
     void handleRemoteProcessStarted();
-    void handleRemoteProcessFinished(qint64 exitCode);
+    void handleAppRunnerFinished(bool success);
+    void handlePortsGathererError(const QString &message);
+    void handlePortListReady();
 
 private:
-    virtual AbstractRemoteLinuxApplicationRunner *runner() const = 0;
-
     void handleAdapterSetupFailed(const QString &error);
     void handleAdapterSetupDone();
     void setFinished();
     bool setPort(int &port);
     void showMessage(const QString &msg, int channel);
 
-    Internal::AbstractRemoteLinuxDebugSupportPrivate * const d;
-};
-
-
-class REMOTELINUX_EXPORT RemoteLinuxDebugSupport : public AbstractRemoteLinuxDebugSupport
-{
-    Q_OBJECT
-public:
-    RemoteLinuxDebugSupport(RemoteLinuxRunConfiguration *runConfig, Debugger::DebuggerEngine *engine);
-    ~RemoteLinuxDebugSupport();
-
-private:
-    AbstractRemoteLinuxApplicationRunner *runner() const;
-
-    Internal::RemoteLinuxDebugSupportPrivate * const d;
+    Internal::LinuxDeviceDebugSupportPrivate * const d;
 };
 
 } // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/remotelinuxruncontrol.cpp b/src/plugins/remotelinux/remotelinuxruncontrol.cpp
index b550c21331e..3492cf3a731 100644
--- a/src/plugins/remotelinux/remotelinuxruncontrol.cpp
+++ b/src/plugins/remotelinux/remotelinuxruncontrol.cpp
@@ -29,10 +29,13 @@
 
 #include "remotelinuxruncontrol.h"
 
-#include "remotelinuxapplicationrunner.h"
 #include "remotelinuxrunconfiguration.h"
+#include "remotelinuxutils.h"
 
+#include <projectexplorer/devicesupport/deviceapplicationrunner.h>
+#include <projectexplorer/profileinformation.h>
 #include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/target.h>
 #include <utils/qtcassert.h>
 
 #include <QString>
@@ -42,120 +45,112 @@ using namespace ProjectExplorer;
 
 namespace RemoteLinux {
 
-using ProjectExplorer::RunConfiguration;
+class RemoteLinuxRunControl::RemoteLinuxRunControlPrivate
+{
+public:
+    bool running;
+    ProjectExplorer::DeviceApplicationRunner runner;
+    IDevice::ConstPtr device;
+    QString remoteExecutable;
+    QString arguments;
+    QString prefix;
+    QByteArray stopCommand;
+};
 
-AbstractRemoteLinuxRunControl::AbstractRemoteLinuxRunControl(RunConfiguration *rc)
-    : RunControl(rc, ProjectExplorer::NormalRunMode)
-    , m_running(false)
+RemoteLinuxRunControl::RemoteLinuxRunControl(RunConfiguration *rc)
+        : RunControl(rc, ProjectExplorer::NormalRunMode), d(new RemoteLinuxRunControlPrivate)
 {
+    d->running = false;
+    d->device = DeviceProfileInformation::device(rc->target()->profile());
+    const RemoteLinuxRunConfiguration * const lrc = qobject_cast<RemoteLinuxRunConfiguration *>(rc);
+    d->remoteExecutable = lrc->remoteExecutableFilePath();
+    d->arguments = lrc->arguments();
+    d->prefix = lrc->commandPrefix();
+    d->stopCommand = RemoteLinuxUtils::killApplicationCommandLine(d->remoteExecutable).toUtf8();
 }
 
-AbstractRemoteLinuxRunControl::~AbstractRemoteLinuxRunControl()
+RemoteLinuxRunControl::~RemoteLinuxRunControl()
 {
+    delete d;
 }
 
-void AbstractRemoteLinuxRunControl::start()
+void RemoteLinuxRunControl::start()
 {
-    m_running = true;
+    d->running = true;
     emit started();
-    disconnect(runner(), 0, this, 0);
-    connect(runner(), SIGNAL(error(QString)), SLOT(handleSshError(QString)));
-    connect(runner(), SIGNAL(readyForExecution()), SLOT(startExecution()));
-    connect(runner(), SIGNAL(remoteErrorOutput(QByteArray)),
+    d->runner.disconnect(this);
+    connect(&d->runner, SIGNAL(reportError(QString)), SLOT(handleErrorMessage(QString)));
+    connect(&d->runner, SIGNAL(remoteStderr(QByteArray)),
         SLOT(handleRemoteErrorOutput(QByteArray)));
-    connect(runner(), SIGNAL(remoteOutput(QByteArray)),
-        SLOT(handleRemoteOutput(QByteArray)));
-    connect(runner(), SIGNAL(remoteProcessStarted()),
-        SLOT(handleRemoteProcessStarted()));
-    connect(runner(), SIGNAL(remoteProcessFinished(qint64)),
-        SLOT(handleRemoteProcessFinished(qint64)));
-    connect(runner(), SIGNAL(reportProgress(QString)),
-        SLOT(handleProgressReport(QString)));
-    runner()->start();
+    connect(&d->runner, SIGNAL(remoteStdout(QByteArray)), SLOT(handleRemoteOutput(QByteArray)));
+    connect(&d->runner, SIGNAL(finished(bool)), SLOT(handleRunnerFinished()));
+    connect(&d->runner, SIGNAL(reportProgress(QString)), SLOT(handleProgressReport(QString)));
+    const QString commandLine = QString::fromLatin1("%1 %2 %3")
+            .arg(d->prefix, d->remoteExecutable, d->arguments);
+    d->runner.start(d->device, commandLine.toUtf8());
 }
 
-RunControl::StopResult AbstractRemoteLinuxRunControl::stop()
+RunControl::StopResult RemoteLinuxRunControl::stop()
 {
-    runner()->stop();
+    d->runner.stop(d->stopCommand);
     return AsynchronousStop;
 }
 
-void AbstractRemoteLinuxRunControl::handleSshError(const QString &error)
+void RemoteLinuxRunControl::handleErrorMessage(const QString &error)
 {
-    handleError(error);
-    setFinished();
+    appendMessage(error, Utils::ErrorMessageFormat);
 }
 
-void AbstractRemoteLinuxRunControl::startExecution()
+void RemoteLinuxRunControl::handleRunnerFinished()
 {
-    appendMessage(tr("Starting remote process...\n"), Utils::NormalMessageFormat);
-    runner()->startExecution(QString::fromLatin1("%1 %2 %3")
-        .arg(runner()->commandPrefix())
-        .arg(runner()->remoteExecutable())
-        .arg(runner()->arguments()).toUtf8());
-}
-
-void AbstractRemoteLinuxRunControl::handleRemoteProcessFinished(qint64 exitCode)
-{
-    if (exitCode != AbstractRemoteLinuxApplicationRunner::InvalidExitCode) {
-        appendMessage(tr("Finished running remote process. Exit code was %1.\n")
-            .arg(exitCode), Utils::NormalMessageFormat);
-    }
     setFinished();
 }
 
-void AbstractRemoteLinuxRunControl::handleRemoteOutput(const QByteArray &output)
+void RemoteLinuxRunControl::handleRemoteOutput(const QByteArray &output)
 {
     appendMessage(QString::fromUtf8(output), Utils::StdOutFormatSameLine);
 }
 
-void AbstractRemoteLinuxRunControl::handleRemoteErrorOutput(const QByteArray &output)
+void RemoteLinuxRunControl::handleRemoteErrorOutput(const QByteArray &output)
 {
     appendMessage(QString::fromUtf8(output), Utils::StdErrFormatSameLine);
 }
 
-void AbstractRemoteLinuxRunControl::handleProgressReport(const QString &progressString)
+void RemoteLinuxRunControl::handleProgressReport(const QString &progressString)
 {
     appendMessage(progressString + QLatin1Char('\n'), Utils::NormalMessageFormat);
 }
 
-bool AbstractRemoteLinuxRunControl::isRunning() const
+bool RemoteLinuxRunControl::isRunning() const
 {
-    return m_running;
+    return d->running;
 }
 
-QIcon AbstractRemoteLinuxRunControl::icon() const
+QIcon RemoteLinuxRunControl::icon() const
 {
     return QIcon(ProjectExplorer::Constants::ICON_RUN_SMALL);
 }
 
-void AbstractRemoteLinuxRunControl::handleError(const QString &errString)
+void RemoteLinuxRunControl::setApplicationRunnerPreRunAction(DeviceApplicationHelperAction *action)
 {
-    stop();
-    appendMessage(errString, Utils::ErrorMessageFormat);
+    d->runner.setPreRunAction(action);
 }
 
-void AbstractRemoteLinuxRunControl::setFinished()
+void RemoteLinuxRunControl::setApplicationRunnerPostRunAction(DeviceApplicationHelperAction *action)
 {
-    disconnect(runner(), 0, this, 0);
-    m_running = false;
-    emit finished();
+    d->runner.setPostRunAction(action);
 }
 
-
-RemoteLinuxRunControl::RemoteLinuxRunControl(ProjectExplorer::RunConfiguration *runConfig)
-    : AbstractRemoteLinuxRunControl(runConfig),
-      m_runner(new GenericRemoteLinuxApplicationRunner(qobject_cast<RemoteLinuxRunConfiguration *>(runConfig), this))
-{
-}
-
-RemoteLinuxRunControl::~RemoteLinuxRunControl()
+void RemoteLinuxRunControl::overrideStopCommandLine(const QByteArray &commandLine)
 {
+    d->stopCommand = commandLine;
 }
 
-AbstractRemoteLinuxApplicationRunner *RemoteLinuxRunControl::runner() const
+void RemoteLinuxRunControl::setFinished()
 {
-    return m_runner;
+    d->runner.disconnect(this);
+    d->running = false;
+    emit finished();
 }
 
 } // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/remotelinuxruncontrol.h b/src/plugins/remotelinux/remotelinuxruncontrol.h
index adde0a01e45..86f690d66a5 100644
--- a/src/plugins/remotelinux/remotelinuxruncontrol.h
+++ b/src/plugins/remotelinux/remotelinuxruncontrol.h
@@ -34,54 +34,38 @@
 
 #include <projectexplorer/runconfiguration.h>
 
-QT_FORWARD_DECLARE_CLASS(QString)
+namespace ProjectExplorer { class DeviceApplicationHelperAction; }
 
 namespace RemoteLinux {
-class AbstractRemoteLinuxApplicationRunner;
 
-class REMOTELINUX_EXPORT AbstractRemoteLinuxRunControl : public ProjectExplorer::RunControl
+class REMOTELINUX_EXPORT RemoteLinuxRunControl : public ProjectExplorer::RunControl
 {
     Q_OBJECT
-    Q_DISABLE_COPY(AbstractRemoteLinuxRunControl)
 public:
-    explicit AbstractRemoteLinuxRunControl(ProjectExplorer::RunConfiguration *runConfig);
-    virtual ~AbstractRemoteLinuxRunControl();
+    explicit RemoteLinuxRunControl(ProjectExplorer::RunConfiguration *runConfig);
+    virtual ~RemoteLinuxRunControl();
 
     virtual void start();
     virtual StopResult stop();
     virtual bool isRunning() const;
     virtual QIcon icon() const;
 
-    virtual AbstractRemoteLinuxApplicationRunner *runner() const = 0;
+    void setApplicationRunnerPreRunAction(ProjectExplorer::DeviceApplicationHelperAction *action);
+    void setApplicationRunnerPostRunAction(ProjectExplorer::DeviceApplicationHelperAction *action);
+    void overrideStopCommandLine(const QByteArray &commandLine);
 
 private slots:
-    void startExecution();
-    void handleSshError(const QString &error);
-    void handleRemoteProcessStarted() {}
-    void handleRemoteProcessFinished(qint64 exitCode);
+    void handleErrorMessage(const QString &error);
+    void handleRunnerFinished();
     void handleRemoteOutput(const QByteArray &output);
     void handleRemoteErrorOutput(const QByteArray &output);
     void handleProgressReport(const QString &progressString);
 
 private:
     void setFinished();
-    void handleError(const QString &errString);
-
-    bool m_running;
-};
-
-
-class REMOTELINUX_EXPORT RemoteLinuxRunControl : public AbstractRemoteLinuxRunControl
-{
-    Q_OBJECT
-
-public:
-    explicit RemoteLinuxRunControl(ProjectExplorer::RunConfiguration *runConfig);
-    virtual ~RemoteLinuxRunControl();
-private:
-    virtual AbstractRemoteLinuxApplicationRunner *runner() const;
 
-    AbstractRemoteLinuxApplicationRunner * const m_runner;
+    class RemoteLinuxRunControlPrivate;
+    RemoteLinuxRunControlPrivate * const d;
 };
 
 } // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp
index 36e2820b36d..449ef7832f9 100644
--- a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp
+++ b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp
@@ -89,14 +89,14 @@ RunControl *RemoteLinuxRunControlFactory::create(RunConfiguration *runConfig, Ru
     if (mode == ProjectExplorer::NormalRunMode)
         return new RemoteLinuxRunControl(rc);
 
-    DebuggerStartParameters params = AbstractRemoteLinuxDebugSupport::startParameters(rc);
+    DebuggerStartParameters params = LinuxDeviceDebugSupport::startParameters(rc);
     if (mode == ProjectExplorer::DebugRunModeWithBreakOnMain)
         params.breakOnMain = true;
     DebuggerRunControl * const runControl = DebuggerPlugin::createDebugger(params, rc);
     if (!runControl)
         return 0;
-    RemoteLinuxDebugSupport *debugSupport =
-        new RemoteLinuxDebugSupport(rc, runControl->engine());
+    LinuxDeviceDebugSupport * const debugSupport =
+            new LinuxDeviceDebugSupport(rc, runControl->engine());
     connect(runControl, SIGNAL(finished()), debugSupport, SLOT(handleDebuggingFinished()));
     return runControl;
 }
diff --git a/src/plugins/remotelinux/remotelinuxutils.cpp b/src/plugins/remotelinux/remotelinuxutils.cpp
index 481fcb2afed..80d2e428634 100644
--- a/src/plugins/remotelinux/remotelinuxutils.cpp
+++ b/src/plugins/remotelinux/remotelinuxutils.cpp
@@ -41,9 +41,14 @@ using namespace ExtensionSystem;
 
 namespace RemoteLinux {
 
-QString RemoteLinuxUtils::deviceConfigurationName(const LinuxDeviceConfiguration::ConstPtr &devConf)
+QString RemoteLinuxUtils::killApplicationCommandLine(const QString &applicationFilePath)
 {
-    return devConf ? devConf->displayName() : QCoreApplication::translate("RemoteLinux", "(No device)");
+    return QString::fromLatin1("cd /proc; for pid in `ls -d [0123456789]*`; "
+        "do "
+            "if [ \"`readlink /proc/$pid/exe`\" = \"%1\" ]; then "
+            "    kill $pid; sleep 1; kill -9 $pid; "
+            "fi; "
+        "done").arg(applicationFilePath);
 }
 
 } // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/remotelinuxutils.h b/src/plugins/remotelinux/remotelinuxutils.h
index 69ae6deeab4..403a60d8d55 100644
--- a/src/plugins/remotelinux/remotelinuxutils.h
+++ b/src/plugins/remotelinux/remotelinuxutils.h
@@ -40,7 +40,7 @@ class LinuxDeviceConfiguration;
 class REMOTELINUX_EXPORT RemoteLinuxUtils
 {
 public:
-    static QString deviceConfigurationName(const QSharedPointer<const LinuxDeviceConfiguration> &devConf);
+    static QString killApplicationCommandLine(const QString &applicationFilePath);
 };
 
 } // namespace RemoteLinux
-- 
GitLab