diff options
author | gspencer@chromium.org <gspencer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-14 00:42:23 +0000 |
---|---|---|
committer | gspencer@chromium.org <gspencer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-14 00:42:23 +0000 |
commit | 443b80e00142dab08385eba06fcea79c96bbee6b (patch) | |
tree | 157caafda0fc699ff453d0d9666d19f2eeff8869 /chrome/browser | |
parent | 458a4362fecfe99bd7bc7e9d918a50fc653b4519 (diff) | |
download | chromium_src-443b80e00142dab08385eba06fcea79c96bbee6b.zip chromium_src-443b80e00142dab08385eba06fcea79c96bbee6b.tar.gz chromium_src-443b80e00142dab08385eba06fcea79c96bbee6b.tar.bz2 |
This adds some plumbing for propagating the status and error code of a renderer process that went away so that we can tell at the UI level what happened to the tab: did it crash, or was it killed by the OOM killer (or some other reason). This is in preparation for implementing a new UI for when a process is killed by the OOM on ChromeOS which handles it differently from a crash.
Most of the changes are modifications of the argument list to include a status and error code for the exited process, but in addition the following was done:
- Changed the name of DidProcessCrash to GetTerminationStatus.
- Added TerminationStatus enum in process_util.h, so it can be used as the status returned by GetTerminationStatus.
- Improved process_util_unittest to actually test for crashing and terminated processes on all platforms.
- Added a new notification for renderers that were killed.
- Added error code information to crash notification.
- Added status and error code information to renderer IPC message for RenderViewGone.
- Added a UMA histogram count for number of renderer kills.
BUG=http://crosbug.com/8505
TEST=ran new unit test. Test passes on try servers.
Review URL: http://codereview.chromium.org/5172009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@69082 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
54 files changed, 288 insertions, 150 deletions
diff --git a/chrome/browser/browser_child_process_host.cc b/chrome/browser/browser_child_process_host.cc index 6ad0c44..6b7d47b 100644 --- a/chrome/browser/browser_child_process_host.cc +++ b/chrome/browser/browser_child_process_host.cc @@ -141,18 +141,34 @@ void BrowserChildProcessHost::Notify(NotificationType type) { BrowserThread::UI, FROM_HERE, new ChildNotificationTask(type, this)); } -bool BrowserChildProcessHost::DidChildCrash() { - return child_process_->DidProcessCrash(); +base::TerminationStatus BrowserChildProcessHost::GetChildTerminationStatus( + int* exit_code) { + return child_process_->GetChildTerminationStatus(exit_code); } void BrowserChildProcessHost::OnChildDied() { if (handle() != base::kNullProcessHandle) { - bool did_crash = DidChildCrash(); - if (did_crash) { - OnProcessCrashed(); - // Report that this child process crashed. - Notify(NotificationType::CHILD_PROCESS_CRASHED); - UMA_HISTOGRAM_COUNTS("ChildProcess.Crashes", this->type()); + int exit_code; + base::TerminationStatus status = GetChildTerminationStatus(&exit_code); + switch (status) { + case base::TERMINATION_STATUS_PROCESS_CRASHED: { + OnProcessCrashed(exit_code); + + // Report that this child process crashed. + Notify(NotificationType::CHILD_PROCESS_CRASHED); + UMA_HISTOGRAM_COUNTS("ChildProcess.Crashes", this->type()); + break; + } + case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: { + OnProcessWasKilled(exit_code); + + // Report that this child process was killed. + Notify(NotificationType::CHILD_PROCESS_WAS_KILLED); + UMA_HISTOGRAM_COUNTS("ChildProcess.Kills", this->type()); + break; + } + default: + break; } // Notify in the main loop of the disconnection. Notify(NotificationType::CHILD_PROCESS_HOST_DISCONNECTED); diff --git a/chrome/browser/browser_child_process_host.h b/chrome/browser/browser_child_process_host.h index f70c035..b7bd39a 100644 --- a/chrome/browser/browser_child_process_host.h +++ b/chrome/browser/browser_child_process_host.h @@ -78,12 +78,25 @@ class BrowserChildProcessHost : public ResourceDispatcherHost::Receiver, base::ProcessHandle GetChildProcessHandle() const; // ChildProcessLauncher::Client implementation. - virtual void OnProcessLaunched() { } + virtual void OnProcessLaunched() {} // Derived classes can override this to know if the process crashed. - virtual void OnProcessCrashed() {} - - virtual bool DidChildCrash(); + // |exit_code| is the status returned when the process crashed (for + // posix, as returned from waitpid(), for Windows, as returned from + // GetExitCodeProcess()). + virtual void OnProcessCrashed(int exit_code) {} + + // Derived classes can override this to know if the process was + // killed. |exit_code| is the status returned when the process + // was killed (for posix, as returned from waitpid(), for Windows, + // as returned from GetExitCodeProcess()). + virtual void OnProcessWasKilled(int exit_code) {} + + // Returns the termination status of a child. |exit_code| is the + // status returned when the process exited (for posix, as returned + // from waitpid(), for Windows, as returned from + // GetExitCodeProcess()). |exit_code| may be NULL. + virtual base::TerminationStatus GetChildTerminationStatus(int* exit_code); // Overrides from ChildProcessHost virtual void OnChildDied(); @@ -111,4 +124,3 @@ class BrowserChildProcessHost : public ResourceDispatcherHost::Receiver, }; #endif // CHROME_BROWSER_BROWSER_CHILD_PROCESS_HOST_H_ - diff --git a/chrome/browser/child_process_launcher.cc b/chrome/browser/child_process_launcher.cc index a4a610a..8ba6941 100644 --- a/chrome/browser/child_process_launcher.cc +++ b/chrome/browser/child_process_launcher.cc @@ -311,28 +311,29 @@ base::ProcessHandle ChildProcessLauncher::GetHandle() { return context_->process_.handle(); } -bool ChildProcessLauncher::DidProcessCrash() { - bool did_crash, child_exited; +base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus( + int* exit_code) { + base::TerminationStatus status; base::ProcessHandle handle = context_->process_.handle(); #if defined(OS_LINUX) if (context_->zygote_) { - did_crash = ZygoteHost::GetInstance()->DidProcessCrash(handle, - &child_exited); + status = ZygoteHost::GetInstance()->GetTerminationStatus(handle, exit_code); } else #endif { - did_crash = base::DidProcessCrash(&child_exited, handle); + status = base::GetTerminationStatus(handle, exit_code); } - // POSIX: If the process crashed, then the kernel closed the socket for it - // and so the child has already died by the time we get here. Since - // DidProcessCrash called waitpid with WNOHANG, it'll reap the process. - // However, if DidProcessCrash didn't reap the child, we'll need to in + // POSIX: If the process crashed, then the kernel closed the socket + // for it and so the child has already died by the time we get + // here. Since GetTerminationStatus called waitpid with WNOHANG, + // it'll reap the process. However, if GetTerminationStatus didn't + // reap the child (because it was still running), we'll need to // Terminate via ProcessWatcher. So we can't close the handle here. - if (child_exited) + if (status != base::TERMINATION_STATUS_STILL_RUNNING) context_->process_.Close(); - return did_crash; + return status; } void ChildProcessLauncher::SetProcessBackgrounded(bool background) { diff --git a/chrome/browser/child_process_launcher.h b/chrome/browser/child_process_launcher.h index 95fb6ea..a3add53 100644 --- a/chrome/browser/child_process_launcher.h +++ b/chrome/browser/child_process_launcher.h @@ -50,8 +50,11 @@ class ChildProcessLauncher { // Getter for the process handle. Only call after the process has started. base::ProcessHandle GetHandle(); - // Call this when the process exits to know if a process crashed or not. - bool DidProcessCrash(); + // Call this when the child process exits to know what happened to + // it. |exit_code| is the exit code of the process if it exited + // (e.g. status from waitpid if on posix, from GetExitCodeProcess on + // Windows). |exit_code| may be NULL. + base::TerminationStatus GetChildTerminationStatus(int* exit_code); // Changes whether the process runs in the background or not. Only call // this after the process has started. diff --git a/chrome/browser/child_process_security_policy_browsertest.cc b/chrome/browser/child_process_security_policy_browsertest.cc index bedac81..4bcd3dc 100644 --- a/chrome/browser/child_process_security_policy_browsertest.cc +++ b/chrome/browser/child_process_security_policy_browsertest.cc @@ -11,6 +11,7 @@ #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/ui/browser.h" +#include "chrome/common/result_codes.h" #include "chrome/test/in_process_browser_test.h" #include "chrome/test/ui_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -43,7 +44,7 @@ IN_PROC_BROWSER_TEST_F(ChildProcessSecurityPolicyInProcessBrowserTest, NoLeak) { TabContents* tab = browser()->GetTabContentsAt(0); ASSERT_TRUE(tab != NULL); base::KillProcess(tab->GetRenderProcessHost()->GetHandle(), - base::PROCESS_END_KILLED_BY_USER, true); + ResultCodes::KILLED, true); tab->controller().Reload(true); EXPECT_EQ( diff --git a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc index 50144e1..1914ec7 100644 --- a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc +++ b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc @@ -14,6 +14,7 @@ #include "chrome/browser/tab_contents/infobar_delegate.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/ui/browser.h" +#include "chrome/common/result_codes.h" #include "chrome/test/ui_test_utils.h" class ExtensionCrashRecoveryTest : public ExtensionBrowserTest { @@ -61,8 +62,7 @@ class ExtensionCrashRecoveryTest : public ExtensionBrowserTest { RenderProcessHost* extension_rph = extension_host->render_view_host()->process(); - base::KillProcess(extension_rph->GetHandle(), - base::PROCESS_END_KILLED_BY_USER, false); + base::KillProcess(extension_rph->GetHandle(), ResultCodes::KILLED, false); ASSERT_TRUE(WaitForExtensionCrash(extension_id)); ASSERT_FALSE( GetExtensionProcessManager()->GetBackgroundHostForExtension(extension)); diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index cb6bd6b..1051399 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -288,7 +288,9 @@ void ExtensionHost::ClearInspectorSettings() { RenderViewHostDelegateHelper::ClearInspectorSettings(profile()); } -void ExtensionHost::RenderViewGone(RenderViewHost* render_view_host) { +void ExtensionHost::RenderViewGone(RenderViewHost* render_view_host, + base::TerminationStatus status, + int error_code) { // During browser shutdown, we may use sudden termination on an extension // process, so it is expected to lose our connection to the render view. // Do nothing. diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h index 935b76c..801bdab 100644 --- a/chrome/browser/extensions/extension_host.h +++ b/chrome/browser/extensions/extension_host.h @@ -112,7 +112,9 @@ class ExtensionHost : public RenderViewHostDelegate, virtual ViewType::Type GetRenderViewType() const; virtual FileSelect* GetFileSelectDelegate(); virtual int GetBrowserWindowID() const; - virtual void RenderViewGone(RenderViewHost* render_view_host); + virtual void RenderViewGone(RenderViewHost* render_view_host, + base::TerminationStatus status, + int error_code); virtual void DidNavigate(RenderViewHost* render_view_host, const ViewHostMsg_FrameNavigate_Params& params); virtual void DidStopLoading(); diff --git a/chrome/browser/extensions/sandboxed_extension_unpacker.cc b/chrome/browser/extensions/sandboxed_extension_unpacker.cc index faf236b..fc01884 100644 --- a/chrome/browser/extensions/sandboxed_extension_unpacker.cc +++ b/chrome/browser/extensions/sandboxed_extension_unpacker.cc @@ -181,7 +181,7 @@ void SandboxedExtensionUnpacker::OnUnpackExtensionFailed( ReportFailure(error); } -void SandboxedExtensionUnpacker::OnProcessCrashed() { +void SandboxedExtensionUnpacker::OnProcessCrashed(int exit_code) { // Don't report crashes if they happen after we got a response. if (got_response_) return; diff --git a/chrome/browser/extensions/sandboxed_extension_unpacker.h b/chrome/browser/extensions/sandboxed_extension_unpacker.h index acb4081..e47b26c 100644 --- a/chrome/browser/extensions/sandboxed_extension_unpacker.h +++ b/chrome/browser/extensions/sandboxed_extension_unpacker.h @@ -124,7 +124,7 @@ class SandboxedExtensionUnpacker : public UtilityProcessHost::Client { // SandboxedExtensionUnpacker virtual void OnUnpackExtensionSucceeded(const DictionaryValue& manifest); virtual void OnUnpackExtensionFailed(const std::string& error_message); - virtual void OnProcessCrashed(); + virtual void OnProcessCrashed(int exit_code); void ReportFailure(const std::string& message); void ReportSuccess(); diff --git a/chrome/browser/gpu_process_host.cc b/chrome/browser/gpu_process_host.cc index af4229a..7ddbdf1 100644 --- a/chrome/browser/gpu_process_host.cc +++ b/chrome/browser/gpu_process_host.cc @@ -495,12 +495,12 @@ void GpuProcessHost::OnChildDied() { BrowserChildProcessHost::OnChildDied(); } -void GpuProcessHost::OnProcessCrashed() { +void GpuProcessHost::OnProcessCrashed(int exit_code) { if (++g_gpu_crash_count >= kGpuMaxCrashCount) { // The gpu process is too unstable to use. Disable it for current session. RenderViewHostDelegateHelper::set_gpu_enabled(false); } - BrowserChildProcessHost::OnProcessCrashed(); + BrowserChildProcessHost::OnProcessCrashed(exit_code); } bool GpuProcessHost::CanLaunchGpuProcess() const { diff --git a/chrome/browser/gpu_process_host.h b/chrome/browser/gpu_process_host.h index a2b3c9e..c60c307 100644 --- a/chrome/browser/gpu_process_host.h +++ b/chrome/browser/gpu_process_host.h @@ -113,7 +113,7 @@ class GpuProcessHost : public BrowserChildProcessHost, public NonThreadSafe { virtual bool CanShutdown(); virtual void OnChildDied(); - virtual void OnProcessCrashed(); + virtual void OnProcessCrashed(int exit_code); bool CanLaunchGpuProcess() const; bool LaunchGpuProcess(); diff --git a/chrome/browser/importer/importer.cc b/chrome/browser/importer/importer.cc index 861db31..6cf596b 100644 --- a/chrome/browser/importer/importer.cc +++ b/chrome/browser/importer/importer.cc @@ -460,7 +460,7 @@ void ExternalProcessImporterClient::NotifyItemFinishedOnIOThread( profile_import_process_host_->ReportImportItemFinished(import_item); } -void ExternalProcessImporterClient::OnProcessCrashed() { +void ExternalProcessImporterClient::OnProcessCrashed(int exit_code) { if (cancelled_) return; diff --git a/chrome/browser/importer/importer.h b/chrome/browser/importer/importer.h index 515c58c..bc25850 100644 --- a/chrome/browser/importer/importer.h +++ b/chrome/browser/importer/importer.h @@ -344,7 +344,7 @@ class ExternalProcessImporterClient void NotifyItemFinishedOnIOThread(importer::ImportItem import_item); // Cancel import on process crash. - virtual void OnProcessCrashed(); + virtual void OnProcessCrashed(int exit_code); // Notifies the importerhost that import has finished, and calls Release(). void Cleanup(); diff --git a/chrome/browser/in_process_webkit/indexed_db_key_utility_client.cc b/chrome/browser/in_process_webkit/indexed_db_key_utility_client.cc index 920da34..e287c2c 100644 --- a/chrome/browser/in_process_webkit/indexed_db_key_utility_client.cc +++ b/chrome/browser/in_process_webkit/indexed_db_key_utility_client.cc @@ -148,7 +148,7 @@ IndexedDBKeyUtilityClient::Client::Client(IndexedDBKeyUtilityClient* parent) : parent_(parent) { } -void IndexedDBKeyUtilityClient::Client::OnProcessCrashed() { +void IndexedDBKeyUtilityClient::Client::OnProcessCrashed(int exit_code) { if (parent_->state_ == STATE_CREATING_KEYS) parent_->FinishCreatingKeys(); } diff --git a/chrome/browser/in_process_webkit/indexed_db_key_utility_client.h b/chrome/browser/in_process_webkit/indexed_db_key_utility_client.h index ee03ed9..6b8aec1 100644 --- a/chrome/browser/in_process_webkit/indexed_db_key_utility_client.h +++ b/chrome/browser/in_process_webkit/indexed_db_key_utility_client.h @@ -45,7 +45,7 @@ class IndexedDBKeyUtilityClient explicit Client(IndexedDBKeyUtilityClient* parent); // UtilityProcessHost::Client - virtual void OnProcessCrashed(); + virtual void OnProcessCrashed(int exit_code); virtual void OnIDBKeysFromValuesAndKeyPathSucceeded( int id, const std::vector<IndexedDBKey>& keys); virtual void OnIDBKeysFromValuesAndKeyPathFailed(int id); diff --git a/chrome/browser/metrics/metrics_service.cc b/chrome/browser/metrics/metrics_service.cc index 092548b..3041549 100644 --- a/chrome/browser/metrics/metrics_service.cc +++ b/chrome/browser/metrics/metrics_service.cc @@ -606,11 +606,13 @@ void MetricsService::Observe(NotificationType type, LogLoadStarted(); break; - case NotificationType::RENDERER_PROCESS_CLOSED: - { + case NotificationType::RENDERER_PROCESS_CLOSED: { RenderProcessHost::RendererClosedDetails* process_details = Details<RenderProcessHost::RendererClosedDetails>(details).ptr(); - if (process_details->did_crash) { + if (process_details->status == + base::TERMINATION_STATUS_PROCESS_CRASHED || + process_details->status == + base::TERMINATION_STATUS_ABNORMAL_TERMINATION) { if (process_details->was_extension_renderer) { LogExtensionRendererCrash(); } else { diff --git a/chrome/browser/nacl_host/nacl_process_host.cc b/chrome/browser/nacl_host/nacl_process_host.cc index ded7390..df661e4 100644 --- a/chrome/browser/nacl_host/nacl_process_host.cc +++ b/chrome/browser/nacl_host/nacl_process_host.cc @@ -163,10 +163,11 @@ void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) { OnProcessLaunched(); } -bool NaClProcessHost::DidChildCrash() { +base::TerminationStatus NaClProcessHost::GetChildTerminationStatus( + int* exit_code) { if (running_on_wow64_) - return base::DidProcessCrash(NULL, handle()); - return BrowserChildProcessHost::DidChildCrash(); + return base::GetTerminationStatus(handle(), exit_code); + return BrowserChildProcessHost::GetChildTerminationStatus(exit_code); } void NaClProcessHost::OnChildDied() { diff --git a/chrome/browser/nacl_host/nacl_process_host.h b/chrome/browser/nacl_host/nacl_process_host.h index 3b35bf7..5d6cc35 100644 --- a/chrome/browser/nacl_host/nacl_process_host.h +++ b/chrome/browser/nacl_host/nacl_process_host.h @@ -37,7 +37,7 @@ class NaClProcessHost : public BrowserChildProcessHost { void OnProcessLaunchedByBroker(base::ProcessHandle handle); protected: - virtual bool DidChildCrash(); + virtual base::TerminationStatus GetChildTerminationStatus(int* exit_code); virtual void OnChildDied(); private: diff --git a/chrome/browser/notifications/balloon_host.cc b/chrome/browser/notifications/balloon_host.cc index 8c778d0..13b092f 100644 --- a/chrome/browser/notifications/balloon_host.cc +++ b/chrome/browser/notifications/balloon_host.cc @@ -91,7 +91,8 @@ const string16& BalloonHost::GetSource() const { WebPreferences BalloonHost::GetWebkitPrefs() { WebPreferences web_prefs = - RenderViewHostDelegateHelper::GetWebkitPrefs(GetProfile(), enable_dom_ui_); + RenderViewHostDelegateHelper::GetWebkitPrefs(GetProfile(), + enable_dom_ui_); web_prefs.allow_scripts_to_close_windows = true; return web_prefs; } @@ -132,7 +133,9 @@ void BalloonHost::RenderViewReady(RenderViewHost* render_view_host) { Source<BalloonHost>(this), NotificationService::NoDetails()); } -void BalloonHost::RenderViewGone(RenderViewHost* render_view_host) { +void BalloonHost::RenderViewGone(RenderViewHost* render_view_host, + base::TerminationStatus status, + int error_code) { Close(render_view_host); } diff --git a/chrome/browser/notifications/balloon_host.h b/chrome/browser/notifications/balloon_host.h index c5a88e7..c3c058b 100644 --- a/chrome/browser/notifications/balloon_host.h +++ b/chrome/browser/notifications/balloon_host.h @@ -49,7 +49,9 @@ class BalloonHost : public RenderViewHostDelegate, virtual void Close(RenderViewHost* render_view_host); virtual void RenderViewCreated(RenderViewHost* render_view_host); virtual void RenderViewReady(RenderViewHost* render_view_host); - virtual void RenderViewGone(RenderViewHost* render_view_host); + virtual void RenderViewGone(RenderViewHost* render_view_host, + base::TerminationStatus status, + int error_code); virtual void UpdateTitle(RenderViewHost* render_view_host, int32 page_id, const std::wstring& title) {} virtual int GetBrowserWindowID() const; diff --git a/chrome/browser/profile_import_process_host.cc b/chrome/browser/profile_import_process_host.cc index 26e4ec1..45ec4f6 100644 --- a/chrome/browser/profile_import_process_host.cc +++ b/chrome/browser/profile_import_process_host.cc @@ -127,12 +127,13 @@ void ProfileImportProcessHost::OnMessageReceived(const IPC::Message& message) { message)); } -void ProfileImportProcessHost::OnProcessCrashed() { +void ProfileImportProcessHost::OnProcessCrashed(int exit_code) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); BrowserThread::PostTask( thread_id_, FROM_HERE, NewRunnableMethod(import_process_client_.get(), - &ImportProcessClient::OnProcessCrashed)); + &ImportProcessClient::OnProcessCrashed, + exit_code)); } bool ProfileImportProcessHost::CanShutdown() { diff --git a/chrome/browser/profile_import_process_host.h b/chrome/browser/profile_import_process_host.h index a6129a1..fabb947 100644 --- a/chrome/browser/profile_import_process_host.h +++ b/chrome/browser/profile_import_process_host.h @@ -40,7 +40,7 @@ class ProfileImportProcessHost : public BrowserChildProcessHost { // These methods are used by the ProfileImportProcessHost to pass messages // received from the external process back to the ImportProcessClient in // ImporterHost. - virtual void OnProcessCrashed() {} + virtual void OnProcessCrashed(int exit_status) {} virtual void OnImportStart() {} virtual void OnImportFinished(bool succeeded, std::string error_msg) {} virtual void OnImportItemStart(int item) {} @@ -126,7 +126,7 @@ class ProfileImportProcessHost : public BrowserChildProcessHost { virtual void OnMessageReceived(const IPC::Message& message); // Overridden from BrowserChildProcessHost: - virtual void OnProcessCrashed(); + virtual void OnProcessCrashed(int exit_code); virtual bool CanShutdown(); virtual URLRequestContext* GetRequestContext( uint32 request_id, diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc index 98b642b..e2c8780 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.cc +++ b/chrome/browser/renderer_host/browser_render_process_host.cc @@ -989,16 +989,26 @@ void BrowserRenderProcessHost::OnChannelError() { if (!channel_.get()) return; - // NULL in single process mode or if fast termination happened. - bool did_crash = - child_process_.get() ? child_process_->DidProcessCrash() : false; - - if (did_crash) { + // child_process_ can be NULL in single process mode or if fast + // termination happened. + int exit_code = 0; + base::TerminationStatus status = + child_process_.get() ? + child_process_->GetChildTerminationStatus(&exit_code) : + base::TERMINATION_STATUS_NORMAL_TERMINATION; + + if (status == base::TERMINATION_STATUS_PROCESS_CRASHED || + status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) { UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes", extension_process_ ? 2 : 1); } - RendererClosedDetails details(did_crash, extension_process_); + if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) { + UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills", + extension_process_ ? 2 : 1); + } + + RendererClosedDetails details(status, exit_code, extension_process_); NotificationService::current()->Notify( NotificationType::RENDERER_PROCESS_CLOSED, Source<RenderProcessHost>(this), @@ -1011,7 +1021,9 @@ void BrowserRenderProcessHost::OnChannelError() { IDMap<IPC::Channel::Listener>::iterator iter(&listeners_); while (!iter.IsAtEnd()) { iter.GetCurrentValue()->OnMessageReceived( - ViewHostMsg_RenderViewGone(iter.GetCurrentKey())); + ViewHostMsg_RenderViewGone(iter.GetCurrentKey(), + static_cast<int>(status), + exit_code)); iter.Advance(); } diff --git a/chrome/browser/renderer_host/render_process_host.h b/chrome/browser/renderer_host/render_process_host.h index a5fd378..c9a8abc 100644 --- a/chrome/browser/renderer_host/render_process_host.h +++ b/chrome/browser/renderer_host/render_process_host.h @@ -11,6 +11,7 @@ #include "app/surface/transport_dib.h" #include "base/id_map.h" #include "base/process.h" +#include "base/process_util.h" #include "base/scoped_ptr.h" #include "base/time.h" #include "chrome/common/visitedlink_common.h" @@ -48,11 +49,15 @@ class RenderProcessHost : public IPC::Channel::Sender, // Details for RENDERER_PROCESS_CLOSED notifications. struct RendererClosedDetails { - RendererClosedDetails(bool did_crash, bool was_extension_renderer) { - this->did_crash = did_crash; + RendererClosedDetails(base::TerminationStatus status, + int exit_code, + bool was_extension_renderer) { + this->status = status; + this->exit_code = exit_code; this->was_extension_renderer = was_extension_renderer; } - bool did_crash; + base::TerminationStatus status; + int exit_code; bool was_extension_renderer; }; diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 1b1cf0b..dc358b6 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -140,7 +140,8 @@ RenderViewHost::RenderViewHost(SiteInstance* instance, session_storage_namespace_(session_storage), is_extension_process_(false), autofill_query_id_(0), - save_accessibility_tree_for_testing_(false) { + save_accessibility_tree_for_testing_(false), + render_view_termination_status_(base::TERMINATION_STATUS_STILL_RUNNING) { if (!session_storage_namespace_) { session_storage_namespace_ = new SessionStorageNamespace(process()->profile()); @@ -998,15 +999,23 @@ void RenderViewHost::OnMsgRunModal(IPC::Message* reply_msg) { } void RenderViewHost::OnMsgRenderViewReady() { + render_view_termination_status_ = base::TERMINATION_STATUS_STILL_RUNNING; WasResized(); delegate_->RenderViewReady(this); } -void RenderViewHost::OnMsgRenderViewGone() { +void RenderViewHost::OnMsgRenderViewGone(int status, int exit_code) { + // Keep the termination status so we can get at it later when we + // need to know why it died. + render_view_termination_status_ = + static_cast<base::TerminationStatus>(status); + // Our base class RenderWidgetHost needs to reset some stuff. - RendererExited(); + RendererExited(render_view_termination_status_, exit_code); - delegate_->RenderViewGone(this); + delegate_->RenderViewGone(this, + static_cast<base::TerminationStatus>(status), + exit_code); } // Called when the renderer navigates. For every frame loaded, we'll get this diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h index b5399bf..81223ea 100644 --- a/chrome/browser/renderer_host/render_view_host.h +++ b/chrome/browser/renderer_host/render_view_host.h @@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/process_util.h" #include "base/scoped_ptr.h" #include "chrome/browser/renderer_host/render_widget_host.h" #include "chrome/browser/ui/find_bar/find_bar_controller.h" @@ -127,6 +128,10 @@ class RenderViewHost : public RenderWidgetHost { // because it is overridden by TestRenderViewHost. virtual bool IsRenderViewLive() const; + base::TerminationStatus render_view_termination_status() const { + return render_view_termination_status_; + } + // Send the renderer process the current preferences supplied by the // RenderViewHostDelegate. void SyncRendererPrefs(); @@ -550,7 +555,7 @@ class RenderViewHost : public RenderWidgetHost { void OnMsgShowFullscreenWidget(int route_id); void OnMsgRunModal(IPC::Message* reply_msg); void OnMsgRenderViewReady(); - void OnMsgRenderViewGone(); + void OnMsgRenderViewGone(int status, int error_code); void OnMsgNavigate(const IPC::Message& msg); void OnMsgUpdateState(int32 page_id, const std::string& state); @@ -819,6 +824,9 @@ class RenderViewHost : public RenderWidgetHost { // The most recently received accessibility tree - for unit testing only. webkit_glue::WebAccessibility accessibility_tree_; + // The termination status of the last render view that terminated. + base::TerminationStatus render_view_termination_status_; + DISALLOW_COPY_AND_ASSIGN(RenderViewHost); }; diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h index a566062..89f7d94 100644 --- a/chrome/browser/renderer_host/render_view_host_delegate.h +++ b/chrome/browser/renderer_host/render_view_host_delegate.h @@ -10,6 +10,7 @@ #include <vector> #include "base/basictypes.h" +#include "base/process_util.h" #include "base/ref_counted.h" #include "base/string16.h" #include "chrome/common/content_settings_types.h" @@ -711,7 +712,9 @@ class RenderViewHostDelegate { virtual void RenderViewReady(RenderViewHost* render_view_host) {} // The RenderView died somehow (crashed or was killed by the user). - virtual void RenderViewGone(RenderViewHost* render_view_host) {} + virtual void RenderViewGone(RenderViewHost* render_view_host, + base::TerminationStatus status, + int error_code) {} // The RenderView is going to be deleted. This is called when each // RenderView is going to be destroyed diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index 3fa5610..3c71440b 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -643,7 +643,8 @@ void RenderWidgetHost::ForwardTouchEvent( } #endif -void RenderWidgetHost::RendererExited() { +void RenderWidgetHost::RendererExited(base::TerminationStatus status, + int exit_code) { // Clearing this flag causes us to re-create the renderer when recovering // from a crashed renderer. renderer_initialized_ = false; @@ -671,7 +672,7 @@ void RenderWidgetHost::RendererExited() { is_accelerated_compositing_active_ = false; if (view_) { - view_->RenderViewGone(); + view_->RenderViewGone(status, exit_code); view_ = NULL; // The View should be deleted by RenderViewGone. } @@ -777,7 +778,7 @@ void RenderWidgetHost::OnMsgRenderViewReady() { WasResized(); } -void RenderWidgetHost::OnMsgRenderViewGone() { +void RenderWidgetHost::OnMsgRenderViewGone(int status, int exit_code) { // TODO(evanm): This synchronously ends up calling "delete this". // Is that really what we want in response to this message? I'm matching // previous behavior of the code here. diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index b0192a4..90204aa 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -12,6 +12,7 @@ #include "app/surface/transport_dib.h" #include "base/gtest_prod_util.h" +#include "base/process_util.h" #include "base/scoped_ptr.h" #include "base/string16.h" #include "base/timer.h" @@ -415,7 +416,7 @@ class RenderWidgetHost : public IPC::Channel::Listener, // Called when we receive a notification indicating that the renderer // process has gone. This will reset our state so that our state will be // consistent if a new renderer is created. - void RendererExited(); + void RendererExited(base::TerminationStatus status, int exit_code); // Retrieves an id the renderer can use to refer to its view. // This is used for various IPC messages, including plugins. @@ -473,7 +474,7 @@ class RenderWidgetHost : public IPC::Channel::Listener, // IPC message handlers void OnMsgRenderViewReady(); - void OnMsgRenderViewGone(); + void OnMsgRenderViewGone(int status, int error_code); void OnMsgClose(); void OnMsgRequestMove(const gfx::Rect& pos); void OnMsgPaintAtSizeAck(int tag, const gfx::Size& size); diff --git a/chrome/browser/renderer_host/render_widget_host_unittest.cc b/chrome/browser/renderer_host/render_widget_host_unittest.cc index 72495d3..758a5bd 100644 --- a/chrome/browser/renderer_host/render_widget_host_unittest.cc +++ b/chrome/browser/renderer_host/render_widget_host_unittest.cc @@ -397,7 +397,7 @@ TEST_F(RenderWidgetHostTest, ResizeThenCrash) { // resize ack logic is cleared. Must clear the view first so it doesn't get // deleted. host_->set_view(NULL); - host_->RendererExited(); + host_->RendererExited(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); EXPECT_FALSE(host_->resize_ack_pending_); EXPECT_EQ(gfx::Size(), host_->in_flight_size_); diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h index af6300e..14cf129 100644 --- a/chrome/browser/renderer_host/render_widget_host_view.h +++ b/chrome/browser/renderer_host/render_widget_host_view.h @@ -14,6 +14,7 @@ #include <vector> #include "app/surface/transport_dib.h" +#include "base/process_util.h" #include "gfx/native_widget_types.h" #include "gfx/rect.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -152,7 +153,8 @@ class RenderWidgetHostView { const std::vector<gfx::Rect>& copy_rects) = 0; // Notifies the View that the renderer has ceased to exist. - virtual void RenderViewGone() = 0; + virtual void RenderViewGone(base::TerminationStatus status, + int error_code) = 0; // Notifies the View that the renderer will be delete soon. virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh) = 0; diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc index 78b26e2..cf3418a 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc @@ -681,7 +681,8 @@ void RenderWidgetHostViewGtk::DidUpdateBackingStore( } } -void RenderWidgetHostViewGtk::RenderViewGone() { +void RenderWidgetHostViewGtk::RenderViewGone(base::TerminationStatus status, + int error_code) { Destroy(); plugin_container_manager_.set_host_widget(NULL); } diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.h b/chrome/browser/renderer_host/render_widget_host_view_gtk.h index cd89ddb..7af66f8 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_gtk.h +++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.h @@ -77,7 +77,8 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView, virtual void DidUpdateBackingStore( const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, const std::vector<gfx::Rect>& copy_rects); - virtual void RenderViewGone(); + virtual void RenderViewGone(base::TerminationStatus status, + int error_code); virtual void Destroy(); virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh) {} virtual void SetTooltipText(const std::wstring& tooltip_text); diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.h b/chrome/browser/renderer_host/render_widget_host_view_mac.h index f4dfd25..46efeee 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.h +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h @@ -200,7 +200,8 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView { virtual void DidUpdateBackingStore( const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, const std::vector<gfx::Rect>& copy_rects); - virtual void RenderViewGone(); + virtual void RenderViewGone(base::TerminationStatus status, + int error_code); virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh) {}; virtual void Destroy(); virtual void SetTooltipText(const std::wstring& tooltip_text); diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm index f88025e..842bf9a 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm @@ -794,7 +794,8 @@ void RenderWidgetHostViewMac::DidUpdateBackingStore( HandleDelayedGpuViewHiding(); } -void RenderWidgetHostViewMac::RenderViewGone() { +void RenderWidgetHostViewMac::RenderViewGone(base::TerminationStatus status, + int error_code) { // TODO(darin): keep this around, and draw sad-tab into it. UpdateCursorIfOverSelf(); Destroy(); diff --git a/chrome/browser/renderer_host/render_widget_host_view_views.cc b/chrome/browser/renderer_host/render_widget_host_view_views.cc index cdc2e38..ea808f0 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_views.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_views.cc @@ -131,7 +131,8 @@ RenderWidgetHostViewViews::RenderWidgetHostViewViews(RenderWidgetHost* host) } RenderWidgetHostViewViews::~RenderWidgetHostViewViews() { - RenderViewGone(); + RenderViewGone(base::TERMINATION_STATUS_NORMAL_TERMINATION, + ResultCodes::NORMAL_EXIT); } void RenderWidgetHostViewViews::InitAsChild() { @@ -286,7 +287,8 @@ void RenderWidgetHostViewViews::DidUpdateBackingStore( } } -void RenderWidgetHostViewViews::RenderViewGone() { +void RenderWidgetHostViewViews::RenderViewGone(base::TerminationStatus status, + int error_code) { GetRenderWidgetHost()->ViewDestroyed(); Destroy(); } diff --git a/chrome/browser/renderer_host/render_widget_host_view_views.h b/chrome/browser/renderer_host/render_widget_host_view_views.h index a9a918f..9c5c8cb 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_views.h +++ b/chrome/browser/renderer_host/render_widget_host_view_views.h @@ -60,7 +60,8 @@ class RenderWidgetHostViewViews : public RenderWidgetHostView, virtual void DidUpdateBackingStore( const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, const std::vector<gfx::Rect>& copy_rects); - virtual void RenderViewGone(); + virtual void RenderViewGone(base::TerminationStatus status, + int error_code); virtual void Destroy(); virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh) {} virtual void SetTooltipText(const std::wstring& tooltip_text); diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.cc b/chrome/browser/renderer_host/render_widget_host_view_win.cc index a665794..f5afe70 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_win.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_win.cc @@ -722,7 +722,8 @@ void RenderWidgetHostViewWin::DidUpdateBackingStore( Redraw(); } -void RenderWidgetHostViewWin::RenderViewGone() { +void RenderWidgetHostViewWin::RenderViewGone(base::TerminationStatus status, + int error_code) { // TODO(darin): keep this around, and draw sad-tab into it. UpdateCursorIfOverSelf(); being_destroyed_ = true; diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.h b/chrome/browser/renderer_host/render_widget_host_view_win.h index 282dfe9..1f67814 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_win.h +++ b/chrome/browser/renderer_host/render_widget_host_view_win.h @@ -148,7 +148,8 @@ class RenderWidgetHostViewWin virtual void DidUpdateBackingStore( const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, const std::vector<gfx::Rect>& copy_rects); - virtual void RenderViewGone(); + virtual void RenderViewGone(base::TerminationStatus status, + int error_code); virtual void WillWmDestroy(); // called by TabContents before DestroyWindow virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh); virtual void Destroy(); diff --git a/chrome/browser/renderer_host/test/test_render_view_host.h b/chrome/browser/renderer_host/test/test_render_view_host.h index a2ff8f7..7aa9638 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.h +++ b/chrome/browser/renderer_host/test/test_render_view_host.h @@ -83,7 +83,8 @@ class TestRenderWidgetHostView : public RenderWidgetHostView { virtual void DidUpdateBackingStore( const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, const std::vector<gfx::Rect>& rects) {} - virtual void RenderViewGone() { delete this; } + virtual void RenderViewGone(base::TerminationStatus status, + int error_code) { delete this; } virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh) { } virtual void Destroy() {} virtual void PrepareToDestroy() {} diff --git a/chrome/browser/renderer_host/test/web_cache_manager_browsertest.cc b/chrome/browser/renderer_host/test/web_cache_manager_browsertest.cc index 06ce085..3681c70 100644 --- a/chrome/browser/renderer_host/test/web_cache_manager_browsertest.cc +++ b/chrome/browser/renderer_host/test/web_cache_manager_browsertest.cc @@ -10,6 +10,7 @@ #include "chrome/browser/renderer_host/web_cache_manager.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/ui/browser.h" +#include "chrome/common/result_codes.h" #include "chrome/test/in_process_browser_test.h" #include "chrome/test/ui_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -33,7 +34,7 @@ IN_PROC_BROWSER_TEST_F(WebCacheManagerBrowserTest, FLAKY_CrashOnceOnly) { TabContents* tab = browser()->GetTabContentsAt(0); ASSERT_TRUE(tab != NULL); base::KillProcess(tab->GetRenderProcessHost()->GetHandle(), - base::PROCESS_END_KILLED_BY_USER, true); + ResultCodes::KILLED, true); browser()->SelectTabContentsAt(0, true); browser()->NewTab(); diff --git a/chrome/browser/tab_contents/interstitial_page.cc b/chrome/browser/tab_contents/interstitial_page.cc index d3c0429..bc9920b 100644 --- a/chrome/browser/tab_contents/interstitial_page.cc +++ b/chrome/browser/tab_contents/interstitial_page.cc @@ -333,7 +333,9 @@ const GURL& InterstitialPage::GetURL() const { return url_; } -void InterstitialPage::RenderViewGone(RenderViewHost* render_view_host) { +void InterstitialPage::RenderViewGone(RenderViewHost* render_view_host, + base::TerminationStatus status, + int error_code) { // Our renderer died. This should not happen in normal cases. // Just dismiss the interstitial. DontProceed(); diff --git a/chrome/browser/tab_contents/interstitial_page.h b/chrome/browser/tab_contents/interstitial_page.h index 50ede04..2faad77 100644 --- a/chrome/browser/tab_contents/interstitial_page.h +++ b/chrome/browser/tab_contents/interstitial_page.h @@ -9,6 +9,7 @@ #include <map> #include <string> +#include "base/process_util.h" #include "base/scoped_ptr.h" #include "chrome/browser/renderer_host/render_view_host_delegate.h" #include "chrome/common/notification_observer.h" @@ -124,7 +125,9 @@ class InterstitialPage : public NotificationObserver, // RenderViewHostDelegate implementation: virtual View* GetViewDelegate(); virtual const GURL& GetURL() const; - virtual void RenderViewGone(RenderViewHost* render_view_host); + virtual void RenderViewGone(RenderViewHost* render_view_host, + base::TerminationStatus status, + int error_code); virtual void DidNavigate(RenderViewHost* render_view_host, const ViewHostMsg_FrameNavigate_Params& params); virtual void UpdateTitle(RenderViewHost* render_view_host, diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 34ec892..f95634f 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -336,7 +336,8 @@ TabContents::TabContents(Profile* profile, bookmark_drag_(NULL), ALLOW_THIS_IN_INITIALIZER_LIST(fav_icon_helper_(this)), is_loading_(false), - is_crashed_(false), + crashed_status_(base::TERMINATION_STATUS_STILL_RUNNING), + crashed_error_code_(0), waiting_for_response_(false), max_page_id_(-1), current_load_start_(), @@ -767,11 +768,12 @@ void TabContents::RemoveNavigationObserver(WebNavigationObserver* observer) { web_navigation_observers_.RemoveObserver(observer); } -void TabContents::SetIsCrashed(bool state) { - if (state == is_crashed_) +void TabContents::SetIsCrashed(base::TerminationStatus status, int error_code) { + if (status == crashed_status_) return; - is_crashed_ = state; + crashed_status_ = status; + crashed_error_code_ = error_code; NotifyNavigationStateChanged(INVALIDATE_TAB); } @@ -2423,7 +2425,7 @@ void TabContents::RenderViewReady(RenderViewHost* rvh) { NotifyConnected(); bool was_crashed = is_crashed(); - SetIsCrashed(false); + SetIsCrashed(base::TERMINATION_STATUS_STILL_RUNNING, 0); // Restore the focus to the tab (otherwise the focus will be on the top // window). @@ -2433,7 +2435,9 @@ void TabContents::RenderViewReady(RenderViewHost* rvh) { } } -void TabContents::RenderViewGone(RenderViewHost* rvh) { +void TabContents::RenderViewGone(RenderViewHost* rvh, + base::TerminationStatus status, + int error_code) { // Ask the print preview if this renderer was valuable. if (!printing_->OnRenderViewGone(rvh)) return; @@ -2444,7 +2448,7 @@ void TabContents::RenderViewGone(RenderViewHost* rvh) { SetIsLoading(false, NULL); NotifyDisconnected(); - SetIsCrashed(true); + SetIsCrashed(status, error_code); // Remove all infobars. for (int i = infobar_delegate_count() - 1; i >=0 ; --i) @@ -3087,7 +3091,8 @@ void TabContents::DidStartLoadingFromRenderManager( void TabContents::RenderViewGoneFromRenderManager( RenderViewHost* render_view_host) { - RenderViewGone(render_view_host); + DCHECK(crashed_status_ != base::TERMINATION_STATUS_STILL_RUNNING); + RenderViewGone(render_view_host, crashed_status_, crashed_error_code_); } void TabContents::UpdateRenderViewSizeForRenderManager() { diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index 122380a..7800ee9 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -308,8 +308,14 @@ class TabContents : public PageNavigator, // Indicates whether this tab should be considered crashed. The setter will // also notify the delegate when the flag is changed. - bool is_crashed() const { return is_crashed_; } - void SetIsCrashed(bool state); + bool is_crashed() const { + return (crashed_status_ == base::TERMINATION_STATUS_PROCESS_CRASHED || + crashed_status_ == base::TERMINATION_STATUS_ABNORMAL_TERMINATION || + crashed_status_ == base::TERMINATION_STATUS_PROCESS_WAS_KILLED); + } + base::TerminationStatus crashed_status() const { return crashed_status_; } + int crashed_error_code() const { return crashed_error_code_; } + void SetIsCrashed(base::TerminationStatus status, int error_code); // Call this after updating a page action to notify clients about the changes. void PageActionStateChanged(); @@ -958,7 +964,9 @@ class TabContents : public PageNavigator, virtual int GetBrowserWindowID() const; virtual void RenderViewCreated(RenderViewHost* render_view_host); virtual void RenderViewReady(RenderViewHost* render_view_host); - virtual void RenderViewGone(RenderViewHost* render_view_host); + virtual void RenderViewGone(RenderViewHost* render_view_host, + base::TerminationStatus status, + int error_code); virtual void RenderViewDeleted(RenderViewHost* render_view_host); virtual void DidNavigate(RenderViewHost* render_view_host, const ViewHostMsg_FrameNavigate_Params& params); @@ -1146,7 +1154,8 @@ class TabContents : public PageNavigator, bool is_loading_; // Indicates if the tab is considered crashed. - bool is_crashed_; + base::TerminationStatus crashed_status_; + int crashed_error_code_; // See waiting_for_response() above. bool waiting_for_response_; diff --git a/chrome/browser/tab_contents/web_contents_unittest.cc b/chrome/browser/tab_contents/web_contents_unittest.cc index abb1578..67d93a3 100644 --- a/chrome/browser/tab_contents/web_contents_unittest.cc +++ b/chrome/browser/tab_contents/web_contents_unittest.cc @@ -120,8 +120,8 @@ class TestInterstitialPage : public InterstitialPage { DidNavigate(render_view_host(), params); } - void TestRenderViewGone() { - RenderViewGone(render_view_host()); + void TestRenderViewGone(base::TerminationStatus status, int error_code) { + RenderViewGone(render_view_host(), status, error_code); } bool is_showing() const { @@ -1151,7 +1151,9 @@ TEST_F(TabContentsTest, ShowInterstitialCrashRendererThenGoBack) { interstitial->TestDidNavigate(2, interstitial_url); // Crash the renderer - rvh()->TestOnMessageReceived(ViewHostMsg_RenderViewGone(0)); + rvh()->TestOnMessageReceived( + ViewHostMsg_RenderViewGone( + 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1)); // While the interstitial is showing, go back. controller().GoBack(); @@ -1186,7 +1188,9 @@ TEST_F(TabContentsTest, ShowInterstitialCrashRendererThenNavigate) { interstitial->Show(); // Crash the renderer - rvh()->TestOnMessageReceived(ViewHostMsg_RenderViewGone(0)); + rvh()->TestOnMessageReceived( + ViewHostMsg_RenderViewGone( + 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1)); interstitial->TestDidNavigate(2, interstitial_url); } @@ -1429,7 +1433,8 @@ TEST_F(TabContentsTest, InterstitialCrasher) { TestInterstitialPageStateGuard state_guard(interstitial); interstitial->Show(); // Simulate a renderer crash before the interstitial is shown. - interstitial->TestRenderViewGone(); + interstitial->TestRenderViewGone( + base::TERMINATION_STATUS_PROCESS_CRASHED, -1); // The interstitial should have been dismissed. EXPECT_TRUE(deleted); EXPECT_EQ(TestInterstitialPage::CANCELED, state); @@ -1440,7 +1445,8 @@ TEST_F(TabContentsTest, InterstitialCrasher) { interstitial->Show(); interstitial->TestDidNavigate(1, url); // Simulate a renderer crash. - interstitial->TestRenderViewGone(); + interstitial->TestRenderViewGone( + base::TERMINATION_STATUS_PROCESS_CRASHED, -1); // The interstitial should have been dismissed. EXPECT_TRUE(deleted); EXPECT_EQ(TestInterstitialPage::CANCELED, state); diff --git a/chrome/browser/task_manager/task_manager.cc b/chrome/browser/task_manager/task_manager.cc index 2dc5029..da19fda 100644 --- a/chrome/browser/task_manager/task_manager.cc +++ b/chrome/browser/task_manager/task_manager.cc @@ -26,6 +26,7 @@ #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/task_manager/task_manager_resource_providers.h" #include "chrome/common/pref_names.h" +#include "chrome/common/result_codes.h" #include "chrome/common/url_constants.h" #include "grit/app_resources.h" #include "grit/chromium_strings.h" @@ -944,7 +945,7 @@ void TaskManager::KillProcess(int index) { base::ProcessHandle process = model_->GetResourceProcessHandle(index); DCHECK(process); if (process != base::GetCurrentProcessHandle()) - base::KillProcess(process, base::PROCESS_END_KILLED_BY_USER, false); + base::KillProcess(process, ResultCodes::KILLED, false); } void TaskManager::ActivateProcess(int index) { diff --git a/chrome/browser/utility_process_host.cc b/chrome/browser/utility_process_host.cc index 1756d3e..b8d6a77 100644 --- a/chrome/browser/utility_process_host.cc +++ b/chrome/browser/utility_process_host.cc @@ -159,10 +159,10 @@ void UtilityProcessHost::OnMessageReceived(const IPC::Message& message) { NewRunnableMethod(client_.get(), &Client::OnMessageReceived, message)); } -void UtilityProcessHost::OnProcessCrashed() { +void UtilityProcessHost::OnProcessCrashed(int exit_code) { BrowserThread::PostTask( client_thread_id_, FROM_HERE, - NewRunnableMethod(client_.get(), &Client::OnProcessCrashed)); + NewRunnableMethod(client_.get(), &Client::OnProcessCrashed, exit_code)); } bool UtilityProcessHost::CanShutdown() { diff --git a/chrome/browser/utility_process_host.h b/chrome/browser/utility_process_host.h index 559f39e..96879a8 100644 --- a/chrome/browser/utility_process_host.h +++ b/chrome/browser/utility_process_host.h @@ -39,7 +39,7 @@ class UtilityProcessHost : public BrowserChildProcessHost { Client() {} // Called when the process has crashed. - virtual void OnProcessCrashed() {} + virtual void OnProcessCrashed(int exit_code) {} // Called when the extension has unpacked successfully. |manifest| is the // parsed manifest.json file. |catalogs| contains list of all parsed @@ -153,7 +153,7 @@ class UtilityProcessHost : public BrowserChildProcessHost { virtual void OnMessageReceived(const IPC::Message& message); // BrowserChildProcessHost: - virtual void OnProcessCrashed(); + virtual void OnProcessCrashed(int exit_code); virtual bool CanShutdown(); virtual URLRequestContext* GetRequestContext( uint32 request_id, diff --git a/chrome/browser/web_resource/web_resource_service.cc b/chrome/browser/web_resource/web_resource_service.cc index ab557f5..e1de48a 100644 --- a/chrome/browser/web_resource/web_resource_service.cc +++ b/chrome/browser/web_resource/web_resource_service.cc @@ -157,7 +157,7 @@ class WebResourceService::UnpackerClient ~UnpackerClient() {} // UtilityProcessHost::Client - virtual void OnProcessCrashed() { + virtual void OnProcessCrashed(int exit_code) { if (got_response_) return; diff --git a/chrome/browser/zygote_host_linux.cc b/chrome/browser/zygote_host_linux.cc index 74b6852..e4e7ce3 100644 --- a/chrome/browser/zygote_host_linux.cc +++ b/chrome/browser/zygote_host_linux.cc @@ -27,6 +27,7 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/process_watcher.h" +#include "chrome/common/result_codes.h" #include "sandbox/linux/suid/suid_unsafe_environment_variables.h" @@ -316,13 +317,18 @@ void ZygoteHost::EnsureProcessTerminated(pid_t process) { PLOG(ERROR) << "write"; } -bool ZygoteHost::DidProcessCrash(base::ProcessHandle handle, - bool* child_exited) { +base::TerminationStatus ZygoteHost::GetTerminationStatus( + base::ProcessHandle handle, + int* exit_code) { DCHECK(init_); Pickle pickle; - pickle.WriteInt(kCmdDidProcessCrash); + pickle.WriteInt(kCmdGetTerminationStatus); pickle.WriteInt(handle); + // Set this now to handle the early termination cases. + if (exit_code) + *exit_code = ResultCodes::NORMAL_EXIT; + static const unsigned kMaxMessageLength = 128; char buf[kMaxMessageLength]; ssize_t len; @@ -336,23 +342,23 @@ bool ZygoteHost::DidProcessCrash(base::ProcessHandle handle, if (len == -1) { LOG(WARNING) << "Error reading message from zygote: " << errno; - return false; + return base::TERMINATION_STATUS_NORMAL_TERMINATION; } else if (len == 0) { LOG(WARNING) << "Socket closed prematurely."; - return false; + return base::TERMINATION_STATUS_NORMAL_TERMINATION; } Pickle read_pickle(buf, len); - bool did_crash, tmp_child_exited; + int status, tmp_exit_code; void* iter = NULL; - if (!read_pickle.ReadBool(&iter, &did_crash) || - !read_pickle.ReadBool(&iter, &tmp_child_exited)) { - LOG(WARNING) << "Error parsing DidProcessCrash response from zygote."; - return false; + if (!read_pickle.ReadInt(&iter, &status) || + !read_pickle.ReadInt(&iter, &tmp_exit_code)) { + LOG(WARNING) << "Error parsing GetTerminationStatus response from zygote."; + return base::TERMINATION_STATUS_NORMAL_TERMINATION; } - if (child_exited) - *child_exited = tmp_child_exited; + if (exit_code) + *exit_code = tmp_exit_code; - return did_crash; + return static_cast<base::TerminationStatus>(status); } diff --git a/chrome/browser/zygote_host_linux.h b/chrome/browser/zygote_host_linux.h index 01a6443..e13f1b4 100644 --- a/chrome/browser/zygote_host_linux.h +++ b/chrome/browser/zygote_host_linux.h @@ -14,6 +14,7 @@ #include "base/global_descriptors_posix.h" #include "base/lock.h" #include "base/process.h" +#include "base/process_util.h" template<typename Type> struct DefaultSingletonTraits; @@ -37,26 +38,27 @@ class ZygoteHost { const base::GlobalDescriptors::Mapping& mapping); void EnsureProcessTerminated(pid_t process); - // Get the termination status (exit code) of the process and return true if - // the status indicates the process crashed. |child_exited| is set to true - // iff the child process has terminated. (|child_exited| may be NULL.) - bool DidProcessCrash(base::ProcessHandle handle, bool* child_exited); + // Get the termination status (and, optionally, the exit code) of + // the process. |exit_code| is set to the exit code of the child + // process. (|exit_code| may be NULL.) + base::TerminationStatus GetTerminationStatus(base::ProcessHandle handle, + int* exit_code); // These are the command codes used on the wire between the browser and the // zygote. enum { - kCmdFork = 0, // Fork off a new renderer. - kCmdReap = 1, // Reap a renderer child. - kCmdDidProcessCrash = 2, // Check if child process crashed. - kCmdGetSandboxStatus = 3, // Read a bitmask of kSandbox* + kCmdFork = 0, // Fork off a new renderer. + kCmdReap = 1, // Reap a renderer child. + kCmdGetTerminationStatus = 2, // Check what happend to a child process. + kCmdGetSandboxStatus = 3, // Read a bitmask of kSandbox* }; // These form a bitmask which describes the conditions of the sandbox that // the zygote finds itself in. enum { - kSandboxSUID = 1 << 0, // SUID sandbox active - kSandboxPIDNS = 1 << 1, // SUID sandbox is using the PID namespace - kSandboxNetNS = 1 << 2, // SUID sandbox is using the network namespace + kSandboxSUID = 1 << 0, // SUID sandbox active + kSandboxPIDNS = 1 << 1, // SUID sandbox is using the PID namespace + kSandboxNetNS = 1 << 2, // SUID sandbox is using the network namespace kSandboxSeccomp = 1 << 3, // seccomp sandbox active. }; diff --git a/chrome/browser/zygote_main_linux.cc b/chrome/browser/zygote_main_linux.cc index 5943d11..1b26a6b 100644 --- a/chrome/browser/zygote_main_linux.cc +++ b/chrome/browser/zygote_main_linux.cc @@ -41,6 +41,7 @@ #include "chrome/common/main_function_params.h" #include "chrome/common/pepper_plugin_registry.h" #include "chrome/common/process_watcher.h" +#include "chrome/common/result_codes.h" #include "chrome/common/sandbox_methods_linux.h" #include "media/base/media.h" @@ -167,10 +168,10 @@ class Zygote { break; HandleReapRequest(fd, pickle, iter); return false; - case ZygoteHost::kCmdDidProcessCrash: + case ZygoteHost::kCmdGetTerminationStatus: if (!fds.empty()) break; - HandleDidProcessCrash(fd, pickle, iter); + HandleGetTerminationStatus(fd, pickle, iter); return false; case ZygoteHost::kCmdGetSandboxStatus: HandleGetSandboxStatus(fd, pickle, iter); @@ -209,26 +210,31 @@ class Zygote { ProcessWatcher::EnsureProcessTerminated(actual_child); } - void HandleDidProcessCrash(int fd, const Pickle& pickle, void* iter) { + void HandleGetTerminationStatus(int fd, const Pickle& pickle, void* iter) { base::ProcessHandle child; if (!pickle.ReadInt(&iter, &child)) { - LOG(WARNING) << "Error parsing DidProcessCrash request from browser"; + LOG(WARNING) << "Error parsing GetTerminationStatus request " + << "from browser"; return; } - bool child_exited; - bool did_crash; + base::TerminationStatus status; + int exit_code; if (g_suid_sandbox_active) child = real_pids_to_sandbox_pids[child]; - if (child) - did_crash = base::DidProcessCrash(&child_exited, child); - else - did_crash = child_exited = false; + if (child) { + status = base::GetTerminationStatus(child, &exit_code); + } else { + // Assume that if we can't find the child in the sandbox, then + // it terminated normally. + status = base::TERMINATION_STATUS_NORMAL_TERMINATION; + exit_code = ResultCodes::NORMAL_EXIT; + } Pickle write_pickle; - write_pickle.WriteBool(did_crash); - write_pickle.WriteBool(child_exited); + write_pickle.WriteInt(static_cast<int>(status)); + write_pickle.WriteInt(exit_code); if (HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size())) != write_pickle.size()) { PLOG(ERROR) << "write"; |