| 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" | |
| 16 #include "ceee/ie/common/ceee_module_util.h" | 14 #include "ceee/ie/common/ceee_module_util.h" |
| 17 #include "ceee/ie/plugin/bho/browser_helper_object.h" | 15 #include "ceee/ie/plugin/bho/browser_helper_object.h" |
| 18 #include "ceee/ie/plugin/bho/executor.h" | 16 #include "ceee/ie/plugin/bho/executor.h" |
| 19 #include "ceee/ie/plugin/toolband/toolband_module_reporting.h" | 17 #include "ceee/ie/plugin/toolband/toolband_module_reporting.h" |
| 20 #include "ceee/ie/plugin/toolband/tool_band.h" | 18 #include "ceee/ie/plugin/toolband/tool_band.h" |
| 21 #include "ceee/ie/plugin/scripting/script_host.h" | 19 #include "ceee/ie/plugin/scripting/script_host.h" |
| 22 #include "ceee/common/windows_constants.h" | 20 #include "ceee/common/windows_constants.h" |
| 23 #include "chrome/common/url_constants.h" | 21 #include "chrome/common/url_constants.h" |
| 24 | 22 |
| 25 #include "toolband.h" // NOLINT | 23 #include "toolband.h" // NOLINT |
| (...skipping 28 matching lines...) Expand all Loading... |
| 54 | 52 |
| 55 // Needed to make sure we call Init/Term outside the loader lock. | 53 // Needed to make sure we call Init/Term outside the loader lock. |
| 56 HRESULT DllCanUnloadNow(); | 54 HRESULT DllCanUnloadNow(); |
| 57 HRESULT DllGetClassObject(REFCLSID clsid, REFIID iid, void** object); | 55 HRESULT DllGetClassObject(REFCLSID clsid, REFIID iid, void** object); |
| 58 void Init(); | 56 void Init(); |
| 59 void Term(); | 57 void Term(); |
| 60 bool module_initialized() const { | 58 bool module_initialized() const { |
| 61 return module_initialized_; | 59 return module_initialized_; |
| 62 } | 60 } |
| 63 | 61 |
| 64 // Fires an event to the broker, so that the call can be made with an | 62 private: |
| 65 // instance of a broker proxy that was CoCreated in the worker thread. | |
| 66 void FireEventToBroker(const std::string& event_name, | |
| 67 const std::string& event_args); | |
| 68 | 63 |
| 69 private: | |
| 70 // TODO(vitalybuka@google.com): Fire events without this thread. | |
| 71 class ComWorkerThread : public base::Thread { | |
| 72 public: | |
| 73 ComWorkerThread(); | |
| 74 | |
| 75 // Called just prior to starting the message loop | |
| 76 virtual void Init(); | |
| 77 | |
| 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_; | 64 base::AtExitManager at_exit_; |
| 118 bool module_initialized_; | 65 bool module_initialized_; |
| 119 bool crash_reporting_initialized_; | 66 bool crash_reporting_initialized_; |
| 120 | |
| 121 int worker_thread_ref_count_; | |
| 122 | |
| 123 friend void ceee_module_util::AddRefModuleWorkerThread(); | |
| 124 friend void ceee_module_util::ReleaseModuleWorkerThread(); | |
| 125 | |
| 126 void IncThreadRefCount(); | |
| 127 void DecThreadRefCount(); | |
| 128 }; | 67 }; |
| 129 | 68 |
| 130 ToolbandModule::ToolbandModule() | 69 ToolbandModule::ToolbandModule() |
| 131 : crash_reporting_initialized_(false), | 70 : crash_reporting_initialized_(false), |
| 132 module_initialized_(false), | 71 module_initialized_(false) { |
| 133 worker_thread_(NULL) { | |
| 134 wchar_t logfile_path[MAX_PATH]; | 72 wchar_t logfile_path[MAX_PATH]; |
| 135 DWORD len = ::GetTempPath(arraysize(logfile_path), logfile_path); | 73 DWORD len = ::GetTempPath(arraysize(logfile_path), logfile_path); |
| 136 ::PathAppend(logfile_path, kLogFileName); | 74 ::PathAppend(logfile_path, kLogFileName); |
| 137 | 75 |
| 138 // It seems we're obliged to initialize the current command line | 76 // It seems we're obliged to initialize the current command line |
| 139 // before initializing logging. This feels a little strange for | 77 // before initializing logging. This feels a little strange for |
| 140 // a plugin. | 78 // a plugin. |
| 141 CommandLine::Init(0, NULL); | 79 CommandLine::Init(0, NULL); |
| 142 | 80 |
| 143 logging::InitLogging( | 81 logging::InitLogging( |
| (...skipping 11 matching lines...) Expand all Loading... |
| 155 | 93 |
| 156 // Needs to be called before we can use GURL. | 94 // Needs to be called before we can use GURL. |
| 157 chrome::RegisterChromeSchemes(); | 95 chrome::RegisterChromeSchemes(); |
| 158 | 96 |
| 159 ScriptHost::set_default_debug_application(&debug_application); | 97 ScriptHost::set_default_debug_application(&debug_application); |
| 160 } | 98 } |
| 161 | 99 |
| 162 ToolbandModule::~ToolbandModule() { | 100 ToolbandModule::~ToolbandModule() { |
| 163 ScriptHost::set_default_debug_application(NULL); | 101 ScriptHost::set_default_debug_application(NULL); |
| 164 | 102 |
| 165 // Just leave thread as is. Releasing interface from this thread may hang IE. | |
| 166 DCHECK(worker_thread_ref_count_ == 0); | |
| 167 DCHECK(worker_thread_ == NULL); | |
| 168 | |
| 169 // Uninitialize control hosting. | 103 // Uninitialize control hosting. |
| 170 BOOL uninitialized = AtlAxWinTerm(); | 104 BOOL uninitialized = AtlAxWinTerm(); |
| 171 DCHECK(uninitialized); | 105 DCHECK(uninitialized); |
| 172 | 106 |
| 173 logging::CloseLogFile(); | 107 logging::CloseLogFile(); |
| 174 } | 108 } |
| 175 | 109 |
| 176 HRESULT ToolbandModule::DllCanUnloadNow() { | 110 HRESULT ToolbandModule::DllCanUnloadNow() { |
| 177 HRESULT hr = CAtlDllModuleT<ToolbandModule>::DllCanUnloadNow(); | 111 HRESULT hr = CAtlDllModuleT<ToolbandModule>::DllCanUnloadNow(); |
| 178 if (hr == S_OK) { | 112 if (hr == S_OK) |
| 179 // We must protect our data member against concurrent calls to check if we | 113 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; | 114 return hr; |
| 190 } | 115 } |
| 191 | 116 |
| 192 HRESULT ToolbandModule::DllGetClassObject(REFCLSID clsid, REFIID iid, | 117 HRESULT ToolbandModule::DllGetClassObject(REFCLSID clsid, REFIID iid, |
| 193 void** object) { | 118 void** object) { |
| 194 // Same comment as above in ToolbandModule::DllCanUnloadNow(). | 119 Init(); |
| 195 m_csStaticDataInitAndTypeInfo.Lock(); | |
| 196 if (!module_initialized_) { | |
| 197 Init(); | |
| 198 } | |
| 199 m_csStaticDataInitAndTypeInfo.Unlock(); | |
| 200 return CAtlDllModuleT<ToolbandModule>::DllGetClassObject(clsid, iid, object); | 120 return CAtlDllModuleT<ToolbandModule>::DllGetClassObject(clsid, iid, object); |
| 201 } | 121 } |
| 202 | 122 |
| 203 void ToolbandModule::Init() { | 123 void ToolbandModule::Init() { |
| 124 // We must protect our data member against concurrent calls to check if we |
| 125 // can be unloaded. We must also making the call to Term within the lock |
| 126 // to make sure we don't try to re-initialize in case a new |
| 127 // DllGetClassObject would occur in the mean time, in another thread. |
| 128 CComCritSecLock<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo); |
| 129 if (module_initialized_) |
| 130 return; |
| 204 crash_reporting_initialized_ = InitializeCrashReporting(); | 131 crash_reporting_initialized_ = InitializeCrashReporting(); |
| 205 module_initialized_ = true; | 132 module_initialized_ = true; |
| 206 } | 133 } |
| 207 | 134 |
| 208 void ToolbandModule::Term() { | 135 void ToolbandModule::Term() { |
| 209 if (worker_thread_ != NULL) { | 136 CComCritSecLock<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo); |
| 210 // It is OK to call Stop on a thread even when it isn't running. | 137 if (!module_initialized_) |
| 211 worker_thread_->Stop(); | 138 return; |
| 212 delete worker_thread_; | |
| 213 worker_thread_ = NULL; | |
| 214 } | |
| 215 if (crash_reporting_initialized_) { | 139 if (crash_reporting_initialized_) { |
| 216 bool crash_reporting_deinitialized = ShutdownCrashReporting(); | 140 bool crash_reporting_deinitialized = ShutdownCrashReporting(); |
| 217 DCHECK(crash_reporting_deinitialized); | 141 DCHECK(crash_reporting_deinitialized); |
| 218 crash_reporting_initialized_ = false; | 142 crash_reporting_initialized_ = false; |
| 219 } | 143 } |
| 220 module_initialized_ = false; | 144 module_initialized_ = false; |
| 221 } | 145 } |
| 222 | 146 |
| 223 void ToolbandModule::IncThreadRefCount() { | |
| 224 m_csStaticDataInitAndTypeInfo.Lock(); | |
| 225 DCHECK_GE(worker_thread_ref_count_, 0); | |
| 226 worker_thread_ref_count_++; | |
| 227 m_csStaticDataInitAndTypeInfo.Unlock(); | |
| 228 } | |
| 229 | |
| 230 void ToolbandModule::DecThreadRefCount() { | |
| 231 ComWorkerThread* thread = NULL; | |
| 232 | |
| 233 m_csStaticDataInitAndTypeInfo.Lock(); | |
| 234 // If we're already at 0, we have a problem, so we check if we're >=. | |
| 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. | |
| 240 if (--worker_thread_ref_count_ == 0) { | |
| 241 if (worker_thread_ != NULL) { | |
| 242 // Store the worker_thread to a temporary pointer. It will be freed later. | |
| 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 } | |
| 256 } | |
| 257 | |
| 258 void ToolbandModule::EnsureThreadStarted() { | |
| 259 m_csStaticDataInitAndTypeInfo.Lock(); | |
| 260 if (worker_thread_ == NULL) { | |
| 261 worker_thread_ = new ComWorkerThread; | |
| 262 // The COM worker thread must be a UI thread so that it can pump windows | |
| 263 // messages and allow COM to handle cross apartment calls. | |
| 264 worker_thread_->StartWithOptions(base::Thread::Options(MessageLoop::TYPE_UI, | |
| 265 0)); // stack_size | |
| 266 } | |
| 267 m_csStaticDataInitAndTypeInfo.Unlock(); | |
| 268 } | |
| 269 | |
| 270 void ToolbandModule::FireEventToBroker(const std::string& event_name, | |
| 271 const std::string& event_args) { | |
| 272 EnsureThreadStarted(); | |
| 273 DCHECK(worker_thread_ != NULL); | |
| 274 MessageLoop* message_loop = worker_thread_->message_loop(); | |
| 275 if (message_loop) { | |
| 276 message_loop->PostTask(FROM_HERE, | |
| 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 } | |
| 283 | |
| 284 | |
| 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; | 147 ToolbandModule module; |
| 312 | 148 |
| 313 void ceee_module_util::AddRefModuleWorkerThread() { | |
| 314 module.IncThreadRefCount(); | |
| 315 } | |
| 316 void ceee_module_util::ReleaseModuleWorkerThread() { | |
| 317 module.DecThreadRefCount(); | |
| 318 } | |
| 319 | |
| 320 void ceee_module_util::FireEventToBroker(const std::string& event_name, | |
| 321 const std::string& event_args) { | |
| 322 module.FireEventToBroker(event_name, event_args); | |
| 323 } | |
| 324 | |
| 325 void ceee_module_util::Lock() { | 149 void ceee_module_util::Lock() { |
| 326 module.m_csStaticDataInitAndTypeInfo.Lock(); | 150 module.m_csStaticDataInitAndTypeInfo.Lock(); |
| 327 } | 151 } |
| 328 | 152 |
| 329 void ceee_module_util::Unlock() { | 153 void ceee_module_util::Unlock() { |
| 330 module.m_csStaticDataInitAndTypeInfo.Unlock(); | 154 module.m_csStaticDataInitAndTypeInfo.Unlock(); |
| 331 } | 155 } |
| 332 | 156 |
| 333 LONG ceee_module_util::LockModule() { | 157 LONG ceee_module_util::LockModule() { |
| 334 return module.Lock(); | 158 return module.Lock(); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 378 } | 202 } |
| 379 | 203 |
| 380 CEEE_DEFINE_DLL_REGISTER_SERVER() | 204 CEEE_DEFINE_DLL_REGISTER_SERVER() |
| 381 | 205 |
| 382 // DllUnregisterServer - Removes entries from the system registry | 206 // DllUnregisterServer - Removes entries from the system registry |
| 383 STDAPI DllUnregisterServer(void) { | 207 STDAPI DllUnregisterServer(void) { |
| 384 // We always allow unregistration, even if no --enable-ceee install flag. | 208 // We always allow unregistration, even if no --enable-ceee install flag. |
| 385 HRESULT hr = module.DllUnregisterServer(); | 209 HRESULT hr = module.DllUnregisterServer(); |
| 386 return hr; | 210 return hr; |
| 387 } | 211 } |
| OLD | NEW |