Merge remote-tracking branch 'origin/10.0'

Conflicts:
	src/plugins/android/androidrunnerworker.cpp
	src/plugins/qtsupport/exampleslistmodel.cpp

Change-Id: I1628528dbc0ffe874b49bbe022da5933b1348057
This commit is contained in:
Eike Ziller
2023-04-18 12:53:45 +02:00
15 changed files with 247 additions and 120 deletions

View File

@@ -51,6 +51,7 @@ namespace Android {
namespace Internal {
static const QString pidPollingScript = QStringLiteral("while [ -d /proc/%1 ]; do sleep 1; done");
static const QRegularExpression userIdPattern("u(\\d+)_a");
static int APP_START_TIMEOUT = 45000;
static bool isTimedOut(const chrono::high_resolution_clock::time_point &start,
@@ -77,8 +78,10 @@ static qint64 extractPID(const QString &output, const QString &packageName)
return pid;
}
static void findProcessPID(QPromise<qint64> &promise, QStringList selector,
const QString &packageName, bool preNougat)
static void findProcessPIDAndUser(QPromise<PidUserPair> &promise,
QStringList selector,
const QString &packageName,
bool preNougat)
{
if (packageName.isEmpty())
return;
@@ -108,8 +111,32 @@ static void findProcessPID(QPromise<qint64> &promise, QStringList selector,
} while ((processPID == -1 || processPID == 0) && !isTimedOut(start) && !promise.isCanceled());
qCDebug(androidRunWorkerLog) << "PID found:" << processPID << ", PreNougat:" << preNougat;
qint64 processUser = 0;
if (processPID > 0 && !promise.isCanceled()) {
args = {selector};
args.append({"shell", "ps", "-o", "user", "-p"});
args.append(QString::number(processPID));
QtcProcess proc;
proc.setCommand({adbPath, args});
proc.runBlocking();
const QString out = proc.allOutput();
if (!out.isEmpty()) {
QRegularExpressionMatch match;
qsizetype matchPos = out.indexOf(userIdPattern, 0, &match);
if (matchPos >= 0 && match.capturedLength(1) > 0) {
bool ok = false;
processUser = match.captured(1).toInt(&ok);
if (!ok)
processUser = 0;
}
}
}
qCDebug(androidRunWorkerLog) << "USER found:" << processUser;
if (!promise.isCanceled())
promise.addResult(processPID);
promise.addResult(PidUserPair(processPID, processUser));
}
static void deleter(QProcess *p)
@@ -325,13 +352,16 @@ bool AndroidRunnerWorker::uploadDebugServer(const QString &debugServerFileName)
return false;
}
QStringList adbArgs = {"shell", "run-as", m_packageName};
if (m_processUser > 0)
adbArgs << "--user" << QString::number(m_processUser);
// Copy gdbserver from temp location to app directory
if (!runAdb({"shell", "run-as", m_packageName, "cp" , tempDebugServerPath, debugServerFileName})) {
if (!runAdb(adbArgs + QStringList({"cp" , tempDebugServerPath, debugServerFileName}))) {
qCDebug(androidRunWorkerLog) << "Debug server copy from temp directory failed";
return false;
}
const bool ok = runAdb({"shell", "run-as", m_packageName, "chmod", "777", debugServerFileName});
const bool ok = runAdb(adbArgs + QStringList({"chmod", "777", debugServerFileName}));
QTC_ASSERT(ok, qCDebug(androidRunWorkerLog) << "Debug server chmod 777 failed.");
return true;
}
@@ -346,7 +376,11 @@ bool AndroidRunnerWorker::deviceFileExists(const QString &filePath)
bool AndroidRunnerWorker::packageFileExists(const QString &filePath)
{
QString output;
const bool success = runAdb({"shell", "run-as", m_packageName, "ls", filePath, "2>/dev/null"}, &output);
QStringList adbArgs = {"shell", "run-as", m_packageName};
if (m_processUser > 0)
adbArgs << "--user" << QString::number(m_processUser);
const bool success = runAdb(adbArgs + QStringList({"ls", filePath, "2>/dev/null"}),
&output);
return success && !output.trimmed().isEmpty();
}
@@ -513,62 +547,8 @@ void AndroidRunnerWorker::asyncStartHelper()
QStringList args({"shell", "am", "start"});
args << "-n" << m_intentName;
if (m_useCppDebugger) {
if (m_useCppDebugger)
args << "-D";
// run-as <package-name> pwd fails on API 22 so route the pwd through shell.
QString packageDir;
if (!runAdb({"shell", "run-as", m_packageName, "/system/bin/sh", "-c", "pwd"},
&packageDir)) {
emit remoteProcessFinished(Tr::tr("Failed to find application directory."));
return;
}
// 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.trimmed()});
if (!m_debugServerPath.exists()) {
QString msg = Tr::tr("Cannot find C++ debug server in NDK installation.");
if (m_useLldb)
msg += "\n" + Tr::tr("The lldb-server binary has not been found.");
emit remoteProcessFinished(msg);
return;
}
QString debugServerFile;
if (m_useLldb) {
debugServerFile = "./lldb-server";
runAdb({"shell", "run-as", m_packageName, "killall", "lldb-server"});
if (!uploadDebugServer(debugServerFile)) {
emit remoteProcessFinished(Tr::tr("Cannot copy C++ debug server."));
return;
}
} else {
if (packageFileExists("./lib/gdbserver")) {
debugServerFile = "./lib/gdbserver";
qCDebug(androidRunWorkerLog) << "Found GDB server " + debugServerFile;
runAdb({"shell", "run-as", m_packageName, "killall", "gdbserver"});
} else if (packageFileExists("./lib/libgdbserver.so")) {
debugServerFile = "./lib/libgdbserver.so";
qCDebug(androidRunWorkerLog) << "Found GDB server " + debugServerFile;
runAdb({"shell", "run-as", m_packageName, "killall", "libgdbserver.so"});
} else {
// Armv8. symlink lib is not available.
debugServerFile = "./gdbserver";
// Kill the previous instances of gdbserver. Do this before copying the gdbserver.
runAdb({"shell", "run-as", m_packageName, "killall", "gdbserver"});
if (!uploadDebugServer("./gdbserver")) {
emit remoteProcessFinished(Tr::tr("Cannot copy C++ debug server."));
return;
}
}
}
QString debuggerServerErr;
if (!startDebuggerServer(packageDir, debugServerFile, &debuggerServerErr)) {
emit remoteProcessFinished(debuggerServerErr);
return;
}
}
if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices) {
// currently forward to same port on device and host
@@ -624,17 +604,79 @@ void AndroidRunnerWorker::asyncStartHelper()
}
}
void AndroidRunnerWorker::startNativeDebugging()
{
// run-as <package-name> pwd fails on API 22 so route the pwd through shell.
QString packageDir;
QStringList adbArgs = {"shell", "run-as", m_packageName};
if (m_processUser > 0)
adbArgs << "--user" << QString::number(m_processUser);
if (!runAdb(adbArgs + QStringList({"/system/bin/sh", "-c", "pwd"}),
&packageDir)) {
emit remoteProcessFinished(Tr::tr("Failed to find application directory."));
return;
}
// 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(adbArgs + QStringList({"chmod", "a+x", packageDir.trimmed()}));
if (!m_debugServerPath.exists()) {
QString msg = Tr::tr("Cannot find C++ debug server in NDK installation.");
if (m_useLldb)
msg += "\n" + Tr::tr("The lldb-server binary has not been found.");
emit remoteProcessFinished(msg);
return;
}
QString debugServerFile;
if (m_useLldb) {
debugServerFile = "./lldb-server";
runAdb(adbArgs + QStringList({"killall", "lldb-server"}));
if (!uploadDebugServer(debugServerFile)) {
emit remoteProcessFinished(Tr::tr("Cannot copy C++ debug server."));
return;
}
} else {
if (packageFileExists("./lib/gdbserver")) {
debugServerFile = "./lib/gdbserver";
qCDebug(androidRunWorkerLog) << "Found GDB server " + debugServerFile;
runAdb(adbArgs + QStringList({"killall", "gdbserver"}));
} else if (packageFileExists("./lib/libgdbserver.so")) {
debugServerFile = "./lib/libgdbserver.so";
qCDebug(androidRunWorkerLog) << "Found GDB server " + debugServerFile;
runAdb(adbArgs + QStringList({"killall", "libgdbserver.so"}));
} else {
// Armv8. symlink lib is not available.
debugServerFile = "./gdbserver";
// Kill the previous instances of gdbserver. Do this before copying the gdbserver.
runAdb(adbArgs + QStringList({"killall", "gdbserver"}));
if (!uploadDebugServer("./gdbserver")) {
emit remoteProcessFinished(Tr::tr("Cannot copy C++ debug server."));
return;
}
}
}
QString debuggerServerErr;
if (!startDebuggerServer(packageDir, debugServerFile, &debuggerServerErr)) {
emit remoteProcessFinished(debuggerServerErr);
return;
}
}
bool AndroidRunnerWorker::startDebuggerServer(const QString &packageDir,
const QString &debugServerFile,
QString *errorStr)
{
QStringList adbArgs = {"shell", "run-as", m_packageName};
if (m_processUser > 0)
adbArgs << "--user" << QString::number(m_processUser);
if (m_useLldb) {
QString lldbServerErr;
QStringList lldbServerArgs = selector();
lldbServerArgs << "shell" << "run-as" << m_packageName << debugServerFile
<< "platform"
// << "--server" // Can lead to zombie servers
<< "--listen" << QString("*:%1").arg(m_localDebugServerPort.toString());
lldbServerArgs += adbArgs;
lldbServerArgs << debugServerFile
<< "platform"
// << "--server" // Can lead to zombie servers
<< "--listen" << QString("*:%1").arg(m_localDebugServerPort.toString());
m_debugServerProcess.reset(AndroidManager::runAdbCommandDetached(lldbServerArgs, &lldbServerErr));
if (!m_debugServerProcess) {
@@ -648,12 +690,13 @@ bool AndroidRunnerWorker::startDebuggerServer(const QString &packageDir,
} else {
QString gdbServerSocket = packageDir + "/debug-socket";
runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket});
runAdb(adbArgs + QStringList({"rm", gdbServerSocket}));
QString gdbProcessErr;
QStringList gdbServerErr = selector();
gdbServerErr << "shell" << "run-as" << m_packageName << debugServerFile
<< "--multi" << "+" + gdbServerSocket;
gdbServerErr += adbArgs;
gdbServerErr << debugServerFile
<< "--multi" << "+" + gdbServerSocket;
m_debugServerProcess.reset(AndroidManager::runAdbCommandDetached(gdbServerErr, &gdbProcessErr));
if (!m_debugServerProcess) {
@@ -683,9 +726,12 @@ void AndroidRunnerWorker::asyncStart()
{
asyncStartHelper();
m_pidFinder = Utils::onResultReady(
Utils::asyncRun(findProcessPID, selector(),m_packageName, m_isPreNougat), this,
bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1));
m_pidFinder = Utils::onResultReady(Utils::asyncRun(findProcessPIDAndUser,
selector(),
m_packageName,
m_isPreNougat),
this,
bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1));
}
void AndroidRunnerWorker::asyncStop()
@@ -793,13 +839,16 @@ void AndroidRunnerWorker::removeForwardPort(const QString &port)
}
}
void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
void AndroidRunnerWorker::onProcessIdChanged(PidUserPair pidUser)
{
qint64 pid = pidUser.first;
qint64 user = pidUser.second;
// Don't write to m_psProc from a different thread
QTC_ASSERT(QThread::currentThread() == thread(), return);
qCDebug(androidRunWorkerLog) << "Process ID changed from:" << m_processPID
<< "to:" << pid;
m_processPID = pid;
m_processUser = user;
if (pid == -1) {
emit remoteProcessFinished(QLatin1String("\n\n") + Tr::tr("\"%1\" died.")
.arg(m_packageName));
@@ -813,6 +862,8 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
for (const QString &entry: std::as_const(m_afterFinishAdbCommands))
runAdb(entry.split(' ', Qt::SkipEmptyParts));
} else {
if (m_useCppDebugger)
startNativeDebugging();
// In debugging cases this will be funneled to the engine to actually start
// and attach gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
emit remoteProcessStarted(m_localDebugServerPort, m_qmlServer, m_processPID);
@@ -824,7 +875,7 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
m_psIsAlive->setObjectName("IsAliveProcess");
m_psIsAlive->setProcessChannelMode(QProcess::MergedChannels);
connect(m_psIsAlive.get(), &QProcess::finished,
this, bind(&AndroidRunnerWorker::onProcessIdChanged, this, -1));
this, bind(&AndroidRunnerWorker::onProcessIdChanged, this, PidUserPair(-1, -1)));
}
}