From 3473ad0239e29f672b6efff0c222f4334b772f52 Mon Sep 17 00:00:00 2001 From: sachintaMSFT <80828309+sachintaMSFT@users.noreply.github.com> Date: Thu, 22 Sep 2022 20:15:55 -0700 Subject: [PATCH] Deployment Manager Repair API (#2954) * Deployment Manager Repair API Co-authored-by: Santosh Chintalapati --- dev/Deployment/Deployment.idl | 10 +- dev/Deployment/DeploymentActivityContext.cpp | 1 + dev/Deployment/DeploymentActivityContext.h | 19 ++- dev/Deployment/DeploymentManager.cpp | 168 +++++++++++++------ dev/Deployment/DeploymentManager.h | 14 +- dev/Deployment/DeploymentTraceLogging.h | 10 +- dev/Deployment/PackageDefinitions.h | 4 + dev/DeploymentAgent/main.cpp | 52 ++++-- dev/DeploymentAgent/tracelogging.h | 10 +- 9 files changed, 200 insertions(+), 88 deletions(-) diff --git a/dev/Deployment/Deployment.idl b/dev/Deployment/Deployment.idl index 05d3a1ff11..224147b04c 100644 --- a/dev/Deployment/Deployment.idl +++ b/dev/Deployment/Deployment.idl @@ -14,6 +14,9 @@ namespace Microsoft.Windows.ApplicationModel.WindowsAppRuntime Ok, PackageInstallRequired, PackageInstallFailed, + + [contract(DeploymentContract, 3)] + PackageRepairFailed, }; /// Represents the result of a Deployment Manager method. @@ -37,7 +40,7 @@ namespace Microsoft.Windows.ApplicationModel.WindowsAppRuntime DeploymentInitializeOptions(); /// Gets or sets a value that indicates whether the processes associated with the - /// WindowsAppSDK main and singleton packages will be shut down forcibly if they are + /// WindowsAppSDK Main and Singleton packages will be shut down forcibly if they are /// currently in use, when registering the WinAppSDK packages. Boolean ForceDeployment; @@ -64,5 +67,10 @@ namespace Microsoft.Windows.ApplicationModel.WindowsAppRuntime [contract(DeploymentContract, 2)] [overload("Initialize")] static DeploymentResult Initialize(Microsoft.Windows.ApplicationModel.WindowsAppRuntime.DeploymentInitializeOptions deploymentInitializeOptions); + + /// Checks the status of the WindowsAppRuntime of the current package and attempts to + /// repair already installed WinAppSDK packages. + [contract(DeploymentContract, 3)] + static DeploymentResult Repair(); }; } diff --git a/dev/Deployment/DeploymentActivityContext.cpp b/dev/Deployment/DeploymentActivityContext.cpp index 3f0ab4cc51..a38a3bd3c6 100644 --- a/dev/Deployment/DeploymentActivityContext.cpp +++ b/dev/Deployment/DeploymentActivityContext.cpp @@ -17,6 +17,7 @@ void WindowsAppRuntime::Deployment::Activity::Context::Reset() m_deploymentErrorExtendedHresult = S_OK; m_deploymentErrorText.clear(); m_deploymentErrorActivityId = GUID{}; + m_useExistingPackageIfHigherVersion = false; } void WindowsAppRuntime::Deployment::Activity::Context::SetDeploymentErrorInfo( diff --git a/dev/Deployment/DeploymentActivityContext.h b/dev/Deployment/DeploymentActivityContext.h index 65ca42ed93..43a59eaa64 100644 --- a/dev/Deployment/DeploymentActivityContext.h +++ b/dev/Deployment/DeploymentActivityContext.h @@ -36,7 +36,8 @@ namespace WindowsAppRuntime::Deployment::Activity GUID m_deploymentErrorActivityId{}; WindowsAppRuntimeDeployment_TraceLogger::Initialize m_activity; WilFailure m_lastFailure; - bool isFullTrustPackage{}; + bool m_isFullTrustPackage{}; + bool m_useExistingPackageIfHigherVersion{}; public: static WindowsAppRuntime::Deployment::Activity::Context& Get(); @@ -78,9 +79,14 @@ namespace WindowsAppRuntime::Deployment::Activity return m_lastFailure; } - const bool& GetIsFullTrustPackage() const + const bool GetIsFullTrustPackage() const { - return isFullTrustPackage; + return m_isFullTrustPackage; + } + + const bool GetUseExistingPackageIfHigherVersion() const + { + return m_useExistingPackageIfHigherVersion; } void SetInstallStage(const DeploymentStage& installStage) @@ -112,7 +118,12 @@ namespace WindowsAppRuntime::Deployment::Activity void SetIsFullTrustPackage() { - isFullTrustPackage = true; + m_isFullTrustPackage = true; + } + + void SetUseExistingPackageIfHigherVersion() + { + m_useExistingPackageIfHigherVersion = true; } }; diff --git a/dev/Deployment/DeploymentManager.cpp b/dev/Deployment/DeploymentManager.cpp index a829fe676a..5cf77e4b40 100644 --- a/dev/Deployment/DeploymentManager.cpp +++ b/dev/Deployment/DeploymentManager.cpp @@ -28,11 +28,10 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem inline void Initialize_StopSuccessActivity( ::WindowsAppRuntime::Deployment::Activity::Context& initializeActivityContext, - const winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentStatus& deploymentStatus, - const HRESULT hr = S_OK) + const winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentStatus& deploymentStatus) { initializeActivityContext.GetActivity().StopWithResult( - hr, + S_OK, static_cast (0), static_cast(nullptr), static_cast (0), @@ -44,7 +43,7 @@ inline void Initialize_StopSuccessActivity( S_OK, static_cast(nullptr), GUID{}, - ::WindowsAppRuntime::Deployment::Activity::Context::Get().GetIsFullTrustPackage()); + ::WindowsAppRuntime::Deployment::Activity::Context::Get().GetUseExistingPackageIfHigherVersion()); } namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implementation @@ -62,11 +61,18 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem return Initialize(options); } - winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentResult DeploymentManager::Initialize(winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentInitializeOptions const& deploymentInitializeOptions) + winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentResult DeploymentManager::Initialize( + winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentInitializeOptions const& deploymentInitializeOptions) { return Initialize(GetCurrentFrameworkPackageFullName(), deploymentInitializeOptions); } + winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentResult DeploymentManager::Repair() + { + winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentInitializeOptions options{}; + return Initialize(GetCurrentFrameworkPackageFullName(), options, true); + } + winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentResult DeploymentManager::GetStatus(hstring const& packageFullName) { // Get PackageInfo for WinAppSDK framework package @@ -83,7 +89,6 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem // The framework and package naming scheme is specified here: // https://github.com/microsoft/WindowsAppSDK/blob/main/specs/Deployment/MSIXPackages.md#3-package-naming std::wstring frameworkName{ frameworkPackageInfo.Package(0).packageId.name }; - FAIL_FAST_HR_IF(E_INVALIDARG, frameworkName.find(WINDOWSAPPRUNTIME_PACKAGE_NAME_PREFIX) != 0); const int c_namePrefixLength{ ARRAYSIZE(WINDOWSAPPRUNTIME_PACKAGE_NAME_PREFIX) - 1 }; // We assume that since this is a framework there is no subtype name, meaning the remainder @@ -101,20 +106,21 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem // Loop through all of the target packages (i.e. main, signleton packages) and capture whether they are all installed or not // (i.e. if any of the target packages is not installed, GetStatus should return PackageInstallRequired). HRESULT verifyResult{}; - for (const auto& package : c_targetPackages) + + for (auto package : c_targetPackages) { // Build package family name based on the framework naming scheme. std::wstring packageFamilyName{}; if (package.versionType == PackageVersionType::Versioned) { // PackageFamilyName = Prefix + SubTypeName + VersionIdentifier + Suffix - // Main and Singleton packages are sharing same Package Name Prefix. + // On WindowsAppSDK 1.1+, Main and Singleton packages are sharing same Package Name Prefix. packageFamilyName = WINDOWSAPPRUNTIME_PACKAGE_NAME_MAINPREFIX WINDOWSAPPRUNTIME_PACKAGE_SUBTYPENAME_DELIMETER + package.identifier + packageNameVersionIdentifier + WINDOWSAPPRUNTIME_PACKAGE_NAME_SUFFIX; } else if (package.versionType == PackageVersionType::Unversioned) { // PackageFamilyName = Prefix + Subtypename + VersionTag + Suffix - // Main and Singleton packages are sharing same Package Name Prefix. + // On WindowsAppSDK 1.1+, Main and Singleton packages are sharing same Package Name Prefix. packageFamilyName = WINDOWSAPPRUNTIME_PACKAGE_NAME_MAINPREFIX WINDOWSAPPRUNTIME_PACKAGE_SUBTYPENAME_DELIMETER + package.identifier + packageNameVersionTag + WINDOWSAPPRUNTIME_PACKAGE_NAME_SUFFIX; } else @@ -126,7 +132,7 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem // Get target version based on the framework. auto targetPackageVersion{ frameworkPackageInfo.Package(0).packageId.version }; - verifyResult = VerifyPackage(packageFamilyName, targetPackageVersion); + verifyResult = VerifyPackage(packageFamilyName, targetPackageVersion, package.identifier); if (FAILED(verifyResult)) { break; @@ -146,20 +152,33 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem return winrt::make(status, verifyResult); } - winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentResult DeploymentManager::Initialize(hstring const& packageFullName) + winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentResult DeploymentManager::Initialize( + hstring const& packageFullName) { winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentInitializeOptions deploymentInitializeOptions{}; return DeploymentManager::Initialize(packageFullName, deploymentInitializeOptions); } - winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentResult DeploymentManager::Initialize(hstring const& packageFullName, winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentInitializeOptions const& deploymentInitializeOptions) + winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentResult DeploymentManager::Initialize( + hstring const& packageFullName, + winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentInitializeOptions const& deploymentInitializeOptions, + bool isRepair) { auto& initializeActivityContext{ ::WindowsAppRuntime::Deployment::Activity::Context::Get() }; const bool isPackagedProcess{ AppModel::Identity::IsPackagedProcess() }; + const int integrityLevel = Security::IntegrityLevel::GetIntegrityLevel(); + if (isPackagedProcess && integrityLevel >= SECURITY_MANDATORY_MEDIUM_RID) + { + initializeActivityContext.SetIsFullTrustPackage(); + } + + ::WindowsAppRuntime::Deployment::Activity::Context::Get().SetIsFullTrustPackage(); initializeActivityContext.GetActivity().Start(deploymentInitializeOptions.ForceDeployment(), Security::IntegrityLevel::IsElevated(), isPackagedProcess, - Security::IntegrityLevel::GetIntegrityLevel()); + initializeActivityContext.GetIsFullTrustPackage(), + Security::IntegrityLevel::GetIntegrityLevel(), + isRepair); // DeploymentManager API requires a packaged process? HRESULT hr{}; @@ -173,7 +192,7 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem try { - deploymentResult = _Initialize(initializeActivityContext, packageFullName, deploymentInitializeOptions); + deploymentResult = _Initialize(initializeActivityContext, packageFullName, deploymentInitializeOptions, isRepair); } catch (winrt::hresult_error const& e) { @@ -208,7 +227,6 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem LOG_IF_FAILED(Initialize_OnError_ShowUI(packageIdentity, release)); } - Initialize_StopSuccessActivity(initializeActivityContext, deploymentResult.Status(), hr); THROW_HR(hr); } @@ -219,10 +237,14 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentResult DeploymentManager::_Initialize( ::WindowsAppRuntime::Deployment::Activity::Context& initializeActivityContext, hstring const& packageFullName, - winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentInitializeOptions const& deploymentInitializeOptions) + winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::DeploymentInitializeOptions const& deploymentInitializeOptions, + bool isRepair) { auto getStatusResult{ DeploymentManager::GetStatus(packageFullName) }; - if (getStatusResult.Status() == DeploymentStatus::Ok) + // Repair API works independent of the current status of DeploymentManager. + // Even for Repair, GetStatus will still need to be run as it also captures the package full name in case higher version is installed + if (getStatusResult.Status() == DeploymentStatus::Ok && + !isRepair) { Initialize_StopSuccessActivity(initializeActivityContext, getStatusResult.Status()); return getStatusResult; @@ -238,7 +260,14 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem } else { - status = DeploymentStatus::PackageInstallFailed; + if (isRepair) + { + status = DeploymentStatus::PackageRepairFailed; + } + else + { + status = DeploymentStatus::PackageInstallFailed; + } initializeActivityContext.GetActivity().StopWithResult( deployPackagesResult, @@ -253,7 +282,7 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem initializeActivityContext.GetDeploymentErrorExtendedHResult(), initializeActivityContext.GetDeploymentErrorText().c_str(), initializeActivityContext.GetDeploymentErrorActivityId(), - initializeActivityContext.GetIsFullTrustPackage()); + initializeActivityContext.GetUseExistingPackageIfHigherVersion()); } return winrt::make(status, deployPackagesResult); @@ -295,7 +324,8 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem return packageFullNamesList; } - HRESULT DeploymentManager::VerifyPackage(const std::wstring& packageFamilyName, const PACKAGE_VERSION targetVersion) try + HRESULT DeploymentManager::VerifyPackage(const std::wstring& packageFamilyName, const PACKAGE_VERSION targetVersion, + __out std::wstring& packageIdentifier) try { auto packageFullNames{ FindPackagesByFamily(packageFamilyName) }; bool match{}; @@ -311,6 +341,10 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem if (packageId.Version().Version >= targetVersion.Version) { match = true; + if (packageId.Version().Version > targetVersion.Version) + { + g_existingTargetPackagesIfHigherVersion.insert(std::make_pair(packageIdentifier, packageFullName)); + } break; } } @@ -340,9 +374,10 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem return std::wstring{ path.get() }; } - // Adds the package at the path using PackageManager. + // If useExistingPackageIfHigherVersion == false, Adds the current version package at the passed in path using PackageManager. + // If useExistingPackageIfHigherVersion == true, Registers the higher version package using the passed in path as manifest path and PackageManager. // This requires the 'packageManagement' or 'runFullTrust' capabilities. - HRESULT DeploymentManager::AddPackage(const std::filesystem::path& packagePath, const bool forceDeployment) try + HRESULT DeploymentManager::AddOrRegisterPackage(const std::filesystem::path& path, const bool useExistingPackageIfHigherVersion, const bool forceDeployment) try { winrt::Windows::Management::Deployment::PackageManager packageManager; @@ -350,26 +385,39 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem winrt::Windows::Management::Deployment::DeploymentOptions::ForceTargetApplicationShutdown : winrt::Windows::Management::Deployment::DeploymentOptions::None }; - const auto packagePathUri{ winrt::Windows::Foundation::Uri(packagePath.c_str()) }; - const auto deploymentOperation{ packageManager.AddPackageAsync(packagePathUri, nullptr, options) }; + winrt::Windows::Foundation::IAsyncOperationWithProgress deploymentOperation; + + const auto pathUri { winrt::Windows::Foundation::Uri(path.c_str()) }; + if (useExistingPackageIfHigherVersion) + { + deploymentOperation = packageManager.RegisterPackageAsync(pathUri, nullptr, options); + } + else + { + deploymentOperation = packageManager.AddPackageAsync(pathUri, nullptr, options); + } deploymentOperation.get(); const auto deploymentResult{ deploymentOperation.GetResults() }; - HRESULT hrAddPackage{}; + HRESULT deploymentOperationHResult{}; + HRESULT deploymentOperationExtendedHResult{}; + if (deploymentOperation.Status() != AsyncStatus::Completed) { - hrAddPackage = static_cast(deploymentOperation.ErrorCode()); + deploymentOperationHResult = static_cast(deploymentOperation.ErrorCode()); + deploymentOperationExtendedHResult = deploymentResult.ExtendedErrorCode(); ::WindowsAppRuntime::Deployment::Activity::Context::Get().SetDeploymentErrorInfo( - deploymentResult.ExtendedErrorCode(), + deploymentOperationExtendedHResult, deploymentResult.ErrorText().c_str(), deploymentResult.ActivityId()); } - return deploymentResult.ExtendedErrorCode(); + return !deploymentOperationHResult ? deploymentOperationHResult : + (deploymentOperationExtendedHResult ? deploymentOperationExtendedHResult : deploymentOperationHResult); } CATCH_RETURN() - std::wstring DeploymentManager::GenerateDeploymentAgentPath() { // Calculate the path to the restart agent as being in the same directory as the current module. @@ -381,13 +429,13 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem } /// @warning This function is ONLY for processes with package identity. It's the caller's responsibility to ensure this. - HRESULT DeploymentManager::AddPackageInBreakAwayProcess(const std::filesystem::path& packagePath, const bool forceDeployment) try + HRESULT DeploymentManager::AddOrRegisterPackageInBreakAwayProcess(const std::filesystem::path& path, const bool useExistingPackageIfHigherVersion, const bool forceDeployment) try { auto exePath{ GenerateDeploymentAgentPath() }; auto activityId{ winrt::to_hstring(*::WindowsAppRuntime::Deployment::Activity::Context::Get().GetActivity().Id()) }; // \deploymentagent.exe - auto cmdLine{ wil::str_printf(L"\"%s\" \"%s\" %u %s", exePath.c_str(), packagePath.c_str(), (forceDeployment ? 1 : 0), activityId.c_str()) }; + auto cmdLine{ wil::str_printf(L"\"%s\" %u \"%s\" %u %s", exePath.c_str(), (useExistingPackageIfHigherVersion ? 1 : 0), path.c_str(), (forceDeployment ? 1 : 0), activityId.c_str()) }; SIZE_T attributeListSize{}; auto attributeCount{ 1 }; @@ -484,29 +532,46 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem HRESULT DeploymentManager::DeployPackages(const std::wstring& frameworkPackageFullName, const bool forceDeployment) { - ::WindowsAppRuntime::Deployment::Activity::Context::Get().SetInstallStage(::WindowsAppRuntime::Deployment::Activity::DeploymentStage::GetPackagePath); + auto initializeActivity{ ::WindowsAppRuntime::Deployment::Activity::Context::Get() }; + + initializeActivity.SetInstallStage(::WindowsAppRuntime::Deployment::Activity::DeploymentStage::GetPackagePath); const auto frameworkPath{ std::filesystem::path(GetPackagePath(frameworkPackageFullName)) }; - ::WindowsAppRuntime::Deployment::Activity::Context::Get().SetInstallStage(::WindowsAppRuntime::Deployment::Activity::DeploymentStage::AddPackage); - for (const auto& package : c_targetPackages) + initializeActivity.SetInstallStage(::WindowsAppRuntime::Deployment::Activity::DeploymentStage::AddPackage); + for (auto package : c_targetPackages) { - ::WindowsAppRuntime::Deployment::Activity::Context::Get().Reset(); - ::WindowsAppRuntime::Deployment::Activity::Context::Get().SetCurrentResourceId(package.identifier); - // Build path for the packages. - auto packagePath{ frameworkPath }; - packagePath /= WINDOWSAPPRUNTIME_FRAMEWORK_PACKAGE_FOLDER; - packagePath /= package.identifier + WINDOWSAPPRUNTIME_FRAMEWORK_PACKAGE_FILE_EXTENSION; - - if (AppModel::Identity::IsPackagedProcess() && - Security::IntegrityLevel::GetIntegrityLevel() >= SECURITY_MANDATORY_MEDIUM_RID) + initializeActivity.Reset(); + initializeActivity.SetCurrentResourceId(package.identifier); + + std::filesystem::path packagePath{}; + + // If there is exisiting target package version higher than that of framework current version package, then re-register it. + // Otherwise, deploy the target msix package from the current framework package version. + auto existingPackageIfHigherVersion = g_existingTargetPackagesIfHigherVersion.find(package.identifier); + auto useExistingPackageIfHigherVersion { existingPackageIfHigherVersion != g_existingTargetPackagesIfHigherVersion.end() }; + if (useExistingPackageIfHigherVersion) { - ::WindowsAppRuntime::Deployment::Activity::Context::Get().SetIsFullTrustPackage(); - RETURN_IF_FAILED(AddPackageInBreakAwayProcess(packagePath, forceDeployment)); + initializeActivity.SetUseExistingPackageIfHigherVersion(); + packagePath = std::filesystem::path(GetPackagePath(existingPackageIfHigherVersion->second)); + packagePath /= WINDOWSAPPRUNTIME_PACKAGE_MANIFEST_FILE; } else { - // Deploy package. - RETURN_IF_FAILED(AddPackage(packagePath, forceDeployment)); + packagePath = frameworkPath; + packagePath /= WINDOWSAPPRUNTIME_FRAMEWORK_PACKAGE_FOLDER; + packagePath /= package.identifier + WINDOWSAPPRUNTIME_FRAMEWORK_PACKAGE_FILE_EXTENSION; + } + + // If the current application has runFullTrust capability, then Deploy the target package in a Breakaway process. + // Otherwise, call PackageManager API to deploy the target package. + if (initializeActivity.GetIsFullTrustPackage()) + { + + RETURN_IF_FAILED(AddOrRegisterPackageInBreakAwayProcess(packagePath, useExistingPackageIfHigherVersion, forceDeployment)); + } + else + { + RETURN_IF_FAILED(AddOrRegisterPackage(packagePath, useExistingPackageIfHigherVersion, forceDeployment)); } // Restart Push Notifications Long Running Platform when ForceDeployment option is applied. @@ -556,14 +621,7 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem continue; } - // Verify that no other SubTypeNames appear in the name. - for (const auto& subType : c_subTypeNames) - { - if (dependencyPackageName.find(subType.identifier) != std::string::npos) - { - continue; - } - } + // On WindowsAppSDK 1.1+, there is no need to check and rule out Main, Singleton and DDLM Package identifiers as their names don't have a overlap with WINDOWSAPPRUNTIME_PACKAGE_NAME_PREFIX. return hstring(currentPackageInfo.Package(i).packageFullName); } diff --git a/dev/Deployment/DeploymentManager.h b/dev/Deployment/DeploymentManager.h index ac384981cc..2129270aa3 100644 --- a/dev/Deployment/DeploymentManager.h +++ b/dev/Deployment/DeploymentManager.h @@ -18,26 +18,30 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem static WindowsAppRuntime::DeploymentResult GetStatus(); static WindowsAppRuntime::DeploymentResult Initialize(); static WindowsAppRuntime::DeploymentResult Initialize(WindowsAppRuntime::DeploymentInitializeOptions const& deploymentInitializeOptions); + static WindowsAppRuntime::DeploymentResult Repair(); private: static WindowsAppRuntime::DeploymentResult GetStatus(hstring const& packageFullName); static WindowsAppRuntime::DeploymentResult Initialize(hstring const& packageFullName); - static WindowsAppRuntime::DeploymentResult Initialize(hstring const& packageFullName, WindowsAppRuntime::DeploymentInitializeOptions const& deploymentInitializeOptions); + static WindowsAppRuntime::DeploymentResult Initialize(hstring const& packageFullName, + WindowsAppRuntime::DeploymentInitializeOptions const& deploymentInitializeOptions, + bool isRepair = false); private: static WindowsAppRuntime::DeploymentResult _Initialize( ::WindowsAppRuntime::Deployment::Activity::Context& initializeActivityContext, hstring const& packageFullName, - WindowsAppRuntime::DeploymentInitializeOptions const& deploymentInitializeOptions); + WindowsAppRuntime::DeploymentInitializeOptions const& deploymentInitializeOptions, + bool isRepair); private: static MddCore::PackageInfo GetPackageInfoForPackage(std::wstring const& packageFullName); static std::vector FindPackagesByFamily(std::wstring const& packageFamilyName); - static HRESULT VerifyPackage(const std::wstring& packageFamilyName, const PACKAGE_VERSION targetVersion); + static HRESULT VerifyPackage(const std::wstring& packageFamilyName, const PACKAGE_VERSION targetVersion, __out std::wstring& matchedPackageFullName); static std::wstring GetPackagePath(std::wstring const& packageFullName); - static HRESULT AddPackageInBreakAwayProcess(const std::filesystem::path& packagePath, const bool forceDeployment); + static HRESULT AddOrRegisterPackageInBreakAwayProcess(const std::filesystem::path& packagePath, const bool regiterHigherVersionPackage, const bool forceDeployment); static std::wstring GenerateDeploymentAgentPath(); - static HRESULT AddPackage(const std::filesystem::path& packagePath, const bool forceDeployment); + static HRESULT AddOrRegisterPackage(const std::filesystem::path& package, const bool regiterHigherVersionPackage, const bool forceDeployment); static HRESULT DeployPackages(const std::wstring& frameworkPackageFullName, const bool forceDeployment); static HRESULT Deploy(const std::wstring& frameworkPackageFullName, const bool forceDeployment = false); static HRESULT InstallLicenses(const std::wstring& frameworkPackageFullName); diff --git a/dev/Deployment/DeploymentTraceLogging.h b/dev/Deployment/DeploymentTraceLogging.h index fcfe12bdd1..6686078237 100644 --- a/dev/Deployment/DeploymentTraceLogging.h +++ b/dev/Deployment/DeploymentTraceLogging.h @@ -20,7 +20,7 @@ class WindowsAppRuntimeDeployment_TraceLogger final : public wil::TraceLoggingPr public: BEGIN_COMPLIANT_CRITICAL_DATA_ACTIVITY_CLASS(Initialize, PDT_ProductAndServicePerformance); - void StartActivity(bool forceDeployment, bool isElevated, bool isPackagedProcess, DWORD integrityLevel) + void StartActivity(bool forceDeployment, bool isElevated, bool isPackagedProcess, bool isFullTrustPackage, DWORD integrityLevel, bool isRepair) { // Clear the process-wide callback set in Start wil::SetResultLoggingCallback(nullptr); @@ -33,7 +33,9 @@ class WindowsAppRuntimeDeployment_TraceLogger final : public wil::TraceLoggingPr TraceLoggingValue(forceDeployment, "forceDeployment"), TraceLoggingValue(isElevated, "isElevated"), TraceLoggingValue(isPackagedProcess, "isPackagedProcess"), - TraceLoggingValue(integrityLevel, "integrityLevel")); + TraceLoggingValue(isFullTrustPackage, "isFullTrustPackage"), + TraceLoggingValue(integrityLevel, "integrityLevel"), + TraceLoggingValue(isRepair, "isRepairAPI")); } void StopWithResult( HRESULT hresult, @@ -48,7 +50,7 @@ class WindowsAppRuntimeDeployment_TraceLogger final : public wil::TraceLoggingPr HRESULT deploymentErrorExtendedHResult, PCWSTR deploymentErrorText, GUID deploymentErrorActivityId, - bool isFullTrustPackage) + bool useExistingPackageIfHigherVersion) { // Set a process-wide callback function for WIL to call each time it logs a failure. wil::SetResultLoggingCallback(nullptr); @@ -69,7 +71,7 @@ class WindowsAppRuntimeDeployment_TraceLogger final : public wil::TraceLoggingPr TraceLoggingValue(deploymentErrorExtendedHResult, "DeploymentErrorExtendedHResult"), TraceLoggingValue(deploymentErrorText, "DeploymentErrorText"), TraceLoggingValue(deploymentErrorActivityId, "DeploymentErrorActivityId"), - TraceLoggingValue(isFullTrustPackage, "isFullTrustPackage")); + TraceLoggingValue(useExistingPackageIfHigherVersion, "useExistingPackageIfHigherVersion")); } else { diff --git a/dev/Deployment/PackageDefinitions.h b/dev/Deployment/PackageDefinitions.h index 3dd0b7f459..0d5d9d6643 100644 --- a/dev/Deployment/PackageDefinitions.h +++ b/dev/Deployment/PackageDefinitions.h @@ -14,6 +14,7 @@ #define WINDOWSAPPRUNTIME_PACKAGE_SUBTYPENAME_DDLM L"DDLM" #define WINDOWSAPPRUNTIME_FRAMEWORK_PACKAGE_FOLDER L"MSIX" #define WINDOWSAPPRUNTIME_FRAMEWORK_PACKAGE_FILE_EXTENSION L".msix" +#define WINDOWSAPPRUNTIME_PACKAGE_MANIFEST_FILE L"AppxManifest.xml" namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implementation { @@ -48,4 +49,7 @@ namespace winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::implem { WINDOWSAPPRUNTIME_PACKAGE_NAME_MAINPREFIX, WINDOWSAPPRUNTIME_PACKAGE_SUBTYPENAME_MAIN, PackageVersionType::Versioned }, { WINDOWSAPPRUNTIME_PACKAGE_NAME_SINGLETONPREFIX, WINDOWSAPPRUNTIME_PACKAGE_SUBTYPENAME_SINGLETON, PackageVersionType::Unversioned }, }; + + // Record existing target package full name(s) to deploy (specifically, re-register) if it's higher version than that of the current framework package version, in this global map. + static std::map g_existingTargetPackagesIfHigherVersion; } diff --git a/dev/DeploymentAgent/main.cpp b/dev/DeploymentAgent/main.cpp index e88662e3b2..0581eff290 100644 --- a/dev/DeploymentAgent/main.cpp +++ b/dev/DeploymentAgent/main.cpp @@ -6,7 +6,8 @@ using namespace winrt::Windows::Foundation; -int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int) +// argv[1] tells whether to use AddPackageAsync (argv[1] == "0") or RegisterPackageAsync (argv[1] == "1") on the path passed in argv[2]. +int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int) try { int argc{}; const std::wstring cmdLine{ GetCommandLineW() }; @@ -17,22 +18,30 @@ int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int) WindowsAppRuntimeDeploymentAgent_TraceLogger::FailedDueToBadArguments(argc); return HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS); } - std::filesystem::path packagePath{ argv[1] }; + + bool useExistingPackageIfHigherVersion{}; + if (argc >= 2) + { + if (CompareStringOrdinal(argv[1], -1, L"1", -1, TRUE) == CSTR_EQUAL) + { + useExistingPackageIfHigherVersion = true; + } + } bool forceDeployment{}; - if (argc >= 3) + if (argc >= 4) { - if (CompareStringOrdinal(argv[2], -1, L"1", -1, TRUE) == CSTR_EQUAL) + if (CompareStringOrdinal(argv[3], -1, L"1", -1, TRUE) == CSTR_EQUAL) { forceDeployment = true; } } GUID callerActivityId{}; - if (argc >= 4) + if (argc >= 5) { // Best effort for telemetry purpose and a failure doesn't affect functionality. - std::ignore = CLSIDFromString(argv[3], &callerActivityId); + std::ignore = CLSIDFromString(argv[4], &callerActivityId); } winrt::Windows::Management::Deployment::PackageManager packageManager; @@ -41,30 +50,43 @@ int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int) winrt::Windows::Management::Deployment::DeploymentOptions::ForceTargetApplicationShutdown : winrt::Windows::Management::Deployment::DeploymentOptions::None }; - const auto packagePathUri{ winrt::Windows::Foundation::Uri(packagePath.c_str()) }; - const auto deploymentOperation{ packageManager.AddPackageAsync(packagePathUri, nullptr, options) }; + winrt::Windows::Foundation::IAsyncOperationWithProgress deploymentOperation; + const auto pathUri{ winrt::Windows::Foundation::Uri(argv[2]) }; + if (useExistingPackageIfHigherVersion) + { + deploymentOperation = packageManager.RegisterPackageAsync(pathUri, nullptr, options); } + else + { + deploymentOperation = packageManager.AddPackageAsync(pathUri, nullptr, options); + } + deploymentOperation.get(); const auto deploymentResult{ deploymentOperation.GetResults() }; if (deploymentOperation.Status() != AsyncStatus::Completed) { - HRESULT hr = static_cast(deploymentOperation.ErrorCode()); - if (FAILED(hr)) + HRESULT deploymentOperationHResult = static_cast(deploymentOperation.ErrorCode()); + HRESULT deploymentOperationExtendedHResult = static_cast(deploymentResult.ExtendedErrorCode()); + if (FAILED(deploymentOperationHResult)) { WindowsAppRuntimeDeploymentAgent_TraceLogger::FailedInDeployment( - hr, - packagePath.wstring().c_str(), + deploymentOperationHResult, + argv[1], + argv[2], forceDeployment, callerActivityId, - deploymentResult.ExtendedErrorCode(), + deploymentOperationExtendedHResult, deploymentResult.ErrorText().c_str(), deploymentResult.ActivityId()); } - return deploymentResult.ExtendedErrorCode(); + return deploymentOperationExtendedHResult ? deploymentOperationExtendedHResult : deploymentOperationHResult; } WindowsAppRuntimeDeploymentAgent_TraceLogger::Success( - packagePath.wstring().c_str(), + argv[1], + argv[2], forceDeployment, callerActivityId); return S_OK; } +CATCH_RETURN() diff --git a/dev/DeploymentAgent/tracelogging.h b/dev/DeploymentAgent/tracelogging.h index 834b37f6ed..062f991ec0 100644 --- a/dev/DeploymentAgent/tracelogging.h +++ b/dev/DeploymentAgent/tracelogging.h @@ -15,10 +15,11 @@ class WindowsAppRuntimeDeploymentAgent_TraceLogger final : public wil::TraceLogg public: - DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM3( + DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM4( Success, PDT_ProductAndServicePerformance, - PCWSTR, packagePath, + bool, useExistingPackageIfHigherVersion, + PCWSTR, path, bool, forceDeployment, GUID, callerActivityId); @@ -27,11 +28,12 @@ class WindowsAppRuntimeDeploymentAgent_TraceLogger final : public wil::TraceLogg PDT_ProductAndServicePerformance, UINT32, argsCount); - DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM7( + DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM8( FailedInDeployment, PDT_ProductAndServicePerformance, HRESULT, hresult, - PCWSTR, packagePath, + bool, useExistingPackageIfHigherVersion, + PCWSTR, path, bool, forceDeployment, GUID, callerActivityId, HRESULT, deploymentExtendedError,