// 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; }