service_process_util_win.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
1// Copyright (c) 2010 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/object_watcher.h"
11#include "base/path_service.h"
12#include "base/scoped_handle_win.h"
13#include "base/string16.h"
14#include "base/utf_string_conversions.h"
15#include "base/win_util.h"
16#include "chrome/common/chrome_switches.h"
17
18namespace {
19
20string16 GetServiceProcessReadyEventName() {
21  return UTF8ToWide(
22      GetServiceProcessScopedVersionedName("_service_ready"));
23}
24
25string16 GetServiceProcessShutdownEventName() {
26  return UTF8ToWide(
27      GetServiceProcessScopedVersionedName("_service_shutdown_evt"));
28}
29
30class ServiceProcessShutdownMonitor : public base::ObjectWatcher::Delegate {
31 public:
32  explicit ServiceProcessShutdownMonitor(Task* shutdown_task)
33      : shutdown_task_(shutdown_task) {
34  }
35  void Start() {
36    string16 event_name = GetServiceProcessShutdownEventName();
37    CHECK(event_name.length() <= MAX_PATH);
38    shutdown_event_.Set(CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
39    watcher_.StartWatching(shutdown_event_.Get(), this);
40  }
41
42  // base::ObjectWatcher::Delegate implementation.
43  virtual void OnObjectSignaled(HANDLE object) {
44    shutdown_task_->Run();
45    shutdown_task_.reset();
46  }
47
48 private:
49  ScopedHandle shutdown_event_;
50  base::ObjectWatcher watcher_;
51  scoped_ptr<Task> shutdown_task_;
52};
53
54}  // namespace
55
56bool ForceServiceProcessShutdown(const std::string& version) {
57  ScopedHandle shutdown_event;
58  std::string versioned_name = version;
59  versioned_name.append("_service_shutdown_evt");
60  string16 event_name =
61      UTF8ToWide(GetServiceProcessScopedName(versioned_name));
62  shutdown_event.Set(OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name.c_str()));
63  if (!shutdown_event.IsValid())
64    return false;
65  SetEvent(shutdown_event.Get());
66  return true;
67}
68
69bool CheckServiceProcessReady() {
70  string16 event_name = GetServiceProcessReadyEventName();
71  ScopedHandle event(
72      OpenEvent(SYNCHRONIZE | READ_CONTROL, false, event_name.c_str()));
73  if (!event.IsValid())
74    return false;
75  // Check if the event is signaled.
76  return WaitForSingleObject(event, 0) == WAIT_OBJECT_0;
77}
78
79struct ServiceProcessState::StateData {
80  // An event that is signaled when a service process is ready.
81  ScopedHandle ready_event;
82  scoped_ptr<ServiceProcessShutdownMonitor> shutdown_monitor;
83};
84
85bool ServiceProcessState::TakeSingletonLock() {
86  DCHECK(!state_);
87  string16 event_name = GetServiceProcessReadyEventName();
88  CHECK(event_name.length() <= MAX_PATH);
89  ScopedHandle service_process_ready_event;
90  service_process_ready_event.Set(
91      CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
92  DWORD error = GetLastError();
93  if ((error == ERROR_ALREADY_EXISTS) || (error == ERROR_ACCESS_DENIED))
94    return false;
95  DCHECK(service_process_ready_event.IsValid());
96  state_ = new StateData;
97  state_->ready_event.Set(service_process_ready_event.Take());
98  return true;
99}
100
101void ServiceProcessState::SignalReady(Task* shutdown_task) {
102  DCHECK(state_);
103  DCHECK(state_->ready_event.IsValid());
104  SetEvent(state_->ready_event.Get());
105  if (shutdown_task) {
106    state_->shutdown_monitor.reset(
107        new ServiceProcessShutdownMonitor(shutdown_task));
108    state_->shutdown_monitor->Start();
109  }
110}
111
112void ServiceProcessState::SignalStopped() {
113  TearDownState();
114  shared_mem_service_data_.reset();
115}
116
117bool ServiceProcessState::AddToAutoRun() {
118  FilePath chrome_path;
119  if (PathService::Get(base::FILE_EXE, &chrome_path)) {
120    CommandLine cmd_line(chrome_path);
121    cmd_line.AppendSwitchASCII(switches::kProcessType,
122                               switches::kServiceProcess);
123    // We need a unique name for the command per user-date-dir. Just use the
124    // channel name.
125    return win_util::AddCommandToAutoRun(
126        HKEY_CURRENT_USER,
127        UTF8ToWide(GetAutoRunKey()),
128        cmd_line.command_line_string());
129  }
130  return false;
131}
132
133bool ServiceProcessState::RemoveFromAutoRun() {
134  return win_util::RemoveCommandFromAutoRun(
135      HKEY_CURRENT_USER, UTF8ToWide(GetAutoRunKey()));
136}
137
138void ServiceProcessState::TearDownState() {
139  delete state_;
140  state_ = NULL;
141}
142
143bool ServiceProcessState::ShouldHandleOtherVersion() {
144  return true;
145}
146