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 "content/zygote/zygote_linux.h" | 5 #include "content/zygote/zygote_linux.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <string.h> | 8 #include <string.h> |
9 #include <sys/socket.h> | 9 #include <sys/socket.h> |
10 #include <sys/types.h> | 10 #include <sys/types.h> |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 | 178 |
179 if (len == -1) { | 179 if (len == -1) { |
180 PLOG(ERROR) << "Error reading message from browser"; | 180 PLOG(ERROR) << "Error reading message from browser"; |
181 return false; | 181 return false; |
182 } | 182 } |
183 | 183 |
184 Pickle pickle(buf, len); | 184 Pickle pickle(buf, len); |
185 PickleIterator iter(pickle); | 185 PickleIterator iter(pickle); |
186 | 186 |
187 int kind; | 187 int kind; |
188 if (pickle.ReadInt(&iter, &kind)) { | 188 if (iter.ReadInt(&kind)) { |
189 switch (kind) { | 189 switch (kind) { |
190 case kZygoteCommandFork: | 190 case kZygoteCommandFork: |
191 // This function call can return multiple times, once per fork(). | 191 // This function call can return multiple times, once per fork(). |
192 return HandleForkRequest(fd, pickle, iter, fds.Pass()); | 192 return HandleForkRequest(fd, iter, fds.Pass()); |
193 | 193 |
194 case kZygoteCommandReap: | 194 case kZygoteCommandReap: |
195 if (!fds.empty()) | 195 if (!fds.empty()) |
196 break; | 196 break; |
197 HandleReapRequest(fd, pickle, iter); | 197 HandleReapRequest(fd, iter); |
198 return false; | 198 return false; |
199 case kZygoteCommandGetTerminationStatus: | 199 case kZygoteCommandGetTerminationStatus: |
200 if (!fds.empty()) | 200 if (!fds.empty()) |
201 break; | 201 break; |
202 HandleGetTerminationStatus(fd, pickle, iter); | 202 HandleGetTerminationStatus(fd, iter); |
203 return false; | 203 return false; |
204 case kZygoteCommandGetSandboxStatus: | 204 case kZygoteCommandGetSandboxStatus: |
205 HandleGetSandboxStatus(fd, pickle, iter); | 205 HandleGetSandboxStatus(fd, iter); |
206 return false; | 206 return false; |
207 case kZygoteCommandForkRealPID: | 207 case kZygoteCommandForkRealPID: |
208 // This shouldn't happen in practice, but some failure paths in | 208 // This shouldn't happen in practice, but some failure paths in |
209 // HandleForkRequest (e.g., if ReadArgsAndFork fails during depickling) | 209 // HandleForkRequest (e.g., if ReadArgsAndFork fails during depickling) |
210 // could leave this command pending on the socket. | 210 // could leave this command pending on the socket. |
211 LOG(ERROR) << "Unexpected real PID message from browser"; | 211 LOG(ERROR) << "Unexpected real PID message from browser"; |
212 NOTREACHED(); | 212 NOTREACHED(); |
213 return false; | 213 return false; |
214 default: | 214 default: |
215 NOTREACHED(); | 215 NOTREACHED(); |
216 break; | 216 break; |
217 } | 217 } |
218 } | 218 } |
219 | 219 |
220 LOG(WARNING) << "Error parsing message from browser"; | 220 LOG(WARNING) << "Error parsing message from browser"; |
221 return false; | 221 return false; |
222 } | 222 } |
223 | 223 |
224 // TODO(jln): remove callers to this broken API. See crbug.com/274855. | 224 // TODO(jln): remove callers to this broken API. See crbug.com/274855. |
225 void Zygote::HandleReapRequest(int fd, | 225 void Zygote::HandleReapRequest(int fd, |
226 const Pickle& pickle, | |
227 PickleIterator iter) { | 226 PickleIterator iter) { |
228 base::ProcessId child; | 227 base::ProcessId child; |
229 | 228 |
230 if (!pickle.ReadInt(&iter, &child)) { | 229 if (!iter.ReadInt(&child)) { |
231 LOG(WARNING) << "Error parsing reap request from browser"; | 230 LOG(WARNING) << "Error parsing reap request from browser"; |
232 return; | 231 return; |
233 } | 232 } |
234 | 233 |
235 ZygoteProcessInfo child_info; | 234 ZygoteProcessInfo child_info; |
236 if (!GetProcessInfo(child, &child_info)) { | 235 if (!GetProcessInfo(child, &child_info)) { |
237 LOG(ERROR) << "Child not found!"; | 236 LOG(ERROR) << "Child not found!"; |
238 NOTREACHED(); | 237 NOTREACHED(); |
239 return; | 238 return; |
240 } | 239 } |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 } | 299 } |
301 // Successfully got a status for |real_pid|. | 300 // Successfully got a status for |real_pid|. |
302 if (*status != base::TERMINATION_STATUS_STILL_RUNNING) { | 301 if (*status != base::TERMINATION_STATUS_STILL_RUNNING) { |
303 // Time to forget about this process. | 302 // Time to forget about this process. |
304 process_info_map_.erase(real_pid); | 303 process_info_map_.erase(real_pid); |
305 } | 304 } |
306 return true; | 305 return true; |
307 } | 306 } |
308 | 307 |
309 void Zygote::HandleGetTerminationStatus(int fd, | 308 void Zygote::HandleGetTerminationStatus(int fd, |
310 const Pickle& pickle, | |
311 PickleIterator iter) { | 309 PickleIterator iter) { |
312 bool known_dead; | 310 bool known_dead; |
313 base::ProcessHandle child_requested; | 311 base::ProcessHandle child_requested; |
314 | 312 |
315 if (!pickle.ReadBool(&iter, &known_dead) || | 313 if (!iter.ReadBool(&known_dead) || !iter.ReadInt(&child_requested)) { |
316 !pickle.ReadInt(&iter, &child_requested)) { | |
317 LOG(WARNING) << "Error parsing GetTerminationStatus request " | 314 LOG(WARNING) << "Error parsing GetTerminationStatus request " |
318 << "from browser"; | 315 << "from browser"; |
319 return; | 316 return; |
320 } | 317 } |
321 | 318 |
322 base::TerminationStatus status; | 319 base::TerminationStatus status; |
323 int exit_code; | 320 int exit_code; |
324 | 321 |
325 bool got_termination_status = | 322 bool got_termination_status = |
326 GetTerminationStatus(child_requested, known_dead, &status, &exit_code); | 323 GetTerminationStatus(child_requested, known_dead, &status, &exit_code); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
421 char buf[kZygoteMaxMessageLength]; | 418 char buf[kZygoteMaxMessageLength]; |
422 const ssize_t len = UnixDomainSocket::RecvMsg( | 419 const ssize_t len = UnixDomainSocket::RecvMsg( |
423 kZygoteSocketPairFd, buf, sizeof(buf), &recv_fds); | 420 kZygoteSocketPairFd, buf, sizeof(buf), &recv_fds); |
424 CHECK_GT(len, 0); | 421 CHECK_GT(len, 0); |
425 CHECK(recv_fds.empty()); | 422 CHECK(recv_fds.empty()); |
426 | 423 |
427 Pickle pickle(buf, len); | 424 Pickle pickle(buf, len); |
428 PickleIterator iter(pickle); | 425 PickleIterator iter(pickle); |
429 | 426 |
430 int kind; | 427 int kind; |
431 CHECK(pickle.ReadInt(&iter, &kind)); | 428 CHECK(iter.ReadInt(&kind)); |
432 CHECK(kind == kZygoteCommandForkRealPID); | 429 CHECK(kind == kZygoteCommandForkRealPID); |
433 CHECK(pickle.ReadInt(&iter, &real_pid)); | 430 CHECK(iter.ReadInt(&real_pid)); |
434 } | 431 } |
435 | 432 |
436 // Fork failed. | 433 // Fork failed. |
437 if (pid < 0) { | 434 if (pid < 0) { |
438 return -1; | 435 return -1; |
439 } | 436 } |
440 | 437 |
441 // If we successfully forked a child, but it crashed without sending | 438 // If we successfully forked a child, but it crashed without sending |
442 // a message to the browser, the browser won't have found its PID. | 439 // a message to the browser, the browser won't have found its PID. |
443 if (real_pid < 0) { | 440 if (real_pid < 0) { |
(...skipping 15 matching lines...) Expand all Loading... |
459 if (process_info_map_.find(real_pid) != process_info_map_.end()) { | 456 if (process_info_map_.find(real_pid) != process_info_map_.end()) { |
460 LOG(ERROR) << "Already tracking PID " << real_pid; | 457 LOG(ERROR) << "Already tracking PID " << real_pid; |
461 NOTREACHED(); | 458 NOTREACHED(); |
462 } | 459 } |
463 process_info_map_[real_pid].internal_pid = pid; | 460 process_info_map_[real_pid].internal_pid = pid; |
464 process_info_map_[real_pid].started_from_helper = helper; | 461 process_info_map_[real_pid].started_from_helper = helper; |
465 | 462 |
466 return real_pid; | 463 return real_pid; |
467 } | 464 } |
468 | 465 |
469 base::ProcessId Zygote::ReadArgsAndFork(const Pickle& pickle, | 466 base::ProcessId Zygote::ReadArgsAndFork(PickleIterator iter, |
470 PickleIterator iter, | |
471 ScopedVector<base::ScopedFD> fds, | 467 ScopedVector<base::ScopedFD> fds, |
472 std::string* uma_name, | 468 std::string* uma_name, |
473 int* uma_sample, | 469 int* uma_sample, |
474 int* uma_boundary_value) { | 470 int* uma_boundary_value) { |
475 std::vector<std::string> args; | 471 std::vector<std::string> args; |
476 int argc = 0; | 472 int argc = 0; |
477 int numfds = 0; | 473 int numfds = 0; |
478 base::GlobalDescriptors::Mapping mapping; | 474 base::GlobalDescriptors::Mapping mapping; |
479 std::string process_type; | 475 std::string process_type; |
480 std::string channel_id; | 476 std::string channel_id; |
481 const std::string channel_id_prefix = std::string("--") | 477 const std::string channel_id_prefix = std::string("--") |
482 + switches::kProcessChannelID + std::string("="); | 478 + switches::kProcessChannelID + std::string("="); |
483 | 479 |
484 if (!pickle.ReadString(&iter, &process_type)) | 480 if (!iter.ReadString(&process_type)) |
485 return -1; | 481 return -1; |
486 if (!pickle.ReadInt(&iter, &argc)) | 482 if (!iter.ReadInt(&argc)) |
487 return -1; | 483 return -1; |
488 | 484 |
489 for (int i = 0; i < argc; ++i) { | 485 for (int i = 0; i < argc; ++i) { |
490 std::string arg; | 486 std::string arg; |
491 if (!pickle.ReadString(&iter, &arg)) | 487 if (!iter.ReadString(&arg)) |
492 return -1; | 488 return -1; |
493 args.push_back(arg); | 489 args.push_back(arg); |
494 if (arg.compare(0, channel_id_prefix.length(), channel_id_prefix) == 0) | 490 if (arg.compare(0, channel_id_prefix.length(), channel_id_prefix) == 0) |
495 channel_id = arg.substr(channel_id_prefix.length()); | 491 channel_id = arg.substr(channel_id_prefix.length()); |
496 } | 492 } |
497 | 493 |
498 if (!pickle.ReadInt(&iter, &numfds)) | 494 if (!iter.ReadInt(&numfds)) |
499 return -1; | 495 return -1; |
500 if (numfds != static_cast<int>(fds.size())) | 496 if (numfds != static_cast<int>(fds.size())) |
501 return -1; | 497 return -1; |
502 | 498 |
503 // First FD is the PID oracle socket. | 499 // First FD is the PID oracle socket. |
504 if (fds.size() < 1) | 500 if (fds.size() < 1) |
505 return -1; | 501 return -1; |
506 base::ScopedFD pid_oracle(fds[0]->Pass()); | 502 base::ScopedFD pid_oracle(fds[0]->Pass()); |
507 | 503 |
508 // Remaining FDs are for the global descriptor mapping. | 504 // Remaining FDs are for the global descriptor mapping. |
509 for (int i = 1; i < numfds; ++i) { | 505 for (int i = 1; i < numfds; ++i) { |
510 base::GlobalDescriptors::Key key; | 506 base::GlobalDescriptors::Key key; |
511 if (!pickle.ReadUInt32(&iter, &key)) | 507 if (!iter.ReadUInt32(&key)) |
512 return -1; | 508 return -1; |
513 mapping.push_back(std::make_pair(key, fds[i]->get())); | 509 mapping.push_back(std::make_pair(key, fds[i]->get())); |
514 } | 510 } |
515 | 511 |
516 mapping.push_back(std::make_pair( | 512 mapping.push_back(std::make_pair( |
517 static_cast<uint32_t>(kSandboxIPCChannel), GetSandboxFD())); | 513 static_cast<uint32_t>(kSandboxIPCChannel), GetSandboxFD())); |
518 | 514 |
519 // Returns twice, once per process. | 515 // Returns twice, once per process. |
520 base::ProcessId child_pid = ForkWithRealPid(process_type, | 516 base::ProcessId child_pid = ForkWithRealPid(process_type, |
521 mapping, | 517 mapping, |
(...skipping 24 matching lines...) Expand all Loading... |
546 // (we don't have the original argv at this point). | 542 // (we don't have the original argv at this point). |
547 SetProcessTitleFromCommandLine(NULL); | 543 SetProcessTitleFromCommandLine(NULL); |
548 } else if (child_pid < 0) { | 544 } else if (child_pid < 0) { |
549 LOG(ERROR) << "Zygote could not fork: process_type " << process_type | 545 LOG(ERROR) << "Zygote could not fork: process_type " << process_type |
550 << " numfds " << numfds << " child_pid " << child_pid; | 546 << " numfds " << numfds << " child_pid " << child_pid; |
551 } | 547 } |
552 return child_pid; | 548 return child_pid; |
553 } | 549 } |
554 | 550 |
555 bool Zygote::HandleForkRequest(int fd, | 551 bool Zygote::HandleForkRequest(int fd, |
556 const Pickle& pickle, | |
557 PickleIterator iter, | 552 PickleIterator iter, |
558 ScopedVector<base::ScopedFD> fds) { | 553 ScopedVector<base::ScopedFD> fds) { |
559 std::string uma_name; | 554 std::string uma_name; |
560 int uma_sample; | 555 int uma_sample; |
561 int uma_boundary_value; | 556 int uma_boundary_value; |
562 base::ProcessId child_pid = ReadArgsAndFork( | 557 base::ProcessId child_pid = ReadArgsAndFork( |
563 pickle, iter, fds.Pass(), &uma_name, &uma_sample, &uma_boundary_value); | 558 iter, fds.Pass(), &uma_name, &uma_sample, &uma_boundary_value); |
564 if (child_pid == 0) | 559 if (child_pid == 0) |
565 return true; | 560 return true; |
566 // If there's no UMA report for this particular fork, then check if any | 561 // If there's no UMA report for this particular fork, then check if any |
567 // helpers have an initial UMA report for us to send instead. | 562 // helpers have an initial UMA report for us to send instead. |
568 while (uma_name.empty() && initial_uma_index_ < helpers_.size()) { | 563 while (uma_name.empty() && initial_uma_index_ < helpers_.size()) { |
569 helpers_[initial_uma_index_++]->InitialUMA( | 564 helpers_[initial_uma_index_++]->InitialUMA( |
570 &uma_name, &uma_sample, &uma_boundary_value); | 565 &uma_name, &uma_sample, &uma_boundary_value); |
571 } | 566 } |
572 // Must always send reply, as ZygoteHost blocks while waiting for it. | 567 // Must always send reply, as ZygoteHost blocks while waiting for it. |
573 Pickle reply_pickle; | 568 Pickle reply_pickle; |
574 reply_pickle.WriteInt(child_pid); | 569 reply_pickle.WriteInt(child_pid); |
575 reply_pickle.WriteString(uma_name); | 570 reply_pickle.WriteString(uma_name); |
576 if (!uma_name.empty()) { | 571 if (!uma_name.empty()) { |
577 reply_pickle.WriteInt(uma_sample); | 572 reply_pickle.WriteInt(uma_sample); |
578 reply_pickle.WriteInt(uma_boundary_value); | 573 reply_pickle.WriteInt(uma_boundary_value); |
579 } | 574 } |
580 if (HANDLE_EINTR(write(fd, reply_pickle.data(), reply_pickle.size())) != | 575 if (HANDLE_EINTR(write(fd, reply_pickle.data(), reply_pickle.size())) != |
581 static_cast<ssize_t> (reply_pickle.size())) | 576 static_cast<ssize_t> (reply_pickle.size())) |
582 PLOG(ERROR) << "write"; | 577 PLOG(ERROR) << "write"; |
583 return false; | 578 return false; |
584 } | 579 } |
585 | 580 |
586 bool Zygote::HandleGetSandboxStatus(int fd, | 581 bool Zygote::HandleGetSandboxStatus(int fd, |
587 const Pickle& pickle, | |
588 PickleIterator iter) { | 582 PickleIterator iter) { |
589 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_))) != | 583 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_))) != |
590 sizeof(sandbox_flags_)) { | 584 sizeof(sandbox_flags_)) { |
591 PLOG(ERROR) << "write"; | 585 PLOG(ERROR) << "write"; |
592 } | 586 } |
593 | 587 |
594 return false; | 588 return false; |
595 } | 589 } |
596 | 590 |
597 } // namespace content | 591 } // namespace content |
OLD | NEW |