2016-01-15 14:57:40 +01:00
|
|
|
/****************************************************************************
|
2012-04-18 20:30:57 +03:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com>
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2012-04-18 20:30:57 +03:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2012-04-18 20:30:57 +03:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2012-04-18 20:30:57 +03:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2012-04-18 20:30:57 +03:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2012-04-18 20:30:57 +03:00
|
|
|
|
|
|
|
#include "androidconfigurations.h"
|
|
|
|
#include "androidconstants.h"
|
2013-02-14 15:51:59 +01:00
|
|
|
#include "androidtoolchain.h"
|
|
|
|
#include "androiddevice.h"
|
2017-03-30 14:43:13 +02:00
|
|
|
#include "androidmanager.h"
|
2013-08-01 12:49:47 +02:00
|
|
|
#include "androidqtversion.h"
|
2013-09-10 19:19:31 +02:00
|
|
|
#include "androiddevicedialog.h"
|
2014-03-24 16:31:28 +01:00
|
|
|
#include "avddialog.h"
|
2012-04-18 20:30:57 +03:00
|
|
|
|
|
|
|
#include <coreplugin/icore.h>
|
2013-11-22 16:40:41 +01:00
|
|
|
#include <coreplugin/messagemanager.h>
|
2020-06-17 06:35:31 +02:00
|
|
|
|
2013-02-14 15:51:59 +01:00
|
|
|
#include <projectexplorer/devicesupport/devicemanager.h>
|
2020-06-17 06:35:31 +02:00
|
|
|
#include <projectexplorer/kitinformation.h>
|
|
|
|
#include <projectexplorer/kitmanager.h>
|
2016-04-29 23:06:26 +02:00
|
|
|
#include <projectexplorer/project.h>
|
2020-07-23 15:48:56 +02:00
|
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
2013-09-10 19:19:31 +02:00
|
|
|
#include <projectexplorer/session.h>
|
2020-06-17 06:35:31 +02:00
|
|
|
#include <projectexplorer/toolchainmanager.h>
|
|
|
|
|
2013-10-25 13:47:08 +02:00
|
|
|
#include <debugger/debuggeritemmanager.h>
|
2015-02-26 15:29:28 +01:00
|
|
|
#include <debugger/debuggeritem.h>
|
2013-02-14 15:51:59 +01:00
|
|
|
#include <debugger/debuggerkitinformation.h>
|
2020-06-17 06:35:31 +02:00
|
|
|
|
2013-02-14 15:51:59 +01:00
|
|
|
#include <qtsupport/baseqtversion.h>
|
|
|
|
#include <qtsupport/qtkitinformation.h>
|
|
|
|
#include <qtsupport/qtversionmanager.h>
|
2020-06-17 06:35:31 +02:00
|
|
|
|
2014-06-16 18:25:52 +04:00
|
|
|
#include <utils/algorithm.h>
|
2013-04-17 11:52:16 +02:00
|
|
|
#include <utils/environment.h>
|
2020-06-17 06:35:31 +02:00
|
|
|
#include <utils/environment.h>
|
2016-04-29 23:06:26 +02:00
|
|
|
#include <utils/hostosinfo.h>
|
|
|
|
#include <utils/persistentsettings.h>
|
2016-04-29 16:52:58 +02:00
|
|
|
#include <utils/qtcassert.h>
|
2021-05-05 18:21:22 +02:00
|
|
|
#include <utils/qtcprocess.h>
|
2016-02-05 15:06:15 +01:00
|
|
|
#include <utils/runextensions.h>
|
2020-06-17 06:35:31 +02:00
|
|
|
#include <utils/stringutils.h>
|
2012-04-18 20:30:57 +03:00
|
|
|
|
2016-04-29 23:06:26 +02:00
|
|
|
#include <QApplication>
|
|
|
|
#include <QDirIterator>
|
|
|
|
#include <QFileInfo>
|
|
|
|
#include <QHostAddress>
|
2019-12-23 16:13:23 +02:00
|
|
|
#include <QJsonArray>
|
|
|
|
#include <QJsonDocument>
|
|
|
|
#include <QJsonObject>
|
2017-05-05 12:26:23 +02:00
|
|
|
#include <QLoggingCategory>
|
2016-04-29 23:06:26 +02:00
|
|
|
#include <QProcess>
|
2017-05-05 12:26:23 +02:00
|
|
|
#include <QRegularExpression>
|
2012-04-18 20:30:57 +03:00
|
|
|
#include <QSettings>
|
2020-05-18 18:58:32 +03:00
|
|
|
#include <QStandardPaths>
|
2012-04-18 20:30:57 +03:00
|
|
|
#include <QStringList>
|
2015-04-23 16:25:44 +02:00
|
|
|
#include <QTcpSocket>
|
2016-09-20 11:22:05 +03:00
|
|
|
#include <QThread>
|
2012-04-18 20:30:57 +03:00
|
|
|
|
2014-06-19 14:16:45 +02:00
|
|
|
#include <functional>
|
2017-08-08 14:27:54 +02:00
|
|
|
#include <memory>
|
2014-06-19 14:16:45 +02:00
|
|
|
|
2019-12-23 16:13:23 +02:00
|
|
|
using namespace QtSupport;
|
2012-08-09 01:56:51 +02:00
|
|
|
using namespace ProjectExplorer;
|
2012-04-18 20:30:57 +03:00
|
|
|
using namespace Utils;
|
|
|
|
|
2017-05-05 12:26:23 +02:00
|
|
|
namespace {
|
2020-01-15 14:39:23 +01:00
|
|
|
static Q_LOGGING_CATEGORY(avdConfigLog, "qtc.android.androidconfig", QtWarningMsg)
|
2017-05-05 12:26:23 +02:00
|
|
|
}
|
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
namespace Android {
|
2014-06-25 15:42:11 +02:00
|
|
|
using namespace Internal;
|
2012-04-18 20:30:57 +03:00
|
|
|
|
2021-04-22 16:15:26 +02:00
|
|
|
const char JsonFilePath[] = "android/sdk_definitions.json";
|
2019-12-23 16:13:23 +02:00
|
|
|
const char SdkToolsUrlKey[] = "sdk_tools_url";
|
|
|
|
const char CommonKey[] = "common";
|
|
|
|
const char SdkEssentialPkgsKey[] = "sdk_essential_packages";
|
|
|
|
const char VersionsKey[] = "versions";
|
|
|
|
const char NdkPathKey[] = "ndk_path";
|
|
|
|
const char SpecificQtVersionsKey[] = "specific_qt_versions";
|
|
|
|
const char DefaultVersionKey[] = "default";
|
2020-03-13 13:50:46 +02:00
|
|
|
const char LinuxOsKey[] = "linux";
|
|
|
|
const char WindowsOsKey[] = "windows";
|
|
|
|
const char macOsKey[] = "mac";
|
|
|
|
|
2019-12-23 16:13:23 +02:00
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
namespace {
|
2020-06-26 00:33:43 +03:00
|
|
|
const char jdk8SettingsPath[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit";
|
|
|
|
const char jdkLatestSettingsPath[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\JDK\\";
|
2017-04-12 14:08:17 +02:00
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
const QLatin1String SettingsGroup("AndroidConfigurations");
|
|
|
|
const QLatin1String SDKLocationKey("SDKLocation");
|
2020-02-24 11:19:02 +02:00
|
|
|
const QLatin1String CustomNdkLocationsKey("CustomNdkLocations");
|
2019-12-23 16:13:23 +02:00
|
|
|
const QLatin1String SdkFullyConfiguredKey("AllEssentialsInstalled");
|
2017-09-27 15:26:59 +02:00
|
|
|
const QLatin1String SDKManagerToolArgsKey("SDKManagerToolArgs");
|
2012-04-18 20:30:57 +03:00
|
|
|
const QLatin1String OpenJDKLocationKey("OpenJDKLocation");
|
2020-02-28 19:27:03 +02:00
|
|
|
const QLatin1String OpenSslPriLocationKey("OpenSSLPriLocation");
|
2013-02-14 15:51:59 +01:00
|
|
|
const QLatin1String AutomaticKitCreationKey("AutomatiKitCreation");
|
2020-10-06 18:49:15 +02:00
|
|
|
const QLatin1String EmulatorArgsKey("EmulatorArgs");
|
2014-11-18 18:37:05 +01:00
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
const QLatin1String ArmToolchainPrefix("arm-linux-androideabi");
|
|
|
|
const QLatin1String X86ToolchainPrefix("x86");
|
2014-11-18 18:37:05 +01:00
|
|
|
const QLatin1String AArch64ToolchainPrefix("aarch64-linux-android");
|
|
|
|
const QLatin1String X86_64ToolchainPrefix("x86_64");
|
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
const QLatin1String ArmToolsPrefix("arm-linux-androideabi");
|
2013-02-16 18:04:00 +02:00
|
|
|
const QLatin1String X86ToolsPrefix("i686-linux-android");
|
2014-11-18 18:37:05 +01:00
|
|
|
const QLatin1String AArch64ToolsPrefix("aarch64-linux-android");
|
|
|
|
const QLatin1String X86_64ToolsPrefix("x86_64-linux-android");
|
|
|
|
|
|
|
|
const QLatin1String ArmToolsDisplayName("arm");
|
|
|
|
const QLatin1String X86ToolsDisplayName("i686");
|
|
|
|
const QLatin1String AArch64ToolsDisplayName("aarch64");
|
|
|
|
const QLatin1String X86_64ToolsDisplayName("x86_64");
|
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
const QLatin1String Unknown("unknown");
|
|
|
|
const QLatin1String keytoolName("keytool");
|
|
|
|
const QLatin1String changeTimeStamp("ChangeTimeStamp");
|
|
|
|
|
2017-03-30 14:47:34 +02:00
|
|
|
const QLatin1String sdkToolsVersionKey("Pkg.Revision");
|
2017-05-05 12:26:23 +02:00
|
|
|
const QLatin1String ndkRevisionKey("Pkg.Revision");
|
2017-03-30 14:47:34 +02:00
|
|
|
|
2012-12-07 19:52:47 +02:00
|
|
|
static QString sdkSettingsFileName()
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2021-04-26 15:46:09 +02:00
|
|
|
return Core::ICore::installerResourcePath("android.xml").toString();
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2014-10-31 16:09:34 +01:00
|
|
|
static bool is32BitUserSpace()
|
|
|
|
{
|
|
|
|
// Do the exact same check as android's emulator is doing:
|
2015-02-03 23:50:37 +02:00
|
|
|
if (HostOsInfo::isLinuxHost()) {
|
2014-10-31 16:09:34 +01:00
|
|
|
if (QSysInfo::WordSize == 32 ) {
|
2015-02-03 23:50:37 +02:00
|
|
|
Environment env = Environment::systemEnvironment();
|
2014-10-31 16:09:34 +01:00
|
|
|
QString executable = env.searchInPath(QLatin1String("file")).toString();
|
|
|
|
QString shell = env.value(QLatin1String("SHELL"));
|
|
|
|
if (executable.isEmpty() || shell.isEmpty())
|
|
|
|
return true; // we can't detect, but creator is 32bit so assume 32bit
|
|
|
|
|
2016-04-29 16:52:58 +02:00
|
|
|
SynchronousProcess proc;
|
2014-10-31 16:09:34 +01:00
|
|
|
proc.setProcessChannelMode(QProcess::MergedChannels);
|
2016-04-29 16:52:58 +02:00
|
|
|
proc.setTimeoutS(30);
|
2021-05-17 12:02:42 +02:00
|
|
|
proc.setCommand({executable, {shell}});
|
|
|
|
proc.runBlocking();
|
2021-05-12 14:25:50 +02:00
|
|
|
if (proc.result() != QtcProcess::Finished)
|
2014-10-31 16:09:34 +01:00
|
|
|
return true;
|
2021-05-12 14:25:50 +02:00
|
|
|
return !proc.allOutput().contains("x86-64");
|
2014-10-31 16:09:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
//////////////////////////////////
|
|
|
|
// AndroidConfig
|
|
|
|
//////////////////////////////////
|
|
|
|
|
2014-11-18 18:37:05 +01:00
|
|
|
QLatin1String AndroidConfig::toolchainPrefix(const Abi &abi)
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2014-11-18 18:37:05 +01:00
|
|
|
switch (abi.architecture()) {
|
2012-08-09 01:56:51 +02:00
|
|
|
case Abi::ArmArchitecture:
|
2014-11-18 18:37:05 +01:00
|
|
|
if (abi.wordWidth() == 64)
|
|
|
|
return AArch64ToolchainPrefix;
|
2012-04-18 20:30:57 +03:00
|
|
|
return ArmToolchainPrefix;
|
2012-08-09 01:56:51 +02:00
|
|
|
case Abi::X86Architecture:
|
2014-11-18 18:37:05 +01:00
|
|
|
if (abi.wordWidth() == 64)
|
|
|
|
return X86_64ToolchainPrefix;
|
2012-04-18 20:30:57 +03:00
|
|
|
return X86ToolchainPrefix;
|
|
|
|
default:
|
|
|
|
return Unknown;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-18 18:37:05 +01:00
|
|
|
QLatin1String AndroidConfig::toolsPrefix(const Abi &abi)
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2014-11-18 18:37:05 +01:00
|
|
|
switch (abi.architecture()) {
|
2012-08-09 01:56:51 +02:00
|
|
|
case Abi::ArmArchitecture:
|
2014-11-18 18:37:05 +01:00
|
|
|
if (abi.wordWidth() == 64)
|
|
|
|
return AArch64ToolsPrefix;
|
2012-04-18 20:30:57 +03:00
|
|
|
return ArmToolsPrefix;
|
2012-08-09 01:56:51 +02:00
|
|
|
case Abi::X86Architecture:
|
2014-11-18 18:37:05 +01:00
|
|
|
if (abi.wordWidth() == 64)
|
|
|
|
return X86_64ToolsPrefix;
|
2012-04-18 20:30:57 +03:00
|
|
|
return X86ToolsPrefix;
|
|
|
|
default:
|
|
|
|
return Unknown;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-18 18:37:05 +01:00
|
|
|
QLatin1String AndroidConfig::displayName(const Abi &abi)
|
|
|
|
{
|
|
|
|
switch (abi.architecture()) {
|
|
|
|
case Abi::ArmArchitecture:
|
|
|
|
if (abi.wordWidth() == 64)
|
|
|
|
return AArch64ToolsDisplayName;
|
|
|
|
return ArmToolsDisplayName;
|
|
|
|
case Abi::X86Architecture:
|
|
|
|
if (abi.wordWidth() == 64)
|
|
|
|
return X86_64ToolsDisplayName;
|
|
|
|
return X86ToolsDisplayName;
|
|
|
|
default:
|
|
|
|
return Unknown;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
void AndroidConfig::load(const QSettings &settings)
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
|
|
|
// user settings
|
2020-10-06 18:49:15 +02:00
|
|
|
m_emulatorArgs = settings.value(EmulatorArgsKey,
|
|
|
|
QStringList({"-netdelay", "none", "-netspeed", "full"})).toStringList();
|
2019-05-28 13:49:26 +02:00
|
|
|
m_sdkLocation = FilePath::fromString(settings.value(SDKLocationKey).toString());
|
2020-02-24 11:19:02 +02:00
|
|
|
m_customNdkList = settings.value(CustomNdkLocationsKey).toStringList();
|
2017-09-27 15:26:59 +02:00
|
|
|
m_sdkManagerToolArgs = settings.value(SDKManagerToolArgsKey).toStringList();
|
2019-05-28 13:49:26 +02:00
|
|
|
m_openJDKLocation = FilePath::fromString(settings.value(OpenJDKLocationKey).toString());
|
2020-02-28 19:27:03 +02:00
|
|
|
m_openSslLocation = FilePath::fromString(settings.value(OpenSslPriLocationKey).toString());
|
2013-12-16 20:19:07 +01:00
|
|
|
m_automaticKitCreation = settings.value(AutomaticKitCreationKey, true).toBool();
|
2019-12-23 16:13:23 +02:00
|
|
|
m_sdkFullyConfigured = settings.value(SdkFullyConfiguredKey, false).toBool();
|
2012-04-18 20:30:57 +03:00
|
|
|
|
|
|
|
PersistentSettingsReader reader;
|
2019-05-28 13:49:26 +02:00
|
|
|
if (reader.load(FilePath::fromString(sdkSettingsFileName()))
|
2012-12-07 19:52:47 +02:00
|
|
|
&& settings.value(changeTimeStamp).toInt() != QFileInfo(sdkSettingsFileName()).lastModified().toMSecsSinceEpoch() / 1000) {
|
2012-04-18 20:30:57 +03:00
|
|
|
// persisten settings
|
2019-05-28 13:49:26 +02:00
|
|
|
m_sdkLocation = FilePath::fromString(reader.restoreValue(SDKLocationKey, m_sdkLocation.toString()).toString());
|
2020-02-24 11:19:02 +02:00
|
|
|
m_customNdkList = reader.restoreValue(CustomNdkLocationsKey).toStringList();
|
2017-09-27 15:26:59 +02:00
|
|
|
m_sdkManagerToolArgs = reader.restoreValue(SDKManagerToolArgsKey, m_sdkManagerToolArgs).toStringList();
|
2019-05-28 13:49:26 +02:00
|
|
|
m_openJDKLocation = FilePath::fromString(reader.restoreValue(OpenJDKLocationKey, m_openJDKLocation.toString()).toString());
|
2020-02-28 19:27:03 +02:00
|
|
|
m_openSslLocation = FilePath::fromString(reader.restoreValue(OpenSslPriLocationKey, m_openSslLocation.toString()).toString());
|
2014-12-16 15:50:02 +01:00
|
|
|
m_automaticKitCreation = reader.restoreValue(AutomaticKitCreationKey, m_automaticKitCreation).toBool();
|
2019-12-23 16:13:23 +02:00
|
|
|
m_sdkFullyConfigured = reader.restoreValue(SdkFullyConfiguredKey, m_sdkFullyConfigured).toBool();
|
2012-04-18 20:30:57 +03:00
|
|
|
// persistent settings
|
|
|
|
}
|
2020-02-24 11:19:02 +02:00
|
|
|
m_customNdkList.removeAll("");
|
2019-12-23 16:13:23 +02:00
|
|
|
parseDependenciesJson();
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::save(QSettings &settings) const
|
|
|
|
{
|
2012-12-07 19:52:47 +02:00
|
|
|
QFileInfo fileInfo(sdkSettingsFileName());
|
2012-04-18 20:30:57 +03:00
|
|
|
if (fileInfo.exists())
|
|
|
|
settings.setValue(changeTimeStamp, fileInfo.lastModified().toMSecsSinceEpoch() / 1000);
|
|
|
|
|
|
|
|
// user settings
|
2013-12-16 20:19:07 +01:00
|
|
|
settings.setValue(SDKLocationKey, m_sdkLocation.toString());
|
2020-02-24 11:19:02 +02:00
|
|
|
settings.setValue(CustomNdkLocationsKey, m_customNdkList);
|
2017-09-27 15:26:59 +02:00
|
|
|
settings.setValue(SDKManagerToolArgsKey, m_sdkManagerToolArgs);
|
2013-12-16 20:19:07 +01:00
|
|
|
settings.setValue(OpenJDKLocationKey, m_openJDKLocation.toString());
|
2020-02-28 19:27:03 +02:00
|
|
|
settings.setValue(OpenSslPriLocationKey, m_openSslLocation.toString());
|
2020-10-06 18:49:15 +02:00
|
|
|
settings.setValue(EmulatorArgsKey, m_emulatorArgs);
|
2013-12-16 20:19:07 +01:00
|
|
|
settings.setValue(AutomaticKitCreationKey, m_automaticKitCreation);
|
2019-12-23 16:13:23 +02:00
|
|
|
settings.setValue(SdkFullyConfiguredKey, m_sdkFullyConfigured);
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2019-12-23 16:13:23 +02:00
|
|
|
void AndroidConfig::parseDependenciesJson()
|
|
|
|
{
|
2021-04-26 15:46:09 +02:00
|
|
|
const FilePath sdkConfigUserFile = Core::ICore::userResourcePath(JsonFilePath);
|
|
|
|
const FilePath sdkConfigFile = Core::ICore::resourcePath(JsonFilePath);
|
2019-12-23 16:13:23 +02:00
|
|
|
|
2021-04-22 16:15:26 +02:00
|
|
|
if (!sdkConfigUserFile.exists()) {
|
|
|
|
QDir(sdkConfigUserFile.toFileInfo().absolutePath()).mkpath(".");
|
|
|
|
QFile::copy(sdkConfigFile.toString(), sdkConfigUserFile.toString());
|
2020-03-16 20:14:56 +02:00
|
|
|
}
|
|
|
|
|
2021-04-22 16:15:26 +02:00
|
|
|
if (sdkConfigFile.toFileInfo().lastModified() > sdkConfigUserFile.toFileInfo().lastModified()) {
|
|
|
|
const QString oldUserFile = (sdkConfigUserFile + ".old").toString();
|
|
|
|
QFile::remove(oldUserFile);
|
|
|
|
QFile::rename(sdkConfigUserFile.toString(), oldUserFile);
|
|
|
|
QFile::copy(sdkConfigFile.toString(), sdkConfigUserFile.toString());
|
2020-03-16 20:14:56 +02:00
|
|
|
}
|
|
|
|
|
2021-04-22 16:15:26 +02:00
|
|
|
QFile jsonFile(sdkConfigUserFile.toString());
|
2020-03-16 20:14:56 +02:00
|
|
|
if (!jsonFile.open(QIODevice::ReadOnly)) {
|
|
|
|
qCDebug(avdConfigLog, "Couldn't open JSON config file %s.", qPrintable(jsonFile.fileName()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QJsonObject jsonObject = QJsonDocument::fromJson(jsonFile.readAll()).object();
|
2019-12-23 16:13:23 +02:00
|
|
|
|
|
|
|
if (jsonObject.contains(CommonKey) && jsonObject[CommonKey].isObject()) {
|
|
|
|
QJsonObject commonObject = jsonObject[CommonKey].toObject();
|
|
|
|
// Parse SDK Tools URL
|
|
|
|
if (commonObject.contains(SdkToolsUrlKey) && commonObject[SdkToolsUrlKey].isObject()) {
|
|
|
|
QJsonObject sdkToolsObj(commonObject[SdkToolsUrlKey].toObject());
|
|
|
|
if (Utils::HostOsInfo::isMacHost()) {
|
2020-03-13 13:50:46 +02:00
|
|
|
m_sdkToolsUrl = sdkToolsObj[macOsKey].toString();
|
2019-12-23 16:13:23 +02:00
|
|
|
m_sdkToolsSha256 = QByteArray::fromHex(sdkToolsObj["mac_sha256"].toString().toUtf8());
|
|
|
|
} else if (Utils::HostOsInfo::isWindowsHost()) {
|
2020-03-13 13:50:46 +02:00
|
|
|
m_sdkToolsUrl = sdkToolsObj[WindowsOsKey].toString();
|
2019-12-23 16:13:23 +02:00
|
|
|
m_sdkToolsSha256 = QByteArray::fromHex(sdkToolsObj["windows_sha256"].toString().toUtf8());
|
|
|
|
} else {
|
2020-03-13 13:50:46 +02:00
|
|
|
m_sdkToolsUrl = sdkToolsObj[LinuxOsKey].toString();
|
2019-12-23 16:13:23 +02:00
|
|
|
m_sdkToolsSha256 = QByteArray::fromHex(sdkToolsObj["linux_sha256"].toString().toUtf8());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse common essential packages
|
2020-03-13 13:50:46 +02:00
|
|
|
auto appendEssentialsFromArray = [this](QJsonArray array) {
|
|
|
|
for (const QJsonValueRef &pkg : array)
|
|
|
|
m_commonEssentialPkgs.append(pkg.toString());
|
|
|
|
};
|
|
|
|
|
|
|
|
QJsonObject commonEssentials = commonObject[SdkEssentialPkgsKey].toObject();
|
|
|
|
appendEssentialsFromArray(commonEssentials[DefaultVersionKey].toArray());
|
|
|
|
|
|
|
|
if (Utils::HostOsInfo::isWindowsHost())
|
|
|
|
appendEssentialsFromArray(commonEssentials[WindowsOsKey].toArray());
|
|
|
|
if (Utils::HostOsInfo::isMacHost())
|
|
|
|
appendEssentialsFromArray(commonEssentials[macOsKey].toArray());
|
|
|
|
else
|
|
|
|
appendEssentialsFromArray(commonEssentials[LinuxOsKey].toArray());
|
2019-12-23 16:13:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
auto fillQtVersionsRange = [](const QString &shortVersion) {
|
|
|
|
QList<QtVersionNumber> versions;
|
|
|
|
QRegularExpression re("([0-9]\\.[0-9]*\\.)\\[([0-9])\\-([0-9])\\]");
|
|
|
|
QRegularExpressionMatch match = re.match(shortVersion);
|
|
|
|
if (match.hasMatch() && match.lastCapturedIndex() == 3)
|
|
|
|
for (int i = match.captured(2).toInt(); i <= match.captured(3).toInt(); ++i)
|
|
|
|
versions.append(QtVersionNumber(match.captured(1) + QString::number(i)));
|
|
|
|
else
|
|
|
|
versions.append(QtVersionNumber(shortVersion));
|
|
|
|
|
|
|
|
return versions;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (jsonObject.contains(SpecificQtVersionsKey) && jsonObject[SpecificQtVersionsKey].isArray()) {
|
|
|
|
QJsonArray versionsArray = jsonObject[SpecificQtVersionsKey].toArray();
|
|
|
|
for (const QJsonValueRef &item : versionsArray) {
|
|
|
|
QJsonObject itemObj = item.toObject();
|
|
|
|
SdkForQtVersions specificVersion;
|
|
|
|
|
|
|
|
specificVersion.ndkPath = itemObj[NdkPathKey].toString();
|
|
|
|
for (const QJsonValueRef &pkg : itemObj[SdkEssentialPkgsKey].toArray())
|
|
|
|
specificVersion.essentialPackages.append(pkg.toString());
|
|
|
|
for (const QJsonValueRef &pkg : itemObj[VersionsKey].toArray())
|
|
|
|
specificVersion.versions.append(fillQtVersionsRange(pkg.toString()));
|
|
|
|
|
|
|
|
if (itemObj[VersionsKey].toArray().first().toString() == DefaultVersionKey)
|
|
|
|
m_defaultSdkDepends = specificVersion;
|
|
|
|
else
|
|
|
|
m_specificQtVersions.append(specificVersion);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-16 20:46:23 +02:00
|
|
|
QVector<int> AndroidConfig::availableNdkPlatforms(const BaseQtVersion *qtVersion) const
|
|
|
|
{
|
|
|
|
QVector<int> availableNdkPlatforms;
|
|
|
|
QDirIterator it(ndkLocation(qtVersion).pathAppended("platforms").toString(),
|
|
|
|
QStringList("android-*"),
|
|
|
|
QDir::Dirs);
|
|
|
|
while (it.hasNext()) {
|
|
|
|
const QString &fileName = it.next();
|
|
|
|
availableNdkPlatforms.push_back(
|
2020-09-18 13:15:18 +02:00
|
|
|
fileName.mid(fileName.lastIndexOf(QLatin1Char('-')) + 1).toInt());
|
2020-02-16 20:46:23 +02:00
|
|
|
}
|
|
|
|
Utils::sort(availableNdkPlatforms, std::greater<>());
|
|
|
|
|
|
|
|
return availableNdkPlatforms;
|
|
|
|
}
|
|
|
|
|
2020-02-24 11:19:02 +02:00
|
|
|
QStringList AndroidConfig::getCustomNdkList() const
|
|
|
|
{
|
|
|
|
return m_customNdkList;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::addCustomNdk(const QString &customNdk)
|
|
|
|
{
|
|
|
|
if (!m_customNdkList.contains(customNdk))
|
|
|
|
m_customNdkList.append(customNdk);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::removeCustomNdk(const QString &customNdk)
|
|
|
|
{
|
|
|
|
m_customNdkList.removeAll(customNdk);
|
|
|
|
}
|
|
|
|
|
2020-02-28 19:27:03 +02:00
|
|
|
Utils::FilePath AndroidConfig::openSslLocation() const
|
|
|
|
{
|
|
|
|
return m_openSslLocation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::setOpenSslLocation(const Utils::FilePath &openSslLocation)
|
|
|
|
{
|
|
|
|
m_openSslLocation = openSslLocation;
|
|
|
|
}
|
|
|
|
|
2017-08-18 08:22:34 +02:00
|
|
|
QStringList AndroidConfig::apiLevelNamesFor(const SdkPlatformList &platforms)
|
2014-03-24 16:31:28 +01:00
|
|
|
{
|
2014-07-16 12:35:29 +02:00
|
|
|
return Utils::transform(platforms, AndroidConfig::apiLevelNameFor);
|
2014-03-24 16:31:28 +01:00
|
|
|
}
|
|
|
|
|
2017-08-18 08:22:34 +02:00
|
|
|
QString AndroidConfig::apiLevelNameFor(const SdkPlatform *platform)
|
2013-10-17 13:23:08 +02:00
|
|
|
{
|
2017-08-18 08:22:34 +02:00
|
|
|
return platform && platform->apiLevel() > 0 ?
|
|
|
|
QString("android-%1").arg(platform->apiLevel()) : "";
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2020-04-16 16:44:06 +03:00
|
|
|
bool AndroidConfig::isCmdlineSdkToolsInstalled() const
|
|
|
|
{
|
|
|
|
QString toolPath("cmdline-tools/latest/bin/sdkmanager");
|
|
|
|
if (HostOsInfo::isWindowsHost())
|
|
|
|
toolPath += ANDROID_BAT_SUFFIX;
|
|
|
|
|
|
|
|
return m_sdkLocation.pathAppended(toolPath).exists();
|
|
|
|
}
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath AndroidConfig::adbToolPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2020-02-19 17:35:56 +01:00
|
|
|
return m_sdkLocation / "platform-tools/adb" QTC_HOST_EXE_SUFFIX;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath AndroidConfig::emulatorToolPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2017-04-03 11:11:17 +02:00
|
|
|
QString relativePath = "emulator/emulator";
|
2020-04-16 16:44:06 +03:00
|
|
|
if (sdkToolsVersion() < QVersionNumber(25, 3, 0) && !isCmdlineSdkToolsInstalled())
|
2017-04-03 11:11:17 +02:00
|
|
|
relativePath = "tools/emulator";
|
2020-02-19 17:35:56 +01:00
|
|
|
return m_sdkLocation / (relativePath + QTC_HOST_EXE_SUFFIX);
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath AndroidConfig::sdkManagerToolPath() const
|
2017-03-30 14:47:34 +02:00
|
|
|
{
|
2020-04-16 16:44:06 +03:00
|
|
|
QStringList sdkmanagerPaths = {"cmdline-tools/latest/bin/sdkmanager",
|
|
|
|
"tools/bin/sdkmanager"};
|
|
|
|
|
|
|
|
for (QString &toolPath : sdkmanagerPaths) {
|
|
|
|
if (HostOsInfo::isWindowsHost())
|
|
|
|
toolPath += ANDROID_BAT_SUFFIX;
|
|
|
|
|
2020-04-20 08:40:54 +02:00
|
|
|
const FilePath sdkmanagerPath = m_sdkLocation / toolPath;
|
2020-04-16 16:44:06 +03:00
|
|
|
if (sdkmanagerPath.exists())
|
|
|
|
return sdkmanagerPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FilePath();
|
2017-03-30 14:47:34 +02:00
|
|
|
}
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath AndroidConfig::avdManagerToolPath() const
|
2017-04-03 11:11:17 +02:00
|
|
|
{
|
2020-04-16 16:44:06 +03:00
|
|
|
QStringList sdkmanagerPaths = {"cmdline-tools/latest/bin/avdmanager",
|
|
|
|
"tools/bin/avdmanager"};
|
|
|
|
|
|
|
|
for (QString &toolPath : sdkmanagerPaths) {
|
|
|
|
if (HostOsInfo::isWindowsHost())
|
|
|
|
toolPath += ANDROID_BAT_SUFFIX;
|
|
|
|
|
2020-04-20 08:40:54 +02:00
|
|
|
const FilePath sdkmanagerPath = m_sdkLocation / toolPath;
|
2020-04-16 16:44:06 +03:00
|
|
|
if (sdkmanagerPath.exists())
|
|
|
|
return sdkmanagerPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FilePath();
|
2017-04-03 11:11:17 +02:00
|
|
|
}
|
|
|
|
|
2020-02-24 11:19:02 +02:00
|
|
|
FilePath AndroidConfig::toolchainPathFromNdk(const Utils::FilePath &ndkLocation) const
|
2013-04-04 01:29:47 -07:00
|
|
|
{
|
2020-02-19 17:35:56 +01:00
|
|
|
const FilePath toolchainPath = ndkLocation / "toolchains/llvm/prebuilt/";
|
2018-10-25 18:12:43 +02:00
|
|
|
|
|
|
|
// detect toolchain host
|
|
|
|
QStringList hostPatterns;
|
|
|
|
switch (HostOsInfo::hostOs()) {
|
|
|
|
case OsTypeLinux:
|
|
|
|
hostPatterns << QLatin1String("linux*");
|
|
|
|
break;
|
|
|
|
case OsTypeWindows:
|
|
|
|
hostPatterns << QLatin1String("windows*");
|
|
|
|
break;
|
|
|
|
case OsTypeMac:
|
|
|
|
hostPatterns << QLatin1String("darwin*");
|
|
|
|
break;
|
2019-05-28 13:49:26 +02:00
|
|
|
default: /* unknown host */ return FilePath();
|
2018-10-25 18:12:43 +02:00
|
|
|
}
|
|
|
|
|
2019-08-26 14:19:07 +03:00
|
|
|
QDirIterator iter(toolchainPath.toString(), hostPatterns, QDir::Dirs);
|
|
|
|
if (iter.hasNext()) {
|
|
|
|
iter.next();
|
2020-02-19 17:35:56 +01:00
|
|
|
return toolchainPath / iter.fileName();
|
2018-10-25 18:12:43 +02:00
|
|
|
}
|
|
|
|
|
2018-11-28 14:30:42 +01:00
|
|
|
return {};
|
2013-04-04 01:29:47 -07:00
|
|
|
}
|
|
|
|
|
2020-02-24 11:19:02 +02:00
|
|
|
FilePath AndroidConfig::toolchainPath(const BaseQtVersion *qtVersion) const
|
|
|
|
{
|
|
|
|
return toolchainPathFromNdk(ndkLocation(qtVersion));
|
|
|
|
}
|
|
|
|
|
|
|
|
FilePath AndroidConfig::clangPathFromNdk(const Utils::FilePath &ndkLocation) const
|
2019-08-26 14:19:07 +03:00
|
|
|
{
|
2020-02-24 11:19:02 +02:00
|
|
|
const FilePath path = toolchainPathFromNdk(ndkLocation);
|
2019-08-26 14:19:07 +03:00
|
|
|
if (path.isEmpty())
|
|
|
|
return {};
|
2020-02-19 17:35:56 +01:00
|
|
|
return path / HostOsInfo::withExecutableSuffix("bin/clang");
|
2019-08-26 14:19:07 +03:00
|
|
|
}
|
|
|
|
|
2020-02-16 20:46:23 +02:00
|
|
|
FilePath AndroidConfig::gdbPath(const ProjectExplorer::Abi &abi, const BaseQtVersion *qtVersion) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2020-02-24 11:19:02 +02:00
|
|
|
return gdbPathFromNdk(abi, ndkLocation(qtVersion));
|
|
|
|
}
|
|
|
|
|
|
|
|
FilePath AndroidConfig::gdbPathFromNdk(const Abi &abi, const FilePath &ndkLocation) const
|
|
|
|
{
|
|
|
|
const FilePath path = ndkLocation.pathAppended(
|
2020-07-16 08:17:01 +02:00
|
|
|
QString("prebuilt/%1/bin/gdb%2").arg(toolchainHostFromNdk(ndkLocation),
|
|
|
|
QString(QTC_HOST_EXE_SUFFIX)));
|
2018-11-28 14:30:42 +01:00
|
|
|
if (path.exists())
|
|
|
|
return path;
|
|
|
|
// fallback for old NDKs (e.g. 10e)
|
2020-02-24 11:19:02 +02:00
|
|
|
return ndkLocation.pathAppended(QString("toolchains/%1-4.9/prebuilt/%2/bin/%3-gdb%4")
|
|
|
|
.arg(toolchainPrefix(abi),
|
|
|
|
toolchainHostFromNdk(ndkLocation),
|
|
|
|
toolsPrefix(abi),
|
2020-07-16 08:17:01 +02:00
|
|
|
QString(QTC_HOST_EXE_SUFFIX)));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2020-02-16 20:46:23 +02:00
|
|
|
FilePath AndroidConfig::makePathFromNdk(const FilePath &ndkLocation) const
|
|
|
|
{
|
|
|
|
return ndkLocation.pathAppended(
|
2020-07-16 08:17:01 +02:00
|
|
|
QString("prebuilt/%1/bin/make%2").arg(toolchainHostFromNdk(ndkLocation),
|
|
|
|
QString(QTC_HOST_EXE_SUFFIX)));
|
2017-11-06 15:59:11 +01:00
|
|
|
}
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath AndroidConfig::openJDKBinPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2019-05-28 13:49:26 +02:00
|
|
|
const FilePath path = m_openJDKLocation;
|
2012-04-24 15:49:09 +02:00
|
|
|
if (!path.isEmpty())
|
2019-05-15 08:15:19 +02:00
|
|
|
return path.pathAppended("bin");
|
2012-04-24 15:49:09 +02:00
|
|
|
return path;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath AndroidConfig::keytoolPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2019-05-15 08:15:19 +02:00
|
|
|
return openJDKBinPath().pathAppended(keytoolName);
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(QString *error) const
|
2015-04-10 18:08:51 +02:00
|
|
|
{
|
2019-06-06 16:27:55 +02:00
|
|
|
return connectedDevices(adbToolPath(), error);
|
2015-04-10 18:08:51 +02:00
|
|
|
}
|
|
|
|
|
2019-06-06 16:27:55 +02:00
|
|
|
QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(const FilePath &adbToolPath, QString *error)
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2012-07-03 16:57:44 +03:00
|
|
|
QVector<AndroidDeviceInfo> devices;
|
2016-04-29 16:52:58 +02:00
|
|
|
SynchronousProcess adbProc;
|
|
|
|
adbProc.setTimeoutS(30);
|
2019-06-06 16:27:55 +02:00
|
|
|
CommandLine cmd{adbToolPath, {"devices"}};
|
2021-05-17 12:02:42 +02:00
|
|
|
adbProc.setCommand(cmd);
|
|
|
|
adbProc.runBlocking();
|
2021-05-12 14:25:50 +02:00
|
|
|
if (adbProc.result() != QtcProcess::Finished) {
|
2013-07-03 17:58:48 +02:00
|
|
|
if (error)
|
2019-06-06 16:27:55 +02:00
|
|
|
*error = QApplication::translate("AndroidConfiguration", "Could not run: %1")
|
|
|
|
.arg(cmd.toUserOutput());
|
2012-04-18 20:30:57 +03:00
|
|
|
return devices;
|
|
|
|
}
|
2021-05-12 14:25:50 +02:00
|
|
|
QStringList adbDevs = adbProc.allOutput().split('\n', Qt::SkipEmptyParts);
|
2013-10-22 13:51:17 +03:00
|
|
|
if (adbDevs.empty())
|
|
|
|
return devices;
|
|
|
|
|
2020-06-03 13:45:30 +02:00
|
|
|
for (const QString &line : adbDevs) // remove the daemon logs
|
2020-05-18 10:43:06 +03:00
|
|
|
if (line.startsWith("* daemon"))
|
|
|
|
adbDevs.removeOne(line);
|
2013-10-22 13:51:17 +03:00
|
|
|
adbDevs.removeFirst(); // remove "List of devices attached" header line
|
2013-02-24 18:04:36 +04:00
|
|
|
|
|
|
|
// workaround for '????????????' serial numbers:
|
|
|
|
// can use "adb -d" when only one usb device attached
|
2016-04-29 16:52:58 +02:00
|
|
|
foreach (const QString &device, adbDevs) {
|
|
|
|
const QString serialNo = device.left(device.indexOf('\t')).trimmed();
|
|
|
|
const QString deviceType = device.mid(device.indexOf('\t')).trimmed();
|
2013-08-28 12:50:32 +02:00
|
|
|
AndroidDeviceInfo dev;
|
2013-02-24 18:04:36 +04:00
|
|
|
dev.serialNumber = serialNo;
|
2013-09-10 19:19:31 +02:00
|
|
|
dev.type = serialNo.startsWith(QLatin1String("emulator")) ? AndroidDeviceInfo::Emulator : AndroidDeviceInfo::Hardware;
|
2015-04-10 18:08:51 +02:00
|
|
|
dev.sdk = getSDKVersion(adbToolPath, dev.serialNumber);
|
|
|
|
dev.cpuAbi = getAbis(adbToolPath, dev.serialNumber);
|
2014-03-10 15:18:46 +01:00
|
|
|
if (deviceType == QLatin1String("unauthorized"))
|
|
|
|
dev.state = AndroidDeviceInfo::UnAuthorizedState;
|
|
|
|
else if (deviceType == QLatin1String("offline"))
|
|
|
|
dev.state = AndroidDeviceInfo::OfflineState;
|
|
|
|
else
|
|
|
|
dev.state = AndroidDeviceInfo::OkState;
|
2015-04-23 16:25:44 +02:00
|
|
|
|
2016-05-05 17:34:22 +03:00
|
|
|
if (dev.type == AndroidDeviceInfo::Emulator) {
|
2015-04-23 16:25:44 +02:00
|
|
|
dev.avdname = getAvdName(dev.serialNumber);
|
2016-05-05 17:34:22 +03:00
|
|
|
if (dev.avdname.isEmpty())
|
|
|
|
dev.avdname = serialNo;
|
|
|
|
}
|
2015-04-23 16:25:44 +02:00
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
devices.push_back(dev);
|
|
|
|
}
|
2013-08-28 12:50:32 +02:00
|
|
|
|
2017-03-30 14:43:13 +02:00
|
|
|
Utils::sort(devices);
|
2013-07-03 17:58:48 +02:00
|
|
|
if (devices.isEmpty() && error)
|
2013-12-16 20:19:07 +01:00
|
|
|
*error = QApplication::translate("AndroidConfiguration",
|
|
|
|
"No devices found in output of: %1")
|
2019-06-06 16:27:55 +02:00
|
|
|
.arg(cmd.toUserOutput());
|
2012-04-18 20:30:57 +03:00
|
|
|
return devices;
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
bool AndroidConfig::isConnected(const QString &serialNumber) const
|
2013-07-05 18:54:42 +02:00
|
|
|
{
|
2013-11-13 16:35:29 +01:00
|
|
|
QVector<AndroidDeviceInfo> devices = connectedDevices();
|
|
|
|
foreach (AndroidDeviceInfo device, devices) {
|
|
|
|
if (device.serialNumber == serialNumber)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2013-07-05 18:54:42 +02:00
|
|
|
|
2019-06-06 16:27:55 +02:00
|
|
|
QString AndroidConfig::getDeviceProperty(const FilePath &adbToolPath, const QString &device, const QString &property)
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-02-24 18:04:36 +04:00
|
|
|
// workaround for '????????????' serial numbers
|
2019-06-06 16:27:55 +02:00
|
|
|
CommandLine cmd(adbToolPath, AndroidDeviceInfo::adbSelector(device));
|
|
|
|
cmd.addArgs({"shell", "getprop", property});
|
2012-04-18 20:30:57 +03:00
|
|
|
|
2016-04-29 16:52:58 +02:00
|
|
|
SynchronousProcess adbProc;
|
|
|
|
adbProc.setTimeoutS(10);
|
2021-05-17 12:02:42 +02:00
|
|
|
adbProc.setCommand(cmd);
|
|
|
|
adbProc.runBlocking();
|
2021-05-12 14:25:50 +02:00
|
|
|
if (adbProc.result() != QtcProcess::Finished)
|
2015-04-10 16:46:30 +02:00
|
|
|
return QString();
|
|
|
|
|
2021-05-12 14:25:50 +02:00
|
|
|
return adbProc.allOutput();
|
2015-04-10 16:46:30 +02:00
|
|
|
}
|
|
|
|
|
2019-06-06 16:27:55 +02:00
|
|
|
int AndroidConfig::getSDKVersion(const FilePath &adbToolPath, const QString &device)
|
2015-04-10 18:08:51 +02:00
|
|
|
{
|
2019-06-06 16:27:55 +02:00
|
|
|
QString tmp = getDeviceProperty(adbToolPath, device, "ro.build.version.sdk");
|
2015-04-10 16:46:30 +02:00
|
|
|
if (tmp.isEmpty())
|
2012-04-18 20:30:57 +03:00
|
|
|
return -1;
|
2015-04-10 16:46:30 +02:00
|
|
|
return tmp.trimmed().toInt();
|
|
|
|
}
|
|
|
|
|
2015-04-23 16:25:44 +02:00
|
|
|
QString AndroidConfig::getAvdName(const QString &serialnumber)
|
|
|
|
{
|
|
|
|
int index = serialnumber.indexOf(QLatin1String("-"));
|
|
|
|
if (index == -1)
|
|
|
|
return QString();
|
|
|
|
bool ok;
|
2020-09-18 13:15:18 +02:00
|
|
|
int port = serialnumber.mid(index + 1).toInt(&ok);
|
2015-04-23 16:25:44 +02:00
|
|
|
if (!ok)
|
|
|
|
return QString();
|
|
|
|
|
2016-04-29 08:54:00 +02:00
|
|
|
const QByteArray avdName = "avd name\n";
|
2015-04-23 16:25:44 +02:00
|
|
|
|
|
|
|
QTcpSocket tcpSocket;
|
|
|
|
tcpSocket.connectToHost(QHostAddress(QHostAddress::LocalHost), port);
|
2016-05-05 17:34:22 +03:00
|
|
|
if (!tcpSocket.waitForConnected(100)) // Don't wait more than 100ms for a local connection
|
|
|
|
return QString{};
|
|
|
|
|
2015-04-23 16:25:44 +02:00
|
|
|
tcpSocket.write(avdName + "exit\n");
|
2016-05-05 17:34:22 +03:00
|
|
|
tcpSocket.waitForDisconnected(500);
|
2015-04-23 16:25:44 +02:00
|
|
|
|
2016-04-29 08:54:00 +02:00
|
|
|
QByteArray name;
|
|
|
|
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) {
|
2016-08-25 15:46:50 +03:00
|
|
|
if (response.at(i).startsWith("OK")) {
|
2016-04-29 08:54:00 +02:00
|
|
|
name = response.at(i - 1);
|
2016-08-25 15:46:50 +03:00
|
|
|
break;
|
|
|
|
}
|
2016-04-29 08:54:00 +02:00
|
|
|
}
|
|
|
|
return QString::fromLatin1(name).trimmed();
|
2015-04-23 16:25:44 +02:00
|
|
|
}
|
|
|
|
|
2015-04-10 16:46:30 +02:00
|
|
|
AndroidConfig::OpenGl AndroidConfig::getOpenGLEnabled(const QString &emulator) const
|
|
|
|
{
|
|
|
|
QDir dir = QDir::home();
|
|
|
|
if (!dir.cd(QLatin1String(".android")))
|
|
|
|
return OpenGl::Unknown;
|
|
|
|
if (!dir.cd(QLatin1String("avd")))
|
|
|
|
return OpenGl::Unknown;
|
|
|
|
if (!dir.cd(emulator + QLatin1String(".avd")))
|
|
|
|
return OpenGl::Unknown;
|
|
|
|
QFile file(dir.filePath(QLatin1String("config.ini")));
|
|
|
|
if (!file.exists())
|
|
|
|
return OpenGl::Unknown;
|
|
|
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
|
|
|
return OpenGl::Unknown;
|
|
|
|
while (!file.atEnd()) {
|
|
|
|
QByteArray line = file.readLine();
|
|
|
|
if (line.contains("hw.gpu.enabled") && line.contains("yes"))
|
|
|
|
return OpenGl::Enabled;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
2015-04-10 16:46:30 +02:00
|
|
|
return OpenGl::Disabled;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-07-03 17:58:48 +02:00
|
|
|
//!
|
|
|
|
//! \brief AndroidConfigurations::getProductModel
|
|
|
|
//! \param device serial number
|
|
|
|
//! \return the produce model of the device or if that cannot be read the serial number
|
|
|
|
//!
|
2013-12-16 20:19:07 +01:00
|
|
|
QString AndroidConfig::getProductModel(const QString &device) const
|
2013-07-03 17:58:48 +02:00
|
|
|
{
|
2013-09-10 19:19:31 +02:00
|
|
|
if (m_serialNumberToDeviceName.contains(device))
|
|
|
|
return m_serialNumberToDeviceName.value(device);
|
2013-07-03 17:58:48 +02:00
|
|
|
|
2019-06-06 16:27:55 +02:00
|
|
|
QString model = getDeviceProperty(adbToolPath(), device, "ro.product.model").trimmed();
|
2013-07-03 17:58:48 +02:00
|
|
|
if (model.isEmpty())
|
|
|
|
return device;
|
2015-04-10 16:46:30 +02:00
|
|
|
|
2013-09-10 19:19:31 +02:00
|
|
|
if (!device.startsWith(QLatin1String("????")))
|
|
|
|
m_serialNumberToDeviceName.insert(device, model);
|
2013-07-03 17:58:48 +02:00
|
|
|
return model;
|
|
|
|
}
|
|
|
|
|
2019-06-06 16:27:55 +02:00
|
|
|
QStringList AndroidConfig::getAbis(const FilePath &adbToolPath, const QString &device)
|
2013-05-03 15:10:21 +02:00
|
|
|
{
|
|
|
|
QStringList result;
|
2014-11-18 12:55:21 +01:00
|
|
|
// First try via ro.product.cpu.abilist
|
|
|
|
QStringList arguments = AndroidDeviceInfo::adbSelector(device);
|
2019-06-06 16:27:55 +02:00
|
|
|
arguments << "shell" << "getprop" << "ro.product.cpu.abilist";
|
2016-04-29 16:52:58 +02:00
|
|
|
SynchronousProcess adbProc;
|
|
|
|
adbProc.setTimeoutS(10);
|
2021-05-17 12:02:42 +02:00
|
|
|
adbProc.setCommand({adbToolPath, arguments});
|
|
|
|
adbProc.runBlocking();
|
2021-05-12 14:25:50 +02:00
|
|
|
if (adbProc.result() != QtcProcess::Finished)
|
2014-11-18 12:55:21 +01:00
|
|
|
return result;
|
2016-04-29 16:52:58 +02:00
|
|
|
|
2021-05-12 14:25:50 +02:00
|
|
|
QString output = adbProc.allOutput().trimmed();
|
2014-11-18 12:55:21 +01:00
|
|
|
if (!output.isEmpty()) {
|
|
|
|
QStringList result = output.split(QLatin1Char(','));
|
|
|
|
if (!result.isEmpty())
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fall back to ro.product.cpu.abi, ro.product.cpu.abi2 ...
|
2013-11-15 16:45:55 +01:00
|
|
|
for (int i = 1; i < 6; ++i) {
|
2013-05-03 15:10:21 +02:00
|
|
|
QStringList arguments = AndroidDeviceInfo::adbSelector(device);
|
|
|
|
arguments << QLatin1String("shell") << QLatin1String("getprop");
|
|
|
|
if (i == 1)
|
|
|
|
arguments << QLatin1String("ro.product.cpu.abi");
|
|
|
|
else
|
|
|
|
arguments << QString::fromLatin1("ro.product.cpu.abi%1").arg(i);
|
|
|
|
|
2016-04-29 16:52:58 +02:00
|
|
|
SynchronousProcess abiProc;
|
|
|
|
abiProc.setTimeoutS(10);
|
2021-05-17 12:02:42 +02:00
|
|
|
abiProc.setCommand({adbToolPath, arguments});
|
|
|
|
abiProc.runBlocking();
|
2021-05-12 14:25:50 +02:00
|
|
|
if (abiProc.result() != QtcProcess::Finished)
|
2013-05-03 15:10:21 +02:00
|
|
|
return result;
|
2016-04-29 16:52:58 +02:00
|
|
|
|
2021-05-12 14:25:50 +02:00
|
|
|
QString abi = abiProc.allOutput().trimmed();
|
2013-05-03 15:10:21 +02:00
|
|
|
if (abi.isEmpty())
|
|
|
|
break;
|
|
|
|
result << abi;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-02-24 11:19:02 +02:00
|
|
|
bool AndroidConfig::isValidNdk(const QString &ndkLocation) const
|
|
|
|
{
|
|
|
|
auto ndkPath = Utils::FilePath::fromUserInput(ndkLocation);
|
|
|
|
const Utils::FilePath ndkPlatformsDir = ndkPath.pathAppended("platforms");
|
|
|
|
|
|
|
|
return ndkPath.exists() && ndkPath.pathAppended("toolchains").exists()
|
|
|
|
&& ndkPlatformsDir.exists() && !ndkPlatformsDir.toString().contains(' ')
|
|
|
|
&& !ndkVersion(ndkPath).isNull();
|
|
|
|
}
|
|
|
|
|
2020-02-16 20:46:23 +02:00
|
|
|
QString AndroidConfig::bestNdkPlatformMatch(int target, const BaseQtVersion *qtVersion) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2018-06-18 13:17:49 +02:00
|
|
|
target = std::max(AndroidManager::apiLevelRange().first, target);
|
2020-02-16 20:46:23 +02:00
|
|
|
foreach (int apiLevel, availableNdkPlatforms(qtVersion)) {
|
2012-04-18 20:30:57 +03:00
|
|
|
if (apiLevel <= target)
|
|
|
|
return QString::fromLatin1("android-%1").arg(apiLevel);
|
|
|
|
}
|
2018-06-18 13:17:49 +02:00
|
|
|
return QString("android-%1").arg(AndroidManager::apiLevelRange().first);
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath AndroidConfig::sdkLocation() const
|
2013-05-16 15:49:24 +02:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
return m_sdkLocation;
|
|
|
|
}
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
void AndroidConfig::setSdkLocation(const FilePath &sdkLocation)
|
2013-12-16 20:19:07 +01:00
|
|
|
{
|
|
|
|
m_sdkLocation = sdkLocation;
|
|
|
|
}
|
|
|
|
|
2017-03-30 14:47:34 +02:00
|
|
|
QVersionNumber AndroidConfig::sdkToolsVersion() const
|
|
|
|
{
|
|
|
|
QVersionNumber version;
|
|
|
|
if (m_sdkLocation.exists()) {
|
2020-04-16 16:44:06 +03:00
|
|
|
FilePath sdkToolsPropertiesPath;
|
|
|
|
if (isCmdlineSdkToolsInstalled())
|
2020-04-20 08:40:54 +02:00
|
|
|
sdkToolsPropertiesPath = m_sdkLocation / "cmdline-tools/latest/source.properties";
|
2020-04-16 16:44:06 +03:00
|
|
|
else
|
2020-04-20 08:40:54 +02:00
|
|
|
sdkToolsPropertiesPath = m_sdkLocation / "tools/source.properties";
|
2017-03-30 14:47:34 +02:00
|
|
|
QSettings settings(sdkToolsPropertiesPath.toString(), QSettings::IniFormat);
|
|
|
|
auto versionStr = settings.value(sdkToolsVersionKey).toString();
|
|
|
|
version = QVersionNumber::fromString(versionStr);
|
|
|
|
}
|
|
|
|
return version;
|
|
|
|
}
|
|
|
|
|
2017-09-04 14:54:50 +02:00
|
|
|
QVersionNumber AndroidConfig::buildToolsVersion() const
|
|
|
|
{
|
2019-12-23 16:13:23 +02:00
|
|
|
//TODO: return version according to qt version
|
2017-09-04 14:54:50 +02:00
|
|
|
QVersionNumber maxVersion;
|
2019-05-17 13:20:41 +02:00
|
|
|
QDir buildToolsDir(m_sdkLocation.pathAppended("build-tools").toString());
|
2020-05-12 13:01:44 +02:00
|
|
|
for (const QFileInfo &file: buildToolsDir.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot))
|
2017-09-04 14:54:50 +02:00
|
|
|
maxVersion = qMax(maxVersion, QVersionNumber::fromString(file.fileName()));
|
|
|
|
return maxVersion;
|
|
|
|
}
|
|
|
|
|
2017-09-27 15:26:59 +02:00
|
|
|
QStringList AndroidConfig::sdkManagerToolArgs() const
|
|
|
|
{
|
|
|
|
return m_sdkManagerToolArgs;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::setSdkManagerToolArgs(const QStringList &args)
|
|
|
|
{
|
|
|
|
m_sdkManagerToolArgs = args;
|
|
|
|
}
|
|
|
|
|
2020-02-16 20:46:23 +02:00
|
|
|
FilePath AndroidConfig::ndkLocation(const BaseQtVersion *qtVersion) const
|
2013-12-16 20:19:07 +01:00
|
|
|
{
|
2020-02-16 20:46:23 +02:00
|
|
|
return sdkLocation().pathAppended(ndkPathFromQtVersion(*qtVersion));
|
2013-12-16 20:19:07 +01:00
|
|
|
}
|
|
|
|
|
2020-02-16 20:46:23 +02:00
|
|
|
QVersionNumber AndroidConfig::ndkVersion(const BaseQtVersion *qtVersion) const
|
|
|
|
{
|
|
|
|
return ndkVersion(ndkLocation(qtVersion));
|
|
|
|
}
|
|
|
|
|
|
|
|
QVersionNumber AndroidConfig::ndkVersion(const FilePath &ndkPath) const
|
2017-05-05 12:26:23 +02:00
|
|
|
{
|
|
|
|
QVersionNumber version;
|
2020-02-16 20:46:23 +02:00
|
|
|
if (!ndkPath.exists()) {
|
2018-10-22 16:34:31 +02:00
|
|
|
qCDebug(avdConfigLog) << "Cannot find ndk version. Check NDK path."
|
2020-02-16 20:46:23 +02:00
|
|
|
<< ndkPath.toString();
|
2017-05-05 12:26:23 +02:00
|
|
|
return version;
|
|
|
|
}
|
|
|
|
|
2020-02-16 20:46:23 +02:00
|
|
|
const FilePath ndkPropertiesPath = ndkPath.pathAppended("source.properties");
|
2017-05-05 12:26:23 +02:00
|
|
|
if (ndkPropertiesPath.exists()) {
|
|
|
|
// source.properties files exists in NDK version > 11
|
|
|
|
QSettings settings(ndkPropertiesPath.toString(), QSettings::IniFormat);
|
|
|
|
auto versionStr = settings.value(ndkRevisionKey).toString();
|
|
|
|
version = QVersionNumber::fromString(versionStr);
|
|
|
|
} else {
|
|
|
|
// No source.properties. There should be a file named RELEASE.TXT
|
2020-02-16 20:46:23 +02:00
|
|
|
const FilePath ndkReleaseTxtPath = ndkPath.pathAppended("RELEASE.TXT");
|
2017-05-05 12:26:23 +02:00
|
|
|
Utils::FileReader reader;
|
|
|
|
QString errorString;
|
2021-05-18 09:47:07 +02:00
|
|
|
if (reader.fetch(ndkReleaseTxtPath, &errorString)) {
|
2017-05-05 12:26:23 +02:00
|
|
|
// RELEASE.TXT contains the ndk version in either of the following formats:
|
|
|
|
// r6a
|
|
|
|
// r10e (64 bit)
|
|
|
|
QString content = QString::fromUtf8(reader.data());
|
|
|
|
QRegularExpression re("(r)(?<major>[0-9]{1,2})(?<minor>[a-z]{1,1})");
|
|
|
|
QRegularExpressionMatch match = re.match(content);
|
|
|
|
if (match.hasMatch()) {
|
|
|
|
QString major = match.captured("major");
|
|
|
|
QString minor = match.captured("minor");
|
|
|
|
// Minor version: a = 0, b = 1, c = 2 and so on.
|
|
|
|
// Int equivalent = minorVersionChar - 'a'. i.e. minorVersionChar - 97.
|
|
|
|
version = QVersionNumber::fromString(QString("%1.%2.0").arg(major)
|
|
|
|
.arg((int)minor[0].toLatin1() - 97));
|
|
|
|
} else {
|
2018-10-22 16:34:31 +02:00
|
|
|
qCDebug(avdConfigLog) << "Cannot find ndk version. Cannot parse RELEASE.TXT."
|
2017-05-05 12:26:23 +02:00
|
|
|
<< content;
|
|
|
|
}
|
|
|
|
} else {
|
2018-10-22 16:34:31 +02:00
|
|
|
qCDebug(avdConfigLog) << "Cannot find ndk version." << errorString;
|
2017-05-05 12:26:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return version;
|
|
|
|
}
|
|
|
|
|
2019-12-23 16:13:23 +02:00
|
|
|
QStringList AndroidConfig::allEssentials() const
|
|
|
|
{
|
|
|
|
QList<BaseQtVersion *> installedVersions = QtVersionManager::versions(
|
|
|
|
[](const BaseQtVersion *v) {
|
|
|
|
return v->targetDeviceTypes().contains(Android::Constants::ANDROID_DEVICE_TYPE);
|
|
|
|
});
|
|
|
|
|
|
|
|
QStringList allPackages(defaultEssentials());
|
|
|
|
for (const BaseQtVersion *version : installedVersions)
|
|
|
|
allPackages.append(essentialsFromQtVersion(*version));
|
|
|
|
allPackages.removeDuplicates();
|
|
|
|
|
|
|
|
return allPackages;
|
|
|
|
}
|
|
|
|
|
2020-07-01 23:42:34 +03:00
|
|
|
bool AndroidConfig::allEssentialsInstalled(AndroidSdkManager *sdkManager)
|
2020-05-18 18:58:32 +03:00
|
|
|
{
|
|
|
|
QStringList essentialPkgs(allEssentials());
|
2020-07-01 23:42:34 +03:00
|
|
|
for (const AndroidSdkPackage *pkg : sdkManager->installedSdkPackages()) {
|
2020-05-18 18:58:32 +03:00
|
|
|
if (essentialPkgs.contains(pkg->sdkStylePath()))
|
|
|
|
essentialPkgs.removeOne(pkg->sdkStylePath());
|
|
|
|
if (essentialPkgs.isEmpty())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return essentialPkgs.isEmpty() ? true : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AndroidConfig::sdkToolsOk() const
|
|
|
|
{
|
|
|
|
bool exists = sdkLocation().exists();
|
|
|
|
bool writable = sdkLocation().isWritablePath();
|
|
|
|
bool sdkToolsExist = !sdkToolsVersion().isNull();
|
|
|
|
return exists && writable && sdkToolsExist;
|
|
|
|
}
|
|
|
|
|
2019-12-23 16:13:23 +02:00
|
|
|
QStringList AndroidConfig::essentialsFromQtVersion(const BaseQtVersion &version) const
|
|
|
|
{
|
|
|
|
QtVersionNumber qtVersion = version.qtVersion();
|
|
|
|
for (const SdkForQtVersions &item : m_specificQtVersions)
|
|
|
|
if (item.containsVersion(qtVersion))
|
|
|
|
return item.essentialPackages;
|
|
|
|
|
|
|
|
return m_defaultSdkDepends.essentialPackages;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString AndroidConfig::ndkPathFromQtVersion(const BaseQtVersion &version) const
|
|
|
|
{
|
2020-02-16 20:46:23 +02:00
|
|
|
QtVersionNumber qtVersion(version.qtVersionString());
|
2019-12-23 16:13:23 +02:00
|
|
|
for (const SdkForQtVersions &item : m_specificQtVersions)
|
|
|
|
if (item.containsVersion(qtVersion))
|
|
|
|
return item.ndkPath;
|
|
|
|
|
|
|
|
return m_defaultSdkDepends.ndkPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList AndroidConfig::defaultEssentials() const
|
|
|
|
{
|
|
|
|
return m_defaultSdkDepends.essentialPackages + m_commonEssentialPkgs;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SdkForQtVersions::containsVersion(const QtVersionNumber &qtVersion) const
|
|
|
|
{
|
|
|
|
return versions.contains(qtVersion)
|
|
|
|
|| versions.contains(QtVersionNumber(qtVersion.majorVersion, qtVersion.minorVersion));
|
|
|
|
}
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath AndroidConfig::openJDKLocation() const
|
2013-12-16 20:19:07 +01:00
|
|
|
{
|
|
|
|
return m_openJDKLocation;
|
|
|
|
}
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
void AndroidConfig::setOpenJDKLocation(const FilePath &openJDKLocation)
|
2013-12-16 20:19:07 +01:00
|
|
|
{
|
|
|
|
m_openJDKLocation = openJDKLocation;
|
|
|
|
}
|
|
|
|
|
2020-02-16 20:46:23 +02:00
|
|
|
QString AndroidConfig::toolchainHost(const BaseQtVersion *qtVersion) const
|
2013-12-16 20:19:07 +01:00
|
|
|
{
|
2020-02-16 20:46:23 +02:00
|
|
|
return toolchainHostFromNdk(ndkLocation(qtVersion));
|
|
|
|
}
|
|
|
|
|
|
|
|
QString AndroidConfig::toolchainHostFromNdk(const FilePath &ndkPath) const
|
|
|
|
{
|
|
|
|
// detect toolchain host
|
|
|
|
QString toolchainHost;
|
|
|
|
QStringList hostPatterns;
|
|
|
|
switch (HostOsInfo::hostOs()) {
|
|
|
|
case OsTypeLinux:
|
|
|
|
hostPatterns << QLatin1String("linux*");
|
|
|
|
break;
|
|
|
|
case OsTypeWindows:
|
|
|
|
hostPatterns << QLatin1String("windows*");
|
|
|
|
break;
|
|
|
|
case OsTypeMac:
|
|
|
|
hostPatterns << QLatin1String("darwin*");
|
|
|
|
break;
|
|
|
|
default: /* unknown host */
|
|
|
|
return toolchainHost;
|
|
|
|
}
|
|
|
|
|
|
|
|
QDirIterator jt(ndkPath.pathAppended("prebuilt").toString(),
|
|
|
|
hostPatterns,
|
|
|
|
QDir::Dirs);
|
|
|
|
if (jt.hasNext()) {
|
|
|
|
jt.next();
|
|
|
|
toolchainHost = jt.fileName();
|
|
|
|
}
|
|
|
|
|
|
|
|
return toolchainHost;
|
2013-12-16 20:19:07 +01:00
|
|
|
}
|
|
|
|
|
2020-10-06 18:49:15 +02:00
|
|
|
QStringList AndroidConfig::emulatorArgs() const
|
2013-12-16 20:19:07 +01:00
|
|
|
{
|
2020-10-06 18:49:15 +02:00
|
|
|
return m_emulatorArgs;
|
2013-12-16 20:19:07 +01:00
|
|
|
}
|
|
|
|
|
2020-10-06 18:49:15 +02:00
|
|
|
void AndroidConfig::setEmulatorArgs(const QStringList &args)
|
2013-12-16 20:19:07 +01:00
|
|
|
{
|
2020-10-06 18:49:15 +02:00
|
|
|
m_emulatorArgs = args;
|
2013-12-16 20:19:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool AndroidConfig::automaticKitCreation() const
|
|
|
|
{
|
|
|
|
return m_automaticKitCreation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::setAutomaticKitCreation(bool b)
|
|
|
|
{
|
|
|
|
m_automaticKitCreation = b;
|
|
|
|
}
|
|
|
|
|
2020-05-18 18:58:32 +03:00
|
|
|
FilePath AndroidConfig::defaultSdkPath()
|
|
|
|
{
|
|
|
|
QString sdkFromEnvVar = QString::fromLocal8Bit(getenv("ANDROID_SDK_ROOT"));
|
|
|
|
if (!sdkFromEnvVar.isEmpty())
|
|
|
|
return Utils::FilePath::fromString(sdkFromEnvVar);
|
|
|
|
|
|
|
|
// Set default path of SDK as used by Android Studio
|
|
|
|
if (Utils::HostOsInfo::isMacHost()) {
|
|
|
|
return Utils::FilePath::fromString(
|
2020-12-14 10:20:55 +02:00
|
|
|
QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/Library/Android/sdk");
|
2020-05-18 18:58:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Utils::HostOsInfo::isWindowsHost()) {
|
|
|
|
return Utils::FilePath::fromString(
|
2020-07-01 09:01:26 +02:00
|
|
|
QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/Android/Sdk");
|
2020-05-18 18:58:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return Utils::FilePath::fromString(
|
|
|
|
QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/Android/Sdk");
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
///////////////////////////////////
|
|
|
|
// AndroidConfigurations
|
|
|
|
///////////////////////////////////
|
|
|
|
void AndroidConfigurations::setConfig(const AndroidConfig &devConfigs)
|
|
|
|
{
|
2019-11-18 16:57:44 +01:00
|
|
|
emit m_instance->aboutToUpdate();
|
2013-12-16 20:19:07 +01:00
|
|
|
m_instance->m_config = devConfigs;
|
|
|
|
|
|
|
|
m_instance->save();
|
2020-11-18 22:42:51 +01:00
|
|
|
updateAndroidDevice();
|
|
|
|
registerNewToolChains();
|
|
|
|
updateAutomaticKitList();
|
|
|
|
removeOldToolChains();
|
2013-12-16 20:19:07 +01:00
|
|
|
emit m_instance->updated();
|
|
|
|
}
|
|
|
|
|
2015-02-03 23:50:37 +02:00
|
|
|
AndroidDeviceInfo AndroidConfigurations::showDeviceDialog(Project *project,
|
2019-08-26 14:19:07 +03:00
|
|
|
int apiLevel, const QStringList &abis)
|
2013-12-16 20:19:07 +01:00
|
|
|
{
|
2019-08-26 14:19:07 +03:00
|
|
|
QString serialNumber;
|
|
|
|
for (const QString &abi : abis) {
|
|
|
|
serialNumber = defaultDevice(project, abi);
|
|
|
|
if (!serialNumber.isEmpty())
|
|
|
|
break;
|
|
|
|
}
|
2020-06-02 09:10:40 +02:00
|
|
|
AndroidDeviceDialog dialog(apiLevel, abis, serialNumber, Core::ICore::dialogParent());
|
2015-12-04 10:03:45 +02:00
|
|
|
AndroidDeviceInfo info = dialog.device();
|
|
|
|
if (dialog.saveDeviceSelection() && info.isValid()) {
|
|
|
|
const QString serialNumber = info.type == AndroidDeviceInfo::Hardware ?
|
|
|
|
info.serialNumber : info.avdname;
|
|
|
|
if (!serialNumber.isEmpty())
|
2019-08-26 14:19:07 +03:00
|
|
|
AndroidConfigurations::setDefaultDevice(project, AndroidManager::devicePreferredAbi(info.cpuAbi, abis), serialNumber);
|
2013-12-16 20:19:07 +01:00
|
|
|
}
|
2015-12-04 10:03:45 +02:00
|
|
|
return info;
|
2013-12-16 20:19:07 +01:00
|
|
|
}
|
|
|
|
|
2015-02-03 23:50:37 +02:00
|
|
|
void AndroidConfigurations::clearDefaultDevices(Project *project)
|
2013-12-16 20:19:07 +01:00
|
|
|
{
|
|
|
|
if (m_instance->m_defaultDeviceForAbi.contains(project))
|
|
|
|
m_instance->m_defaultDeviceForAbi.remove(project);
|
|
|
|
}
|
|
|
|
|
2015-02-03 23:50:37 +02:00
|
|
|
void AndroidConfigurations::setDefaultDevice(Project *project, const QString &abi, const QString &serialNumber)
|
2013-12-16 20:19:07 +01:00
|
|
|
{
|
|
|
|
m_instance->m_defaultDeviceForAbi[project][abi] = serialNumber;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString AndroidConfigurations::defaultDevice(Project *project, const QString &abi)
|
|
|
|
{
|
|
|
|
if (!m_instance->m_defaultDeviceForAbi.contains(project))
|
|
|
|
return QString();
|
|
|
|
const QMap<QString, QString> &map = m_instance->m_defaultDeviceForAbi.value(project);
|
|
|
|
if (!map.contains(abi))
|
|
|
|
return QString();
|
|
|
|
return map.value(abi);
|
2013-05-16 15:49:24 +02:00
|
|
|
}
|
|
|
|
|
2016-10-24 15:53:37 +02:00
|
|
|
static bool matchToolChain(const ToolChain *atc, const ToolChain *btc)
|
2013-02-14 15:51:59 +01:00
|
|
|
{
|
2015-04-22 17:42:23 +02:00
|
|
|
if (atc == btc)
|
|
|
|
return true;
|
2016-10-24 15:53:37 +02:00
|
|
|
|
|
|
|
if (!atc || !btc)
|
2015-04-22 17:42:23 +02:00
|
|
|
return false;
|
2016-10-24 15:53:37 +02:00
|
|
|
|
2019-06-14 11:12:19 +02:00
|
|
|
if (atc->typeId() != Constants::ANDROID_TOOLCHAIN_TYPEID || btc->typeId() != Constants::ANDROID_TOOLCHAIN_TYPEID)
|
2015-04-22 17:42:23 +02:00
|
|
|
return false;
|
2016-10-24 15:53:37 +02:00
|
|
|
|
|
|
|
auto aatc = static_cast<const AndroidToolChain *>(atc);
|
|
|
|
auto abtc = static_cast<const AndroidToolChain *>(btc);
|
2018-10-25 18:12:43 +02:00
|
|
|
return aatc->targetAbi() == abtc->targetAbi();
|
2016-10-24 15:53:37 +02:00
|
|
|
}
|
|
|
|
|
2015-04-22 17:42:23 +02:00
|
|
|
void AndroidConfigurations::registerNewToolChains()
|
2014-03-11 13:05:36 +01:00
|
|
|
{
|
2015-10-15 16:01:40 +02:00
|
|
|
const QList<ToolChain *> existingAndroidToolChains
|
2017-01-11 16:12:32 +01:00
|
|
|
= ToolChainManager::toolChains(Utils::equal(&ToolChain::typeId,
|
2020-06-26 13:59:38 +02:00
|
|
|
Utils::Id(Constants::ANDROID_TOOLCHAIN_TYPEID)));
|
2020-02-24 11:19:02 +02:00
|
|
|
QList<ToolChain *> newToolchains = AndroidToolChainFactory::autodetectToolChains(
|
|
|
|
existingAndroidToolChains);
|
|
|
|
|
2015-10-15 16:01:40 +02:00
|
|
|
foreach (ToolChain *tc, newToolchains)
|
2017-01-11 16:14:31 +01:00
|
|
|
ToolChainManager::registerToolChain(tc);
|
2020-02-24 11:19:02 +02:00
|
|
|
|
|
|
|
registerCustomToolChainsAndDebuggers();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfigurations::registerCustomToolChainsAndDebuggers()
|
|
|
|
{
|
|
|
|
const QList<ToolChain *> existingAndroidToolChains = ToolChainManager::toolChains(
|
2020-06-26 13:59:38 +02:00
|
|
|
Utils::equal(&ToolChain::typeId, Utils::Id(Constants::ANDROID_TOOLCHAIN_TYPEID)));
|
2020-02-24 11:19:02 +02:00
|
|
|
QList<FilePath> customNdks = Utils::transform(currentConfig().getCustomNdkList(),
|
|
|
|
FilePath::fromString);
|
|
|
|
QList<ToolChain *> customToolchains
|
|
|
|
= AndroidToolChainFactory::autodetectToolChainsFromNdks(existingAndroidToolChains,
|
|
|
|
customNdks,
|
|
|
|
true);
|
|
|
|
for (ToolChain *tc : customToolchains) {
|
|
|
|
ToolChainManager::registerToolChain(tc);
|
|
|
|
|
|
|
|
const FilePath ndk = static_cast<AndroidToolChain *>(tc)->ndkLocation();
|
|
|
|
const FilePath command = AndroidConfigurations::currentConfig()
|
|
|
|
.gdbPathFromNdk(tc->targetAbi(), ndk);
|
|
|
|
|
|
|
|
const Debugger::DebuggerItem *existing = Debugger::DebuggerItemManager::findByCommand(
|
|
|
|
command);
|
|
|
|
QString abiStr
|
|
|
|
= static_cast<AndroidToolChain *>(tc)->platformLinkerFlags().at(1).split('-').first();
|
|
|
|
Abi abi = Abi::abiFromTargetTriplet(abiStr);
|
|
|
|
if (existing && existing->abis().contains(abi))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Debugger::DebuggerItem debugger;
|
|
|
|
debugger.setCommand(command);
|
|
|
|
debugger.setEngineType(Debugger::GdbEngineType);
|
|
|
|
debugger.setUnexpandedDisplayName(
|
|
|
|
AndroidConfigurations::tr("Custom Android Debugger (%1, NDK %2)")
|
|
|
|
.arg(abiStr,
|
|
|
|
AndroidConfigurations::currentConfig().ndkVersion(ndk).toString()));
|
|
|
|
debugger.setAutoDetected(true);
|
|
|
|
debugger.setAbi(abi);
|
|
|
|
debugger.reinitializeFromFile();
|
|
|
|
|
|
|
|
Debugger::DebuggerItemManager::registerDebugger(debugger);
|
|
|
|
}
|
2015-04-22 17:42:23 +02:00
|
|
|
}
|
2014-03-11 13:05:36 +01:00
|
|
|
|
2015-04-22 17:42:23 +02:00
|
|
|
void AndroidConfigurations::removeOldToolChains()
|
|
|
|
{
|
2020-06-26 13:59:38 +02:00
|
|
|
foreach (ToolChain *tc, ToolChainManager::toolChains(Utils::equal(&ToolChain::typeId, Utils::Id(Constants::ANDROID_TOOLCHAIN_TYPEID)))) {
|
2017-01-11 16:12:32 +01:00
|
|
|
if (!tc->isValid())
|
|
|
|
ToolChainManager::deregisterToolChain(tc);
|
2014-03-11 13:05:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-25 00:19:28 +02:00
|
|
|
void AndroidConfigurations::removeUnusedDebuggers()
|
2018-11-28 14:30:42 +01:00
|
|
|
{
|
2020-02-25 00:19:28 +02:00
|
|
|
QList<FilePath> uniqueNdks;
|
|
|
|
const QList<QtSupport::BaseQtVersion *> qtVersions
|
|
|
|
= QtSupport::QtVersionManager::versions([](const QtSupport::BaseQtVersion *v) {
|
|
|
|
return v->type() == Constants::ANDROIDQT;
|
|
|
|
});
|
|
|
|
|
|
|
|
for (const QtSupport::BaseQtVersion *qt : qtVersions) {
|
|
|
|
FilePath ndkLocation = currentConfig().ndkLocation(qt);
|
|
|
|
if (!uniqueNdks.contains(ndkLocation))
|
|
|
|
uniqueNdks.append(ndkLocation);
|
|
|
|
}
|
|
|
|
|
2020-02-24 11:19:02 +02:00
|
|
|
uniqueNdks.append(Utils::transform(currentConfig().getCustomNdkList(), FilePath::fromString));
|
|
|
|
|
2020-02-25 00:19:28 +02:00
|
|
|
const QList<Debugger::DebuggerItem> allDebuggers = Debugger::DebuggerItemManager::debuggers();
|
|
|
|
for (const Debugger::DebuggerItem &debugger : allDebuggers) {
|
|
|
|
if (!debugger.displayName().contains("Android"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
bool isChildOfNdk = false;
|
|
|
|
for (const FilePath &path : uniqueNdks) {
|
|
|
|
if (debugger.command().isChildOf(path)) {
|
|
|
|
isChildOfNdk = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isChildOfNdk && debugger.isAutoDetected())
|
|
|
|
Debugger::DebuggerItemManager::deregisterDebugger(debugger.id());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-02 09:32:27 +03:00
|
|
|
static bool containsAllAbis(const QStringList &abis)
|
|
|
|
{
|
2020-07-23 15:48:56 +02:00
|
|
|
QStringList supportedAbis{
|
|
|
|
ProjectExplorer::Constants::ANDROID_ABI_ARMEABI_V7A,
|
|
|
|
ProjectExplorer::Constants::ANDROID_ABI_ARM64_V8A,
|
|
|
|
ProjectExplorer::Constants::ANDROID_ABI_X86,
|
|
|
|
ProjectExplorer::Constants::ANDROID_ABI_X86_64,
|
|
|
|
};
|
2020-06-02 09:32:27 +03:00
|
|
|
for (const QString &abi : abis)
|
|
|
|
if (supportedAbis.contains(abi))
|
|
|
|
supportedAbis.removeOne(abi);
|
|
|
|
|
|
|
|
return supportedAbis.isEmpty();
|
|
|
|
}
|
|
|
|
|
2020-02-25 00:19:28 +02:00
|
|
|
static QVariant findOrRegisterDebugger(ToolChain *tc,
|
|
|
|
const QStringList &abisList,
|
|
|
|
const BaseQtVersion *qtVersion)
|
|
|
|
{
|
|
|
|
const FilePath command = AndroidConfigurations::currentConfig().gdbPath(tc->targetAbi(),
|
|
|
|
qtVersion);
|
2018-11-28 14:30:42 +01:00
|
|
|
// check if the debugger is already registered, but ignoring the display name
|
|
|
|
const Debugger::DebuggerItem *existing = Debugger::DebuggerItemManager::findByCommand(command);
|
2020-02-25 00:19:28 +02:00
|
|
|
|
|
|
|
QList<Abi> abis = Utils::transform(abisList, Abi::abiFromTargetTriplet);
|
|
|
|
|
|
|
|
auto containsAbis = [abis](const Abis &secondAbis) {
|
|
|
|
for (const Abi &abi : secondAbis) {
|
|
|
|
if (!abis.contains(abi))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2018-11-28 14:30:42 +01:00
|
|
|
if (existing && existing->engineType() == Debugger::GdbEngineType && existing->isAutoDetected()
|
2020-02-25 00:19:28 +02:00
|
|
|
&& containsAbis(existing->abis())) {
|
|
|
|
// update debugger info with new
|
2018-11-28 14:30:42 +01:00
|
|
|
return existing->id();
|
2020-02-25 00:19:28 +02:00
|
|
|
}
|
|
|
|
|
2018-11-28 14:30:42 +01:00
|
|
|
// debugger not found, register a new one
|
|
|
|
Debugger::DebuggerItem debugger;
|
2019-06-11 19:06:27 +02:00
|
|
|
debugger.setCommand(command);
|
2018-11-28 14:30:42 +01:00
|
|
|
debugger.setEngineType(Debugger::GdbEngineType);
|
|
|
|
debugger.setUnexpandedDisplayName(
|
2020-02-25 00:19:28 +02:00
|
|
|
AndroidConfigurations::tr("Android Debugger (%1, NDK %2)")
|
2020-06-02 09:32:27 +03:00
|
|
|
.arg(containsAllAbis(abisList) ? "Multi-Abi" : abisList.join(","))
|
|
|
|
.arg(AndroidConfigurations::currentConfig().ndkVersion(qtVersion).toString()));
|
2018-11-28 14:30:42 +01:00
|
|
|
debugger.setAutoDetected(true);
|
2020-02-25 00:19:28 +02:00
|
|
|
debugger.setAbis(abis.toVector());
|
2018-11-28 14:30:42 +01:00
|
|
|
debugger.reinitializeFromFile();
|
|
|
|
return Debugger::DebuggerItemManager::registerDebugger(debugger);
|
|
|
|
}
|
|
|
|
|
2013-02-14 15:51:59 +01:00
|
|
|
void AndroidConfigurations::updateAutomaticKitList()
|
|
|
|
{
|
2020-04-30 16:41:39 +02:00
|
|
|
for (Kit *k : KitManager::kits()) {
|
|
|
|
if (DeviceTypeKitAspect::deviceTypeId(k) == Constants::ANDROID_DEVICE_TYPE) {
|
|
|
|
if (k->value(Constants::ANDROID_KIT_NDK).isNull() || k->value(Constants::ANDROID_KIT_SDK).isNull()) {
|
|
|
|
if (BaseQtVersion *qt = QtKitAspect::qtVersion(k)) {
|
|
|
|
k->setValueSilently(Constants::ANDROID_KIT_NDK, currentConfig().ndkLocation(qt).toString());
|
|
|
|
k->setValue(Constants::ANDROID_KIT_SDK, currentConfig().sdkLocation().toString());
|
|
|
|
}
|
|
|
|
}
|
2019-04-03 18:10:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:57:51 +02:00
|
|
|
const QList<Kit *> existingKits = Utils::filtered(KitManager::kits(), [](Kit *k) {
|
2020-06-26 13:59:38 +02:00
|
|
|
Utils::Id deviceTypeId = DeviceTypeKitAspect::deviceTypeId(k);
|
2017-05-19 09:57:51 +02:00
|
|
|
if (k->isAutoDetected() && !k->isSdkProvided()
|
2020-06-26 13:59:38 +02:00
|
|
|
&& deviceTypeId == Utils::Id(Constants::ANDROID_DEVICE_TYPE)) {
|
2019-02-06 12:50:51 +01:00
|
|
|
if (!QtSupport::QtKitAspect::qtVersion(k))
|
2017-05-19 09:57:51 +02:00
|
|
|
KitManager::deregisterKit(k); // Remove autoDetected kits without Qt.
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2016-10-26 14:40:21 +02:00
|
|
|
});
|
2013-02-14 15:51:59 +01:00
|
|
|
|
2020-02-25 00:19:28 +02:00
|
|
|
removeUnusedDebuggers();
|
|
|
|
|
2016-10-26 14:40:21 +02:00
|
|
|
QHash<Abi, QList<const QtSupport::BaseQtVersion *> > qtVersionsForArch;
|
|
|
|
const QList<QtSupport::BaseQtVersion *> qtVersions
|
2017-01-12 10:37:29 +01:00
|
|
|
= QtSupport::QtVersionManager::versions([](const QtSupport::BaseQtVersion *v) {
|
2016-10-26 14:40:21 +02:00
|
|
|
return v->type() == Constants::ANDROIDQT;
|
|
|
|
});
|
|
|
|
for (const QtSupport::BaseQtVersion *qtVersion : qtVersions) {
|
2019-05-27 11:04:18 +02:00
|
|
|
const Abis qtAbis = qtVersion->qtAbis();
|
2013-02-25 09:17:43 +02:00
|
|
|
if (qtAbis.empty())
|
|
|
|
continue;
|
2014-11-18 18:37:05 +01:00
|
|
|
qtVersionsForArch[qtAbis.first()].append(qtVersion);
|
2013-02-14 15:51:59 +01:00
|
|
|
}
|
|
|
|
|
2013-08-23 09:21:18 +02:00
|
|
|
DeviceManager *dm = DeviceManager::instance();
|
2020-06-26 13:59:38 +02:00
|
|
|
IDevice::ConstPtr device = dm->find(Utils::Id(Constants::ANDROID_DEVICE_ID));
|
2013-10-30 17:02:28 +01:00
|
|
|
if (device.isNull()) {
|
|
|
|
// no device, means no sdk path
|
2016-10-26 14:40:21 +02:00
|
|
|
for (Kit *k : existingKits)
|
2013-10-30 17:02:28 +01:00
|
|
|
KitManager::deregisterKit(k);
|
|
|
|
return;
|
|
|
|
}
|
2013-02-14 15:51:59 +01:00
|
|
|
|
|
|
|
// register new kits
|
2018-10-25 18:12:43 +02:00
|
|
|
const QList<ToolChain *> toolchains = ToolChainManager::toolChains([](const ToolChain *tc) {
|
2016-10-24 15:53:37 +02:00
|
|
|
return tc->isAutoDetected()
|
|
|
|
&& tc->isValid()
|
2019-06-14 11:12:19 +02:00
|
|
|
&& tc->typeId() == Constants::ANDROID_TOOLCHAIN_TYPEID;
|
2016-10-24 15:53:37 +02:00
|
|
|
});
|
2018-10-25 18:12:43 +02:00
|
|
|
for (ToolChain *tc : toolchains) {
|
2020-06-26 13:59:38 +02:00
|
|
|
if (tc->language() != Utils::Id(ProjectExplorer::Constants::CXX_LANGUAGE_ID))
|
2013-10-10 18:04:27 +02:00
|
|
|
continue;
|
2019-03-12 11:49:39 +01:00
|
|
|
|
2017-05-18 10:37:19 +02:00
|
|
|
for (const QtSupport::BaseQtVersion *qt : qtVersionsForArch.value(tc->targetAbi())) {
|
2020-02-16 20:46:23 +02:00
|
|
|
FilePath tcNdk = static_cast<const AndroidToolChain *>(tc)->ndkLocation();
|
|
|
|
if (tcNdk != currentConfig().ndkLocation(qt))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const QList<ToolChain *> allLanguages
|
|
|
|
= Utils::filtered(toolchains, [tc, tcNdk](ToolChain *otherTc) {
|
|
|
|
FilePath otherNdk = static_cast<const AndroidToolChain *>(otherTc)->ndkLocation();
|
|
|
|
return tc->targetAbi() == otherTc->targetAbi() && tcNdk == otherNdk;
|
|
|
|
});
|
|
|
|
|
2020-06-26 13:59:38 +02:00
|
|
|
QHash<Utils::Id, ToolChain *> toolChainForLanguage;
|
2020-02-16 20:46:23 +02:00
|
|
|
for (ToolChain *tc : allLanguages)
|
|
|
|
toolChainForLanguage[tc->language()] = tc;
|
|
|
|
|
2019-03-12 11:49:39 +01:00
|
|
|
Kit *existingKit = Utils::findOrDefault(existingKits, [&](const Kit *b) {
|
|
|
|
if (qt != QtSupport::QtKitAspect::qtVersion(b))
|
2019-03-11 16:59:16 +01:00
|
|
|
return false;
|
2019-03-12 11:49:39 +01:00
|
|
|
return matchToolChain(toolChainForLanguage[ProjectExplorer::Constants::CXX_LANGUAGE_ID],
|
2020-02-18 18:25:26 +01:00
|
|
|
ToolChainKitAspect::cxxToolChain(b))
|
2019-03-12 11:49:39 +01:00
|
|
|
&& matchToolChain(toolChainForLanguage[ProjectExplorer::Constants::C_LANGUAGE_ID],
|
2020-02-18 18:25:26 +01:00
|
|
|
ToolChainKitAspect::cToolChain(b));
|
2019-03-12 11:49:39 +01:00
|
|
|
});
|
2019-03-12 14:07:43 +01:00
|
|
|
|
|
|
|
const auto initializeKit = [allLanguages, device, tc, qt](Kit *k) {
|
|
|
|
k->setAutoDetected(true);
|
|
|
|
k->setAutoDetectionSource("AndroidConfiguration");
|
2020-06-26 13:59:38 +02:00
|
|
|
DeviceTypeKitAspect::setDeviceTypeId(k, Utils::Id(Constants::ANDROID_DEVICE_TYPE));
|
2019-03-12 14:07:43 +01:00
|
|
|
for (ToolChain *tc : allLanguages)
|
|
|
|
ToolChainKitAspect::setToolChain(k, tc);
|
|
|
|
QtSupport::QtKitAspect::setQtVersion(k, qt);
|
|
|
|
DeviceKitAspect::setDevice(k, device);
|
2020-02-25 00:19:28 +02:00
|
|
|
QStringList abis = static_cast<const AndroidQtVersion *>(qt)->androidAbis();
|
|
|
|
Debugger::DebuggerKitAspect::setDebugger(k, findOrRegisterDebugger(tc, abis, QtKitAspect::qtVersion(k)));
|
2020-12-07 18:08:32 +02:00
|
|
|
|
|
|
|
k->setSticky(ToolChainKitAspect::id(), true);
|
|
|
|
k->setSticky(QtSupport::QtKitAspect::id(), true);
|
|
|
|
k->setSticky(DeviceKitAspect::id(), true);
|
|
|
|
k->setSticky(DeviceTypeKitAspect::id(), true);
|
2020-07-02 14:47:43 +03:00
|
|
|
|
|
|
|
QString versionStr = QLatin1String("Qt %{Qt:Version}");
|
|
|
|
if (!qt->isAutodetected())
|
2020-07-08 11:01:16 +02:00
|
|
|
versionStr = QString("%1").arg(qt->displayName());
|
2020-07-02 14:47:43 +03:00
|
|
|
k->setUnexpandedDisplayName(tr("Android %1 Clang %2")
|
|
|
|
.arg(versionStr)
|
2020-06-02 09:32:27 +03:00
|
|
|
.arg(containsAllAbis(abis) ? "Multi-Abi" : abis.join(",")));
|
2020-02-16 20:46:23 +02:00
|
|
|
k->setValueSilently(Constants::ANDROID_KIT_NDK, currentConfig().ndkLocation(qt).toString());
|
2019-04-03 18:10:35 +02:00
|
|
|
k->setValueSilently(Constants::ANDROID_KIT_SDK, currentConfig().sdkLocation().toString());
|
2019-03-12 14:07:43 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
if (existingKit)
|
|
|
|
initializeKit(existingKit); // Update the existing kit with new data.
|
|
|
|
else
|
|
|
|
KitManager::registerKit(initializeKit);
|
2013-08-28 13:34:24 +02:00
|
|
|
}
|
|
|
|
}
|
2013-02-14 15:51:59 +01:00
|
|
|
}
|
|
|
|
|
2014-10-31 16:09:34 +01:00
|
|
|
bool AndroidConfigurations::force32bitEmulator()
|
|
|
|
{
|
|
|
|
return m_instance->m_force32bit;
|
|
|
|
}
|
|
|
|
|
2021-04-30 17:50:30 +02:00
|
|
|
Environment AndroidConfigurations::toolsEnvironment(const AndroidConfig &config)
|
2017-10-10 09:58:19 +02:00
|
|
|
{
|
|
|
|
Environment env = Environment::systemEnvironment();
|
2021-04-30 17:50:30 +02:00
|
|
|
FilePath jdkLocation = config.openJDKLocation();
|
2017-10-10 09:58:19 +02:00
|
|
|
if (!jdkLocation.isEmpty()) {
|
|
|
|
env.set("JAVA_HOME", jdkLocation.toUserOutput());
|
2019-05-17 13:28:38 +02:00
|
|
|
env.prependOrSetPath(jdkLocation.pathAppended("bin").toUserOutput());
|
2017-10-10 09:58:19 +02:00
|
|
|
}
|
2021-04-30 17:50:30 +02:00
|
|
|
return env;
|
2017-10-10 09:58:19 +02:00
|
|
|
}
|
|
|
|
|
2014-03-07 13:44:20 +01:00
|
|
|
const AndroidConfig &AndroidConfigurations::currentConfig()
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
return m_instance->m_config; // ensure that m_instance is initialized
|
|
|
|
}
|
|
|
|
|
2017-08-18 08:22:34 +02:00
|
|
|
AndroidSdkManager *AndroidConfigurations::sdkManager()
|
|
|
|
{
|
|
|
|
return m_instance->m_sdkManager.get();
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
AndroidConfigurations *AndroidConfigurations::instance()
|
|
|
|
{
|
|
|
|
return m_instance;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfigurations::save()
|
|
|
|
{
|
2013-09-20 23:17:22 +02:00
|
|
|
QSettings *settings = Core::ICore::settings();
|
2012-04-18 20:30:57 +03:00
|
|
|
settings->beginGroup(SettingsGroup);
|
|
|
|
m_config.save(*settings);
|
|
|
|
settings->endGroup();
|
|
|
|
}
|
|
|
|
|
2018-01-26 14:57:01 +01:00
|
|
|
AndroidConfigurations::AndroidConfigurations()
|
|
|
|
: m_sdkManager(new AndroidSdkManager(m_config))
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
|
|
|
load();
|
2013-09-10 19:19:31 +02:00
|
|
|
|
2016-04-29 23:06:26 +02:00
|
|
|
connect(SessionManager::instance(), &SessionManager::projectRemoved,
|
|
|
|
this, &AndroidConfigurations::clearDefaultDevices);
|
2018-02-09 16:16:38 +01:00
|
|
|
connect(DeviceManager::instance(), &DeviceManager::devicesLoaded,
|
|
|
|
this, &AndroidConfigurations::updateAndroidDevice);
|
2013-12-16 20:19:07 +01:00
|
|
|
|
2014-10-31 16:09:34 +01:00
|
|
|
m_force32bit = is32BitUserSpace();
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
m_instance = this;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2018-07-25 12:19:15 +02:00
|
|
|
AndroidConfigurations::~AndroidConfigurations() = default;
|
2017-08-18 08:22:34 +02:00
|
|
|
|
2020-07-20 15:07:48 +02:00
|
|
|
static Utils::FilePath androidStudioPath()
|
|
|
|
{
|
2020-12-08 13:38:19 +01:00
|
|
|
#if defined(Q_OS_WIN)
|
|
|
|
const QLatin1String registryKey("HKEY_LOCAL_MACHINE\\SOFTWARE\\Android Studio");
|
|
|
|
const QLatin1String valueName("Path");
|
|
|
|
const QSettings settings64(registryKey, QSettings::Registry64Format);
|
|
|
|
const QSettings settings32(registryKey, QSettings::Registry32Format);
|
|
|
|
return Utils::FilePath::fromUserInput(
|
|
|
|
settings64.value(valueName, settings32.value(valueName).toString()).toString());
|
|
|
|
#endif
|
2020-07-20 15:07:48 +02:00
|
|
|
return {}; // TODO non-Windows
|
|
|
|
}
|
|
|
|
|
2020-06-26 00:33:43 +03:00
|
|
|
FilePath AndroidConfig::getJdkPath()
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2020-06-26 00:33:43 +03:00
|
|
|
FilePath jdkHome;
|
2013-04-17 11:52:16 +02:00
|
|
|
|
2020-06-26 00:33:43 +03:00
|
|
|
if (HostOsInfo::isWindowsHost()) {
|
|
|
|
QStringList allVersions;
|
|
|
|
std::unique_ptr<QSettings> settings(
|
|
|
|
new QSettings(jdk8SettingsPath, QSettings::NativeFormat));
|
|
|
|
allVersions = settings->childGroups();
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
if (allVersions.isEmpty()) {
|
|
|
|
settings.reset(new QSettings(jdk8SettingsPath, QSettings::Registry64Format));
|
|
|
|
allVersions = settings->childGroups();
|
|
|
|
}
|
|
|
|
#endif // Q_OS_WIN
|
|
|
|
|
|
|
|
// If no jdk 1.8 can be found, look for jdk versions above 1.8
|
|
|
|
// Android section would warn if sdkmanager cannot run with newer jdk versions
|
|
|
|
if (allVersions.isEmpty()) {
|
|
|
|
settings.reset(new QSettings(jdkLatestSettingsPath, QSettings::NativeFormat));
|
2017-08-08 14:27:54 +02:00
|
|
|
allVersions = settings->childGroups();
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
if (allVersions.isEmpty()) {
|
2020-06-26 00:33:43 +03:00
|
|
|
settings.reset(new QSettings(jdkLatestSettingsPath, QSettings::Registry64Format));
|
2017-08-08 14:27:54 +02:00
|
|
|
allVersions = settings->childGroups();
|
|
|
|
}
|
2018-04-25 13:24:28 +02:00
|
|
|
#endif // Q_OS_WIN
|
2020-06-26 00:33:43 +03:00
|
|
|
}
|
2018-04-25 13:24:28 +02:00
|
|
|
|
2021-02-16 20:40:12 +01:00
|
|
|
for (const QString &version : qAsConst(allVersions)) {
|
2020-06-26 00:33:43 +03:00
|
|
|
settings->beginGroup(version);
|
|
|
|
jdkHome = FilePath::fromUserInput(settings->value("JavaHome").toString());
|
|
|
|
settings->endGroup();
|
|
|
|
if (version.startsWith("1.8")) {
|
|
|
|
if (!jdkHome.exists())
|
2013-06-10 18:19:08 +02:00
|
|
|
continue;
|
2020-06-26 00:33:43 +03:00
|
|
|
break;
|
2013-06-10 18:19:08 +02:00
|
|
|
}
|
|
|
|
}
|
2020-07-20 15:07:48 +02:00
|
|
|
|
|
|
|
// Nothing found yet? Let's try finding Android Studio's jdk
|
|
|
|
if (jdkHome.isEmpty()) {
|
|
|
|
const Utils::FilePath androidStudioSdkPath = androidStudioPath();
|
|
|
|
if (!androidStudioSdkPath.isEmpty()) {
|
|
|
|
const Utils::FilePath androidStudioSdkJrePath = androidStudioSdkPath / "jre";
|
|
|
|
if (androidStudioSdkJrePath.exists())
|
|
|
|
jdkHome = androidStudioSdkJrePath;
|
|
|
|
}
|
|
|
|
}
|
2020-06-26 00:33:43 +03:00
|
|
|
} else {
|
|
|
|
QStringList args;
|
|
|
|
if (HostOsInfo::isMacHost())
|
|
|
|
args << "-c"
|
|
|
|
<< "/usr/libexec/java_home";
|
|
|
|
else
|
|
|
|
args << "-c"
|
|
|
|
<< "readlink -f $(which java)";
|
|
|
|
|
|
|
|
QProcess findJdkPathProc;
|
|
|
|
findJdkPathProc.start("sh", args);
|
|
|
|
findJdkPathProc.waitForFinished();
|
|
|
|
QByteArray jdkPath = findJdkPathProc.readAllStandardOutput().trimmed();
|
|
|
|
|
|
|
|
if (HostOsInfo::isMacHost()) {
|
|
|
|
jdkHome = FilePath::fromUtf8(jdkPath);
|
|
|
|
} else {
|
|
|
|
jdkPath.replace("bin/java", ""); // For OpenJDK 11
|
2020-07-22 10:55:17 +03:00
|
|
|
jdkPath.replace("jre", "");
|
|
|
|
jdkPath.replace("//", "/");
|
2020-06-26 00:33:43 +03:00
|
|
|
jdkHome = FilePath::fromUtf8(jdkPath);
|
|
|
|
}
|
2013-04-17 11:52:16 +02:00
|
|
|
}
|
|
|
|
|
2020-06-26 00:33:43 +03:00
|
|
|
return jdkHome;
|
|
|
|
}
|
2013-06-10 18:19:08 +02:00
|
|
|
|
2020-06-26 00:33:43 +03:00
|
|
|
void AndroidConfigurations::load()
|
|
|
|
{
|
|
|
|
QSettings *settings = Core::ICore::settings();
|
|
|
|
settings->beginGroup(SettingsGroup);
|
|
|
|
m_config.load(*settings);
|
|
|
|
settings->endGroup();
|
2013-03-27 15:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfigurations::updateAndroidDevice()
|
|
|
|
{
|
2013-08-23 09:21:18 +02:00
|
|
|
DeviceManager * const devMgr = DeviceManager::instance();
|
2014-10-24 13:15:54 +02:00
|
|
|
if (m_instance->m_config.adbToolPath().exists())
|
2019-01-14 18:01:06 +01:00
|
|
|
devMgr->addDevice(AndroidDevice::create());
|
2013-04-10 11:05:33 +02:00
|
|
|
else if (devMgr->find(Constants::ANDROID_DEVICE_ID))
|
2020-06-26 13:59:38 +02:00
|
|
|
devMgr->removeDevice(Utils::Id(Constants::ANDROID_DEVICE_ID));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2018-07-25 12:19:15 +02:00
|
|
|
AndroidConfigurations *AndroidConfigurations::m_instance = nullptr;
|
2012-04-18 20:30:57 +03:00
|
|
|
|
|
|
|
} // namespace Android
|