From b410def067082b88fb2c65dc66a6fcb69584ad90 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Fri, 26 Jun 2020 00:33:43 +0300 Subject: [PATCH] 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 --- src/plugins/android/androidconfigurations.cpp | 149 ++++++++---------- src/plugins/android/androidconfigurations.h | 1 + src/plugins/android/androidsdkmanager.cpp | 3 +- src/plugins/android/androidsettingswidget.cpp | 74 +-------- 4 files changed, 68 insertions(+), 159 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index d96447181e5..cf1d2a7ae66 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -105,7 +105,8 @@ const char macOsKey[] = "mac"; 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 SDKLocationKey("SDKLocation"); @@ -1476,103 +1477,77 @@ AndroidConfigurations::AndroidConfigurations() AndroidConfigurations::~AndroidConfigurations() = default; -static FilePath javaHomeForJavac(const FilePath &location) +FilePath AndroidConfig::getJdkPath() { - QFileInfo fileInfo = location.toFileInfo(); - 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()); + FilePath jdkHome; + + if (HostOsInfo::isWindowsHost()) { + QStringList allVersions; + std::unique_ptr 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)); + allVersions = settings->childGroups(); +#ifdef Q_OS_WIN + if (allVersions.isEmpty()) { + settings.reset(new QSettings(jdkLatestSettingsPath, QSettings::Registry64Format)); + allVersions = settings->childGroups(); + } +#endif // Q_OS_WIN + } + + for (const QString &version : allVersions) { + settings->beginGroup(version); + jdkHome = FilePath::fromUserInput(settings->value("JavaHome").toString()); + settings->endGroup(); + if (version.startsWith("1.8")) { + if (!jdkHome.exists()) + continue; + break; + } + } + } else { + QStringList args; + if (HostOsInfo::isMacHost()) + args << "-c" + << "/usr/libexec/java_home"; else - break; - --tries; + 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 + jdkPath.replace("jre/bin/java", ""); + jdkHome = FilePath::fromUtf8(jdkPath); + } } - return FilePath(); + + return jdkHome; } void AndroidConfigurations::load() { - 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; - std::unique_ptr settings(new QSettings(jdkSettingsPath, - QSettings::NativeFormat)); - allVersions = settings->childGroups(); -#ifdef Q_OS_WIN - if (allVersions.isEmpty()) { - settings.reset(new QSettings(jdkSettingsPath, QSettings::Registry64Format)); - allVersions = settings->childGroups(); - } -#endif // Q_OS_WIN - - QString javaHome; - int major = -1; - int minor = -1; - foreach (const QString &version, allVersions) { - QStringList parts = version.split(QLatin1Char('.')); - if (parts.size() != 2) // not interested in 1.7.0_u21 - continue; - bool okMajor, okMinor; - int tmpMajor = parts.at(0).toInt(&okMajor); - int tmpMinor = parts.at(1).toInt(&okMinor); - if (!okMajor || !okMinor) - continue; - if (tmpMajor > major - || (tmpMajor == major - && tmpMinor > minor)) { - settings->beginGroup(version); - QString tmpJavaHome = settings->value(QLatin1String("JavaHome")).toString(); - settings->endGroup(); - if (!QFileInfo::exists(tmpJavaHome)) - continue; - - major = tmpMajor; - minor = tmpMinor; - javaHome = tmpJavaHome; - } - } - if (!javaHome.isEmpty()) { - m_config.setOpenJDKLocation(FilePath::fromString(javaHome)); - saveSettings = true; - } - } - } - settings->endGroup(); - - if (saveSettings) - save(); } void AndroidConfigurations::updateAndroidDevice() diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index f3aa3acaae4..0f0cca2ddab 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -196,6 +196,7 @@ public: Utils::FilePath openSslLocation() const; void setOpenSslLocation(const Utils::FilePath &openSslLocation); + static Utils::FilePath getJdkPath(); private: static QString getDeviceProperty(const Utils::FilePath &adbToolPath, diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index 8e2115db862..e5df4a2d827 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -242,7 +242,7 @@ private: mutable QReadWriteLock m_licenseInputLock; public: - bool m_packageListingSuccessful = true; + bool m_packageListingSuccessful = false; }; /*! @@ -908,6 +908,7 @@ void AndroidSdkManagerPrivate::reloadSdkPackages() clearPackages(); lastSdkManagerPath = m_config.sdkManagerToolPath(); + m_packageListingSuccessful = false; if (m_config.sdkToolsVersion().isNull()) { // Configuration has invalid sdk path or corrupt installation. diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index 30442612210..951b40a2227 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -103,7 +103,6 @@ private: void apply() final { AndroidConfigurations::setConfig(m_androidConfig); } void validateJdk(); - FilePath findJdkInCommonPaths() const; void validateNdk(); void updateNdkList(); void onSdkPathChanged(); @@ -155,8 +154,7 @@ private: enum JavaValidation { JavaPathExistsRow, - JavaJdkValidRow, - JavaJdkValidVersionRow + JavaJdkValidRow }; enum AndroidValidation { @@ -395,7 +393,6 @@ AndroidSettingsWidget::AndroidSettingsWidget() QMap javaValidationPoints; javaValidationPoints[JavaPathExistsRow] = tr("JDK path exists."); 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."), tr("Java settings have errors."), m_ui.javaDetailsWidget); @@ -405,7 +402,7 @@ AndroidSettingsWidget::AndroidSettingsWidget() androidValidationPoints[SdkToolsInstalledRow] = tr("SDK tools installed."); androidValidationPoints[PlatformToolsInstalledRow] = tr("Platform tools installed."); 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( "All essential packages installed for all installed Qt versions."); androidValidationPoints[BuildToolsInstalledRow] = tr("Build tools installed."); @@ -433,7 +430,7 @@ AndroidSettingsWidget::AndroidSettingsWidget() this, &AndroidSettingsWidget::validateJdk); FilePath currentJdkPath = m_androidConfig.openJDKLocation(); if (currentJdkPath.isEmpty()) - currentJdkPath = findJdkInCommonPaths(); + currentJdkPath = AndroidConfig::getJdkPath(); m_ui.OpenJDKLocationPathChooser->setFilePath(currentJdkPath); 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); 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(); } @@ -620,53 +599,6 @@ void AndroidSettingsWidget::validateOpenSsl() 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() { const QListWidgetItem *currentItem = m_ui.ndkListWidget->currentItem();