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/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"
23 const char kTerminateEventSuffix
[] = "_service_terminate_evt";
25 base::string16
GetServiceProcessReadyEventName() {
26 return base::UTF8ToWide(
27 GetServiceProcessScopedVersionedName("_service_ready"));
30 base::string16
GetServiceProcessTerminateEventName() {
31 return base::UTF8ToWide(
32 GetServiceProcessScopedVersionedName(kTerminateEventSuffix
));
35 std::string
GetServiceProcessAutoRunKey() {
36 return GetServiceProcessScopedName("_service_run");
39 // Returns the name of the autotun reg value that we used to use for older
40 // versions of Chrome.
41 std::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");
51 class ServiceProcessTerminateMonitor
52 : public base::win::ObjectWatcher::Delegate
{
54 explicit ServiceProcessTerminateMonitor(const base::Closure
& terminate_task
)
55 : terminate_task_(terminate_task
) {
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);
64 // base::ObjectWatcher::Delegate implementation.
65 void OnObjectSignaled(HANDLE object
) override
{
66 if (!terminate_task_
.is_null()) {
67 terminate_task_
.Run();
68 terminate_task_
.Reset();
73 base::win::ScopedHandle terminate_event_
;
74 base::win::ObjectWatcher watcher_
;
75 base::Closure terminate_task_
;
80 // Gets the name of the service process IPC channel.
81 IPC::ChannelHandle
GetServiceProcessChannel() {
82 return GetServiceProcessScopedVersionedName("_service_ipc");
85 bool 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())
95 SetEvent(terminate_event
.Get());
99 bool 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())
105 // Check if the event is signaled.
106 return WaitForSingleObject(event
.Get(), 0) == WAIT_OBJECT_0
;
109 struct 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
;
115 void ServiceProcessState::CreateState() {
117 state_
= new StateData
;
120 bool ServiceProcessState::TakeSingletonLock() {
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
))
130 DCHECK(service_process_ready_event
.IsValid());
131 state_
->ready_event
.Set(service_process_ready_event
.Take());
135 bool ServiceProcessState::SignalReady(
136 base::MessageLoopProxy
* message_loop_proxy
,
137 const base::Closure
& terminate_task
) {
139 DCHECK(state_
->ready_event
.IsValid());
140 if (!SetEvent(state_
->ready_event
.Get())) {
143 if (!terminate_task
.is_null()) {
144 state_
->terminate_monitor
.reset(
145 new ServiceProcessTerminateMonitor(terminate_task
));
146 state_
->terminate_monitor
->Start();
151 bool 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(
157 base::UTF8ToWide(GetObsoleteServiceProcessAutoRunKey()));
158 return base::win::AddCommandToAutoRun(
160 base::UTF8ToWide(GetServiceProcessAutoRunKey()),
161 autorun_command_line_
->GetCommandLineString());
164 bool 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(
169 base::UTF8ToWide(GetObsoleteServiceProcessAutoRunKey()));
170 return base::win::RemoveCommandFromAutoRun(
171 HKEY_CURRENT_USER
, base::UTF8ToWide(GetServiceProcessAutoRunKey()));
174 void ServiceProcessState::TearDownState() {