Add AndroidRunnable

Using the AndroidRunnable is easy for other plugins to run custom adb
commands before intent is started and after it's stopped.

Change-Id: I012ae87c92cea16aa8074dce2dc6f2b0c4ebeb30
Reviewed-by: hjk <hjk@theqtcompany.com>
This commit is contained in:
BogDan Vatra
2016-01-29 14:05:00 +02:00
parent b5b328c331
commit 221b03a162
6 changed files with 91 additions and 23 deletions

View File

@@ -47,7 +47,8 @@ HEADERS += \
avddialog.h \ avddialog.h \
android_global.h \ android_global.h \
androidbuildapkstep.h \ androidbuildapkstep.h \
androidbuildapkwidget.h androidbuildapkwidget.h \
androidrunnable.h
SOURCES += \ SOURCES += \
androidconfigurations.cpp \ androidconfigurations.cpp \

View File

@@ -77,6 +77,7 @@ QtcPlugin {
"androidruncontrol.h", "androidruncontrol.h",
"androidrunfactories.cpp", "androidrunfactories.cpp",
"androidrunfactories.h", "androidrunfactories.h",
"androidrunnable.h",
"androidrunner.cpp", "androidrunner.cpp",
"androidrunner.h", "androidrunner.h",
"androidsettingspage.cpp", "androidsettingspage.cpp",

View File

@@ -42,6 +42,7 @@ AndroidRunControl::AndroidRunControl(AndroidRunConfiguration *rc)
, m_runner(new AndroidRunner(this, rc, ProjectExplorer::Constants::NORMAL_RUN_MODE)) , m_runner(new AndroidRunner(this, rc, ProjectExplorer::Constants::NORMAL_RUN_MODE))
, m_running(false) , m_running(false)
{ {
setRunnable(m_runner->runnable());
setIcon(Icons::RUN_SMALL); setIcon(Icons::RUN_SMALL);
} }
@@ -63,6 +64,7 @@ void AndroidRunControl::start()
connect(m_runner, SIGNAL(remoteProcessFinished(QString)), connect(m_runner, SIGNAL(remoteProcessFinished(QString)),
SLOT(handleRemoteProcessFinished(QString))); SLOT(handleRemoteProcessFinished(QString)));
appendMessage(tr("Starting remote process."), Utils::NormalMessageFormat); appendMessage(tr("Starting remote process."), Utils::NormalMessageFormat);
m_runner->setRunnable(runnable().as<AndroidRunnable>());
m_runner->start(); m_runner->start();
} }

View File

@@ -0,0 +1,47 @@
/****************************************************************************
**
** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#ifndef ANDROIDRUNNABLE_H
#define ANDROIDRUNNABLE_H
#include "android_global.h"
#include <projectexplorer/runnables.h>
namespace Android {
struct ANDROID_EXPORT AndroidRunnable
{
QString packageName;
QString intentName;
QString commandLineArguments;
Utils::Environment environment;
QVector<QStringList> beforeStartADBCommands;
QVector<QStringList> afterFinishADBCommands;
QString deviceSerialNumber;
};
} // namespace Android
#endif // ANDROIDRUNNABLE_H

View File

@@ -149,17 +149,17 @@ AndroidRunner::AndroidRunner(QObject *parent,
m_qmlPort = 0; m_qmlPort = 0;
} }
ProjectExplorer::Target *target = runConfig->target(); ProjectExplorer::Target *target = runConfig->target();
m_intentName = AndroidManager::intentName(target); m_androidRunnable.intentName = AndroidManager::intentName(target);
m_packageName = m_intentName.left(m_intentName.indexOf(QLatin1Char('/'))); m_androidRunnable.packageName = m_androidRunnable.intentName.left(m_androidRunnable.intentName.indexOf(QLatin1Char('/')));
m_deviceSerialNumber = AndroidManager::deviceSerialNumber(target); m_androidRunnable.deviceSerialNumber = AndroidManager::deviceSerialNumber(target);
m_processPID = -1; m_processPID = -1;
m_adb = AndroidConfigurations::currentConfig().adbToolPath().toString(); m_adb = AndroidConfigurations::currentConfig().adbToolPath().toString();
m_selector = AndroidDeviceInfo::adbSelector(m_deviceSerialNumber); m_selector = AndroidDeviceInfo::adbSelector(m_androidRunnable.deviceSerialNumber);
QString packageDir = _("/data/data/") + m_packageName; QString packageDir = _("/data/data/") + m_androidRunnable.packageName;
m_pingFile = packageDir + _("/debug-ping"); m_pingFile = packageDir + _("/debug-ping");
m_pongFile = _("/data/local/tmp/qt/debug-pong-") + m_packageName; m_pongFile = _("/data/local/tmp/qt/debug-pong-") + m_androidRunnable.packageName;
m_gdbserverSocket = packageDir + _("/debug-socket"); m_gdbserverSocket = packageDir + _("/debug-socket");
const QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target->kit()); const QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target->kit());
if (version && version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0)) if (version && version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0))
@@ -263,16 +263,16 @@ QByteArray AndroidRunner::runPs()
void AndroidRunner::checkPID() void AndroidRunner::checkPID()
{ {
QByteArray psOut = runPs(); QByteArray psOut = runPs();
m_processPID = extractPid(m_packageName, psOut); m_processPID = extractPid(m_androidRunnable.packageName, psOut);
if (m_processPID == -1) { if (m_processPID == -1) {
if (m_wasStarted) { if (m_wasStarted) {
m_wasStarted = false; m_wasStarted = false;
m_checkPIDTimer.stop(); m_checkPIDTimer.stop();
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.").arg(m_packageName)); emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.").arg(m_androidRunnable.packageName));
} else { } else {
if (++m_tries > 3) if (++m_tries > 3)
emit remoteProcessFinished(QLatin1String("\n\n") + tr("Unable to start \"%1\".").arg(m_packageName)); emit remoteProcessFinished(QLatin1String("\n\n") + tr("Unable to start \"%1\".").arg(m_androidRunnable.packageName));
} }
} else if (!m_wasStarted){ } else if (!m_wasStarted){
if (m_useCppDebugger) { if (m_useCppDebugger) {
@@ -300,7 +300,7 @@ void AndroidRunner::forceStop()
{ {
QProcess proc; QProcess proc;
proc.start(m_adb, selector() << _("shell") << _("am") << _("force-stop") proc.start(m_adb, selector() << _("shell") << _("am") << _("force-stop")
<< m_packageName); << m_androidRunnable.packageName);
proc.waitForFinished(); proc.waitForFinished();
// try killing it via kill -9 // try killing it via kill -9
@@ -311,7 +311,7 @@ void AndroidRunner::forceStop()
if (to == -1) if (to == -1)
break; break;
QString line = QString::fromUtf8(out.data() + from, to - from - 1); QString line = QString::fromUtf8(out.data() + from, to - from - 1);
if (line.endsWith(m_packageName) || line.endsWith(m_gdbserverPath)) { if (line.endsWith(m_androidRunnable.packageName) || line.endsWith(m_gdbserverPath)) {
int pid = extractPidFromChunk(out, from); int pid = extractPidFromChunk(out, from);
adbKill(pid); adbKill(pid);
} }
@@ -337,8 +337,14 @@ void AndroidRunner::asyncStart()
adb.waitForFinished(); adb.waitForFinished();
} }
foreach (const QStringList &entry, m_androidRunnable.beforeStartADBCommands) {
QProcess adb;
adb.start(m_adb, selector() << entry);
adb.waitForFinished();
}
QStringList args = selector(); QStringList args = selector();
args << _("shell") << _("am") << _("start") << _("-n") << m_intentName; args << _("shell") << _("am") << _("start") << _("-n") << m_androidRunnable.intentName;
if (m_useCppDebugger) { if (m_useCppDebugger) {
QProcess adb; QProcess adb;
@@ -354,7 +360,7 @@ void AndroidRunner::asyncStart()
return; return;
} }
const QString pingPongSocket(m_packageName + _(".ping_pong_socket")); const QString pingPongSocket(m_androidRunnable.packageName + _(".ping_pong_socket"));
args << _("-e") << _("debug_ping") << _("true"); args << _("-e") << _("debug_ping") << _("true");
if (m_handShakeMethod == SocketHandShake) { if (m_handShakeMethod == SocketHandShake) {
args << _("-e") << _("ping_socket") << pingPongSocket; args << _("-e") << _("ping_socket") << pingPongSocket;
@@ -411,7 +417,7 @@ void AndroidRunner::asyncStart()
} }
if (!adb.waitForFinished(10000)) { if (!adb.waitForFinished(10000)) {
adb.terminate(); adb.terminate();
emit remoteProcessFinished(tr("Unable to start \"%1\".").arg(m_packageName)); emit remoteProcessFinished(tr("Unable to start \"%1\".").arg(m_androidRunnable.packageName));
return; return;
} }
@@ -476,7 +482,7 @@ void AndroidRunner::asyncStart()
break; break;
if (i == 20) { if (i == 20) {
emit remoteProcessFinished(tr("Unable to start \"%1\".").arg(m_packageName)); emit remoteProcessFinished(tr("Unable to start \"%1\".").arg(m_androidRunnable.packageName));
return; return;
} }
qDebug() << "WAITING FOR " << tmp.fileName(); qDebug() << "WAITING FOR " << tmp.fileName();
@@ -540,11 +546,16 @@ void AndroidRunner::stop()
m_tries = 0; m_tries = 0;
if (m_processPID != -1) { if (m_processPID != -1) {
forceStop(); forceStop();
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" terminated.").arg(m_packageName)); emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" terminated.").arg(m_androidRunnable.packageName));
} }
//QObject::disconnect(&m_adbLogcatProcess, 0, this, 0); //QObject::disconnect(&m_adbLogcatProcess, 0, this, 0);
m_adbLogcatProcess.kill(); m_adbLogcatProcess.kill();
m_adbLogcatProcess.waitForFinished(); m_adbLogcatProcess.waitForFinished();
foreach (const QStringList &entry, m_androidRunnable.afterFinishADBCommands) {
QProcess adb;
adb.start(m_adb, selector() << entry);
adb.waitForFinished();
}
} }
void AndroidRunner::logcatProcess(const QByteArray &text, QByteArray &buffer, bool onlyError) void AndroidRunner::logcatProcess(const QByteArray &text, QByteArray &buffer, bool onlyError)
@@ -613,7 +624,7 @@ void AndroidRunner::adbKill(qint64 pid)
{ {
QProcess process; QProcess process;
process.start(m_adb, selector() << _("shell") process.start(m_adb, selector() << _("shell")
<< _("run-as") << m_packageName << _("run-as") << m_androidRunnable.packageName
<< _("kill") << QLatin1String("-9") << QString::number(pid)); << _("kill") << QLatin1String("-9") << QString::number(pid));
process.waitForFinished(); process.waitForFinished();
} }
@@ -621,7 +632,13 @@ void AndroidRunner::adbKill(qint64 pid)
QString AndroidRunner::displayName() const QString AndroidRunner::displayName() const
{ {
return m_packageName; return m_androidRunnable.packageName;
}
void AndroidRunner::setRunnable(const AndroidRunnable &runnable)
{
m_androidRunnable = runnable;
m_selector = AndroidDeviceInfo::adbSelector(m_androidRunnable.deviceSerialNumber);
} }
} // namespace Internal } // namespace Internal

View File

@@ -27,6 +27,7 @@
#define ANDROIDRUNNER_H #define ANDROIDRUNNER_H
#include "androidconfigurations.h" #include "androidconfigurations.h"
#include "androidrunnable.h"
#include <projectexplorer/runconfiguration.h> #include <projectexplorer/runconfiguration.h>
#include <qmldebug/qmldebugcommandlinearguments.h> #include <qmldebug/qmldebugcommandlinearguments.h>
@@ -58,6 +59,8 @@ public:
~AndroidRunner(); ~AndroidRunner();
QString displayName() const; QString displayName() const;
void setRunnable(const AndroidRunnable &runnable);
const AndroidRunnable &runnable() const { return m_androidRunnable; }
public slots: public slots:
void start(); void start();
@@ -92,12 +95,9 @@ private:
QTimer m_checkPIDTimer; QTimer m_checkPIDTimer;
bool m_wasStarted; bool m_wasStarted;
int m_tries; int m_tries;
QByteArray m_stdoutBuffer; QByteArray m_stdoutBuffer;
QByteArray m_stderrBuffer; QByteArray m_stderrBuffer;
QString m_intentName; AndroidRunnable m_androidRunnable;
QString m_packageName;
QString m_deviceSerialNumber;
qint64 m_processPID; qint64 m_processPID;
bool m_useCppDebugger; bool m_useCppDebugger;
QmlDebug::QmlDebugServicesPreset m_qmlDebugServices; QmlDebug::QmlDebugServicesPreset m_qmlDebugServices;