Android: Avoid using connectedDevices() in findAvd()

The connectedDevices() constructs the full list of
AndroidDeviceInfo with details not needed by findAvd().
These details were generated by using 2 excessive
process runs. Get rid of them, and deliver result
as soon as the matching device if found.

Make getAvdName() public.

Change-Id: Ic58e2ee55f275e230c07631853225ca3fdefd730
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
Jarek Kobus
2024-05-21 20:59:47 +02:00
parent 2d1d4d9ba3
commit ffc3c9b7f3
3 changed files with 46 additions and 32 deletions

View File

@@ -89,12 +89,25 @@ bool startAvdAsync(const QString &avdName)
QString findAvd(const QString &avdName)
{
const QList<AndroidDeviceInfo> devices = AndroidConfig::connectedDevices();
for (const AndroidDeviceInfo &device : devices) {
if (device.type != ProjectExplorer::IDevice::Emulator)
Process adbProcess;
adbProcess.setCommand({AndroidConfig::adbToolPath(), {"devices"}});
adbProcess.runBlocking();
if (adbProcess.result() != ProcessResult::FinishedWithSuccess)
return {};
// mid(1) - remove "List of devices attached" header line
const QStringList lines = adbProcess.allOutput().split('\n', Qt::SkipEmptyParts).mid(1);
for (const QString &line : lines) {
// skip the daemon logs
if (line.startsWith("* daemon"))
continue;
if (device.avdName == avdName)
return device.serialNumber;
const QString serialNumber = line.left(line.indexOf('\t')).trimmed();
if (!serialNumber.startsWith("emulator"))
continue;
if (AndroidConfig::getAvdName(serialNumber) == avdName)
return serialNumber;
}
return {};
}

View File

@@ -141,33 +141,6 @@ static QString buildToolsPackageMarker()
return QLatin1String(Constants::buildToolsPackageName) + ";";
}
static QString getAvdName(const QString &serialnumber)
{
const int index = serialnumber.indexOf(QLatin1String("-"));
if (index == -1)
return {};
bool ok;
const int port = serialnumber.mid(index + 1).toInt(&ok);
if (!ok)
return {};
QTcpSocket tcpSocket;
tcpSocket.connectToHost(QHostAddress(QHostAddress::LocalHost), port);
if (!tcpSocket.waitForConnected(100)) // Don't wait more than 100ms for a local connection
return {};
tcpSocket.write("avd name\nexit\n");
tcpSocket.waitForDisconnected(500);
const QByteArrayList response = tcpSocket.readAll().split('\n');
// The input "avd name" might not be echoed as-is, but contain ASCII control sequences.
for (int i = response.size() - 1; i > 1; --i) {
if (response.at(i).startsWith("OK"))
return QString::fromLatin1(response.at(i - 1)).trimmed();
}
return {};
}
static QString getDeviceProperty(const QString &device, const QString &property)
{
// workaround for '????????????' serial numbers
@@ -311,6 +284,33 @@ static FilePath ndkSubPathFromQtVersion(const QtVersion &version)
// AndroidConfig
//////////////////////////////////
QString getAvdName(const QString &serialnumber)
{
const int index = serialnumber.indexOf(QLatin1String("-"));
if (index == -1)
return {};
bool ok;
const int port = serialnumber.mid(index + 1).toInt(&ok);
if (!ok)
return {};
QTcpSocket tcpSocket;
tcpSocket.connectToHost(QHostAddress(QHostAddress::LocalHost), port);
if (!tcpSocket.waitForConnected(100)) // Don't wait more than 100ms for a local connection
return {};
tcpSocket.write("avd name\nexit\n");
tcpSocket.waitForDisconnected(500);
const QByteArrayList response = tcpSocket.readAll().split('\n');
// The input "avd name" might not be echoed as-is, but contain ASCII control sequences.
for (int i = response.size() - 1; i > 1; --i) {
if (response.at(i).startsWith("OK"))
return QString::fromLatin1(response.at(i - 1)).trimmed();
}
return {};
}
QLatin1String displayName(const Abi &abi)
{
switch (abi.architecture()) {

View File

@@ -38,6 +38,7 @@ public:
namespace AndroidConfig {
QString getAvdName(const QString &serialnumber);
QStringList apiLevelNamesFor(const SdkPlatformList &platforms);
QString apiLevelNameFor(const SdkPlatform *platform);