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