1//
2// Copyright (C) 2015 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#ifndef SHILL_PROCESS_MANAGER_H_
18#define SHILL_PROCESS_MANAGER_H_
19
20#include <map>
21#include <string>
22#include <vector>
23
24#include <base/callback.h>
25#include <base/cancelable_callback.h>
26#include <base/files/file_path.h>
27#include <base/lazy_instance.h>
28#include <base/memory/weak_ptr.h>
29#include <base/tracked_objects.h>
30#include <brillo/minijail/minijail.h>
31#include <brillo/process.h>
32#include <brillo/process_reaper.h>
33
34namespace shill {
35
36class EventDispatcher;
37
38// The ProcessManager is a singleton providing process creation and
39// asynchronous process termination. Need to initialize it once with
40// Init method call.
41class ProcessManager {
42 public:
43  virtual ~ProcessManager();
44
45  // This is a singleton -- use ProcessManager::GetInstance()->Foo().
46  static ProcessManager* GetInstance();
47
48  // Register async signal handler and setup process reaper.
49  virtual void Init(EventDispatcher* dispatcher);
50
51  // Call on shutdown to release async_signal_handler_.
52  virtual void Stop();
53
54  // Create and start a process for |program| with |arguments|. |enivronment|
55  // variables will be setup in the child process before exec the |program|.
56  // |terminate_with_parent| is used to indicate if child process should
57  // self terminate if the parent process exits.  |exit_callback| will be
58  // invoked when child process exits (not terminated by us).  Return -1
59  // if failed to start the process, otherwise, return the pid of the child
60  // process.
61  virtual pid_t StartProcess(
62      const tracked_objects::Location& spawn_source,
63      const base::FilePath& program,
64      const std::vector<std::string>& arguments,
65      const std::map<std::string, std::string>& environment,
66      bool terminate_with_parent,
67      const base::Callback<void(int)>& exit_callback);
68
69  // Similar to StartProcess(), with the following differences:
70  // - environment variables are not supported (no need yet)
71  // - terminate_with_parent is not supported (may be non-trivial)
72  // - the child process will run as |user| and |group|
73  // - the |capmask| argument can be used to provide the child process
74  //   with capabilities, which |user| might not have on its own
75  virtual pid_t StartProcessInMinijail(
76      const tracked_objects::Location& spawn_source,
77      const base::FilePath& program,
78      const std::vector<std::string>& arguments,
79      const std::string& user,
80      const std::string& group,
81      uint64_t capmask,
82      const base::Callback<void(int)>& exit_callback) {
83    return StartProcessInMinijailWithPipes(
84        spawn_source, program, arguments, user, group, capmask, exit_callback,
85        nullptr, nullptr, nullptr);
86  }
87
88  // Similar to StartProcessInMinijail(), with the additional ability to
89  // pipe the child's stdin/stdout/stderr back to us. If any of those
90  // streams is not needed, simply pass nullptr for the corresponding
91  // 'fd' argument. If no pipes are needed, use StartProcessInMinijail().
92  virtual pid_t StartProcessInMinijailWithPipes(
93      const tracked_objects::Location& spawn_source,
94      const base::FilePath& program,
95      const std::vector<std::string>& arguments,
96      const std::string& user,
97      const std::string& group,
98      uint64_t capmask,
99      const base::Callback<void(int)>& exit_callback,
100      int* stdin_fd,
101      int* stdout_fd,
102      int* stderr_fd);
103
104  // Stop the given |pid|.  Previously registered |exit_callback| will be
105  // unregistered, since the caller is not interested in this process anymore
106  // and that callback might not be valid by the time this process terminates.
107  // This will attempt to terminate the child process by sending a SIGTERM
108  // signal first.  If the process doesn't terminate within a certain time,
109  // ProcessManager will attempt to send a SIGKILL signal.  It will give up
110  // with an error log If the process still doesn't terminate within a certain
111  // time.
112  virtual bool StopProcess(pid_t pid);
113
114  // Stop the given |pid| in a synchronous manner.
115  virtual bool StopProcessAndBlock(pid_t pid);
116
117  // Replace the current exit callback for |pid| with |new_callback|.
118  virtual bool UpdateExitCallback(
119      pid_t pid,
120      const base::Callback<void(int)>& new_callback);
121
122 protected:
123  ProcessManager();
124
125 private:
126  friend class ProcessManagerTest;
127  friend struct base::DefaultLazyInstanceTraits<ProcessManager>;
128
129  using TerminationTimeoutCallback = base::CancelableClosure;
130
131  // Invoked when process |pid| exited.
132  void OnProcessExited(pid_t pid, const siginfo_t& info);
133
134  // Invoked when process |pid| did not terminate within a certain timeout.
135  // |kill_signal| indicates the signal used for termination. When it is set
136  // to true, SIGKILL was used to terminate the process, otherwise, SIGTERM
137  // was used.
138  void ProcessTerminationTimeoutHandler(pid_t pid, bool kill_signal);
139
140  // Send a termination signal to process |pid|. If |kill_signal| is set to
141  // true, SIGKILL is sent, otherwise, SIGTERM is sent.  After signal is sent,
142  // |pid| and timeout handler is added to |pending_termination_processes_|
143  // list, to make sure process |pid| does exit in timely manner.
144  bool TerminateProcess(pid_t pid, bool kill_signal);
145
146  // Kill process |pid|. If |kill_signal| is true it will send SIGKILL,
147  // otherwise it will send SIGTERM.
148  // It returns true when the process was already dead or killed within
149  // the timeout.
150  // It returns false when the process failed to exit within the timeout
151  // or the system failed to send kill singal.
152  bool KillProcessWithTimeout(pid_t pid, bool kill_signal);
153
154  // Kill process |pid| using signal |signal|.
155  // The |killed| will be set true when the process was already dead.
156  // It returns true when it sent the |signal| successfully or the
157  // process was already dead.
158  // It returns false when the system failed to send |signal|.
159  bool KillProcess(pid_t pid, int signal, bool* killed);
160
161  // Wait for process |pid| to exit. This function will check it for at most
162  // |tries| times. The interval of waiting time grows exponentially from
163  // |sleep_ms| and it has an |upper_bound_ms| upper bound.
164  bool WaitpidWithTimeout(pid_t pid,
165                          unsigned int sleep_ms,
166                          unsigned int upper_bound_ms,
167                          int tries);
168
169  // Used to watch processes.
170  std::unique_ptr<brillo::AsynchronousSignalHandler> async_signal_handler_;
171  brillo::ProcessReaper process_reaper_;
172
173  EventDispatcher* dispatcher_;
174  brillo::Minijail* minijail_;
175
176  // Processes to watch for the caller.
177  std::map<pid_t, base::Callback<void(int)>> watched_processes_;
178  // Processes being terminated by us.  Use a timer to make sure process
179  // does exit, log an error if it failed to exit within a specific timeout.
180  std::map<pid_t, std::unique_ptr<TerminationTimeoutCallback>>
181      pending_termination_processes_;
182
183  base::WeakPtrFactory<ProcessManager> weak_factory_{this};
184  DISALLOW_COPY_AND_ASSIGN(ProcessManager);
185};
186
187}  // namespace shill
188
189#endif  // SHILL_PROCESS_MANAGER_H_
190