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

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: Count the worker exiting too such as a failure. 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" 17 #include "base/time.h"
18 #include "base/timer.h"
20 #include "base/utf_string_conversions.h" 19 #include "base/utf_string_conversions.h"
20 #include "base/win/object_watcher.h"
21 #include "base/win/scoped_handle.h" 21 #include "base/win/scoped_handle.h"
22 #include "ipc/ipc_channel.h"
22 #include "ipc/ipc_channel_proxy.h" 23 #include "ipc/ipc_channel_proxy.h"
23 #include "ipc/ipc_message.h" 24 #include "ipc/ipc_message.h"
25 #include "net/base/backoff_entry.h"
26 #include "remoting/host/host_exit_codes.h"
24 #include "remoting/host/worker_process_ipc_delegate.h" 27 #include "remoting/host/worker_process_ipc_delegate.h"
25 28
26 using base::win::ScopedHandle; 29 using base::win::ScopedHandle;
27 30 using base::TimeDelta;
28 namespace {
29 31
30 // Match the pipe name prefix used by Chrome IPC channels so that the client 32 // Match the pipe name prefix used by Chrome IPC channels so that the client
31 // could use Chrome IPC APIs instead of connecting manually. 33 // could use Chrome IPC APIs instead of connecting manually.
32 const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome."; 34 const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome.";
33 35
34 } // namespace 36 // The minimum and maximum delays between attempts to inject host process into
37 // a session.
38 const int kMaxLaunchDelaySeconds = 60;
39 const int kMinLaunchDelaySeconds = 1;
40
41 const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
42 // Number of initial errors (in sequence) to ignore before applying
43 // exponential back-off rules.
44 0,
45
46 // Initial delay for exponential back-off in ms.
47 1000,
48
49 // Factor by which the waiting time will be multiplied.
50 2,
51
52 // Fuzzing percentage. ex: 10% will spread requests randomly
53 // between 90%-100% of the calculated time.
54 0,
55
56 // Maximum amount of time we are willing to delay our request in ms.
57 60000,
58
59 // Time to keep an entry from being discarded even when it
60 // has no significant state, -1 to never discard.
61 -1,
62
63 // Don't use initial delay unless the last request was an error.
64 false,
65 };
66
35 67
36 namespace remoting { 68 namespace remoting {
37 69
70 // Launches a worker process that is controlled via an IPC channel. All
71 // interaction with the spawned process is through the IPC::Listener and Send()
72 // method. In case of error the channel is closed and the worker process is
73 // terminated.
74 class WorkerProcessLauncher::Core
75 : public base::RefCountedThreadSafe<WorkerProcessLauncher::Core>,
76 public base::win::ObjectWatcher::Delegate,
77 public IPC::Listener {
78 public:
79 // Creates the launcher that will use |launcher_delegate| to manage the worker
80 // process and |worker_delegate| to handle IPCs. The caller must ensure that
81 // |worker_delegate| remains valid until Stoppable::Stop() method has been
82 // called.
83 //
84 // The caller should call all the methods on this class on
85 // the |caller_task_runner| thread. Methods of both delegate interfaces are
86 // called on the |caller_task_runner| thread as well. |io_task_runner| is used
87 // to perform background IPC I/O.
88 Core(scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
89 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
90 scoped_ptr<WorkerProcessLauncher::Delegate> launcher_delegate,
91 WorkerProcessIpcDelegate* worker_delegate,
92 const std::string& pipe_security_descriptor);
93
94 // Launches the worker process.
95 void Start();
96
97 // Stops the worker process asynchronously. The caller can drop the reference
98 // to |this| as soon as Stop() returns.
99 void Stop();
100
101 // Sends an IPC message to the worker process. The message will be silently
102 // dropped if Send() is called before Start() or after stutdown has been
103 // initiated.
104 void Send(IPC::Message* message);
105
106 // base::win::ObjectWatcher::Delegate implementation.
107 virtual void OnObjectSignaled(HANDLE object) OVERRIDE;
108
109 // IPC::Listener implementation.
110 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
111 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
112 virtual void OnChannelError() OVERRIDE;
113
114 private:
115 friend class base::RefCountedThreadSafe<Core>;
116 virtual ~Core();
117
118 // Creates the server end of the Chromoting IPC channel.
119 bool CreatePipeForIpcChannel(const std::string& channel_name,
120 const std::string& pipe_security_descriptor,
121 base::win::ScopedHandle* pipe_out);
122
123 // Generates random channel ID.
124 std::string GenerateRandomChannelId();
125
126 // Attempts to launch the worker process. Schedules next launch attempt if
127 // creation of the process fails.
128 void LaunchWorker();
129
130 // Records a successfull launch attempt.
131 void RecordSuccessfullLaunch();
132
133 // Stops the worker process asynchronously and schedules next launch attempt
134 // unless Stop() has been called already.
135 void StopWorker();
136
137 // All public methods are called on the |caller_task_runner| thread.
138 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
139
140 // The task runner is used perform background IPC I/O.
141 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
142
143 // Implements specifics of launching a worker process.
144 scoped_ptr<WorkerProcessLauncher::Delegate> launcher_delegate_;
145
146 // Handles IPC messages sent by the worker process.
147 WorkerProcessIpcDelegate* worker_delegate_;
148
149 // The IPC channel connecting to the launched process.
150 scoped_ptr<IPC::ChannelProxy> ipc_channel_;
151
152 // The timer used to delay termination of the process in the case of an IPC
153 // error.
154 scoped_ptr<base::OneShotTimer<Core> > ipc_error_timer_;
155
156 // Launch backoff state.
157 net::BackoffEntry launch_backoff_;
158
159 // Timer used to delay recording a successfull launch.
160 scoped_ptr<base::OneShotTimer<Core> > launch_success_timer_;
161
162 // Timer used to schedule the next attempt to launch the process.
163 scoped_ptr<base::OneShotTimer<Core> > launch_timer_;
164
165 // Used to determine when the launched process terminates.
166 base::win::ObjectWatcher process_watcher_;
167
168 // A waiting handle that becomes signalled once the launched process has
169 // been terminated.
170 base::win::ScopedHandle process_exit_event_;
171
172 // The server end of the pipe.
173 base::win::ScopedHandle pipe_;
174
175 // The security descriptor (as SDDL) of the server end of the pipe.
176 std::string pipe_security_descriptor_;
177
178 // Self reference to keep the object alive while the worker process is being
179 // terminated.
180 scoped_refptr<Core> self_;
181
182 // True when Stop() has been called.
183 bool stopping_;
184
185 DISALLOW_COPY_AND_ASSIGN(Core);
186 };
187
38 WorkerProcessLauncher::Delegate::~Delegate() { 188 WorkerProcessLauncher::Delegate::~Delegate() {
39 } 189 }
40 190
41 WorkerProcessLauncher::WorkerProcessLauncher( 191 WorkerProcessLauncher::Core::Core(
42 Delegate* launcher_delegate, 192 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
193 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
194 scoped_ptr<WorkerProcessLauncher::Delegate> launcher_delegate,
43 WorkerProcessIpcDelegate* worker_delegate, 195 WorkerProcessIpcDelegate* worker_delegate,
44 const base::Closure& stopped_callback, 196 const std::string& pipe_security_descriptor)
45 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 197 : caller_task_runner_(caller_task_runner),
46 scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner) 198 io_task_runner_(io_task_runner),
47 : Stoppable(main_task_runner, stopped_callback), 199 launcher_delegate_(launcher_delegate.Pass()),
48 launcher_delegate_(launcher_delegate),
49 worker_delegate_(worker_delegate), 200 worker_delegate_(worker_delegate),
50 main_task_runner_(main_task_runner), 201 launch_backoff_(&kDefaultBackoffPolicy),
51 ipc_task_runner_(ipc_task_runner) { 202 pipe_security_descriptor_(pipe_security_descriptor),
52 } 203 stopping_(false) {
53 204 DCHECK(caller_task_runner_->BelongsToCurrentThread());
54 WorkerProcessLauncher::~WorkerProcessLauncher() { 205
55 DCHECK(main_task_runner_->BelongsToCurrentThread()); 206 // base::OneShotTimer must be destroyed on the same thread it was created on.
56 } 207 ipc_error_timer_.reset(new base::OneShotTimer<Core>());
57 208 launch_success_timer_.reset(new base::OneShotTimer<Core>());
58 void WorkerProcessLauncher::Start(const std::string& pipe_sddl) { 209 launch_timer_.reset(new base::OneShotTimer<Core>());
59 DCHECK(main_task_runner_->BelongsToCurrentThread()); 210 }
60 DCHECK(ipc_channel_.get() == NULL); 211
61 DCHECK(!pipe_.IsValid()); 212 void WorkerProcessLauncher::Core::Start() {
62 DCHECK(!process_exit_event_.IsValid()); 213 DCHECK(caller_task_runner_->BelongsToCurrentThread());
63 DCHECK(process_watcher_.GetWatchedObject() == NULL); 214 DCHECK(!stopping_);
64 215
65 std::string channel_name = GenerateRandomChannelId(); 216 LaunchWorker();
66 if (CreatePipeForIpcChannel(channel_name, pipe_sddl, &pipe_)) { 217 }
67 // Wrap the pipe into an IPC channel. 218
68 ipc_channel_.reset(new IPC::ChannelProxy( 219 void WorkerProcessLauncher::Core::Stop() {
69 IPC::ChannelHandle(pipe_), 220 DCHECK(caller_task_runner_->BelongsToCurrentThread());
70 IPC::Channel::MODE_SERVER, 221
71 this, 222 if (!stopping_) {
72 ipc_task_runner_)); 223 stopping_ = true;
73 224 worker_delegate_ = NULL;
74 // Launch the process and attach an object watcher to the returned process 225 StopWorker();
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 } 226 }
85 227 }
86 Stop(); 228
87 } 229 void WorkerProcessLauncher::Core::Send(IPC::Message* message) {
88 230 DCHECK(caller_task_runner_->BelongsToCurrentThread());
89 void WorkerProcessLauncher::Send(IPC::Message* message) {
90 DCHECK(main_task_runner_->BelongsToCurrentThread());
91 231
92 if (ipc_channel_.get()) { 232 if (ipc_channel_.get()) {
93 ipc_channel_->Send(message); 233 ipc_channel_->Send(message);
94 } else { 234 } else {
95 delete message; 235 delete message;
96 } 236 }
97 } 237 }
98 238
99 void WorkerProcessLauncher::OnObjectSignaled(HANDLE object) { 239 void WorkerProcessLauncher::Core::OnObjectSignaled(HANDLE object) {
100 DCHECK(main_task_runner_->BelongsToCurrentThread()); 240 DCHECK(caller_task_runner_->BelongsToCurrentThread());
101 DCHECK(process_watcher_.GetWatchedObject() == NULL); 241 DCHECK(process_watcher_.GetWatchedObject() == NULL);
102 242
103 Stop(); 243 StopWorker();
104 } 244 }
105 245
106 bool WorkerProcessLauncher::OnMessageReceived(const IPC::Message& message) { 246 bool WorkerProcessLauncher::Core::OnMessageReceived(
107 DCHECK(main_task_runner_->BelongsToCurrentThread()); 247 const IPC::Message& message) {
248 DCHECK(caller_task_runner_->BelongsToCurrentThread());
108 DCHECK(ipc_channel_.get() != NULL); 249 DCHECK(ipc_channel_.get() != NULL);
109 DCHECK(pipe_.IsValid());
110 DCHECK(process_exit_event_.IsValid());
111 250
112 return worker_delegate_->OnMessageReceived(message); 251 return worker_delegate_->OnMessageReceived(message);
113 } 252 }
114 253
115 void WorkerProcessLauncher::OnChannelConnected(int32 peer_pid) { 254 void WorkerProcessLauncher::Core::OnChannelConnected(int32 peer_pid) {
116 DCHECK(main_task_runner_->BelongsToCurrentThread()); 255 DCHECK(caller_task_runner_->BelongsToCurrentThread());
117 DCHECK(ipc_channel_.get() != NULL); 256 DCHECK(ipc_channel_.get() != NULL);
118 DCHECK(pipe_.IsValid());
119 DCHECK(process_exit_event_.IsValid());
120 257
121 // |peer_pid| is send by the client and cannot be trusted. 258 // |peer_pid| is send by the client and cannot be trusted.
122 // GetNamedPipeClientProcessId() is not available on XP. The pipe's security 259 // GetNamedPipeClientProcessId() is not available on XP. The pipe's security
123 // descriptor is the only protection we currently have against malicious 260 // descriptor is the only protection we currently have against malicious
124 // clients. 261 // clients.
125 // 262 //
126 // If we'd like to be able to launch low-privileged workers and let them 263 // 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 264 // connect back, the pipe handle should be passed to the worker instead of
128 // the pipe name. 265 // the pipe name.
129 worker_delegate_->OnChannelConnected(); 266 worker_delegate_->OnChannelConnected();
130 } 267 }
131 268
132 void WorkerProcessLauncher::OnChannelError() { 269 void WorkerProcessLauncher::Core::OnChannelError() {
133 DCHECK(main_task_runner_->BelongsToCurrentThread()); 270 DCHECK(caller_task_runner_->BelongsToCurrentThread());
134 DCHECK(ipc_channel_.get() != NULL); 271 DCHECK(ipc_channel_.get() != NULL);
135 DCHECK(pipe_.IsValid());
136 DCHECK(process_exit_event_.IsValid());
137 272
138 // Schedule a delayed termination of the worker process. Usually, the pipe is 273 // 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 274 // disconnected when the worker process is about to exit. Waiting a little bit
140 // here allows the worker to exit completely and so, notify 275 // here allows the worker to exit completely and so, notify
141 // |process_watcher_|. As the result DoKillProcess() will not be called and 276 // |process_watcher_|. As the result KillProcess() will not be called and
142 // the original exit code reported by the worker process will be retrieved. 277 // the original exit code reported by the worker process will be retrieved.
143 ipc_error_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5), 278 ipc_error_timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
144 this, &WorkerProcessLauncher::Stop); 279 this, &Core::StopWorker);
145 } 280 }
146 281
147 void WorkerProcessLauncher::DoStop() { 282 WorkerProcessLauncher::Core::~Core() {
148 DCHECK(main_task_runner_->BelongsToCurrentThread()); 283 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 } 284 }
168 285
169 // Creates the server end of the Chromoting IPC channel. 286 // Creates the server end of the Chromoting IPC channel.
170 bool WorkerProcessLauncher::CreatePipeForIpcChannel( 287 bool WorkerProcessLauncher::Core::CreatePipeForIpcChannel(
171 const std::string& channel_name, 288 const std::string& channel_name,
172 const std::string& pipe_sddl, 289 const std::string& pipe_security_descriptor,
173 ScopedHandle* pipe_out) { 290 ScopedHandle* pipe_out) {
174 // Create security descriptor for the channel. 291 // Create security descriptor for the channel.
175 SECURITY_ATTRIBUTES security_attributes; 292 SECURITY_ATTRIBUTES security_attributes;
176 security_attributes.nLength = sizeof(security_attributes); 293 security_attributes.nLength = sizeof(security_attributes);
177 security_attributes.bInheritHandle = FALSE; 294 security_attributes.bInheritHandle = FALSE;
178 295
179 ULONG security_descriptor_length = 0; 296 ULONG security_descriptor_length = 0;
180 if (!ConvertStringSecurityDescriptorToSecurityDescriptor( 297 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
181 UTF8ToUTF16(pipe_sddl).c_str(), 298 UTF8ToUTF16(pipe_security_descriptor).c_str(),
182 SDDL_REVISION_1, 299 SDDL_REVISION_1,
183 reinterpret_cast<PSECURITY_DESCRIPTOR*>( 300 reinterpret_cast<PSECURITY_DESCRIPTOR*>(
184 &security_attributes.lpSecurityDescriptor), 301 &security_attributes.lpSecurityDescriptor),
185 &security_descriptor_length)) { 302 &security_descriptor_length)) {
186 LOG_GETLASTERROR(ERROR) << 303 LOG_GETLASTERROR(ERROR) <<
187 "Failed to create a security descriptor for the Chromoting IPC channel"; 304 "Failed to create a security descriptor for the Chromoting IPC channel";
188 return false; 305 return false;
189 } 306 }
190 307
191 // Convert the channel name to the pipe name. 308 // Convert the channel name to the pipe name.
(...skipping 19 matching lines...) Expand all
211 return false; 328 return false;
212 } 329 }
213 330
214 LocalFree(security_attributes.lpSecurityDescriptor); 331 LocalFree(security_attributes.lpSecurityDescriptor);
215 332
216 *pipe_out = pipe.Pass(); 333 *pipe_out = pipe.Pass();
217 return true; 334 return true;
218 } 335 }
219 336
220 // N.B. Copied from src/content/common/child_process_host_impl.cc 337 // N.B. Copied from src/content/common/child_process_host_impl.cc
221 std::string WorkerProcessLauncher::GenerateRandomChannelId() { 338 std::string WorkerProcessLauncher::Core::GenerateRandomChannelId() {
222 return base::StringPrintf("%d.%p.%d", 339 return base::StringPrintf("%d.%p.%d",
223 base::GetCurrentProcId(), this, 340 base::GetCurrentProcId(), this,
224 base::RandInt(0, std::numeric_limits<int>::max())); 341 base::RandInt(0, std::numeric_limits<int>::max()));
225 } 342 }
226 343
344 void WorkerProcessLauncher::Core::LaunchWorker() {
345 DCHECK(caller_task_runner_->BelongsToCurrentThread());
346 DCHECK(ipc_channel_.get() == NULL);
347 DCHECK(!launch_success_timer_->IsRunning());
348 DCHECK(!launch_timer_->IsRunning());
349 DCHECK(!pipe_.IsValid());
350 DCHECK(!process_exit_event_.IsValid());
351 DCHECK(process_watcher_.GetWatchedObject() == NULL);
352
353 std::string channel_name = GenerateRandomChannelId();
354 if (CreatePipeForIpcChannel(channel_name, pipe_security_descriptor_,
355 &pipe_)) {
356 // Wrap the pipe into an IPC channel.
357 ipc_channel_.reset(new IPC::ChannelProxy(
358 IPC::ChannelHandle(pipe_),
359 IPC::Channel::MODE_SERVER,
360 this,
361 io_task_runner_));
362
363 // Launch the process and attach an object watcher to the returned process
364 // handle so that we get notified if the process terminates.
365 if (launcher_delegate_->LaunchProcess(channel_name, &process_exit_event_)) {
366 if (process_watcher_.StartWatching(process_exit_event_, this)) {
367 // Record a successful launch once the process has been running for at
368 // least two seconds.
Wez 2012/10/10 00:52:03 nit: Record success two seconds after the process
alexeypa (please no reviews) 2012/10/10 16:58:19 It makes sense. It is a more than a single line ch
369 launch_success_timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(2),
370 this, &Core::RecordSuccessfullLaunch);
371 return;
372 }
373
374 launcher_delegate_->KillProcess(CONTROL_C_EXIT);
375 }
376 }
377
378 launch_backoff_.InformOfRequest(false);
379 StopWorker();
380 }
381
382 void WorkerProcessLauncher::Core::RecordSuccessfullLaunch() {
383 DCHECK(caller_task_runner_->BelongsToCurrentThread());
384
385 launch_backoff_.InformOfRequest(true);
386 }
387
388 void WorkerProcessLauncher::Core::StopWorker() {
389 DCHECK(caller_task_runner_->BelongsToCurrentThread());
390
391 // Record a launch failure if the process exited too soon.
392 if (launch_success_timer_->IsRunning()) {
393 launch_success_timer_->Stop();
394 launch_backoff_.InformOfRequest(false);
395 }
396
397 // Keep |this| alive until the worker process is terminated.
398 self_ = this;
399
400 ipc_channel_.reset();
401 pipe_.Close();
402
403 // Kill the process if it has been started already.
404 if (process_watcher_.GetWatchedObject() != NULL) {
405 launcher_delegate_->KillProcess(CONTROL_C_EXIT);
406 return;
407 }
408
409 ipc_error_timer_->Stop();
410
411 DCHECK(ipc_channel_.get() == NULL);
412 DCHECK(!pipe_.IsValid());
413 DCHECK(process_watcher_.GetWatchedObject() == NULL);
414
415 process_exit_event_.Close();
416
417 // Do not relaunch the worker process if the caller has asked us to stop.
418 if (stopping_) {
419 ipc_error_timer_.reset();
420 launch_timer_.reset();
421 self_ = NULL;
422 return;
423 }
424
425 self_ = NULL;
426
427 // Stop trying to restart the worker process if it exited due to
428 // misconfiguration.
429 DWORD exit_code = launcher_delegate_->GetExitCode();
430 if (kMinPermanentErrorExitCode <= exit_code &&
431 exit_code <= kMaxPermanentErrorExitCode) {
432 // |delegate_| must be valid because Stop() hasn't been called yet and
433 // |running_| is true. |worker_delegate_| is valid here because Stop()
434 // hasn't been called yet (|stopping_| is false).
435 worker_delegate_->OnPermanentError();
436 return;
437 }
438
439 // Schedule the next attempt to launch the worker process.
440 launch_timer_->Start(FROM_HERE, launch_backoff_.GetTimeUntilRelease(),
441 this, &Core::LaunchWorker);
442 }
443
444 WorkerProcessLauncher::WorkerProcessLauncher(
445 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
446 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
447 scoped_ptr<Delegate> launcher_delegate,
448 WorkerProcessIpcDelegate* worker_delegate,
449 const std::string& pipe_security_descriptor) {
450 core_ = new Core(caller_task_runner, io_task_runner, launcher_delegate.Pass(),
451 worker_delegate, pipe_security_descriptor);
452 core_->Start();
453 }
454
455 WorkerProcessLauncher::~WorkerProcessLauncher() {
456 core_->Stop();
457 core_ = NULL;
458 }
459
460 void WorkerProcessLauncher::Send(IPC::Message* message) {
461 core_->Send(message);
462 }
463
227 } // namespace remoting 464 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698