aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/android/androidrunnerworker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/android/androidrunnerworker.cpp')
-rw-r--r--src/plugins/android/androidrunnerworker.cpp342
1 files changed, 228 insertions, 114 deletions
diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp
index 1fb878109f..9b1b067f76 100644
--- a/src/plugins/android/androidrunnerworker.cpp
+++ b/src/plugins/android/androidrunnerworker.cpp
@@ -30,6 +30,7 @@
#include "androidmanager.h"
#include "androidrunconfiguration.h"
+#include <debugger/debuggerkitinformation.h>
#include <debugger/debuggerrunconfigurationaspect.h>
#include <projectexplorer/environmentaspect.h>
@@ -40,15 +41,21 @@
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
+#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
+#include <utils/qtcprocess.h>
#include <utils/runextensions.h>
+#include <utils/stringutils.h>
#include <utils/synchronousprocess.h>
#include <utils/temporaryfile.h>
-#include <utils/qtcprocess.h>
#include <utils/url.h>
-#include <utils/fileutils.h>
+#include <QDir>
+#include <QDirIterator>
+#include <QFileInfo>
#include <QLoggingCategory>
+#include <QScopeGuard>
+#include <QRegularExpression>
#include <QTcpServer>
#include <QThread>
@@ -72,20 +79,19 @@ static const QString pidScriptPreNougat = QStringLiteral("for p in /proc/[0-9]*;
"do cat <$p/cmdline && echo :${p##*/}; done");
static const QString pidPollingScript = QStringLiteral("while [ -d /proc/%1 ]; do sleep 1; done");
-static const QString regExpLogcat = QStringLiteral("[0-9\\-]*" // date
- "\\s+"
- "[0-9\\-:.]*"// time
- "\\s*"
- "(\\d*)" // pid 1. capture
- "\\s+"
- "\\d*" // unknown
- "\\s+"
- "(\\w)" // message type 2. capture
- "\\s+"
- "(.*): " // source 3. capture
- "(.*)" // message 4. capture
- "[\\n\\r]*"
- );
+static const QRegularExpression regExpLogcat{"^[0-9\\-]*" // date
+ "\\s+"
+ "[0-9\\-:.]*"// time
+ "\\s*"
+ "(\\d*)" // pid 1. capture
+ "\\s+"
+ "\\d*" // unknown
+ "\\s+"
+ "(\\w)" // message type 2. capture
+ "\\s+"
+ "(.*): " // source 3. capture
+ "(.*)" // message 4. capture
+ "[\\n\\r]*$"};
static int APP_START_TIMEOUT = 45000;
static bool isTimedOut(const chrono::high_resolution_clock::time_point &start,
@@ -118,7 +124,6 @@ static qint64 extractPID(const QByteArray &output, const QString &packageName)
static void findProcessPID(QFutureInterface<qint64> &fi, QStringList selector,
const QString &packageName, bool preNougat)
{
- qCDebug(androidRunWorkerLog) << "Finding PID. PreNougat:" << preNougat;
if (packageName.isEmpty())
return;
@@ -138,7 +143,7 @@ static void findProcessPID(QFutureInterface<qint64> &fi, QStringList selector,
}
} while (processPID == -1 && !isTimedOut(start) && !fi.isCanceled());
- qCDebug(androidRunWorkerLog) << "PID found:" << processPID;
+ qCDebug(androidRunWorkerLog) << "PID found:" << processPID << ", PreNougat:" << preNougat;
if (!fi.isCanceled())
fi.reportResult(processPID);
}
@@ -151,23 +156,100 @@ static void deleter(QProcess *p)
p->kill();
p->waitForFinished();
}
- qCDebug(androidRunWorkerLog) << "Done killing process:" << p->objectName();
// Might get deleted from its own signal handler.
p->deleteLater();
}
+static QString gdbServerArch(const QString &androidAbi)
+{
+ if (androidAbi == "arm64-v8a")
+ return QString("arm64");
+ if (androidAbi == "armeabi-v7a")
+ return QString("arm");
+ // That's correct for "x86_64" and "x86", and best guess at anything that will evolve:
+ return androidAbi;
+}
+
+static QString lldbServerArch(const QString &androidAbi)
+{
+ if (androidAbi == "armeabi-v7a")
+ return QString("armeabi");
+ // Correct for arm64-v8a "x86_64" and "x86", and best guess at anything that will evolve:
+ return androidAbi; // arm64-v8a, x86, x86_64
+}
+
+static QString lldbServerArch2(const QString &androidAbi)
+{
+ if (androidAbi == "armeabi-v7a")
+ return {"arm"};
+ if (androidAbi == "x86")
+ return {"i386"};
+ if (androidAbi == "arm64-v8a")
+ return {"aarch64"};
+ // Correct for "x86_64" a and best guess at anything that will evolve:
+ return androidAbi; // arm64-v8a
+}
+
+static FilePath debugServer(bool useLldb, const Target *target)
+{
+ QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target->kit());
+ QString preferredAbi = AndroidManager::apkDevicePreferredAbi(target);
+
+ const AndroidConfig &config = AndroidConfigurations::currentConfig();
+
+ if (useLldb) {
+ // Search suitable lldb-server binary.
+ const FilePath prebuilt = config.ndkLocation(qtVersion) / "toolchains/llvm/prebuilt";
+ const QString abiNeedle = lldbServerArch2(preferredAbi);
+
+ // The new, built-in LLDB.
+ QDirIterator it(prebuilt.toString(), QDir::Files|QDir::Executable, QDirIterator::Subdirectories);
+ while (it.hasNext()) {
+ it.next();
+ const QString filePath = it.filePath();
+ if (filePath.endsWith(abiNeedle + "/lldb-server")) {
+ return FilePath::fromString(filePath);
+ }
+ }
+
+ // Older: Find LLDB version. sdk_definitions.json contains something like "lldb;3.1". Use that.
+ const QStringList packages = config.defaultEssentials();
+ for (const QString &package : packages) {
+ if (package.startsWith("lldb;")) {
+ const QString lldbVersion = package.mid(5);
+ const FilePath path = config.sdkLocation()
+ / QString("lldb/%1/android/%2/lldb-server")
+ .arg(lldbVersion, lldbServerArch(preferredAbi));
+ if (path.exists())
+ return path;
+ }
+ }
+ } else {
+ // Search suitable gdbserver binary.
+ const FilePath path = config.ndkLocation(qtVersion)
+ .pathAppended(QString("prebuilt/android-%1/gdbserver/gdbserver")
+ .arg(gdbServerArch(preferredAbi)));
+ if (path.exists())
+ return path;
+ }
+
+ return {};
+}
+
+
AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packageName)
: m_packageName(packageName)
, m_adbLogcatProcess(nullptr, deleter)
, m_psIsAlive(nullptr, deleter)
- , m_logCatRegExp(regExpLogcat)
- , m_gdbServerProcess(nullptr, deleter)
+ , m_debugServerProcess(nullptr, deleter)
, m_jdbProcess(nullptr, deleter)
{
auto runControl = runner->runControl();
+ m_useLldb = Debugger::DebuggerKitAspect::engineType(runControl->kit())
+ == Debugger::LldbEngineType;
auto aspect = runControl->aspect<Debugger::DebuggerRunConfigurationAspect>();
- Core::Id runMode = runControl->runMode();
+ Utils::Id runMode = runControl->runMode();
const bool debuggingMode = runMode == ProjectExplorer::Constants::DEBUG_RUN_MODE;
m_useCppDebugger = debuggingMode && aspect->useCppDebugger();
if (debuggingMode && aspect->useQmlDebugger())
@@ -178,8 +260,8 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
m_qmlDebugServices = QmlDebug::QmlPreviewServices;
else
m_qmlDebugServices = QmlDebug::NoQmlDebugServices;
- m_localGdbServerPort = Utils::Port(5039);
- QTC_CHECK(m_localGdbServerPort.isValid());
+ m_localDebugServerPort = Utils::Port(5039);
+ QTC_CHECK(m_localDebugServerPort.isValid());
if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices) {
qCDebug(androidRunWorkerLog) << "QML debugging enabled";
QTcpServer server;
@@ -203,8 +285,10 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
m_extraAppParams = runControl->runnable().commandLineArguments;
- if (auto aspect = runControl->aspect(Constants::ANDROID_AMSTARTARGS))
- m_amStartExtraArgs = static_cast<BaseStringAspect *>(aspect)->value().split(' ');
+ if (auto aspect = runControl->aspect(Constants::ANDROID_AMSTARTARGS)) {
+ const QString startArgs = static_cast<BaseStringAspect *>(aspect)->value();
+ m_amStartExtraArgs = QtcProcess::splitArgs(startArgs, OsTypeOtherUnix);
+ }
if (auto aspect = runControl->aspect(Constants::ANDROID_PRESTARTSHELLCMDLIST)) {
for (const QString &shellCmd : static_cast<BaseStringListAspect *>(aspect)->value())
@@ -220,16 +304,15 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
for (const QString &shellCmd : runner->recordedData(Constants::ANDROID_POSTFINISHSHELLCMDLIST).toStringList())
m_afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd));
+ m_debugServerPath = debugServer(m_useLldb, target).toString();
qCDebug(androidRunWorkerLog) << "Device Serial:" << m_deviceSerialNumber
- << "API level:" << m_apiLevel
- << "Extra Start Args:" << m_amStartExtraArgs
- << "Before Start ADB cmds:" << m_beforeStartAdbCommands
- << "After finish ADB cmds:" << m_afterFinishAdbCommands;
+ << ", API level:" << m_apiLevel
+ << ", Extra Start Args:" << m_amStartExtraArgs
+ << ", Before Start ADB cmds:" << m_beforeStartAdbCommands
+ << ", After finish ADB cmds:" << m_afterFinishAdbCommands
+ << ", Debug server path:" << m_debugServerPath;
+
QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(target->kit());
- QString preferredAbi = AndroidManager::apkDevicePreferredAbi(target);
- if (!preferredAbi.isEmpty())
- m_gdbserverPath = AndroidConfigurations::instance()
- ->currentConfig().gdbServer(preferredAbi, version).toString();
m_useAppParamsForQmlDebugger = version->qtVersion() >= QtSupport::QtVersionNumber(5, 12);
}
@@ -254,45 +337,41 @@ bool AndroidRunnerWorker::runAdb(const QStringList &args, QString *stdOut,
return result.success();
}
-bool AndroidRunnerWorker::uploadGdbServer()
+bool AndroidRunnerWorker::uploadDebugServer(const QString &debugServerFileName)
{
- // Push the gdbserver to temp location and then to package dir.
+ // Push the gdbserver or lldb-server to temp location and then to package dir.
// the files can't be pushed directly to package because of permissions.
qCDebug(androidRunWorkerLog) << "Uploading GdbServer";
- bool foundUnique = true;
- auto cleanUp = [this, &foundUnique] (QString *p) {
- if (foundUnique && !runAdb({"shell", "rm", "-f", *p}))
- qCDebug(androidRunWorkerLog) << "Gdbserver cleanup failed.";
- delete p;
- };
- std::unique_ptr<QString, decltype (cleanUp)>
- tempGdbServerPath(new QString("/data/local/tmp/%1"), cleanUp);
-
- // Get a unique temp file name for gdbserver copy
+ // Get a unique temp file name for gdb/lldbserver copy
+ const QString tempDebugServerPathTemplate = "/data/local/tmp/%1";
int count = 0;
- while (deviceFileExists(tempGdbServerPath->arg(++count))) {
+ while (deviceFileExists(tempDebugServerPathTemplate.arg(++count))) {
if (count > GdbTempFileMaxCounter) {
qCDebug(androidRunWorkerLog) << "Can not get temporary file name";
- foundUnique = false;
return false;
}
}
- *tempGdbServerPath = tempGdbServerPath->arg(count);
+
+ const QString tempDebugServerPath = tempDebugServerPathTemplate.arg(count);
+ auto cleanUp = qScopeGuard([this, tempDebugServerPath] {
+ if (!runAdb({"shell", "rm", "-f", tempDebugServerPath}))
+ qCDebug(androidRunWorkerLog) << "Debug server cleanup failed.";
+ });
// Copy gdbserver to temp location
- if (!runAdb({"push", m_gdbserverPath , *tempGdbServerPath})) {
- qCDebug(androidRunWorkerLog) << "Gdbserver upload to temp directory failed";
+ if (!runAdb({"push", m_debugServerPath , tempDebugServerPath})) {
+ qCDebug(androidRunWorkerLog) << "Debug server upload to temp directory failed";
return false;
}
// Copy gdbserver from temp location to app directory
- if (!runAdb({"shell", "run-as", m_packageName, "cp" , *tempGdbServerPath, "./gdbserver"})) {
- qCDebug(androidRunWorkerLog) << "Gdbserver copy from temp directory failed";
+ if (!runAdb({"shell", "run-as", m_packageName, "cp" , tempDebugServerPath, debugServerFileName})) {
+ qCDebug(androidRunWorkerLog) << "Debug server copy from temp directory failed";
return false;
}
- QTC_ASSERT(runAdb({"shell", "run-as", m_packageName, "chmod", "777", "./gdbserver"}),
- qCDebug(androidRunWorkerLog) << "Gdbserver chmod 777 failed.");
+ QTC_ASSERT(runAdb({"shell", "run-as", m_packageName, "chmod", "777", debugServerFileName}),
+ qCDebug(androidRunWorkerLog) << "Debug server chmod 777 failed.");
return true;
}
@@ -378,11 +457,12 @@ void AndroidRunnerWorker::logcatProcess(const QByteArray &text, QByteArray &buff
break;
}
}
- if (m_logCatRegExp.exactMatch(line)) {
+ const QRegularExpressionMatch match = regExpLogcat.match(line);
+ if (match.hasMatch()) {
// Android M
- if (m_logCatRegExp.cap(1) == pidString) {
- const QString &messagetype = m_logCatRegExp.cap(2);
- QString output = line.mid(m_logCatRegExp.pos(2));
+ if (match.captured(1) == pidString) {
+ const QString messagetype = match.captured(2);
+ const QString output = line.mid(match.capturedStart(2));
if (onlyError
|| messagetype == QLatin1String("F")
@@ -428,7 +508,7 @@ void AndroidRunnerWorker::asyncStartHelper()
}
for (const QString &entry : m_beforeStartAdbCommands)
- runAdb(entry.split(' ', QString::SkipEmptyParts));
+ runAdb(entry.split(' ', Utils::SkipEmptyParts));
QStringList args({"shell", "am", "start"});
args << m_amStartExtraArgs;
@@ -447,32 +527,47 @@ void AndroidRunnerWorker::asyncStartHelper()
// e.g. on Android 8 with NDK 10e
runAdb({"shell", "run-as", m_packageName, "chmod", "a+x", packageDir.trimmed()});
- QString gdbServerExecutable = "gdbserver";
- QString gdbServerPrefix = "./lib/";
- auto findGdbServer = [this, &gdbServerExecutable, gdbServerPrefix](const QString& gdbEx) {
- if (!packageFileExists(gdbServerPrefix + gdbEx))
- return false;
- gdbServerExecutable = gdbEx;
- return true;
- };
-
- if (!findGdbServer("gdbserver") && !findGdbServer("libgdbserver.so")) {
- // Armv8. symlink lib is not available.
- // Kill the previous instances of gdbserver. Do this before copying the gdbserver.
- runAdb({"shell", "run-as", m_packageName, "killall", gdbServerExecutable});
- if (!m_gdbserverPath.isEmpty() && uploadGdbServer()) {
- gdbServerPrefix = "./";
- } else {
- emit remoteProcessFinished(tr("Cannot find or copy C++ debug server."));
+ if (!QFileInfo::exists(m_debugServerPath)) {
+ QString msg = tr("Cannot find C++ debug server in NDK installation");
+ if (m_useLldb) {
+ msg += "\n" + tr("The lldb-server binary has not been found. Maybe "
+ "sdk_definitions.json does not contain 'lldb;x.y' as "
+ "sdk_essential_package or LLDB was not installed.");
+ }
+ emit remoteProcessFinished(msg);
+ return;
+ }
+
+ QString debugServerFile;
+ if (m_useLldb) {
+ debugServerFile = "./lldb-server";
+ runAdb({"shell", "run-as", m_packageName, "killall", "lldb-server"});
+ if (!uploadDebugServer(debugServerFile)) {
+ emit remoteProcessFinished(tr("Cannot copy C++ debug server."));
return;
}
} else {
- qCDebug(androidRunWorkerLog) << "Found GDB server under ./lib";
- runAdb({"shell", "run-as", m_packageName, "killall", gdbServerExecutable});
+ if (packageFileExists("./lib/gdbserver")) {
+ debugServerFile = "./lib/gdbserver";
+ qCDebug(androidRunWorkerLog) << "Found GDB server " + debugServerFile;
+ runAdb({"shell", "run-as", m_packageName, "killall", "gdbserver"});
+ } else if (packageFileExists("./lib/libgdbserver.so")) {
+ debugServerFile = "./lib/libgdbserver.so";
+ qCDebug(androidRunWorkerLog) << "Found GDB server " + debugServerFile;
+ runAdb({"shell", "run-as", m_packageName, "killall", "libgdbserver.so"});
+ } else {
+ // Armv8. symlink lib is not available.
+ debugServerFile = "./gdbserver";
+ // Kill the previous instances of gdbserver. Do this before copying the gdbserver.
+ runAdb({"shell", "run-as", m_packageName, "killall", "gdbserver"});
+ if (!uploadDebugServer("./gdbserver")) {
+ emit remoteProcessFinished(tr("Cannot copy C++ debug server."));
+ return;
+ }
+ }
}
-
QString debuggerServerErr;
- if (!startDebuggerServer(packageDir, gdbServerPrefix, gdbServerExecutable, &debuggerServerErr)) {
+ if (!startDebuggerServer(packageDir, debugServerFile, &debuggerServerErr)) {
emit remoteProcessFinished(debuggerServerErr);
return;
}
@@ -525,37 +620,56 @@ void AndroidRunnerWorker::asyncStartHelper()
}
bool AndroidRunnerWorker::startDebuggerServer(const QString &packageDir,
- const QString &gdbServerPrefix,
- const QString &gdbServerExecutable,
+ const QString &debugServerFile,
QString *errorStr)
{
- QString gdbServerSocket = packageDir + "/debug-socket";
- runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket});
-
- QString gdbProcessErr;
- QStringList gdbServerArgs = selector();
- gdbServerArgs << "shell" << "run-as" << m_packageName << gdbServerPrefix + gdbServerExecutable
- << "--multi" << "+" + gdbServerSocket;
- m_gdbServerProcess.reset(AndroidManager::runAdbCommandDetached(gdbServerArgs, &gdbProcessErr));
-
- if (!m_gdbServerProcess) {
- qCDebug(androidRunWorkerLog) << "Debugger process failed to start" << gdbProcessErr;
- if (errorStr)
- *errorStr = tr("Failed to start debugger server.");
- return false;
- }
- qCDebug(androidRunWorkerLog) << "Debugger process started";
- m_gdbServerProcess->setObjectName("AndroidDebugServerProcess");
+ if (m_useLldb) {
+ QString lldbServerErr;
+ QStringList lldbServerArgs = selector();
+ lldbServerArgs << "shell" << "run-as" << m_packageName << debugServerFile
+ << "platform"
+ // << "--server" // Can lead to zombie servers
+ << "--listen" << QString("*:%1").arg(m_localDebugServerPort.toString());
+ m_debugServerProcess.reset(AndroidManager::runAdbCommandDetached(lldbServerArgs, &lldbServerErr));
+
+ if (!m_debugServerProcess) {
+ qCDebug(androidRunWorkerLog) << "Debugger process failed to start" << lldbServerErr;
+ if (errorStr)
+ *errorStr = tr("Failed to start debugger server.");
+ return false;
+ }
+ qCDebug(androidRunWorkerLog) << "Debugger process started";
+ m_debugServerProcess->setObjectName("AndroidDebugServerProcess");
- QStringList removeForward{"forward", "--remove", "tcp:" + m_localGdbServerPort.toString()};
- runAdb(removeForward);
- if (!runAdb({"forward", "tcp:" + m_localGdbServerPort.toString(),
- "localfilesystem:" + gdbServerSocket})) {
- if (errorStr)
- *errorStr = tr("Failed to forward C++ debugging ports.");
- return false;
+ } else {
+ QString gdbServerSocket = packageDir + "/debug-socket";
+ runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket});
+
+ QString gdbProcessErr;
+ QStringList gdbServerErr = selector();
+ gdbServerErr << "shell" << "run-as" << m_packageName << debugServerFile
+ << "--multi" << "+" + gdbServerSocket;
+ m_debugServerProcess.reset(AndroidManager::runAdbCommandDetached(gdbServerErr, &gdbProcessErr));
+
+ if (!m_debugServerProcess) {
+ qCDebug(androidRunWorkerLog) << "Debugger process failed to start" << gdbServerErr;
+ if (errorStr)
+ *errorStr = tr("Failed to start debugger server.");
+ return false;
+ }
+ qCDebug(androidRunWorkerLog) << "Debugger process started";
+ m_debugServerProcess->setObjectName("AndroidDebugServerProcess");
+
+ QStringList removeForward{"forward", "--remove", "tcp:" + m_localDebugServerPort.toString()};
+ runAdb(removeForward);
+ if (!runAdb({"forward", "tcp:" + m_localDebugServerPort.toString(),
+ "localfilesystem:" + gdbServerSocket})) {
+ if (errorStr)
+ *errorStr = tr("Failed to forward C++ debugging ports.");
+ return false;
+ }
+ m_afterFinishAdbCommands.push_back(removeForward.join(' '));
}
- m_afterFinishAdbCommands.push_back(removeForward.join(' '));
return true;
}
@@ -577,7 +691,7 @@ void AndroidRunnerWorker::asyncStop()
forceStop();
m_jdbProcess.reset();
- m_gdbServerProcess.reset();
+ m_debugServerProcess.reset();
}
void AndroidRunnerWorker::handleJdbWaiting()
@@ -612,7 +726,7 @@ void AndroidRunnerWorker::handleJdbWaiting()
void AndroidRunnerWorker::handleJdbSettled()
{
qCDebug(androidRunWorkerLog) << "Handle JDB settled";
- auto waitForCommand = [&]() {
+ auto waitForCommand = [this]() {
for (int i= 0; i < 5 && m_jdbProcess->state() == QProcess::Running; ++i) {
m_jdbProcess->waitForReadyRead(500);
QByteArray lines = m_jdbProcess->readAll();
@@ -655,19 +769,19 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
if (pid == -1) {
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.")
.arg(m_packageName));
- // App died/killed. Reset log, monitor, jdb & gdb processes.
+ // App died/killed. Reset log, monitor, jdb & gdbserver/lldb-server processes.
m_adbLogcatProcess.reset();
m_psIsAlive.reset();
m_jdbProcess.reset();
- m_gdbServerProcess.reset();
+ m_debugServerProcess.reset();
// Run adb commands after application quit.
for (const QString &entry: m_afterFinishAdbCommands)
- runAdb(entry.split(' ', QString::SkipEmptyParts));
+ runAdb(entry.split(' ', Utils::SkipEmptyParts));
} else {
// In debugging cases this will be funneled to the engine to actually start
// and attach gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
- emit remoteProcessStarted(m_localGdbServerPort, m_qmlServer, m_processPID);
+ emit remoteProcessStarted(m_localDebugServerPort, m_qmlServer, m_processPID);
logcatReadStandardOutput();
QTC_ASSERT(!m_psIsAlive, /**/);
QStringList isAliveArgs = selector() << "shell" << pidPollingScript.arg(m_processPID);