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 |