OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | 4 // |
5 // Declaration of ATL module object and DLL exports. | 5 // Declaration of ATL module object and DLL exports. |
6 | 6 |
7 #include "base/at_exit.h" | 7 #include "base/at_exit.h" |
8 #include "base/atomic_ref_count.h" | 8 #include "base/atomic_ref_count.h" |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/logging_win.h" | 11 #include "base/logging_win.h" |
12 #include "base/thread.h" | |
13 #include "ceee/common/com_utils.h" | 12 #include "ceee/common/com_utils.h" |
14 #include "ceee/common/install_utils.h" | 13 #include "ceee/common/install_utils.h" |
15 #include "ceee/ie/broker/broker_rpc_client.h" | 14 #include "ceee/ie/broker/broker_rpc_client.h" |
16 #include "ceee/ie/common/ceee_module_util.h" | 15 #include "ceee/ie/common/ceee_module_util.h" |
17 #include "ceee/ie/plugin/bho/browser_helper_object.h" | 16 #include "ceee/ie/plugin/bho/browser_helper_object.h" |
18 #include "ceee/ie/plugin/bho/executor.h" | 17 #include "ceee/ie/plugin/bho/executor.h" |
19 #include "ceee/ie/plugin/toolband/toolband_module_reporting.h" | 18 #include "ceee/ie/plugin/toolband/toolband_module_reporting.h" |
20 #include "ceee/ie/plugin/toolband/tool_band.h" | 19 #include "ceee/ie/plugin/toolband/tool_band.h" |
21 #include "ceee/ie/plugin/scripting/script_host.h" | 20 #include "ceee/ie/plugin/scripting/script_host.h" |
22 #include "ceee/common/windows_constants.h" | 21 #include "ceee/common/windows_constants.h" |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
54 | 53 |
55 // Needed to make sure we call Init/Term outside the loader lock. | 54 // Needed to make sure we call Init/Term outside the loader lock. |
56 HRESULT DllCanUnloadNow(); | 55 HRESULT DllCanUnloadNow(); |
57 HRESULT DllGetClassObject(REFCLSID clsid, REFIID iid, void** object); | 56 HRESULT DllGetClassObject(REFCLSID clsid, REFIID iid, void** object); |
58 void Init(); | 57 void Init(); |
59 void Term(); | 58 void Term(); |
60 bool module_initialized() const { | 59 bool module_initialized() const { |
61 return module_initialized_; | 60 return module_initialized_; |
62 } | 61 } |
63 | 62 |
64 // Fires an event to the broker, so that the call can be made with an | 63 // Fires an event to the broker. |
65 // instance of a broker proxy that was CoCreated in the worker thread. | |
66 void FireEventToBroker(const std::string& event_name, | 64 void FireEventToBroker(const std::string& event_name, |
67 const std::string& event_args); | 65 const std::string& event_args); |
68 | 66 |
69 private: | 67 private: |
70 // TODO(vitalybuka@google.com): Fire events without this thread. | |
71 class ComWorkerThread : public base::Thread { | |
72 public: | |
73 ComWorkerThread(); | |
74 | 68 |
75 // Called just prior to starting the message loop | 69 // We only attach broker on first use. |
76 virtual void Init(); | 70 void EnsureBrokerIsConnected(); |
77 | 71 |
78 // Called just after the message loop ends | |
79 virtual void CleanUp(); | |
80 | |
81 // Called by FireEventTask so that the broker we instantiate in the | |
82 // worker thread can be used. | |
83 void FireEventToBroker(BSTR event_name, BSTR event_args); | |
84 protected: | |
85 BrokerRpcClient broker_rpc_; | |
86 }; | |
87 | |
88 class FireEventTask : public Task { | |
89 public: | |
90 FireEventTask(ComWorkerThread* worker_thread, | |
91 const std::string& event_name, | |
92 const std::string& event_args) | |
93 : worker_thread_(worker_thread), | |
94 event_name_(event_name.c_str()), | |
95 event_args_(event_args.c_str()) { | |
96 } | |
97 virtual void Run() { | |
98 worker_thread_->FireEventToBroker(event_name_, event_args_); | |
99 } | |
100 private: | |
101 ComWorkerThread* worker_thread_; | |
102 CComBSTR event_name_; | |
103 CComBSTR event_args_; | |
104 }; | |
105 // We only start the thread on first use. If we would start it on | |
106 // initialization, when our DLL is loaded into the broker process, | |
107 // it would try to start this thread which tries to CoCreate a Broker | |
108 // and this could cause a complex deadlock... | |
109 void EnsureThreadStarted(); | |
110 | |
111 // We use a pointer so that we can make sure we only destroy the object | |
112 // when the thread is properly stopped. Otherwise, we would get a DCHECK | |
113 // if the thread is killed before we get to Stop it when DllCanUnloadNow | |
114 // returns S_OK, which happens when the application quits with live objects, | |
115 // this causes the destructor to DCHECK. | |
116 ComWorkerThread* worker_thread_; | |
117 base::AtExitManager at_exit_; | 72 base::AtExitManager at_exit_; |
118 bool module_initialized_; | 73 bool module_initialized_; |
119 bool crash_reporting_initialized_; | 74 bool crash_reporting_initialized_; |
120 | 75 |
121 int worker_thread_ref_count_; | 76 int broker_ref_count_; |
122 | 77 |
123 friend void ceee_module_util::AddRefModuleWorkerThread(); | 78 BrokerRpcClient broker_rpc_client_; |
124 friend void ceee_module_util::ReleaseModuleWorkerThread(); | |
125 | 79 |
126 void IncThreadRefCount(); | 80 friend void ceee_module_util::AddRefBroker(); |
127 void DecThreadRefCount(); | 81 friend void ceee_module_util::ReleaseBroker(); |
82 | |
83 void IncBrokerRefCount(); | |
84 void DecBrokerRefCount(); | |
128 }; | 85 }; |
129 | 86 |
130 ToolbandModule::ToolbandModule() | 87 ToolbandModule::ToolbandModule() |
131 : crash_reporting_initialized_(false), | 88 : crash_reporting_initialized_(false), |
132 module_initialized_(false), | 89 module_initialized_(false) { |
133 worker_thread_(NULL) { | |
134 wchar_t logfile_path[MAX_PATH]; | 90 wchar_t logfile_path[MAX_PATH]; |
135 DWORD len = ::GetTempPath(arraysize(logfile_path), logfile_path); | 91 DWORD len = ::GetTempPath(arraysize(logfile_path), logfile_path); |
136 ::PathAppend(logfile_path, kLogFileName); | 92 ::PathAppend(logfile_path, kLogFileName); |
137 | 93 |
138 // It seems we're obliged to initialize the current command line | 94 // It seems we're obliged to initialize the current command line |
139 // before initializing logging. This feels a little strange for | 95 // before initializing logging. This feels a little strange for |
140 // a plugin. | 96 // a plugin. |
141 CommandLine::Init(0, NULL); | 97 CommandLine::Init(0, NULL); |
142 | 98 |
143 logging::InitLogging( | 99 logging::InitLogging( |
(...skipping 11 matching lines...) Expand all Loading... | |
155 | 111 |
156 // Needs to be called before we can use GURL. | 112 // Needs to be called before we can use GURL. |
157 chrome::RegisterChromeSchemes(); | 113 chrome::RegisterChromeSchemes(); |
158 | 114 |
159 ScriptHost::set_default_debug_application(&debug_application); | 115 ScriptHost::set_default_debug_application(&debug_application); |
160 } | 116 } |
161 | 117 |
162 ToolbandModule::~ToolbandModule() { | 118 ToolbandModule::~ToolbandModule() { |
163 ScriptHost::set_default_debug_application(NULL); | 119 ScriptHost::set_default_debug_application(NULL); |
164 | 120 |
165 // Just leave thread as is. Releasing interface from this thread may hang IE. | 121 DCHECK(!broker_rpc_client_.is_connected()); |
166 DCHECK(worker_thread_ref_count_ == 0); | |
167 DCHECK(worker_thread_ == NULL); | |
168 | 122 |
169 // Uninitialize control hosting. | 123 // Uninitialize control hosting. |
170 BOOL uninitialized = AtlAxWinTerm(); | 124 BOOL uninitialized = AtlAxWinTerm(); |
171 DCHECK(uninitialized); | 125 DCHECK(uninitialized); |
172 | 126 |
173 logging::CloseLogFile(); | 127 logging::CloseLogFile(); |
174 } | 128 } |
175 | 129 |
176 HRESULT ToolbandModule::DllCanUnloadNow() { | 130 HRESULT ToolbandModule::DllCanUnloadNow() { |
177 HRESULT hr = CAtlDllModuleT<ToolbandModule>::DllCanUnloadNow(); | 131 HRESULT hr = CAtlDllModuleT<ToolbandModule>::DllCanUnloadNow(); |
178 if (hr == S_OK) { | 132 if (hr == S_OK) |
179 // We must protect our data member against concurrent calls to check if we | 133 Term(); |
180 // can be unloaded. We must also making the call to Term within the lock | |
181 // to make sure we don't try to re-initialize in case a new | |
182 // DllGetClassObject would occur in the mean time, in another thread. | |
183 m_csStaticDataInitAndTypeInfo.Lock(); | |
184 if (module_initialized_) { | |
185 Term(); | |
186 } | |
187 m_csStaticDataInitAndTypeInfo.Unlock(); | |
188 } | |
189 return hr; | 134 return hr; |
190 } | 135 } |
191 | 136 |
192 HRESULT ToolbandModule::DllGetClassObject(REFCLSID clsid, REFIID iid, | 137 HRESULT ToolbandModule::DllGetClassObject(REFCLSID clsid, REFIID iid, |
193 void** object) { | 138 void** object) { |
194 // Same comment as above in ToolbandModule::DllCanUnloadNow(). | 139 Init(); |
195 m_csStaticDataInitAndTypeInfo.Lock(); | |
196 if (!module_initialized_) { | |
197 Init(); | |
198 } | |
199 m_csStaticDataInitAndTypeInfo.Unlock(); | |
200 return CAtlDllModuleT<ToolbandModule>::DllGetClassObject(clsid, iid, object); | 140 return CAtlDllModuleT<ToolbandModule>::DllGetClassObject(clsid, iid, object); |
201 } | 141 } |
202 | 142 |
203 void ToolbandModule::Init() { | 143 void ToolbandModule::Init() { |
144 // We must protect our data member against concurrent calls to check if we | |
145 // can be unloaded. We must also making the call to Term within the lock | |
146 // to make sure we don't try to re-initialize in case a new | |
147 // DllGetClassObject would occur in the mean time, in another thread. | |
148 CComCritSecLock<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo); | |
149 if (module_initialized_) | |
150 return; | |
204 crash_reporting_initialized_ = InitializeCrashReporting(); | 151 crash_reporting_initialized_ = InitializeCrashReporting(); |
205 module_initialized_ = true; | 152 module_initialized_ = true; |
206 } | 153 } |
207 | 154 |
208 void ToolbandModule::Term() { | 155 void ToolbandModule::Term() { |
209 if (worker_thread_ != NULL) { | 156 CComCritSecLock<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo); |
210 // It is OK to call Stop on a thread even when it isn't running. | 157 if (!module_initialized_) |
211 worker_thread_->Stop(); | 158 return; |
212 delete worker_thread_; | 159 if (broker_rpc_client_.is_connected()) |
213 worker_thread_ = NULL; | 160 broker_rpc_client_.Disconnect(); |
214 } | 161 |
215 if (crash_reporting_initialized_) { | 162 if (crash_reporting_initialized_) { |
216 bool crash_reporting_deinitialized = ShutdownCrashReporting(); | 163 bool crash_reporting_deinitialized = ShutdownCrashReporting(); |
217 DCHECK(crash_reporting_deinitialized); | 164 DCHECK(crash_reporting_deinitialized); |
218 crash_reporting_initialized_ = false; | 165 crash_reporting_initialized_ = false; |
219 } | 166 } |
220 module_initialized_ = false; | 167 module_initialized_ = false; |
221 } | 168 } |
222 | 169 |
223 void ToolbandModule::IncThreadRefCount() { | 170 void ToolbandModule::IncBrokerRefCount() { |
224 m_csStaticDataInitAndTypeInfo.Lock(); | 171 CComCritSecLock<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo); |
225 DCHECK_GE(worker_thread_ref_count_, 0); | 172 DCHECK_GE(broker_ref_count_, 0); |
226 worker_thread_ref_count_++; | 173 broker_ref_count_++; |
227 m_csStaticDataInitAndTypeInfo.Unlock(); | |
228 } | 174 } |
229 | 175 |
230 void ToolbandModule::DecThreadRefCount() { | 176 void ToolbandModule::DecBrokerRefCount() { |
231 ComWorkerThread* thread = NULL; | 177 CComCritSecLock<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo); |
178 // If we're already at 0, we have a problem, so we check if we're >=. | |
179 DCHECK_GT(broker_ref_count_, 0); | |
232 | 180 |
233 m_csStaticDataInitAndTypeInfo.Lock(); | 181 // If this was our last reference, we disconnect broker. This is okay even if |
234 // If we're already at 0, we have a problem, so we check if we're >=. | 182 // we increment the count again, because the broker is created on the "first" |
235 DCHECK_GT(worker_thread_ref_count_, 0); | |
236 | |
237 // If this was our last reference, we delete the thread. This is okay even if | |
238 // we increment the count again, because the thread is created on the "first" | |
239 // FireEventToBroker, thus it will be created again if needed. | 183 // FireEventToBroker, thus it will be created again if needed. |
240 if (--worker_thread_ref_count_ == 0) { | 184 if (--broker_ref_count_ == 0) { |
241 if (worker_thread_ != NULL) { | 185 if (broker_rpc_client_.is_connected()) |
242 // Store the worker_thread to a temporary pointer. It will be freed later. | 186 broker_rpc_client_.Disconnect(); |
243 thread = worker_thread_; | |
244 worker_thread_ = NULL; | |
245 } | |
246 } | |
247 m_csStaticDataInitAndTypeInfo.Unlock(); | |
248 | |
249 // Clean the thread after the unlock to be certain we don't get a deadlock | |
250 // (the CriticalSection could be used in the worker thread). | |
251 if (thread) { | |
252 // It is OK to call Stop on a thread even when it isn't running. | |
253 thread->Stop(); | |
254 delete thread; | |
255 } | 187 } |
256 } | 188 } |
257 | 189 |
258 void ToolbandModule::EnsureThreadStarted() { | 190 void ToolbandModule::EnsureBrokerIsConnected() { |
259 m_csStaticDataInitAndTypeInfo.Lock(); | 191 CComCritSecLock<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo); |
260 if (worker_thread_ == NULL) { | 192 if (!broker_rpc_client_.is_connected()) { |
261 worker_thread_ = new ComWorkerThread; | 193 ::CoInitializeEx(0, COINIT_MULTITHREADED); |
Sigurður Ásgeirsson
2010/11/16 18:23:04
I think we can skip the Coinit calls. We're runnin
Vitaly Buka corp
2010/11/18 23:14:21
Done.
| |
262 // The COM worker thread must be a UI thread so that it can pump windows | 194 // TODO(vitalybuka@google.com): Start broker without COM after the last |
263 // messages and allow COM to handle cross apartment calls. | 195 // COM interface is removed. |
264 worker_thread_->StartWithOptions(base::Thread::Options(MessageLoop::TYPE_UI, | 196 CComPtr<ICeeeBrokerRegistrar> broker; |
265 0)); // stack_size | 197 HRESULT hr = broker.CoCreateInstance(CLSID_CeeeBroker); |
198 DCHECK(SUCCEEDED(hr)) << "Failed to create broker. " << com::LogHr(hr); | |
199 broker_rpc_client_.Connect(); | |
Sigurður Ásgeirsson
2010/11/16 18:23:04
test return value and LOG(ERROR) here?
Vitaly Buka corp
2010/11/18 23:14:21
Done.
| |
200 DCHECK(broker_rpc_client_.is_connected()); | |
201 ::CoUninitialize(); | |
Sigurður Ásgeirsson
2010/11/16 18:23:04
Ooof.
If the ::Coinitialize call fails (e.g. due t
Vitaly Buka corp
2010/11/18 23:14:21
Done.
| |
266 } | 202 } |
267 m_csStaticDataInitAndTypeInfo.Unlock(); | |
268 } | 203 } |
269 | 204 |
270 void ToolbandModule::FireEventToBroker(const std::string& event_name, | 205 void ToolbandModule::FireEventToBroker(const std::string& event_name, |
271 const std::string& event_args) { | 206 const std::string& event_args) { |
272 EnsureThreadStarted(); | 207 EnsureBrokerIsConnected(); |
273 DCHECK(worker_thread_ != NULL); | 208 CComBSTR name(event_name.c_str()); |
Sigurður Ásgeirsson
2010/11/16 18:23:04
This looks like needless conversion and allocation
Vitaly Buka corp
2010/11/18 23:14:21
Done.
| |
274 MessageLoop* message_loop = worker_thread_->message_loop(); | 209 CComBSTR args(event_args.c_str()); |
275 if (message_loop) { | 210 LOG_IF(ERROR, broker_rpc_client_.FireEvent(name, args)) << |
Sigurður Ásgeirsson
2010/11/16 18:23:04
Fire event returns true on error?
I don't like hid
Vitaly Buka corp
2010/11/18 23:14:21
Done.
| |
276 message_loop->PostTask(FROM_HERE, | 211 "Failed to fire event to broker."; |
277 new FireEventTask(worker_thread_, event_name, event_args)); | |
278 } else { | |
279 LOG(ERROR) << "Trying to post a message before the COM worker thread is" | |
280 "completely initialized and ready."; | |
281 } | |
282 } | 212 } |
283 | 213 |
284 | 214 |
285 ToolbandModule::ComWorkerThread::ComWorkerThread() | |
286 : base::Thread("CEEE-COM Worker Thread") { | |
287 } | |
288 | |
289 void ToolbandModule::ComWorkerThread::Init() { | |
290 ::CoInitializeEx(0, COINIT_MULTITHREADED); | |
291 // TODO(vitalybuka@google.com): Start broker without COM. | |
292 CComPtr<ICeeeBroker> broker_; | |
293 HRESULT hr = broker_.CoCreateInstance(CLSID_CeeeBroker); | |
294 DCHECK(SUCCEEDED(hr)) << "Failed to create broker. " << com::LogHr(hr); | |
295 broker_rpc_.Connect(); | |
296 DCHECK(broker_rpc_.is_connected()); | |
297 ::CoUninitialize(); | |
298 } | |
299 | |
300 void ToolbandModule::ComWorkerThread::CleanUp() { | |
301 broker_rpc_.Disconnect(); | |
302 } | |
303 | |
304 void ToolbandModule::ComWorkerThread::FireEventToBroker(BSTR event_name, | |
305 BSTR event_args) { | |
306 DCHECK(broker_rpc_.is_connected()); | |
307 bool result = broker_rpc_.FireEvent(event_name, event_args); | |
308 DCHECK(result); | |
309 } | |
310 | |
311 ToolbandModule module; | 215 ToolbandModule module; |
312 | 216 |
313 void ceee_module_util::AddRefModuleWorkerThread() { | 217 void ceee_module_util::AddRefBroker() { |
314 module.IncThreadRefCount(); | 218 module.IncBrokerRefCount(); |
315 } | 219 } |
316 void ceee_module_util::ReleaseModuleWorkerThread() { | 220 void ceee_module_util::ReleaseBroker() { |
317 module.DecThreadRefCount(); | 221 module.DecBrokerRefCount(); |
318 } | 222 } |
319 | 223 |
320 void ceee_module_util::FireEventToBroker(const std::string& event_name, | 224 void ceee_module_util::FireEventToBroker(const std::string& event_name, |
321 const std::string& event_args) { | 225 const std::string& event_args) { |
322 module.FireEventToBroker(event_name, event_args); | 226 module.FireEventToBroker(event_name, event_args); |
323 } | 227 } |
324 | 228 |
325 void ceee_module_util::Lock() { | 229 void ceee_module_util::Lock() { |
326 module.m_csStaticDataInitAndTypeInfo.Lock(); | 230 module.m_csStaticDataInitAndTypeInfo.Lock(); |
327 } | 231 } |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
378 } | 282 } |
379 | 283 |
380 CEEE_DEFINE_DLL_REGISTER_SERVER() | 284 CEEE_DEFINE_DLL_REGISTER_SERVER() |
381 | 285 |
382 // DllUnregisterServer - Removes entries from the system registry | 286 // DllUnregisterServer - Removes entries from the system registry |
383 STDAPI DllUnregisterServer(void) { | 287 STDAPI DllUnregisterServer(void) { |
384 // We always allow unregistration, even if no --enable-ceee install flag. | 288 // We always allow unregistration, even if no --enable-ceee install flag. |
385 HRESULT hr = module.DllUnregisterServer(); | 289 HRESULT hr = module.DllUnregisterServer(); |
386 return hr; | 290 return hr; |
387 } | 291 } |
OLD | NEW |