AndroidTestRunner: simplify crash logcat dump
Avoid using two processes where one is the input of the other and having to do any dance to safely terminate each one in case the other fails. Do the following instead: * Get the crash logs output first, if it's not possible return. * Get the abi for ndk-stack command, if getting the value from the device fails, we still get it from the build dir if the emulator doesn't repond for some reason. * Fall host architecture if failed to get ABI * Call ndk-stack with the already obtainted logs * Override the output only if ndk-stack gives back some output * Print the output This would avoid errors/warnings like this: QProcess: Destroyed while process ("/opt/android/sdk/platform-tools/ adb") is still running. QProcess: Destroyed while process ("/opt/android/android-ndk-r26b/ndk- stack") is still running. QProcess: Destroyed while process ("/opt/android/sdk/platform-tools/ adb") is still running. Change-Id: I2f508998c0376d901947b169632b22a1bbba74b9 Reviewed-by: Ville Voutilainen <ville.voutilainen@qt.io> (cherry picked from commit e70dae69a544c7061ef03885b1defc3989552268) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
7bbe59b541
commit
e0df563495
@ -13,6 +13,7 @@
|
|||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
#include <QtCore/QXmlStreamReader>
|
#include <QtCore/QXmlStreamReader>
|
||||||
#include <QtCore/QFileInfo>
|
#include <QtCore/QFileInfo>
|
||||||
|
#include <QtCore/QSysInfo>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
@ -598,91 +599,80 @@ void printLogcat(const QString &formattedTime)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "****** Begin logcat output ******";
|
qDebug() << "********** logcat dump **********";
|
||||||
qDebug().noquote() << logcat;
|
qDebug().noquote() << logcat;
|
||||||
qDebug() << "****** End logcat output ******";
|
qDebug() << "********** End logcat dump **********";
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString getDeviceABI()
|
static QString getAbiLibsPath()
|
||||||
{
|
{
|
||||||
|
QString libsPath = "%1/libs/"_L1.arg(g_options.buildPath);
|
||||||
const QStringList abiArgs = { "shell"_L1, "getprop"_L1, "ro.product.cpu.abi"_L1 };
|
const QStringList abiArgs = { "shell"_L1, "getprop"_L1, "ro.product.cpu.abi"_L1 };
|
||||||
QByteArray abi;
|
QByteArray abi;
|
||||||
if (!execAdbCommand(abiArgs, &abi, false)) {
|
if (!execAdbCommand(abiArgs, &abi, false)) {
|
||||||
qWarning() << "Warning: failed to get the device abi, fallback to first libs dir";
|
QStringList subDirs = QDir(libsPath).entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
return {};
|
if (!subDirs.isEmpty())
|
||||||
|
abi = subDirs.first().toUtf8();
|
||||||
}
|
}
|
||||||
|
|
||||||
return QString::fromUtf8(abi.simplified());
|
abi = abi.trimmed();
|
||||||
|
if (abi.isEmpty())
|
||||||
|
qWarning() << "Failed to get the libs abi, falling to host architecture";
|
||||||
|
|
||||||
|
QString hostArch = QSysInfo::currentCpuArchitecture();
|
||||||
|
if (hostArch == "x86_64"_L1)
|
||||||
|
abi = "arm64-x86_64";
|
||||||
|
else if (hostArch == "arm64"_L1)
|
||||||
|
abi = "arm64-v8a";
|
||||||
|
else if (hostArch == "i386"_L1)
|
||||||
|
abi = "x86";
|
||||||
|
else
|
||||||
|
abi = "armeabi-v7a";
|
||||||
|
|
||||||
|
return libsPath + QString::fromUtf8(abi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printLogcatCrashBuffer(const QString &formattedTime)
|
void printLogcatCrashBuffer(const QString &formattedTime)
|
||||||
{
|
{
|
||||||
bool useNdkStack = false;
|
QStringList adbCrashArgs = {"logcat"_L1, "-d"_L1, "-b"_L1, "crash"_L1, "-t"_L1, formattedTime};
|
||||||
auto libsPath = "%1/libs/"_L1.arg(g_options.buildPath);
|
QByteArray crashOutput;
|
||||||
|
|
||||||
|
if (!execAdbCommand(adbCrashArgs, &crashOutput, false)) {
|
||||||
|
qCritical() << "Error: failed to run adb logcat crash command";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No crash report, do nothing
|
||||||
|
if (crashOutput.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
if (!g_options.ndkStackPath.isEmpty()) {
|
if (!g_options.ndkStackPath.isEmpty()) {
|
||||||
QString abi = getDeviceABI();
|
QProcess ndkStackProc;
|
||||||
if (abi.isEmpty()) {
|
ndkStackProc.start(g_options.ndkStackPath, { "-sym"_L1, getAbiLibsPath() });
|
||||||
QStringList subDirs = QDir(libsPath).entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
|
||||||
if (!subDirs.isEmpty())
|
|
||||||
abi = subDirs.first();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!abi.isEmpty()) {
|
if (ndkStackProc.waitForStarted()) {
|
||||||
libsPath += abi;
|
ndkStackProc.write(crashOutput);
|
||||||
useNdkStack = true;
|
ndkStackProc.closeWriteChannel();
|
||||||
|
|
||||||
|
if (ndkStackProc.waitForReadyRead())
|
||||||
|
crashOutput = ndkStackProc.readAllStandardOutput();
|
||||||
|
|
||||||
|
ndkStackProc.terminate();
|
||||||
|
if (!ndkStackProc.waitForFinished())
|
||||||
|
qCritical() << "Error: ndk-stack command timed out.";
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Warning: failed to get the libs abi, ndk-stack cannot be used.";
|
qCritical() << "Error: failed to run ndk-stack command.";
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Warning: ndk-stack path not provided and couldn't be deduced "
|
qWarning() << "Warning: ndk-stack path not provided and couldn't be deduced "
|
||||||
"using the ANDROID_NDK_ROOT environment variable.";
|
"using the ANDROID_NDK_ROOT environment variable.";
|
||||||
}
|
}
|
||||||
|
|
||||||
QProcess adbCrashProcess;
|
if (!crashOutput.startsWith("********** Crash dump"))
|
||||||
QProcess ndkStackProcess;
|
qDebug() << "********** Crash dump: **********";
|
||||||
|
qDebug().noquote() << crashOutput;
|
||||||
if (useNdkStack) {
|
qDebug() << "********** End crash dump **********";
|
||||||
adbCrashProcess.setStandardOutputProcess(&ndkStackProcess);
|
|
||||||
ndkStackProcess.start(g_options.ndkStackPath, { "-sym"_L1, libsPath });
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList adbCrashArgs = {"logcat"_L1, "-d"_L1, "-b"_L1, "crash"_L1, "-t"_L1, formattedTime};
|
|
||||||
if (!g_options.serial.isEmpty())
|
|
||||||
adbCrashArgs = QStringList{"-s"_L1 + g_options.serial} + adbCrashArgs;
|
|
||||||
|
|
||||||
adbCrashProcess.start(g_options.adbCommand, adbCrashArgs);
|
|
||||||
|
|
||||||
if (!adbCrashProcess.waitForStarted()) {
|
|
||||||
qCritical() << "Error: failed to run adb logcat crash command.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!adbCrashProcess.waitForFinished()) {
|
|
||||||
qCritical() << "Error: adb command timed out.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useNdkStack) {
|
|
||||||
if (!ndkStackProcess.waitForStarted()) {
|
|
||||||
qCritical() << "Error: failed to run ndk-stack command.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ndkStackProcess.waitForFinished()) {
|
|
||||||
qCritical() << "Error: ndk-stack command timed out.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const QByteArray crash = useNdkStack ? ndkStackProcess.readAllStandardOutput()
|
|
||||||
: adbCrashProcess.readAllStandardOutput();
|
|
||||||
if (crash.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
qDebug() << "****** Begin logcat crash buffer output ******";
|
|
||||||
qDebug().noquote() << crash;
|
|
||||||
qDebug() << "****** End logcat crash buffer output ******";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString getCurrentTimeString()
|
static QString getCurrentTimeString()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user