Chromium Code Reviews| 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 base::AutoLock lock(child_tracking_lock_); | |
| 224 should_teardown_after_last_child_exits_ = true; | |
| 225 if (list_of_running_zygote_children_.empty()) { | |
| 226 TearDown(); | |
|
piman
2014/01/28 22:38:32
Can we release the lock before calling TearDown?
T
jln (very slow on Chromium)
2014/01/28 23:22:11
On 2014/01/28 22:38:32, piman wrote:
[...]
| |
| 227 } | |
| 228 } | |
| 229 | |
| 230 // Note: this is also called from the destructor. | |
| 231 void ZygoteHostImpl::TearDown() { | |
| 232 base::AutoLock lock(control_lock_); | |
| 233 if (control_fd_ > -1) { | |
| 234 // Closing the IPC channel will act as a notification to exit | |
| 235 // to the Zygote. | |
| 236 if (IGNORE_EINTR(close(control_fd_))) { | |
| 237 PLOG(ERROR) << "Could not close Zygote control channel."; | |
| 238 NOTREACHED(); | |
| 239 } | |
| 240 control_fd_ = -1; | |
| 241 } | |
| 242 } | |
| 243 | |
| 244 void ZygoteHostImpl::ZygoteChildBorn(pid_t process) { | |
| 245 base::AutoLock lock(child_tracking_lock_); | |
| 246 bool new_element_inserted = | |
| 247 list_of_running_zygote_children_.insert(process).second; | |
| 248 DCHECK(new_element_inserted); | |
| 249 } | |
| 250 | |
| 251 void ZygoteHostImpl::ZygoteChildDied(pid_t process) { | |
| 252 base::AutoLock lock(child_tracking_lock_); | |
| 253 size_t num_erased = list_of_running_zygote_children_.erase(process); | |
| 254 DCHECK_EQ(1U, num_erased); | |
| 255 if (should_teardown_after_last_child_exits_ && | |
| 256 list_of_running_zygote_children_.empty()) { | |
| 257 TearDown(); | |
| 258 } | |
| 259 } | |
| 260 | |
| 220 bool ZygoteHostImpl::SendMessage(const Pickle& data, | 261 bool ZygoteHostImpl::SendMessage(const Pickle& data, |
| 221 const std::vector<int>* fds) { | 262 const std::vector<int>* fds) { |
| 263 DCHECK_NE(-1, control_fd_); | |
| 222 CHECK(data.size() <= kZygoteMaxMessageLength) | 264 CHECK(data.size() <= kZygoteMaxMessageLength) |
| 223 << "Trying to send too-large message to zygote (sending " << data.size() | 265 << "Trying to send too-large message to zygote (sending " << data.size() |
| 224 << " bytes, max is " << kZygoteMaxMessageLength << ")"; | 266 << " bytes, max is " << kZygoteMaxMessageLength << ")"; |
| 225 CHECK(!fds || fds->size() <= UnixDomainSocket::kMaxFileDescriptors) | 267 CHECK(!fds || fds->size() <= UnixDomainSocket::kMaxFileDescriptors) |
| 226 << "Trying to send message with too many file descriptors to zygote " | 268 << "Trying to send message with too many file descriptors to zygote " |
| 227 << "(sending " << fds->size() << ", max is " | 269 << "(sending " << fds->size() << ", max is " |
| 228 << UnixDomainSocket::kMaxFileDescriptors << ")"; | 270 << UnixDomainSocket::kMaxFileDescriptors << ")"; |
| 229 | 271 |
| 230 return UnixDomainSocket::SendMsg(control_fd_, | 272 return UnixDomainSocket::SendMsg(control_fd_, |
| 231 data.data(), data.size(), | 273 data.data(), data.size(), |
| 232 fds ? *fds : std::vector<int>()); | 274 fds ? *fds : std::vector<int>()); |
| 233 } | 275 } |
| 234 | 276 |
| 235 ssize_t ZygoteHostImpl::ReadReply(void* buf, size_t buf_len) { | 277 ssize_t ZygoteHostImpl::ReadReply(void* buf, size_t buf_len) { |
| 278 DCHECK_NE(-1, control_fd_); | |
| 236 // At startup we send a kZygoteCommandGetSandboxStatus request to the zygote, | 279 // 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 | 280 // 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. | 281 // zygote, we get the reply to that request. |
| 239 if (!have_read_sandbox_status_word_) { | 282 if (!have_read_sandbox_status_word_) { |
| 240 if (HANDLE_EINTR(read(control_fd_, &sandbox_status_, | 283 if (HANDLE_EINTR(read(control_fd_, &sandbox_status_, |
| 241 sizeof(sandbox_status_))) != | 284 sizeof(sandbox_status_))) != |
| 242 sizeof(sandbox_status_)) { | 285 sizeof(sandbox_status_)) { |
| 243 return -1; | 286 return -1; |
| 244 } | 287 } |
| 245 have_read_sandbox_status_word_ = true; | 288 have_read_sandbox_status_word_ = true; |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 329 #if !defined(OS_OPENBSD) | 372 #if !defined(OS_OPENBSD) |
| 330 // This is just a starting score for a renderer or extension (the | 373 // 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 | 374 // 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 | 375 // get adjusted as time goes on. (This is the same value as |
| 333 // chrome::kLowestRendererOomScore in chrome/chrome_constants.h, but | 376 // chrome::kLowestRendererOomScore in chrome/chrome_constants.h, but |
| 334 // that's not something we can include here.) | 377 // that's not something we can include here.) |
| 335 const int kLowestRendererOomScore = 300; | 378 const int kLowestRendererOomScore = 300; |
| 336 AdjustRendererOOMScore(pid, kLowestRendererOomScore); | 379 AdjustRendererOOMScore(pid, kLowestRendererOomScore); |
| 337 #endif | 380 #endif |
| 338 | 381 |
| 382 ZygoteChildBorn(pid); | |
| 339 return pid; | 383 return pid; |
| 340 } | 384 } |
| 341 | 385 |
| 342 #if !defined(OS_OPENBSD) | 386 #if !defined(OS_OPENBSD) |
| 343 void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid, | 387 void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid, |
| 344 int score) { | 388 int score) { |
| 345 // 1) You can't change the oom_score_adj of a non-dumpable process | 389 // 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 | 390 // (EPERM) unless you're root. Because of this, we can't set the |
| 347 // oom_adj from the browser process. | 391 // oom_adj from the browser process. |
| 348 // | 392 // |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 408 #endif | 452 #endif |
| 409 | 453 |
| 410 void ZygoteHostImpl::EnsureProcessTerminated(pid_t process) { | 454 void ZygoteHostImpl::EnsureProcessTerminated(pid_t process) { |
| 411 DCHECK(init_); | 455 DCHECK(init_); |
| 412 Pickle pickle; | 456 Pickle pickle; |
| 413 | 457 |
| 414 pickle.WriteInt(kZygoteCommandReap); | 458 pickle.WriteInt(kZygoteCommandReap); |
| 415 pickle.WriteInt(process); | 459 pickle.WriteInt(process); |
| 416 if (!SendMessage(pickle, NULL)) | 460 if (!SendMessage(pickle, NULL)) |
| 417 LOG(ERROR) << "Failed to send Reap message to zygote"; | 461 LOG(ERROR) << "Failed to send Reap message to zygote"; |
| 462 ZygoteChildDied(process); | |
| 418 } | 463 } |
| 419 | 464 |
| 420 base::TerminationStatus ZygoteHostImpl::GetTerminationStatus( | 465 base::TerminationStatus ZygoteHostImpl::GetTerminationStatus( |
| 421 base::ProcessHandle handle, | 466 base::ProcessHandle handle, |
| 422 bool known_dead, | 467 bool known_dead, |
| 423 int* exit_code) { | 468 int* exit_code) { |
| 424 DCHECK(init_); | 469 DCHECK(init_); |
| 425 Pickle pickle; | 470 Pickle pickle; |
| 426 pickle.WriteInt(kZygoteCommandGetTerminationStatus); | 471 pickle.WriteInt(kZygoteCommandGetTerminationStatus); |
| 427 pickle.WriteBool(known_dead); | 472 pickle.WriteBool(known_dead); |
| 428 pickle.WriteInt(handle); | 473 pickle.WriteInt(handle); |
| 429 | 474 |
| 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; | 475 static const unsigned kMaxMessageLength = 128; |
| 435 char buf[kMaxMessageLength]; | 476 char buf[kMaxMessageLength]; |
| 436 ssize_t len; | 477 ssize_t len; |
| 437 { | 478 { |
| 438 base::AutoLock lock(control_lock_); | 479 base::AutoLock lock(control_lock_); |
| 439 if (!SendMessage(pickle, NULL)) | 480 if (!SendMessage(pickle, NULL)) |
| 440 LOG(ERROR) << "Failed to send GetTerminationStatus message to zygote"; | 481 LOG(ERROR) << "Failed to send GetTerminationStatus message to zygote"; |
| 441 len = ReadReply(buf, sizeof(buf)); | 482 len = ReadReply(buf, sizeof(buf)); |
| 442 } | 483 } |
| 443 | 484 |
| 485 // Set this now to handle the error cases. | |
| 486 if (exit_code) | |
| 487 *exit_code = RESULT_CODE_NORMAL_EXIT; | |
| 488 int status = base::TERMINATION_STATUS_NORMAL_TERMINATION; | |
| 489 | |
| 444 if (len == -1) { | 490 if (len == -1) { |
| 445 LOG(WARNING) << "Error reading message from zygote: " << errno; | 491 LOG(WARNING) << "Error reading message from zygote: " << errno; |
| 446 return base::TERMINATION_STATUS_NORMAL_TERMINATION; | |
| 447 } else if (len == 0) { | 492 } else if (len == 0) { |
| 448 LOG(WARNING) << "Socket closed prematurely."; | 493 LOG(WARNING) << "Socket closed prematurely."; |
| 449 return base::TERMINATION_STATUS_NORMAL_TERMINATION; | 494 } else { |
| 495 Pickle read_pickle(buf, len); | |
| 496 int tmp_status, tmp_exit_code; | |
| 497 PickleIterator iter(read_pickle); | |
| 498 if (!read_pickle.ReadInt(&iter, &tmp_status) || | |
| 499 !read_pickle.ReadInt(&iter, &tmp_exit_code)) { | |
| 500 LOG(WARNING) | |
| 501 << "Error parsing GetTerminationStatus response from zygote."; | |
| 502 } else { | |
| 503 if (exit_code) | |
| 504 *exit_code = tmp_exit_code; | |
| 505 status = tmp_status; | |
| 506 } | |
| 450 } | 507 } |
| 451 | 508 |
| 452 Pickle read_pickle(buf, len); | 509 if (status != base::TERMINATION_STATUS_STILL_RUNNING) { |
| 453 int status, tmp_exit_code; | 510 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 } | 511 } |
| 460 | |
| 461 if (exit_code) | |
| 462 *exit_code = tmp_exit_code; | |
| 463 | |
| 464 return static_cast<base::TerminationStatus>(status); | 512 return static_cast<base::TerminationStatus>(status); |
| 465 } | 513 } |
| 466 | 514 |
| 467 pid_t ZygoteHostImpl::GetPid() const { | 515 pid_t ZygoteHostImpl::GetPid() const { |
| 468 return pid_; | 516 return pid_; |
| 469 } | 517 } |
| 470 | 518 |
| 471 pid_t ZygoteHostImpl::GetSandboxHelperPid() const { | 519 pid_t ZygoteHostImpl::GetSandboxHelperPid() const { |
| 472 return RenderSandboxHostLinux::GetInstance()->pid(); | 520 return RenderSandboxHostLinux::GetInstance()->pid(); |
| 473 } | 521 } |
| 474 | 522 |
| 475 int ZygoteHostImpl::GetSandboxStatus() const { | 523 int ZygoteHostImpl::GetSandboxStatus() const { |
| 476 if (have_read_sandbox_status_word_) | 524 if (have_read_sandbox_status_word_) |
| 477 return sandbox_status_; | 525 return sandbox_status_; |
| 478 return 0; | 526 return 0; |
| 479 } | 527 } |
| 480 | 528 |
| 481 } // namespace content | 529 } // namespace content |
| OLD | NEW |