forked from qt-creator/qt-creator
Android: Remove multiple code paths to run adb
Refactor the code to use adb from AndroidManager, do cleanup and improve logging Change-Id: I77b682d37c9328e6aa978eaf05b3b5c131907f09 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -79,18 +79,6 @@ namespace {
|
||||
|
||||
Q_LOGGING_CATEGORY(androidManagerLog, "qtc.android.androidManager")
|
||||
|
||||
bool runCommand(const QString &executable, const QStringList &args,
|
||||
QString *output = nullptr, int timeoutS = 30)
|
||||
{
|
||||
Utils::SynchronousProcess cmdProc;
|
||||
cmdProc.setTimeoutS(timeoutS);
|
||||
qCDebug(androidManagerLog) << executable << args.join(' ');
|
||||
Utils::SynchronousProcessResponse response = cmdProc.runBlocking(executable, args);
|
||||
if (output)
|
||||
*output = response.allOutput();
|
||||
return response.result == Utils::SynchronousProcessResponse::Finished;
|
||||
}
|
||||
|
||||
QString parseAaptOutput(const QString &output, const QString ®Ex) {
|
||||
const QRegularExpression regRx(regEx,
|
||||
QRegularExpression::CaseInsensitiveOption |
|
||||
@@ -162,10 +150,8 @@ bool AndroidManager::packageInstalled(const QString &deviceSerial,
|
||||
return false;
|
||||
QStringList args = AndroidDeviceInfo::adbSelector(deviceSerial);
|
||||
args << "shell" << "pm" << "list" << "packages";
|
||||
QString output;
|
||||
runAdbCommand(args, &output);
|
||||
QStringList lines = output.split(QRegularExpression("[\\n\\r]"),
|
||||
QString::SkipEmptyParts);
|
||||
QStringList lines = runAdbCommand(args).stdOut().split(QRegularExpression("[\\n\\r]"),
|
||||
QString::SkipEmptyParts);
|
||||
for (const QString &line : lines) {
|
||||
// Don't want to confuse com.abc.xyz with com.abc.xyz.def so check with
|
||||
// endsWith
|
||||
@@ -180,24 +166,24 @@ void AndroidManager::apkInfo(const Utils::FileName &apkPath,
|
||||
QVersionNumber *version,
|
||||
QString *activityPath)
|
||||
{
|
||||
QString output;
|
||||
runAaptCommand({"dump", "badging", apkPath.toString()}, &output);
|
||||
SdkToolResult result;
|
||||
result = runAaptCommand({"dump", "badging", apkPath.toString()});
|
||||
|
||||
QString packageStr;
|
||||
if (activityPath) {
|
||||
packageStr = parseAaptOutput(output, packageNameRegEx);
|
||||
QString path = parseAaptOutput(output, activityRegEx);
|
||||
packageStr = parseAaptOutput(result.stdOut(), packageNameRegEx);
|
||||
QString path = parseAaptOutput(result.stdOut(), activityRegEx);
|
||||
if (!packageStr.isEmpty() && !path.isEmpty())
|
||||
*activityPath = packageStr + '/' + path;
|
||||
}
|
||||
|
||||
if (packageName) {
|
||||
*packageName = activityPath ? packageStr :
|
||||
parseAaptOutput(output, packageNameRegEx);
|
||||
parseAaptOutput(result.stdOut(), packageNameRegEx);
|
||||
}
|
||||
|
||||
if (version) {
|
||||
QString versionStr = parseAaptOutput(output, apkVersionRegEx);
|
||||
QString versionStr = parseAaptOutput(result.stdOut(), apkVersionRegEx);
|
||||
*version = QVersionNumber::fromString(versionStr);
|
||||
}
|
||||
}
|
||||
@@ -477,8 +463,11 @@ void AndroidManager::cleanLibsOnDevice(ProjectExplorer::Target *target)
|
||||
}
|
||||
|
||||
QStringList arguments = AndroidDeviceInfo::adbSelector(deviceSerialNumber);
|
||||
arguments << QLatin1String("shell") << QLatin1String("rm") << QLatin1String("-r") << QLatin1String("/data/local/tmp/qt");
|
||||
runAdbCommandDetached(arguments);
|
||||
arguments << "shell" << "rm" << "-r" << "/data/local/tmp/qt";
|
||||
|
||||
QString error;
|
||||
if (!runAdbCommandDetached(arguments, &error))
|
||||
Core::MessageManager::write(tr("Cleaning Qt libraries on device failed.\n%1").arg(error));
|
||||
}
|
||||
|
||||
void AndroidManager::installQASIPackage(ProjectExplorer::Target *target, const QString &packagePath)
|
||||
@@ -499,8 +488,10 @@ void AndroidManager::installQASIPackage(ProjectExplorer::Target *target, const Q
|
||||
}
|
||||
|
||||
QStringList arguments = AndroidDeviceInfo::adbSelector(deviceSerialNumber);
|
||||
arguments << QLatin1String("install") << QLatin1String("-r ") << packagePath;
|
||||
runAdbCommandDetached(arguments);
|
||||
arguments << "install" << "-r " << packagePath;
|
||||
QString error;
|
||||
if (!runAdbCommandDetached(arguments, &error, true))
|
||||
Core::MessageManager::write(tr("Android package installation failed.\n%1").arg(error));
|
||||
}
|
||||
|
||||
bool AndroidManager::checkKeystorePassword(const QString &keystorePath, const QString &keystorePasswd)
|
||||
@@ -683,27 +674,57 @@ int AndroidManager::findApiLevel(const Utils::FileName &platformPath)
|
||||
return apiLevel;
|
||||
}
|
||||
|
||||
void AndroidManager::runAdbCommandDetached(const QStringList &args)
|
||||
QProcess *AndroidManager::runAdbCommandDetached(const QStringList &args, QString *err,
|
||||
bool deleteOnFinish)
|
||||
{
|
||||
auto process = new QProcess();
|
||||
connect(process, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
|
||||
process, &QObject::deleteLater);
|
||||
std::unique_ptr<QProcess> p(new QProcess);
|
||||
const QString adb = AndroidConfigurations::currentConfig().adbToolPath().toString();
|
||||
qCDebug(androidManagerLog) << adb << args.join(' ');
|
||||
process->start(adb, args);
|
||||
if (!process->waitForStarted(500) && process->state() != QProcess::Running)
|
||||
delete process;
|
||||
qCDebug(androidManagerLog) << "Running command:" << adb << args.join(' ');
|
||||
p->start(adb, args);
|
||||
if (p->waitForStarted(500) && p->state() == QProcess::Running) {
|
||||
if (deleteOnFinish) {
|
||||
connect(p.get(), static_cast<void (QProcess::*)(int)>(&QProcess::finished),
|
||||
p.get(), &QObject::deleteLater);
|
||||
}
|
||||
return p.release();
|
||||
}
|
||||
|
||||
QString errorStr = QString::fromUtf8(p->readAllStandardError());
|
||||
qCDebug(androidManagerLog) << "Running command failed" << adb << args.join(' ') << errorStr;
|
||||
if (err)
|
||||
*err = errorStr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool AndroidManager::runAdbCommand(const QStringList &args, QString *output)
|
||||
SdkToolResult AndroidManager::runCommand(const QString &executable, const QStringList &args,
|
||||
const QByteArray &writeData, int timeoutS)
|
||||
{
|
||||
return runCommand(AndroidConfigurations::currentConfig().adbToolPath().toString(),
|
||||
args, output);
|
||||
Android::SdkToolResult cmdResult;
|
||||
Utils::SynchronousProcess cmdProc;
|
||||
cmdProc.setTimeoutS(timeoutS);
|
||||
qCDebug(androidManagerLog) << "Running command: " << executable << args.join(' ');
|
||||
Utils::SynchronousProcessResponse response = cmdProc.run(executable, args, writeData);
|
||||
cmdResult.m_stdOut = response.stdOut().trimmed();
|
||||
cmdResult.m_stdErr = response.stdErr().trimmed();
|
||||
cmdResult.m_success = response.result == Utils::SynchronousProcessResponse::Finished;
|
||||
qCDebug(androidManagerLog) << "Running command finshed:" << executable << args.join(' ')
|
||||
<< "Success:" << cmdResult.m_success
|
||||
<< "Output:" << response.allRawOutput();
|
||||
if (!cmdResult.success())
|
||||
cmdResult.m_exitMessage = response.exitMessage(executable, timeoutS);
|
||||
return cmdResult;
|
||||
}
|
||||
|
||||
bool AndroidManager::runAaptCommand(const QStringList &args, QString *output)
|
||||
SdkToolResult AndroidManager::runAdbCommand(const QStringList &args,
|
||||
const QByteArray &writeData, int timeoutS)
|
||||
{
|
||||
return runCommand(AndroidConfigurations::currentConfig().aaptToolPath().toString(),
|
||||
args, output);
|
||||
return runCommand(AndroidConfigurations::currentConfig().adbToolPath().toString(), args,
|
||||
writeData, timeoutS);
|
||||
}
|
||||
|
||||
SdkToolResult AndroidManager::runAaptCommand(const QStringList &args, int timeoutS)
|
||||
{
|
||||
return runCommand(AndroidConfigurations::currentConfig().aaptToolPath().toString(), args, {},
|
||||
timeoutS);
|
||||
}
|
||||
} // namespace Android
|
||||
|
@@ -31,6 +31,10 @@
|
||||
#include <QObject>
|
||||
#include <QVersionNumber>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QProcess;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class Kit;
|
||||
class Target;
|
||||
@@ -42,6 +46,22 @@ namespace Android {
|
||||
|
||||
class AndroidQtSupport;
|
||||
|
||||
class SdkToolResult {
|
||||
public:
|
||||
SdkToolResult() = default;
|
||||
bool success() const { return m_success; }
|
||||
const QString &stdOut() { return m_stdOut; }
|
||||
const QString &stdErr() { return m_stdErr; }
|
||||
const QString &exitMessage() { return m_exitMessage; }
|
||||
|
||||
private:
|
||||
bool m_success = false;
|
||||
QString m_stdOut;
|
||||
QString m_stdErr;
|
||||
QString m_exitMessage;
|
||||
friend class AndroidManager;
|
||||
};
|
||||
|
||||
class ANDROID_EXPORT AndroidManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -94,9 +114,15 @@ public:
|
||||
static bool updateGradleProperties(ProjectExplorer::Target *target);
|
||||
static int findApiLevel(const Utils::FileName &platformPath);
|
||||
|
||||
static void runAdbCommandDetached(const QStringList &args);
|
||||
static bool runAdbCommand(const QStringList &args, QString *output = nullptr);
|
||||
static bool runAaptCommand(const QStringList &args, QString *output = nullptr);
|
||||
static QProcess *runAdbCommandDetached(const QStringList &args, QString *err = nullptr,
|
||||
bool deleteOnFinish = false);
|
||||
static SdkToolResult runAdbCommand(const QStringList &args, const QByteArray &writeData = {},
|
||||
int timeoutS = 30);
|
||||
static SdkToolResult runAaptCommand(const QStringList &args, int timeoutS = 30);
|
||||
|
||||
private:
|
||||
static SdkToolResult runCommand(const QString &executable, const QStringList &args,
|
||||
const QByteArray &writeData = {}, int timeoutS = 30);
|
||||
};
|
||||
|
||||
} // namespace Android
|
||||
|
@@ -94,14 +94,14 @@ static bool isTimedOut(const chrono::high_resolution_clock::time_point &start,
|
||||
return timedOut;
|
||||
}
|
||||
|
||||
static qint64 extractPID(const QByteArray &output, const QString &packageName)
|
||||
static qint64 extractPID(const QString &output, const QString &packageName)
|
||||
{
|
||||
qint64 pid = -1;
|
||||
foreach (auto tuple, output.split('\n')) {
|
||||
tuple = tuple.simplified();
|
||||
if (!tuple.isEmpty()) {
|
||||
auto parts = tuple.split(':');
|
||||
QString commandName = QString::fromLocal8Bit(parts.first());
|
||||
QString commandName = parts.first();
|
||||
if (parts.length() == 2 && commandName == packageName) {
|
||||
pid = parts.last().toLongLong();
|
||||
break;
|
||||
@@ -111,9 +111,8 @@ static qint64 extractPID(const QByteArray &output, const QString &packageName)
|
||||
return pid;
|
||||
}
|
||||
|
||||
static void findProcessPID(QFutureInterface<qint64> &fi, const QString &adbPath,
|
||||
QStringList selector, const QString &packageName,
|
||||
bool preNougat)
|
||||
static void findProcessPID(QFutureInterface<qint64> &fi, QStringList selector,
|
||||
const QString &packageName, bool preNougat)
|
||||
{
|
||||
qCDebug(androidRunWorkerLog) << "Finding PID. PreNougat:" << preNougat;
|
||||
if (packageName.isEmpty())
|
||||
@@ -127,12 +126,12 @@ static void findProcessPID(QFutureInterface<qint64> &fi, const QString &adbPath,
|
||||
|
||||
do {
|
||||
QThread::msleep(200);
|
||||
const QByteArray out = Utils::SynchronousProcess().runBlocking(adbPath, selector).allRawOutput();
|
||||
SdkToolResult result = AndroidManager::runAdbCommand(selector);
|
||||
if (preNougat) {
|
||||
processPID = extractPID(out, packageName);
|
||||
processPID = extractPID(result.stdOut(), packageName);
|
||||
} else {
|
||||
if (!out.isEmpty())
|
||||
processPID = out.trimmed().toLongLong();
|
||||
if (!result.stdOut().isEmpty())
|
||||
processPID = result.stdOut().trimmed().toLongLong();
|
||||
}
|
||||
} while (processPID == -1 && !isTimedOut(start) && !fi.isCanceled());
|
||||
|
||||
@@ -188,7 +187,6 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
|
||||
m_qmlServer.setPort(server.serverPort());
|
||||
qCDebug(androidRunWorkerLog) << "QML server:" << m_qmlServer.toDisplayString();
|
||||
}
|
||||
m_adb = AndroidConfigurations::currentConfig().adbToolPath().toString();
|
||||
m_localJdbServerPort = Utils::Port(5038);
|
||||
QTC_CHECK(m_localJdbServerPort.isValid());
|
||||
|
||||
@@ -236,40 +234,16 @@ AndroidRunnerWorker::~AndroidRunnerWorker()
|
||||
m_pidFinder.cancel();
|
||||
}
|
||||
|
||||
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.
|
||||
// Run a test to find out on what side of the fence we live.
|
||||
// The command will fail with a complaint about the "--dummy"
|
||||
// option on newer SDKs, and with "No intent supplied" on older ones.
|
||||
// In case the test itself fails assume a new SDK.
|
||||
Utils::SynchronousProcess adb;
|
||||
adb.setTimeoutS(10);
|
||||
Utils::SynchronousProcessResponse response
|
||||
= adb.run(m_adb, selector() << "shell" << "am" << "start"
|
||||
<< "-e" << "dummy" << "dummy --dummy");
|
||||
if (response.result == Utils::SynchronousProcessResponse::StartFailed
|
||||
|| response.result != Utils::SynchronousProcessResponse::Finished)
|
||||
return true;
|
||||
|
||||
const QString output = response.allOutput();
|
||||
const bool oldSdk = output.contains("Error: No intent supplied");
|
||||
return !oldSdk;
|
||||
}
|
||||
|
||||
bool AndroidRunnerWorker::runAdb(const QStringList &args, int timeoutS, const QByteArray &writeData)
|
||||
bool AndroidRunnerWorker::runAdb(const QStringList &args, QString *stdOut,
|
||||
const QByteArray &writeData)
|
||||
{
|
||||
QStringList adbArgs = selector() + args;
|
||||
qCDebug(androidRunWorkerLog) << "ADB command: " << m_adb << adbArgs.join(' ');
|
||||
Utils::SynchronousProcess adb;
|
||||
adb.setTimeoutS(timeoutS);
|
||||
Utils::SynchronousProcessResponse response = adb.run(m_adb, adbArgs, writeData);
|
||||
m_lastRunAdbError = response.exitMessage(m_adb, timeoutS);
|
||||
m_lastRunAdbRawOutput = response.allRawOutput();
|
||||
bool success = response.result == Utils::SynchronousProcessResponse::Finished;
|
||||
qCDebug(androidRunWorkerLog) << "ADB command result:" << success << response.allRawOutput();
|
||||
return success;
|
||||
SdkToolResult result = AndroidManager::runAdbCommand(adbArgs, writeData);
|
||||
if (!result.success())
|
||||
emit remoteErrorOutput(result.exitMessage() + "\n" + result.stdErr());
|
||||
if (stdOut)
|
||||
*stdOut = result.stdOut();
|
||||
return result.success();
|
||||
}
|
||||
|
||||
bool AndroidRunnerWorker::uploadFile(const QString &from, const QString &to, const QString &flags)
|
||||
@@ -278,7 +252,8 @@ bool AndroidRunnerWorker::uploadFile(const QString &from, const QString &to, con
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
return false;
|
||||
runAdb({"shell", "run-as", m_packageName, "rm", to});
|
||||
auto res = runAdb({"shell", "run-as", m_packageName, "sh", "-c", QString("'cat > %1'").arg(to)}, 60, f.readAll());
|
||||
auto res = runAdb({"shell", "run-as", m_packageName, "sh", "-c", QString("'cat > %1'").arg(to)},
|
||||
nullptr, f.readAll());
|
||||
if (!res)
|
||||
return false;
|
||||
return runAdb({"shell", "run-as", m_packageName, "chmod", flags, to});
|
||||
@@ -297,17 +272,14 @@ QStringList AndroidRunnerWorker::selector() const
|
||||
|
||||
void AndroidRunnerWorker::forceStop()
|
||||
{
|
||||
runAdb({"shell", "am", "force-stop", m_packageName}, 30);
|
||||
runAdb({"shell", "am", "force-stop", m_packageName});
|
||||
|
||||
// try killing it via kill -9
|
||||
const QByteArray out = Utils::SynchronousProcess()
|
||||
.runBlocking(m_adb, selector() << QStringLiteral("shell") << pidScriptPreNougat)
|
||||
.allRawOutput();
|
||||
|
||||
QString out;
|
||||
runAdb({"shell", pidScriptPreNougat}, &out);
|
||||
qint64 pid = extractPID(out.simplified(), m_packageName);
|
||||
if (pid != -1) {
|
||||
if (pid != -1)
|
||||
adbKill(pid);
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidRunnerWorker::logcatReadStandardError()
|
||||
@@ -395,17 +367,18 @@ 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, &AndroidRunnerWorker::logcatReadStandardOutput);
|
||||
connect(logcatProcess.get(), &QProcess::readyReadStandardError,
|
||||
this, &AndroidRunnerWorker::logcatReadStandardError);
|
||||
// Its assumed that the device or avd returned by selector() is online.
|
||||
logcatProcess->start(m_adb, selector() << "logcat");
|
||||
// Start the logcat process before app starts.
|
||||
QTC_ASSERT(!m_adbLogcatProcess, /**/);
|
||||
m_adbLogcatProcess = std::move(logcatProcess);
|
||||
m_adbLogcatProcess->setObjectName("AdbLogcatProcess");
|
||||
m_adbLogcatProcess.reset(AndroidManager::runAdbCommandDetached(selector() << "logcat"));
|
||||
if (m_adbLogcatProcess) {
|
||||
m_adbLogcatProcess->setObjectName("AdbLogcatProcess");
|
||||
connect(m_adbLogcatProcess.get(), &QProcess::readyReadStandardOutput,
|
||||
this, &AndroidRunnerWorker::logcatReadStandardOutput);
|
||||
connect(m_adbLogcatProcess.get(), &QProcess::readyReadStandardError,
|
||||
this, &AndroidRunnerWorker::logcatReadStandardError);
|
||||
}
|
||||
|
||||
for (const QString &entry : m_beforeStartAdbCommands)
|
||||
runAdb(entry.split(' ', QString::SkipEmptyParts));
|
||||
|
||||
@@ -415,42 +388,27 @@ void AndroidRunnerWorker::asyncStartHelper()
|
||||
if (m_useCppDebugger) {
|
||||
args << "-D";
|
||||
// run-as <package-name> pwd fails on API 22 so route the pwd through shell.
|
||||
if (!runAdb({"shell", "run-as", m_packageName, "/system/bin/sh", "-c", "pwd"})) {
|
||||
emit remoteProcessFinished(tr("Failed to get process path. Reason: %1.").arg(m_lastRunAdbError));
|
||||
QString packageDir;
|
||||
if (!runAdb({"shell", "run-as", m_packageName, "/system/bin/sh", "-c", "pwd"},
|
||||
&packageDir)) {
|
||||
emit remoteProcessFinished(tr("Failed to find application directory."));
|
||||
return;
|
||||
}
|
||||
|
||||
QString packageDir = QString::fromUtf8(m_lastRunAdbRawOutput.trimmed());
|
||||
// Add executable flag to package dir. Gdb can't connect to running server on device on
|
||||
// e.g. on Android 8 with NDK 10e
|
||||
runAdb({"shell", "run-as", m_packageName, "chmod", "a+x", packageDir});
|
||||
runAdb({"shell", "run-as", m_packageName, "chmod", "a+x", packageDir.trimmed()});
|
||||
|
||||
if (m_gdbserverPath.isEmpty() || !uploadFile(m_gdbserverPath, "gdbserver")) {
|
||||
emit remoteProcessFinished(tr("Can not find/copy C++ debug server."));
|
||||
return;
|
||||
}
|
||||
|
||||
QString gdbServerSocket = packageDir + "/debug-socket";
|
||||
runAdb({"shell", "run-as", m_packageName, "killall", "gdbserver"});
|
||||
runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket});
|
||||
std::unique_ptr<QProcess, Deleter> gdbServerProcess(new QProcess, deleter);
|
||||
gdbServerProcess->start(m_adb, selector() << "shell" << "run-as"
|
||||
<< m_packageName << "./gdbserver"
|
||||
<< "--multi" << "+" + gdbServerSocket);
|
||||
if (!gdbServerProcess->waitForStarted()) {
|
||||
emit remoteProcessFinished(tr("Failed to start C++ debugger."));
|
||||
QString debuggerServerErr;
|
||||
if (!startDebuggerServer(packageDir, &debuggerServerErr)) {
|
||||
emit remoteProcessFinished(debuggerServerErr);
|
||||
return;
|
||||
}
|
||||
m_gdbServerProcess = std::move(gdbServerProcess);
|
||||
m_gdbServerProcess->setObjectName("GdbServerProcess");
|
||||
QStringList removeForward{"forward", "--remove", "tcp:" + m_localGdbServerPort.toString()};
|
||||
runAdb(removeForward);
|
||||
if (!runAdb({"forward", "tcp:" + m_localGdbServerPort.toString(),
|
||||
"localfilesystem:" + gdbServerSocket})) {
|
||||
emit remoteProcessFinished(tr("Failed to forward C++ debugging ports. Reason: %1.").arg(m_lastRunAdbError));
|
||||
return;
|
||||
}
|
||||
m_afterFinishAdbCommands.push_back(removeForward.join(' '));
|
||||
}
|
||||
|
||||
if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices) {
|
||||
@@ -459,8 +417,7 @@ void AndroidRunnerWorker::asyncStartHelper()
|
||||
QStringList removeForward{{"forward", "--remove", port}};
|
||||
runAdb(removeForward);
|
||||
if (!runAdb({"forward", port, port})) {
|
||||
emit remoteProcessFinished(tr("Failed to forward QML debugging ports. Reason: %1.")
|
||||
.arg(m_lastRunAdbError) + "\n" + m_lastRunAdbRawOutput);
|
||||
emit remoteProcessFinished(tr("Failed to forward QML debugging ports."));
|
||||
return;
|
||||
}
|
||||
m_afterFinishAdbCommands.push_back(removeForward.join(' '));
|
||||
@@ -487,17 +444,49 @@ void AndroidRunnerWorker::asyncStartHelper()
|
||||
}
|
||||
|
||||
if (!runAdb(args)) {
|
||||
emit remoteProcessFinished(tr("Failed to start the activity. Reason: %1.")
|
||||
.arg(m_lastRunAdbError));
|
||||
emit remoteProcessFinished(tr("Failed to start the activity"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool AndroidRunnerWorker::startDebuggerServer(QString packageDir, QString *errorStr)
|
||||
{
|
||||
QString gdbServerSocket = packageDir + "/debug-socket";
|
||||
runAdb({"shell", "run-as", m_packageName, "killall", "gdbserver"});
|
||||
runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket});
|
||||
|
||||
QString gdbProcessErr;
|
||||
QStringList gdbServerArgs = selector();
|
||||
gdbServerArgs << "shell" << "run-as" << m_packageName << "./gdbserver" << "--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");
|
||||
|
||||
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;
|
||||
}
|
||||
m_afterFinishAdbCommands.push_back(removeForward.join(' '));
|
||||
return true;
|
||||
}
|
||||
|
||||
void AndroidRunnerWorker::asyncStart()
|
||||
{
|
||||
asyncStartHelper();
|
||||
|
||||
m_pidFinder = Utils::onResultReady(Utils::runAsync(findProcessPID, m_adb, selector(),
|
||||
m_pidFinder = Utils::onResultReady(Utils::runAsync(findProcessPID, selector(),
|
||||
m_packageName, m_isPreNougat),
|
||||
bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1));
|
||||
}
|
||||
@@ -520,7 +509,7 @@ void AndroidRunnerWorker::handleJdbWaiting()
|
||||
runAdb(removeForward);
|
||||
if (!runAdb({"forward", "tcp:" + m_localJdbServerPort.toString(),
|
||||
"jdwp:" + QString::number(m_processPID)})) {
|
||||
emit remoteProcessFinished(tr("Failed to forward jdb debugging ports. Reason: %1.").arg(m_lastRunAdbError));
|
||||
emit remoteProcessFinished(tr("Failed to forward jdb debugging ports."));
|
||||
return;
|
||||
}
|
||||
m_afterFinishAdbCommands.push_back(removeForward.join(' '));
|
||||
@@ -579,8 +568,7 @@ void AndroidRunnerWorker::handleJdbSettled()
|
||||
}
|
||||
}
|
||||
}
|
||||
emit remoteProcessFinished(tr("Cannot attach jdb to the running application. Reason: %1.")
|
||||
.arg(m_lastRunAdbError));
|
||||
emit remoteProcessFinished(tr("Cannot attach jdb to the running application"));
|
||||
}
|
||||
|
||||
void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
|
||||
@@ -608,13 +596,13 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
|
||||
emit remoteProcessStarted(m_localGdbServerPort, m_qmlServer, m_processPID);
|
||||
logcatReadStandardOutput();
|
||||
QTC_ASSERT(!m_psIsAlive, /**/);
|
||||
m_psIsAlive.reset(new QProcess);
|
||||
QStringList isAliveArgs = selector() << "shell" << pidPollingScript.arg(m_processPID);
|
||||
m_psIsAlive.reset(AndroidManager::runAdbCommandDetached(isAliveArgs));
|
||||
QTC_ASSERT(m_psIsAlive, return);
|
||||
m_psIsAlive->setObjectName("IsAliveProcess");
|
||||
m_psIsAlive->setProcessChannelMode(QProcess::MergedChannels);
|
||||
connect(m_psIsAlive.get(), static_cast<void(QProcess::*)(int)>(&QProcess::finished),
|
||||
this, bind(&AndroidRunnerWorker::onProcessIdChanged, this, -1));
|
||||
m_psIsAlive->start(m_adb, selector() << QStringLiteral("shell")
|
||||
<< pidPollingScript.arg(m_processPID));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -46,9 +46,9 @@ class AndroidRunnerWorker : public QObject
|
||||
public:
|
||||
AndroidRunnerWorker(ProjectExplorer::RunWorker *runner, const QString &packageName);
|
||||
~AndroidRunnerWorker() override;
|
||||
bool adbShellAmNeedsQuotes();
|
||||
bool runAdb(const QStringList &args, int timeoutS = 10, const QByteArray &writeData = {});
|
||||
|
||||
bool uploadFile(const QString &from, const QString &to, const QString &flags = QString("+x"));
|
||||
bool runAdb(const QStringList &args, QString *stdOut = nullptr, const QByteArray &writeData = {});
|
||||
void adbKill(qint64 pid);
|
||||
QStringList selector() const;
|
||||
void forceStop();
|
||||
@@ -73,6 +73,7 @@ signals:
|
||||
|
||||
protected:
|
||||
void asyncStartHelper();
|
||||
bool startDebuggerServer(QString packageDir, QString *errorStr = nullptr);
|
||||
|
||||
enum class JDBState {
|
||||
Idle,
|
||||
@@ -88,7 +89,6 @@ protected:
|
||||
QString m_intentName;
|
||||
QStringList m_beforeStartAdbCommands;
|
||||
QStringList m_afterFinishAdbCommands;
|
||||
QString m_adb;
|
||||
QStringList m_amStartExtraArgs;
|
||||
qint64 m_processPID = -1;
|
||||
std::unique_ptr<QProcess, Deleter> m_adbLogcatProcess;
|
||||
@@ -101,8 +101,6 @@ protected:
|
||||
QmlDebug::QmlDebugServicesPreset m_qmlDebugServices;
|
||||
Utils::Port m_localGdbServerPort; // Local end of forwarded debug socket.
|
||||
QUrl m_qmlServer;
|
||||
QByteArray m_lastRunAdbRawOutput;
|
||||
QString m_lastRunAdbError;
|
||||
JDBState m_jdbState = JDBState::Idle;
|
||||
Utils::Port m_localJdbServerPort;
|
||||
std::unique_ptr<QProcess, Deleter> m_gdbServerProcess;
|
||||
|
Reference in New Issue
Block a user