From 59de3fcb6416dc0387e85a1852d1226ae507b7fe Mon Sep 17 00:00:00 2001 From: Vikas Pachdha Date: Thu, 20 Dec 2018 18:40:34 +0100 Subject: Android: Fix gdbserver upload for Windows when using Armv8 arch The gdbserver is not uploaded to device for armv7 as lib symlink is available and we can use the gdbserver packaged with the apk Task-number: QTCREATORBUG-21317 Change-Id: I263eb48bbf3cf05b969db934a928185dba10373b Reviewed-by: Eike Ziller Reviewed-by: hjk --- src/plugins/android/androidrunnerworker.cpp | 90 +++++++++++++++++++++-------- src/plugins/android/androidrunnerworker.h | 6 +- 2 files changed, 71 insertions(+), 25 deletions(-) diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index a4b6772f61..37191848fd 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -53,6 +53,7 @@ namespace { Q_LOGGING_CATEGORY(androidRunWorkerLog, "qtc.android.run.androidrunnerworker", QtWarningMsg) +static const int GdbTempFileMaxCounter = 20; } using namespace std; @@ -274,17 +275,58 @@ bool AndroidRunnerWorker::runAdb(const QStringList &args, int timeoutS, const QB return success; } -bool AndroidRunnerWorker::uploadFile(const QString &from, const QString &to, const QString &flags) +bool AndroidRunnerWorker::uploadGdbServer() { - QFile f(from); - if (!f.open(QIODevice::ReadOnly)) + // Push the gdbserver 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 + tempGdbServerPath(new QString("/data/local/tmp/%1"), cleanUp); + + // Get a unique temp file name for gdbserver copy + int count = 0; + while (deviceFileExists(tempGdbServerPath->arg(++count))) { + if (count > GdbTempFileMaxCounter) { + qCDebug(androidRunWorkerLog) << "Can not get temporary file name"; + foundUnique = false; + return false; + } + } + *tempGdbServerPath = tempGdbServerPath->arg(count); + + // Copy gdbserver to temp location + if (!runAdb({"push", m_gdbserverPath , *tempGdbServerPath})) { + qCDebug(androidRunWorkerLog) << "Gdbserver upload to temp directory failed"; return false; - runAdb({"shell", "run-as", m_packageName, "rm", to}); - const QByteArray data = f.readAll(); - const bool res = runAdb({"shell", "run-as", m_packageName, QString("sh -c 'base64 -d > %1'").arg(to)}, 60, data.toBase64()); - if (!res || m_lastRunAdbRawOutput.contains("base64: not found")) + } + + // 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"; return false; - return runAdb({"shell", "run-as", m_packageName, "chmod", flags, to}); + } + QTC_ASSERT(runAdb({"shell", "run-as", m_packageName, "chmod", "+x", "./gdbserver"}), + qCDebug(androidRunWorkerLog) << "Gdbserver chmod +x failed."); + return true; +} + +bool AndroidRunnerWorker::deviceFileExists(const QString &filePath) +{ + return runAdb({"shell", "ls", filePath, "2>/dev/null"}) + && !m_lastRunAdbRawOutput.trimmed().isEmpty(); +} + +bool AndroidRunnerWorker::packageFileExists(const QString &filePath) +{ + return runAdb({"shell", "run-as", m_packageName, "ls", filePath, "2>/dev/null"}) + && !m_lastRunAdbRawOutput.trimmed().isEmpty(); } void AndroidRunnerWorker::adbKill(qint64 pid) @@ -428,29 +470,31 @@ void AndroidRunnerWorker::asyncStartHelper() // e.g. on Android 8 with NDK 10e runAdb({"shell", "run-as", m_packageName, "chmod", "a+x", packageDir}); - QString gdbServerExecutable; + QString gdbServerExecutable = "gdbserver"; QString gdbServerPrefix = "./lib/"; - if (m_gdbserverPath.isEmpty() || !uploadFile(m_gdbserverPath, "gdbserver")) { - // upload failed - check for old devices - if (runAdb({"shell", "run-as", m_packageName, "ls", "lib/"})) { - for (const auto &line: m_lastRunAdbRawOutput.split('\n')) { - if (line.indexOf("gdbserver") != -1/* || line.indexOf("lldb-server") != -1*/) { - gdbServerExecutable = QString::fromUtf8(line.trimmed()); - break; - } - } - } - if (gdbServerExecutable.isEmpty()) { + 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/copy C++ debug server.")); return; } } else { - gdbServerPrefix = "./"; - gdbServerExecutable = "gdbserver"; + qCDebug(androidRunWorkerLog) << "Found GDB server under ./lib"; + runAdb({"shell", "run-as", m_packageName, "killall", gdbServerExecutable}); } QString gdbServerSocket = packageDir + "/debug-socket"; - runAdb({"shell", "run-as", m_packageName, "killall", gdbServerExecutable}); runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket}); std::unique_ptr gdbServerProcess(new QProcess, deleter); diff --git a/src/plugins/android/androidrunnerworker.h b/src/plugins/android/androidrunnerworker.h index 18639683ae..39b25a1a29 100644 --- a/src/plugins/android/androidrunnerworker.h +++ b/src/plugins/android/androidrunnerworker.h @@ -48,7 +48,6 @@ public: ~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")); void adbKill(qint64 pid); QStringList selector() const; void forceStop(); @@ -71,8 +70,11 @@ signals: void remoteOutput(const QString &output); void remoteErrorOutput(const QString &output); -protected: +private: void asyncStartHelper(); + bool deviceFileExists(const QString &filePath); + bool packageFileExists(const QString& filePath); + bool uploadGdbServer(); enum class JDBState { Idle, -- cgit v1.2.1