1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // This macro is used in <wrl/module.h>. Since only the COM functionality is
6 // used here (while WinRT isn't being used), define this macro to optimize
7 // compilation of <wrl/module.h> for COM-only.
8 #ifndef __WRL_CLASSIC_COM_STRICT__
9 #define __WRL_CLASSIC_COM_STRICT__
10 #endif // __WRL_CLASSIC_COM_STRICT__
12 #include "chrome/notification_helper/com_server_module.h"
14 #include <wrl/module.h>
16 #include <type_traits>
18 #include "base/metrics/histogram_macros.h"
19 #include "chrome/install_static/install_util.h"
20 #include "chrome/notification_helper/notification_activator.h"
21 #include "chrome/notification_helper/trace_util.h"
23 namespace mswr = Microsoft::WRL;
27 // These values are persisted to logs. Entries should not be renumbered and
28 // numeric values should never be reused.
29 enum class ComServerModuleStatus {
31 FACTORY_CREATION_FAILED = 1,
32 ICLASSFACTORY_OBJECT_CREATION_FAILED = 2,
33 REGISTRATION_FAILED = 3,
34 UNREGISTRATION_FAILED = 4,
35 COUNT // Must be the final value.
38 void LogComServerModuleHistogram(ComServerModuleStatus status) {
39 UMA_HISTOGRAM_ENUMERATION(
40 "Notifications.NotificationHelper.ComServerModuleStatus", status,
41 ComServerModuleStatus::COUNT);
46 namespace notification_helper {
48 // The reset policy of the event MUST BE set to MANUAL to avoid signaling the
49 // event in IsSignaled() itself, which is called by IsEventSignaled().
50 ComServerModule::ComServerModule()
51 : object_zero_count_(base::WaitableEvent::ResetPolicy::MANUAL,
52 base::WaitableEvent::InitialState::NOT_SIGNALED) {}
54 ComServerModule::~ComServerModule() = default;
56 HRESULT ComServerModule::Run() {
57 HRESULT hr = RegisterClassObjects();
59 WaitForZeroObjectCount();
60 hr = UnregisterClassObjects();
63 LogComServerModuleHistogram(ComServerModuleStatus::SUCCESS);
68 HRESULT ComServerModule::RegisterClassObjects() {
69 // Create an out-of-proc COM module with caching disabled. The supplied
70 // method is invoked when the last instance object of the module is released.
71 auto& module = mswr::Module<mswr::OutOfProcDisableCaching>::Create(
72 this, &ComServerModule::SignalObjectCountZero);
74 // Usually COM module classes statically define their CLSID at compile time
75 // through the use of various macros, and WRL::Module internals takes care of
76 // creating the class objects and registering them. However, we need to
77 // register the same object with different CLSIDs depending on a runtime
78 // setting, so we handle that logic here.
80 mswr::ComPtr<IUnknown> factory;
81 unsigned int flags = mswr::ModuleType::OutOfProcDisableCaching;
83 HRESULT hr = mswr::Details::CreateClassFactory<
84 mswr::SimpleClassFactory<NotificationActivator>>(
85 &flags, nullptr, __uuidof(IClassFactory), &factory);
87 LogComServerModuleHistogram(ComServerModuleStatus::FACTORY_CREATION_FAILED);
88 Trace(L"%hs(Factory creation failed; hr: 0x%08X)\n", __func__, hr);
92 mswr::ComPtr<IClassFactory> class_factory;
93 hr = factory.As(&class_factory);
95 LogComServerModuleHistogram(
96 ComServerModuleStatus::ICLASSFACTORY_OBJECT_CREATION_FAILED);
97 Trace(L"%hs(IClassFactory object creation failed; hr: 0x%08X)\n", __func__,
102 // All pointers in this array are unowned. Do not release them.
103 IClassFactory* class_factories[] = {class_factory.Get()};
104 static_assert(std::extent<decltype(cookies_)>() == std::size(class_factories),
105 "Arrays cookies_ and class_factories must be the same size.");
107 IID class_ids[] = {install_static::GetToastActivatorClsid()};
108 static_assert(std::extent<decltype(cookies_)>() == std::size(class_ids),
109 "Arrays cookies_ and class_ids must be the same size.");
111 hr = module.RegisterCOMObject(nullptr, class_ids, class_factories, cookies_,
112 std::extent<decltype(cookies_)>());
114 LogComServerModuleHistogram(ComServerModuleStatus::REGISTRATION_FAILED);
115 Trace(L"%hs(NotificationActivator registration failed; hr: 0x%08X)\n",
122 HRESULT ComServerModule::UnregisterClassObjects() {
123 auto& module = mswr::Module<mswr::OutOfProcDisableCaching>::GetModule();
124 HRESULT hr = module.UnregisterCOMObject(nullptr, cookies_,
125 std::extent<decltype(cookies_)>());
127 LogComServerModuleHistogram(ComServerModuleStatus::UNREGISTRATION_FAILED);
128 Trace(L"%hs(NotificationActivator unregistration failed; hr: 0x%08X)\n",
134 bool ComServerModule::IsEventSignaled() {
135 return object_zero_count_.IsSignaled();
138 void ComServerModule::WaitForZeroObjectCount() {
139 object_zero_count_.Wait();
142 void ComServerModule::SignalObjectCountZero() {
143 object_zero_count_.Signal();
146 } // namespace notification_helper