1 // 2 // Copyright (C) 2011 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 UPDATE_ENGINE_COMMON_SUBPROCESS_H_ 18 #define UPDATE_ENGINE_COMMON_SUBPROCESS_H_ 19 20 #include <unistd.h> 21 22 #include <map> 23 #include <memory> 24 #include <string> 25 #include <vector> 26 27 #include <base/callback.h> 28 #include <base/logging.h> 29 #include <base/macros.h> 30 #include <brillo/asynchronous_signal_handler_interface.h> 31 #include <brillo/message_loops/message_loop.h> 32 #include <brillo/process.h> 33 #include <brillo/process_reaper.h> 34 #include <gtest/gtest_prod.h> // for FRIEND_TEST 35 36 // The Subprocess class is a singleton. It's used to spawn off a subprocess 37 // and get notified when the subprocess exits. The result of Exec() can 38 // be saved and used to cancel the callback request and kill your process. If 39 // you know you won't call KillExec(), you may safely lose the return value 40 // from Exec(). 41 42 // To create the Subprocess singleton just instantiate it with and call Init(). 43 // You can't have two Subprocess instances initialized at the same time. 44 45 namespace chromeos_update_engine { 46 47 class Subprocess { 48 public: 49 enum Flags { 50 kSearchPath = 1 << 0, 51 kRedirectStderrToStdout = 1 << 1, 52 }; 53 54 // Callback type used when an async process terminates. It receives the exit 55 // code and the stdout output (and stderr if redirected). 56 using ExecCallback = base::Callback<void(int, const std::string&)>; 57 58 Subprocess() = default; 59 60 // Destroy and unregister the Subprocess singleton. 61 ~Subprocess(); 62 63 // Initialize and register the Subprocess singleton. 64 void Init(brillo::AsynchronousSignalHandlerInterface* async_signal_handler); 65 66 // Launches a process in the background and calls the passed |callback| when 67 // the process exits. The file descriptors specified in |output_pipes| will 68 // be available in the child as the writer end of a pipe. Use GetPipeFd() to 69 // know the reader end in the parent. Only stdin, stdout, stderr and the file 70 // descriptors in |output_pipes| will be open in the child. 71 // Returns the process id of the new launched process or 0 in case of failure. 72 pid_t Exec(const std::vector<std::string>& cmd, const ExecCallback& callback); 73 pid_t ExecFlags(const std::vector<std::string>& cmd, 74 uint32_t flags, 75 const std::vector<int>& output_pipes, 76 const ExecCallback& callback); 77 78 // Kills the running process with SIGTERM and ignores the callback. 79 void KillExec(pid_t pid); 80 81 // Return the parent end of the pipe mapped onto |fd| in the child |pid|. This 82 // file descriptor is available until the callback for the child |pid| 83 // returns. After that the file descriptor will be closed. The passed |fd| 84 // must be one of the file descriptors passed to ExecFlags() in 85 // |output_pipes|, otherwise returns -1. 86 int GetPipeFd(pid_t pid, int fd) const; 87 88 // Executes a command synchronously. Returns true on success. If |stdout| is 89 // non-null, the process output is stored in it, otherwise the output is 90 // logged. Note that stderr is redirected to stdout. 91 static bool SynchronousExec(const std::vector<std::string>& cmd, 92 int* return_code, 93 std::string* stdout); 94 static bool SynchronousExecFlags(const std::vector<std::string>& cmd, 95 uint32_t flags, 96 int* return_code, 97 std::string* stdout); 98 99 // Gets the one instance. Get()100 static Subprocess& Get() { 101 return *subprocess_singleton_; 102 } 103 104 // Returns true iff there is at least one subprocess we're waiting on. 105 bool SubprocessInFlight(); 106 107 private: 108 FRIEND_TEST(SubprocessTest, CancelTest); 109 110 struct SubprocessRecord { SubprocessRecordSubprocessRecord111 explicit SubprocessRecord(const ExecCallback& callback) 112 : callback(callback) {} 113 114 // The callback supplied by the caller. 115 ExecCallback callback; 116 117 // The ProcessImpl instance managing the child process. Destroying this 118 // will close our end of the pipes we have open. 119 brillo::ProcessImpl proc; 120 121 // These are used to monitor the stdout of the running process, including 122 // the stderr if it was redirected. 123 brillo::MessageLoop::TaskId stdout_task_id{ 124 brillo::MessageLoop::kTaskIdNull}; 125 int stdout_fd{-1}; 126 std::string stdout; 127 }; 128 129 // Callback which runs whenever there is input available on the subprocess 130 // stdout pipe. 131 static void OnStdoutReady(SubprocessRecord* record); 132 133 // Callback for when any subprocess terminates. This calls the user 134 // requested callback. 135 void ChildExitedCallback(const siginfo_t& info); 136 137 // The global instance. 138 static Subprocess* subprocess_singleton_; 139 140 // A map from the asynchronous subprocess tag (see Exec) to the subprocess 141 // record structure for all active asynchronous subprocesses. 142 std::map<pid_t, std::unique_ptr<SubprocessRecord>> subprocess_records_; 143 144 // Used to watch for child processes. 145 brillo::ProcessReaper process_reaper_; 146 147 DISALLOW_COPY_AND_ASSIGN(Subprocess); 148 }; 149 150 } // namespace chromeos_update_engine 151 152 #endif // UPDATE_ENGINE_COMMON_SUBPROCESS_H_ 153