forked from qt-creator/qt-creator
Android: Start avd emulator via detached process
Address the TODO about the process leak. Before, the process was potentially started in a separate thread. In this case the done handler of the process could work only when the thread was still executing, otherwise it couldn't be invoked because of the missing event loop in a separate thread. Thus, it was only serving for start process failures which are raised synchronously. After the successful start the process thread finished soon, and then we were losing a handle to the running process. Later, on shutdown, the process was still running (so a possible assert from process laucher could have been triggered), and the emulator process kept running after the Creator shutdown. This patch executes the emulator process as a detached process. This makes it possible to continue running the process after the Creator shutdown without leaking a Process instance. We also handle the detached process start failure and execute a message box. Change-Id: I855d280c257a0cfaca7722a3b1e14d1ead9021f7 Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
@@ -45,46 +45,32 @@ static bool is32BitUserSpace()
|
|||||||
|
|
||||||
bool startAvdAsync(const QString &avdName)
|
bool startAvdAsync(const QString &avdName)
|
||||||
{
|
{
|
||||||
const FilePath emulator = AndroidConfig::emulatorToolPath();
|
const FilePath emulatorPath = AndroidConfig::emulatorToolPath();
|
||||||
if (!emulator.exists()) {
|
if (!emulatorPath.exists()) {
|
||||||
QMetaObject::invokeMethod(Core::ICore::mainWindow(), [emulator] {
|
QMetaObject::invokeMethod(Core::ICore::mainWindow(), [emulatorPath] {
|
||||||
QMessageBox::critical(Core::ICore::dialogParent(),
|
QMessageBox::critical(Core::ICore::dialogParent(),
|
||||||
Tr::tr("Emulator Tool Is Missing"),
|
Tr::tr("Emulator Tool Is Missing"),
|
||||||
Tr::tr("Install the missing emulator tool (%1) to the"
|
Tr::tr("Install the missing emulator tool (%1) to the"
|
||||||
" installed Android SDK.")
|
" installed Android SDK.")
|
||||||
.arg(emulator.displayName()));
|
.arg(emulatorPath.displayName()));
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Here we are potentially leaking Process instance in case when shutdown happens
|
CommandLine cmd(emulatorPath);
|
||||||
// after the avdProcess has started and before it has finished. Giving a parent object here
|
|
||||||
// should solve the issue. However, AndroidAvdManager is not a QObject, so no clue what parent
|
|
||||||
// would be the most appropriate. Preferably some object taken form android plugin...
|
|
||||||
Process *avdProcess = new Process;
|
|
||||||
avdProcess->setProcessChannelMode(QProcess::MergedChannels);
|
|
||||||
QObject::connect(avdProcess, &Process::done, avdProcess, [avdProcess] {
|
|
||||||
if (avdProcess->exitCode()) {
|
|
||||||
const QString errorOutput = QString::fromLatin1(avdProcess->rawStdOut());
|
|
||||||
QMetaObject::invokeMethod(Core::ICore::mainWindow(), [errorOutput] {
|
|
||||||
const QString title = Tr::tr("AVD Start Error");
|
|
||||||
QMessageBox::critical(Core::ICore::dialogParent(), title, errorOutput);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
avdProcess->deleteLater();
|
|
||||||
});
|
|
||||||
|
|
||||||
// start the emulator
|
|
||||||
CommandLine cmd(emulator);
|
|
||||||
if (is32BitUserSpace())
|
if (is32BitUserSpace())
|
||||||
cmd.addArg("-force-32bit");
|
cmd.addArg("-force-32bit");
|
||||||
|
|
||||||
cmd.addArgs(AndroidConfig::emulatorArgs(), CommandLine::Raw);
|
cmd.addArgs(AndroidConfig::emulatorArgs(), CommandLine::Raw);
|
||||||
cmd.addArgs({"-avd", avdName});
|
cmd.addArgs({"-avd", avdName});
|
||||||
qCDebug(avdManagerLog).noquote() << "Running command (startAvdAsync):" << cmd.toUserOutput();
|
qCDebug(avdManagerLog).noquote() << "Running command (startAvdAsync):" << cmd.toUserOutput();
|
||||||
avdProcess->setCommand(cmd);
|
if (Process::startDetached(cmd, {}, DetachedChannelMode::Discard))
|
||||||
avdProcess->start();
|
return true;
|
||||||
return avdProcess->waitForStarted(QDeadlineTimer::Forever);
|
|
||||||
|
QMetaObject::invokeMethod(Core::ICore::mainWindow(), [avdName] {
|
||||||
|
QMessageBox::critical(Core::ICore::dialogParent(), Tr::tr("AVD Start Error"),
|
||||||
|
Tr::tr("Failed to start AVD emulator for \"%1\" device.").arg(avdName));
|
||||||
|
});
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString findAvd(const QString &avdName)
|
QString findAvd(const QString &avdName)
|
||||||
|
Reference in New Issue
Block a user