| 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/browser/zygote_host/zygote_host_impl_linux.h" | 5 #include "content/browser/zygote_host/zygote_host_impl_linux.h" |
| 6 | 6 |
| 7 #include <sys/socket.h> | 7 #include <sys/socket.h> |
| 8 #include <sys/stat.h> | 8 #include <sys/stat.h> |
| 9 #include <sys/types.h> | 9 #include <sys/types.h> |
| 10 #include <unistd.h> | 10 #include <unistd.h> |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 45 | 45 |
| 46 namespace content { | 46 namespace content { |
| 47 | 47 |
| 48 // static | 48 // static |
| 49 ZygoteHost* ZygoteHost::GetInstance() { | 49 ZygoteHost* ZygoteHost::GetInstance() { |
| 50 return ZygoteHostImpl::GetInstance(); | 50 return ZygoteHostImpl::GetInstance(); |
| 51 } | 51 } |
| 52 | 52 |
| 53 ZygoteHostImpl::ZygoteHostImpl() | 53 ZygoteHostImpl::ZygoteHostImpl() |
| 54 : control_fd_(-1), | 54 : control_fd_(-1), |
| 55 control_lock_(), |
| 55 pid_(-1), | 56 pid_(-1), |
| 56 init_(false), | 57 init_(false), |
| 57 using_suid_sandbox_(false), | 58 using_suid_sandbox_(false), |
| 59 sandbox_binary_(), |
| 58 have_read_sandbox_status_word_(false), | 60 have_read_sandbox_status_word_(false), |
| 59 sandbox_status_(0) {} | 61 sandbox_status_(0), |
| 62 child_tracking_lock_(), |
| 63 list_of_running_zygote_children_(), |
| 64 should_teardown_after_last_child_exits_(false) {} |
| 60 | 65 |
| 61 ZygoteHostImpl::~ZygoteHostImpl() { | 66 ZygoteHostImpl::~ZygoteHostImpl() { TearDown(); } |
| 62 if (init_) | |
| 63 close(control_fd_); | |
| 64 } | |
| 65 | 67 |
| 66 // static | 68 // static |
| 67 ZygoteHostImpl* ZygoteHostImpl::GetInstance() { | 69 ZygoteHostImpl* ZygoteHostImpl::GetInstance() { |
| 68 return Singleton<ZygoteHostImpl>::get(); | 70 return Singleton<ZygoteHostImpl>::get(); |
| 69 } | 71 } |
| 70 | 72 |
| 71 void ZygoteHostImpl::Init(const std::string& sandbox_cmd) { | 73 void ZygoteHostImpl::Init(const std::string& sandbox_cmd) { |
| 72 DCHECK(!init_); | 74 DCHECK(!init_); |
| 73 init_ = true; | 75 init_ = true; |
| 74 | 76 |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 close(fds[1]); | 212 close(fds[1]); |
| 211 control_fd_ = fds[0]; | 213 control_fd_ = fds[0]; |
| 212 | 214 |
| 213 Pickle pickle; | 215 Pickle pickle; |
| 214 pickle.WriteInt(kZygoteCommandGetSandboxStatus); | 216 pickle.WriteInt(kZygoteCommandGetSandboxStatus); |
| 215 if (!SendMessage(pickle, NULL)) | 217 if (!SendMessage(pickle, NULL)) |
| 216 LOG(FATAL) << "Cannot communicate with zygote"; | 218 LOG(FATAL) << "Cannot communicate with zygote"; |
| 217 // We don't wait for the reply. We'll read it in ReadReply. | 219 // We don't wait for the reply. We'll read it in ReadReply. |
| 218 } | 220 } |
| 219 | 221 |
| 222 void ZygoteHostImpl::TearDownAfterLastChild() { |
| 223 bool do_teardown = false; |
| 224 { |
| 225 base::AutoLock lock(child_tracking_lock_); |
| 226 should_teardown_after_last_child_exits_ = true; |
| 227 do_teardown = list_of_running_zygote_children_.empty(); |
| 228 } |
| 229 if (do_teardown) { |
| 230 TearDown(); |
| 231 } |
| 232 } |
| 233 |
| 234 // Note: this is also called from the destructor. |
| 235 void ZygoteHostImpl::TearDown() { |
| 236 base::AutoLock lock(control_lock_); |
| 237 if (control_fd_ > -1) { |
| 238 // Closing the IPC channel will act as a notification to exit |
| 239 // to the Zygote. |
| 240 if (IGNORE_EINTR(close(control_fd_))) { |
| 241 PLOG(ERROR) << "Could not close Zygote control channel."; |
| 242 NOTREACHED(); |
| 243 } |
| 244 control_fd_ = -1; |
| 245 } |
| 246 } |
| 247 |
| 248 void ZygoteHostImpl::ZygoteChildBorn(pid_t process) { |
| 249 base::AutoLock lock(child_tracking_lock_); |
| 250 bool new_element_inserted = |
| 251 list_of_running_zygote_children_.insert(process).second; |
| 252 DCHECK(new_element_inserted); |
| 253 } |
| 254 |
| 255 void ZygoteHostImpl::ZygoteChildDied(pid_t process) { |
| 256 bool do_teardown = false; |
| 257 { |
| 258 base::AutoLock lock(child_tracking_lock_); |
| 259 size_t num_erased = list_of_running_zygote_children_.erase(process); |
| 260 DCHECK_EQ(1U, num_erased); |
| 261 do_teardown = should_teardown_after_last_child_exits_ && |
| 262 list_of_running_zygote_children_.empty(); |
| 263 } |
| 264 if (do_teardown) { |
| 265 TearDown(); |
| 266 } |
| 267 } |
| 268 |
| 220 bool ZygoteHostImpl::SendMessage(const Pickle& data, | 269 bool ZygoteHostImpl::SendMessage(const Pickle& data, |
| 221 const std::vector<int>* fds) { | 270 const std::vector<int>* fds) { |
| 271 DCHECK_NE(-1, control_fd_); |
| 222 CHECK(data.size() <= kZygoteMaxMessageLength) | 272 CHECK(data.size() <= kZygoteMaxMessageLength) |
| 223 << "Trying to send too-large message to zygote (sending " << data.size() | 273 << "Trying to send too-large message to zygote (sending " << data.size() |
| 224 << " bytes, max is " << kZygoteMaxMessageLength << ")"; | 274 << " bytes, max is " << kZygoteMaxMessageLength << ")"; |
| 225 CHECK(!fds || fds->size() <= UnixDomainSocket::kMaxFileDescriptors) | 275 CHECK(!fds || fds->size() <= UnixDomainSocket::kMaxFileDescriptors) |
| 226 << "Trying to send message with too many file descriptors to zygote " | 276 << "Trying to send message with too many file descriptors to zygote " |
| 227 << "(sending " << fds->size() << ", max is " | 277 << "(sending " << fds->size() << ", max is " |
| 228 << UnixDomainSocket::kMaxFileDescriptors << ")"; | 278 << UnixDomainSocket::kMaxFileDescriptors << ")"; |
| 229 | 279 |
| 230 return UnixDomainSocket::SendMsg(control_fd_, | 280 return UnixDomainSocket::SendMsg(control_fd_, |
| 231 data.data(), data.size(), | 281 data.data(), data.size(), |
| 232 fds ? *fds : std::vector<int>()); | 282 fds ? *fds : std::vector<int>()); |
| 233 } | 283 } |
| 234 | 284 |
| 235 ssize_t ZygoteHostImpl::ReadReply(void* buf, size_t buf_len) { | 285 ssize_t ZygoteHostImpl::ReadReply(void* buf, size_t buf_len) { |
| 286 DCHECK_NE(-1, control_fd_); |
| 236 // At startup we send a kZygoteCommandGetSandboxStatus request to the zygote, | 287 // At startup we send a kZygoteCommandGetSandboxStatus request to the zygote, |
| 237 // but don't wait for the reply. Thus, the first time that we read from the | 288 // but don't wait for the reply. Thus, the first time that we read from the |
| 238 // zygote, we get the reply to that request. | 289 // zygote, we get the reply to that request. |
| 239 if (!have_read_sandbox_status_word_) { | 290 if (!have_read_sandbox_status_word_) { |
| 240 if (HANDLE_EINTR(read(control_fd_, &sandbox_status_, | 291 if (HANDLE_EINTR(read(control_fd_, &sandbox_status_, |
| 241 sizeof(sandbox_status_))) != | 292 sizeof(sandbox_status_))) != |
| 242 sizeof(sandbox_status_)) { | 293 sizeof(sandbox_status_)) { |
| 243 return -1; | 294 return -1; |
| 244 } | 295 } |
| 245 have_read_sandbox_status_word_ = true; | 296 have_read_sandbox_status_word_ = true; |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 329 #if !defined(OS_OPENBSD) | 380 #if !defined(OS_OPENBSD) |
| 330 // This is just a starting score for a renderer or extension (the | 381 // This is just a starting score for a renderer or extension (the |
| 331 // only types of processes that will be started this way). It will | 382 // only types of processes that will be started this way). It will |
| 332 // get adjusted as time goes on. (This is the same value as | 383 // get adjusted as time goes on. (This is the same value as |
| 333 // chrome::kLowestRendererOomScore in chrome/chrome_constants.h, but | 384 // chrome::kLowestRendererOomScore in chrome/chrome_constants.h, but |
| 334 // that's not something we can include here.) | 385 // that's not something we can include here.) |
| 335 const int kLowestRendererOomScore = 300; | 386 const int kLowestRendererOomScore = 300; |
| 336 AdjustRendererOOMScore(pid, kLowestRendererOomScore); | 387 AdjustRendererOOMScore(pid, kLowestRendererOomScore); |
| 337 #endif | 388 #endif |
| 338 | 389 |
| 390 ZygoteChildBorn(pid); |
| 339 return pid; | 391 return pid; |
| 340 } | 392 } |
| 341 | 393 |
| 342 #if !defined(OS_OPENBSD) | 394 #if !defined(OS_OPENBSD) |
| 343 void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid, | 395 void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid, |
| 344 int score) { | 396 int score) { |
| 345 // 1) You can't change the oom_score_adj of a non-dumpable process | 397 // 1) You can't change the oom_score_adj of a non-dumpable process |
| 346 // (EPERM) unless you're root. Because of this, we can't set the | 398 // (EPERM) unless you're root. Because of this, we can't set the |
| 347 // oom_adj from the browser process. | 399 // oom_adj from the browser process. |
| 348 // | 400 // |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 #endif | 460 #endif |
| 409 | 461 |
| 410 void ZygoteHostImpl::EnsureProcessTerminated(pid_t process) { | 462 void ZygoteHostImpl::EnsureProcessTerminated(pid_t process) { |
| 411 DCHECK(init_); | 463 DCHECK(init_); |
| 412 Pickle pickle; | 464 Pickle pickle; |
| 413 | 465 |
| 414 pickle.WriteInt(kZygoteCommandReap); | 466 pickle.WriteInt(kZygoteCommandReap); |
| 415 pickle.WriteInt(process); | 467 pickle.WriteInt(process); |
| 416 if (!SendMessage(pickle, NULL)) | 468 if (!SendMessage(pickle, NULL)) |
| 417 LOG(ERROR) << "Failed to send Reap message to zygote"; | 469 LOG(ERROR) << "Failed to send Reap message to zygote"; |
| 470 ZygoteChildDied(process); |
| 418 } | 471 } |
| 419 | 472 |
| 420 base::TerminationStatus ZygoteHostImpl::GetTerminationStatus( | 473 base::TerminationStatus ZygoteHostImpl::GetTerminationStatus( |
| 421 base::ProcessHandle handle, | 474 base::ProcessHandle handle, |
| 422 bool known_dead, | 475 bool known_dead, |
| 423 int* exit_code) { | 476 int* exit_code) { |
| 424 DCHECK(init_); | 477 DCHECK(init_); |
| 425 Pickle pickle; | 478 Pickle pickle; |
| 426 pickle.WriteInt(kZygoteCommandGetTerminationStatus); | 479 pickle.WriteInt(kZygoteCommandGetTerminationStatus); |
| 427 pickle.WriteBool(known_dead); | 480 pickle.WriteBool(known_dead); |
| 428 pickle.WriteInt(handle); | 481 pickle.WriteInt(handle); |
| 429 | 482 |
| 430 // Set this now to handle the early termination cases. | |
| 431 if (exit_code) | |
| 432 *exit_code = RESULT_CODE_NORMAL_EXIT; | |
| 433 | |
| 434 static const unsigned kMaxMessageLength = 128; | 483 static const unsigned kMaxMessageLength = 128; |
| 435 char buf[kMaxMessageLength]; | 484 char buf[kMaxMessageLength]; |
| 436 ssize_t len; | 485 ssize_t len; |
| 437 { | 486 { |
| 438 base::AutoLock lock(control_lock_); | 487 base::AutoLock lock(control_lock_); |
| 439 if (!SendMessage(pickle, NULL)) | 488 if (!SendMessage(pickle, NULL)) |
| 440 LOG(ERROR) << "Failed to send GetTerminationStatus message to zygote"; | 489 LOG(ERROR) << "Failed to send GetTerminationStatus message to zygote"; |
| 441 len = ReadReply(buf, sizeof(buf)); | 490 len = ReadReply(buf, sizeof(buf)); |
| 442 } | 491 } |
| 443 | 492 |
| 493 // Set this now to handle the error cases. |
| 494 if (exit_code) |
| 495 *exit_code = RESULT_CODE_NORMAL_EXIT; |
| 496 int status = base::TERMINATION_STATUS_NORMAL_TERMINATION; |
| 497 |
| 444 if (len == -1) { | 498 if (len == -1) { |
| 445 LOG(WARNING) << "Error reading message from zygote: " << errno; | 499 LOG(WARNING) << "Error reading message from zygote: " << errno; |
| 446 return base::TERMINATION_STATUS_NORMAL_TERMINATION; | |
| 447 } else if (len == 0) { | 500 } else if (len == 0) { |
| 448 LOG(WARNING) << "Socket closed prematurely."; | 501 LOG(WARNING) << "Socket closed prematurely."; |
| 449 return base::TERMINATION_STATUS_NORMAL_TERMINATION; | 502 } else { |
| 503 Pickle read_pickle(buf, len); |
| 504 int tmp_status, tmp_exit_code; |
| 505 PickleIterator iter(read_pickle); |
| 506 if (!read_pickle.ReadInt(&iter, &tmp_status) || |
| 507 !read_pickle.ReadInt(&iter, &tmp_exit_code)) { |
| 508 LOG(WARNING) |
| 509 << "Error parsing GetTerminationStatus response from zygote."; |
| 510 } else { |
| 511 if (exit_code) |
| 512 *exit_code = tmp_exit_code; |
| 513 status = tmp_status; |
| 514 } |
| 450 } | 515 } |
| 451 | 516 |
| 452 Pickle read_pickle(buf, len); | 517 if (status != base::TERMINATION_STATUS_STILL_RUNNING) { |
| 453 int status, tmp_exit_code; | 518 ZygoteChildDied(handle); |
| 454 PickleIterator iter(read_pickle); | |
| 455 if (!read_pickle.ReadInt(&iter, &status) || | |
| 456 !read_pickle.ReadInt(&iter, &tmp_exit_code)) { | |
| 457 LOG(WARNING) << "Error parsing GetTerminationStatus response from zygote."; | |
| 458 return base::TERMINATION_STATUS_NORMAL_TERMINATION; | |
| 459 } | 519 } |
| 460 | |
| 461 if (exit_code) | |
| 462 *exit_code = tmp_exit_code; | |
| 463 | |
| 464 return static_cast<base::TerminationStatus>(status); | 520 return static_cast<base::TerminationStatus>(status); |
| 465 } | 521 } |
| 466 | 522 |
| 467 pid_t ZygoteHostImpl::GetPid() const { | 523 pid_t ZygoteHostImpl::GetPid() const { |
| 468 return pid_; | 524 return pid_; |
| 469 } | 525 } |
| 470 | 526 |
| 471 pid_t ZygoteHostImpl::GetSandboxHelperPid() const { | 527 pid_t ZygoteHostImpl::GetSandboxHelperPid() const { |
| 472 return RenderSandboxHostLinux::GetInstance()->pid(); | 528 return RenderSandboxHostLinux::GetInstance()->pid(); |
| 473 } | 529 } |
| 474 | 530 |
| 475 int ZygoteHostImpl::GetSandboxStatus() const { | 531 int ZygoteHostImpl::GetSandboxStatus() const { |
| 476 if (have_read_sandbox_status_word_) | 532 if (have_read_sandbox_status_word_) |
| 477 return sandbox_status_; | 533 return sandbox_status_; |
| 478 return 0; | 534 return 0; |
| 479 } | 535 } |
| 480 | 536 |
| 481 } // namespace content | 537 } // namespace content |
| OLD | NEW |