Android: Run stop() asynchronously

Running SynchronousProcess (for adb) on the GUI thread is dangerous as
it might process unrelated events without returning, breaking
assumptions in other parts of Qt Creator. Rather run those things on a
worker thread, with a separate event loop, like we already do it when
starting processes.

Furthermore, returning, from start() or stop() while a thread is
running that accesses internals of AndroidRunner is also dangerous,
because most methods of AndroidRunner are not protected by relevant
mutexes and especially the destructor might get invoked while the
worker thread is still runnig. Thus, wait for the worker threads to
finish, in start() and stop().

This is a crutch, of course, as with proper locking we could keep the
GUI thread responsive while the adb commands are running, but just
serializing the execution reduces the risk of further breakage for now.

Change-Id: Ife92dc19aa8111374413590c3156027ba759746f
Task-number: QTCREATORBUG-16667
Reviewed-by: BogDan Vatra <bogdan@kdab.com>
This commit is contained in:
Ulf Hermann
2016-07-27 15:58:28 +02:00
parent cbd738ab90
commit 6c2036d900
2 changed files with 12 additions and 7 deletions

View File

@@ -324,7 +324,7 @@ void AndroidRunner::start()
{
m_adbLogcatProcess.start(m_adb, selector() << _("logcat"));
m_psProc.start(m_adb, selector() << _("shell"));
Utils::runAsync(&AndroidRunner::asyncStart, this);
Utils::runAsync(&AndroidRunner::asyncStart, this).waitForFinished();
}
void AndroidRunner::asyncStart()
@@ -519,18 +519,22 @@ void AndroidRunner::handleRemoteDebuggerRunning()
void AndroidRunner::stop()
{
QMutexLocker locker(&m_mutex);
m_checkPIDTimer.stop();
m_adbLogcatProcess.kill();
m_psProc.kill();
Utils::runAsync(&AndroidRunner::asyncStop, this).waitForFinished();
m_adbLogcatProcess.waitForFinished();
m_psProc.waitForFinished();
}
void AndroidRunner::asyncStop()
{
QMutexLocker locker(&m_mutex);
m_tries = 0;
if (m_processPID != -1) {
forceStop();
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" terminated.").arg(m_androidRunnable.packageName));
}
//QObject::disconnect(&m_adbLogcatProcess, 0, this, 0);
m_adbLogcatProcess.kill();
m_adbLogcatProcess.waitForFinished();
m_psProc.kill();
m_psProc.waitForFinished();
foreach (const QStringList &entry, m_androidRunnable.afterFinishADBCommands)
runAdb(selector() << entry);
}