// // Copyright (C) 2011 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #ifndef UPDATE_ENGINE_COMMON_SUBPROCESS_H_ #define UPDATE_ENGINE_COMMON_SUBPROCESS_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include // for FRIEND_TEST // The Subprocess class is a singleton. It's used to spawn off a subprocess // and get notified when the subprocess exits. The result of Exec() can // be saved and used to cancel the callback request and kill your process. If // you know you won't call KillExec(), you may safely lose the return value // from Exec(). // To create the Subprocess singleton just instantiate it with and call Init(). // You can't have two Subprocess instances initialized at the same time. namespace chromeos_update_engine { class Subprocess { public: enum Flags { kSearchPath = 1 << 0, kRedirectStderrToStdout = 1 << 1, }; // Callback type used when an async process terminates. It receives the exit // code and the stdout output (and stderr if redirected). using ExecCallback = base::Callback; Subprocess() = default; // Destroy and unregister the Subprocess singleton. ~Subprocess(); // Initialize and register the Subprocess singleton. void Init(brillo::AsynchronousSignalHandlerInterface* async_signal_handler); // Launches a process in the background and calls the passed |callback| when // the process exits. The file descriptors specified in |output_pipes| will // be available in the child as the writer end of a pipe. Use GetPipeFd() to // know the reader end in the parent. Only stdin, stdout, stderr and the file // descriptors in |output_pipes| will be open in the child. // Returns the process id of the new launched process or 0 in case of failure. pid_t Exec(const std::vector& cmd, const ExecCallback& callback); pid_t ExecFlags(const std::vector& cmd, uint32_t flags, const std::vector& output_pipes, const ExecCallback& callback); // Kills the running process with SIGTERM and ignores the callback. void KillExec(pid_t pid); // Return the parent end of the pipe mapped onto |fd| in the child |pid|. This // file descriptor is available until the callback for the child |pid| // returns. After that the file descriptor will be closed. The passed |fd| // must be one of the file descriptors passed to ExecFlags() in // |output_pipes|, otherwise returns -1. int GetPipeFd(pid_t pid, int fd) const; // Executes a command synchronously. Returns true on success. If |stdout| is // non-null, the process output is stored in it, otherwise the output is // logged. Note that stderr is redirected to stdout. static bool SynchronousExec(const std::vector& cmd, int* return_code, std::string* stdout); static bool SynchronousExecFlags(const std::vector& cmd, uint32_t flags, int* return_code, std::string* stdout); // Gets the one instance. static Subprocess& Get() { return *subprocess_singleton_; } // Returns true iff there is at least one subprocess we're waiting on. bool SubprocessInFlight(); private: FRIEND_TEST(SubprocessTest, CancelTest); struct SubprocessRecord { explicit SubprocessRecord(const ExecCallback& callback) : callback(callback) {} // The callback supplied by the caller. ExecCallback callback; // The ProcessImpl instance managing the child process. Destroying this // will close our end of the pipes we have open. brillo::ProcessImpl proc; // These are used to monitor the stdout of the running process, including // the stderr if it was redirected. brillo::MessageLoop::TaskId stdout_task_id{ brillo::MessageLoop::kTaskIdNull}; int stdout_fd{-1}; std::string stdout; }; // Callback which runs whenever there is input available on the subprocess // stdout pipe. static void OnStdoutReady(SubprocessRecord* record); // Callback for when any subprocess terminates. This calls the user // requested callback. void ChildExitedCallback(const siginfo_t& info); // The global instance. static Subprocess* subprocess_singleton_; // A map from the asynchronous subprocess tag (see Exec) to the subprocess // record structure for all active asynchronous subprocesses. std::map> subprocess_records_; // Used to watch for child processes. brillo::ProcessReaper process_reaper_; DISALLOW_COPY_AND_ASSIGN(Subprocess); }; } // namespace chromeos_update_engine #endif // UPDATE_ENGINE_COMMON_SUBPROCESS_H_