1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/updater/app/server/win/server.h"
6
7 #include <wrl/implements.h>
8
9 #include <algorithm>
10
11 #include "base/bind.h"
12 #include "base/callback_helpers.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/system/sys_info.h"
16 #include "base/task/task_traits.h"
17 #include "base/task/thread_pool.h"
18 #include "base/task/thread_pool/thread_pool_instance.h"
19 #include "base/threading/sequenced_task_runner_handle.h"
20 #include "chrome/updater/app/server/win/com_classes.h"
21 #include "chrome/updater/app/server/win/com_classes_legacy.h"
22 #include "chrome/updater/configurator.h"
23 #include "chrome/updater/control_service.h"
24 #include "chrome/updater/prefs.h"
25 #include "chrome/updater/update_service.h"
26 #include "chrome/updater/win/constants.h"
27 #include "chrome/updater/win/setup/uninstall.h"
28 #include "chrome/updater/win/wrl_module.h"
29 #include "components/prefs/pref_service.h"
30
31 namespace updater {
32
33 // Returns a leaky singleton of the App instance.
AppServerSingletonInstance()34 scoped_refptr<ComServerApp> AppServerSingletonInstance() {
35 return AppSingletonInstance<ComServerApp>();
36 }
37
ComServerApp()38 ComServerApp::ComServerApp()
39 : com_initializer_(base::win::ScopedCOMInitializer::kMTA) {}
40
41 ComServerApp::~ComServerApp() = default;
42
InitializeThreadPool()43 void ComServerApp::InitializeThreadPool() {
44 base::ThreadPoolInstance::Create(kThreadPoolName);
45
46 // Reuses the logic in base::ThreadPoolInstance::StartWithDefaultParams.
47 const int num_cores = base::SysInfo::NumberOfProcessors();
48 const int max_num_foreground_threads = std::max(3, num_cores - 1);
49 base::ThreadPoolInstance::InitParams init_params(max_num_foreground_threads);
50 init_params.common_thread_pool_environment = base::ThreadPoolInstance::
51 InitParams::CommonThreadPoolEnvironment::COM_MTA;
52 base::ThreadPoolInstance::Get()->Start(init_params);
53 }
54
RegisterClassObjects()55 HRESULT ComServerApp::RegisterClassObjects() {
56 auto& module = Microsoft::WRL::Module<Microsoft::WRL::OutOfProc>::GetModule();
57
58 Microsoft::WRL::ComPtr<IUnknown> factory;
59 unsigned int flags = Microsoft::WRL::ModuleType::OutOfProc;
60
61 HRESULT hr = Microsoft::WRL::Details::CreateClassFactory<
62 Microsoft::WRL::SimpleClassFactory<UpdaterImpl>>(
63 &flags, nullptr, __uuidof(IClassFactory), &factory);
64 if (FAILED(hr)) {
65 LOG(ERROR) << "Factory creation for UpdaterImpl failed; hr: " << hr;
66 return hr;
67 }
68
69 Microsoft::WRL::ComPtr<IClassFactory> class_factory_updater;
70 hr = factory.As(&class_factory_updater);
71 if (FAILED(hr)) {
72 LOG(ERROR) << "IClassFactory object creation failed; hr: " << hr;
73 return hr;
74 }
75 factory.Reset();
76
77 hr = Microsoft::WRL::Details::CreateClassFactory<
78 Microsoft::WRL::SimpleClassFactory<UpdaterControlImpl>>(
79 &flags, nullptr, __uuidof(IClassFactory), &factory);
80 if (FAILED(hr)) {
81 LOG(ERROR) << "Factory creation for UpdaterControlImpl failed; hr: " << hr;
82 return hr;
83 }
84
85 Microsoft::WRL::ComPtr<IClassFactory> class_factory_updater_control;
86 hr = factory.As(&class_factory_updater_control);
87 if (FAILED(hr)) {
88 LOG(ERROR) << "IClassFactory object creation failed; hr: " << hr;
89 return hr;
90 }
91 factory.Reset();
92
93 hr = Microsoft::WRL::Details::CreateClassFactory<
94 Microsoft::WRL::SimpleClassFactory<LegacyOnDemandImpl>>(
95 &flags, nullptr, __uuidof(IClassFactory), &factory);
96 if (FAILED(hr)) {
97 LOG(ERROR) << "Factory creation for LegacyOnDemandImpl failed; hr: " << hr;
98 return hr;
99 }
100
101 Microsoft::WRL::ComPtr<IClassFactory> class_factory_legacy_ondemand;
102 hr = factory.As(&class_factory_legacy_ondemand);
103 if (FAILED(hr)) {
104 LOG(ERROR) << "IClassFactory object creation failed; hr: " << hr;
105 return hr;
106 }
107
108 // The pointer in this array is unowned. Do not release it.
109 IClassFactory* class_factories[] = {class_factory_updater.Get(),
110 class_factory_updater_control.Get(),
111 class_factory_legacy_ondemand.Get()};
112 static_assert(
113 std::extent<decltype(cookies_)>() == base::size(class_factories),
114 "Arrays cookies_ and class_factories must be the same size.");
115
116 IID class_ids[] = {__uuidof(UpdaterClass), CLSID_UpdaterControlClass,
117 CLSID_GoogleUpdate3WebUserClass};
118 DCHECK_EQ(base::size(cookies_), base::size(class_ids));
119 static_assert(std::extent<decltype(cookies_)>() == base::size(class_ids),
120 "Arrays cookies_ and class_ids must be the same size.");
121
122 hr = module.RegisterCOMObject(nullptr, class_ids, class_factories, cookies_,
123 base::size(cookies_));
124 if (FAILED(hr)) {
125 LOG(ERROR) << "RegisterCOMObject failed; hr: " << hr;
126 return hr;
127 }
128
129 return hr;
130 }
131
UnregisterClassObjects()132 void ComServerApp::UnregisterClassObjects() {
133 auto& module = Microsoft::WRL::Module<Microsoft::WRL::OutOfProc>::GetModule();
134 const HRESULT hr =
135 module.UnregisterCOMObject(nullptr, cookies_, base::size(cookies_));
136 if (FAILED(hr))
137 LOG(ERROR) << "UnregisterCOMObject failed; hr: " << hr;
138 }
139
CreateWRLModule()140 void ComServerApp::CreateWRLModule() {
141 Microsoft::WRL::Module<Microsoft::WRL::OutOfProc>::Create(
142 this, &ComServerApp::Stop);
143 }
144
Stop()145 void ComServerApp::Stop() {
146 VLOG(2) << __func__ << ": COM server is shutting down.";
147 UnregisterClassObjects();
148 main_task_runner_->PostTask(
149 FROM_HERE, base::BindOnce([]() {
150 scoped_refptr<ComServerApp> this_server = AppServerSingletonInstance();
151 this_server->update_service_ = nullptr;
152 this_server->control_service_ = nullptr;
153 this_server->Shutdown(0);
154 }));
155 }
156
ActiveDuty(scoped_refptr<UpdateService> update_service,scoped_refptr<ControlService> control_service)157 void ComServerApp::ActiveDuty(scoped_refptr<UpdateService> update_service,
158 scoped_refptr<ControlService> control_service) {
159 if (!com_initializer_.Succeeded()) {
160 PLOG(ERROR) << "Failed to initialize COM";
161 Shutdown(-1);
162 return;
163 }
164 main_task_runner_ = base::SequencedTaskRunnerHandle::Get();
165 update_service_ = update_service;
166 control_service_ = control_service;
167 CreateWRLModule();
168 HRESULT hr = RegisterClassObjects();
169 if (FAILED(hr))
170 Shutdown(hr);
171 }
172
UninstallSelf()173 void ComServerApp::UninstallSelf() {
174 // TODO(crbug.com/1096654): Add support for is_machine.
175 UninstallCandidate(false);
176 }
177
SwapRPCInterfaces()178 bool ComServerApp::SwapRPCInterfaces() {
179 // TODO(crbug.com/1098935): Update non-side-by-side COM registration.
180 return true;
181 }
182
183 } // namespace updater
184