From be222eaff4da289bc83c0e8f177b0ed8a7420719 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 10 May 2024 10:46:02 +0200 Subject: Android: Simplify execution of createAvdCommand() Don't create a separate thread just to blocking execute it from the caller thread. Use runBlocking with event loop enabled instead. Change-Id: I9930d91d25ef4d1af1062570db1cfe20a1c4ca2b Reviewed-by: Alessandro Portale --- src/plugins/android/androidavdmanager.cpp | 88 +---------------------------- src/plugins/android/androidavdmanager.h | 6 +- src/plugins/android/androidconfigurations.h | 3 - src/plugins/android/avddialog.cpp | 79 +++++++++++++++----------- 4 files changed, 49 insertions(+), 127 deletions(-) diff --git a/src/plugins/android/androidavdmanager.cpp b/src/plugins/android/androidavdmanager.cpp index 4670a904621..fcc56980bca 100644 --- a/src/plugins/android/androidavdmanager.cpp +++ b/src/plugins/android/androidavdmanager.cpp @@ -2,32 +2,25 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "androidavdmanager.h" +#include "androidconfigurations.h" #include "androidtr.h" #include "avdmanageroutputparser.h" #include -#include - #include #include #include -#include #include #include #include -#include - using namespace Utils; -using namespace std; using namespace std::chrono_literals; namespace Android::Internal { -const int avdCreateTimeoutMs = 30000; - static Q_LOGGING_CATEGORY(avdManagerLog, "qtc.android.avdManager", QtWarningMsg) /*! @@ -51,85 +44,6 @@ bool AndroidAvdManager::avdManagerCommand(const QStringList &args, QString *outp return false; } -static bool checkForTimeout(const chrono::steady_clock::time_point &start, - int msecs = 3000) -{ - bool timedOut = false; - auto end = chrono::steady_clock::now(); - if (chrono::duration_cast(end-start).count() > msecs) - timedOut = true; - return timedOut; -} - -static CreateAvdInfo createAvdCommand(const CreateAvdInfo &info) -{ - CreateAvdInfo result = info; - CommandLine avdManager(androidConfig().avdManagerToolPath(), {"create", "avd", "-n", result.name}); - avdManager.addArgs({"-k", result.sdkStylePath}); - - if (result.sdcardSize > 0) - avdManager.addArgs({"-c", QString("%1M").arg(result.sdcardSize)}); - - if (!result.deviceDefinition.isEmpty() && result.deviceDefinition != "Custom") - avdManager.addArgs({"-d", QString("%1").arg(result.deviceDefinition)}); - - if (result.overwrite) - avdManager.addArg("-f"); - - qCDebug(avdManagerLog).noquote() << "Running AVD Manager command:" << avdManager.toUserOutput(); - Process proc; - proc.setProcessMode(ProcessMode::Writer); - proc.setEnvironment(androidConfig().toolsEnvironment()); - proc.setCommand(avdManager); - proc.start(); - if (!proc.waitForStarted()) { - result.error = Tr::tr("Could not start process \"%1\".").arg(avdManager.toUserOutput()); - return result; - } - QTC_CHECK(proc.isRunning()); - proc.write("yes\n"); // yes to "Do you wish to create a custom hardware profile" - - auto start = chrono::steady_clock::now(); - QString errorOutput; - QByteArray question; - while (errorOutput.isEmpty()) { - proc.waitForReadyRead(500ms); - question += proc.readAllRawStandardOutput(); - if (question.endsWith(QByteArray("]:"))) { - // truncate to last line - int index = question.lastIndexOf(QByteArray("\n")); - if (index != -1) - question = question.mid(index); - if (question.contains("hw.gpu.enabled")) - proc.write("yes\n"); - else - proc.write("\n"); - question.clear(); - } - // The exit code is always 0, so we need to check stderr - // For now assume that any output at all indicates a error - errorOutput = QString::fromLocal8Bit(proc.readAllRawStandardError()); - if (!proc.isRunning()) - break; - - // For a sane input and command, process should finish before timeout. - if (checkForTimeout(start, avdCreateTimeoutMs)) - result.error = Tr::tr("Cannot create AVD. Command timed out."); - } - - result.error = errorOutput; - return result; -} - -AndroidAvdManager::AndroidAvdManager() = default; - -AndroidAvdManager::~AndroidAvdManager() = default; - -QFuture AndroidAvdManager::createAvd(CreateAvdInfo info) const -{ - return Utils::asyncRun(&createAvdCommand, info); -} - static void avdConfigEditManufacturerTag(const FilePath &avdPath, bool recoverMode = false) { if (!avdPath.exists()) diff --git a/src/plugins/android/androidavdmanager.h b/src/plugins/android/androidavdmanager.h index 4cf9a8d81d3..81686748edd 100644 --- a/src/plugins/android/androidavdmanager.h +++ b/src/plugins/android/androidavdmanager.h @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once -#include "androidconfigurations.h" +#include "androiddeviceinfo.h" #include @@ -13,10 +13,6 @@ namespace Android::Internal { class AndroidAvdManager { public: - AndroidAvdManager(); - ~AndroidAvdManager(); - - QFuture createAvd(CreateAvdInfo info) const; QFuture avdList() const; QString startAvd(const QString &name) const; diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index aa8f1da33a5..f45801c3615 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -34,9 +34,6 @@ public: QString abi; QString deviceDefinition; int sdcardSize = 0; - QString error; // only used in the return value of createAVD - bool overwrite = false; - bool cancelled = false; }; struct SdkForQtVersions diff --git a/src/plugins/android/avddialog.cpp b/src/plugins/android/avddialog.cpp index 1d613855346..e2d06eac61f 100644 --- a/src/plugins/android/avddialog.cpp +++ b/src/plugins/android/avddialog.cpp @@ -4,6 +4,7 @@ #include "avddialog.h" #include "androidtr.h" #include "androidavdmanager.h" +#include "androidconfigurations.h" #include "androidconstants.h" #include "androiddevice.h" #include "androidsdkmanager.h" @@ -16,13 +17,13 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -39,8 +40,8 @@ namespace Android::Internal { static Q_LOGGING_CATEGORY(avdDialogLog, "qtc.android.avdDialog", QtWarningMsg) AvdDialog::AvdDialog(QWidget *parent) - : QDialog(parent), - m_allowedNameChars(QLatin1String("[a-z|A-Z|0-9|._-]*")) + : QDialog(parent) + , m_allowedNameChars(QLatin1String("[a-z|A-Z|0-9|._-]*")) { resize(800, 0); setWindowTitle(Tr::tr("Create new AVD")); @@ -129,37 +130,51 @@ int AvdDialog::exec() return QDialog::Rejected; } - CreateAvdInfo result; - result.sdkStylePath = si->sdkStylePath(); - result.apiLevel = si->apiLevel(); - result.name = name(); - result.abi = abi(); - result.deviceDefinition = deviceDefinition(); - result.sdcardSize = sdcardSize(); - result.overwrite = m_overwriteCheckBox->isChecked(); - - const AndroidAvdManager avdManager; - QFutureWatcher createAvdFutureWatcher; - - QEventLoop loop; - QObject::connect(&createAvdFutureWatcher, &QFutureWatcher::finished, - &loop, &QEventLoop::quit); - QObject::connect(&createAvdFutureWatcher, &QFutureWatcher::canceled, - &loop, &QEventLoop::quit); - createAvdFutureWatcher.setFuture(avdManager.createAvd(result)); - loop.exec(QEventLoop::ExcludeUserInputEvents); - - const QFuture future = createAvdFutureWatcher.future(); - if (future.isResultReadyAt(0)) { - const CreateAvdInfo &info = future.result(); - if (!info.error.isEmpty()) { - QMessageBox::warning(Core::ICore::dialogParent(), - Tr::tr("Create new AVD"), info.error); - return QDialog::Rejected; + CommandLine cmd(androidConfig().avdManagerToolPath(), {"create", "avd", "-n", name()}); + cmd.addArgs({"-k", si->sdkStylePath()}); + if (sdcardSize() > 0) + cmd.addArgs({"-c", QString("%1M").arg(sdcardSize())}); + + const QString deviceDef = deviceDefinition(); + if (!deviceDef.isEmpty() && deviceDef != "Custom") + cmd.addArgs({"-d", QString("%1").arg(deviceDef)}); + + if (m_overwriteCheckBox->isChecked()) + cmd.addArg("-f"); + + Process process; + process.setProcessMode(ProcessMode::Writer); + process.setEnvironment(androidConfig().toolsEnvironment()); + process.setCommand(cmd); + process.setWriteData("yes\n"); // yes to "Do you wish to create a custom hardware profile" + + QByteArray buffer; + QObject::connect(&process, &Process::readyReadStandardOutput, &process, [&process, &buffer] { + // This interaction is needed only if there is no "-d" arg for the avdmanager command. + buffer += process.readAllRawStandardOutput(); + if (buffer.endsWith(QByteArray("]:"))) { + // truncate to last line + const int index = buffer.lastIndexOf(QByteArray("\n")); + if (index != -1) + buffer = buffer.mid(index); + if (buffer.contains("hw.gpu.enabled")) + process.write("yes\n"); + else + process.write("\n"); + buffer.clear(); } - m_createdAvdInfo = info; - AndroidDeviceManager::instance()->updateAvdsList(); + }); + + using namespace std::chrono_literals; + process.runBlocking(10s, EventLoopMode::On); + if (process.result() != ProcessResult::FinishedWithSuccess) { + QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Create new AVD"), + process.exitMessage()); + return QDialog::Rejected; } + m_createdAvdInfo = {si->sdkStylePath(), si->apiLevel(), name(), abi(), deviceDef, + sdcardSize()}; + AndroidDeviceManager::instance()->updateAvdsList(); } return execResult; -- cgit v1.2.3