blob: e26e9bbef6d5eb0df27de03d3935764be1ce76e6 [file] [log] [blame]
Viet-Trung Luuc8e6b802015-10-01 14:58:35 -07001// Copyright 2015 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 "services/native_support/process_controller_impl.h"
6
7#include <errno.h>
8#include <signal.h>
9#include <sys/types.h>
10
11#include <utility>
12
13#include "base/bind.h"
14#include "base/callback.h"
15#include "base/location.h"
16#include "base/logging.h"
17#include "base/message_loop/message_loop.h"
18#include "base/task_runner.h"
19#include "base/threading/simple_thread.h"
Viet-Trung Luu08e339a2015-10-10 01:03:09 -070020#include "mojo/services/files/interfaces/types.mojom.h"
Viet-Trung Luuc8e6b802015-10-01 14:58:35 -070021#include "services/native_support/process_io_redirection.h"
22
23namespace native_support {
24
25namespace {
26
27void WaitForProcess(
28 base::Process process,
29 scoped_refptr<base::TaskRunner> done_runner,
30 const base::Callback<void(mojo::files::Error, int32_t)>& done_callback) {
31 int exit_status = 0;
32 mojo::files::Error result = process.WaitForExit(&exit_status)
John Grossman87fe5142015-10-02 10:11:43 -070033 ? mojo::files::Error::OK
34 : mojo::files::Error::UNKNOWN;
Viet-Trung Luuc8e6b802015-10-01 14:58:35 -070035 done_runner->PostTask(
36 FROM_HERE,
37 base::Bind(done_callback, result, static_cast<int32_t>(exit_status)));
38}
39
40void TerminateProcess(base::Process process) {
41 if (!process.Terminate(-1, true))
42 LOG(ERROR) << "Failed to kill PID " << process.Pid();
43}
44
45} // namespace
46
47ProcessControllerImpl::ProcessControllerImpl(
48 scoped_refptr<base::TaskRunner> worker_runner,
49 mojo::InterfaceRequest<ProcessController> request,
50 base::Process process,
51 std::unique_ptr<ProcessIORedirection> process_io_redirection)
52 : worker_runner_(worker_runner.Pass()),
53 binding_(this, request.Pass()),
54 process_(process.Pass()),
55 process_io_redirection_(std::move(process_io_redirection)),
56 weak_factory_(this) {
57 DCHECK(process_.IsValid());
58}
59
60ProcessControllerImpl::~ProcessControllerImpl() {
61 if (process_.IsValid()) {
62 worker_runner_->PostTask(
63 FROM_HERE, base::Bind(&TerminateProcess, base::Passed(&process_)));
64 }
65}
66
67void ProcessControllerImpl::Wait(const WaitCallback& callback) {
68 if (!process_.IsValid()) {
69 // TODO(vtl): This isn't quite right.
John Grossman87fe5142015-10-02 10:11:43 -070070 callback.Run(mojo::files::Error::UNAVAILABLE, 0);
Viet-Trung Luuc8e6b802015-10-01 14:58:35 -070071 return;
72 }
73
74 worker_runner_->PostTask(
75 FROM_HERE, base::Bind(&WaitForProcess, base::Passed(&process_),
76 base::MessageLoop::current()->task_runner(),
77 base::Bind(&ProcessControllerImpl::OnWaitComplete,
78 weak_factory_.GetWeakPtr(), callback)));
79}
80
81void ProcessControllerImpl::Kill(int32_t signal, const KillCallback& callback) {
82 callback.Run(KillHelper(signal));
83}
84
85void ProcessControllerImpl::OnWaitComplete(const WaitCallback& callback,
86 mojo::files::Error result,
87 int32_t exit_status) {
88 callback.Run(result, exit_status);
89}
90
91mojo::files::Error ProcessControllerImpl::KillHelper(int32_t signal) {
92 if (signal < 0)
John Grossman87fe5142015-10-02 10:11:43 -070093 return mojo::files::Error::INVALID_ARGUMENT;
Viet-Trung Luuc8e6b802015-10-01 14:58:35 -070094
95 if (!process_.IsValid()) {
96 LOG(ERROR) << "Kill() called after Wait()";
97 // TODO(vtl): This error code isn't quite right, but "unavailable" (which
98 // would also be wrong) is used for a more appropriate purpose below.
John Grossman87fe5142015-10-02 10:11:43 -070099 return mojo::files::Error::INVALID_ARGUMENT;
Viet-Trung Luuc8e6b802015-10-01 14:58:35 -0700100 }
101
102 // |base::HandleType| is just a typedef for |pid_t|.
103 pid_t pid = process_.Handle();
104
105 // Note: |kill()| is not interruptible.
106 if (kill(pid, static_cast<int>(signal)) == 0)
John Grossman87fe5142015-10-02 10:11:43 -0700107 return mojo::files::Error::OK;
Viet-Trung Luuc8e6b802015-10-01 14:58:35 -0700108
109 switch (errno) {
110 case EINVAL:
John Grossman87fe5142015-10-02 10:11:43 -0700111 return mojo::files::Error::INVALID_ARGUMENT;
Viet-Trung Luuc8e6b802015-10-01 14:58:35 -0700112 case EPERM:
John Grossman87fe5142015-10-02 10:11:43 -0700113 return mojo::files::Error::PERMISSION_DENIED;
Viet-Trung Luuc8e6b802015-10-01 14:58:35 -0700114 case ESRCH:
John Grossman87fe5142015-10-02 10:11:43 -0700115 return mojo::files::Error::UNAVAILABLE;
Viet-Trung Luuc8e6b802015-10-01 14:58:35 -0700116 default:
117 break;
118 }
John Grossman87fe5142015-10-02 10:11:43 -0700119 return mojo::files::Error::UNKNOWN;
Viet-Trung Luuc8e6b802015-10-01 14:58:35 -0700120}
121
122} // namespace native_support