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

Side by Side Diff: chrome/browser/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/browser_child_process_host.h ('k') | chrome/browser/browser_process_impl.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 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 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/child_process_host.h" 5 #include "chrome/browser/browser_child_process_host.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/compiler_specific.h"
9 #include "base/file_path.h" 8 #include "base/file_path.h"
10 #include "base/histogram.h" 9 #include "base/histogram.h"
11 #include "base/logging.h" 10 #include "base/logging.h"
12 #include "base/path_service.h" 11 #include "base/path_service.h"
13 #include "base/process_util.h" 12 #include "base/process_util.h"
14 #include "base/singleton.h" 13 #include "base/singleton.h"
15 #include "base/stl_util-inl.h" 14 #include "base/stl_util-inl.h"
16 #include "base/string_util.h" 15 #include "base/string_util.h"
17 #include "base/waitable_event.h" 16 #include "base/waitable_event.h"
18 #include "chrome/browser/chrome_thread.h" 17 #include "chrome/browser/chrome_thread.h"
19 #include "chrome/common/chrome_constants.h" 18 #include "chrome/common/chrome_constants.h"
20 #include "chrome/common/chrome_paths_internal.h" 19 #include "chrome/common/chrome_paths_internal.h"
21 #include "chrome/common/chrome_switches.h" 20 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/env_vars.h" 21 #include "chrome/common/env_vars.h"
23 #include "chrome/common/notification_service.h" 22 #include "chrome/common/notification_service.h"
24 #include "chrome/common/notification_type.h"
25 #include "chrome/common/plugin_messages.h" 23 #include "chrome/common/plugin_messages.h"
26 #include "chrome/common/process_watcher.h" 24 #include "chrome/common/process_watcher.h"
27 #include "chrome/common/result_codes.h" 25 #include "chrome/common/result_codes.h"
28 #include "chrome/installer/util/google_update_settings.h" 26 #include "chrome/installer/util/google_update_settings.h"
29 27
30 #if defined(OS_LINUX) 28 #if defined(OS_LINUX)
31 #include "base/linux_util.h" 29 #include "base/linux_util.h"
32 #endif // OS_LINUX 30 #endif // OS_LINUX
33 31
34 #if defined(OS_POSIX) 32 #if defined(OS_POSIX)
35 // This is defined in chrome/browser/google_update_settings_posix.cc. It's the 33 // 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 34 // static string containing the user's unique GUID. We send this in the crash
37 // report. 35 // report.
38 namespace google_update { 36 namespace google_update {
39 extern std::string posix_guid; 37 extern std::string posix_guid;
40 } // namespace google_update 38 } // namespace google_update
41 #endif // OS_POSIX 39 #endif // OS_POSIX
42 40
43 41
44 namespace { 42 namespace {
45 43
46 typedef std::list<ChildProcessHost*> ChildProcessList; 44 typedef std::list<BrowserChildProcessHost*> ChildProcessList;
47 45
48 // The NotificationTask is used to notify about plugin process connection/ 46 // The NotificationTask is used to notify about plugin process connection/
49 // disconnection. It is needed because the notifications in the 47 // disconnection. It is needed because the notifications in the
50 // NotificationService must happen in the main thread. 48 // NotificationService must happen in the main thread.
51 class ChildNotificationTask : public Task { 49 class ChildNotificationTask : public Task {
52 public: 50 public:
53 ChildNotificationTask( 51 ChildNotificationTask(
54 NotificationType notification_type, ChildProcessInfo* info) 52 NotificationType notification_type, ChildProcessInfo* info)
55 : notification_type_(notification_type), info_(*info) { } 53 : notification_type_(notification_type), info_(*info) { }
56 54
57 virtual void Run() { 55 virtual void Run() {
58 NotificationService::current()-> 56 NotificationService::current()->
59 Notify(notification_type_, NotificationService::AllSources(), 57 Notify(notification_type_, NotificationService::AllSources(),
60 Details<ChildProcessInfo>(&info_)); 58 Details<ChildProcessInfo>(&info_));
61 } 59 }
62 60
63 private: 61 private:
64 NotificationType notification_type_; 62 NotificationType notification_type_;
65 ChildProcessInfo info_; 63 ChildProcessInfo info_;
66 }; 64 };
67 65
68 } // namespace 66 } // namespace
69 67
70 68
71 ChildProcessHost::ChildProcessHost( 69 BrowserChildProcessHost::BrowserChildProcessHost(
72 ProcessType type, ResourceDispatcherHost* resource_dispatcher_host) 70 ProcessType type, ResourceDispatcherHost* resource_dispatcher_host)
73 : Receiver(type, -1), 71 : Receiver(type, -1),
74 ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)), 72 ALLOW_THIS_IN_INITIALIZER_LIST(client_(this)),
75 resource_dispatcher_host_(resource_dispatcher_host), 73 resource_dispatcher_host_(resource_dispatcher_host) {
76 opening_channel_(false) {
77 Singleton<ChildProcessList>::get()->push_back(this); 74 Singleton<ChildProcessList>::get()->push_back(this);
78 } 75 }
79 76
80 77
81 ChildProcessHost::~ChildProcessHost() { 78 BrowserChildProcessHost::~BrowserChildProcessHost() {
82 Singleton<ChildProcessList>::get()->remove(this); 79 Singleton<ChildProcessList>::get()->remove(this);
83 80
84 if (resource_dispatcher_host_) 81 if (resource_dispatcher_host_)
85 resource_dispatcher_host_->CancelRequestsForProcess(id()); 82 resource_dispatcher_host_->CancelRequestsForProcess(id());
86 } 83 }
87 84
88 // static 85 // static
89 FilePath ChildProcessHost::GetChildPath(bool allow_self) { 86 void BrowserChildProcessHost::SetCrashReporterCommandLine(
90 FilePath child_path; 87 CommandLine* command_line) {
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) 88 #if defined(USE_LINUX_BREAKPAD)
120 const bool unattended = (getenv(env_vars::kHeadless) != NULL); 89 const bool unattended = (getenv(env_vars::kHeadless) != NULL);
121 if (unattended || GoogleUpdateSettings::GetCollectStatsConsent()) { 90 if (unattended || GoogleUpdateSettings::GetCollectStatsConsent()) {
122 command_line->AppendSwitchWithValue(switches::kEnableCrashReporter, 91 command_line->AppendSwitchWithValue(switches::kEnableCrashReporter,
123 ASCIIToWide(google_update::posix_guid + 92 ASCIIToWide(google_update::posix_guid +
124 "," + 93 "," +
125 base::GetLinuxDistro())); 94 base::GetLinuxDistro()));
126 } 95 }
127 #elif defined(OS_MACOSX) 96 #elif defined(OS_MACOSX)
128 if (GoogleUpdateSettings::GetCollectStatsConsent()) 97 if (GoogleUpdateSettings::GetCollectStatsConsent())
129 command_line->AppendSwitchWithValue(switches::kEnableCrashReporter, 98 command_line->AppendSwitchWithValue(switches::kEnableCrashReporter,
130 ASCIIToWide(google_update::posix_guid)); 99 ASCIIToWide(google_update::posix_guid));
131 #endif // OS_MACOSX 100 #endif // OS_MACOSX
132 } 101 }
133 102
134 // static 103 // static
135 void ChildProcessHost::TerminateAll() { 104 void BrowserChildProcessHost::TerminateAll() {
136 // Make a copy since the ChildProcessHost dtor mutates the original list. 105 // Make a copy since the ChildProcessHost dtor mutates the original list.
137 ChildProcessList copy = *(Singleton<ChildProcessList>::get()); 106 ChildProcessList copy = *(Singleton<ChildProcessList>::get());
138 STLDeleteElements(&copy); 107 STLDeleteElements(&copy);
139 } 108 }
140 109
141 void ChildProcessHost::Launch( 110 void BrowserChildProcessHost::Launch(
142 #if defined(OS_WIN) 111 #if defined(OS_WIN)
143 const FilePath& exposed_dir, 112 const FilePath& exposed_dir,
144 #elif defined(OS_POSIX) 113 #elif defined(OS_POSIX)
145 bool use_zygote, 114 bool use_zygote,
146 const base::environment_vector& environ, 115 const base::environment_vector& environ,
147 #endif 116 #endif
148 CommandLine* cmd_line) { 117 CommandLine* cmd_line) {
149 child_process_.reset(new ChildProcessLauncher( 118 child_process_.reset(new ChildProcessLauncher(
150 #if defined(OS_WIN) 119 #if defined(OS_WIN)
151 exposed_dir, 120 exposed_dir,
152 #elif defined(OS_POSIX) 121 #elif defined(OS_POSIX)
153 use_zygote, 122 use_zygote,
154 environ, 123 environ,
155 channel_->GetClientFileDescriptor(), 124 channel()->GetClientFileDescriptor(),
156 #endif 125 #endif
157 cmd_line, 126 cmd_line,
158 &listener_)); 127 &client_));
159 } 128 }
160 129
161 bool ChildProcessHost::CreateChannel() { 130 bool BrowserChildProcessHost::Send(IPC::Message* msg) {
162 channel_id_ = GenerateRandomChannelID(this); 131 return SendOnChannel(msg);
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 } 132 }
172 133
173 void ChildProcessHost::InstanceCreated() { 134 void BrowserChildProcessHost::ForceShutdown() {
174 Notify(NotificationType::CHILD_INSTANCE_CREATED); 135 Singleton<ChildProcessList>::get()->remove(this);
136 ChildProcessHost::ForceShutdown();
175 } 137 }
176 138
177 bool ChildProcessHost::Send(IPC::Message* msg) { 139 void BrowserChildProcessHost::Notify(NotificationType type) {
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( 140 ChromeThread::PostTask(
187 ChromeThread::UI, FROM_HERE, new ChildNotificationTask(type, this)); 141 ChromeThread::UI, FROM_HERE, new ChildNotificationTask(type, this));
188 } 142 }
189 143
190 bool ChildProcessHost::DidChildCrash() { 144 bool BrowserChildProcessHost::DidChildCrash() {
191 return child_process_->DidProcessCrash(); 145 return child_process_->DidProcessCrash();
192 } 146 }
193 147
194 void ChildProcessHost::OnChildDied() { 148 void BrowserChildProcessHost::OnChildDied() {
195 if (handle() != base::kNullProcessHandle) { 149 if (handle() != base::kNullProcessHandle) {
196 bool did_crash = DidChildCrash(); 150 bool did_crash = DidChildCrash();
197 if (did_crash) { 151 if (did_crash) {
198 OnProcessCrashed(); 152 OnProcessCrashed();
199 // Report that this child process crashed. 153 // Report that this child process crashed.
200 Notify(NotificationType::CHILD_PROCESS_CRASHED); 154 Notify(NotificationType::CHILD_PROCESS_CRASHED);
201 UMA_HISTOGRAM_COUNTS("ChildProcess.Crashes", this->type()); 155 UMA_HISTOGRAM_COUNTS("ChildProcess.Crashes", this->type());
202 } 156 }
203 // Notify in the main loop of the disconnection. 157 // Notify in the main loop of the disconnection.
204 Notify(NotificationType::CHILD_PROCESS_HOST_DISCONNECTED); 158 Notify(NotificationType::CHILD_PROCESS_HOST_DISCONNECTED);
205 } 159 }
206 160 ChildProcessHost::OnChildDied();
207 delete this;
208 } 161 }
209 162
210 ChildProcessHost::ListenerHook::ListenerHook(ChildProcessHost* host) 163 bool BrowserChildProcessHost::InterceptMessageFromChild(
164 const IPC::Message& msg) {
165 bool msg_is_ok = true;
166 bool handled = false;
167 if (resource_dispatcher_host_) {
168 handled = resource_dispatcher_host_->OnMessageReceived(
169 msg, this, &msg_is_ok);
170 }
171 if (!handled && (msg.type() == PluginProcessHostMsg_ShutdownRequest::ID)) {
172 // Must remove the process from the list now, in case it gets used for a
173 // new instance before our watcher tells us that the process terminated.
174 Singleton<ChildProcessList>::get()->remove(this);
175 }
176 if (!msg_is_ok)
177 base::KillProcess(handle(), ResultCodes::KILLED_BAD_MESSAGE, false);
178 return handled;
179 }
180
181 BrowserChildProcessHost::ClientHook::ClientHook(BrowserChildProcessHost* host)
211 : host_(host) { 182 : host_(host) {
212 } 183 }
213 184
214 void ChildProcessHost::ListenerHook::OnMessageReceived( 185 void BrowserChildProcessHost::ClientHook::OnProcessLaunched() {
215 const IPC::Message& msg) { 186 if (!host_->child_process_->GetHandle()) {
216 #ifdef IPC_MESSAGE_LOG_ENABLED 187 host_->OnChildDied();
217 IPC::Logging* logger = IPC::Logging::current();
218 if (msg.type() == IPC_LOGGING_ID) {
219 logger->OnReceivedLoggingMessage(msg);
220 return; 188 return;
221 } 189 }
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()); 190 host_->set_handle(host_->child_process_->GetHandle());
286 host_->OnProcessLaunched(); 191 host_->OnProcessLaunched();
287 } 192 }
288 193
289 194 BrowserChildProcessHost::Iterator::Iterator()
290 ChildProcessHost::Iterator::Iterator()
291 : all_(true), type_(UNKNOWN_PROCESS) { 195 : all_(true), type_(UNKNOWN_PROCESS) {
292 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)) << 196 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)) <<
293 "ChildProcessInfo::Iterator must be used on the IO thread."; 197 "ChildProcessInfo::Iterator must be used on the IO thread.";
294 iterator_ = Singleton<ChildProcessList>::get()->begin(); 198 iterator_ = Singleton<ChildProcessList>::get()->begin();
295 } 199 }
296 200
297 ChildProcessHost::Iterator::Iterator(ProcessType type) 201 BrowserChildProcessHost::Iterator::Iterator(ProcessType type)
298 : all_(false), type_(type) { 202 : all_(false), type_(type) {
299 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)) << 203 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)) <<
300 "ChildProcessInfo::Iterator must be used on the IO thread."; 204 "ChildProcessInfo::Iterator must be used on the IO thread.";
301 iterator_ = Singleton<ChildProcessList>::get()->begin(); 205 iterator_ = Singleton<ChildProcessList>::get()->begin();
302 if (!Done() && (*iterator_)->type() != type_) 206 if (!Done() && (*iterator_)->type() != type_)
303 ++(*this); 207 ++(*this);
304 } 208 }
305 209
306 ChildProcessHost* ChildProcessHost::Iterator::operator++() { 210 BrowserChildProcessHost* BrowserChildProcessHost::Iterator::operator++() {
307 do { 211 do {
308 ++iterator_; 212 ++iterator_;
309 if (Done()) 213 if (Done())
310 break; 214 break;
311 215
312 if (!all_ && (*iterator_)->type() != type_) 216 if (!all_ && (*iterator_)->type() != type_)
313 continue; 217 continue;
314 218
315 return *iterator_; 219 return *iterator_;
316 } while (true); 220 } while (true);
317 221
318 return NULL; 222 return NULL;
319 } 223 }
320 224
321 bool ChildProcessHost::Iterator::Done() { 225 bool BrowserChildProcessHost::Iterator::Done() {
322 return iterator_ == Singleton<ChildProcessList>::get()->end(); 226 return iterator_ == Singleton<ChildProcessList>::get()->end();
323 } 227 }
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/browser_child_process_host.h ('k') | chrome/browser/browser_process_impl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698