Index: android_webview/browser/aw_browser_terminator.cc |
diff --git a/android_webview/browser/aw_browser_terminator.cc b/android_webview/browser/aw_browser_terminator.cc |
index 23c42856fdf84fbebcd58067417c979c8f91c7db..34052e0a0994061b923adf220440b694cdf84f89 100644 |
--- a/android_webview/browser/aw_browser_terminator.cc |
+++ b/android_webview/browser/aw_browser_terminator.cc |
@@ -6,6 +6,7 @@ |
#include <unistd.h> |
+#include "android_webview/browser/aw_render_process_gone_delegate.h" |
#include "android_webview/common/aw_descriptors.h" |
#include "android_webview/common/crash_reporter/aw_microdump_crash_reporter.h" |
#include "base/bind.h" |
@@ -17,11 +18,64 @@ |
#include "content/public/browser/notification_service.h" |
#include "content/public/browser/notification_types.h" |
#include "content/public/browser/render_process_host.h" |
+#include "content/public/browser/render_view_host.h" |
+#include "content/public/browser/render_widget_host.h" |
+#include "content/public/browser/render_widget_host_iterator.h" |
+#include "content/public/browser/web_contents.h" |
using content::BrowserThread; |
namespace android_webview { |
+namespace { |
+ |
+void GetAwRenderProcessGoneDelegatesForRenderProcess( |
+ int render_process_id, |
+ std::vector<AwRenderProcessGoneDelegate*>* delegates) { |
+ content::RenderProcessHost* rph = |
+ content::RenderProcessHost::FromID(render_process_id); |
+ if (!rph) |
+ return; |
+ |
+ std::unique_ptr<content::RenderWidgetHostIterator> widgets( |
+ content::RenderWidgetHost::GetRenderWidgetHosts()); |
+ while (content::RenderWidgetHost* widget = widgets->GetNextHost()) { |
+ content::RenderViewHost* view = content::RenderViewHost::From(widget); |
+ if (view && rph == view->GetProcess()) { |
+ content::WebContents* wc = content::WebContents::FromRenderViewHost(view); |
+ if (wc) { |
+ AwRenderProcessGoneDelegate* delegate = |
+ AwRenderProcessGoneDelegate::FromWebContents(wc); |
+ if (delegate) |
+ delegates->push_back(delegate); |
+ } |
+ } |
+ } |
+} |
+ |
+void OnRenderProcessGone(int child_process_id) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ std::vector<AwRenderProcessGoneDelegate*> delegates; |
+ GetAwRenderProcessGoneDelegatesForRenderProcess(child_process_id, &delegates); |
+ for (auto delegate : delegates) |
+ delegate->OnRenderProcessGone(child_process_id); |
+} |
+ |
+void OnRenderProcessGoneDetail(int child_process_id, bool crashed) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ std::vector<AwRenderProcessGoneDelegate*> delegates; |
+ GetAwRenderProcessGoneDelegatesForRenderProcess(child_process_id, &delegates); |
+ for (auto delegate : delegates) { |
+ if (!delegate->OnRenderProcessGoneDetail(child_process_id, crashed)) { |
+ // Keeps this log unchanged, CTS test uses it to detect crash. |
+ LOG(FATAL) << "Render process's abnormal termination wasn't handled by" |
+ << " all associated webviews, triggering application crash"; |
+ } |
+ } |
+} |
+ |
+} // namespace |
+ |
AwBrowserTerminator::AwBrowserTerminator() {} |
AwBrowserTerminator::~AwBrowserTerminator() {} |
@@ -43,19 +97,23 @@ void AwBrowserTerminator::OnChildStart(int child_process_id, |
} |
void AwBrowserTerminator::ProcessTerminationStatus( |
+ int child_process_id, |
std::unique_ptr<base::SyncSocket> pipe) { |
+ bool crashed = false; |
+ |
+ // If the child process hasn't written anything into the pipe. This implies |
+ // that it was terminated via SIGKILL by the low memory killer. |
if (pipe->Peek() >= sizeof(int)) { |
int exit_code; |
pipe->Receive(&exit_code, sizeof(exit_code)); |
crash_reporter::SuppressDumpGeneration(); |
- LOG(FATAL) << "Renderer process crash detected (code " << exit_code |
- << "). Terminating browser."; |
- } else { |
- // The child process hasn't written anything into the pipe. This implies |
- // that it was terminated via SIGKILL by the low memory killer, and thus we |
- // need to perform a clean exit. |
- exit(0); |
+ LOG(ERROR) << "Renderer process crash detected (code " << exit_code << ")."; |
+ crashed = true; |
} |
+ |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ base::Bind(&OnRenderProcessGoneDetail, child_process_id, crashed)); |
} |
void AwBrowserTerminator::OnChildExit( |
@@ -79,10 +137,12 @@ void AwBrowserTerminator::OnChildExit( |
} |
if (termination_status == base::TERMINATION_STATUS_NORMAL_TERMINATION) |
return; |
+ OnRenderProcessGone(child_process_id); |
DCHECK(pipe->handle() != base::SyncSocket::kInvalidHandle); |
BrowserThread::PostTask( |
BrowserThread::FILE, FROM_HERE, |
base::Bind(&AwBrowserTerminator::ProcessTerminationStatus, |
+ child_process_id, |
base::Passed(std::move(pipe)))); |
} |