| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // This macro is used in <wrl/module.h>. Since only the COM functionality is |
| // used here (while WinRT isn't being used), define this macro to optimize |
| // compilation of <wrl/module.h> for COM-only. |
| #ifndef __WRL_CLASSIC_COM_STRICT__ |
| #define __WRL_CLASSIC_COM_STRICT__ |
| #endif // __WRL_CLASSIC_COM_STRICT__ |
| |
| #include "chrome/notification_helper/com_server_module.h" |
| |
| #include <wrl/module.h> |
| |
| #include <type_traits> |
| |
| #include "base/metrics/histogram_macros.h" |
| #include "chrome/install_static/install_util.h" |
| #include "chrome/notification_helper/notification_activator.h" |
| #include "chrome/notification_helper/trace_util.h" |
| |
| namespace mswr = Microsoft::WRL; |
| |
| namespace { |
| |
| // These values are persisted to logs. Entries should not be renumbered and |
| // numeric values should never be reused. |
| enum class ComServerModuleStatus { |
| SUCCESS = 0, |
| FACTORY_CREATION_FAILED = 1, |
| ICLASSFACTORY_OBJECT_CREATION_FAILED = 2, |
| REGISTRATION_FAILED = 3, |
| UNREGISTRATION_FAILED = 4, |
| COUNT // Must be the final value. |
| }; |
| |
| void LogComServerModuleHistogram(ComServerModuleStatus status) { |
| UMA_HISTOGRAM_ENUMERATION( |
| "Notifications.NotificationHelper.ComServerModuleStatus", status, |
| ComServerModuleStatus::COUNT); |
| } |
| |
| } // namespace |
| |
| namespace notification_helper { |
| |
| // The reset policy of the event MUST BE set to MANUAL to avoid signaling the |
| // event in IsSignaled() itself, which is called by IsEventSignaled(). |
| ComServerModule::ComServerModule() |
| : object_zero_count_(base::WaitableEvent::ResetPolicy::MANUAL, |
| base::WaitableEvent::InitialState::NOT_SIGNALED) {} |
| |
| ComServerModule::~ComServerModule() = default; |
| |
| HRESULT ComServerModule::Run() { |
| HRESULT hr = RegisterClassObjects(); |
| if (SUCCEEDED(hr)) { |
| WaitForZeroObjectCount(); |
| hr = UnregisterClassObjects(); |
| } |
| if (SUCCEEDED(hr)) |
| LogComServerModuleHistogram(ComServerModuleStatus::SUCCESS); |
| |
| return hr; |
| } |
| |
| HRESULT ComServerModule::RegisterClassObjects() { |
| // Create an out-of-proc COM module with caching disabled. The supplied |
| // method is invoked when the last instance object of the module is released. |
| auto& module = mswr::Module<mswr::OutOfProcDisableCaching>::Create( |
| this, &ComServerModule::SignalObjectCountZero); |
| |
| // Usually COM module classes statically define their CLSID at compile time |
| // through the use of various macros, and WRL::Module internals takes care of |
| // creating the class objects and registering them. However, we need to |
| // register the same object with different CLSIDs depending on a runtime |
| // setting, so we handle that logic here. |
| |
| mswr::ComPtr<IUnknown> factory; |
| unsigned int flags = mswr::ModuleType::OutOfProcDisableCaching; |
| |
| HRESULT hr = mswr::Details::CreateClassFactory< |
| mswr::SimpleClassFactory<NotificationActivator>>( |
| &flags, nullptr, __uuidof(IClassFactory), &factory); |
| if (FAILED(hr)) { |
| LogComServerModuleHistogram(ComServerModuleStatus::FACTORY_CREATION_FAILED); |
| Trace(L"%hs(Factory creation failed; hr: 0x%08X)\n", __func__, hr); |
| return hr; |
| } |
| |
| mswr::ComPtr<IClassFactory> class_factory; |
| hr = factory.As(&class_factory); |
| if (FAILED(hr)) { |
| LogComServerModuleHistogram( |
| ComServerModuleStatus::ICLASSFACTORY_OBJECT_CREATION_FAILED); |
| Trace(L"%hs(IClassFactory object creation failed; hr: 0x%08X)\n", __func__, |
| hr); |
| return hr; |
| } |
| |
| // All pointers in this array are unowned. Do not release them. |
| IClassFactory* class_factories[] = {class_factory.Get()}; |
| static_assert(std::extent<decltype(cookies_)>() == std::size(class_factories), |
| "Arrays cookies_ and class_factories must be the same size."); |
| |
| IID class_ids[] = {install_static::GetToastActivatorClsid()}; |
| static_assert(std::extent<decltype(cookies_)>() == std::size(class_ids), |
| "Arrays cookies_ and class_ids must be the same size."); |
| |
| hr = module.RegisterCOMObject(nullptr, class_ids, class_factories, cookies_, |
| std::extent<decltype(cookies_)>()); |
| if (FAILED(hr)) { |
| LogComServerModuleHistogram(ComServerModuleStatus::REGISTRATION_FAILED); |
| Trace(L"%hs(NotificationActivator registration failed; hr: 0x%08X)\n", |
| __func__, hr); |
| } |
| |
| return hr; |
| } |
| |
| HRESULT ComServerModule::UnregisterClassObjects() { |
| auto& module = mswr::Module<mswr::OutOfProcDisableCaching>::GetModule(); |
| HRESULT hr = module.UnregisterCOMObject(nullptr, cookies_, |
| std::extent<decltype(cookies_)>()); |
| if (FAILED(hr)) { |
| LogComServerModuleHistogram(ComServerModuleStatus::UNREGISTRATION_FAILED); |
| Trace(L"%hs(NotificationActivator unregistration failed; hr: 0x%08X)\n", |
| __func__, hr); |
| } |
| return hr; |
| } |
| |
| bool ComServerModule::IsEventSignaled() { |
| return object_zero_count_.IsSignaled(); |
| } |
| |
| void ComServerModule::WaitForZeroObjectCount() { |
| object_zero_count_.Wait(); |
| } |
| |
| void ComServerModule::SignalObjectCountZero() { |
| object_zero_count_.Signal(); |
| } |
| |
| } // namespace notification_helper |