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"
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");
52 class ServiceProcessTerminateMonitor
53 : public base::win::ObjectWatcher::Delegate
{
55 explicit ServiceProcessTerminateMonitor(const base::Closure
& terminate_task
)
56 : terminate_task_(terminate_task
) {
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();
79 base::win::ScopedHandle terminate_event_
;
80 base::win::ObjectWatcher watcher_
;
81 base::Closure terminate_task_
;
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())
101 SetEvent(terminate_event
.Get());
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())
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() {
123 state_
= new StateData
;
126 bool ServiceProcessState::TakeSingletonLock() {
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
))
136 DCHECK(service_process_ready_event
.IsValid());
137 state_
->ready_event
.Set(service_process_ready_event
.Take());
141 bool ServiceProcessState::SignalReady(
142 base::MessageLoopProxy
* message_loop_proxy
,
143 const base::Closure
& terminate_task
) {
145 DCHECK(state_
->ready_event
.IsValid());
146 if (!SetEvent(state_
->ready_event
.Get())) {
149 if (!terminate_task
.is_null()) {
150 state_
->terminate_monitor
.reset(
151 new ServiceProcessTerminateMonitor(terminate_task
));
152 state_
->terminate_monitor
->Start();
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(
163 base::UTF8ToWide(GetObsoleteServiceProcessAutoRunKey()));
164 return base::win::AddCommandToAutoRun(
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(
175 base::UTF8ToWide(GetObsoleteServiceProcessAutoRunKey()));
176 return base::win::RemoveCommandFromAutoRun(
177 HKEY_CURRENT_USER
, base::UTF8ToWide(GetServiceProcessAutoRunKey()));
180 void ServiceProcessState::TearDownState() {