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
3 // found in the LICENSE file.
5 #include "remoting/host/win/worker_process_launcher.h"
7 #include "base/logging.h"
8 #include "base/single_thread_task_runner.h"
10 #include "base/timer.h"
11 #include "base/win/object_watcher.h"
12 #include "base/win/windows_version.h"
13 #include "ipc/ipc_listener.h"
14 #include "ipc/ipc_message.h"
15 #include "net/base/backoff_entry.h"
16 #include "remoting/host/worker_process_ipc_delegate.h"
18 using base::TimeDelta
;
19 using base::win::ScopedHandle
;
21 const net::BackoffEntry::Policy kDefaultBackoffPolicy
= {
22 // Number of initial errors (in sequence) to ignore before applying
23 // exponential back-off rules.
26 // Initial delay for exponential back-off in ms.
29 // Factor by which the waiting time will be multiplied.
32 // Fuzzing percentage. ex: 10% will spread requests randomly
33 // between 90%-100% of the calculated time.
36 // Maximum amount of time we are willing to delay our request in ms.
39 // Time to keep an entry from being discarded even when it
40 // has no significant state, -1 to never discard.
43 // Don't use initial delay unless the last request was an error.
50 // Launches a worker process that is controlled via an IPC channel. All
51 // interaction with the spawned process is through the IPC::Listener and Send()
52 // method. In case of error the channel is closed and the worker process is
54 class WorkerProcessLauncher::Core
55 : public base::RefCountedThreadSafe
<WorkerProcessLauncher::Core
>,
56 public base::win::ObjectWatcher::Delegate
,
57 public IPC::Listener
{
59 // Creates the launcher that will use |launcher_delegate| to manage the worker
60 // process and |worker_delegate| to handle IPCs. The caller must ensure that
61 // |worker_delegate| remains valid until Stoppable::Stop() method has been
64 // The caller should call all the methods on this class on
65 // the |caller_task_runner| thread. Methods of both delegate interfaces are
66 // called on the |caller_task_runner| thread as well.
67 Core(scoped_refptr
<base::SingleThreadTaskRunner
> caller_task_runner
,
68 scoped_ptr
<WorkerProcessLauncher::Delegate
> launcher_delegate
,
69 WorkerProcessIpcDelegate
* worker_delegate
);
71 // Launches the worker process.
74 // Stops the worker process asynchronously. The caller can drop the reference
75 // to |this| as soon as Stop() returns.
78 // Sends an IPC message to the worker process. The message will be silently
79 // dropped if Send() is called before Start() or after stutdown has been
81 void Send(IPC::Message
* message
);
83 // base::win::ObjectWatcher::Delegate implementation.
84 virtual void OnObjectSignaled(HANDLE object
) OVERRIDE
;
86 // IPC::Listener implementation.
87 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
;
88 virtual void OnChannelConnected(int32 peer_pid
) OVERRIDE
;
89 virtual void OnChannelError() OVERRIDE
;
92 friend class base::RefCountedThreadSafe
<Core
>;
95 // Attempts to launch the worker process. Schedules next launch attempt if
96 // creation of the process fails.
99 // Records a successful launch attempt.
100 void RecordSuccessfulLaunch();
102 // Stops the worker process asynchronously and schedules next launch attempt
103 // unless Stop() has been called already.
106 // All public methods are called on the |caller_task_runner| thread.
107 scoped_refptr
<base::SingleThreadTaskRunner
> caller_task_runner_
;
109 // Implements specifics of launching a worker process.
110 scoped_ptr
<WorkerProcessLauncher::Delegate
> launcher_delegate_
;
112 // Handles IPC messages sent by the worker process.
113 WorkerProcessIpcDelegate
* worker_delegate_
;
115 // Pointer to GetNamedPipeClientProcessId() API if it is available.
116 typedef BOOL (WINAPI
* GetNamedPipeClientProcessIdFn
)(HANDLE
, DWORD
*);
117 GetNamedPipeClientProcessIdFn get_named_pipe_client_pid_
;
119 // True if IPC messages should be passed to |worker_delegate_|.
122 // The timer used to delay termination of the process in the case of an IPC
124 scoped_ptr
<base::OneShotTimer
<Core
> > ipc_error_timer_
;
126 // Launch backoff state.
127 net::BackoffEntry launch_backoff_
;
129 // Timer used to delay recording a successfull launch.
130 scoped_ptr
<base::OneShotTimer
<Core
> > launch_success_timer_
;
132 // Timer used to schedule the next attempt to launch the process.
133 scoped_ptr
<base::OneShotTimer
<Core
> > launch_timer_
;
135 // Used to determine when the launched process terminates.
136 base::win::ObjectWatcher process_watcher_
;
138 // A waiting handle that becomes signalled once the launched process has
140 ScopedHandle process_exit_event_
;
142 // True when Stop() has been called.
145 DISALLOW_COPY_AND_ASSIGN(Core
);
148 WorkerProcessLauncher::Delegate::~Delegate() {
151 WorkerProcessLauncher::Core::Core(
152 scoped_refptr
<base::SingleThreadTaskRunner
> caller_task_runner
,
153 scoped_ptr
<WorkerProcessLauncher::Delegate
> launcher_delegate
,
154 WorkerProcessIpcDelegate
* worker_delegate
)
155 : caller_task_runner_(caller_task_runner
),
156 launcher_delegate_(launcher_delegate
.Pass()),
157 worker_delegate_(worker_delegate
),
158 get_named_pipe_client_pid_(NULL
),
160 launch_backoff_(&kDefaultBackoffPolicy
),
162 DCHECK(caller_task_runner_
->BelongsToCurrentThread());
164 // base::OneShotTimer must be destroyed on the same thread it was created on.
165 ipc_error_timer_
.reset(new base::OneShotTimer
<Core
>());
166 launch_success_timer_
.reset(new base::OneShotTimer
<Core
>());
167 launch_timer_
.reset(new base::OneShotTimer
<Core
>());
170 void WorkerProcessLauncher::Core::Start() {
171 DCHECK(caller_task_runner_
->BelongsToCurrentThread());
177 void WorkerProcessLauncher::Core::Stop() {
178 DCHECK(caller_task_runner_
->BelongsToCurrentThread());
182 worker_delegate_
= NULL
;
187 void WorkerProcessLauncher::Core::Send(IPC::Message
* message
) {
188 DCHECK(caller_task_runner_
->BelongsToCurrentThread());
191 launcher_delegate_
->Send(message
);
197 void WorkerProcessLauncher::Core::OnObjectSignaled(HANDLE object
) {
198 DCHECK(caller_task_runner_
->BelongsToCurrentThread());
199 DCHECK(process_watcher_
.GetWatchedObject() == NULL
);
204 bool WorkerProcessLauncher::Core::OnMessageReceived(
205 const IPC::Message
& message
) {
206 DCHECK(caller_task_runner_
->BelongsToCurrentThread());
211 return worker_delegate_
->OnMessageReceived(message
);
214 void WorkerProcessLauncher::Core::OnChannelConnected(int32 peer_pid
) {
215 DCHECK(caller_task_runner_
->BelongsToCurrentThread());
220 // Verify |peer_pid| because it is controlled by the client and cannot be
222 DWORD actual_pid
= launcher_delegate_
->GetProcessId();
223 if (peer_pid
!= static_cast<int32
>(actual_pid
)) {
224 LOG(ERROR
) << "The actual client PID " << actual_pid
225 << " does not match the one reported by the client: "
231 // This can result in |this| being deleted, so this call must be the last in
233 worker_delegate_
->OnChannelConnected(peer_pid
);
236 void WorkerProcessLauncher::Core::OnChannelError() {
237 DCHECK(caller_task_runner_
->BelongsToCurrentThread());
239 // Schedule a delayed termination of the worker process. Usually, the pipe is
240 // disconnected when the worker process is about to exit. Waiting a little bit
241 // here allows the worker to exit completely and so, notify
242 // |process_watcher_|. As the result KillProcess() will not be called and
243 // the original exit code reported by the worker process will be retrieved.
244 ipc_error_timer_
->Start(FROM_HERE
, base::TimeDelta::FromSeconds(5),
245 this, &Core::StopWorker
);
248 WorkerProcessLauncher::Core::~Core() {
252 void WorkerProcessLauncher::Core::LaunchWorker() {
253 DCHECK(caller_task_runner_
->BelongsToCurrentThread());
254 DCHECK(!ipc_enabled_
);
255 DCHECK(!launch_success_timer_
->IsRunning());
256 DCHECK(!launch_timer_
->IsRunning());
257 DCHECK(!process_exit_event_
.IsValid());
258 DCHECK(process_watcher_
.GetWatchedObject() == NULL
);
260 // Launch the process and attach an object watcher to the returned process
261 // handle so that we get notified if the process terminates.
262 if (launcher_delegate_
->LaunchProcess(this, &process_exit_event_
)) {
263 if (process_watcher_
.StartWatching(process_exit_event_
, this)) {
265 // Record a successful launch once the process has been running for at
266 // least two seconds.
267 launch_success_timer_
->Start(FROM_HERE
, base::TimeDelta::FromSeconds(2),
268 this, &Core::RecordSuccessfulLaunch
);
272 launcher_delegate_
->KillProcess(CONTROL_C_EXIT
);
275 launch_backoff_
.InformOfRequest(false);
279 void WorkerProcessLauncher::Core::RecordSuccessfulLaunch() {
280 DCHECK(caller_task_runner_
->BelongsToCurrentThread());
282 launch_backoff_
.InformOfRequest(true);
285 void WorkerProcessLauncher::Core::StopWorker() {
286 DCHECK(caller_task_runner_
->BelongsToCurrentThread());
288 // Keep the object alive in case one of delegates decides to delete |this|.
289 scoped_refptr
<Core
> self
= this;
291 // Record a launch failure if the process exited too soon.
292 if (launch_success_timer_
->IsRunning()) {
293 launch_success_timer_
->Stop();
294 launch_backoff_
.InformOfRequest(false);
297 // Ignore any remaining IPC messages.
298 ipc_enabled_
= false;
300 // Kill the process if it has been started already.
301 if (process_watcher_
.GetWatchedObject() != NULL
) {
302 launcher_delegate_
->KillProcess(CONTROL_C_EXIT
);
304 // Wait until the process is actually stopped if the caller keeps
305 // a reference to |this|. Otherwise terminate everything right now - there
306 // won't be a second chance.
310 process_watcher_
.StopWatching();
313 ipc_error_timer_
->Stop();
314 process_exit_event_
.Close();
316 // Do not relaunch the worker process if the caller has asked us to stop.
318 ipc_error_timer_
.reset();
319 launch_timer_
.reset();
323 if (launcher_delegate_
->IsPermanentError(launch_backoff_
.failure_count())) {
325 worker_delegate_
->OnPermanentError();
327 // Schedule the next attempt to launch the worker process.
328 launch_timer_
->Start(FROM_HERE
, launch_backoff_
.GetTimeUntilRelease(),
329 this, &Core::LaunchWorker
);
333 WorkerProcessLauncher::WorkerProcessLauncher(
334 scoped_refptr
<base::SingleThreadTaskRunner
> caller_task_runner
,
335 scoped_ptr
<Delegate
> launcher_delegate
,
336 WorkerProcessIpcDelegate
* worker_delegate
) {
337 core_
= new Core(caller_task_runner
, launcher_delegate
.Pass(),
342 WorkerProcessLauncher::~WorkerProcessLauncher() {
347 void WorkerProcessLauncher::Send(IPC::Message
* message
) {
348 core_
->Send(message
);
351 } // namespace remoting