• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
21 namespace {
22 
23 const char* kTerminateEventSuffix = "_service_terminate_evt";
24 
GetServiceProcessReadyEventName()25 base::string16 GetServiceProcessReadyEventName() {
26   return base::UTF8ToWide(
27       GetServiceProcessScopedVersionedName("_service_ready"));
28 }
29 
GetServiceProcessTerminateEventName()30 base::string16 GetServiceProcessTerminateEventName() {
31   return base::UTF8ToWide(
32       GetServiceProcessScopedVersionedName(kTerminateEventSuffix));
33 }
34 
GetServiceProcessAutoRunKey()35 std::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.
GetObsoleteServiceProcessAutoRunKey()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");
48   return scoped_name;
49 }
50 
51 class ServiceProcessTerminateMonitor
52     : public base::win::ObjectWatcher::Delegate {
53  public:
ServiceProcessTerminateMonitor(const base::Closure & terminate_task)54   explicit ServiceProcessTerminateMonitor(const base::Closure& terminate_task)
55       : terminate_task_(terminate_task) {
56   }
Start()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.
OnObjectSignaled(HANDLE object)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.
GetServiceProcessChannel()81 IPC::ChannelHandle GetServiceProcessChannel() {
82   return GetServiceProcessScopedVersionedName("_service_ipc");
83 }
84 
ForceServiceProcessShutdown(const std::string & version,base::ProcessId process_id)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())
94     return false;
95   SetEvent(terminate_event.Get());
96   return true;
97 }
98 
CheckServiceProcessReady()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())
104     return false;
105   // Check if the event is signaled.
106   return WaitForSingleObject(event, 0) == WAIT_OBJECT_0;
107 }
108 
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;
113 };
114 
CreateState()115 void ServiceProcessState::CreateState() {
116   DCHECK(!state_);
117   state_ = new StateData;
118 }
119 
TakeSingletonLock()120 bool 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 
SignalReady(base::MessageLoopProxy * message_loop_proxy,const base::Closure & terminate_task)135 bool 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 
AddToAutoRun()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(
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 
RemoveFromAutoRun()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(
168       HKEY_CURRENT_USER,
169       base::UTF8ToWide(GetObsoleteServiceProcessAutoRunKey()));
170   return base::win::RemoveCommandFromAutoRun(
171       HKEY_CURRENT_USER, base::UTF8ToWide(GetServiceProcessAutoRunKey()));
172 }
173 
TearDownState()174 void ServiceProcessState::TearDownState() {
175   delete state_;
176   state_ = NULL;
177 }
178