Android: Flatten then AndroidRunnerWorker hierarchy again

The difference was the selection of findProcessPID vs
findProcessPIDPreNougat functions, done by a flag now
passed to and used inside a combined findProcessPID function.

Change-Id: I738cdac1a81302c2207f9bc3c74c7cf916ca4089
Reviewed-by: BogDan Vatra <bogdan@kdab.com>
This commit is contained in:
hjk
2018-05-09 12:20:54 +02:00
parent 5c8d49a3f6
commit 52e0b47c3f
4 changed files with 67 additions and 115 deletions

View File

@@ -147,26 +147,24 @@ AndroidRunner::AndroidRunner(RunControl *runControl,
}
const int apiLevel = AndroidManager::deviceApiLevel(m_target);
if (apiLevel > 23)
m_worker.reset(new AndroidRunnerWorker(runControl, m_androidRunnable));
else
m_worker.reset(new AndroidRunnerWorkerPreNougat(runControl, m_androidRunnable));
m_worker.reset(new AndroidRunnerWorker(runControl, m_androidRunnable));
m_worker->setIsPreNougat(apiLevel <= 23);
m_worker->setExtraAppParams(extraAppParams);
m_worker->setExtraEnvVars(extraEnvVars);
m_worker->moveToThread(&m_thread);
connect(this, &AndroidRunner::asyncStart, m_worker.data(), &AndroidRunnerWorkerBase::asyncStart);
connect(this, &AndroidRunner::asyncStop, m_worker.data(), &AndroidRunnerWorkerBase::asyncStop);
connect(this, &AndroidRunner::asyncStart, m_worker.data(), &AndroidRunnerWorker::asyncStart);
connect(this, &AndroidRunner::asyncStop, m_worker.data(), &AndroidRunnerWorker::asyncStop);
connect(this, &AndroidRunner::androidDeviceInfoChanged,
m_worker.data(), &AndroidRunnerWorkerBase::setAndroidDeviceInfo);
connect(m_worker.data(), &AndroidRunnerWorkerBase::remoteProcessStarted,
m_worker.data(), &AndroidRunnerWorker::setAndroidDeviceInfo);
connect(m_worker.data(), &AndroidRunnerWorker::remoteProcessStarted,
this, &AndroidRunner::handleRemoteProcessStarted);
connect(m_worker.data(), &AndroidRunnerWorkerBase::remoteProcessFinished,
connect(m_worker.data(), &AndroidRunnerWorker::remoteProcessFinished,
this, &AndroidRunner::handleRemoteProcessFinished);
connect(m_worker.data(), &AndroidRunnerWorkerBase::remoteOutput,
connect(m_worker.data(), &AndroidRunnerWorker::remoteOutput,
this, &AndroidRunner::remoteOutput);
connect(m_worker.data(), &AndroidRunnerWorkerBase::remoteErrorOutput,
connect(m_worker.data(), &AndroidRunnerWorker::remoteErrorOutput,
this, &AndroidRunner::remoteErrorOutput);
connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort,

View File

@@ -43,7 +43,7 @@
namespace Android {
namespace Internal {
class AndroidRunnerWorkerBase;
class AndroidRunnerWorker;
class AndroidRunner : public ProjectExplorer::RunWorker
{
@@ -84,7 +84,7 @@ private:
QString m_launchedAVDName;
QThread m_thread;
QTimer m_checkAVDTimer;
QScopedPointer<AndroidRunnerWorkerBase> m_worker;
QScopedPointer<AndroidRunnerWorker> m_worker;
QPointer<ProjectExplorer::Target> m_target;
Utils::Port m_gdbServerPort;
QUrl m_qmlServer;

View File

@@ -98,41 +98,28 @@ static qint64 extractPID(const QByteArray &output, const QString &packageName)
return pid;
}
void findProcessPIDPreNougat(QFutureInterface<qint64> &fi, const QString &adbPath,
QStringList selector, const QString &packageName)
static void findProcessPID(QFutureInterface<qint64> &fi, const QString &adbPath,
QStringList selector, const QString &packageName,
bool preNougat)
{
if (packageName.isEmpty())
return;
qint64 processPID = -1;
chrono::high_resolution_clock::time_point start = chrono::high_resolution_clock::now();
selector.append("shell");
selector.append(preNougat ? pidScriptPreNougat : pidScript.arg(packageName));
do {
QThread::msleep(200);
const QByteArray out = Utils::SynchronousProcess()
.runBlocking(adbPath, selector << QStringLiteral("shell") << pidScriptPreNougat)
.allRawOutput();
processPID = extractPID(out, packageName);
} while (processPID == -1 && !isTimedOut(start) && !fi.isCanceled());
if (!fi.isCanceled())
fi.reportResult(processPID);
}
void findProcessPID(QFutureInterface<qint64> &fi, const QString &adbPath,
QStringList selector, const QString &packageName)
{
if (packageName.isEmpty())
return;
qint64 processPID = -1;
chrono::high_resolution_clock::time_point start = chrono::high_resolution_clock::now();
do {
QThread::msleep(200);
const QByteArray out = Utils::SynchronousProcess()
.runBlocking(adbPath, selector << QStringLiteral("shell") << pidScript.arg(packageName))
.allRawOutput();
if (!out.isEmpty())
processPID = out.trimmed().toLongLong();
const QByteArray out = Utils::SynchronousProcess().runBlocking(adbPath, selector).allRawOutput();
if (preNougat) {
processPID = extractPID(out, packageName);
} else {
if (!out.isEmpty())
processPID = out.trimmed().toLongLong();
}
} while (processPID == -1 && !isTimedOut(start) && !fi.isCanceled());
if (!fi.isCanceled())
@@ -150,7 +137,7 @@ static void deleter(QProcess *p)
p->deleteLater();
}
AndroidRunnerWorkerBase::AndroidRunnerWorkerBase(RunControl *runControl, const AndroidRunnable &runnable)
AndroidRunnerWorker::AndroidRunnerWorker(RunControl *runControl, const AndroidRunnable &runnable)
: m_androidRunnable(runnable)
, m_adbLogcatProcess(nullptr, deleter)
, m_psIsAlive(nullptr, deleter)
@@ -192,7 +179,7 @@ AndroidRunnerWorkerBase::AndroidRunnerWorkerBase(RunControl *runControl, const A
m_apiLevel = AndroidManager::deviceApiLevel(target);
}
AndroidRunnerWorkerBase::~AndroidRunnerWorkerBase()
AndroidRunnerWorker::~AndroidRunnerWorker()
{
if (m_processPID != -1)
forceStop();
@@ -201,7 +188,7 @@ AndroidRunnerWorkerBase::~AndroidRunnerWorkerBase()
m_pidFinder.cancel();
}
bool AndroidRunnerWorkerBase::adbShellAmNeedsQuotes()
bool AndroidRunnerWorker::adbShellAmNeedsQuotes()
{
// Between Android SDK Tools version 24.3.1 and 24.3.4 the quoting
// needs for the 'adb shell am start ...' parameters changed.
@@ -223,7 +210,7 @@ bool AndroidRunnerWorkerBase::adbShellAmNeedsQuotes()
return !oldSdk;
}
bool AndroidRunnerWorkerBase::runAdb(const QStringList &args, int timeoutS)
bool AndroidRunnerWorker::runAdb(const QStringList &args, int timeoutS)
{
Utils::SynchronousProcess adb;
adb.setTimeoutS(timeoutS);
@@ -233,18 +220,18 @@ bool AndroidRunnerWorkerBase::runAdb(const QStringList &args, int timeoutS)
return response.result == Utils::SynchronousProcessResponse::Finished;
}
void AndroidRunnerWorkerBase::adbKill(qint64 pid)
void AndroidRunnerWorker::adbKill(qint64 pid)
{
runAdb({"shell", "kill", "-9", QString::number(pid)});
runAdb({"shell", "run-as", m_androidRunnable.packageName, "kill", "-9", QString::number(pid)});
}
QStringList AndroidRunnerWorkerBase::selector() const
QStringList AndroidRunnerWorker::selector() const
{
return AndroidDeviceInfo::adbSelector(m_deviceSerialNumber);
}
void AndroidRunnerWorkerBase::forceStop()
void AndroidRunnerWorker::forceStop()
{
runAdb({"shell", "am", "force-stop", m_androidRunnable.packageName}, 30);
@@ -259,19 +246,19 @@ void AndroidRunnerWorkerBase::forceStop()
}
}
void AndroidRunnerWorkerBase::logcatReadStandardError()
void AndroidRunnerWorker::logcatReadStandardError()
{
if (m_processPID != -1)
logcatProcess(m_adbLogcatProcess->readAllStandardError(), m_stderrBuffer, true);
}
void AndroidRunnerWorkerBase::logcatReadStandardOutput()
void AndroidRunnerWorker::logcatReadStandardOutput()
{
if (m_processPID != -1)
logcatProcess(m_adbLogcatProcess->readAllStandardOutput(), m_stdoutBuffer, false);
}
void AndroidRunnerWorkerBase::logcatProcess(const QByteArray &text, QByteArray &buffer, bool onlyError)
void AndroidRunnerWorker::logcatProcess(const QByteArray &text, QByteArray &buffer, bool onlyError)
{
QList<QByteArray> lines = text.split('\n');
// lines always contains at least one item
@@ -332,22 +319,22 @@ void AndroidRunnerWorkerBase::logcatProcess(const QByteArray &text, QByteArray &
}
}
void AndroidRunnerWorkerBase::setAndroidDeviceInfo(const AndroidDeviceInfo &info)
void AndroidRunnerWorker::setAndroidDeviceInfo(const AndroidDeviceInfo &info)
{
m_deviceSerialNumber = info.serialNumber;
m_apiLevel = info.sdk;
}
void AndroidRunnerWorkerBase::asyncStart()
void AndroidRunnerWorker::asyncStartHelper()
{
forceStop();
// Start the logcat process before app starts.
std::unique_ptr<QProcess, Deleter> logcatProcess(new QProcess, deleter);
connect(logcatProcess.get(), &QProcess::readyReadStandardOutput,
this, &AndroidRunnerWorkerBase::logcatReadStandardOutput);
this, &AndroidRunnerWorker::logcatReadStandardOutput);
connect(logcatProcess.get(), &QProcess::readyReadStandardError,
this, &AndroidRunnerWorkerBase::logcatReadStandardError);
this, &AndroidRunnerWorker::logcatReadStandardError);
// Its assumed that the device or avd returned by selector() is online.
logcatProcess->start(m_adb, selector() << "logcat");
QTC_ASSERT(!m_adbLogcatProcess, /**/);
@@ -444,7 +431,16 @@ void AndroidRunnerWorkerBase::asyncStart()
}
}
void AndroidRunnerWorkerBase::asyncStop()
void AndroidRunnerWorker::asyncStart()
{
asyncStartHelper();
m_pidFinder = Utils::onResultReady(Utils::runAsync(findProcessPID, m_adb, selector(),
m_androidRunnable.packageName, m_isPreNougat),
bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1));
}
void AndroidRunnerWorker::asyncStop()
{
if (!m_pidFinder.isFinished())
m_pidFinder.cancel();
@@ -456,7 +452,7 @@ void AndroidRunnerWorkerBase::asyncStop()
m_gdbServerProcess.reset();
}
void AndroidRunnerWorkerBase::handleJdbWaiting()
void AndroidRunnerWorker::handleJdbWaiting()
{
QStringList removeForward{"forward", "--remove", "tcp:" + m_localJdbServerPort.toString()};
runAdb(removeForward);
@@ -485,7 +481,7 @@ void AndroidRunnerWorkerBase::handleJdbWaiting()
m_jdbProcess = std::move(jdbProcess);
}
void AndroidRunnerWorkerBase::handleJdbSettled()
void AndroidRunnerWorker::handleJdbSettled()
{
auto waitForCommand = [&]() {
for (int i= 0; i < 5 && m_jdbProcess->state() == QProcess::Running; ++i) {
@@ -518,7 +514,7 @@ void AndroidRunnerWorkerBase::handleJdbSettled()
emit remoteProcessFinished(tr("Can't attach jdb to the running application").arg(m_lastRunAdbError));
}
void AndroidRunnerWorkerBase::onProcessIdChanged(qint64 pid)
void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
{
// Don't write to m_psProc from a different thread
QTC_ASSERT(QThread::currentThread() == thread(), return);
@@ -544,49 +540,22 @@ void AndroidRunnerWorkerBase::onProcessIdChanged(qint64 pid)
m_psIsAlive.reset(new QProcess);
m_psIsAlive->setProcessChannelMode(QProcess::MergedChannels);
connect(m_psIsAlive.get(), static_cast<void(QProcess::*)(int)>(&QProcess::finished),
this, bind(&AndroidRunnerWorkerBase::onProcessIdChanged, this, -1));
this, bind(&AndroidRunnerWorker::onProcessIdChanged, this, -1));
m_psIsAlive->start(m_adb, selector() << QStringLiteral("shell")
<< pidPollingScript.arg(m_processPID));
}
}
void AndroidRunnerWorkerBase::setExtraEnvVars(const Utils::Environment &extraEnvVars)
void AndroidRunnerWorker::setExtraEnvVars(const Utils::Environment &extraEnvVars)
{
m_extraEnvVars = extraEnvVars;
}
void AndroidRunnerWorkerBase::setExtraAppParams(const QString &extraAppParams)
void AndroidRunnerWorker::setExtraAppParams(const QString &extraAppParams)
{
m_extraAppParams = extraAppParams;
}
AndroidRunnerWorker::AndroidRunnerWorker(RunControl *runControl, const AndroidRunnable &runnable)
: AndroidRunnerWorkerBase(runControl, runnable)
{
}
void AndroidRunnerWorker::asyncStart()
{
AndroidRunnerWorkerBase::asyncStart();
m_pidFinder = Utils::onResultReady(Utils::runAsync(&findProcessPID, m_adb, selector(),
m_androidRunnable.packageName),
bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1));
}
AndroidRunnerWorkerPreNougat::AndroidRunnerWorkerPreNougat(RunControl *runControl, const AndroidRunnable &runnable)
: AndroidRunnerWorkerBase(runControl, runnable)
{
}
void AndroidRunnerWorkerPreNougat::asyncStart()
{
AndroidRunnerWorkerBase::asyncStart();
m_pidFinder = Utils::onResultReady(Utils::runAsync(&findProcessPIDPreNougat, m_adb, selector(),
m_androidRunnable.packageName),
bind(&AndroidRunnerWorkerPreNougat::onProcessIdChanged, this, _1));
}
} // namespace Internal
} // namespace Android

View File

@@ -29,7 +29,6 @@
#include <qmldebug/qmldebugcommandlinearguments.h>
#include <QFuture>
#include <QTcpSocket>
#include "androidrunnable.h"
@@ -45,12 +44,12 @@ namespace Internal {
const int MIN_SOCKET_HANDSHAKE_PORT = 20001;
class AndroidRunnerWorkerBase : public QObject
class AndroidRunnerWorker : public QObject
{
Q_OBJECT
public:
AndroidRunnerWorkerBase(ProjectExplorer::RunControl *runControl, const AndroidRunnable &runnable);
~AndroidRunnerWorkerBase() override;
AndroidRunnerWorker(ProjectExplorer::RunControl *runControl, const AndroidRunnable &runnable);
~AndroidRunnerWorker() override;
bool adbShellAmNeedsQuotes();
bool runAdb(const QStringList &args, int timeoutS = 10);
void adbKill(qint64 pid);
@@ -62,11 +61,12 @@ public:
void setAndroidDeviceInfo(const AndroidDeviceInfo &info);
void setExtraEnvVars(const Utils::Environment &extraEnvVars);
void setExtraAppParams(const QString &extraAppParams);
void setIsPreNougat(bool isPreNougat) { m_isPreNougat = isPreNougat; }
virtual void asyncStart();
virtual void asyncStop();
virtual void handleJdbWaiting();
virtual void handleJdbSettled();
void asyncStart();
void asyncStop();
void handleJdbWaiting();
void handleJdbSettled();
signals:
void remoteProcessStarted(Utils::Port gdbServerPort, const QUrl &qmlServer, int pid);
@@ -76,15 +76,18 @@ signals:
void remoteErrorOutput(const QString &output);
protected:
void asyncStartHelper();
enum class JDBState {
Idle,
Waiting,
Settled
};
virtual void onProcessIdChanged(qint64 pid);
void onProcessIdChanged(qint64 pid);
using Deleter = void (*)(QProcess *);
// Create the processes and timer in the worker thread, for correct thread affinity
bool m_isPreNougat = false;
AndroidRunnable m_androidRunnable;
QString m_adb;
qint64 m_processPID = -1;
@@ -110,23 +113,5 @@ protected:
Utils::Environment m_extraEnvVars;
};
class AndroidRunnerWorker : public AndroidRunnerWorkerBase
{
Q_OBJECT
public:
AndroidRunnerWorker(ProjectExplorer::RunControl *runControl, const AndroidRunnable &runnable);
void asyncStart() override;
};
class AndroidRunnerWorkerPreNougat : public AndroidRunnerWorkerBase
{
Q_OBJECT
public:
AndroidRunnerWorkerPreNougat(ProjectExplorer::RunControl *runControl, const AndroidRunnable &runnable);
void asyncStart() override;
};
} // namespace Internal
} // namespace Android