| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/common/service_process_util.h" |
| |
| #include "base/command_line.h" |
| #include "base/file_util.h" |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/path_service.h" |
| #include "base/string16.h" |
| #include "base/task.h" |
| #include "base/utf_string_conversions.h" |
| #include "base/win/object_watcher.h" |
| #include "base/win/scoped_handle.h" |
| #include "base/win/win_util.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "chrome/common/chrome_switches.h" |
| |
| namespace { |
| |
| string16 GetServiceProcessReadyEventName() { |
| return UTF8ToWide( |
| GetServiceProcessScopedVersionedName("_service_ready")); |
| } |
| |
| string16 GetServiceProcessShutdownEventName() { |
| return UTF8ToWide( |
| GetServiceProcessScopedVersionedName("_service_shutdown_evt")); |
| } |
| |
| std::string GetServiceProcessAutoRunKey() { |
| return GetServiceProcessScopedName("_service_run"); |
| } |
| |
| // Returns the name of the autotun reg value that we used to use for older |
| // versions of Chrome. |
| std::string GetObsoleteServiceProcessAutoRunKey() { |
| FilePath user_data_dir; |
| PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); |
| std::string scoped_name = WideToUTF8(user_data_dir.value()); |
| std::replace(scoped_name.begin(), scoped_name.end(), '\\', '!'); |
| std::replace(scoped_name.begin(), scoped_name.end(), '/', '!'); |
| scoped_name.append("_service_run"); |
| return scoped_name; |
| } |
| |
| class ServiceProcessShutdownMonitor |
| : public base::win::ObjectWatcher::Delegate { |
| public: |
| explicit ServiceProcessShutdownMonitor(Task* shutdown_task) |
| : shutdown_task_(shutdown_task) { |
| } |
| void Start() { |
| string16 event_name = GetServiceProcessShutdownEventName(); |
| CHECK(event_name.length() <= MAX_PATH); |
| shutdown_event_.Set(CreateEvent(NULL, TRUE, FALSE, event_name.c_str())); |
| watcher_.StartWatching(shutdown_event_.Get(), this); |
| } |
| |
| // base::ObjectWatcher::Delegate implementation. |
| virtual void OnObjectSignaled(HANDLE object) { |
| shutdown_task_->Run(); |
| shutdown_task_.reset(); |
| } |
| |
| private: |
| base::win::ScopedHandle shutdown_event_; |
| base::win::ObjectWatcher watcher_; |
| scoped_ptr<Task> shutdown_task_; |
| }; |
| |
| } // namespace |
| |
| bool ForceServiceProcessShutdown(const std::string& version, |
| base::ProcessId process_id) { |
| base::win::ScopedHandle shutdown_event; |
| std::string versioned_name = version; |
| versioned_name.append("_service_shutdown_evt"); |
| string16 event_name = |
| UTF8ToWide(GetServiceProcessScopedName(versioned_name)); |
| shutdown_event.Set(OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name.c_str())); |
| if (!shutdown_event.IsValid()) |
| return false; |
| SetEvent(shutdown_event.Get()); |
| return true; |
| } |
| |
| bool CheckServiceProcessReady() { |
| string16 event_name = GetServiceProcessReadyEventName(); |
| base::win::ScopedHandle event( |
| OpenEvent(SYNCHRONIZE | READ_CONTROL, false, event_name.c_str())); |
| if (!event.IsValid()) |
| return false; |
| // Check if the event is signaled. |
| return WaitForSingleObject(event, 0) == WAIT_OBJECT_0; |
| } |
| |
| struct ServiceProcessState::StateData { |
| // An event that is signaled when a service process is ready. |
| base::win::ScopedHandle ready_event; |
| scoped_ptr<ServiceProcessShutdownMonitor> shutdown_monitor; |
| }; |
| |
| void ServiceProcessState::CreateState() { |
| CHECK(!state_); |
| state_ = new StateData; |
| } |
| |
| bool ServiceProcessState::TakeSingletonLock() { |
| DCHECK(state_); |
| string16 event_name = GetServiceProcessReadyEventName(); |
| CHECK(event_name.length() <= MAX_PATH); |
| base::win::ScopedHandle service_process_ready_event; |
| service_process_ready_event.Set( |
| CreateEvent(NULL, TRUE, FALSE, event_name.c_str())); |
| DWORD error = GetLastError(); |
| if ((error == ERROR_ALREADY_EXISTS) || (error == ERROR_ACCESS_DENIED)) |
| return false; |
| DCHECK(service_process_ready_event.IsValid()); |
| state_->ready_event.Set(service_process_ready_event.Take()); |
| return true; |
| } |
| |
| bool ServiceProcessState::SignalReady( |
| base::MessageLoopProxy* message_loop_proxy, Task* shutdown_task) { |
| DCHECK(state_); |
| DCHECK(state_->ready_event.IsValid()); |
| scoped_ptr<Task> scoped_shutdown_task(shutdown_task); |
| if (!SetEvent(state_->ready_event.Get())) { |
| return false; |
| } |
| if (shutdown_task) { |
| state_->shutdown_monitor.reset( |
| new ServiceProcessShutdownMonitor(scoped_shutdown_task.release())); |
| state_->shutdown_monitor->Start(); |
| } |
| return true; |
| } |
| |
| bool ServiceProcessState::AddToAutoRun() { |
| DCHECK(autorun_command_line_.get()); |
| // Remove the old autorun value first because we changed the naming scheme |
| // for the autorun value name. |
| base::win::RemoveCommandFromAutoRun( |
| HKEY_CURRENT_USER, UTF8ToWide(GetObsoleteServiceProcessAutoRunKey())); |
| return base::win::AddCommandToAutoRun( |
| HKEY_CURRENT_USER, |
| UTF8ToWide(GetServiceProcessAutoRunKey()), |
| autorun_command_line_->command_line_string()); |
| } |
| |
| bool ServiceProcessState::RemoveFromAutoRun() { |
| // Remove the old autorun value first because we changed the naming scheme |
| // for the autorun value name. |
| base::win::RemoveCommandFromAutoRun( |
| HKEY_CURRENT_USER, UTF8ToWide(GetObsoleteServiceProcessAutoRunKey())); |
| return base::win::RemoveCommandFromAutoRun( |
| HKEY_CURRENT_USER, UTF8ToWide(GetServiceProcessAutoRunKey())); |
| } |
| |
| void ServiceProcessState::TearDownState() { |
| delete state_; |
| state_ = NULL; |
| } |