From 79db165dcb7c6999ccc9241910b7f762f358188a Mon Sep 17 00:00:00 2001
From: Christian Kandeler <christian.kandeler@nokia.com>
Date: Wed, 21 Dec 2011 20:14:42 +0100
Subject: [PATCH] Revert "Remote Linux: Rework device testing"

This reverts commit 934c067ddf365c6f12b1e4a1e431f27610b32f7d,
because it breaks running remote Linux applications due to
buggy refactoring of the remote ports gatherer.

Change-Id: I15fd8d4f3e76452a8c5c735316991bd00900444f
Reviewed-by: Christian Kandeler <christian.kandeler@nokia.com>
---
 src/plugins/madde/madde.pro                   |   2 +
 .../madde/maddedeviceconfigurationfactory.cpp |  29 +-
 .../madde/maddedeviceconfigurationfactory.h   |   2 -
 src/plugins/madde/maddedevicetester.cpp       | 293 ++++++++++++++++++
 src/plugins/madde/maddedevicetester.h         |  85 +++++
 src/plugins/madde/maemodeploymentmounter.cpp  |  26 +-
 src/plugins/madde/maemodeploymentmounter.h    |   5 +-
 src/plugins/madde/maemodeviceconfigwizard.cpp |  13 +-
 ...genericlinuxdeviceconfigurationfactory.cpp |  11 +-
 .../genericlinuxdeviceconfigurationfactory.h  |   1 -
 .../genericlinuxdeviceconfigurationwizard.cpp |  17 +-
 .../remotelinux/linuxdevicetestdialog.cpp     | 124 ++------
 .../remotelinux/linuxdevicetestdialog.h       |  11 +-
 src/plugins/remotelinux/linuxdevicetester.cpp | 151 ++++++---
 src/plugins/remotelinux/linuxdevicetester.h   |  76 ++---
 src/plugins/remotelinux/remotelinux.pro       |   2 -
 .../remotelinuxapplicationrunner.cpp          |   9 +-
 .../remotelinuxusedportsgatherer.cpp          | 145 ++++++---
 .../remotelinuxusedportsgatherer.h            |  31 +-
 src/plugins/remotelinux/simplerunner.cpp      | 160 ----------
 src/plugins/remotelinux/simplerunner.h        |  98 ------
 .../remotelinux/startgdbserverdialog.cpp      |  25 +-
 22 files changed, 703 insertions(+), 613 deletions(-)
 create mode 100644 src/plugins/madde/maddedevicetester.cpp
 create mode 100644 src/plugins/madde/maddedevicetester.h
 delete mode 100644 src/plugins/remotelinux/simplerunner.cpp
 delete mode 100644 src/plugins/remotelinux/simplerunner.h

diff --git a/src/plugins/madde/madde.pro b/src/plugins/madde/madde.pro
index debbe8c880f..2ff8bf148e3 100644
--- a/src/plugins/madde/madde.pro
+++ b/src/plugins/madde/madde.pro
@@ -50,6 +50,7 @@ HEADERS += \
     maemorunconfiguration.h \
     maddeuploadandinstallpackagesteps.h \
     maemodeploybymountsteps.h \
+    maddedevicetester.h \
     maddedeviceconfigurationfactory.h \
 
 SOURCES += \
@@ -95,6 +96,7 @@ SOURCES += \
     maddedeviceconfigurationfactory.cpp \
     maddeuploadandinstallpackagesteps.cpp \
     maemodeploybymountsteps.cpp \
+    maddedevicetester.cpp \
     maemorunconfiguration.cpp
 
 FORMS += \
diff --git a/src/plugins/madde/maddedeviceconfigurationfactory.cpp b/src/plugins/madde/maddedeviceconfigurationfactory.cpp
index d1d43506c90..7dfff2837ac 100644
--- a/src/plugins/madde/maddedeviceconfigurationfactory.cpp
+++ b/src/plugins/madde/maddedeviceconfigurationfactory.cpp
@@ -31,9 +31,9 @@
 **************************************************************************/
 #include "maddedeviceconfigurationfactory.h"
 
+#include "maddedevicetester.h"
 #include "maemoconstants.h"
 #include "maemodeviceconfigwizard.h"
-#include "maemoglobal.h"
 
 #include <remotelinux/linuxdevicetestdialog.h>
 #include <remotelinux/publickeydeploymentdialog.h>
@@ -46,8 +46,10 @@ using namespace RemoteLinux;
 
 namespace Madde {
 namespace Internal {
-
+namespace {
+const char MaddeDeviceTestActionId[] = "Madde.DeviceTestAction";
 const char MaddeRemoteProcessesActionId[] = "Madde.RemoteProcessesAction";
+} // anonymous namespace
 
 MaddeDeviceConfigurationFactory::MaddeDeviceConfigurationFactory(QObject *parent)
     : ILinuxDeviceConfigurationFactory(parent)
@@ -105,27 +107,8 @@ QDialog *MaddeDeviceConfigurationFactory::createDeviceAction(const QString &acti
 {
     Q_ASSERT(supportedDeviceActionIds().contains(actionId));
 
-    if (actionId == QLatin1String(MaddeDeviceTestActionId)) {
-        QList<LinuxDeviceTester *>  tests;
-        tests.append(new AuthenticationTester(deviceConfig));
-        tests.append(new LinuxDeviceTester(deviceConfig,
-                                           tr("Checking kernel version..."),
-                                           QLatin1String("uname -rsm")));
-        QString infoCmd = QLatin1String("dpkg-query -W -f "
-                                        "'${Package} ${Version} ${Status}\\n' 'libqt*' | "
-                                        "grep ' installed$' | cut -d' ' -f-2");
-        if (deviceConfig->osType() == MeeGoOsType)
-            infoCmd = QLatin1String("rpm -qa 'libqt*' --queryformat '%{NAME} %{VERSION}\\n'");
-        tests.append(new LinuxDeviceTester(deviceConfig, tr("Checking for Qt libraries..."), infoCmd));
-        tests.append(new LinuxDeviceTester(deviceConfig,
-                                           tr("Checking for connectivity support..."),
-                                           QLatin1String("test -x ") + MaemoGlobal::devrootshPath()));
-        tests.append(new LinuxDeviceTester(deviceConfig,
-                                           tr("Checking for QML tooling support..."),
-                                           QLatin1String("test -d /usr/lib/qt4/plugins/qmltooling")));
-        tests.append(new UsedPortsTester(deviceConfig));
-        return new LinuxDeviceTestDialog(tests, parent);
-    }
+    if (actionId == QLatin1String(MaddeDeviceTestActionId))
+        return new LinuxDeviceTestDialog(deviceConfig, new MaddeDeviceTester, parent);
     if (actionId == QLatin1String(MaddeRemoteProcessesActionId))
         return new RemoteLinuxProcessesDialog(new GenericRemoteLinuxProcessList(deviceConfig), parent);
     if (actionId == QLatin1String(Constants::GenericDeployKeyToDeviceActionId))
diff --git a/src/plugins/madde/maddedeviceconfigurationfactory.h b/src/plugins/madde/maddedeviceconfigurationfactory.h
index 133b9b19705..38da1b98945 100644
--- a/src/plugins/madde/maddedeviceconfigurationfactory.h
+++ b/src/plugins/madde/maddedeviceconfigurationfactory.h
@@ -37,8 +37,6 @@
 namespace Madde {
 namespace Internal {
 
-const char MaddeDeviceTestActionId[] = "Madde.DeviceTestAction";
-
 class MaddeDeviceConfigurationFactory : public RemoteLinux::ILinuxDeviceConfigurationFactory
 {
     Q_OBJECT
diff --git a/src/plugins/madde/maddedevicetester.cpp b/src/plugins/madde/maddedevicetester.cpp
new file mode 100644
index 00000000000..0968f206952
--- /dev/null
+++ b/src/plugins/madde/maddedevicetester.cpp
@@ -0,0 +1,293 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.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 qt-info@nokia.com.
+**
+**************************************************************************/
+#include "maddedevicetester.h"
+
+#include "maemoconstants.h"
+#include "maemoglobal.h"
+
+#include <remotelinux/linuxdeviceconfiguration.h>
+#include <utils/qtcassert.h>
+#include <utils/ssh/sshremoteprocessrunner.h>
+
+#include <QtCore/QRegExp>
+
+using namespace RemoteLinux;
+using namespace Utils;
+
+namespace Madde {
+namespace Internal {
+namespace {
+const char QmlToolingDirectory[] = "/usr/lib/qt4/plugins/qmltooling";
+} // anonymous namespace
+
+MaddeDeviceTester::MaddeDeviceTester(QObject *parent)
+    : AbstractLinuxDeviceTester(parent),
+      m_genericTester(new GenericLinuxDeviceTester(this)),
+      m_state(Inactive),
+      m_processRunner(0)
+{
+}
+
+MaddeDeviceTester::~MaddeDeviceTester()
+{
+}
+
+void MaddeDeviceTester::testDevice(const LinuxDeviceConfiguration::ConstPtr &deviceConfiguration)
+{
+    QTC_ASSERT(m_state == Inactive, return);
+
+    m_deviceConfiguration = deviceConfiguration;
+    m_result = TestSuccess;
+
+    m_state = GenericTest;
+    connect(m_genericTester, SIGNAL(progressMessage(QString)), SIGNAL(progressMessage(QString)));
+    connect(m_genericTester, SIGNAL(errorMessage(QString)), SIGNAL(errorMessage(QString)));
+    connect(m_genericTester, SIGNAL(finished(RemoteLinux::AbstractLinuxDeviceTester::TestResult)),
+        SLOT(handleGenericTestFinished(RemoteLinux::AbstractLinuxDeviceTester::TestResult)));
+    m_genericTester->testDevice(deviceConfiguration);
+}
+
+void MaddeDeviceTester::stopTest()
+{
+    QTC_ASSERT(m_state != Inactive, return);
+
+    switch (m_state) {
+    case Inactive:
+        break;
+    case GenericTest:
+        m_genericTester->stopTest();
+        break;
+    case QtTest:
+    case MadDeveloperTest:
+    case QmlToolingTest:
+        m_processRunner->cancel();
+        break;
+    }
+
+    m_result = TestFailure;
+    setFinished();
+}
+
+void MaddeDeviceTester::handleGenericTestFinished(TestResult result)
+{
+    QTC_ASSERT(m_state == GenericTest, return);
+
+    if (result == TestFailure) {
+        m_result = TestFailure;
+        setFinished();
+        return;
+    }
+
+    if (!m_processRunner)
+        m_processRunner = new SshRemoteProcessRunner(this);
+    connect(m_processRunner, SIGNAL(connectionError()), SLOT(handleConnectionError()));
+    connect(m_processRunner, SIGNAL(processOutputAvailable(QByteArray)),
+        SLOT(handleStdout(QByteArray)));
+    connect(m_processRunner, SIGNAL(processErrorOutputAvailable(QByteArray)),
+        SLOT(handleStderr(QByteArray)));
+    connect(m_processRunner, SIGNAL(processClosed(int)), SLOT(handleProcessFinished(int)));
+
+    QString qtInfoCmd;
+    if (m_deviceConfiguration->osType() == QLatin1String(MeeGoOsType)) {
+        qtInfoCmd = QLatin1String("rpm -qa 'libqt*' --queryformat '%{NAME} %{VERSION}\\n'");
+    } else {
+        qtInfoCmd = QLatin1String("dpkg-query -W -f "
+            "'${Package} ${Version} ${Status}\n' 'libqt*' |grep ' installed$'");
+    }
+
+    emit progressMessage(tr("Checking for Qt libraries..."));
+    m_stdout.clear();
+    m_stderr.clear();
+    m_state = QtTest;
+    m_processRunner->run(qtInfoCmd.toUtf8(), m_genericTester->connection()->connectionParameters());
+}
+
+void MaddeDeviceTester::handleConnectionError()
+{
+    QTC_ASSERT(m_state != Inactive, return);
+
+    emit errorMessage(tr("SSH connection error: %1\n")
+        .arg(m_processRunner->lastConnectionErrorString()));
+    m_result = TestFailure;
+    setFinished();
+}
+
+void MaddeDeviceTester::handleStdout(const QByteArray &data)
+{
+    QTC_ASSERT(m_state == QtTest || m_state == MadDeveloperTest || m_state == QmlToolingTest,
+        return);
+
+    m_stdout += data;
+}
+
+void MaddeDeviceTester::handleStderr(const QByteArray &data)
+{
+    QTC_ASSERT(m_state == QtTest || m_state == MadDeveloperTest || m_state == QmlToolingTest,
+        return);
+
+    m_stderr += data;
+}
+
+void MaddeDeviceTester::handleProcessFinished(int exitStatus)
+{
+    switch (m_state) {
+    case QtTest:
+        handleQtTestFinished(exitStatus);
+        break;
+    case MadDeveloperTest:
+        handleMadDeveloperTestFinished(exitStatus);
+        break;
+    case QmlToolingTest:
+        handleQmlToolingTestFinished(exitStatus);
+        break;
+    default:
+        qWarning("%s: Unexpected state %d.", Q_FUNC_INFO, m_state);
+    }
+}
+
+void MaddeDeviceTester::handleQtTestFinished(int exitStatus)
+{
+    if (exitStatus != SshRemoteProcess::ExitedNormally
+            || m_processRunner->processExitCode() != 0) {
+        if (!m_stderr.isEmpty()) {
+            emit errorMessage(tr("Error checking for Qt libraries: %1\n")
+                .arg(QString::fromUtf8(m_stderr)));
+        } else {
+            emit errorMessage(tr("Error checking for Qt libraries.\n"));
+        }
+
+        m_result = TestFailure;
+    } else {
+        emit progressMessage(processedQtLibsList());
+    }
+
+    m_stdout.clear();
+    m_stderr.clear();
+
+    emit progressMessage(tr("Checking for connectivity support..."));
+    m_state = MadDeveloperTest;
+    m_processRunner->run(QString(QLatin1String("test -x") + MaemoGlobal::devrootshPath()).toUtf8(),
+        m_genericTester->connection()->connectionParameters());
+}
+
+void MaddeDeviceTester::handleMadDeveloperTestFinished(int exitStatus)
+{
+    if (exitStatus != SshRemoteProcess::ExitedNormally) {
+        if (!m_stderr.isEmpty()) {
+            emit errorMessage(tr("Error checking for connectivity tool: %1\n")
+                .arg(QString::fromUtf8(m_stderr)));
+        } else {
+            emit errorMessage(tr("Error checking for connectivity tool.\n"));
+        }
+        m_result = TestFailure;
+    } else if (m_processRunner->processExitCode() != 0) {
+        QString message = tr("Connectivity tool not installed on device. "
+            "Deployment currently not possible.");
+        if (m_deviceConfiguration->osType() == QLatin1String(HarmattanOsType)) {
+            message += tr("Please switch the device to developer mode "
+                "via Settings -> Security.");
+        }
+        emit errorMessage(message + QLatin1Char('\n'));
+        m_result = TestFailure;
+    } else {
+        emit progressMessage(tr("Connectivity tool present.\n"));
+    }
+
+    if (m_deviceConfiguration->osType() != QLatin1String(HarmattanOsType)) {
+        setFinished();
+        return;
+    }
+
+    m_stdout.clear();
+    m_stderr.clear();
+
+    emit progressMessage(tr("Checking for QML tooling support..."));
+    m_state = QmlToolingTest;
+    m_processRunner->run(QString(QLatin1String("test -d ")
+        + QLatin1String(QmlToolingDirectory)).toUtf8(),
+        m_genericTester->connection()->connectionParameters());
+}
+
+void MaddeDeviceTester::handleQmlToolingTestFinished(int exitStatus)
+{
+    if (exitStatus != SshRemoteProcess::ExitedNormally) {
+        if (!m_stderr.isEmpty()) {
+            emit errorMessage(tr("Error checking for QML tooling support: %1\n")
+                .arg(QString::fromUtf8(m_stderr)));
+        } else {
+            emit errorMessage(tr("Error checking for QML tooling support.\n"));
+        }
+        m_result = TestFailure;
+    } else if (m_processRunner->processExitCode() != 0) {
+        emit errorMessage(tr("Missing directory '%1'. You will not be able to do "
+            "QML debugging on this device.\n").arg(QmlToolingDirectory));
+        m_result = TestFailure;
+    } else {
+        emit progressMessage(tr("QML tooling support present.\n"));
+    }
+
+    setFinished();
+}
+
+QString MaddeDeviceTester::processedQtLibsList()
+{
+    QString unfilteredLibs = QString::fromUtf8(m_stdout);
+    QString filteredLibs;
+    QString patternString;
+    if (m_deviceConfiguration->osType() == QLatin1String(MeeGoOsType))
+        patternString = QLatin1String("(libqt\\S+) ((\\d+)\\.(\\d+)\\.(\\d+))");
+    else
+        patternString = QLatin1String("(\\S+) (\\S*(\\d+)\\.(\\d+)\\.(\\d+)\\S*) \\S+ \\S+ \\S+");
+    const QRegExp packagePattern(patternString);
+    int index = packagePattern.indexIn(unfilteredLibs);
+    if (index == -1)
+        return tr("No Qt packages installed.");
+
+    do {
+        filteredLibs += QLatin1String("    ") + packagePattern.cap(1) + QLatin1String(": ")
+            + packagePattern.cap(2) + QLatin1Char('\n');
+        index = packagePattern.indexIn(unfilteredLibs, index + packagePattern.cap(0).length());
+    } while (index != -1);
+    return filteredLibs;
+}
+
+ void MaddeDeviceTester::setFinished()
+{
+    m_state = Inactive;
+    disconnect(m_genericTester, 0, this, 0);
+    if (m_processRunner)
+        disconnect(m_processRunner, 0, this, 0);
+    emit finished(m_result);
+}
+
+} // namespace Internal
+} // namespace Madde
diff --git a/src/plugins/madde/maddedevicetester.h b/src/plugins/madde/maddedevicetester.h
new file mode 100644
index 00000000000..cb13fe91096
--- /dev/null
+++ b/src/plugins/madde/maddedevicetester.h
@@ -0,0 +1,85 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.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 qt-info@nokia.com.
+**
+**************************************************************************/
+#ifndef MADDEDEVICETESTER_H
+#define MADDEDEVICETESTER_H
+
+#include <remotelinux/linuxdevicetester.h>
+
+#include <QtCore/QByteArray>
+
+namespace Utils {
+class SshRemoteProcessRunner;
+}
+
+namespace Madde {
+namespace Internal {
+
+class MaddeDeviceTester : public RemoteLinux::AbstractLinuxDeviceTester
+{
+    Q_OBJECT
+public:
+    explicit MaddeDeviceTester(QObject *parent = 0);
+    ~MaddeDeviceTester();
+
+    void testDevice(const QSharedPointer<const RemoteLinux::LinuxDeviceConfiguration> &deviceConfiguration);
+    void stopTest();
+
+private slots:
+    void handleGenericTestFinished(RemoteLinux::AbstractLinuxDeviceTester::TestResult result);
+    void handleConnectionError();
+    void handleStdout(const QByteArray &data);
+    void handleStderr(const QByteArray &data);
+    void handleProcessFinished(int exitStatus);
+
+private:
+    enum State { Inactive, GenericTest, QtTest, MadDeveloperTest, QmlToolingTest };
+
+    void handleQtTestFinished(int exitStatus);
+    void handleMadDeveloperTestFinished(int exitStatus);
+    void handleQmlToolingTestFinished(int exitStatus);
+
+    QString processedQtLibsList();
+    void setFinished();
+
+    RemoteLinux::GenericLinuxDeviceTester * const m_genericTester;
+    State m_state;
+    TestResult m_result;
+    Utils::SshRemoteProcessRunner *m_processRunner;
+    QSharedPointer<const RemoteLinux::LinuxDeviceConfiguration> m_deviceConfiguration;
+    QByteArray m_stdout;
+    QByteArray m_stderr;
+};
+
+} // namespace Internal
+} // namespace Madde
+
+#endif // MADDEDEVICETESTER_H
diff --git a/src/plugins/madde/maemodeploymentmounter.cpp b/src/plugins/madde/maemodeploymentmounter.cpp
index 648ed0cbf7a..81cca42c618 100644
--- a/src/plugins/madde/maemodeploymentmounter.cpp
+++ b/src/plugins/madde/maemodeploymentmounter.cpp
@@ -52,7 +52,7 @@ MaemoDeploymentMounter::MaemoDeploymentMounter(QObject *parent)
     : QObject(parent),
       m_state(Inactive),
       m_mounter(new MaemoRemoteMounter(this)),
-      m_portsGatherer(0)
+      m_portsGatherer(new RemoteLinuxUsedPortsGatherer(this))
 {
     connect(m_mounter, SIGNAL(error(QString)), SLOT(handleMountError(QString)));
     connect(m_mounter, SIGNAL(mounted()), SLOT(handleMounted()));
@@ -61,6 +61,11 @@ MaemoDeploymentMounter::MaemoDeploymentMounter(QObject *parent)
         SIGNAL(reportProgress(QString)));
     connect(m_mounter, SIGNAL(debugOutput(QString)),
         SIGNAL(debugOutput(QString)));
+
+    connect(m_portsGatherer, SIGNAL(error(QString)),
+        SLOT(handlePortsGathererError(QString)));
+    connect(m_portsGatherer, SIGNAL(portListReady()),
+        SLOT(handlePortListReady()));
 }
 
 MaemoDeploymentMounter::~MaemoDeploymentMounter() {}
@@ -137,12 +142,7 @@ void MaemoDeploymentMounter::handleUnmounted()
         break;
     case UnmountingCurrentDirs:
         setState(GatheringPorts);
-        if (m_portsGatherer)
-            delete m_portsGatherer;
-        m_portsGatherer = new RemoteLinuxUsedPortsGatherer(m_devConf);
-        connect(m_portsGatherer, SIGNAL(finished(RemoteLinux::LinuxDeviceTester::TestResult)),
-                this, SLOT(handlePortListReady(RemoteLinux::LinuxDeviceTester::TestResult)));
-        m_portsGatherer->run();
+        m_portsGatherer->start(m_connection, m_devConf);
         break;
     case UnmountingCurrentMounts:
         setState(Inactive);
@@ -166,20 +166,16 @@ void MaemoDeploymentMounter::handlePortsGathererError(const QString &errorMsg)
     emit error(errorMsg);
 }
 
-void MaemoDeploymentMounter::handlePortListReady(LinuxDeviceTester::TestResult result)
+void MaemoDeploymentMounter::handlePortListReady()
 {
     QTC_ASSERT(m_state == GatheringPorts || m_state == Inactive, return);
 
     if (m_state == Inactive)
         return;
 
-    if (result == LinuxDeviceTester::TestFailure) {
-        handlePortsGathererError(tr("Failed to gather port information."));
-    } else {
-        setState(Mounting);
-        m_freePorts = MaemoGlobal::freePorts(m_devConf, m_buildConfig->qtVersion());
-        m_mounter->mount(&m_freePorts, m_portsGatherer);
-    }
+    setState(Mounting);
+    m_freePorts = MaemoGlobal::freePorts(m_devConf, m_buildConfig->qtVersion());
+    m_mounter->mount(&m_freePorts, m_portsGatherer);
 }
 
 void MaemoDeploymentMounter::handleMountError(const QString &errorMsg)
diff --git a/src/plugins/madde/maemodeploymentmounter.h b/src/plugins/madde/maemodeploymentmounter.h
index 50a16909583..0a6ac4a6987 100644
--- a/src/plugins/madde/maemodeploymentmounter.h
+++ b/src/plugins/madde/maemodeploymentmounter.h
@@ -35,7 +35,6 @@
 
 #include "maemomountspecification.h"
 
-#include <remotelinux/linuxdevicetester.h>
 #include <remotelinux/portlist.h>
 
 #include <QtCore/QList>
@@ -80,7 +79,7 @@ private slots:
     void handleUnmounted();
     void handleMountError(const QString &errorMsg);
     void handlePortsGathererError(const QString &errorMsg);
-    void handlePortListReady(RemoteLinux::LinuxDeviceTester::TestResult result);
+    void handlePortListReady();
     void handleConnectionError();
 
 private:
@@ -97,7 +96,7 @@ private:
     QSharedPointer<Utils::SshConnection> m_connection;
     QSharedPointer<const RemoteLinux::LinuxDeviceConfiguration> m_devConf;
     MaemoRemoteMounter * const m_mounter;
-    RemoteLinux::RemoteLinuxUsedPortsGatherer *m_portsGatherer;
+    RemoteLinux::RemoteLinuxUsedPortsGatherer * const m_portsGatherer;
     RemoteLinux::PortList m_freePorts;
     QList<MaemoMountSpecification> m_mountSpecs;
     const Qt4ProjectManager::Qt4BuildConfiguration *m_buildConfig;
diff --git a/src/plugins/madde/maemodeviceconfigwizard.cpp b/src/plugins/madde/maemodeviceconfigwizard.cpp
index a4f6f65616f..a6279128704 100644
--- a/src/plugins/madde/maemodeviceconfigwizard.cpp
+++ b/src/plugins/madde/maemodeviceconfigwizard.cpp
@@ -30,23 +30,21 @@
 **************************************************************************/
 
 #include "maemodeviceconfigwizard.h"
-#include "maddedeviceconfigurationfactory.h"
 #include "ui_maemodeviceconfigwizardkeycreationpage.h"
 #include "ui_maemodeviceconfigwizardkeydeploymentpage.h"
 #include "ui_maemodeviceconfigwizardpreviouskeysetupcheckpage.h"
 #include "ui_maemodeviceconfigwizardreusekeyscheckpage.h"
 #include "ui_maemodeviceconfigwizardstartpage.h"
 
+#include "maddedevicetester.h"
 #include "maemoconstants.h"
 #include "maemoglobal.h"
 
-#include <extensionsystem/pluginmanager.h>
 #include <remotelinux/genericlinuxdeviceconfigurationwizardpages.h>
 #include <remotelinux/linuxdevicetestdialog.h>
 #include <remotelinux/remotelinuxutils.h>
 #include <remotelinux/sshkeydeployer.h>
 #include <utils/fileutils.h>
-#include <utils/qtcassert.h>
 #include <utils/ssh/sshkeygenerator.h>
 
 #include <QtCore/QDir>
@@ -584,13 +582,8 @@ LinuxDeviceConfiguration::Ptr MaemoDeviceConfigWizard::deviceConfiguration()
         d->wizardData.osType, d->wizardData.deviceType, PortList::fromString(freePortsSpec),
         sshParams);
     if (doTest) {
-        MaddeDeviceConfigurationFactory *factory
-                = ExtensionSystem::PluginManager::instance()->getObject<MaddeDeviceConfigurationFactory>();
-        QTC_ASSERT(factory, return LinuxDeviceConfiguration::Ptr(0));
-        QDialog *dlg = factory->createDeviceAction(QLatin1String(MaddeDeviceTestActionId), devConf, 0);
-        QTC_ASSERT(dlg, return LinuxDeviceConfiguration::Ptr(0));
-        dlg->exec();
-        delete dlg;
+        LinuxDeviceTestDialog dlg(devConf, new MaddeDeviceTester(this), this);
+        dlg.exec();
     }
     return devConf;
 }
diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.cpp
index 364b5a27927..65f36533085 100644
--- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.cpp
+++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.cpp
@@ -93,15 +93,8 @@ QDialog *GenericLinuxDeviceConfigurationFactory::createDeviceAction(const QStrin
 {
     Q_ASSERT(supportedDeviceActionIds().contains(actionId));
 
-    if (actionId == QLatin1String(Constants::GenericTestDeviceActionId)) {
-        QList<LinuxDeviceTester *>  tests;
-        tests.append(new AuthenticationTester(deviceConfig));
-        tests.append(new LinuxDeviceTester(deviceConfig,
-                                           tr("Checking kernel version..."),
-                                           QLatin1String("uname -rsm")));
-        tests.append(new UsedPortsTester(deviceConfig));
-        return new LinuxDeviceTestDialog(tests, parent);
-    }
+    if (actionId == QLatin1String(Constants::GenericTestDeviceActionId))
+        return new LinuxDeviceTestDialog(deviceConfig, new GenericLinuxDeviceTester, parent);
     if (actionId == QLatin1String(Constants::GenericRemoteProcessesActionId)) {
         return new RemoteLinuxProcessesDialog(new GenericRemoteLinuxProcessList(deviceConfig),
             parent);
diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.h b/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.h
index 931ae931b97..c29f52435f9 100644
--- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.h
+++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.h
@@ -29,7 +29,6 @@
 ** Nokia at qt-info@nokia.com.
 **
 **************************************************************************/
-
 #ifndef GENERICLINUXDEVICECONFIGURATIONFACTORY_H
 #define GENERICLINUXDEVICECONFIGURATIONFACTORY_H
 
diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp
index 8bba285cf41..bbb838d98d8 100644
--- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp
+++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp
@@ -30,17 +30,12 @@
 **************************************************************************/
 #include "genericlinuxdeviceconfigurationwizard.h"
 
-#include "genericlinuxdeviceconfigurationfactory.h"
 #include "genericlinuxdeviceconfigurationwizardpages.h"
 #include "linuxdevicetestdialog.h"
 #include "linuxdevicetester.h"
 #include "portlist.h"
 #include "remotelinux_constants.h"
 
-#include <extensionsystem/pluginmanager.h>
-
-#include <utils/qtcassert.h>
-
 using namespace Utils;
 
 namespace RemoteLinux {
@@ -92,16 +87,8 @@ LinuxDeviceConfiguration::Ptr GenericLinuxDeviceConfigurationWizard::deviceConfi
     LinuxDeviceConfiguration::Ptr devConf = LinuxDeviceConfiguration::create(d->setupPage.configurationName(),
         QLatin1String(Constants::GenericLinuxOsType), LinuxDeviceConfiguration::Hardware,
         PortList::fromString(QLatin1String("10000-10100")), sshParams);
-
-    GenericLinuxDeviceConfigurationFactory *factory =
-            ExtensionSystem::PluginManager::instance()->getObject<GenericLinuxDeviceConfigurationFactory>();
-    QTC_ASSERT(factory, return LinuxDeviceConfiguration::Ptr(0));
-
-    QDialog *dlg = factory->createDeviceAction(QLatin1String(Constants::GenericTestDeviceActionId), devConf, 0);
-    QTC_ASSERT(dlg, return LinuxDeviceConfiguration::Ptr(0));
-    dlg->exec();
-    delete dlg;
-
+    LinuxDeviceTestDialog dlg(devConf, new GenericLinuxDeviceTester(this), this);
+    dlg.exec();
     return devConf;
 }
 
diff --git a/src/plugins/remotelinux/linuxdevicetestdialog.cpp b/src/plugins/remotelinux/linuxdevicetestdialog.cpp
index e19f2c0a9a9..dcb9cfbb4a2 100644
--- a/src/plugins/remotelinux/linuxdevicetestdialog.cpp
+++ b/src/plugins/remotelinux/linuxdevicetestdialog.cpp
@@ -32,9 +32,6 @@
 #include "linuxdevicetestdialog.h"
 #include "ui_linuxdevicetestdialog.h"
 
-#include <utils/qtcassert.h>
-#include <utils/ssh/sshconnectionmanager.h>
-
 #include <QtGui/QBrush>
 #include <QtGui/QColor>
 #include <QtGui/QFont>
@@ -43,77 +40,34 @@
 
 namespace RemoteLinux {
 namespace Internal {
-
-class LinuxDeviceTestDialogPrivate
-{
+class LinuxDeviceTestDialogPrivate {
 public:
-    LinuxDeviceTestDialogPrivate(LinuxDeviceTestDialog *qptr, QList<LinuxDeviceTester *> &tester)
-        : deviceTests(tester), lastTest(0), currentTestPosition(-1), failCount(0), q(qptr)
-    { }
-
-    ~LinuxDeviceTestDialogPrivate()
-    {
-        qDeleteAll(deviceTests);
-    }
-
-    LinuxDeviceTester *currentTest()
-    {
-        return deviceTests.at(currentTestPosition);
-    }
-
-    void runTest()
-    {
-        if (lastTest)
-            QObject::disconnect(lastTest, 0, q, 0);
-
-        LinuxDeviceTester *curTest = currentTest();
-
-        QObject::connect(curTest, SIGNAL(progressMessage(QString)),
-                         q, SLOT(handleProgressMessage(QString)));
-        QObject::connect(curTest, SIGNAL(errorMessage(QString)),
-                         q, SLOT(handleErrorMessage(QString)));
-        QObject::connect(curTest, SIGNAL(finished(int)),
-                         q, SLOT(handleTestFinished(int)));
-
-        lastTest = curTest;
-
-        q->addText(curTest->headLine(), QLatin1String("black"), true);
-        q->addText(curTest->commandLine(), QLatin1String("darkGray"), false);
-        curTest->run();
-    }
-
-    bool runNextTest()
+    LinuxDeviceTestDialogPrivate(AbstractLinuxDeviceTester *tester)
+        : deviceTester(tester), finished(false)
     {
-        ++currentTestPosition;
-        if (currentTestPosition < deviceTests.count()) {
-            runTest();
-        } else {
-            currentTestPosition = -1;
-            lastTest = 0;
-        }
-
-        return currentTestPosition != -1;
     }
 
     Ui::LinuxDeviceTestDialog ui;
-    QList<LinuxDeviceTester *> deviceTests;
-    LinuxDeviceTester *lastTest;
-    int currentTestPosition;
-    int failCount;
-    LinuxDeviceTestDialog *const q;
+    AbstractLinuxDeviceTester * const deviceTester;
+    bool finished;
 };
 
 } // namespace Internal
 
-LinuxDeviceTestDialog::LinuxDeviceTestDialog(QList<LinuxDeviceTester *> tests, QWidget *parent) :
-    QDialog(parent),
-    d(new Internal::LinuxDeviceTestDialogPrivate(this, tests))
-{
-    QTC_ASSERT(!tests.isEmpty(), return);
+using namespace Internal;
 
+LinuxDeviceTestDialog::LinuxDeviceTestDialog(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration,
+        AbstractLinuxDeviceTester *deviceTester, QWidget *parent)
+    : QDialog(parent), d(new LinuxDeviceTestDialogPrivate(deviceTester))
+{
     d->ui.setupUi(this);
 
-    d->runNextTest();
+    d->deviceTester->setParent(this);
+    connect(d->deviceTester, SIGNAL(progressMessage(QString)), SLOT(handleProgressMessage(QString)));
+    connect(d->deviceTester, SIGNAL(errorMessage(QString)), SLOT(handleErrorMessage(QString)));
+    connect(d->deviceTester, SIGNAL(finished(RemoteLinux::AbstractLinuxDeviceTester::TestResult)),
+        SLOT(handleTestFinished(RemoteLinux::AbstractLinuxDeviceTester::TestResult)));
+    d->deviceTester->testDevice(deviceConfiguration);
 }
 
 LinuxDeviceTestDialog::~LinuxDeviceTestDialog()
@@ -123,22 +77,14 @@ LinuxDeviceTestDialog::~LinuxDeviceTestDialog()
 
 void LinuxDeviceTestDialog::reject()
 {
-    if (d->currentTestPosition >= 0) {
-        d->deviceTests.at(d->currentTestPosition)->cancel();
-        disconnect(d->deviceTests.at(d->currentTestPosition), 0, this, 0);
-    }
-
+    if (!d->finished)
+        d->deviceTester->stopTest();
     QDialog::reject();
 }
 
 void LinuxDeviceTestDialog::handleProgressMessage(const QString &message)
 {
-    QString tmp = QLatin1String("    ") + message;
-    if (tmp.endsWith('\n'))
-        tmp = tmp.left(tmp.count() - 1);
-    tmp.replace(QLatin1Char('\n'), QLatin1String("\n    "));
-
-    addText(tmp, QLatin1String("black"), false);
+    addText(message, QLatin1String("black"), false);
 }
 
 void LinuxDeviceTestDialog::handleErrorMessage(const QString &message)
@@ -146,33 +92,15 @@ void LinuxDeviceTestDialog::handleErrorMessage(const QString &message)
     addText(message, QLatin1String("red"), false);
 }
 
-void LinuxDeviceTestDialog::handleTestFinished(int result)
+void LinuxDeviceTestDialog::handleTestFinished(AbstractLinuxDeviceTester::TestResult result)
 {
-    bool abortRun = false;
-    if (result == LinuxDeviceTester::TestSuccess) {
-        addText(tr("Ok.\n"), QLatin1String("black"), true);
-    } else if (result == LinuxDeviceTester::TestCriticalFailure) {
-        addText(tr("Critical device test failure, aborting.\n"), QLatin1String("red"), true);
-        ++d->failCount;
-        abortRun = true;
-    } else {
-        addText(tr("Device test failed.\n"), QLatin1String("red"), true);
-        ++d->failCount;
-    }
-
-    if (abortRun || !d->runNextTest()) {
-        if (d->failCount == 0 && !abortRun) {
-            addText(tr("All device tests finished successfully.\n"), QLatin1String("blue"), true);
-        } else {
-            if (!abortRun) {
-                //: %1: number of failed tests, %2 total tests
-                addText(tr("%1 device tests of %2 failed.\n").arg(d->failCount).arg(d->deviceTests.count()),
-                        QLatin1String("red"), true);
-            }
-        }
+    d->finished = true;
+    d->ui.buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Close"));
 
-        d->ui.buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Close"));
-    }
+    if (result == AbstractLinuxDeviceTester::TestSuccess)
+        addText(tr("Device test finished successfully."), QLatin1String("blue"), true);
+    else
+        addText(tr("Device test failed."), QLatin1String("red"), true);
 }
 
 void LinuxDeviceTestDialog::addText(const QString &text, const QString &color, bool bold)
diff --git a/src/plugins/remotelinux/linuxdevicetestdialog.h b/src/plugins/remotelinux/linuxdevicetestdialog.h
index 6aa150bcc3a..ec8becdce94 100644
--- a/src/plugins/remotelinux/linuxdevicetestdialog.h
+++ b/src/plugins/remotelinux/linuxdevicetestdialog.h
@@ -47,8 +47,9 @@ class REMOTELINUX_EXPORT LinuxDeviceTestDialog : public QDialog
     Q_OBJECT
 public:
 
-    // Note: The dialog takes ownership of deviceTests
-    LinuxDeviceTestDialog(QList<LinuxDeviceTester *> tests, QWidget *parent = 0);
+    // Note: The dialog takes ownership of deviceTester
+    explicit LinuxDeviceTestDialog(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration,
+        AbstractLinuxDeviceTester * deviceTester, QWidget *parent = 0);
     ~LinuxDeviceTestDialog();
 
     void reject();
@@ -56,14 +57,12 @@ public:
 private slots:
     void handleProgressMessage(const QString &message);
     void handleErrorMessage(const QString &message);
-    void handleTestFinished(int result);
+    void handleTestFinished(RemoteLinux::AbstractLinuxDeviceTester::TestResult result);
 
 private:
     void addText(const QString &text, const QString &color, bool bold);
 
-    Internal::LinuxDeviceTestDialogPrivate *const d;
-
-    friend class Internal::LinuxDeviceTestDialogPrivate;
+    Internal::LinuxDeviceTestDialogPrivate * const d;
 };
 
 } // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp
index 5d2f4b2c9a8..cd9c4651748 100644
--- a/src/plugins/remotelinux/linuxdevicetester.cpp
+++ b/src/plugins/remotelinux/linuxdevicetester.cpp
@@ -35,99 +35,164 @@
 #include "remotelinuxusedportsgatherer.h"
 
 #include <utils/qtcassert.h>
-#include <utils/ssh/sshremoteprocessrunner.h>
+#include <utils/ssh/sshremoteprocess.h>
 #include <utils/ssh/sshconnection.h>
-#include <utils/ssh/sshconnectionmanager.h>
 
 using namespace Utils;
 
 namespace RemoteLinux {
 namespace Internal {
+namespace {
 
-class LinuxDeviceTesterPrivate
+enum State { Inactive, Connecting, RunningUname, TestingPorts };
+
+} // anonymous namespace
+
+class GenericLinuxDeviceTesterPrivate
 {
 public:
-    LinuxDeviceTesterPrivate()
-    { }
+    GenericLinuxDeviceTesterPrivate() : state(Inactive) {}
 
-    QString headLine;
+    LinuxDeviceConfiguration::ConstPtr deviceConfiguration;
+    SshConnection::Ptr connection;
+    SshRemoteProcess::Ptr process;
+    RemoteLinuxUsedPortsGatherer portsGatherer;
+    State state;
 };
 
 } // namespace Internal
 
 using namespace Internal;
 
-LinuxDeviceTester::LinuxDeviceTester(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration,
-                                     const QString &headline, const QString &commandline) :
-    SimpleRunner(deviceConfiguration, commandline),
-    d(new LinuxDeviceTesterPrivate)
+AbstractLinuxDeviceTester::AbstractLinuxDeviceTester(QObject *parent) : QObject(parent)
 {
-    d->headLine = headline;
 }
 
-LinuxDeviceTester::~LinuxDeviceTester()
+
+GenericLinuxDeviceTester::GenericLinuxDeviceTester(QObject *parent)
+    : AbstractLinuxDeviceTester(parent), d(new GenericLinuxDeviceTesterPrivate)
 {
-    delete d;
 }
 
-QString LinuxDeviceTester::headLine() const
+GenericLinuxDeviceTester::~GenericLinuxDeviceTester()
 {
-    return d->headLine;
+    delete d;
 }
 
-int LinuxDeviceTester::processFinished(int exitStatus)
+void GenericLinuxDeviceTester::testDevice(const LinuxDeviceConfiguration::ConstPtr &deviceConfiguration)
 {
-    return SimpleRunner::processFinished(exitStatus) == 0 ? TestSuccess : TestFailure;
+    QTC_ASSERT(d->state == Inactive, return);
+
+    d->deviceConfiguration = deviceConfiguration;
+    d->connection = SshConnection::create(deviceConfiguration->sshParameters());
+    connect(d->connection.data(), SIGNAL(connected()), SLOT(handleConnected()));
+    connect(d->connection.data(), SIGNAL(error(Utils::SshError)),
+        SLOT(handleConnectionFailure()));
+
+    emit progressMessage(tr("Connecting to host..."));
+    d->state = Connecting;
+    d->connection->connectToHost();
 }
 
-AuthenticationTester::AuthenticationTester(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration) :
-    LinuxDeviceTester(deviceConfiguration, tr("Checking authentication data..."),
-                      QLatin1String("echo \"Success!\""))
+void GenericLinuxDeviceTester::stopTest()
 {
-    SshConnectionManager::instance().forceNewConnection(sshParameters());
+    QTC_ASSERT(d->state != Inactive, return);
+
+    switch (d->state) {
+    case Connecting:
+        d->connection->disconnectFromHost();
+        break;
+    case TestingPorts:
+        d->portsGatherer.stop();
+        break;
+    case RunningUname:
+        d->process->close();
+        break;
+    case Inactive:
+        break;
+    }
+
+    setFinished(TestFailure);
 }
 
-void AuthenticationTester::handleStdOutput(const QByteArray &data)
+SshConnection::Ptr GenericLinuxDeviceTester::connection() const
 {
-    m_authenticationSucceded = data.contains("Success!");
-    LinuxDeviceTester::handleStdOutput(data);
+    return d->connection;
 }
 
-int AuthenticationTester::processFinished(int exitStatus)
+void GenericLinuxDeviceTester::handleConnected()
 {
-    return LinuxDeviceTester::processFinished(exitStatus) == TestSuccess
-            && m_authenticationSucceded ? TestSuccess : TestCriticalFailure;
+    QTC_ASSERT(d->state == Connecting, return);
+
+    d->process = d->connection->createRemoteProcess("uname -rsm");
+    connect(d->process.data(), SIGNAL(closed(int)), SLOT(handleProcessFinished(int)));
+
+    emit progressMessage("Checking kernel version...");
+    d->state = RunningUname;
+    d->process->start();
 }
 
-UsedPortsTester::UsedPortsTester(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration) :
-    LinuxDeviceTester(deviceConfiguration, tr("Checking for available ports..."), QString()),
-    gatherer(new RemoteLinuxUsedPortsGatherer(deviceConfiguration))
+void GenericLinuxDeviceTester::handleConnectionFailure()
 {
-    connect(gatherer, SIGNAL(aboutToStart()), this, SIGNAL(aboutToStart()));
-    connect(gatherer, SIGNAL(errorMessage(QString)), this, SIGNAL(errorMessage(QString)));
-    connect(gatherer, SIGNAL(finished(int)), this, SIGNAL(finished(int)));
-    connect(gatherer, SIGNAL(progressMessage(QString)), this, SIGNAL(progressMessage(QString)));
-    connect(gatherer, SIGNAL(started()), this, SIGNAL(started()));
+    QTC_ASSERT(d->state != Inactive, return);
+
+    emit errorMessage(tr("SSH connection failure: %1\n").arg(d->connection->errorString()));
+    setFinished(TestFailure);
 }
 
-UsedPortsTester::~UsedPortsTester()
+void GenericLinuxDeviceTester::handleProcessFinished(int exitStatus)
 {
-    delete gatherer;
+    QTC_ASSERT(d->state == RunningUname, return);
+
+    if (exitStatus != SshRemoteProcess::ExitedNormally || d->process->exitCode() != 0) {
+        const QByteArray stderrOutput = d->process->readAllStandardError();
+        if (!stderrOutput.isEmpty())
+            emit errorMessage(tr("uname failed: %1\n").arg(QString::fromUtf8(stderrOutput)));
+        else
+            emit errorMessage(tr("uname failed.\n"));
+    } else {
+        emit progressMessage(QString::fromUtf8(d->process->readAllStandardOutput()));
+    }
+
+    connect(&d->portsGatherer, SIGNAL(error(QString)), SLOT(handlePortsGatheringError(QString)));
+    connect(&d->portsGatherer, SIGNAL(portListReady()), SLOT(handlePortListReady()));
+
+    emit progressMessage(tr("Checking if specified ports are available..."));
+    d->state = TestingPorts;
+    d->portsGatherer.start(d->connection, d->deviceConfiguration);
 }
 
-QString UsedPortsTester::commandLine() const
+void GenericLinuxDeviceTester::handlePortsGatheringError(const QString &message)
 {
-    return gatherer->commandLine();
+    QTC_ASSERT(d->state == TestingPorts, return);
+
+    emit errorMessage(tr("Error gathering ports: %1\n").arg(message));
+    setFinished(TestFailure);
 }
 
-void UsedPortsTester::run()
+void GenericLinuxDeviceTester::handlePortListReady()
 {
-    gatherer->run();
+    QTC_ASSERT(d->state == TestingPorts, return);
+
+    if (d->portsGatherer.usedPorts().isEmpty()) {
+        emit progressMessage("All specified ports are available.\n");
+    } else {
+        QString portList;
+        foreach (const int port, d->portsGatherer.usedPorts())
+            portList += QString::number(port) + QLatin1String(", ");
+        portList.remove(portList.count() - 2, 2);
+        emit errorMessage(tr("The following specified ports are currently in use: %1\n")
+            .arg(portList));
+    }
+    setFinished(TestSuccess);
 }
 
-void UsedPortsTester::cancel()
+void GenericLinuxDeviceTester::setFinished(TestResult result)
 {
-    gatherer->cancel();
+    d->state = Inactive;
+    disconnect(d->connection.data(), 0, this, 0);
+    disconnect(&d->portsGatherer, 0, this, 0);
+    emit finished(result);
 }
 
 } // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/linuxdevicetester.h b/src/plugins/remotelinux/linuxdevicetester.h
index 7c1df21eaea..1a469af8062 100644
--- a/src/plugins/remotelinux/linuxdevicetester.h
+++ b/src/plugins/remotelinux/linuxdevicetester.h
@@ -34,79 +34,65 @@
 
 #include "remotelinux_export.h"
 
-#include "simplerunner.h"
-
-#include <utils/ssh/sshconnection.h>
-
 #include <QtCore/QObject>
 #include <QtCore/QSharedPointer>
 
 QT_FORWARD_DECLARE_CLASS(QString)
 
+namespace Utils {
+class SshConnection;
+}
+
 namespace RemoteLinux {
 class LinuxDeviceConfiguration;
-class RemoteLinuxUsedPortsGatherer;
 
 namespace Internal {
-class LinuxDeviceTesterPrivate;
+class GenericLinuxDeviceTesterPrivate;
 } // namespace Internal
 
-// -----------------------------------------------------------------------
-// LinuxDeviceTester:
-// -----------------------------------------------------------------------
-
-class REMOTELINUX_EXPORT LinuxDeviceTester : public SimpleRunner
+class REMOTELINUX_EXPORT AbstractLinuxDeviceTester : public QObject
 {
     Q_OBJECT
-
+    Q_DISABLE_COPY(AbstractLinuxDeviceTester)
 public:
-    enum TestResult { TestSuccess = 0, TestFailure, TestCriticalFailure };
+    enum TestResult { TestSuccess, TestFailure };
 
-    LinuxDeviceTester(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration,
-                      const QString &headline, const QString &commandline);
-    ~LinuxDeviceTester();
+    virtual void testDevice(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration) = 0;
+    virtual void stopTest() = 0;
 
-    virtual QString headLine() const;
+signals:
+    void progressMessage(const QString &message);
+    void errorMessage(const QString &message);
+    void finished(RemoteLinux::AbstractLinuxDeviceTester::TestResult result);
 
 protected:
-    int processFinished(int exitStatus);
-
-private:
-    Internal::LinuxDeviceTesterPrivate *const d;
+    explicit AbstractLinuxDeviceTester(QObject *parent = 0);
 };
 
-class REMOTELINUX_EXPORT AuthenticationTester : public LinuxDeviceTester
-{
-    Q_OBJECT
-
-public:
-    AuthenticationTester(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration);
-
-protected slots:
-    void handleStdOutput(const QByteArray &data);
-
-protected:
-    int processFinished(int exitStatus);
-
-private:
-    bool m_authenticationSucceded;
-};
 
-class REMOTELINUX_EXPORT UsedPortsTester : public LinuxDeviceTester
+class REMOTELINUX_EXPORT GenericLinuxDeviceTester : public AbstractLinuxDeviceTester
 {
     Q_OBJECT
-
 public:
-    UsedPortsTester(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration);
-    ~UsedPortsTester();
+    explicit GenericLinuxDeviceTester(QObject *parent = 0);
+    ~GenericLinuxDeviceTester();
 
-    QString commandLine() const;
+    void testDevice(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration);
+    void stopTest();
 
-    void run();
-    void cancel();
+    QSharedPointer<Utils::SshConnection> connection() const;
+
+private slots:
+    void handleConnected();
+    void handleConnectionFailure();
+    void handleProcessFinished(int exitStatus);
+    void handlePortsGatheringError(const QString &message);
+    void handlePortListReady();
 
 private:
-    RemoteLinuxUsedPortsGatherer *const gatherer;
+    void setFinished(TestResult result);
+
+    Internal::GenericLinuxDeviceTesterPrivate * const d;
 };
 
 } // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/remotelinux.pro b/src/plugins/remotelinux/remotelinux.pro
index 8852d46111b..00990e02520 100644
--- a/src/plugins/remotelinux/remotelinux.pro
+++ b/src/plugins/remotelinux/remotelinux.pro
@@ -9,7 +9,6 @@ HEADERS += \
     embeddedlinuxtargetfactory.h \
     embeddedlinuxqtversion.h \
     embeddedlinuxqtversionfactory.h \
-    simplerunner.h \
     remotelinuxplugin.h \
     remotelinux_export.h \
     linuxdeviceconfiguration.h \
@@ -69,7 +68,6 @@ SOURCES += \
     embeddedlinuxtargetfactory.cpp \
     embeddedlinuxqtversion.cpp \
     embeddedlinuxqtversionfactory.cpp \
-    simplerunner.cpp \
     remotelinuxplugin.cpp \
     linuxdeviceconfiguration.cpp \
     linuxdeviceconfigurations.cpp \
diff --git a/src/plugins/remotelinux/remotelinuxapplicationrunner.cpp b/src/plugins/remotelinux/remotelinuxapplicationrunner.cpp
index d9a77c4e812..c38b29444d1 100644
--- a/src/plugins/remotelinux/remotelinuxapplicationrunner.cpp
+++ b/src/plugins/remotelinux/remotelinuxapplicationrunner.cpp
@@ -62,8 +62,7 @@ class AbstractRemoteLinuxApplicationRunnerPrivate
 {
 public:
     AbstractRemoteLinuxApplicationRunnerPrivate(const RemoteLinuxRunConfiguration *runConfig)
-        : portsGatherer(runConfig->deviceConfig()),
-          devConfig(runConfig->deviceConfig()),
+        : devConfig(runConfig->deviceConfig()),
           remoteExecutable(runConfig->remoteExecutableFilePath()),
           appArguments(runConfig->arguments()),
           commandPrefix(runConfig->commandPrefix()),
@@ -168,7 +167,7 @@ void AbstractRemoteLinuxApplicationRunner::stop()
         emit remoteProcessFinished(InvalidExitCode);
         break;
     case GatheringPorts:
-        d->portsGatherer.cancel();
+        d->portsGatherer.stop();
         setInactive();
         emit remoteProcessFinished(InvalidExitCode);
         break;
@@ -308,7 +307,7 @@ void AbstractRemoteLinuxApplicationRunner::handleRemoteProcessFinished(int exitS
 
 void AbstractRemoteLinuxApplicationRunner::setInactive()
 {
-    d->portsGatherer.cancel();
+    d->portsGatherer.stop();
     if (d->connection) {
         disconnect(d->connection.data(), 0, this, 0);
         SshConnectionManager::instance().releaseConnection(d->connection);
@@ -423,7 +422,7 @@ void AbstractRemoteLinuxApplicationRunner::handleInitialCleanupDone(bool success
     }
 
     d->state = GatheringPorts;
-    d->portsGatherer.run();
+    d->portsGatherer.start(d->connection, d->devConfig);
 }
 
 void AbstractRemoteLinuxApplicationRunner::handleInitializationsDone(bool success)
diff --git a/src/plugins/remotelinux/remotelinuxusedportsgatherer.cpp b/src/plugins/remotelinux/remotelinuxusedportsgatherer.cpp
index e0d201ddde3..a239edfae05 100644
--- a/src/plugins/remotelinux/remotelinuxusedportsgatherer.cpp
+++ b/src/plugins/remotelinux/remotelinuxusedportsgatherer.cpp
@@ -33,7 +33,6 @@
 #include "linuxdeviceconfiguration.h"
 #include "portlist.h"
 
-#include <utils/ssh/sshconnectionmanager.h>
 #include <utils/ssh/sshremoteprocessrunner.h>
 
 #include <QtCore/QString>
@@ -46,32 +45,23 @@ namespace Internal {
 class RemoteLinuxUsedPortsGathererPrivate
 {
  public:
-    RemoteLinuxUsedPortsGathererPrivate()
-    { }
+    RemoteLinuxUsedPortsGathererPrivate() : running(false) {}
 
+    SshRemoteProcessRunner procRunner;
     PortList portsToCheck;
     QList<int> usedPorts;
-    QByteArray keepSake;
+    QByteArray remoteStdout;
+    QByteArray remoteStderr;
+    bool running; // TODO: Redundant due to being in sync with procRunner?
 };
 
 } // namespace Internal
 
 using namespace Internal;
 
-RemoteLinuxUsedPortsGatherer::RemoteLinuxUsedPortsGatherer(
-        const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration) :
-    SimpleRunner(deviceConfiguration,
-                 // Match
-                 //  0: 0100007F:706E 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 8141 1 ce498900 300 0 0 2 -1
-                 // and report   ^^^^ this local port number
-                 QLatin1String("FILE=/proc/net/tcp ; "
-                               "echo \"$SSH_CONNECTION\" | grep : > /dev/null && FILE=/proc/net/tcp6 ; "
-                               "sed 's/^\\s\\+[0-9a-fA-F]\\+:\\s\\+[0-9a-fA-F]\\+:\\([0-9a-fA-F]\\+\\)\\s.*$/\\1/' $FILE")),
-    d(new RemoteLinuxUsedPortsGathererPrivate)
+RemoteLinuxUsedPortsGatherer::RemoteLinuxUsedPortsGatherer(QObject *parent) :
+    QObject(parent), d(new RemoteLinuxUsedPortsGathererPrivate)
 {
-    d->portsToCheck = deviceConfiguration->freePorts();
-
-    connect(this, SIGNAL(aboutToStart()), this, SLOT(cleanup()));
 }
 
 RemoteLinuxUsedPortsGatherer::~RemoteLinuxUsedPortsGatherer()
@@ -79,6 +69,48 @@ RemoteLinuxUsedPortsGatherer::~RemoteLinuxUsedPortsGatherer()
     delete d;
 }
 
+void RemoteLinuxUsedPortsGatherer::start(const Utils::SshConnection::Ptr &connection,
+    const LinuxDeviceConfiguration::ConstPtr &devConf)
+{
+    if (d->running)
+        qWarning("Unexpected call of %s in running state", Q_FUNC_INFO);
+    d->portsToCheck = devConf->freePorts();
+    d->usedPorts.clear();
+    d->remoteStdout.clear();
+    d->remoteStderr.clear();
+    connect(&d->procRunner, SIGNAL(connectionError()), SLOT(handleConnectionError()));
+    connect(&d->procRunner, SIGNAL(processClosed(int)), SLOT(handleProcessClosed(int)));
+    connect(&d->procRunner, SIGNAL(processOutputAvailable(QByteArray)),
+        SLOT(handleRemoteStdOut(QByteArray)));
+    connect(&d->procRunner, SIGNAL(processErrorOutputAvailable(QByteArray)),
+        SLOT(handleRemoteStdErr(QByteArray)));
+    QString procFilePath;
+    int addressLength;
+    if (connection->ipProtocolVersion() == QAbstractSocket::IPv4Protocol) {
+        procFilePath = QLatin1String("/proc/net/tcp");
+        addressLength = 8;
+    } else {
+        procFilePath = QLatin1String("/proc/net/tcp6");
+        addressLength = 32;
+    }
+    const QString command = QString::fromLocal8Bit("sed "
+        "'s/.*: [[:xdigit:]]\\{%1\\}:\\([[:xdigit:]]\\{4\\}\\).*/\\1/g' %2")
+        .arg(addressLength).arg(procFilePath);
+
+    // TODO: We should not use an SshRemoteProcessRunner here, because we have to check
+    // for the type of the connection before we can say what the exact command line is.
+    d->procRunner.run(command.toUtf8(), connection->connectionParameters());
+    d->running = true;
+}
+
+void RemoteLinuxUsedPortsGatherer::stop()
+{
+    if (!d->running)
+        return;
+    d->running = false;
+    disconnect(&d->procRunner, 0, this, 0);
+}
+
 int RemoteLinuxUsedPortsGatherer::getNextFreePort(PortList *freePorts) const
 {
     while (freePorts->hasMore()) {
@@ -94,20 +126,12 @@ QList<int> RemoteLinuxUsedPortsGatherer::usedPorts() const
     return d->usedPorts;
 }
 
-void RemoteLinuxUsedPortsGatherer::handleStdOutput(const QByteArray &output)
+void RemoteLinuxUsedPortsGatherer::setupUsedPorts()
 {
-    QByteArray data = d->keepSake + output;
-
-    // make sure we only process complete lines:
-    int lastEol = output.lastIndexOf('\n');
-    if (lastEol != output.count() - 1) {
-        d->keepSake = data.mid(lastEol + 1);
-        data = data.left(lastEol);
-    }
-
-    QList<QByteArray> portStrings = data.split('\n');
+    QList<QByteArray> portStrings = d->remoteStdout.split('\n');
+    portStrings.removeFirst();
     foreach (const QByteArray &portString, portStrings) {
-        if (portString.isEmpty() || portString.contains("local_address"))
+        if (portString.isEmpty())
             continue;
         bool ok;
         const int port = portString.toInt(&ok, 16);
@@ -119,32 +143,61 @@ void RemoteLinuxUsedPortsGatherer::handleStdOutput(const QByteArray &output)
                 Q_FUNC_INFO, portString.data());
         }
     }
+    emit portListReady();
 }
 
-void RemoteLinuxUsedPortsGatherer::cleanup()
+void RemoteLinuxUsedPortsGatherer::handleConnectionError()
 {
-    d->keepSake.clear();
-    d->usedPorts.clear();
+    if (!d->running)
+        return;
+    emit error(tr("Connection error: %1").arg(d->procRunner.lastConnectionErrorString()));
+    stop();
 }
 
-int RemoteLinuxUsedPortsGatherer::processFinished(int exitStatus)
+void RemoteLinuxUsedPortsGatherer::handleProcessClosed(int exitStatus)
 {
-    if (!d->keepSake.isEmpty()) {
-        d->keepSake.append('\n');
-        handleStdOutput(d->keepSake);
+    if (!d->running)
+        return;
+    QString errMsg;
+    switch (exitStatus) {
+    case SshRemoteProcess::FailedToStart:
+        errMsg = tr("Could not start remote process: %1")
+            .arg(d->procRunner.processErrorString());
+        break;
+    case SshRemoteProcess::KilledBySignal:
+        errMsg = tr("Remote process crashed: %1")
+            .arg(d->procRunner.processErrorString());
+        break;
+    case SshRemoteProcess::ExitedNormally:
+        if (d->procRunner.processExitCode() == 0) {
+            setupUsedPorts();
+        } else {
+            errMsg = tr("Remote process failed; exit code was %1.")
+                .arg(d->procRunner.processExitCode());
+        }
+        break;
+    default:
+        Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid exit status");
     }
 
-    if (usedPorts().isEmpty()) {
-        emit progressMessage("All specified ports are available.\n");
-    } else {
-        QString portList;
-        foreach (const int port, usedPorts())
-            portList += QString::number(port) + QLatin1String(", ");
-        portList.remove(portList.count() - 2, 2);
-        emit errorMessage(tr("The following specified ports are currently in use: %1\n")
-                          .arg(portList));
+    if (!errMsg.isEmpty()) {
+        if (!d->remoteStderr.isEmpty()) {
+            errMsg += tr("\nRemote error output was: %1")
+                .arg(QString::fromUtf8(d->remoteStderr));
+        }
+        emit error(errMsg);
     }
-    return SimpleRunner::processFinished(exitStatus);
+    stop();
+}
+
+void RemoteLinuxUsedPortsGatherer::handleRemoteStdOut(const QByteArray &output)
+{
+    d->remoteStdout += output;
+}
+
+void RemoteLinuxUsedPortsGatherer::handleRemoteStdErr(const QByteArray &output)
+{
+    d->remoteStderr += output;
 }
 
 } // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/remotelinuxusedportsgatherer.h b/src/plugins/remotelinux/remotelinuxusedportsgatherer.h
index dec6b006697..a5a51362afb 100644
--- a/src/plugins/remotelinux/remotelinuxusedportsgatherer.h
+++ b/src/plugins/remotelinux/remotelinuxusedportsgatherer.h
@@ -33,9 +33,9 @@
 
 #include "remotelinux_export.h"
 
-#include "simplerunner.h"
-
 #include <QtCore/QList>
+#include <QtCore/QObject>
+#include <QtCore/QSharedPointer>
 
 QT_FORWARD_DECLARE_CLASS(QString)
 
@@ -51,28 +51,33 @@ namespace Internal {
 class RemoteLinuxUsedPortsGathererPrivate;
 } // namespace Internal
 
-class REMOTELINUX_EXPORT RemoteLinuxUsedPortsGatherer : public SimpleRunner
+class REMOTELINUX_EXPORT RemoteLinuxUsedPortsGatherer : public QObject
 {
     Q_OBJECT
-
+    Q_DISABLE_COPY(RemoteLinuxUsedPortsGatherer)
 public:
-    explicit RemoteLinuxUsedPortsGatherer(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration);
+    explicit RemoteLinuxUsedPortsGatherer(QObject *parent = 0);
     ~RemoteLinuxUsedPortsGatherer();
-
+    void start(const QSharedPointer<Utils::SshConnection> &connection,
+        const QSharedPointer<const LinuxDeviceConfiguration> &devConf);
+    void stop();
     int getNextFreePort(PortList *freePorts) const; // returns -1 if no more are left
     QList<int> usedPorts() const;
 
-protected slots:
-    void handleStdOutput(const QByteArray &output);
-
-protected:
-    int processFinished(int exitStatus);
+signals:
+    void error(const QString &errMsg);
+    void portListReady();
 
 private slots:
-    void cleanup();
+    void handleConnectionError();
+    void handleProcessClosed(int exitStatus);
+    void handleRemoteStdOut(const QByteArray &output);
+    void handleRemoteStdErr(const QByteArray &output);
 
 private:
-    Internal::RemoteLinuxUsedPortsGathererPrivate *const d;
+    void setupUsedPorts();
+
+    Internal::RemoteLinuxUsedPortsGathererPrivate * const d;
 };
 
 } // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/simplerunner.cpp b/src/plugins/remotelinux/simplerunner.cpp
deleted file mode 100644
index cdebd869aa2..00000000000
--- a/src/plugins/remotelinux/simplerunner.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (qt-info@nokia.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 qt-info@nokia.com.
-**
-**************************************************************************/
-
-#include "simplerunner.h"
-
-#include "linuxdeviceconfiguration.h"
-
-#include <utils/qtcassert.h>
-#include <utils/ssh/sshremoteprocessrunner.h>
-#include <utils/ssh/sshconnection.h>
-#include <utils/ssh/sshconnectionmanager.h>
-
-using namespace Utils;
-
-namespace RemoteLinux {
-namespace Internal {
-
-class SimpleRunnerPrivate
-{
-public:
-    SimpleRunnerPrivate() : process(0), sshParameters(Utils::SshConnectionParameters::NoProxy)
-    { }
-
-    QString commandline;
-
-    SshRemoteProcessRunner *process;
-    Utils::SshConnectionParameters sshParameters;
-};
-
-} // namespace Internal
-
-using namespace Internal;
-
-SimpleRunner::SimpleRunner(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration,
-                           const QString &commandline) :
-    d(new SimpleRunnerPrivate)
-{
-    QTC_ASSERT(!deviceConfiguration.isNull(), return);
-    d->commandline = commandline;
-    d->sshParameters = deviceConfiguration->sshParameters();
-}
-
-SimpleRunner::~SimpleRunner()
-{
-    delete d;
-}
-
-QString SimpleRunner::commandLine() const
-{
-    return d->commandline;
-}
-
-void SimpleRunner::run()
-{
-    QTC_ASSERT(!d->process, return);
-
-    d->process = new SshRemoteProcessRunner(this);
-
-    connect(d->process, SIGNAL(connectionError()), this, SLOT(handleConnectionFailure()));
-    connect(d->process, SIGNAL(processClosed(int)), this, SLOT(handleProcessFinished(int)));
-    connect(d->process, SIGNAL(processOutputAvailable(QByteArray)), this, SLOT(handleStdOutput(QByteArray)));
-    connect(d->process, SIGNAL(processErrorOutputAvailable(QByteArray)),
-            this, SLOT(handleStdError(QByteArray)));
-
-    emit aboutToStart();
-    d->process->run(d->commandline.toUtf8(), sshParameters());
-    emit started();
-}
-
-void SimpleRunner::cancel()
-{
-    if (!d->process)
-        return;
-
-    d->process->cancel();
-    emit finished(-1);
-}
-
-void SimpleRunner::handleConnectionFailure()
-{
-    QTC_ASSERT(d->process, return);
-
-    emit errorMessage(tr("SSH connection failure: %1\n").arg(d->process->lastConnectionErrorString()));
-    delete d->process;
-    d->process = 0;
-
-    emit finished(processFinished(SshRemoteProcess::FailedToStart));
-}
-
-void SimpleRunner::handleProcessFinished(int exitStatus)
-{
-    emit finished(processFinished(exitStatus));
-}
-
-void SimpleRunner::handleStdOutput(const QByteArray &data)
-{
-    if (data.isEmpty())
-        return;
-    emit progressMessage(QString::fromUtf8(data));
-}
-
-void SimpleRunner::handleStdError(const QByteArray &data)
-{
-    if (data.isEmpty())
-        return;
-    emit errorMessage(QString::fromUtf8(data));
-}
-
-int SimpleRunner::processFinished(int exitStatus)
-{
-    int exitCode = -1;
-    if (d->process)
-        exitCode = d->process->processExitCode();
-    delete d->process;
-    d->process = 0;
-
-    return (exitStatus == SshRemoteProcess::ExitedNormally && exitCode == 0) ? 0 : 1;
-}
-
-void SimpleRunner::setCommandLine(const QString &cmd)
-{
-    QTC_ASSERT(d->commandline.isEmpty(), return);
-    d->commandline = cmd;
-}
-
-SshConnectionParameters SimpleRunner::sshParameters() const
-{
-    return d->sshParameters;
-}
-
-} // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/simplerunner.h b/src/plugins/remotelinux/simplerunner.h
deleted file mode 100644
index 056d19268be..00000000000
--- a/src/plugins/remotelinux/simplerunner.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (qt-info@nokia.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 qt-info@nokia.com.
-**
-**************************************************************************/
-
-#ifndef SIMPLERUNNER_H
-#define SIMPLERUNNER_H
-
-#include "remotelinux_export.h"
-
-#include <utils/ssh/sshconnection.h>
-
-#include <QtCore/QObject>
-
-QT_FORWARD_DECLARE_CLASS(QString)
-
-namespace RemoteLinux {
-class LinuxDeviceConfiguration;
-
-namespace Internal {
-class SimpleRunnerPrivate;
-} // namespace Internal
-
-// -----------------------------------------------------------------------
-// SimpleRunner:
-// -----------------------------------------------------------------------
-
-class REMOTELINUX_EXPORT SimpleRunner : public QObject
-{
-    Q_OBJECT
-
-public:
-    SimpleRunner(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration,
-                 const QString &commandline);
-    ~SimpleRunner();
-
-    virtual QString commandLine() const;
-
-    virtual void run();
-    virtual void cancel();
-
-signals:
-    void aboutToStart();
-    void started();
-    void progressMessage(const QString &message);
-    void errorMessage(const QString &message);
-    // 0 on success, other value on failure.
-    void finished(int result);
-
-protected slots:
-    void handleProcessFinished(int exitStatus);
-
-    virtual void handleConnectionFailure();
-    virtual void handleStdOutput(const QByteArray &data);
-    virtual void handleStdError(const QByteArray &data);
-
-    // 0 on success, any other value on failure.
-    virtual int processFinished(int exitStatus);
-
-protected:
-    void setCommandLine(const QString &cmd);
-
-    Utils::SshConnectionParameters sshParameters() const;
-
-private:
-    Internal::SimpleRunnerPrivate *const d;
-};
-
-} // namespace RemoteLinux
-
-#endif // SIMPLERUNNER_H
diff --git a/src/plugins/remotelinux/startgdbserverdialog.cpp b/src/plugins/remotelinux/startgdbserverdialog.cpp
index 879815f72c6..794fb6135f9 100644
--- a/src/plugins/remotelinux/startgdbserverdialog.cpp
+++ b/src/plugins/remotelinux/startgdbserverdialog.cpp
@@ -103,14 +103,14 @@ public:
     QPushButton *closeButton;
     PathChooser *sysrootPathChooser;
 
-    RemoteLinuxUsedPortsGatherer *gatherer;
+    RemoteLinuxUsedPortsGatherer gatherer;
     SshRemoteProcessRunner runner;
     QSettings *settings;
     QString remoteCommandLine;
 };
 
 StartGdbServerDialogPrivate::StartGdbServerDialogPrivate(StartGdbServerDialog *q)
-    : q(q), processList(0), gatherer(0), settings(0)
+    : q(q), processList(0)
 {
     settings = ICore::instance()->settings();
 
@@ -179,6 +179,8 @@ StartGdbServerDialog::StartGdbServerDialog(QWidget *parent) :
 
     d->deviceComboBox->setModel(devices);
     d->deviceComboBox->setCurrentIndex(d->settings->value(LastDevice).toInt());
+    connect(&d->gatherer, SIGNAL(error(QString)), SLOT(portGathererError(QString)));
+    connect(&d->gatherer, SIGNAL(portListReady()), SLOT(portListReady()));
     if (devices->rowCount() == 0) {
         d->tableView->setEnabled(false);
     } else {
@@ -213,15 +215,6 @@ StartGdbServerDialog::~StartGdbServerDialog()
 void StartGdbServerDialog::attachToDevice(int index)
 {
     LinuxDeviceConfigurations *devices = LinuxDeviceConfigurations::instance();
-
-    if (d->gatherer)
-        delete d->gatherer;
-
-    d->gatherer = new RemoteLinuxUsedPortsGatherer(devices->deviceAt(index));
-    connect(d->gatherer, SIGNAL(finished(RemoteLinux::LinuxDeviceTester::TestResult)),
-            this, SLOT(portListReady(RemoteLinux::LinuxDeviceTester::TestResult)));
-    connect(d->gatherer, SIGNAL(errorMessage(QString)), SLOT(portGathererError(QString)));
-
     delete d->processList;
     d->processList = new GenericRemoteLinuxProcessList(devices->deviceAt(index));
     d->proxyModel.setSourceModel(d->processList);
@@ -257,8 +250,6 @@ void StartGdbServerDialog::updateProcessList()
 
 void StartGdbServerDialog::attachToProcess()
 {
-    QTC_ASSERT(d->gatherer, return);
-
     const QModelIndexList &indexes =
             d->tableView->selectionModel()->selectedIndexes();
     if (indexes.empty())
@@ -267,7 +258,7 @@ void StartGdbServerDialog::attachToProcess()
 
     LinuxDeviceConfiguration::ConstPtr device = d->currentDevice();
     PortList ports = device->freePorts();
-    const int port = d->gatherer->getNextFreePort(&ports);
+    const int port = d->gatherer.getNextFreePort(&ports);
     const int row = d->proxyModel.mapToSource(indexes.first()).row();
     QTC_ASSERT(row >= 0, return);
     const int pid = d->processList->pidAt(row);
@@ -321,11 +312,7 @@ void StartGdbServerDialog::portListReady()
 void StartGdbServerDialog::startGdbServer()
 {
     LinuxDeviceConfiguration::ConstPtr device = d->currentDevice();
-    if (d->gatherer)
-        delete d->gatherer;
-    d->gatherer = new RemoteLinuxUsedPortsGatherer(device);
-
-    d->gatherer->run();
+    d->gatherer.start(SshConnection::create(device->sshParameters()), device);
 }
 
 void StartGdbServerDialog::attachToRemoteProcess()
-- 
GitLab