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 "chrome/browser/nacl_host/nacl_process_host.h" | 5 #include "chrome/browser/nacl_host/nacl_process_host.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/memory/mru_cache.h" | 12 #include "base/memory/mru_cache.h" |
| 13 #include "base/memory/singleton.h" | 13 #include "base/memory/singleton.h" |
| 14 #include "base/message_loop.h" | |
| 14 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
| 15 #include "base/path_service.h" | 16 #include "base/path_service.h" |
| 17 #include "base/string_number_conversions.h" | |
| 18 #include "base/string_split.h" | |
| 16 #include "base/string_util.h" | 19 #include "base/string_util.h" |
| 17 #include "base/rand_util.h" | 20 #include "base/rand_util.h" |
| 18 #include "base/stringprintf.h" | 21 #include "base/stringprintf.h" |
| 19 #include "base/utf_string_conversions.h" | 22 #include "base/utf_string_conversions.h" |
| 20 #include "base/win/windows_version.h" | 23 #include "base/win/windows_version.h" |
| 21 #include "build/build_config.h" | 24 #include "build/build_config.h" |
| 22 #include "chrome/browser/extensions/extension_info_map.h" | 25 #include "chrome/browser/extensions/extension_info_map.h" |
| 23 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" | 26 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" |
| 24 #include "chrome/common/chrome_constants.h" | 27 #include "chrome/common/chrome_constants.h" |
| 25 #include "chrome/common/chrome_paths.h" | 28 #include "chrome/common/chrome_paths.h" |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 262 return (base::win::OSInfo::GetInstance()->wow64_status() == | 265 return (base::win::OSInfo::GetInstance()->wow64_status() == |
| 263 base::win::OSInfo::WOW64_ENABLED); | 266 base::win::OSInfo::WOW64_ENABLED); |
| 264 } | 267 } |
| 265 #endif | 268 #endif |
| 266 | 269 |
| 267 NaClProcessHost::NaClProcessHost(const std::wstring& url) | 270 NaClProcessHost::NaClProcessHost(const std::wstring& url) |
| 268 : | 271 : |
| 269 #if defined(OS_WIN) | 272 #if defined(OS_WIN) |
| 270 process_launched_by_broker_(false), | 273 process_launched_by_broker_(false), |
| 271 #endif | 274 #endif |
| 275 #if defined(OS_LINUX) | |
|
Mark Seaborn
2012/04/03 21:57:44
#elif for neatness.
halyavin
2012/04/04 09:23:15
Done.
| |
| 276 wait_for_nacl_gdb_(false), | |
| 277 #endif | |
| 272 reply_msg_(NULL), | 278 reply_msg_(NULL), |
| 273 internal_(new NaClInternal()), | 279 internal_(new NaClInternal()), |
| 274 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | 280 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), |
| 275 enable_exception_handling_(false) { | 281 enable_exception_handling_(false) { |
| 276 process_.reset(content::BrowserChildProcessHost::Create( | 282 process_.reset(content::BrowserChildProcessHost::Create( |
| 277 content::PROCESS_TYPE_NACL_LOADER, this)); | 283 content::PROCESS_TYPE_NACL_LOADER, this)); |
| 278 process_->SetName(WideToUTF16Hack(url)); | 284 process_->SetName(WideToUTF16Hack(url)); |
| 279 | 285 |
| 280 // We allow untrusted hardware exception handling to be enabled via | 286 // We allow untrusted hardware exception handling to be enabled via |
| 281 // an env var for consistency with the standalone build of NaCl. | 287 // an env var for consistency with the standalone build of NaCl. |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 401 internal_->sockets_for_sel_ldr.push_back(pair[1]); | 407 internal_->sockets_for_sel_ldr.push_back(pair[1]); |
| 402 SetCloseOnExec(pair[0]); | 408 SetCloseOnExec(pair[0]); |
| 403 SetCloseOnExec(pair[1]); | 409 SetCloseOnExec(pair[1]); |
| 404 } | 410 } |
| 405 | 411 |
| 406 // Launch the process | 412 // Launch the process |
| 407 if (!LaunchSelLdr()) { | 413 if (!LaunchSelLdr()) { |
| 408 delete this; | 414 delete this; |
| 409 } | 415 } |
| 410 } | 416 } |
| 411 | 417 #if defined(OS_WIN) |
| 412 scoped_ptr<CommandLine> NaClProcessHost::LaunchWithNaClGdb( | 418 scoped_ptr<CommandLine> NaClProcessHost::LaunchWithNaClGdb( |
| 413 const FilePath& nacl_gdb, | 419 const FilePath& nacl_gdb, |
| 414 CommandLine* line, | 420 CommandLine* line) { |
| 415 const FilePath& manifest_path) { | |
| 416 CommandLine* cmd_line = new CommandLine(nacl_gdb); | 421 CommandLine* cmd_line = new CommandLine(nacl_gdb); |
| 417 // We can't use PrependWrapper because our parameters contain spaces. | 422 // We can't use PrependWrapper because our parameters contain spaces. |
| 418 cmd_line->AppendArg("--eval-command"); | 423 cmd_line->AppendArg("-ex"); |
|
Mark Seaborn
2012/04/03 21:57:44
Please stick with --eval-command since it's more o
halyavin
2012/04/04 09:23:15
Done.
| |
| 419 const FilePath::StringType& irt_path = | 424 const FilePath::StringType& irt_path = |
| 420 NaClBrowser::GetInstance()->GetIrtFilePath().value(); | 425 NaClBrowser::GetInstance()->GetIrtFilePath().value(); |
| 421 cmd_line->AppendArgNative(FILE_PATH_LITERAL("nacl-irt ") + irt_path); | 426 cmd_line->AppendArgNative(FILE_PATH_LITERAL("nacl-irt ") + irt_path); |
| 427 FilePath manifest_path = GetManifestPath(); | |
| 422 if (!manifest_path.empty()) { | 428 if (!manifest_path.empty()) { |
| 423 cmd_line->AppendArg("--eval-command"); | 429 cmd_line->AppendArg("-ex"); |
|
Mark Seaborn
2012/04/03 21:57:44
ditto
| |
| 424 cmd_line->AppendArgNative(FILE_PATH_LITERAL("nacl-manifest ") + | 430 cmd_line->AppendArgNative(FILE_PATH_LITERAL("nacl-manifest ") + |
| 425 manifest_path.value()); | 431 manifest_path.value()); |
| 426 } | 432 } |
| 427 cmd_line->AppendArg("--args"); | 433 cmd_line->AppendArg("--args"); |
| 428 const CommandLine::StringVector& argv = line->argv(); | 434 const CommandLine::StringVector& argv = line->argv(); |
| 429 for (size_t i = 0; i < argv.size(); i++) { | 435 for (size_t i = 0; i < argv.size(); i++) { |
| 430 cmd_line->AppendArgNative(argv[i]); | 436 cmd_line->AppendArgNative(argv[i]); |
| 431 } | 437 } |
| 432 return scoped_ptr<CommandLine>(cmd_line); | 438 return scoped_ptr<CommandLine>(cmd_line); |
| 433 } | 439 } |
| 440 #elif defined(OS_LINUX) | |
| 441 namespace { | |
| 442 class NaClGdbWatchDelegate : public MessageLoopForIO::Watcher { | |
| 443 public: | |
| 444 NaClGdbWatchDelegate(int fds_read, int fds_write, | |
| 445 const base::Closure& reply) | |
| 446 : fds_read_(fds_read), | |
| 447 fds_write_(fds_write), | |
|
Mark Seaborn
2012/04/03 21:57:44
Why are you passing fds_write through? It's not u
halyavin
2012/04/04 09:23:15
It is used by nacl-gdb. It opens fds_write in our
| |
| 448 reply_(reply) {} | |
| 449 | |
| 450 ~NaClGdbWatchDelegate() { | |
| 451 close(fds_read_); | |
|
Mark Seaborn
2012/04/03 21:57:44
Please do LOG(ERROR) on error from close(), otherw
halyavin
2012/04/04 09:23:15
Done.
| |
| 452 close(fds_write_); | |
| 453 } | |
| 454 | |
| 455 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE; | |
| 456 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {} | |
| 457 | |
| 458 private: | |
| 459 int fds_read_; | |
|
Mark Seaborn
2012/04/03 21:57:44
Should be "fd" not "fds".
halyavin
2012/04/04 09:23:15
Done.
| |
| 460 int fds_write_; | |
| 461 base::Closure reply_; | |
| 462 }; | |
| 463 | |
| 464 void NaClGdbWatchDelegate::OnFileCanReadWithoutBlocking(int fd) { | |
| 465 char buf; | |
| 466 if (read(fds_read_, &buf, 1) != 1) | |
| 467 LOG(ERROR) << "Failed to sync with nacl-gdb"; | |
|
Mark Seaborn
2012/04/03 21:57:44
Suggestion: you might also want to sanity check th
halyavin
2012/04/04 09:23:15
I added sanity check but I don't think using non-z
| |
| 468 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, reply_); | |
| 469 } | |
| 470 } // namespace | |
| 471 | |
| 472 bool NaClProcessHost::LaunchNaClGdb(base::ProcessId pid) { | |
| 473 CommandLine::StringType nacl_gdb = | |
| 474 CommandLine::ForCurrentProcess()->GetSwitchValueNative( | |
| 475 switches::kNaClGdb); | |
| 476 CommandLine::StringVector argv; | |
| 477 base::SplitString(nacl_gdb, static_cast<CommandLine::CharType>(' '), &argv); | |
|
Mark Seaborn
2012/04/03 21:57:44
Can you put a comment in here to say that we don't
halyavin
2012/04/04 09:23:15
Done.
| |
| 478 CommandLine cmd_line(argv); | |
| 479 cmd_line.AppendArg("-ex"); | |
|
Mark Seaborn
2012/04/03 21:57:44
Please use --eval-command here and below.
| |
| 480 const FilePath::StringType& irt_path = | |
| 481 NaClBrowser::GetInstance()->GetIrtFilePath().value(); | |
|
Mark Seaborn
2012/04/03 21:57:44
Indent -2
halyavin
2012/04/04 09:23:15
Done.
| |
| 482 cmd_line.AppendArgNative(FILE_PATH_LITERAL("nacl-irt ") + irt_path); | |
| 483 FilePath manifest_path = GetManifestPath(); | |
| 484 if (!manifest_path.empty()) { | |
| 485 cmd_line.AppendArg("-ex"); | |
| 486 cmd_line.AppendArgNative(FILE_PATH_LITERAL("nacl-manifest ") + | |
| 487 manifest_path.value()); | |
| 488 } | |
| 489 cmd_line.AppendArg("-ex"); | |
| 490 cmd_line.AppendArg("attach " + base::IntToString(pid)); | |
| 491 int fds[2]; | |
| 492 if (pipe(fds) != 0) | |
| 493 return false; | |
| 494 cmd_line.AppendArg("-ex"); | |
| 495 cmd_line.AppendArg("dump binary value /proc/" + | |
| 496 base::IntToString(base::GetCurrentProcId()) + | |
| 497 "/fd/" + base::IntToString(fds[1]) + " (char)0"); | |
| 498 // wait on fds[0] | |
| 499 nacl_gdb_watcher_delegate_.reset( | |
| 500 new NaClGdbWatchDelegate( | |
| 501 fds[0], fds[1], | |
| 502 base::Bind(&NaClProcessHost::OnNaClGdbAttached, | |
| 503 weak_factory_.GetWeakPtr()))); | |
| 504 MessageLoopForIO::current()->WatchFileDescriptor( | |
| 505 fds[0], | |
| 506 true, | |
| 507 MessageLoopForIO::WATCH_READ, | |
| 508 &nacl_gdb_watcher_, | |
| 509 nacl_gdb_watcher_delegate_.get()); | |
| 510 return base::LaunchProcess(cmd_line, base::LaunchOptions(), NULL); | |
|
Mark Seaborn
2012/04/03 21:57:44
This seems to suggest that all FDs, including fds[
halyavin
2012/04/04 09:23:15
nacl-gdb opens file descriptor in our process. I e
Mark Seaborn
2012/04/04 15:46:12
I missed that. It's totally non-obvious. It defi
| |
| 511 } | |
| 512 | |
| 513 void NaClProcessHost::OnNaClGdbAttached() { | |
| 514 wait_for_nacl_gdb_ = false; | |
| 515 nacl_gdb_watcher_.StopWatchingFileDescriptor(); | |
| 516 nacl_gdb_watcher_delegate_.reset(); | |
| 517 OnProcessLaunched(); | |
| 518 } | |
| 519 #endif | |
| 520 | |
| 521 FilePath NaClProcessHost::GetManifestPath() { | |
| 522 GURL manifest_url = GURL(process_->GetData().name); | |
| 523 const Extension* extension = extension_info_map_->extensions() | |
| 524 .GetExtensionOrAppByURL(ExtensionURLInfo(manifest_url)); | |
| 525 if (extension != NULL && manifest_url.SchemeIs(chrome::kExtensionScheme)) { | |
| 526 std::string path = manifest_url.path(); | |
| 527 TrimString(path, "/", &path); // Remove first slash | |
| 528 return extension->path().AppendASCII(path); | |
| 529 } | |
| 530 return FilePath(); | |
| 531 } | |
| 434 | 532 |
| 435 bool NaClProcessHost::LaunchSelLdr() { | 533 bool NaClProcessHost::LaunchSelLdr() { |
| 436 std::string channel_id = process_->GetHost()->CreateChannel(); | 534 std::string channel_id = process_->GetHost()->CreateChannel(); |
| 437 if (channel_id.empty()) | 535 if (channel_id.empty()) |
| 438 return false; | 536 return false; |
| 439 | 537 |
| 440 CommandLine::StringType nacl_loader_prefix; | 538 CommandLine::StringType nacl_loader_prefix; |
| 441 #if defined(OS_POSIX) | 539 #if defined(OS_POSIX) |
| 442 nacl_loader_prefix = CommandLine::ForCurrentProcess()->GetSwitchValueNative( | 540 nacl_loader_prefix = CommandLine::ForCurrentProcess()->GetSwitchValueNative( |
| 443 switches::kNaClLoaderCmdPrefix); | 541 switches::kNaClLoaderCmdPrefix); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 482 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id); | 580 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id); |
| 483 if (logging::DialogsAreSuppressed()) | 581 if (logging::DialogsAreSuppressed()) |
| 484 cmd_line->AppendSwitch(switches::kNoErrorDialogs); | 582 cmd_line->AppendSwitch(switches::kNoErrorDialogs); |
| 485 | 583 |
| 486 if (!nacl_loader_prefix.empty()) | 584 if (!nacl_loader_prefix.empty()) |
| 487 cmd_line->PrependWrapper(nacl_loader_prefix); | 585 cmd_line->PrependWrapper(nacl_loader_prefix); |
| 488 | 586 |
| 489 FilePath nacl_gdb = CommandLine::ForCurrentProcess()->GetSwitchValuePath( | 587 FilePath nacl_gdb = CommandLine::ForCurrentProcess()->GetSwitchValuePath( |
| 490 switches::kNaClGdb); | 588 switches::kNaClGdb); |
| 491 if (!nacl_gdb.empty()) { | 589 if (!nacl_gdb.empty()) { |
| 492 GURL manifest_url = GURL(process_->GetData().name); | 590 #if defined(OS_WIN) |
| 493 FilePath manifest_path; | |
| 494 const Extension* extension = extension_info_map_->extensions(). | |
| 495 GetExtensionOrAppByURL(ExtensionURLInfo(manifest_url)); | |
| 496 if (extension != NULL && manifest_url.SchemeIs(chrome::kExtensionScheme)) { | |
| 497 std::string path = manifest_url.path(); | |
| 498 TrimString(path, "/", &path); // Remove first slash | |
| 499 manifest_path = extension->path().AppendASCII(path); | |
| 500 } | |
| 501 cmd_line->AppendSwitch(switches::kNoSandbox); | 591 cmd_line->AppendSwitch(switches::kNoSandbox); |
| 502 scoped_ptr<CommandLine> gdb_cmd_line( | 592 scoped_ptr<CommandLine> gdb_cmd_line( |
| 503 LaunchWithNaClGdb(nacl_gdb, cmd_line.get(), manifest_path)); | 593 LaunchWithNaClGdb(nacl_gdb, cmd_line.get())); |
| 504 // We can't use process_->Launch() because OnProcessLaunched will be called | 594 // We can't use process_->Launch() because OnProcessLaunched will be called |
| 505 // with process_->GetData().handle filled by handle of gdb process. This | 595 // with process_->GetData().handle filled by handle of gdb process. This |
| 506 // handle will be used to duplicate handles for NaCl process and as | 596 // handle will be used to duplicate handles for NaCl process and as |
| 507 // a result NaCl process will not be able to use them. | 597 // a result NaCl process will not be able to use them. |
| 508 // | 598 // |
| 509 // So we don't fill process_->GetData().handle and wait for | 599 // So we don't fill process_->GetData().handle and wait for |
| 510 // OnChannelConnected to get handle of NaCl process from its pid. Then we | 600 // OnChannelConnected to get handle of NaCl process from its pid. Then we |
| 511 // call OnProcessLaunched. | 601 // call OnProcessLaunched. |
| 512 return base::LaunchProcess(*gdb_cmd_line, base::LaunchOptions(), NULL); | 602 return base::LaunchProcess(*gdb_cmd_line, base::LaunchOptions(), NULL); |
| 603 #elif defined(OS_LINUX) | |
| 604 wait_for_nacl_gdb_ = true; | |
| 605 #endif | |
| 513 } | 606 } |
| 514 | 607 |
| 515 // On Windows we might need to start the broker process to launch a new loader | 608 // On Windows we might need to start the broker process to launch a new loader |
| 516 #if defined(OS_WIN) | 609 #if defined(OS_WIN) |
| 517 if (RunningOnWOW64()) { | 610 if (RunningOnWOW64()) { |
| 518 return NaClBrokerService::GetInstance()->LaunchLoader(this, channel_id); | 611 return NaClBrokerService::GetInstance()->LaunchLoader(this, channel_id); |
| 519 } else { | 612 } else { |
| 520 process_->Launch(FilePath(), cmd_line.release()); | 613 process_->Launch(FilePath(), cmd_line.release()); |
| 521 } | 614 } |
| 522 #elif defined(OS_POSIX) | 615 #elif defined(OS_POSIX) |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 617 NULL, | 710 NULL, |
| 618 &error_code); | 711 &error_code); |
| 619 if (error_code != base::PLATFORM_FILE_OK) { | 712 if (error_code != base::PLATFORM_FILE_OK) { |
| 620 LOG(ERROR) << "Failed to open NaCl IRT file \"" | 713 LOG(ERROR) << "Failed to open NaCl IRT file \"" |
| 621 << irt_filepath_.LossyDisplayName() | 714 << irt_filepath_.LossyDisplayName() |
| 622 << "\": " << error_code; | 715 << "\": " << error_code; |
| 623 } | 716 } |
| 624 } | 717 } |
| 625 | 718 |
| 626 void NaClProcessHost::OnProcessLaunched() { | 719 void NaClProcessHost::OnProcessLaunched() { |
| 720 #if defined(OS_LINUX) | |
| 721 if (wait_for_nacl_gdb_) { | |
| 722 if (LaunchNaClGdb(base::GetProcId(process_->GetData().handle))) { | |
| 723 // OnProcessLaunched will be called with wait_for_nacl_gdb_ = false once | |
| 724 // debugger is attached to the program. | |
| 725 return; | |
| 726 } | |
| 727 LOG(ERROR) << "Cannot launch debugger"; | |
|
Mark Seaborn
2012/04/03 21:57:44
"Failed to launch debugger" might be better
halyavin
2012/04/04 09:23:15
Done.
| |
| 728 // Continue execution without debugger. | |
| 729 } | |
| 730 #endif | |
| 627 NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); | 731 NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); |
| 628 | 732 |
| 629 if (nacl_browser->IrtAvailable()) { | 733 if (nacl_browser->IrtAvailable()) { |
| 630 // The IRT is already open. Away we go. | 734 // The IRT is already open. Away we go. |
| 631 SendStart(); | 735 SendStart(); |
| 632 } else { | 736 } else { |
| 633 // We're waiting for the IRT to be open. | 737 // We're waiting for the IRT to be open. |
| 634 if (!nacl_browser->MakeIrtAvailable( | 738 if (!nacl_browser->MakeIrtAvailable( |
| 635 base::Bind(&NaClProcessHost::IrtReady, | 739 base::Bind(&NaClProcessHost::IrtReady, |
| 636 weak_factory_.GetWeakPtr()))) | 740 weak_factory_.GetWeakPtr()))) |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 914 bool handled = true; | 1018 bool handled = true; |
| 915 IPC_BEGIN_MESSAGE_MAP(NaClProcessHost, msg) | 1019 IPC_BEGIN_MESSAGE_MAP(NaClProcessHost, msg) |
| 916 IPC_MESSAGE_HANDLER(NaClProcessMsg_QueryKnownToValidate, | 1020 IPC_MESSAGE_HANDLER(NaClProcessMsg_QueryKnownToValidate, |
| 917 OnQueryKnownToValidate) | 1021 OnQueryKnownToValidate) |
| 918 IPC_MESSAGE_HANDLER(NaClProcessMsg_SetKnownToValidate, | 1022 IPC_MESSAGE_HANDLER(NaClProcessMsg_SetKnownToValidate, |
| 919 OnSetKnownToValidate) | 1023 OnSetKnownToValidate) |
| 920 IPC_MESSAGE_UNHANDLED(handled = false) | 1024 IPC_MESSAGE_UNHANDLED(handled = false) |
| 921 IPC_END_MESSAGE_MAP() | 1025 IPC_END_MESSAGE_MAP() |
| 922 return handled; | 1026 return handled; |
| 923 } | 1027 } |
| OLD | NEW |