Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1950)

Side by Side Diff: chrome/browser/child_process_host.cc

Issue 2885017: Moved common parts of ChildProcessHost into chrome/common and created a Brows... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Code review changes Created 10 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/child_process_host.h ('k') | chrome/browser/gpu_process_host.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/child_process_host.h"
6
7 #include "base/command_line.h"
8 #include "base/compiler_specific.h"
9 #include "base/file_path.h"
10 #include "base/histogram.h"
11 #include "base/logging.h"
12 #include "base/path_service.h"
13 #include "base/process_util.h"
14 #include "base/singleton.h"
15 #include "base/stl_util-inl.h"
16 #include "base/string_util.h"
17 #include "base/waitable_event.h"
18 #include "chrome/browser/chrome_thread.h"
19 #include "chrome/common/chrome_constants.h"
20 #include "chrome/common/chrome_paths_internal.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/env_vars.h"
23 #include "chrome/common/notification_service.h"
24 #include "chrome/common/notification_type.h"
25 #include "chrome/common/plugin_messages.h"
26 #include "chrome/common/process_watcher.h"
27 #include "chrome/common/result_codes.h"
28 #include "chrome/installer/util/google_update_settings.h"
29
30 #if defined(OS_LINUX)
31 #include "base/linux_util.h"
32 #endif // OS_LINUX
33
34 #if defined(OS_POSIX)
35 // This is defined in chrome/browser/google_update_settings_posix.cc. It's the
36 // static string containing the user's unique GUID. We send this in the crash
37 // report.
38 namespace google_update {
39 extern std::string posix_guid;
40 } // namespace google_update
41 #endif // OS_POSIX
42
43
44 namespace {
45
46 typedef std::list<ChildProcessHost*> ChildProcessList;
47
48 // The NotificationTask is used to notify about plugin process connection/
49 // disconnection. It is needed because the notifications in the
50 // NotificationService must happen in the main thread.
51 class ChildNotificationTask : public Task {
52 public:
53 ChildNotificationTask(
54 NotificationType notification_type, ChildProcessInfo* info)
55 : notification_type_(notification_type), info_(*info) { }
56
57 virtual void Run() {
58 NotificationService::current()->
59 Notify(notification_type_, NotificationService::AllSources(),
60 Details<ChildProcessInfo>(&info_));
61 }
62
63 private:
64 NotificationType notification_type_;
65 ChildProcessInfo info_;
66 };
67
68 } // namespace
69
70
71 ChildProcessHost::ChildProcessHost(
72 ProcessType type, ResourceDispatcherHost* resource_dispatcher_host)
73 : Receiver(type, -1),
74 ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)),
75 resource_dispatcher_host_(resource_dispatcher_host),
76 opening_channel_(false) {
77 Singleton<ChildProcessList>::get()->push_back(this);
78 }
79
80
81 ChildProcessHost::~ChildProcessHost() {
82 Singleton<ChildProcessList>::get()->remove(this);
83
84 if (resource_dispatcher_host_)
85 resource_dispatcher_host_->CancelRequestsForProcess(id());
86 }
87
88 // static
89 FilePath ChildProcessHost::GetChildPath(bool allow_self) {
90 FilePath child_path;
91
92 child_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
93 switches::kBrowserSubprocessPath);
94 if (!child_path.empty())
95 return child_path;
96
97 #if defined(OS_MACOSX)
98 // On the Mac, the child executable lives at a predefined location within
99 // the app bundle's versioned directory.
100 return chrome::GetVersionedDirectory().
101 Append(chrome::kHelperProcessExecutablePath);
102 #endif
103
104 #if defined(OS_LINUX)
105 // Use /proc/self/exe rather than our known binary path so updates
106 // can't swap out the binary from underneath us.
107 if (allow_self)
108 return FilePath("/proc/self/exe");
109 #endif
110
111 // On most platforms, the child executable is the same as the current
112 // executable.
113 PathService::Get(base::FILE_EXE, &child_path);
114 return child_path;
115 }
116
117 // static
118 void ChildProcessHost::SetCrashReporterCommandLine(CommandLine* command_line) {
119 #if defined(USE_LINUX_BREAKPAD)
120 const bool unattended = (getenv(env_vars::kHeadless) != NULL);
121 if (unattended || GoogleUpdateSettings::GetCollectStatsConsent()) {
122 command_line->AppendSwitchWithValue(switches::kEnableCrashReporter,
123 ASCIIToWide(google_update::posix_guid +
124 "," +
125 base::GetLinuxDistro()));
126 }
127 #elif defined(OS_MACOSX)
128 if (GoogleUpdateSettings::GetCollectStatsConsent())
129 command_line->AppendSwitchWithValue(switches::kEnableCrashReporter,
130 ASCIIToWide(google_update::posix_guid));
131 #endif // OS_MACOSX
132 }
133
134 // static
135 void ChildProcessHost::TerminateAll() {
136 // Make a copy since the ChildProcessHost dtor mutates the original list.
137 ChildProcessList copy = *(Singleton<ChildProcessList>::get());
138 STLDeleteElements(&copy);
139 }
140
141 void ChildProcessHost::Launch(
142 #if defined(OS_WIN)
143 const FilePath& exposed_dir,
144 #elif defined(OS_POSIX)
145 bool use_zygote,
146 const base::environment_vector& environ,
147 #endif
148 CommandLine* cmd_line) {
149 child_process_.reset(new ChildProcessLauncher(
150 #if defined(OS_WIN)
151 exposed_dir,
152 #elif defined(OS_POSIX)
153 use_zygote,
154 environ,
155 channel_->GetClientFileDescriptor(),
156 #endif
157 cmd_line,
158 &listener_));
159 }
160
161 bool ChildProcessHost::CreateChannel() {
162 channel_id_ = GenerateRandomChannelID(this);
163 channel_.reset(new IPC::Channel(
164 channel_id_, IPC::Channel::MODE_SERVER, &listener_));
165 if (!channel_->Connect())
166 return false;
167
168 opening_channel_ = true;
169
170 return true;
171 }
172
173 void ChildProcessHost::InstanceCreated() {
174 Notify(NotificationType::CHILD_INSTANCE_CREATED);
175 }
176
177 bool ChildProcessHost::Send(IPC::Message* msg) {
178 if (!channel_.get()) {
179 delete msg;
180 return false;
181 }
182 return channel_->Send(msg);
183 }
184
185 void ChildProcessHost::Notify(NotificationType type) {
186 ChromeThread::PostTask(
187 ChromeThread::UI, FROM_HERE, new ChildNotificationTask(type, this));
188 }
189
190 bool ChildProcessHost::DidChildCrash() {
191 return child_process_->DidProcessCrash();
192 }
193
194 void ChildProcessHost::OnChildDied() {
195 if (handle() != base::kNullProcessHandle) {
196 bool did_crash = DidChildCrash();
197 if (did_crash) {
198 OnProcessCrashed();
199 // Report that this child process crashed.
200 Notify(NotificationType::CHILD_PROCESS_CRASHED);
201 UMA_HISTOGRAM_COUNTS("ChildProcess.Crashes", this->type());
202 }
203 // Notify in the main loop of the disconnection.
204 Notify(NotificationType::CHILD_PROCESS_HOST_DISCONNECTED);
205 }
206
207 delete this;
208 }
209
210 ChildProcessHost::ListenerHook::ListenerHook(ChildProcessHost* host)
211 : host_(host) {
212 }
213
214 void ChildProcessHost::ListenerHook::OnMessageReceived(
215 const IPC::Message& msg) {
216 #ifdef IPC_MESSAGE_LOG_ENABLED
217 IPC::Logging* logger = IPC::Logging::current();
218 if (msg.type() == IPC_LOGGING_ID) {
219 logger->OnReceivedLoggingMessage(msg);
220 return;
221 }
222
223 if (logger->Enabled())
224 logger->OnPreDispatchMessage(msg);
225 #endif
226
227 bool msg_is_ok = true;
228 bool handled = false;
229
230 if (host_->resource_dispatcher_host_) {
231 handled = host_->resource_dispatcher_host_->OnMessageReceived(
232 msg, host_, &msg_is_ok);
233 }
234
235 if (!handled) {
236 if (msg.type() == PluginProcessHostMsg_ShutdownRequest::ID) {
237 // Must remove the process from the list now, in case it gets used for a
238 // new instance before our watcher tells us that the process terminated.
239 Singleton<ChildProcessList>::get()->remove(host_);
240 if (host_->CanShutdown())
241 host_->Send(new PluginProcessMsg_Shutdown());
242 } else {
243 host_->OnMessageReceived(msg);
244 }
245 }
246
247 if (!msg_is_ok)
248 base::KillProcess(host_->handle(), ResultCodes::KILLED_BAD_MESSAGE, false);
249
250 #ifdef IPC_MESSAGE_LOG_ENABLED
251 if (logger->Enabled())
252 logger->OnPostDispatchMessage(msg, host_->channel_id_);
253 #endif
254 }
255
256 void ChildProcessHost::ListenerHook::OnChannelConnected(int32 peer_pid) {
257 host_->opening_channel_ = false;
258 host_->OnChannelConnected(peer_pid);
259
260 #if defined(IPC_MESSAGE_LOG_ENABLED)
261 bool enabled = IPC::Logging::current()->Enabled();
262 host_->Send(new PluginProcessMsg_SetIPCLoggingEnabled(enabled));
263 #endif
264
265 host_->Send(new PluginProcessMsg_AskBeforeShutdown());
266
267 // Notify in the main loop of the connection.
268 host_->Notify(NotificationType::CHILD_PROCESS_HOST_CONNECTED);
269 }
270
271 void ChildProcessHost::ListenerHook::OnChannelError() {
272 host_->opening_channel_ = false;
273 host_->OnChannelError();
274
275 // This will delete host_, which will also destroy this!
276 host_->OnChildDied();
277 }
278
279 void ChildProcessHost::ListenerHook::OnProcessLaunched() {
280 if (!host_->child_process_->GetHandle()) {
281 delete this;
282 return;
283 }
284
285 host_->set_handle(host_->child_process_->GetHandle());
286 host_->OnProcessLaunched();
287 }
288
289
290 ChildProcessHost::Iterator::Iterator()
291 : all_(true), type_(UNKNOWN_PROCESS) {
292 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)) <<
293 "ChildProcessInfo::Iterator must be used on the IO thread.";
294 iterator_ = Singleton<ChildProcessList>::get()->begin();
295 }
296
297 ChildProcessHost::Iterator::Iterator(ProcessType type)
298 : all_(false), type_(type) {
299 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)) <<
300 "ChildProcessInfo::Iterator must be used on the IO thread.";
301 iterator_ = Singleton<ChildProcessList>::get()->begin();
302 if (!Done() && (*iterator_)->type() != type_)
303 ++(*this);
304 }
305
306 ChildProcessHost* ChildProcessHost::Iterator::operator++() {
307 do {
308 ++iterator_;
309 if (Done())
310 break;
311
312 if (!all_ && (*iterator_)->type() != type_)
313 continue;
314
315 return *iterator_;
316 } while (true);
317
318 return NULL;
319 }
320
321 bool ChildProcessHost::Iterator::Done() {
322 return iterator_ == Singleton<ChildProcessList>::get()->end();
323 }
324
325 void ChildProcessHost::ForceShutdown() {
326 Singleton<ChildProcessList>::get()->remove(this);
327 Send(new PluginProcessMsg_Shutdown());
328 }
OLDNEW
« no previous file with comments | « chrome/browser/child_process_host.h ('k') | chrome/browser/gpu_process_host.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698