commit 8996d9b97968a6af595f88b47f813850ee708926
parent 43686bbe75eb257ccba95cc9e47f713691ee1da9
Author: JohnMcPMS <johnmcp@microsoft.com>
Date: Tue, 3 Sep 2024 15:21:40 -0700
Add diagnostics to dynamic factory (#4757)
## Change
Adds diagnostics to the dynamic factory.
Diffstat:
1 file changed, 100 insertions(+), 38 deletions(-)
diff --git a/src/AppInstallerCLICore/ConfigurationDynamicRuntimeFactory.cpp b/src/AppInstallerCLICore/ConfigurationDynamicRuntimeFactory.cpp
@@ -36,17 +36,49 @@ namespace AppInstaller::CLI::ConfigurationRemoting
}
#endif
+ // This is implemented completely in the packaged context for now, if we want to make it more configurable, we will probably want to move it to configuration and
+ // have this implementation leverage that one with an event handler for the packaged specifics.
+ // TODO: Add SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties and pass values along to sets on creation
+ // In turn, any properties must only be set via the command line (or eventual UI requests to the user).
+ struct DynamicFactory : winrt::implements<DynamicFactory, IConfigurationSetProcessorFactory, winrt::cloaked<WinRT::ILifetimeWatcher>>, WinRT::LifetimeWatcherBase
+ {
+ DynamicFactory();
+
+ IConfigurationSetProcessor CreateSetProcessor(const ConfigurationSet& configurationSet);
+
+ winrt::event_token Diagnostics(const EventHandler<IDiagnosticInformation>& handler);
+ void Diagnostics(const winrt::event_token& token) noexcept;
+
+ DiagnosticLevel MinimumLevel();
+ void MinimumLevel(DiagnosticLevel value);
+
+ HRESULT STDMETHODCALLTYPE SetLifetimeWatcher(IUnknown* watcher);
+
+ IConfigurationSetProcessorFactory& DefaultFactory();
+
+ void SendDiagnostics(const IDiagnosticInformation& information);
+
+ private:
+ IConfigurationSetProcessorFactory m_defaultRemoteFactory;
+ winrt::event<EventHandler<IDiagnosticInformation>> m_diagnostics;
+ IConfigurationSetProcessorFactory::Diagnostics_revoker m_factoryDiagnosticsEventRevoker;
+ std::mutex m_diagnosticsMutex;
+ DiagnosticLevel m_minimumLevel = DiagnosticLevel::Informational;
+ };
+
struct DynamicProcessorInfo
{
IConfigurationSetProcessorFactory Factory;
IConfigurationSetProcessor Processor;
+ IConfigurationSetProcessorFactory::Diagnostics_revoker DiagnosticsEventRevoker;
};
struct DynamicSetProcessor : winrt::implements<DynamicSetProcessor, IConfigurationSetProcessor>
{
using ProcessorMap = std::map<Security::IntegrityLevel, DynamicProcessorInfo>;
- DynamicSetProcessor(IConfigurationSetProcessorFactory defaultRemoteFactory, IConfigurationSetProcessor defaultRemoteSetProcessor, const ConfigurationSet& configurationSet) : m_configurationSet(configurationSet)
+ DynamicSetProcessor(winrt::com_ptr<DynamicFactory> dynamicFactory, IConfigurationSetProcessor defaultRemoteSetProcessor, const ConfigurationSet& configurationSet) :
+ m_dynamicFactory(std::move(dynamicFactory)), m_configurationSet(configurationSet)
{
#ifndef AICLI_DISABLE_TEST_HOOKS
m_enableTestMode = GetConfigurationSetMetadataOverride(m_configurationSet, EnableTestModeTestGuid);
@@ -58,7 +90,7 @@ namespace AppInstaller::CLI::ConfigurationRemoting
m_currentIntegrityLevel = Security::GetEffectiveIntegrityLevel();
#endif
- m_setProcessors.emplace(m_currentIntegrityLevel, DynamicProcessorInfo{ defaultRemoteFactory, defaultRemoteSetProcessor });
+ m_setProcessors.emplace(m_currentIntegrityLevel, DynamicProcessorInfo{ m_dynamicFactory->DefaultFactory(), defaultRemoteSetProcessor});
}
IConfigurationUnitProcessorDetails GetUnitProcessorDetails(const ConfigurationUnit& unit, ConfigurationUnitDetailFlags detailFlags)
@@ -212,6 +244,7 @@ namespace AppInstaller::CLI::ConfigurationRemoting
ProcessorMap::iterator CreateSetProcessorForIntegrityLevel(Security::IntegrityLevel integrityLevel)
{
IConfigurationSetProcessorFactory factory;
+ IConfigurationSetProcessorFactory::Diagnostics_revoker factoryDiagnosticsEventRevoker;
// If we got here, the only option is that the current integrity level is not High.
if (integrityLevel == Security::IntegrityLevel::High)
@@ -228,9 +261,22 @@ namespace AppInstaller::CLI::ConfigurationRemoting
THROW_WIN32(ERROR_NOT_SUPPORTED);
}
- return m_setProcessors.emplace(integrityLevel, DynamicProcessorInfo{ factory, factory.CreateSetProcessor(m_configurationSet) }).first;
+ if (factory)
+ {
+ factoryDiagnosticsEventRevoker = factory.Diagnostics(winrt::auto_revoke,
+ [weak_this{ get_weak() }](const IInspectable&, const IDiagnosticInformation& information)
+ {
+ if (auto strong_this{ weak_this.get() })
+ {
+ strong_this->m_dynamicFactory->SendDiagnostics(information);
+ }
+ });
+ }
+
+ return m_setProcessors.emplace(integrityLevel, DynamicProcessorInfo{ factory, factory.CreateSetProcessor(m_configurationSet), std::move(factoryDiagnosticsEventRevoker) }).first;
}
+ winrt::com_ptr<DynamicFactory> m_dynamicFactory;
Security::IntegrityLevel m_currentIntegrityLevel;
ProcessorMap m_setProcessors;
ConfigurationSet m_configurationSet;
@@ -243,52 +289,68 @@ namespace AppInstaller::CLI::ConfigurationRemoting
#endif
};
- // This is implemented completely in the packaged context for now, if we want to make it more configurable, we will probably want to move it to configuration and
- // have this implementation leverage that one with an event handler for the packaged specifics.
- // TODO: Add SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties and pass values along to sets on creation
- // In turn, any properties must only be set via the command line (or eventual UI requests to the user).
- struct DynamicFactory : winrt::implements<DynamicFactory, IConfigurationSetProcessorFactory, winrt::cloaked<WinRT::ILifetimeWatcher>>, WinRT::LifetimeWatcherBase
+ DynamicFactory::DynamicFactory()
{
- DynamicFactory()
- {
- m_defaultRemoteFactory = CreateOutOfProcessFactory();
- }
+ m_defaultRemoteFactory = CreateOutOfProcessFactory();
- IConfigurationSetProcessor CreateSetProcessor(const ConfigurationSet& configurationSet)
+ if (m_defaultRemoteFactory)
{
- return winrt::make<DynamicSetProcessor>(m_defaultRemoteFactory, m_defaultRemoteFactory.CreateSetProcessor(configurationSet), configurationSet);
+ m_factoryDiagnosticsEventRevoker = m_defaultRemoteFactory.Diagnostics(winrt::auto_revoke,
+ [weak_this{ get_weak() }](const IInspectable&, const IDiagnosticInformation& information)
+ {
+ if (auto strong_this{ weak_this.get() })
+ {
+ strong_this->SendDiagnostics(information);
+ }
+ });
}
+ }
- winrt::event_token Diagnostics(const EventHandler<IDiagnosticInformation>&)
- {
- // TODO: If we want diagnostics here, see ConfigurationProcessor for how to integrate nicely with the infrastructure.
- // Best solution is probably to create a base class that both can leverage to handle it cleanly.
- return {};
- }
+ IConfigurationSetProcessor DynamicFactory::CreateSetProcessor(const ConfigurationSet& configurationSet)
+ {
+ return winrt::make<DynamicSetProcessor>(get_strong(), m_defaultRemoteFactory.CreateSetProcessor(configurationSet), configurationSet);
+ }
- void Diagnostics(const winrt::event_token&) noexcept
- {
- }
+ winrt::event_token DynamicFactory::Diagnostics(const EventHandler<IDiagnosticInformation>& handler)
+ {
+ return m_diagnostics.add(handler);
+ }
- DiagnosticLevel MinimumLevel()
- {
- return m_minimumLevel;
- }
+ void DynamicFactory::Diagnostics(const winrt::event_token& token) noexcept
+ {
+ m_diagnostics.remove(token);
+ }
- void MinimumLevel(DiagnosticLevel value)
- {
- m_minimumLevel = value;
- }
+ DiagnosticLevel DynamicFactory::MinimumLevel()
+ {
+ return m_minimumLevel;
+ }
- HRESULT STDMETHODCALLTYPE SetLifetimeWatcher(IUnknown* watcher)
+ void DynamicFactory::MinimumLevel(DiagnosticLevel value)
+ {
+ m_minimumLevel = value;
+ }
+
+ HRESULT STDMETHODCALLTYPE DynamicFactory::SetLifetimeWatcher(IUnknown* watcher)
+ {
+ return WinRT::LifetimeWatcherBase::SetLifetimeWatcher(watcher);
+ }
+
+ IConfigurationSetProcessorFactory& DynamicFactory::DefaultFactory()
+ {
+ return m_defaultRemoteFactory;
+ }
+
+ void DynamicFactory::SendDiagnostics(const IDiagnosticInformation& information) try
+ {
+ if (information.Level() >= m_minimumLevel)
{
- return WinRT::LifetimeWatcherBase::SetLifetimeWatcher(watcher);
+ std::lock_guard<std::mutex> lock{ m_diagnosticsMutex };
+ m_diagnostics(*this, information);
}
-
- private:
- IConfigurationSetProcessorFactory m_defaultRemoteFactory;
- DiagnosticLevel m_minimumLevel = DiagnosticLevel::Informational;
- };
+ }
+ // While diagnostics can be important, a failure to send them should not cause additional issues.
+ catch (...) {}
}
winrt::Microsoft::Management::Configuration::IConfigurationSetProcessorFactory CreateDynamicRuntimeFactory()