commit 804c1252382cd0435f9fde68b192d2012516c3d0
parent 657d33ce1702fc11f1fa64ca46c7dd6c07bd12ac
Author: yao-msft <50888816+yao-msft@users.noreply.github.com>
Date: Mon, 25 Sep 2023 20:54:12 -0700
Log Com invocation startup telemetry and delay auto update time when invoked from explorer (#3665)
- Add telemetry event for PackageManager class creation
- Delay source update time to 7 days by default when invoked from explorer
- Also fixes Source agreements related crash found when doing the above work
Diffstat:
13 files changed, 180 insertions(+), 48 deletions(-)
diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt
@@ -454,6 +454,7 @@ Syncy
sysrefcomp
systemnotsupported
Tagit
+taskhostw
TCpp
tcs
TEMPDIRECTORY
diff --git a/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp b/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp
@@ -173,6 +173,11 @@ namespace AppInstaller::Logging
m_executionStage = stage;
}
+ void TelemetryTraceLogger::SetUseSummary(bool useSummary) noexcept
+ {
+ m_useSummary = useSummary;
+ }
+
std::unique_ptr<TelemetryTraceLogger> TelemetryTraceLogger::CreateSubTraceLogger() const
{
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), !this->m_isInitialized);
diff --git a/src/AppInstallerCommonCore/Public/AppInstallerTelemetry.h b/src/AppInstallerCommonCore/Public/AppInstallerTelemetry.h
@@ -168,6 +168,8 @@ namespace AppInstaller::Logging
void SetExecutionStage(uint32_t stage) noexcept;
+ void SetUseSummary(bool useSummary) noexcept;
+
std::unique_ptr<TelemetryTraceLogger> CreateSubTraceLogger() const;
// Logs the failure info.
diff --git a/src/AppInstallerRepositoryCore/Public/winget/RepositorySource.h b/src/AppInstallerRepositoryCore/Public/winget/RepositorySource.h
@@ -17,6 +17,9 @@
namespace AppInstaller::Repository
{
+ // The interval is of 100 nano seconds precision.This is used by file date period and the Windows::Foundation::TimeSpan exposed in COM api.
+ using TimeSpan = std::chrono::duration<int64_t, std::ratio_multiply<std::ratio<100>, std::nano>>;
+
struct ISourceReference;
struct ISource;
@@ -219,6 +222,9 @@ namespace AppInstaller::Repository
// Set caller.
void SetCaller(std::string caller);
+ // Set background update check interval.
+ void SetBackgroundUpdateInterval(TimeSpan interval);
+
// Execute a search on the source.
SearchResult Search(const SearchRequest& request) const;
@@ -280,6 +286,7 @@ namespace AppInstaller::Repository
std::shared_ptr<ISource> m_source;
bool m_isSourceToBeAdded = false;
bool m_isComposite = false;
+ std::optional<TimeSpan> m_backgroundUpdateInterval;
mutable PackageTrackingCatalog m_trackingCatalog;
};
}
diff --git a/src/AppInstallerRepositoryCore/RepositorySource.cpp b/src/AppInstallerRepositoryCore/RepositorySource.cpp
@@ -97,25 +97,32 @@ namespace AppInstaller::Repository
}
// Determines whether (and logs why) a source should be updated before it is opened.
- bool ShouldUpdateBeforeOpen(const SourceDetails& details)
+ bool ShouldUpdateBeforeOpen(const SourceDetails& details, std::optional<TimeSpan> backgroundUpdateInterval)
{
if (!ContainsAvailablePackagesInternal(details.Origin))
{
return false;
}
- constexpr static auto s_ZeroMins = 0min;
- auto autoUpdateTime = User().Get<Setting::AutoUpdateTimeInMinutes>();
+ constexpr static TimeSpan s_ZeroMins = 0min;
+ TimeSpan autoUpdateTime;
+ if (backgroundUpdateInterval.has_value())
+ {
+ autoUpdateTime = backgroundUpdateInterval.value();
+ }
+ else
+ {
+ autoUpdateTime = User().Get<Setting::AutoUpdateTimeInMinutes>();
+ }
// A value of zero means no auto update, to get update the source run `winget update`
if (autoUpdateTime != s_ZeroMins)
{
- auto autoUpdateTimeMins = std::chrono::minutes(autoUpdateTime);
auto timeSinceLastUpdate = std::chrono::system_clock::now() - details.LastUpdateTime;
- if (timeSinceLastUpdate > autoUpdateTimeMins)
+ if (timeSinceLastUpdate > autoUpdateTime)
{
AICLI_LOG(Repo, Info, << "Source past auto update time [" <<
- std::chrono::duration_cast<std::chrono::minutes>(autoUpdateTimeMins).count() << " mins]; it has been at least " <<
+ std::chrono::duration_cast<std::chrono::minutes>(autoUpdateTime).count() << " mins]; it has been at least " <<
std::chrono::duration_cast<std::chrono::minutes>(timeSinceLastUpdate).count() << " mins");
return true;
}
@@ -278,7 +285,16 @@ namespace AppInstaller::Repository
{
THROW_HR_IF(APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY, !IsWellKnownSourceEnabled(source));
- SourceDetails details = GetWellKnownSourceDetailsInternal(source);
+ auto details = GetWellKnownSourceDetailsInternal(source);
+
+ // Populate metadata
+ SourceList sourceList;
+ auto sourceDetailsWithMetadata = sourceList.GetSource(details.Name);
+ if (sourceDetailsWithMetadata)
+ {
+ sourceDetailsWithMetadata->CopyMetadataFieldsTo(details);
+ }
+
m_sourceReferences.emplace_back(CreateSourceFromDetails(details));
}
@@ -454,6 +470,11 @@ namespace AppInstaller::Repository
}
}
+ void Source::SetBackgroundUpdateInterval(TimeSpan interval)
+ {
+ m_backgroundUpdateInterval = interval;
+ }
+
SearchResult Source::Search(const SearchRequest& request) const
{
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), !m_source);
@@ -539,7 +560,7 @@ namespace AppInstaller::Repository
for (auto& sourceReference : m_sourceReferences)
{
auto& details = sourceReference->GetDetails();
- if (ShouldUpdateBeforeOpen(details))
+ if (ShouldUpdateBeforeOpen(details, m_backgroundUpdateInterval))
{
try
{
diff --git a/src/Microsoft.Management.Deployment/Helpers.cpp b/src/Microsoft.Management.Deployment/Helpers.cpp
@@ -118,4 +118,54 @@ namespace winrt::Microsoft::Management::Deployment::implementation
return {};
}
+
+ std::string GetCallerName()
+ {
+ // See if caller name is set by caller
+ std::string callerName = GetComCallerName("");
+
+ // Get process string
+ if (callerName.empty())
+ {
+ try
+ {
+ auto [hrGetCallerId, callerProcessId] = GetCallerProcessId();
+ if (SUCCEEDED(hrGetCallerId))
+ {
+ callerName = AppInstaller::Utility::ConvertToUTF8(TryGetCallerProcessInfo(callerProcessId));
+ }
+ }
+ CATCH_LOG();
+ }
+
+ if (callerName.empty())
+ {
+ callerName = "UnknownComCaller";
+ }
+
+ return callerName;
+ }
+
+ bool IsBackgroundProcessForPolicy()
+ {
+ bool isBackgroundProcessForPolicy = false;
+ try
+ {
+ auto [hrGetCallerId, callerProcessId] = GetCallerProcessId();
+ if (SUCCEEDED(hrGetCallerId) && callerProcessId != GetCurrentProcessId())
+ {
+ // OutOfProc case, we check for explorer.exe
+ auto callerNameWide = AppInstaller::Utility::ConvertToUTF16(GetCallerName());
+ auto processName = AppInstaller::Utility::ConvertToUTF8(std::filesystem::path{ callerNameWide }.filename().wstring());
+ if (::AppInstaller::Utility::CaseInsensitiveEquals("explorer.exe", processName) ||
+ ::AppInstaller::Utility::CaseInsensitiveEquals("taskhostw.exe", processName))
+ {
+ isBackgroundProcessForPolicy = true;
+ }
+ }
+ }
+ CATCH_LOG();
+
+ return isBackgroundProcessForPolicy;
+ }
}
\ No newline at end of file
diff --git a/src/Microsoft.Management.Deployment/Helpers.h b/src/Microsoft.Management.Deployment/Helpers.h
@@ -18,4 +18,6 @@ namespace winrt::Microsoft::Management::Deployment::implementation
HRESULT EnsureComCallerHasCapability(Capability requiredCapability);
std::pair<HRESULT, DWORD> GetCallerProcessId();
std::wstring TryGetCallerProcessInfo(DWORD callerProcessId);
+ std::string GetCallerName();
+ bool IsBackgroundProcessForPolicy();
}
diff --git a/src/Microsoft.Management.Deployment/PackageCatalogReference.cpp b/src/Microsoft.Management.Deployment/PackageCatalogReference.cpp
@@ -15,42 +15,28 @@
#include <winget/GroupPolicy.h>
#include <AppInstallerErrors.h>
#include <AppInstallerStrings.h>
+#include <winget/UserSettings.h>
#include <Helpers.h>
namespace winrt::Microsoft::Management::Deployment::implementation
{
- namespace
+ void PackageCatalogReference::Initialize(winrt::Microsoft::Management::Deployment::PackageCatalogInfo packageCatalogInfo, ::AppInstaller::Repository::Source sourceReference)
{
- std::string GetCallerName()
+ m_info = packageCatalogInfo;
+ m_sourceReference = std::move(sourceReference);
+ m_packageCatalogBackgroundUpdateInterval = ::AppInstaller::Settings::User().Get<::AppInstaller::Settings::Setting::AutoUpdateTimeInMinutes>();
+
+ if (IsBackgroundProcessForPolicy())
{
- // See if caller name is set by caller
- static auto callerName = GetComCallerName("");
+ static constexpr winrt::Windows::Foundation::TimeSpan s_PackageCatalogUpdateIntervalDelay_Base = 168h; //1 week
- // Get process string
- if (callerName.empty())
- {
- try
- {
- auto [hrGetCallerId, callerProcessId] = GetCallerProcessId();
- THROW_IF_FAILED(hrGetCallerId);
- callerName = AppInstaller::Utility::ConvertToUTF8(TryGetCallerProcessInfo(callerProcessId));
- }
- CATCH_LOG();
- }
+ // Add a bit of randomness to the default interval time
+ std::default_random_engine randomEngine(std::random_device{}());
+ std::uniform_int_distribution<long long> distribution(0, 604800);
- if (callerName.empty())
- {
- callerName = "UnknownComCaller";
- }
-
- return callerName;
+ m_packageCatalogBackgroundUpdateInterval = s_PackageCatalogUpdateIntervalDelay_Base + std::chrono::seconds(distribution(randomEngine));
}
}
- void PackageCatalogReference::Initialize(winrt::Microsoft::Management::Deployment::PackageCatalogInfo packageCatalogInfo, ::AppInstaller::Repository::Source sourceReference)
- {
- m_info = packageCatalogInfo;
- m_sourceReference = std::move(sourceReference);
- }
void PackageCatalogReference::Initialize(winrt::Microsoft::Management::Deployment::CreateCompositePackageCatalogOptions options)
{
m_compositePackageCatalogOptions = options;
@@ -89,10 +75,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
return GetConnectCatalogErrorResult();
}
- if (!m_acceptSourceAgreements && SourceAgreements().Size() != 0)
- {
- return GetConnectSourceAgreementsNotAcceptedErrorResult();
- }
+ std::string callerName = GetCallerName();
::AppInstaller::ProgressCallback progress;
::AppInstaller::Repository::Source source;
@@ -103,9 +86,15 @@ namespace winrt::Microsoft::Management::Deployment::implementation
for (uint32_t i = 0; i < m_compositePackageCatalogOptions.Catalogs().Size(); ++i)
{
auto catalog = m_compositePackageCatalogOptions.Catalogs().GetAt(i);
+ if (!catalog.AcceptSourceAgreements() && catalog.SourceAgreements().Size() != 0)
+ {
+ return GetConnectSourceAgreementsNotAcceptedErrorResult();
+ }
+
winrt::Microsoft::Management::Deployment::implementation::PackageCatalogReference* catalogImpl = get_self<winrt::Microsoft::Management::Deployment::implementation::PackageCatalogReference>(catalog);
auto copy = catalogImpl->m_sourceReference;
- copy.SetCaller(GetCallerName());
+ copy.SetCaller(callerName);
+ copy.SetBackgroundUpdateInterval(catalog.PackageCatalogBackgroundUpdateInterval());
copy.Open(progress);
remoteSources.emplace_back(std::move(copy));
}
@@ -140,8 +129,14 @@ namespace winrt::Microsoft::Management::Deployment::implementation
}
else
{
+ if (!m_acceptSourceAgreements && SourceAgreements().Size() != 0)
+ {
+ return GetConnectSourceAgreementsNotAcceptedErrorResult();
+ }
+
source = m_sourceReference;
- source.SetCaller(GetCallerName());
+ source.SetCaller(callerName);
+ source.SetBackgroundUpdateInterval(PackageCatalogBackgroundUpdateInterval());
source.Open(progress);
}
@@ -171,11 +166,14 @@ namespace winrt::Microsoft::Management::Deployment::implementation
std::call_once(m_sourceAgreementsOnceFlag,
[&]()
{
- for (auto const& agreement : m_sourceReference.GetInformation().SourceAgreements)
+ if (!IsComposite())
{
- auto sourceAgreement = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::SourceAgreement>>();
- sourceAgreement->Initialize(agreement);
- m_sourceAgreements.Append(*sourceAgreement);
+ for (auto const& agreement : m_sourceReference.GetInformation().SourceAgreements)
+ {
+ auto sourceAgreement = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::SourceAgreement>>();
+ sourceAgreement->Initialize(agreement);
+ m_sourceAgreements.Append(*sourceAgreement);
+ }
}
});
return m_sourceAgreements.GetView();
@@ -207,10 +205,28 @@ namespace winrt::Microsoft::Management::Deployment::implementation
}
void PackageCatalogReference::AcceptSourceAgreements(bool value)
{
+ if (IsComposite())
+ {
+ // Can't set AcceptSourceAgreements on a composite. Callers should set it on each non-composite PackageCatalogReference in the composite.
+ throw winrt::hresult_illegal_state_change();
+ }
m_acceptSourceAgreements = value;
}
bool PackageCatalogReference::AcceptSourceAgreements()
{
return m_acceptSourceAgreements;
}
+ void PackageCatalogReference::PackageCatalogBackgroundUpdateInterval(winrt::Windows::Foundation::TimeSpan const& value)
+ {
+ if (IsComposite())
+ {
+ // Can't set PackageCatalogBackgroundUpdateInterval on a composite. Callers should set it on each non-composite PackageCatalogReference in the composite.
+ throw winrt::hresult_illegal_state_change();
+ }
+ m_packageCatalogBackgroundUpdateInterval = value;
+ }
+ winrt::Windows::Foundation::TimeSpan PackageCatalogReference::PackageCatalogBackgroundUpdateInterval()
+ {
+ return m_packageCatalogBackgroundUpdateInterval;
+ }
}
diff --git a/src/Microsoft.Management.Deployment/PackageCatalogReference.h b/src/Microsoft.Management.Deployment/PackageCatalogReference.h
@@ -25,6 +25,9 @@ namespace winrt::Microsoft::Management::Deployment::implementation
// Contract 6.0
bool AcceptSourceAgreements();
void AcceptSourceAgreements(bool value);
+ // Contract 8.0
+ winrt::Windows::Foundation::TimeSpan PackageCatalogBackgroundUpdateInterval();
+ void PackageCatalogBackgroundUpdateInterval(winrt::Windows::Foundation::TimeSpan const& value);
#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
private:
@@ -35,6 +38,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
std::optional<std::string> m_additionalPackageCatalogArguments;
bool m_acceptSourceAgreements = true;
std::once_flag m_sourceAgreementsOnceFlag;
+ winrt::Windows::Foundation::TimeSpan m_packageCatalogBackgroundUpdateInterval = winrt::Windows::Foundation::TimeSpan::zero();
#endif
};
}
diff --git a/src/Microsoft.Management.Deployment/PackageManager.cpp b/src/Microsoft.Management.Deployment/PackageManager.cpp
@@ -39,6 +39,17 @@ using namespace ::AppInstaller::CLI::Execution;
namespace winrt::Microsoft::Management::Deployment::implementation
{
+ PackageManager::PackageManager()
+ {
+ auto previousThreadGlobals = m_threadGlobals.SetForCurrentThread();
+ // Immediately reset as we only want the thread globals for logging within this object.
+ previousThreadGlobals.reset();
+ // TODO: Disable summary until we log more and have meaningful summary to be sent in the future.
+ m_threadGlobals.GetTelemetryLogger().SetUseSummary(false);
+ m_threadGlobals.GetTelemetryLogger().SetCaller(GetCallerName());
+ m_threadGlobals.GetTelemetryLogger().LogStartup(true);
+ }
+
winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Management::Deployment::PackageCatalogReference> PackageManager::GetPackageCatalogs()
{
Windows::Foundation::Collections::IVector<Microsoft::Management::Deployment::PackageCatalogReference> catalogs{ winrt::single_threaded_vector<Microsoft::Management::Deployment::PackageCatalogReference>() };
diff --git a/src/Microsoft.Management.Deployment/PackageManager.h b/src/Microsoft.Management.Deployment/PackageManager.h
@@ -3,6 +3,7 @@
#pragma once
#include "PackageManager.g.h"
#include "Public/ComClsids.h"
+#include <winget/ThreadGlobals.h>
#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
// Forward declaration
@@ -17,7 +18,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
[uuid(WINGET_OUTOFPROC_COM_CLSID_PackageManager)]
struct PackageManager : PackageManagerT<PackageManager>
{
- PackageManager() = default;
+ PackageManager();
winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Management::Deployment::PackageCatalogReference> GetPackageCatalogs();
winrt::Microsoft::Management::Deployment::PackageCatalogReference GetPredefinedPackageCatalog(winrt::Microsoft::Management::Deployment::PredefinedPackageCatalog const& predefinedPackageCatalog);
@@ -41,6 +42,11 @@ namespace winrt::Microsoft::Management::Deployment::implementation
DownloadPackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::DownloadOptions options);
winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::DownloadResult, winrt::Microsoft::Management::Deployment::PackageDownloadProgress>
GetDownloadProgress(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::PackageCatalogInfo catalogInfo);
+
+#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
+ private:
+ AppInstaller::ThreadLocalStorage::WingetThreadGlobals m_threadGlobals;
+#endif
};
#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
diff --git a/src/Microsoft.Management.Deployment/PackageManager.idl b/src/Microsoft.Management.Deployment/PackageManager.idl
@@ -2,7 +2,7 @@
// Licensed under the MIT License.
namespace Microsoft.Management.Deployment
{
- [contractversion(7)]
+ [contractversion(8)]
apicontract WindowsPackageManagerContract{};
/// State of the install
@@ -749,6 +749,12 @@ namespace Microsoft.Management.Deployment
Boolean AcceptSourceAgreements;
}
+
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 8)]
+ {
+ /// Time interval for package catalog to check for an update. Setting to zero will disable the check for update.
+ Windows.Foundation.TimeSpan PackageCatalogBackgroundUpdateInterval;
+ }
}
/// Catalogs with PackageCatalogOrigin Predefined
diff --git a/src/Microsoft.Management.Deployment/pch.h b/src/Microsoft.Management.Deployment/pch.h
@@ -5,4 +5,5 @@
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
-#include <mutex>-
\ No newline at end of file
+#include <mutex>
+#include <random>+
\ No newline at end of file