From f10002e3f53fff02e8488d50b7441d3dbd999d1b Mon Sep 17 00:00:00 2001 From: Vikas Pachdha Date: Mon, 18 Jun 2018 13:40:02 +0200 Subject: [PATCH] Android: Deploy Qt live apk for QML projects Task-number: QDS-16 Change-Id: Iafb1f7ea5d354e73020ff3c5175efa82f99bdffe Reviewed-by: Ulf Hermann --- src/plugins/android/androidconfigurations.cpp | 20 +-- src/plugins/android/androidconfigurations.h | 4 +- src/plugins/android/androiddeployqtstep.cpp | 126 +++++++++++------- src/plugins/android/androiddeployqtstep.h | 3 +- src/plugins/android/androiddevice.cpp | 6 +- 5 files changed, 90 insertions(+), 69 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 92a06639e6e..8df7fdce432 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -93,7 +93,6 @@ namespace { const QLatin1String OpenJDKLocationKey("OpenJDKLocation"); const QLatin1String KeystoreLocationKey("KeystoreLocation"); const QLatin1String AutomaticKitCreationKey("AutomatiKitCreation"); - const QLatin1String DeviceQmlsceneCommandKey("DeviceQmlsceneCommand"); const QLatin1String MakeExtraSearchDirectory("MakeExtraSearchDirectory"); const QLatin1String PartitionSizeKey("PartitionSize"); const QLatin1String ToolchainHostKey("ToolchainHost"); @@ -126,8 +125,8 @@ namespace { const QLatin1String sdkToolsVersionKey("Pkg.Revision"); const QLatin1String ndkRevisionKey("Pkg.Revision"); - const QLatin1String defaultQmlScene("org.qtproject.example.qmlscene/" - "org.qtproject.qt5.android.bindings.QtActivity"); + const QString defaultQtLiveApk = Core::ICore::resourcePath() + + ("/qtlive/android/armv7/qt_live_viewer.apk"); static QString sdkSettingsFileName() { @@ -257,7 +256,6 @@ void AndroidConfig::load(const QSettings &settings) m_keystoreLocation = FileName::fromString(settings.value(KeystoreLocationKey).toString()); m_toolchainHost = settings.value(ToolchainHostKey).toString(); m_automaticKitCreation = settings.value(AutomaticKitCreationKey, true).toBool(); - m_deviceQmlsceneCommand = settings.value(DeviceQmlsceneCommandKey, defaultQmlScene).toString(); QString extraDirectory = settings.value(MakeExtraSearchDirectory).toString(); m_makeExtraSearchDirectories.clear(); if (!extraDirectory.isEmpty()) @@ -274,7 +272,6 @@ void AndroidConfig::load(const QSettings &settings) m_keystoreLocation = FileName::fromString(reader.restoreValue(KeystoreLocationKey, m_keystoreLocation.toString()).toString()); m_toolchainHost = reader.restoreValue(ToolchainHostKey, m_toolchainHost).toString(); m_automaticKitCreation = reader.restoreValue(AutomaticKitCreationKey, m_automaticKitCreation).toBool(); - m_deviceQmlsceneCommand = reader.restoreValue(DeviceQmlsceneCommandKey, m_deviceQmlsceneCommand).toString(); QString extraDirectory = reader.restoreValue(MakeExtraSearchDirectory).toString(); m_makeExtraSearchDirectories.clear(); if (!extraDirectory.isEmpty()) @@ -298,7 +295,6 @@ void AndroidConfig::save(QSettings &settings) const settings.setValue(KeystoreLocationKey, m_keystoreLocation.toString()); settings.setValue(PartitionSizeKey, m_partitionSize); settings.setValue(AutomaticKitCreationKey, m_automaticKitCreation); - settings.setValue(DeviceQmlsceneCommandKey, m_deviceQmlsceneCommand); settings.setValue(ToolchainHostKey, m_toolchainHost); settings.setValue(MakeExtraSearchDirectory, m_makeExtraSearchDirectories.isEmpty() ? QString() @@ -876,14 +872,12 @@ void AndroidConfig::setAutomaticKitCreation(bool b) m_automaticKitCreation = b; } -QString AndroidConfig::deviceQmlsceneCommand() const +FileName AndroidConfig::qtLiveApkPath() const { - return m_deviceQmlsceneCommand; -} - -void AndroidConfig::setDeviceQmlsceneCommand(const QString &qmlsceneCommand) -{ - m_deviceQmlsceneCommand = qmlsceneCommand; + QString apkPathStr(defaultQtLiveApk); + if (qEnvironmentVariableIsSet("QTC_QT_LIVE_APK_PATH")) + apkPathStr = QString::fromLocal8Bit(qgetenv("QTC_QT_LIVE_APK_PATH")); + return Utils::FileName::fromString(apkPathStr); } /////////////////////////////////// diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 0a7fa4c3b72..95de9aad65f 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -124,8 +124,7 @@ public: bool automaticKitCreation() const; void setAutomaticKitCreation(bool b); - QString deviceQmlsceneCommand() const; - void setDeviceQmlsceneCommand(const QString &qmlsceneCommand); + Utils::FileName qtLiveApkPath() const; Utils::FileName adbToolPath() const; Utils::FileName androidToolPath() const; @@ -182,7 +181,6 @@ private: QStringList m_makeExtraSearchDirectories; unsigned m_partitionSize = 1024; bool m_automaticKitCreation = true; - QString m_deviceQmlsceneCommand; //caches mutable bool m_NdkInformationUpToDate = false; diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 980fb3f91da..3e00c4a838e 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -72,6 +73,7 @@ const QLatin1String InstallFailedUpdateIncompatible("INSTALL_FAILED_UPDATE_INCOM const QLatin1String InstallFailedPermissionModelDowngrade("INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE"); const QLatin1String InstallFailedVersionDowngrade("INSTALL_FAILED_VERSION_DOWNGRADE"); const Core::Id AndroidDeployQtStep::Id("Qt4ProjectManager.AndroidDeployQtStep"); +static const char *qmlProjectRunConfigIdName = "QmlProjectManager.QmlRunConfiguration"; // AndroidDeployQtStepFactory @@ -121,10 +123,17 @@ bool AndroidDeployQtStep::init(QList &earlierSteps) return false; } - AndroidBuildApkStep *androidBuildApkStep - = AndroidGlobal::buildStep(buildConfiguration()); - if (!androidBuildApkStep) + RunConfiguration *rc = target()->activeRunConfiguration(); + QTC_ASSERT(rc, return false); + const bool deployQtLive = rc->id().name().startsWith(qmlProjectRunConfigIdName); + ProjectExplorer::BuildConfiguration *bc = buildConfiguration(); + QTC_ASSERT(deployQtLive || bc, return false); + + AndroidBuildApkStep *androidBuildApkStep = AndroidGlobal::buildStep(bc); + if (!androidBuildApkStep && !deployQtLive) { emit addOutput(tr("Cannot find the android build step."), OutputFormat::Stderr); + return false; + } int deviceAPILevel = AndroidManager::minimumSDK(target()); AndroidDeviceInfo info = earlierDeviceInfo(earlierSteps, Id); @@ -140,40 +149,9 @@ bool AndroidDeployQtStep::init(QList &earlierSteps) m_serialNumber = info.serialNumber; qCDebug(deployStepLog) << "AVD:" << m_avdName << "Device Serial:" << m_serialNumber; - ProjectExplorer::BuildConfiguration *bc = buildConfiguration(); - m_filesToPull.clear(); - QString buildDir = bc ? bc->buildDirectory().toString() : QString(); - if (bc && !buildDir.endsWith("/")) { - buildDir += "/"; - } + if (!deployQtLive) + gatherFilesToPull(); - ProjectExplorer::ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain( - target()->kit(), ProjectExplorer::Constants::CXX_LANGUAGE_ID); - qCDebug(deployStepLog) << "Device CPU ABI: " << info.cpuAbi.join(", "); - qCDebug(deployStepLog) << "TC ABI: " << (tc ? tc->targetAbi().toString() : "No Toolchain"); - - QString linkerName("linker"); - QString libDirName("lib"); - if (info.cpuAbi.contains(QLatin1String("arm64-v8a")) || - info.cpuAbi.contains(QLatin1String("x86_64"))) { - if (tc && tc->targetAbi().wordWidth() == 64) { - m_filesToPull["/system/bin/app_process64"] = buildDir + "app_process"; - libDirName = "lib64"; - linkerName = "linker64"; - } else { - m_filesToPull["/system/bin/app_process32"] = buildDir + "app_process"; - } - } else { - m_filesToPull["/system/bin/app_process32"] = buildDir + "app_process"; - m_filesToPull["/system/bin/app_process"] = buildDir + "app_process"; - } - - m_filesToPull["/system/bin/" + linkerName] = buildDir + linkerName; - m_filesToPull["/system/" + libDirName + "/libc.so"] = buildDir + "libc.so"; - - qCDebug(deployStepLog) << "Files to pull from device:"; - for (auto itr = m_filesToPull.constBegin(); itr != m_filesToPull.constEnd(); ++itr) - qCDebug(deployStepLog) << itr.key() << "to" << itr.value(); AndroidManager::setDeviceSerialNumber(target(), m_serialNumber); AndroidManager::setDeviceApiLevel(target(), info.sdk); @@ -186,7 +164,8 @@ bool AndroidDeployQtStep::init(QList &earlierSteps) m_manifestName = AndroidManager::manifestPath(target()); AndroidQtSupport *qtSupport = AndroidManager::androidQtSupport(target()); - m_useAndroiddeployqt = qtSupport && version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0); + m_useAndroiddeployqt = !deployQtLive && qtSupport && + version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0); if (m_useAndroiddeployqt) { m_command = version->qmakeProperty("QT_HOST_BINS"); @@ -199,8 +178,7 @@ bool AndroidDeployQtStep::init(QList &earlierSteps) m_command += QLatin1Char('/'); m_command += Utils::HostOsInfo::withExecutableSuffix(QLatin1String("androiddeployqt")); - m_workingDirectory = bc ? bc->buildDirectory().appendPath(QLatin1String(Constants::ANDROID_BUILDDIRECTORY)).toString() - : QString(); + m_workingDirectory = bc->buildDirectory().appendPath(QLatin1String(Constants::ANDROID_BUILDDIRECTORY)).toString(); Utils::QtcProcess::addArg(&m_androiddeployqtArgs, QLatin1String("--verbose")); Utils::QtcProcess::addArg(&m_androiddeployqtArgs, QLatin1String("--output")); @@ -233,7 +211,9 @@ bool AndroidDeployQtStep::init(QList &earlierSteps) } else { m_uninstallPreviousPackageRun = true; m_command = AndroidConfigurations::currentConfig().adbToolPath().toString(); - m_apkPath = qtSupport ? qtSupport->apkPath(target()).toString() : QString(); + const AndroidConfig &config = AndroidConfigurations::currentConfig(); + m_apkPath = deployQtLive ? config.qtLiveApkPath() : + (qtSupport ? qtSupport->apkPath(target()) : Utils::FileName()); m_workingDirectory = bc ? bc->buildDirectory().toString() : QString(); } m_environment = bc ? bc->environment() : Utils::Environment(); @@ -262,14 +242,24 @@ AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::runDeploy(QFutureInter Utils::QtcProcess::addArg(&args, m_serialNumber); } } else { + RunConfiguration *rc = target()->activeRunConfiguration(); + QTC_ASSERT(rc, return DeployErrorCode::Failure); + const bool deployQtLive = rc->id().name().startsWith(qmlProjectRunConfigIdName); + QString packageName; + if (deployQtLive) { + AndroidManager::apkInfo(m_apkPath, &packageName); + if (AndroidManager::packageInstalled(m_serialNumber, packageName)) + return DeployErrorCode::NoError; + } + if (m_uninstallPreviousPackageRun) { - qCDebug(deployStepLog) << "Uninstalling previous package"; - const QString packageName = AndroidManager::packageName(m_manifestName); + if (!deployQtLive) + packageName = AndroidManager::packageName(m_manifestName); if (packageName.isEmpty()) { emit addOutput(tr("Cannot find the package name."), OutputFormat::Stderr); return Failure; } - + qCDebug(deployStepLog) << "Uninstalling previous package"; emit addOutput(tr("Uninstall previous package %1.").arg(packageName), OutputFormat::NormalMessage); runCommand(m_adbPath, AndroidDeviceInfo::adbSelector(m_serialNumber) @@ -281,7 +271,7 @@ AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::runDeploy(QFutureInter Utils::QtcProcess::addArg(&args, QLatin1String("install")); Utils::QtcProcess::addArg(&args, QLatin1String("-r")); - Utils::QtcProcess::addArg(&args, m_apkPath); + Utils::QtcProcess::addArg(&args, m_apkPath.toString()); } m_process = new Utils::QtcProcess; @@ -407,12 +397,6 @@ void AndroidDeployQtStep::run(QFutureInterface &fi) emit setSerialNumber(serialNumber); } - if (!buildConfiguration()) { // nothing to deploy - qCDebug(deployStepLog) << "Skip deployment. No build configuration. (e.g. *.qmlproject)"; - reportRunResult(fi, true); - return; - } - DeployErrorCode returnValue = runDeploy(fi); if (returnValue > DeployErrorCode::NoError && returnValue < DeployErrorCode::Failure) { emit askForUninstall(returnValue); @@ -422,7 +406,9 @@ void AndroidDeployQtStep::run(QFutureInterface &fi) } } - emit addOutput(tr("Pulling files necessary for debugging."), OutputFormat::NormalMessage); + if (!m_filesToPull.isEmpty()) + emit addOutput(tr("Pulling files necessary for debugging."), OutputFormat::NormalMessage); + for (auto itr = m_filesToPull.constBegin(); itr != m_filesToPull.constEnd(); ++itr) { QFile::remove(itr.value()); runCommand(m_adbPath, @@ -438,6 +424,44 @@ void AndroidDeployQtStep::run(QFutureInterface &fi) reportRunResult(fi, returnValue == NoError); } +void AndroidDeployQtStep::gatherFilesToPull() +{ + m_filesToPull.clear(); + ProjectExplorer::BuildConfiguration *bc = buildConfiguration(); + QString buildDir = bc ? bc->buildDirectory().toString() : QString(); + if (bc && !buildDir.endsWith("/")) { + buildDir += "/"; + } + + if (!m_deviceInfo.isValid()) + return; + + QString linkerName("linker"); + QString libDirName("lib"); + if (m_deviceInfo.cpuAbi.contains(QLatin1String("arm64-v8a")) || + m_deviceInfo.cpuAbi.contains(QLatin1String("x86_64"))) { + const Core::Id cxxLanguageId = ProjectExplorer::Constants::CXX_LANGUAGE_ID; + ToolChain *tc = ToolChainKitInformation::toolChain(target()->kit(), cxxLanguageId); + if (tc && tc->targetAbi().wordWidth() == 64) { + m_filesToPull["/system/bin/app_process64"] = buildDir + "app_process"; + libDirName = "lib64"; + linkerName = "linker64"; + } else { + m_filesToPull["/system/bin/app_process32"] = buildDir + "app_process"; + } + } else { + m_filesToPull["/system/bin/app_process32"] = buildDir + "app_process"; + m_filesToPull["/system/bin/app_process"] = buildDir + "app_process"; + } + + m_filesToPull["/system/bin/" + linkerName] = buildDir + linkerName; + m_filesToPull["/system/" + libDirName + "/libc.so"] = buildDir + "libc.so"; + + qCDebug(deployStepLog) << "Files to pull from device:"; + for (auto itr = m_filesToPull.constBegin(); itr != m_filesToPull.constEnd(); ++itr) + qCDebug(deployStepLog) << itr.key() << "to" << itr.value(); +} + void AndroidDeployQtStep::runCommand(const QString &program, const QStringList &arguments) { Utils::SynchronousProcess buildProc; diff --git a/src/plugins/android/androiddeployqtstep.h b/src/plugins/android/androiddeployqtstep.h index fcdff97253b..a23f8f9ef61 100644 --- a/src/plugins/android/androiddeployqtstep.h +++ b/src/plugins/android/androiddeployqtstep.h @@ -91,6 +91,7 @@ private: bool init(QList &earlierSteps) override; void run(QFutureInterface &fi) override; + void gatherFilesToPull(); DeployErrorCode runDeploy(QFutureInterface &fi); void slotAskForUninstall(DeployErrorCode errorCode); void slotSetSerialNumber(const QString &serialNumber); @@ -113,7 +114,7 @@ private: Utils::FileName m_manifestName; QString m_serialNumber; QString m_avdName; - QString m_apkPath; + Utils::FileName m_apkPath; QMap m_filesToPull; QString m_targetArch; diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 48aaa35ccaf..7b9cc3a3de4 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -27,6 +27,7 @@ #include "androidconstants.h" #include "androidsignaloperation.h" #include "androidconfigurations.h" +#include "androidmanager.h" #include @@ -47,7 +48,10 @@ AndroidDevice::AndroidDevice() { setDisplayName(QCoreApplication::translate("Android::Internal::AndroidDevice", "Run on Android")); setDeviceState(DeviceReadyToUse); - setQmlsceneCommand(AndroidConfigurations::currentConfig().deviceQmlsceneCommand()); + QString activityPath; + const AndroidConfig &config = AndroidConfigurations::currentConfig(); + AndroidManager::apkInfo(config.qtLiveApkPath(), nullptr, nullptr, &activityPath); + setQmlsceneCommand(activityPath); } AndroidDevice::AndroidDevice(const AndroidDevice &other)