1// Copyright (c) 2011 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/common/service_process_util.h" 6 7#include "base/command_line.h" 8#include "base/file_util.h" 9#include "base/logging.h" 10#include "base/memory/scoped_ptr.h" 11#include "base/path_service.h" 12#include "base/string16.h" 13#include "base/task.h" 14#include "base/utf_string_conversions.h" 15#include "base/win/object_watcher.h" 16#include "base/win/scoped_handle.h" 17#include "base/win/win_util.h" 18#include "chrome/common/chrome_paths.h" 19#include "chrome/common/chrome_switches.h" 20 21namespace { 22 23string16 GetServiceProcessReadyEventName() { 24 return UTF8ToWide( 25 GetServiceProcessScopedVersionedName("_service_ready")); 26} 27 28string16 GetServiceProcessShutdownEventName() { 29 return UTF8ToWide( 30 GetServiceProcessScopedVersionedName("_service_shutdown_evt")); 31} 32 33std::string GetServiceProcessAutoRunKey() { 34 return GetServiceProcessScopedName("_service_run"); 35} 36 37// Returns the name of the autotun reg value that we used to use for older 38// versions of Chrome. 39std::string GetObsoleteServiceProcessAutoRunKey() { 40 FilePath user_data_dir; 41 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); 42 std::string scoped_name = WideToUTF8(user_data_dir.value()); 43 std::replace(scoped_name.begin(), scoped_name.end(), '\\', '!'); 44 std::replace(scoped_name.begin(), scoped_name.end(), '/', '!'); 45 scoped_name.append("_service_run"); 46 return scoped_name; 47} 48 49class ServiceProcessShutdownMonitor 50 : public base::win::ObjectWatcher::Delegate { 51 public: 52 explicit ServiceProcessShutdownMonitor(Task* shutdown_task) 53 : shutdown_task_(shutdown_task) { 54 } 55 void Start() { 56 string16 event_name = GetServiceProcessShutdownEventName(); 57 CHECK(event_name.length() <= MAX_PATH); 58 shutdown_event_.Set(CreateEvent(NULL, TRUE, FALSE, event_name.c_str())); 59 watcher_.StartWatching(shutdown_event_.Get(), this); 60 } 61 62 // base::ObjectWatcher::Delegate implementation. 63 virtual void OnObjectSignaled(HANDLE object) { 64 shutdown_task_->Run(); 65 shutdown_task_.reset(); 66 } 67 68 private: 69 base::win::ScopedHandle shutdown_event_; 70 base::win::ObjectWatcher watcher_; 71 scoped_ptr<Task> shutdown_task_; 72}; 73 74} // namespace 75 76bool ForceServiceProcessShutdown(const std::string& version, 77 base::ProcessId process_id) { 78 base::win::ScopedHandle shutdown_event; 79 std::string versioned_name = version; 80 versioned_name.append("_service_shutdown_evt"); 81 string16 event_name = 82 UTF8ToWide(GetServiceProcessScopedName(versioned_name)); 83 shutdown_event.Set(OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name.c_str())); 84 if (!shutdown_event.IsValid()) 85 return false; 86 SetEvent(shutdown_event.Get()); 87 return true; 88} 89 90bool CheckServiceProcessReady() { 91 string16 event_name = GetServiceProcessReadyEventName(); 92 base::win::ScopedHandle event( 93 OpenEvent(SYNCHRONIZE | READ_CONTROL, false, event_name.c_str())); 94 if (!event.IsValid()) 95 return false; 96 // Check if the event is signaled. 97 return WaitForSingleObject(event, 0) == WAIT_OBJECT_0; 98} 99 100struct ServiceProcessState::StateData { 101 // An event that is signaled when a service process is ready. 102 base::win::ScopedHandle ready_event; 103 scoped_ptr<ServiceProcessShutdownMonitor> shutdown_monitor; 104}; 105 106void ServiceProcessState::CreateState() { 107 CHECK(!state_); 108 state_ = new StateData; 109} 110 111bool ServiceProcessState::TakeSingletonLock() { 112 DCHECK(state_); 113 string16 event_name = GetServiceProcessReadyEventName(); 114 CHECK(event_name.length() <= MAX_PATH); 115 base::win::ScopedHandle service_process_ready_event; 116 service_process_ready_event.Set( 117 CreateEvent(NULL, TRUE, FALSE, event_name.c_str())); 118 DWORD error = GetLastError(); 119 if ((error == ERROR_ALREADY_EXISTS) || (error == ERROR_ACCESS_DENIED)) 120 return false; 121 DCHECK(service_process_ready_event.IsValid()); 122 state_->ready_event.Set(service_process_ready_event.Take()); 123 return true; 124} 125 126bool ServiceProcessState::SignalReady( 127 base::MessageLoopProxy* message_loop_proxy, Task* shutdown_task) { 128 DCHECK(state_); 129 DCHECK(state_->ready_event.IsValid()); 130 scoped_ptr<Task> scoped_shutdown_task(shutdown_task); 131 if (!SetEvent(state_->ready_event.Get())) { 132 return false; 133 } 134 if (shutdown_task) { 135 state_->shutdown_monitor.reset( 136 new ServiceProcessShutdownMonitor(scoped_shutdown_task.release())); 137 state_->shutdown_monitor->Start(); 138 } 139 return true; 140} 141 142bool ServiceProcessState::AddToAutoRun() { 143 DCHECK(autorun_command_line_.get()); 144 // Remove the old autorun value first because we changed the naming scheme 145 // for the autorun value name. 146 base::win::RemoveCommandFromAutoRun( 147 HKEY_CURRENT_USER, UTF8ToWide(GetObsoleteServiceProcessAutoRunKey())); 148 return base::win::AddCommandToAutoRun( 149 HKEY_CURRENT_USER, 150 UTF8ToWide(GetServiceProcessAutoRunKey()), 151 autorun_command_line_->command_line_string()); 152} 153 154bool ServiceProcessState::RemoveFromAutoRun() { 155 // Remove the old autorun value first because we changed the naming scheme 156 // for the autorun value name. 157 base::win::RemoveCommandFromAutoRun( 158 HKEY_CURRENT_USER, UTF8ToWide(GetObsoleteServiceProcessAutoRunKey())); 159 return base::win::RemoveCommandFromAutoRun( 160 HKEY_CURRENT_USER, UTF8ToWide(GetServiceProcessAutoRunKey())); 161} 162 163void ServiceProcessState::TearDownState() { 164 delete state_; 165 state_ = NULL; 166} 167