forked from qt-creator/qt-creator
Android: fix some issues with jdk path detection
* There were two functions to detect jdk path, unified them. * First try to find jdk 1.8, if not found, look for newer versions. SDK Tools version 26.x needs jdk 1.8 however, the new cmdline-tools can work with the newest jdk, so the UI will warn the user if the selected jdk cannot run sdkmanager potentially because of the jdk version. Change-Id: Iee2c378598c26e8a9a8245262110ac20322a2d2b Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
@@ -105,7 +105,8 @@ const char macOsKey[] = "mac";
|
|||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const char jdkSettingsPath[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit";
|
const char jdk8SettingsPath[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit";
|
||||||
|
const char jdkLatestSettingsPath[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\JDK\\";
|
||||||
|
|
||||||
const QLatin1String SettingsGroup("AndroidConfigurations");
|
const QLatin1String SettingsGroup("AndroidConfigurations");
|
||||||
const QLatin1String SDKLocationKey("SDKLocation");
|
const QLatin1String SDKLocationKey("SDKLocation");
|
||||||
@@ -1476,103 +1477,77 @@ AndroidConfigurations::AndroidConfigurations()
|
|||||||
|
|
||||||
AndroidConfigurations::~AndroidConfigurations() = default;
|
AndroidConfigurations::~AndroidConfigurations() = default;
|
||||||
|
|
||||||
static FilePath javaHomeForJavac(const FilePath &location)
|
FilePath AndroidConfig::getJdkPath()
|
||||||
{
|
{
|
||||||
QFileInfo fileInfo = location.toFileInfo();
|
FilePath jdkHome;
|
||||||
int tries = 5;
|
|
||||||
while (tries > 0) {
|
|
||||||
QDir dir = fileInfo.dir();
|
|
||||||
dir.cdUp();
|
|
||||||
if (QFileInfo::exists(dir.filePath(QLatin1String("lib/tools.jar"))))
|
|
||||||
return FilePath::fromString(dir.path());
|
|
||||||
if (fileInfo.isSymLink())
|
|
||||||
fileInfo.setFile(fileInfo.symLinkTarget());
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
--tries;
|
|
||||||
}
|
|
||||||
return FilePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidConfigurations::load()
|
if (HostOsInfo::isWindowsHost()) {
|
||||||
{
|
|
||||||
bool saveSettings = false;
|
|
||||||
QSettings *settings = Core::ICore::settings();
|
|
||||||
settings->beginGroup(SettingsGroup);
|
|
||||||
m_config.load(*settings);
|
|
||||||
|
|
||||||
if (m_config.openJDKLocation().isEmpty()) {
|
|
||||||
if (HostOsInfo::isLinuxHost()) {
|
|
||||||
Environment env = Environment::systemEnvironment();
|
|
||||||
FilePath location = env.searchInPath(QLatin1String("javac"));
|
|
||||||
QFileInfo fi = location.toFileInfo();
|
|
||||||
if (fi.exists() && fi.isExecutable() && !fi.isDir()) {
|
|
||||||
m_config.setOpenJDKLocation(javaHomeForJavac(location));
|
|
||||||
saveSettings = true;
|
|
||||||
}
|
|
||||||
} else if (HostOsInfo::isMacHost()) {
|
|
||||||
QFileInfo javaHomeExec(QLatin1String("/usr/libexec/java_home"));
|
|
||||||
if (javaHomeExec.isExecutable() && !javaHomeExec.isDir()) {
|
|
||||||
SynchronousProcess proc;
|
|
||||||
proc.setTimeoutS(2);
|
|
||||||
proc.setProcessChannelMode(QProcess::MergedChannels);
|
|
||||||
SynchronousProcessResponse response =
|
|
||||||
proc.runBlocking({javaHomeExec.absoluteFilePath(), {}});
|
|
||||||
if (response.result == SynchronousProcessResponse::Finished) {
|
|
||||||
const QString &javaHome = response.allOutput().trimmed();
|
|
||||||
if (!javaHome.isEmpty() && QFileInfo::exists(javaHome))
|
|
||||||
m_config.setOpenJDKLocation(FilePath::fromString(javaHome));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (HostOsInfo::isWindowsHost()) {
|
|
||||||
QStringList allVersions;
|
QStringList allVersions;
|
||||||
std::unique_ptr<QSettings> settings(new QSettings(jdkSettingsPath,
|
std::unique_ptr<QSettings> settings(
|
||||||
QSettings::NativeFormat));
|
new QSettings(jdk8SettingsPath, QSettings::NativeFormat));
|
||||||
allVersions = settings->childGroups();
|
allVersions = settings->childGroups();
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
if (allVersions.isEmpty()) {
|
if (allVersions.isEmpty()) {
|
||||||
settings.reset(new QSettings(jdkSettingsPath, QSettings::Registry64Format));
|
settings.reset(new QSettings(jdk8SettingsPath, QSettings::Registry64Format));
|
||||||
allVersions = settings->childGroups();
|
allVersions = settings->childGroups();
|
||||||
}
|
}
|
||||||
#endif // Q_OS_WIN
|
#endif // Q_OS_WIN
|
||||||
|
|
||||||
QString javaHome;
|
// If no jdk 1.8 can be found, look for jdk versions above 1.8
|
||||||
int major = -1;
|
// Android section would warn if sdkmanager cannot run with newer jdk versions
|
||||||
int minor = -1;
|
if (allVersions.isEmpty()) {
|
||||||
foreach (const QString &version, allVersions) {
|
settings.reset(new QSettings(jdkLatestSettingsPath, QSettings::NativeFormat));
|
||||||
QStringList parts = version.split(QLatin1Char('.'));
|
allVersions = settings->childGroups();
|
||||||
if (parts.size() != 2) // not interested in 1.7.0_u21
|
#ifdef Q_OS_WIN
|
||||||
continue;
|
if (allVersions.isEmpty()) {
|
||||||
bool okMajor, okMinor;
|
settings.reset(new QSettings(jdkLatestSettingsPath, QSettings::Registry64Format));
|
||||||
int tmpMajor = parts.at(0).toInt(&okMajor);
|
allVersions = settings->childGroups();
|
||||||
int tmpMinor = parts.at(1).toInt(&okMinor);
|
}
|
||||||
if (!okMajor || !okMinor)
|
#endif // Q_OS_WIN
|
||||||
continue;
|
}
|
||||||
if (tmpMajor > major
|
|
||||||
|| (tmpMajor == major
|
for (const QString &version : allVersions) {
|
||||||
&& tmpMinor > minor)) {
|
|
||||||
settings->beginGroup(version);
|
settings->beginGroup(version);
|
||||||
QString tmpJavaHome = settings->value(QLatin1String("JavaHome")).toString();
|
jdkHome = FilePath::fromUserInput(settings->value("JavaHome").toString());
|
||||||
settings->endGroup();
|
settings->endGroup();
|
||||||
if (!QFileInfo::exists(tmpJavaHome))
|
if (version.startsWith("1.8")) {
|
||||||
|
if (!jdkHome.exists())
|
||||||
continue;
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QStringList args;
|
||||||
|
if (HostOsInfo::isMacHost())
|
||||||
|
args << "-c"
|
||||||
|
<< "/usr/libexec/java_home";
|
||||||
|
else
|
||||||
|
args << "-c"
|
||||||
|
<< "readlink -f $(which java)";
|
||||||
|
|
||||||
major = tmpMajor;
|
QProcess findJdkPathProc;
|
||||||
minor = tmpMinor;
|
findJdkPathProc.start("sh", args);
|
||||||
javaHome = tmpJavaHome;
|
findJdkPathProc.waitForFinished();
|
||||||
}
|
QByteArray jdkPath = findJdkPathProc.readAllStandardOutput().trimmed();
|
||||||
}
|
|
||||||
if (!javaHome.isEmpty()) {
|
if (HostOsInfo::isMacHost()) {
|
||||||
m_config.setOpenJDKLocation(FilePath::fromString(javaHome));
|
jdkHome = FilePath::fromUtf8(jdkPath);
|
||||||
saveSettings = true;
|
} else {
|
||||||
}
|
jdkPath.replace("bin/java", ""); // For OpenJDK 11
|
||||||
|
jdkPath.replace("jre/bin/java", "");
|
||||||
|
jdkHome = FilePath::fromUtf8(jdkPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return jdkHome;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidConfigurations::load()
|
||||||
|
{
|
||||||
|
QSettings *settings = Core::ICore::settings();
|
||||||
|
settings->beginGroup(SettingsGroup);
|
||||||
|
m_config.load(*settings);
|
||||||
settings->endGroup();
|
settings->endGroup();
|
||||||
|
|
||||||
if (saveSettings)
|
|
||||||
save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidConfigurations::updateAndroidDevice()
|
void AndroidConfigurations::updateAndroidDevice()
|
||||||
|
@@ -196,6 +196,7 @@ public:
|
|||||||
Utils::FilePath openSslLocation() const;
|
Utils::FilePath openSslLocation() const;
|
||||||
void setOpenSslLocation(const Utils::FilePath &openSslLocation);
|
void setOpenSslLocation(const Utils::FilePath &openSslLocation);
|
||||||
|
|
||||||
|
static Utils::FilePath getJdkPath();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static QString getDeviceProperty(const Utils::FilePath &adbToolPath,
|
static QString getDeviceProperty(const Utils::FilePath &adbToolPath,
|
||||||
|
@@ -242,7 +242,7 @@ private:
|
|||||||
mutable QReadWriteLock m_licenseInputLock;
|
mutable QReadWriteLock m_licenseInputLock;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool m_packageListingSuccessful = true;
|
bool m_packageListingSuccessful = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -908,6 +908,7 @@ void AndroidSdkManagerPrivate::reloadSdkPackages()
|
|||||||
clearPackages();
|
clearPackages();
|
||||||
|
|
||||||
lastSdkManagerPath = m_config.sdkManagerToolPath();
|
lastSdkManagerPath = m_config.sdkManagerToolPath();
|
||||||
|
m_packageListingSuccessful = false;
|
||||||
|
|
||||||
if (m_config.sdkToolsVersion().isNull()) {
|
if (m_config.sdkToolsVersion().isNull()) {
|
||||||
// Configuration has invalid sdk path or corrupt installation.
|
// Configuration has invalid sdk path or corrupt installation.
|
||||||
|
@@ -103,7 +103,6 @@ private:
|
|||||||
void apply() final { AndroidConfigurations::setConfig(m_androidConfig); }
|
void apply() final { AndroidConfigurations::setConfig(m_androidConfig); }
|
||||||
|
|
||||||
void validateJdk();
|
void validateJdk();
|
||||||
FilePath findJdkInCommonPaths() const;
|
|
||||||
void validateNdk();
|
void validateNdk();
|
||||||
void updateNdkList();
|
void updateNdkList();
|
||||||
void onSdkPathChanged();
|
void onSdkPathChanged();
|
||||||
@@ -155,8 +154,7 @@ private:
|
|||||||
|
|
||||||
enum JavaValidation {
|
enum JavaValidation {
|
||||||
JavaPathExistsRow,
|
JavaPathExistsRow,
|
||||||
JavaJdkValidRow,
|
JavaJdkValidRow
|
||||||
JavaJdkValidVersionRow
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum AndroidValidation {
|
enum AndroidValidation {
|
||||||
@@ -395,7 +393,6 @@ AndroidSettingsWidget::AndroidSettingsWidget()
|
|||||||
QMap<int, QString> javaValidationPoints;
|
QMap<int, QString> javaValidationPoints;
|
||||||
javaValidationPoints[JavaPathExistsRow] = tr("JDK path exists.");
|
javaValidationPoints[JavaPathExistsRow] = tr("JDK path exists.");
|
||||||
javaValidationPoints[JavaJdkValidRow] = tr("JDK path is a valid JDK root folder.");
|
javaValidationPoints[JavaJdkValidRow] = tr("JDK path is a valid JDK root folder.");
|
||||||
javaValidationPoints[JavaJdkValidVersionRow] = tr("Working JDK version (8) detected.");
|
|
||||||
m_javaSummary = new SummaryWidget(javaValidationPoints, tr("Java Settings are OK."),
|
m_javaSummary = new SummaryWidget(javaValidationPoints, tr("Java Settings are OK."),
|
||||||
tr("Java settings have errors."), m_ui.javaDetailsWidget);
|
tr("Java settings have errors."), m_ui.javaDetailsWidget);
|
||||||
|
|
||||||
@@ -405,7 +402,7 @@ AndroidSettingsWidget::AndroidSettingsWidget()
|
|||||||
androidValidationPoints[SdkToolsInstalledRow] = tr("SDK tools installed.");
|
androidValidationPoints[SdkToolsInstalledRow] = tr("SDK tools installed.");
|
||||||
androidValidationPoints[PlatformToolsInstalledRow] = tr("Platform tools installed.");
|
androidValidationPoints[PlatformToolsInstalledRow] = tr("Platform tools installed.");
|
||||||
androidValidationPoints[SdkManagerSuccessfulRow] = tr(
|
androidValidationPoints[SdkManagerSuccessfulRow] = tr(
|
||||||
"SDK manager runs (requires exactly Java 1.8).");
|
"SDK manager runs (SDK Tools versions <= 26.x require exactly Java 1.8).");
|
||||||
androidValidationPoints[AllEssentialsInstalledRow] = tr(
|
androidValidationPoints[AllEssentialsInstalledRow] = tr(
|
||||||
"All essential packages installed for all installed Qt versions.");
|
"All essential packages installed for all installed Qt versions.");
|
||||||
androidValidationPoints[BuildToolsInstalledRow] = tr("Build tools installed.");
|
androidValidationPoints[BuildToolsInstalledRow] = tr("Build tools installed.");
|
||||||
@@ -433,7 +430,7 @@ AndroidSettingsWidget::AndroidSettingsWidget()
|
|||||||
this, &AndroidSettingsWidget::validateJdk);
|
this, &AndroidSettingsWidget::validateJdk);
|
||||||
FilePath currentJdkPath = m_androidConfig.openJDKLocation();
|
FilePath currentJdkPath = m_androidConfig.openJDKLocation();
|
||||||
if (currentJdkPath.isEmpty())
|
if (currentJdkPath.isEmpty())
|
||||||
currentJdkPath = findJdkInCommonPaths();
|
currentJdkPath = AndroidConfig::getJdkPath();
|
||||||
m_ui.OpenJDKLocationPathChooser->setFilePath(currentJdkPath);
|
m_ui.OpenJDKLocationPathChooser->setFilePath(currentJdkPath);
|
||||||
m_ui.OpenJDKLocationPathChooser->setPromptDialogTitle(tr("Select JDK Path"));
|
m_ui.OpenJDKLocationPathChooser->setPromptDialogTitle(tr("Select JDK Path"));
|
||||||
|
|
||||||
@@ -584,24 +581,6 @@ void AndroidSettingsWidget::validateJdk()
|
|||||||
const FilePath bin = m_androidConfig.openJDKLocation().pathAppended("bin/javac" QTC_HOST_EXE_SUFFIX);
|
const FilePath bin = m_androidConfig.openJDKLocation().pathAppended("bin/javac" QTC_HOST_EXE_SUFFIX);
|
||||||
m_javaSummary->setPointValid(JavaJdkValidRow, jdkPathExists && bin.exists());
|
m_javaSummary->setPointValid(JavaJdkValidRow, jdkPathExists && bin.exists());
|
||||||
|
|
||||||
bool jdkVersionCorrect = false;
|
|
||||||
SynchronousProcess javacProcess;
|
|
||||||
const int timeoutS = 5;
|
|
||||||
javacProcess.setTimeoutS(timeoutS);
|
|
||||||
const CommandLine cmd(bin, {"-version"});
|
|
||||||
SynchronousProcessResponse response = javacProcess.runBlocking(cmd);
|
|
||||||
if (response.result == SynchronousProcessResponse::Finished) {
|
|
||||||
QString output = response.stdOut(); // JDK 14 uses stdOut for this output.
|
|
||||||
if (output.isEmpty())
|
|
||||||
output = response.stdErr(); // JDK 8 uses stdErr for this output.
|
|
||||||
if (output.startsWith("javac ")) {
|
|
||||||
const QVersionNumber javacVersion = QVersionNumber::fromString(output.mid(6));
|
|
||||||
if (QVersionNumber(1, 8).isPrefixOf(javacVersion))
|
|
||||||
jdkVersionCorrect = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_javaSummary->setPointValid(JavaJdkValidVersionRow, jdkVersionCorrect);
|
|
||||||
|
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,53 +599,6 @@ void AndroidSettingsWidget::validateOpenSsl()
|
|||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePath AndroidSettingsWidget::findJdkInCommonPaths() const
|
|
||||||
{
|
|
||||||
QString jdkFromEnvVar = QString::fromLocal8Bit(getenv("JAVA_HOME"));
|
|
||||||
if (!jdkFromEnvVar.isEmpty())
|
|
||||||
return FilePath::fromUserInput(jdkFromEnvVar);
|
|
||||||
|
|
||||||
if (HostOsInfo::isWindowsHost()) {
|
|
||||||
QString jdkRegisteryPath = "HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\JDK\\";
|
|
||||||
QSettings jdkSettings(jdkRegisteryPath, QSettings::NativeFormat);
|
|
||||||
|
|
||||||
QStringList jdkVersions = jdkSettings.childGroups();
|
|
||||||
FilePath jdkHome;
|
|
||||||
|
|
||||||
for (const QString &version : jdkVersions) {
|
|
||||||
jdkSettings.beginGroup(version);
|
|
||||||
jdkHome = FilePath::fromUserInput(jdkSettings.value("JavaHome").toString());
|
|
||||||
jdkSettings.endGroup();
|
|
||||||
if (version.startsWith("1.8"))
|
|
||||||
return jdkHome;
|
|
||||||
}
|
|
||||||
|
|
||||||
return jdkHome;
|
|
||||||
}
|
|
||||||
|
|
||||||
QProcess findJdkPathProc;
|
|
||||||
|
|
||||||
QString cmd;
|
|
||||||
QStringList args;
|
|
||||||
|
|
||||||
if (HostOsInfo::isMacHost()) {
|
|
||||||
cmd = "sh";
|
|
||||||
args << "-c" << "/usr/libexec/java_home";
|
|
||||||
} else {
|
|
||||||
cmd = "sh";
|
|
||||||
args << "-c" << "readlink -f $(which java)";
|
|
||||||
}
|
|
||||||
|
|
||||||
findJdkPathProc.start(cmd, args);
|
|
||||||
findJdkPathProc.waitForFinished();
|
|
||||||
QByteArray jdkPath = findJdkPathProc.readAllStandardOutput().trimmed();
|
|
||||||
|
|
||||||
if (HostOsInfo::isMacHost())
|
|
||||||
return FilePath::fromUtf8(jdkPath);
|
|
||||||
else
|
|
||||||
return FilePath::fromUtf8(jdkPath.replace("jre/bin/java", ""));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidSettingsWidget::validateNdk()
|
void AndroidSettingsWidget::validateNdk()
|
||||||
{
|
{
|
||||||
const QListWidgetItem *currentItem = m_ui.ndkListWidget->currentItem();
|
const QListWidgetItem *currentItem = m_ui.ndkListWidget->currentItem();
|
||||||
|
Reference in New Issue
Block a user