From e0df563495b32efca0dc96062a6d9cae120fb297 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Sat, 26 Oct 2024 15:11:39 +0300 Subject: [PATCH] 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 (cherry picked from commit e70dae69a544c7061ef03885b1defc3989552268) Reviewed-by: Qt Cherry-pick Bot --- src/tools/androidtestrunner/main.cpp | 114 ++++++++++++--------------- 1 file changed, 52 insertions(+), 62 deletions(-) diff --git a/src/tools/androidtestrunner/main.cpp b/src/tools/androidtestrunner/main.cpp index bb0a385cfea..ad5f3ba0b09 100644 --- a/src/tools/androidtestrunner/main.cpp +++ b/src/tools/androidtestrunner/main.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -598,91 +599,80 @@ void printLogcat(const QString &formattedTime) return; } - qDebug() << "****** Begin logcat output ******"; + qDebug() << "********** logcat dump **********"; 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 }; QByteArray abi; if (!execAdbCommand(abiArgs, &abi, false)) { - qWarning() << "Warning: failed to get the device abi, fallback to first libs dir"; - return {}; + QStringList subDirs = QDir(libsPath).entryList(QDir::Dirs | QDir::NoDotAndDotDot); + 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) { - bool useNdkStack = false; - auto libsPath = "%1/libs/"_L1.arg(g_options.buildPath); + QStringList adbCrashArgs = {"logcat"_L1, "-d"_L1, "-b"_L1, "crash"_L1, "-t"_L1, formattedTime}; + 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()) { - QString abi = getDeviceABI(); - if (abi.isEmpty()) { - QStringList subDirs = QDir(libsPath).entryList(QDir::Dirs | QDir::NoDotAndDotDot); - if (!subDirs.isEmpty()) - abi = subDirs.first(); - } + QProcess ndkStackProc; + ndkStackProc.start(g_options.ndkStackPath, { "-sym"_L1, getAbiLibsPath() }); - if (!abi.isEmpty()) { - libsPath += abi; - useNdkStack = true; + if (ndkStackProc.waitForStarted()) { + ndkStackProc.write(crashOutput); + ndkStackProc.closeWriteChannel(); + + if (ndkStackProc.waitForReadyRead()) + crashOutput = ndkStackProc.readAllStandardOutput(); + + ndkStackProc.terminate(); + if (!ndkStackProc.waitForFinished()) + qCritical() << "Error: ndk-stack command timed out."; } else { - qWarning() << "Warning: failed to get the libs abi, ndk-stack cannot be used."; + qCritical() << "Error: failed to run ndk-stack command."; + return; } } else { qWarning() << "Warning: ndk-stack path not provided and couldn't be deduced " "using the ANDROID_NDK_ROOT environment variable."; } - QProcess adbCrashProcess; - QProcess ndkStackProcess; - - if (useNdkStack) { - 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 ******"; + if (!crashOutput.startsWith("********** Crash dump")) + qDebug() << "********** Crash dump: **********"; + qDebug().noquote() << crashOutput; + qDebug() << "********** End crash dump **********"; } static QString getCurrentTimeString()