Commit 2930eb12 authored by Tobias Sargeant's avatar Tobias Sargeant Committed by Commit Bot

[wv] Propagate onRenderProcessGone exceptions back to the application.

If an exception is thrown in onRenderProcessGone, then it should be
propagated back to the UI thread message loop so that it is observable
by the application/debuggerd as something other than a native crash.

Bug: 592556
Change-Id: I28b6792c4503347092ce4e79370b20de87c51114
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1585881
Commit-Queue: Tobias Sargeant <tobiasjs@chromium.org>
Reviewed-by: default avatarRichard Coles <torne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#663026}
parent b997fe2a
...@@ -9,11 +9,14 @@ ...@@ -9,11 +9,14 @@
#include "android_webview/browser/aw_render_process_gone_delegate.h" #include "android_webview/browser/aw_render_process_gone_delegate.h"
#include "android_webview/common/aw_descriptors.h" #include "android_webview/common/aw_descriptors.h"
#include "base/android/scoped_java_ref.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "components/crash/content/app/crashpad.h" #include "components/crash/content/app/crashpad.h"
#include "components/crash/content/browser/crash_metrics_reporter_android.h" #include "components/crash/content/browser/crash_metrics_reporter_android.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_data.h" #include "content/public/browser/child_process_data.h"
#include "content/public/browser/child_process_launcher_utils.h" #include "content/public/browser/child_process_launcher_utils.h"
...@@ -26,15 +29,16 @@ ...@@ -26,15 +29,16 @@
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "jni/AwBrowserProcess_jni.h" #include "jni/AwBrowserProcess_jni.h"
using base::android::ScopedJavaGlobalRef;
using content::BrowserThread; using content::BrowserThread;
namespace android_webview { namespace android_webview {
namespace { namespace {
void GetAwRenderProcessGoneDelegatesForRenderProcess( void GetJavaWebContentsForRenderProcess(
content::RenderProcessHost* rph, content::RenderProcessHost* rph,
std::vector<AwRenderProcessGoneDelegate*>* delegates) { std::vector<ScopedJavaGlobalRef<jobject>>* java_web_contents) {
std::unique_ptr<content::RenderWidgetHostIterator> widgets( std::unique_ptr<content::RenderWidgetHostIterator> widgets(
content::RenderWidgetHost::GetRenderWidgetHosts()); content::RenderWidgetHost::GetRenderWidgetHosts());
while (content::RenderWidgetHost* widget = widgets->GetNextHost()) { while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
...@@ -42,39 +46,56 @@ void GetAwRenderProcessGoneDelegatesForRenderProcess( ...@@ -42,39 +46,56 @@ void GetAwRenderProcessGoneDelegatesForRenderProcess(
if (view && rph == view->GetProcess()) { if (view && rph == view->GetProcess()) {
content::WebContents* wc = content::WebContents::FromRenderViewHost(view); content::WebContents* wc = content::WebContents::FromRenderViewHost(view);
if (wc) { if (wc) {
AwRenderProcessGoneDelegate* delegate = java_web_contents->push_back(static_cast<ScopedJavaGlobalRef<jobject>>(
AwRenderProcessGoneDelegate::FromWebContents(wc); wc->GetJavaWebContents()));
if (delegate)
delegates->push_back(delegate);
} }
} }
} }
} }
void OnRenderProcessGone(content::RenderProcessHost* host, void OnRenderProcessGone(
base::ProcessId child_process_pid, const std::vector<ScopedJavaGlobalRef<jobject>>& java_web_contents,
bool crashed) { base::ProcessId child_process_pid,
bool crashed) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
std::vector<AwRenderProcessGoneDelegate*> delegates;
GetAwRenderProcessGoneDelegatesForRenderProcess(host, &delegates); for (auto& java_wc : java_web_contents) {
for (auto* delegate : delegates) { content::WebContents* wc =
if (!delegate->OnRenderProcessGone(child_process_pid, crashed)) { content::WebContents::FromJavaWebContents(java_wc);
if (crashed) { if (!wc)
// Keeps this log unchanged, CTS test uses it to detect crash. continue;
std::string message = base::StringPrintf(
"Render process (%d)'s crash wasn't handled by all associated " AwRenderProcessGoneDelegate* delegate =
"webviews, triggering application crash.", AwRenderProcessGoneDelegate::FromWebContents(wc);
child_process_pid); if (!delegate)
crash_reporter::CrashWithoutDumping(message); continue;
} else {
// The render process was most likely killed for OOM or switching switch (delegate->OnRenderProcessGone(child_process_pid, crashed)) {
// WebView provider, to make WebView backward compatible, kills the case AwRenderProcessGoneDelegate::RenderProcessGoneResult::kException:
// browser process instead of triggering crash. // Let the exception propagate back to the message loop.
LOG(ERROR) << "Render process (" << child_process_pid << ") kill (OOM" base::MessageLoopCurrentForUI::Get()->Abort();
<< " or update) wasn't handed by all associated webviews," return;
<< " killing application."; case AwRenderProcessGoneDelegate::RenderProcessGoneResult::kUnhandled:
kill(getpid(), SIGKILL); if (crashed) {
} // Keeps this log unchanged, CTS test uses it to detect crash.
std::string message = base::StringPrintf(
"Render process (%d)'s crash wasn't handled by all associated "
"webviews, triggering application crash.",
child_process_pid);
crash_reporter::CrashWithoutDumping(message);
} else {
// The render process was most likely killed for OOM or switching
// WebView provider, to make WebView backward compatible, kills the
// browser process instead of triggering crash.
LOG(ERROR) << "Render process (" << child_process_pid << ") kill (OOM"
<< " or update) wasn't handed by all associated webviews,"
<< " killing application.";
kill(getpid(), SIGKILL);
}
NOTREACHED();
break;
case AwRenderProcessGoneDelegate::RenderProcessGoneResult::kHandled:
break;
} }
} }
...@@ -104,7 +125,13 @@ void AwBrowserTerminator::OnChildExit( ...@@ -104,7 +125,13 @@ void AwBrowserTerminator::OnChildExit(
LOG(ERROR) << "Renderer process (" << info.pid << ") crash detected (code " LOG(ERROR) << "Renderer process (" << info.pid << ") crash detected (code "
<< info.crash_signo << ")."; << info.crash_signo << ").";
OnRenderProcessGone(rph, info.pid, info.is_crashed()); std::vector<ScopedJavaGlobalRef<jobject>> java_web_contents;
GetJavaWebContentsForRenderProcess(rph, &java_web_contents);
base::PostTaskWithTraits(
FROM_HERE, {content::BrowserThread::UI, base::TaskPriority::HIGHEST},
base::BindOnce(OnRenderProcessGone, java_web_contents, info.pid,
info.is_crashed()));
} }
} // namespace android_webview } // namespace android_webview
...@@ -1493,15 +1493,23 @@ void AwContents::RendererResponsive( ...@@ -1493,15 +1493,23 @@ void AwContents::RendererResponsive(
aw_render_process->GetJavaObject()); aw_render_process->GetJavaObject());
} }
bool AwContents::OnRenderProcessGone(int child_process_id, bool crashed) { AwContents::RenderProcessGoneResult AwContents::OnRenderProcessGone(
int child_process_id,
bool crashed) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
JNIEnv* env = AttachCurrentThread(); JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null()) if (obj.is_null())
return false; return RenderProcessGoneResult::kHandled;
bool result =
Java_AwContents_onRenderProcessGone(env, obj, child_process_id, crashed);
if (HasException(env))
return RenderProcessGoneResult::kException;
return Java_AwContents_onRenderProcessGone(env, obj, child_process_id, return result ? RenderProcessGoneResult::kHandled
crashed); : RenderProcessGoneResult::kUnhandled;
} }
} // namespace android_webview } // namespace android_webview
...@@ -365,7 +365,8 @@ class AwContents : public FindHelper::Listener, ...@@ -365,7 +365,8 @@ class AwContents : public FindHelper::Listener,
const base::android::JavaParamRef<jobject>& callback); const base::android::JavaParamRef<jobject>& callback);
// AwRenderProcessGoneDelegate overrides // AwRenderProcessGoneDelegate overrides
bool OnRenderProcessGone(int child_process_id, bool crashed) override; RenderProcessGoneResult OnRenderProcessGone(int child_process_id,
bool crashed) override;
private: private:
void InitAutofillIfNecessary(bool autocomplete_enabled); void InitAutofillIfNecessary(bool autocomplete_enabled);
......
...@@ -14,13 +14,15 @@ namespace android_webview { ...@@ -14,13 +14,15 @@ namespace android_webview {
// Delegate interface to handle the events that render process was gone. // Delegate interface to handle the events that render process was gone.
class AwRenderProcessGoneDelegate { class AwRenderProcessGoneDelegate {
public: public:
enum class RenderProcessGoneResult { kHandled, kUnhandled, kException };
// Returns the AwRenderProcessGoneDelegate instance associated with // Returns the AwRenderProcessGoneDelegate instance associated with
// the given |web_contents|. // the given |web_contents|.
static AwRenderProcessGoneDelegate* FromWebContents( static AwRenderProcessGoneDelegate* FromWebContents(
content::WebContents* web_contents); content::WebContents* web_contents);
// Notify if render process crashed or was killed. // Notify if render process crashed or was killed.
virtual bool OnRenderProcessGone(int child_process_id, bool crashed) = 0; virtual RenderProcessGoneResult OnRenderProcessGone(int child_process_id,
bool crashed) = 0;
protected: protected:
AwRenderProcessGoneDelegate() {} AwRenderProcessGoneDelegate() {}
......
...@@ -61,6 +61,7 @@ import org.chromium.base.ThreadUtils; ...@@ -61,6 +61,7 @@ import org.chromium.base.ThreadUtils;
import org.chromium.base.TraceEvent; import org.chromium.base.TraceEvent;
import org.chromium.base.VisibleForTesting; import org.chromium.base.VisibleForTesting;
import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.CalledByNativeUnchecked;
import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.task.AsyncTask; import org.chromium.base.task.AsyncTask;
...@@ -1371,7 +1372,7 @@ public class AwContents implements SmartClipProvider { ...@@ -1371,7 +1372,7 @@ public class AwContents implements SmartClipProvider {
} }
@VisibleForTesting @VisibleForTesting
@CalledByNative @CalledByNativeUnchecked
protected boolean onRenderProcessGone(int childProcessID, boolean crashed) { protected boolean onRenderProcessGone(int childProcessID, boolean crashed) {
if (isDestroyed(NO_WARN)) return true; if (isDestroyed(NO_WARN)) return true;
return mContentsClient.onRenderProcessGone(new AwRenderProcessGoneDetail( return mContentsClient.onRenderProcessGone(new AwRenderProcessGoneDetail(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment