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

Side by Side Diff: remoting/host/win/worker_process_launcher.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/win/worker_process_launcher.h" 5 #include "remoting/host/win/worker_process_launcher.h"
6 6
7 #include <windows.h>
8 #include <sddl.h> 7 #include <sddl.h>
9 #include <limits> 8 #include <limits>
10 9
11 #include "base/base_switches.h"
12 #include "base/bind.h" 10 #include "base/bind.h"
13 #include "base/bind_helpers.h" 11 #include "base/bind_helpers.h"
14 #include "base/logging.h" 12 #include "base/logging.h"
15 #include "base/single_thread_task_runner.h" 13 #include "base/single_thread_task_runner.h"
16 #include "base/process_util.h" 14 #include "base/process_util.h"
17 #include "base/rand_util.h" 15 #include "base/rand_util.h"
18 #include "base/stringprintf.h" 16 #include "base/stringprintf.h"
19 #include "base/time.h"
20 #include "base/utf_string_conversions.h" 17 #include "base/utf_string_conversions.h"
21 #include "base/win/scoped_handle.h" 18 #include "base/win/scoped_handle.h"
22 #include "ipc/ipc_channel_proxy.h" 19 #include "ipc/ipc_channel_proxy.h"
23 #include "ipc/ipc_message.h" 20 #include "ipc/ipc_message.h"
21 #include "remoting/host/host_exit_codes.h"
24 #include "remoting/host/worker_process_ipc_delegate.h" 22 #include "remoting/host/worker_process_ipc_delegate.h"
25 23
26 using base::win::ScopedHandle; 24 using base::win::ScopedHandle;
25 using base::TimeDelta;
27 26
28 namespace { 27 namespace {
29 28
30 // Match the pipe name prefix used by Chrome IPC channels so that the client 29 // Match the pipe name prefix used by Chrome IPC channels so that the client
31 // could use Chrome IPC APIs instead of connecting manually. 30 // could use Chrome IPC APIs instead of connecting manually.
32 const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome."; 31 const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome.";
33 32
33 // The minimum and maximum delays between attempts to inject host process into
34 // a session.
35 const int kMaxLaunchDelaySeconds = 60;
36 const int kMinLaunchDelaySeconds = 1;
37
34 } // namespace 38 } // namespace
35 39
36 namespace remoting { 40 namespace remoting {
37 41
38 WorkerProcessLauncher::Delegate::~Delegate() { 42 WorkerProcessLauncher::Delegate::~Delegate() {
39 } 43 }
40 44
41 WorkerProcessLauncher::WorkerProcessLauncher( 45 WorkerProcessLauncher::WorkerProcessLauncher(
42 Delegate* launcher_delegate, 46 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
47 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
48 scoped_ptr<Delegate> launcher_delegate,
43 WorkerProcessIpcDelegate* worker_delegate, 49 WorkerProcessIpcDelegate* worker_delegate,
44 const base::Closure& stopped_callback, 50 const std::string& pipe_security_descriptor)
45 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 51 : main_task_runner_(main_task_runner),
46 scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner) 52 io_task_runner_(io_task_runner),
47 : Stoppable(main_task_runner, stopped_callback), 53 launcher_delegate_(launcher_delegate.Pass()),
48 launcher_delegate_(launcher_delegate),
49 worker_delegate_(worker_delegate), 54 worker_delegate_(worker_delegate),
50 main_task_runner_(main_task_runner), 55 pipe_security_descriptor_(pipe_security_descriptor),
51 ipc_task_runner_(ipc_task_runner) { 56 stopping_(false) {
57 DCHECK(main_task_runner_->BelongsToCurrentThread());
58
59 // base::OneShotTimer must be destroyed on the same thread it was created on.
60 ipc_error_timer_.reset(new base::OneShotTimer<WorkerProcessLauncher>());
61 launch_timer_.reset(new base::OneShotTimer<WorkerProcessLauncher>());
52 } 62 }
53 63
54 WorkerProcessLauncher::~WorkerProcessLauncher() { 64 void WorkerProcessLauncher::Start() {
55 DCHECK(main_task_runner_->BelongsToCurrentThread()); 65 DCHECK(main_task_runner_->BelongsToCurrentThread());
66 DCHECK(!stopping_);
67
68 LaunchWorker();
56 } 69 }
57 70
58 void WorkerProcessLauncher::Start(const std::string& pipe_sddl) { 71 void WorkerProcessLauncher::Stop() {
59 DCHECK(main_task_runner_->BelongsToCurrentThread()); 72 DCHECK(main_task_runner_->BelongsToCurrentThread());
60 DCHECK(ipc_channel_.get() == NULL);
61 DCHECK(!pipe_.IsValid());
62 DCHECK(!process_exit_event_.IsValid());
63 DCHECK(process_watcher_.GetWatchedObject() == NULL);
64 73
65 std::string channel_name = GenerateRandomChannelId(); 74 if (!stopping_) {
66 if (CreatePipeForIpcChannel(channel_name, pipe_sddl, &pipe_)) { 75 stopping_ = true;
67 // Wrap the pipe into an IPC channel. 76 worker_delegate_ = NULL;
68 ipc_channel_.reset(new IPC::ChannelProxy( 77 StopWorker();
69 IPC::ChannelHandle(pipe_),
70 IPC::Channel::MODE_SERVER,
71 this,
72 ipc_task_runner_));
73
74 // Launch the process and attach an object watcher to the returned process
75 // handle so that we get notified if the process terminates.
76 if (launcher_delegate_->DoLaunchProcess(channel_name,
77 &process_exit_event_)) {
78 if (process_watcher_.StartWatching(process_exit_event_, this)) {
79 return;
80 }
81
82 launcher_delegate_->DoKillProcess(CONTROL_C_EXIT);
83 }
84 } 78 }
85
86 Stop();
87 } 79 }
88 80
89 void WorkerProcessLauncher::Send(IPC::Message* message) { 81 void WorkerProcessLauncher::Send(IPC::Message* message) {
90 DCHECK(main_task_runner_->BelongsToCurrentThread()); 82 DCHECK(main_task_runner_->BelongsToCurrentThread());
91 83
92 if (ipc_channel_.get()) { 84 if (ipc_channel_.get()) {
93 ipc_channel_->Send(message); 85 ipc_channel_->Send(message);
94 } else { 86 } else {
95 delete message; 87 delete message;
96 } 88 }
97 } 89 }
98 90
99 void WorkerProcessLauncher::OnObjectSignaled(HANDLE object) { 91 void WorkerProcessLauncher::OnObjectSignaled(HANDLE object) {
100 DCHECK(main_task_runner_->BelongsToCurrentThread()); 92 DCHECK(main_task_runner_->BelongsToCurrentThread());
101 DCHECK(process_watcher_.GetWatchedObject() == NULL); 93 DCHECK(process_watcher_.GetWatchedObject() == NULL);
102 94
103 Stop(); 95 StopWorker();
104 } 96 }
105 97
106 bool WorkerProcessLauncher::OnMessageReceived(const IPC::Message& message) { 98 bool WorkerProcessLauncher::OnMessageReceived(const IPC::Message& message) {
107 DCHECK(main_task_runner_->BelongsToCurrentThread()); 99 DCHECK(main_task_runner_->BelongsToCurrentThread());
108 DCHECK(ipc_channel_.get() != NULL); 100 DCHECK(ipc_channel_.get() != NULL);
109 DCHECK(pipe_.IsValid());
110 DCHECK(process_exit_event_.IsValid());
111 101
112 return worker_delegate_->OnMessageReceived(message); 102 return worker_delegate_->OnMessageReceived(message);
113 } 103 }
114 104
115 void WorkerProcessLauncher::OnChannelConnected(int32 peer_pid) { 105 void WorkerProcessLauncher::OnChannelConnected(int32 peer_pid) {
116 DCHECK(main_task_runner_->BelongsToCurrentThread()); 106 DCHECK(main_task_runner_->BelongsToCurrentThread());
117 DCHECK(ipc_channel_.get() != NULL); 107 DCHECK(ipc_channel_.get() != NULL);
118 DCHECK(pipe_.IsValid());
119 DCHECK(process_exit_event_.IsValid());
120 108
121 // |peer_pid| is send by the client and cannot be trusted. 109 // |peer_pid| is send by the client and cannot be trusted.
122 // GetNamedPipeClientProcessId() is not available on XP. The pipe's security 110 // GetNamedPipeClientProcessId() is not available on XP. The pipe's security
123 // descriptor is the only protection we currently have against malicious 111 // descriptor is the only protection we currently have against malicious
124 // clients. 112 // clients.
125 // 113 //
126 // If we'd like to be able to launch low-privileged workers and let them 114 // If we'd like to be able to launch low-privileged workers and let them
127 // connect back, the pipe handle should be passed to the worker instead of 115 // connect back, the pipe handle should be passed to the worker instead of
128 // the pipe name. 116 // the pipe name.
129 worker_delegate_->OnChannelConnected(); 117 worker_delegate_->OnChannelConnected();
130 } 118 }
131 119
132 void WorkerProcessLauncher::OnChannelError() { 120 void WorkerProcessLauncher::OnChannelError() {
133 DCHECK(main_task_runner_->BelongsToCurrentThread()); 121 DCHECK(main_task_runner_->BelongsToCurrentThread());
134 DCHECK(ipc_channel_.get() != NULL); 122 DCHECK(ipc_channel_.get() != NULL);
135 DCHECK(pipe_.IsValid());
136 DCHECK(process_exit_event_.IsValid());
137 123
138 // Schedule a delayed termination of the worker process. Usually, the pipe is 124 // Schedule a delayed termination of the worker process. Usually, the pipe is
139 // disconnected when the worker process is about to exit. Waiting a little bit 125 // disconnected when the worker process is about to exit. Waiting a little bit
140 // here allows the worker to exit completely and so, notify 126 // here allows the worker to exit completely and so, notify
141 // |process_watcher_|. As the result DoKillProcess() will not be called and 127 // |process_watcher_|. As the result KillProcess() will not be called and
142 // the original exit code reported by the worker process will be retrieved. 128 // the original exit code reported by the worker process will be retrieved.
143 ipc_error_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5), 129 ipc_error_timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
144 this, &WorkerProcessLauncher::Stop); 130 this, &WorkerProcessLauncher::StopWorker);
145 } 131 }
146 132
147 void WorkerProcessLauncher::DoStop() { 133 WorkerProcessLauncher::~WorkerProcessLauncher() {
148 DCHECK(main_task_runner_->BelongsToCurrentThread()); 134 DCHECK(stopping_);
149
150 ipc_channel_.reset();
151 pipe_.Close();
152
153 // Kill the process if it has been started already.
154 if (process_watcher_.GetWatchedObject() != NULL) {
155 launcher_delegate_->DoKillProcess(CONTROL_C_EXIT);
156 return;
157 }
158
159 ipc_error_timer_.Stop();
160
161 DCHECK(ipc_channel_.get() == NULL);
162 DCHECK(!pipe_.IsValid());
163 DCHECK(process_watcher_.GetWatchedObject() == NULL);
164
165 process_exit_event_.Close();
166 CompleteStopping();
167 } 135 }
168 136
169 // Creates the server end of the Chromoting IPC channel. 137 // Creates the server end of the Chromoting IPC channel.
170 bool WorkerProcessLauncher::CreatePipeForIpcChannel( 138 bool WorkerProcessLauncher::CreatePipeForIpcChannel(
171 const std::string& channel_name, 139 const std::string& channel_name,
172 const std::string& pipe_sddl, 140 const std::string& pipe_security_descriptor,
173 ScopedHandle* pipe_out) { 141 ScopedHandle* pipe_out) {
174 // Create security descriptor for the channel. 142 // Create security descriptor for the channel.
175 SECURITY_ATTRIBUTES security_attributes; 143 SECURITY_ATTRIBUTES security_attributes;
176 security_attributes.nLength = sizeof(security_attributes); 144 security_attributes.nLength = sizeof(security_attributes);
177 security_attributes.bInheritHandle = FALSE; 145 security_attributes.bInheritHandle = FALSE;
178 146
179 ULONG security_descriptor_length = 0; 147 ULONG security_descriptor_length = 0;
180 if (!ConvertStringSecurityDescriptorToSecurityDescriptor( 148 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
181 UTF8ToUTF16(pipe_sddl).c_str(), 149 UTF8ToUTF16(pipe_security_descriptor).c_str(),
182 SDDL_REVISION_1, 150 SDDL_REVISION_1,
183 reinterpret_cast<PSECURITY_DESCRIPTOR*>( 151 reinterpret_cast<PSECURITY_DESCRIPTOR*>(
184 &security_attributes.lpSecurityDescriptor), 152 &security_attributes.lpSecurityDescriptor),
185 &security_descriptor_length)) { 153 &security_descriptor_length)) {
186 LOG_GETLASTERROR(ERROR) << 154 LOG_GETLASTERROR(ERROR) <<
187 "Failed to create a security descriptor for the Chromoting IPC channel"; 155 "Failed to create a security descriptor for the Chromoting IPC channel";
188 return false; 156 return false;
189 } 157 }
190 158
191 // Convert the channel name to the pipe name. 159 // Convert the channel name to the pipe name.
(...skipping 25 matching lines...) Expand all
217 return true; 185 return true;
218 } 186 }
219 187
220 // N.B. Copied from src/content/common/child_process_host_impl.cc 188 // N.B. Copied from src/content/common/child_process_host_impl.cc
221 std::string WorkerProcessLauncher::GenerateRandomChannelId() { 189 std::string WorkerProcessLauncher::GenerateRandomChannelId() {
222 return base::StringPrintf("%d.%p.%d", 190 return base::StringPrintf("%d.%p.%d",
223 base::GetCurrentProcId(), this, 191 base::GetCurrentProcId(), this,
224 base::RandInt(0, std::numeric_limits<int>::max())); 192 base::RandInt(0, std::numeric_limits<int>::max()));
225 } 193 }
226 194
195 void WorkerProcessLauncher::LaunchWorker() {
196 DCHECK(main_task_runner_->BelongsToCurrentThread());
197 DCHECK(ipc_channel_.get() == NULL);
198 DCHECK(!launch_timer_->IsRunning());
199 DCHECK(!pipe_.IsValid());
200 DCHECK(!process_exit_event_.IsValid());
201 DCHECK(process_watcher_.GetWatchedObject() == NULL);
202
203 launch_time_ = base::Time::Now();
204 std::string channel_name = GenerateRandomChannelId();
205 if (CreatePipeForIpcChannel(channel_name, pipe_security_descriptor_,
206 &pipe_)) {
207 // Wrap the pipe into an IPC channel.
208 ipc_channel_.reset(new IPC::ChannelProxy(
209 IPC::ChannelHandle(pipe_),
210 IPC::Channel::MODE_SERVER,
211 this,
212 io_task_runner_));
213
214 // Launch the process and attach an object watcher to the returned process
215 // handle so that we get notified if the process terminates.
216 if (launcher_delegate_->LaunchProcess(channel_name, &process_exit_event_)) {
217 if (process_watcher_.StartWatching(process_exit_event_, this)) {
218 return;
219 }
220
221 launcher_delegate_->KillProcess(CONTROL_C_EXIT);
222 }
223 }
224
225 StopWorker();
226 }
227
228 void WorkerProcessLauncher::StopWorker() {
229 DCHECK(main_task_runner_->BelongsToCurrentThread());
230
231 // Keep |this| alive until the worker process is terminated.
232 self_ = this;
233
234 ipc_channel_.reset();
235 pipe_.Close();
236
237 // Kill the process if it has been started already.
238 if (process_watcher_.GetWatchedObject() != NULL) {
239 launcher_delegate_->KillProcess(CONTROL_C_EXIT);
240 return;
241 }
242
243 ipc_error_timer_->Stop();
244
245 DCHECK(ipc_channel_.get() == NULL);
246 DCHECK(!pipe_.IsValid());
247 DCHECK(process_watcher_.GetWatchedObject() == NULL);
248
249 process_exit_event_.Close();
250
251 // Do not relaunch the worker process if the caller has asked us to stop.
252 if (stopping_) {
253 ipc_error_timer_.reset();
254 launch_timer_.reset();
255 self_ = NULL;
256 return;
257 }
258
259 self_ = NULL;
260
261 // Stop trying to restart the worker process if it exited due to
262 // misconfiguration.
263 DWORD exit_code = launcher_delegate_->GetExitCode();
264 if (kMinPermanentErrorExitCode <= exit_code &&
265 exit_code <= kMaxPermanentErrorExitCode) {
266 // |delegate_| must be valid because Stop() hasn't been called yet and
267 // |running_| is true. |worker_delegate_| is valid here because Stop()
268 // hasn't been called yet (|stopping_| is false).
269 worker_delegate_->OnPermanentError();
270 return;
271 }
272
273 // Try to restart the worker process. Expand the backoff interval if
274 // the process has died quickly or reset it if it was up longer than
275 // the maximum backoff delay.
Wez 2012/10/09 03:40:39 We use net::BackoffEntry to handle authentication
alexeypa (please no reviews) 2012/10/09 19:42:04 Done.
276 base::TimeDelta delta = base::Time::Now() - launch_time_;
277 if (delta < base::TimeDelta() ||
278 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) {
279 launch_backoff_ = base::TimeDelta();
280 } else {
281 launch_backoff_ = std::max(
282 launch_backoff_ * 2, TimeDelta::FromSeconds(kMinLaunchDelaySeconds));
283 launch_backoff_ = std::min(
284 launch_backoff_, TimeDelta::FromSeconds(kMaxLaunchDelaySeconds));
285 }
286
287 // Try to launch the worker process.
288 launch_timer_->Start(FROM_HERE, launch_backoff_, this,
289 &WorkerProcessLauncher::LaunchWorker);
290 }
291
227 } // namespace remoting 292 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698