| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/process_proxy/process_proxy.h" | 5 #include "chromeos/process_proxy/process_proxy.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <stdlib.h> | 8 #include <stdlib.h> |
| 9 #include <sys/ioctl.h> | 9 #include <sys/ioctl.h> |
| 10 | 10 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/file_util.h" | 13 #include "base/file_util.h" |
| 14 #include "base/posix/eintr_wrapper.h" | 14 #include "base/posix/eintr_wrapper.h" |
| 15 #include "base/process_util.h" | 15 #include "base/process_util.h" |
| 16 #include "base/logging.h" | 16 #include "base/logging.h" |
| 17 #include "base/threading/thread.h" | 17 #include "base/threading/thread.h" |
| 18 #include "chrome/browser/chromeos/process_proxy/process_output_watcher.h" | 18 #include "chromeos/process_proxy/process_output_watcher.h" |
| 19 #include "content/public/browser/browser_thread.h" | |
| 20 | 19 |
| 21 namespace { | 20 namespace { |
| 22 | 21 |
| 23 enum PipeEnd { | 22 enum PipeEnd { |
| 24 PIPE_END_READ, | 23 PIPE_END_READ, |
| 25 PIPE_END_WRITE | 24 PIPE_END_WRITE |
| 26 }; | 25 }; |
| 27 | 26 |
| 28 enum PseudoTerminalFd { | 27 enum PseudoTerminalFd { |
| 29 PT_MASTER_FD, | 28 PT_MASTER_FD, |
| 30 PT_SLAVE_FD | 29 PT_SLAVE_FD |
| 31 }; | 30 }; |
| 32 | 31 |
| 33 const int kInvalidFd = -1; | 32 const int kInvalidFd = -1; |
| 34 | 33 |
| 35 } // namespace | 34 } // namespace |
| 36 | 35 |
| 36 namespace chromeos { |
| 37 |
| 37 ProcessProxy::ProcessProxy(): process_launched_(false), | 38 ProcessProxy::ProcessProxy(): process_launched_(false), |
| 38 callback_set_(false), | 39 callback_set_(false), |
| 39 watcher_started_(false) { | 40 watcher_started_(false) { |
| 40 // Set pipes to initial, invalid value so we can easily know if a pipe was | 41 // Set pipes to initial, invalid value so we can easily know if a pipe was |
| 41 // opened by us. | 42 // opened by us. |
| 42 ClearAllFdPairs(); | 43 ClearAllFdPairs(); |
| 43 }; | 44 }; |
| 44 | 45 |
| 45 bool ProcessProxy::Open(const std::string& command, pid_t* pid) { | 46 bool ProcessProxy::Open(const std::string& command, pid_t* pid) { |
| 46 if (process_launched_) | 47 if (process_launched_) |
| 47 return false; | 48 return false; |
| 48 | 49 |
| 49 if (!CreatePseudoTerminalPair(pt_pair_)) { | 50 if (!CreatePseudoTerminalPair(pt_pair_)) { |
| 50 return false; | 51 return false; |
| 51 } | 52 } |
| 52 | 53 |
| 53 process_launched_ = LaunchProcess(command, pt_pair_[PT_SLAVE_FD], &pid_); | 54 process_launched_ = LaunchProcess(command, pt_pair_[PT_SLAVE_FD], &pid_); |
| 54 | 55 |
| 55 if (process_launched_) { | 56 if (process_launched_) { |
| 56 // We won't need these anymore. These will be used by the launched process. | 57 // We won't need these anymore. These will be used by the launched process. |
| 57 CloseFd(&pt_pair_[PT_SLAVE_FD]); | 58 CloseFd(&pt_pair_[PT_SLAVE_FD]); |
| 58 *pid = pid_; | 59 *pid = pid_; |
| 59 LOG(WARNING) << "Process launched: " << pid_; | 60 LOG(WARNING) << "Process launched: " << pid_; |
| 60 } else { | 61 } else { |
| 61 CloseFdPair(pt_pair_); | 62 CloseFdPair(pt_pair_); |
| 62 } | 63 } |
| 63 return process_launched_; | 64 return process_launched_; |
| 64 } | 65 } |
| 65 | 66 |
| 66 bool ProcessProxy::StartWatchingOnThread(base::Thread* watch_thread, | 67 bool ProcessProxy::StartWatchingOnThread( |
| 67 const ProcessOutputCallback& callback) { | 68 base::Thread* watch_thread, |
| 69 const ProcessOutputCallback& callback) { |
| 68 DCHECK(process_launched_); | 70 DCHECK(process_launched_); |
| 69 if (watcher_started_) | 71 if (watcher_started_) |
| 70 return false; | 72 return false; |
| 71 if (pipe(shutdown_pipe_)) | 73 if (pipe(shutdown_pipe_)) |
| 72 return false; | 74 return false; |
| 73 | 75 |
| 74 // We give ProcessOutputWatcher a copy of master to make life easier during | 76 // We give ProcessOutputWatcher a copy of master to make life easier during |
| 75 // tear down. | 77 // tear down. |
| 76 // TODO(tbarzic): improve fd managment. | 78 // TODO(tbarzic): improve fd managment. |
| 77 int master_copy = HANDLE_EINTR(dup(pt_pair_[PT_MASTER_FD])); | 79 int master_copy = HANDLE_EINTR(dup(pt_pair_[PT_MASTER_FD])); |
| 78 if (master_copy == -1) | 80 if (master_copy == -1) |
| 79 return false; | 81 return false; |
| 80 | 82 |
| 81 callback_set_ = true; | 83 callback_set_ = true; |
| 82 callback_ = callback; | 84 callback_ = callback; |
| 85 callback_runner_ = base::MessageLoopProxy::current(); |
| 83 | 86 |
| 84 // This object will delete itself once watching is stopped. | 87 // This object will delete itself once watching is stopped. |
| 85 // It also takes ownership of the passed fds. | 88 // It also takes ownership of the passed fds. |
| 86 ProcessOutputWatcher* output_watcher = | 89 ProcessOutputWatcher* output_watcher = |
| 87 new ProcessOutputWatcher(master_copy, | 90 new ProcessOutputWatcher(master_copy, |
| 88 shutdown_pipe_[PIPE_END_READ], | 91 shutdown_pipe_[PIPE_END_READ], |
| 89 base::Bind(&ProcessProxy::OnProcessOutput, | 92 base::Bind(&ProcessProxy::OnProcessOutput, |
| 90 this)); | 93 this)); |
| 91 | 94 |
| 92 // Output watcher took ownership of the read end of shutdown pipe. | 95 // Output watcher took ownership of the read end of shutdown pipe. |
| 93 shutdown_pipe_[PIPE_END_READ] = -1; | 96 shutdown_pipe_[PIPE_END_READ] = -1; |
| 94 | 97 |
| 95 // |watch| thread is blocked by |output_watcher| from now on. | 98 // |watch| thread is blocked by |output_watcher| from now on. |
| 96 watch_thread->message_loop()->PostTask(FROM_HERE, | 99 watch_thread->message_loop()->PostTask(FROM_HERE, |
| 97 base::Bind(&ProcessOutputWatcher::Start, | 100 base::Bind(&ProcessOutputWatcher::Start, |
| 98 base::Unretained(output_watcher))); | 101 base::Unretained(output_watcher))); |
| 99 watcher_started_ = true; | 102 watcher_started_ = true; |
| 100 return true; | 103 return true; |
| 101 } | 104 } |
| 102 | 105 |
| 103 void ProcessProxy::OnProcessOutput(ProcessOutputType type, | 106 void ProcessProxy::OnProcessOutput(ProcessOutputType type, |
| 104 const std::string& output) { | 107 const std::string& output) { |
| 105 // We have to check if callback is set on FILE thread.. | 108 if (!callback_runner_) |
| 106 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)) { | |
| 107 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, | |
| 108 base::Bind(&ProcessProxy::OnProcessOutput, this, type, output)); | |
| 109 return; | 109 return; |
| 110 } | |
| 111 | 110 |
| 111 callback_runner_->PostTask( |
| 112 FROM_HERE, |
| 113 base::Bind(&ProcessProxy::CallOnProcessOutputCallback, |
| 114 this, type, output)); |
| 115 } |
| 116 |
| 117 void ProcessProxy::CallOnProcessOutputCallback(ProcessOutputType type, |
| 118 const std::string& output) { |
| 112 // We may receive some output even after Close was called (crosh process does | 119 // We may receive some output even after Close was called (crosh process does |
| 113 // not have to quit instantly, or there may be some trailing data left in | 120 // not have to quit instantly, or there may be some trailing data left in |
| 114 // output stream fds). In that case owner of the callback may be gone so we | 121 // output stream fds). In that case owner of the callback may be gone so we |
| 115 // don't want to send it anything. |callback_set_| is reset when this gets | 122 // don't want to send it anything. |callback_set_| is reset when this gets |
| 116 // closed. | 123 // closed. |
| 117 if (callback_set_) | 124 if (callback_set_) |
| 118 callback_.Run(type, output); | 125 callback_.Run(type, output); |
| 119 } | 126 } |
| 120 | 127 |
| 121 bool ProcessProxy::StopWatching() { | 128 bool ProcessProxy::StopWatching() { |
| 122 if (!watcher_started_) | 129 if (!watcher_started_) |
| 123 return true; | 130 return true; |
| 124 // Signal Watcher that we are done. We use self-pipe trick to unblock watcher. | 131 // Signal Watcher that we are done. We use self-pipe trick to unblock watcher. |
| 125 // Anything may be written to the pipe. | 132 // Anything may be written to the pipe. |
| 126 const char message[] = "q"; | 133 const char message[] = "q"; |
| 127 return file_util::WriteFileDescriptor(shutdown_pipe_[PIPE_END_WRITE], | 134 return file_util::WriteFileDescriptor(shutdown_pipe_[PIPE_END_WRITE], |
| 128 message, sizeof(message)); | 135 message, sizeof(message)); |
| 129 } | 136 } |
| 130 | 137 |
| 131 void ProcessProxy::Close() { | 138 void ProcessProxy::Close() { |
| 132 if (!process_launched_) | 139 if (!process_launched_) |
| 133 return; | 140 return; |
| 134 | 141 |
| 135 process_launched_ = false; | 142 process_launched_ = false; |
| 136 callback_set_ = false; | 143 callback_set_ = false; |
| 144 callback_ = ProcessOutputCallback(); |
| 145 callback_runner_ = NULL; |
| 137 | 146 |
| 138 base::KillProcess(pid_, 0, true /* wait */); | 147 base::KillProcess(pid_, 0, true /* wait */); |
| 139 | 148 |
| 140 // TODO(tbarzic): What if this fails? | 149 // TODO(tbarzic): What if this fails? |
| 141 StopWatching(); | 150 StopWatching(); |
| 142 | 151 |
| 143 CloseAllFdPairs(); | 152 CloseAllFdPairs(); |
| 144 } | 153 } |
| 145 | 154 |
| 146 bool ProcessProxy::Write(const std::string& text) { | 155 bool ProcessProxy::Write(const std::string& text) { |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 | 254 |
| 246 void ProcessProxy::ClearAllFdPairs() { | 255 void ProcessProxy::ClearAllFdPairs() { |
| 247 ClearFdPair(pt_pair_); | 256 ClearFdPair(pt_pair_); |
| 248 ClearFdPair(shutdown_pipe_); | 257 ClearFdPair(shutdown_pipe_); |
| 249 } | 258 } |
| 250 | 259 |
| 251 void ProcessProxy::ClearFdPair(int* pipe) { | 260 void ProcessProxy::ClearFdPair(int* pipe) { |
| 252 pipe[PIPE_END_READ] = kInvalidFd; | 261 pipe[PIPE_END_READ] = kInvalidFd; |
| 253 pipe[PIPE_END_WRITE] = kInvalidFd; | 262 pipe[PIPE_END_WRITE] = kInvalidFd; |
| 254 } | 263 } |
| 264 |
| 265 } // namespace chromeos |
| OLD | NEW |