Skip to content

Commit

Permalink
Log Com invocation startup telemetry and delay auto update time when …
Browse files Browse the repository at this point in the history
…invoked from explorer (microsoft#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
  • Loading branch information
yao-msft authored Sep 26, 2023
1 parent 657d33c commit 804c125
Show file tree
Hide file tree
Showing 13 changed files with 179 additions and 47 deletions.
1 change: 1 addition & 0 deletions .github/actions/spelling/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ Syncy
sysrefcomp
systemnotsupported
Tagit
taskhostw
TCpp
tcs
TEMPDIRECTORY
Expand Down
5 changes: 5 additions & 0 deletions src/AppInstallerCommonCore/AppInstallerTelemetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/AppInstallerCommonCore/Public/AppInstallerTelemetry.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
};
}
37 changes: 29 additions & 8 deletions src/AppInstallerRepositoryCore/RepositorySource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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));
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
{
Expand Down
50 changes: 50 additions & 0 deletions src/Microsoft.Management.Deployment/Helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
2 changes: 2 additions & 0 deletions src/Microsoft.Management.Deployment/Helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
88 changes: 52 additions & 36 deletions src/Microsoft.Management.Deployment/PackageCatalogReference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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));
}
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
}
}
4 changes: 4 additions & 0 deletions src/Microsoft.Management.Deployment/PackageCatalogReference.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
};
}
11 changes: 11 additions & 0 deletions src/Microsoft.Management.Deployment/PackageManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>() };
Expand Down
Loading

0 comments on commit 804c125

Please sign in to comment.