Roll src/third_party/WebKit 6f84130:7353389 (svn 184386:184391)
[chromium-blink-merge.git] / chrome / common / service_process_util_win.cc
blob9e358a7cc4593fd552143a68cbe93c79370a7c32
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.
5 #include "chrome/common/service_process_util.h"
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/profiler/scoped_profile.h"
14 #include "base/strings/string16.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/win/object_watcher.h"
17 #include "base/win/scoped_handle.h"
18 #include "base/win/win_util.h"
19 #include "chrome/common/chrome_paths.h"
20 #include "chrome/common/chrome_switches.h"
22 namespace {
24 const char kTerminateEventSuffix[] = "_service_terminate_evt";
26 base::string16 GetServiceProcessReadyEventName() {
27 return base::UTF8ToWide(
28 GetServiceProcessScopedVersionedName("_service_ready"));
31 base::string16 GetServiceProcessTerminateEventName() {
32 return base::UTF8ToWide(
33 GetServiceProcessScopedVersionedName(kTerminateEventSuffix));
36 std::string GetServiceProcessAutoRunKey() {
37 return GetServiceProcessScopedName("_service_run");
40 // Returns the name of the autotun reg value that we used to use for older
41 // versions of Chrome.
42 std::string GetObsoleteServiceProcessAutoRunKey() {
43 base::FilePath user_data_dir;
44 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
45 std::string scoped_name = base::WideToUTF8(user_data_dir.value());
46 std::replace(scoped_name.begin(), scoped_name.end(), '\\', '!');
47 std::replace(scoped_name.begin(), scoped_name.end(), '/', '!');
48 scoped_name.append("_service_run");
49 return scoped_name;
52 class ServiceProcessTerminateMonitor
53 : public base::win::ObjectWatcher::Delegate {
54 public:
55 explicit ServiceProcessTerminateMonitor(const base::Closure& terminate_task)
56 : terminate_task_(terminate_task) {
58 void Start() {
59 base::string16 event_name = GetServiceProcessTerminateEventName();
60 DCHECK(event_name.length() <= MAX_PATH);
61 terminate_event_.Set(CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
62 watcher_.StartWatching(terminate_event_.Get(), this);
65 // base::ObjectWatcher::Delegate implementation.
66 virtual void OnObjectSignaled(HANDLE object) {
67 // TODO(vadimt): Remove ScopedProfile below once crbug.com/418183 is fixed.
68 tracked_objects::ScopedProfile tracking_profile(
69 FROM_HERE_WITH_EXPLICIT_FUNCTION(
70 "ServiceProcessTerminateMonitor_OnObjectSignaled"));
72 if (!terminate_task_.is_null()) {
73 terminate_task_.Run();
74 terminate_task_.Reset();
78 private:
79 base::win::ScopedHandle terminate_event_;
80 base::win::ObjectWatcher watcher_;
81 base::Closure terminate_task_;
84 } // namespace
86 // Gets the name of the service process IPC channel.
87 IPC::ChannelHandle GetServiceProcessChannel() {
88 return GetServiceProcessScopedVersionedName("_service_ipc");
91 bool ForceServiceProcessShutdown(const std::string& version,
92 base::ProcessId process_id) {
93 base::win::ScopedHandle terminate_event;
94 std::string versioned_name = version;
95 versioned_name.append(kTerminateEventSuffix);
96 base::string16 event_name =
97 base::UTF8ToWide(GetServiceProcessScopedName(versioned_name));
98 terminate_event.Set(OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name.c_str()));
99 if (!terminate_event.IsValid())
100 return false;
101 SetEvent(terminate_event.Get());
102 return true;
105 bool CheckServiceProcessReady() {
106 base::string16 event_name = GetServiceProcessReadyEventName();
107 base::win::ScopedHandle event(
108 OpenEvent(SYNCHRONIZE | READ_CONTROL, false, event_name.c_str()));
109 if (!event.IsValid())
110 return false;
111 // Check if the event is signaled.
112 return WaitForSingleObject(event.Get(), 0) == WAIT_OBJECT_0;
115 struct ServiceProcessState::StateData {
116 // An event that is signaled when a service process is ready.
117 base::win::ScopedHandle ready_event;
118 scoped_ptr<ServiceProcessTerminateMonitor> terminate_monitor;
121 void ServiceProcessState::CreateState() {
122 DCHECK(!state_);
123 state_ = new StateData;
126 bool ServiceProcessState::TakeSingletonLock() {
127 DCHECK(state_);
128 base::string16 event_name = GetServiceProcessReadyEventName();
129 DCHECK(event_name.length() <= MAX_PATH);
130 base::win::ScopedHandle service_process_ready_event;
131 service_process_ready_event.Set(
132 CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
133 DWORD error = GetLastError();
134 if ((error == ERROR_ALREADY_EXISTS) || (error == ERROR_ACCESS_DENIED))
135 return false;
136 DCHECK(service_process_ready_event.IsValid());
137 state_->ready_event.Set(service_process_ready_event.Take());
138 return true;
141 bool ServiceProcessState::SignalReady(
142 base::MessageLoopProxy* message_loop_proxy,
143 const base::Closure& terminate_task) {
144 DCHECK(state_);
145 DCHECK(state_->ready_event.IsValid());
146 if (!SetEvent(state_->ready_event.Get())) {
147 return false;
149 if (!terminate_task.is_null()) {
150 state_->terminate_monitor.reset(
151 new ServiceProcessTerminateMonitor(terminate_task));
152 state_->terminate_monitor->Start();
154 return true;
157 bool ServiceProcessState::AddToAutoRun() {
158 DCHECK(autorun_command_line_.get());
159 // Remove the old autorun value first because we changed the naming scheme
160 // for the autorun value name.
161 base::win::RemoveCommandFromAutoRun(
162 HKEY_CURRENT_USER,
163 base::UTF8ToWide(GetObsoleteServiceProcessAutoRunKey()));
164 return base::win::AddCommandToAutoRun(
165 HKEY_CURRENT_USER,
166 base::UTF8ToWide(GetServiceProcessAutoRunKey()),
167 autorun_command_line_->GetCommandLineString());
170 bool ServiceProcessState::RemoveFromAutoRun() {
171 // Remove the old autorun value first because we changed the naming scheme
172 // for the autorun value name.
173 base::win::RemoveCommandFromAutoRun(
174 HKEY_CURRENT_USER,
175 base::UTF8ToWide(GetObsoleteServiceProcessAutoRunKey()));
176 return base::win::RemoveCommandFromAutoRun(
177 HKEY_CURRENT_USER, base::UTF8ToWide(GetServiceProcessAutoRunKey()));
180 void ServiceProcessState::TearDownState() {
181 delete state_;
182 state_ = NULL;