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 
34 namespace shill {
35 
36 class 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.
41 class 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
StartProcessInMinijail(const tracked_objects::Location & spawn_source,const base::FilePath & program,const std::vector<std::string> & arguments,const std::string & user,const std::string & group,uint64_t capmask,const base::Callback<void (int)> & exit_callback)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