Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(107)

Side by Side Diff: remoting/host/daemon_process_win.cc

Issue 11040065: [Chromoting] Reimplemented the worker process launcher to take into account the encountered issues: (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: CR feedback. Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/host/daemon_process.h" 5 #include "remoting/host/daemon_process.h"
6 6
7 #include "base/base_switches.h" 7 #include "base/base_switches.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/bind_helpers.h" 9 #include "base/bind_helpers.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/path_service.h" 11 #include "base/path_service.h"
12 #include "base/single_thread_task_runner.h" 12 #include "base/single_thread_task_runner.h"
13 #include "base/time.h" 13 #include "base/time.h"
14 #include "base/timer.h" 14 #include "base/timer.h"
15 #include "base/utf_string_conversions.h" 15 #include "base/utf_string_conversions.h"
16 #include "base/win/scoped_handle.h" 16 #include "base/win/scoped_handle.h"
17 #include "remoting/host/host_exit_codes.h" 17 #include "remoting/host/host_exit_codes.h"
18 #include "remoting/host/win/launch_process_with_token.h" 18 #include "remoting/host/win/launch_process_with_token.h"
19 #include "remoting/host/win/unprivileged_process_delegate.h"
19 #include "remoting/host/win/worker_process_launcher.h" 20 #include "remoting/host/win/worker_process_launcher.h"
20 21
21 using base::win::ScopedHandle; 22 using base::win::ScopedHandle;
22 using base::TimeDelta; 23 using base::TimeDelta;
23 24
24 namespace { 25 namespace {
25 26
26 // The minimum and maximum delays between attempts to launch the networking
27 // process.
28 const int kMaxLaunchDelaySeconds = 60;
29 const int kMinLaunchDelaySeconds = 1;
30
31 const FilePath::CharType kMe2meHostBinaryName[] = 27 const FilePath::CharType kMe2meHostBinaryName[] =
32 FILE_PATH_LITERAL("remoting_host.exe"); 28 FILE_PATH_LITERAL("remoting_host.exe");
33 29
34 // The IPC channel name is passed to the networking process in the command line.
35 const char kDaemonPipeSwitchName[] = "daemon-pipe";
36
37 // The command line parameters that should be copied from the service's command
38 // line to the network process.
39 const char* kCopiedSwitchNames[] = {
40 "host-config", switches::kV, switches::kVModule };
41
42 // The security descriptor of the daemon IPC endpoint. It gives full access 30 // The security descriptor of the daemon IPC endpoint. It gives full access
43 // to LocalSystem and denies access by anyone else. 31 // to LocalSystem and denies access by anyone else.
44 const char kDaemonPipeSecurityDescriptor[] = "O:SYG:SYD:(A;;GA;;;SY)"; 32 const char kDaemonPipeSecurityDescriptor[] = "O:SYG:SYD:(A;;GA;;;SY)";
45 33
46 } // namespace 34 } // namespace
47 35
48 namespace remoting { 36 namespace remoting {
49 37
50 class DaemonProcessWin : public DaemonProcess, 38 class DaemonProcessWin : public DaemonProcess {
51 public WorkerProcessLauncher::Delegate {
52 public: 39 public:
53 DaemonProcessWin(scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 40 DaemonProcessWin(scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
54 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, 41 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
55 const base::Closure& stopped_callback); 42 const base::Closure& stopped_callback);
56 virtual ~DaemonProcessWin(); 43 virtual ~DaemonProcessWin();
57 44
58 virtual void OnChannelConnected() OVERRIDE; 45 virtual void OnChannelConnected() OVERRIDE;
59 46
60 // Sends an IPC message to the worker process. This method can be called only 47 // Sends an IPC message to the worker process. This method can be called only
61 // after successful Start() and until Stop() is called or an error occurred. 48 // after successful Start() and until Stop() is called or an error occurred.
62 virtual void Send(IPC::Message* message) OVERRIDE; 49 virtual void Send(IPC::Message* message) OVERRIDE;
63 50
64 // WorkerProcessLauncher::Delegate implementation.
65 virtual bool DoLaunchProcess(
66 const std::string& channel_name,
67 ScopedHandle* process_exit_event_out) OVERRIDE;
68 virtual void DoKillProcess(DWORD exit_code) OVERRIDE;
69
70 protected: 51 protected:
71 // Stoppable implementation. 52 // Stoppable implementation.
72 virtual void DoStop() OVERRIDE; 53 virtual void DoStop() OVERRIDE;
73 54
74 // DaemonProcess implementation. 55 // DaemonProcess implementation.
75 virtual void LaunchNetworkProcess() OVERRIDE; 56 virtual void LaunchNetworkProcess() OVERRIDE;
76 57
77 private: 58 private:
78 // Called when the launcher reports the worker process has stopped. 59 // True if the network process has connected to the daemon at least once.
Wez 2012/10/09 03:40:39 You clear this flag in DoStop, though, so that's n
alexeypa (please no reviews) 2012/10/09 19:42:04 Removed |connected_|. This is not much value in it
79 void OnLauncherStopped();
80
81 // True if the network process is connected to the daemon.
82 bool connected_; 60 bool connected_;
83 61
84 // Time of the last launch attempt. 62 scoped_refptr<WorkerProcessLauncher> launcher_;
85 base::Time launch_time_;
86
87 // Current backoff delay.
88 base::TimeDelta launch_backoff_;
89
90 // Timer used to schedule the next attempt to launch the process.
91 base::OneShotTimer<DaemonProcessWin> timer_;
92
93 scoped_ptr<WorkerProcessLauncher> launcher_;
94
95 ScopedHandle network_process_;
96 63
97 DISALLOW_COPY_AND_ASSIGN(DaemonProcessWin); 64 DISALLOW_COPY_AND_ASSIGN(DaemonProcessWin);
98 }; 65 };
99 66
100 DaemonProcessWin::DaemonProcessWin( 67 DaemonProcessWin::DaemonProcessWin(
101 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 68 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
102 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, 69 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
103 const base::Closure& stopped_callback) 70 const base::Closure& stopped_callback)
104 : DaemonProcess(main_task_runner, io_task_runner, stopped_callback), 71 : DaemonProcess(main_task_runner, io_task_runner, stopped_callback),
105 connected_(false) { 72 connected_(false) {
106 } 73 }
107 74
108 DaemonProcessWin::~DaemonProcessWin() { 75 DaemonProcessWin::~DaemonProcessWin() {
109 // Make sure that the object is completely stopped. The same check exists 76 // Make sure that the object is completely stopped. The same check exists
110 // in Stoppable::~Stoppable() but this one helps us to fail early and 77 // in Stoppable::~Stoppable() but this one helps us to fail early and
111 // predictably. 78 // predictably.
112 CHECK_EQ(stoppable_state(), Stoppable::kStopped); 79 CHECK_EQ(stoppable_state(), Stoppable::kStopped);
113 } 80 }
114 81
115 void DaemonProcessWin::LaunchNetworkProcess() { 82 void DaemonProcessWin::LaunchNetworkProcess() {
116 DCHECK(main_task_runner()->BelongsToCurrentThread()); 83 DCHECK(main_task_runner()->BelongsToCurrentThread());
117 DCHECK(launcher_.get() == NULL); 84 DCHECK(launcher_.get() == NULL);
118 DCHECK(!network_process_.IsValid());
119 DCHECK(!timer_.IsRunning());
120 85
121 launch_time_ = base::Time::Now(); 86 // Construct the host binary name.
122 launcher_.reset(new WorkerProcessLauncher( 87 FilePath dir_path;
123 this, this, 88 if (!PathService::Get(base::DIR_EXE, &dir_path)) {
124 base::Bind(&DaemonProcessWin::OnLauncherStopped, base::Unretained(this)), 89 LOG(ERROR) << "Failed to get the executable file name.";
125 main_task_runner(), 90 Stop();
126 io_task_runner())); 91 return;
127 launcher_->Start(kDaemonPipeSecurityDescriptor); 92 }
93
94 scoped_ptr<UnprivilegedProcessDelegate> delegate(
95 new UnprivilegedProcessDelegate(main_task_runner(), io_task_runner(),
96 dir_path.Append(kMe2meHostBinaryName)));
97 launcher_ = new WorkerProcessLauncher(main_task_runner(),
98 io_task_runner(),
99 delegate.Pass(),
100 this,
101 kDaemonPipeSecurityDescriptor);
102 launcher_->Start();
128 } 103 }
129 104
130 void DaemonProcessWin::OnChannelConnected() { 105 void DaemonProcessWin::OnChannelConnected() {
131 connected_ = true; 106 connected_ = true;
132 DaemonProcess::OnChannelConnected(); 107 DaemonProcess::OnChannelConnected();
133 } 108 }
134 109
135 void DaemonProcessWin::Send(IPC::Message* message) { 110 void DaemonProcessWin::Send(IPC::Message* message) {
136 if (connected_) { 111 if (connected_) {
137 launcher_->Send(message); 112 launcher_->Send(message);
138 } else { 113 } else {
139 delete message; 114 delete message;
140 } 115 }
141 } 116 }
142 117
143 bool DaemonProcessWin::DoLaunchProcess(
144 const std::string& channel_name,
145 ScopedHandle* process_exit_event_out) {
146 DCHECK(main_task_runner()->BelongsToCurrentThread());
147 DCHECK(!network_process_.IsValid());
148
149 // Construct the host binary name.
150 FilePath dir_path;
151 if (!PathService::Get(base::DIR_EXE, &dir_path)) {
152 LOG(ERROR) << "Failed to get the executable file name.";
153 return false;
154 }
155 FilePath host_binary = dir_path.Append(kMe2meHostBinaryName);
156
157 // Create the host process command line, passing the name of the IPC channel
158 // to use and copying known switches from the service's command line.
159 CommandLine command_line(host_binary);
160 command_line.AppendSwitchNative(kDaemonPipeSwitchName,
161 UTF8ToWide(channel_name));
162 command_line.CopySwitchesFrom(*CommandLine::ForCurrentProcess(),
163 kCopiedSwitchNames,
164 _countof(kCopiedSwitchNames));
165
166 ScopedHandle token;
167 if (!OpenProcessToken(GetCurrentProcess(),
168 MAXIMUM_ALLOWED,
169 token.Receive())) {
170 LOG_GETLASTERROR(FATAL) << "Failed to open process token";
171 return false;
172 }
173
174 // Try to launch the process and attach an object watcher to the returned
175 // handle so that we get notified when the process terminates.
176 // TODO(alexeypa): Pass a restricted process token.
177 // See http://crbug.com/134694.
178 ScopedHandle worker_thread;
179 if (!LaunchProcessWithToken(host_binary,
180 command_line.GetCommandLineString(),
181 token,
182 0,
183 &network_process_,
184 &worker_thread)) {
185 return false;
186 }
187
188 ScopedHandle process_exit_event;
189 if (!DuplicateHandle(GetCurrentProcess(),
190 network_process_,
191 GetCurrentProcess(),
192 process_exit_event.Receive(),
193 SYNCHRONIZE,
194 FALSE,
195 0)) {
196 LOG_GETLASTERROR(ERROR) << "Failed to duplicate a handle";
197 DoKillProcess(CONTROL_C_EXIT);
198 return false;
199 }
200
201 *process_exit_event_out = process_exit_event.Pass();
202 return true;
203 }
204
205 void DaemonProcessWin::DoKillProcess(DWORD exit_code) {
206 DCHECK(main_task_runner()->BelongsToCurrentThread());
207 CHECK(network_process_.IsValid());
208
209 TerminateProcess(network_process_, exit_code);
210 }
211
212 void DaemonProcessWin::DoStop() { 118 void DaemonProcessWin::DoStop() {
213 DCHECK(main_task_runner()->BelongsToCurrentThread()); 119 DCHECK(main_task_runner()->BelongsToCurrentThread());
214 120
215 timer_.Stop(); 121 connected_ = false;
216
217 if (launcher_.get() != NULL) { 122 if (launcher_.get() != NULL) {
218 launcher_->Stop(); 123 launcher_->Stop();
219 } 124 launcher_ = NULL;
220
221 // Early exit if we're still waiting for |launcher_| to stop.
222 if (launcher_.get() != NULL) {
223 return;
224 } 125 }
225 126
226 DaemonProcess::DoStop(); 127 DaemonProcess::DoStop();
227 } 128 }
228 129
229 void DaemonProcessWin::OnLauncherStopped() {
230 DCHECK(main_task_runner()->BelongsToCurrentThread());
231 CHECK(network_process_.IsValid());
232
233 DWORD exit_code = CONTROL_C_EXIT;
234 if (!::GetExitCodeProcess(network_process_, &exit_code)) {
235 LOG_GETLASTERROR(INFO)
236 << "Failed to query the exit code of the worker process";
237 exit_code = CONTROL_C_EXIT;
238 }
239
240 network_process_.Close();
241 connected_ = false;
242 launcher_.reset(NULL);
243
244 // Do not relaunch the network process if the caller has asked us to stop.
245 if (stoppable_state() != Stoppable::kRunning) {
246 Stop();
247 return;
248 }
249
250 // Stop trying to restart the worker process if its process exited due to
251 // misconfiguration.
252 if (kMinPermanentErrorExitCode <= exit_code &&
253 exit_code <= kMaxPermanentErrorExitCode) {
254 Stop();
255 return;
256 }
257
258 // Expand the backoff interval if the process has died quickly or reset it
259 // if it was up longer than the maximum backoff delay.
260 base::TimeDelta delta = base::Time::Now() - launch_time_;
261 if (delta < base::TimeDelta() ||
262 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) {
263 launch_backoff_ = base::TimeDelta();
264 } else {
265 launch_backoff_ = std::max(
266 launch_backoff_ * 2, TimeDelta::FromSeconds(kMinLaunchDelaySeconds));
267 launch_backoff_ = std::min(
268 launch_backoff_, TimeDelta::FromSeconds(kMaxLaunchDelaySeconds));
269 }
270
271 // Try to launch the worker process.
272 timer_.Start(FROM_HERE, launch_backoff_,
273 this, &DaemonProcessWin::LaunchNetworkProcess);
274 }
275
276 scoped_ptr<DaemonProcess> DaemonProcess::Create( 130 scoped_ptr<DaemonProcess> DaemonProcess::Create(
277 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 131 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
278 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, 132 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
279 const base::Closure& stopped_callback) { 133 const base::Closure& stopped_callback) {
280 scoped_ptr<DaemonProcessWin> daemon_process( 134 scoped_ptr<DaemonProcessWin> daemon_process(
281 new DaemonProcessWin(main_task_runner, io_task_runner, stopped_callback)); 135 new DaemonProcessWin(main_task_runner, io_task_runner, stopped_callback));
282 return daemon_process.PassAs<DaemonProcess>(); 136 return daemon_process.PassAs<DaemonProcess>();
283 } 137 }
284 138
285 } // namespace remoting 139 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698