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