Home | History | Annotate | Download | only in common
      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.
    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 {
    111     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