Add CefV8ContextHandler::OnUncaughtException callback (issue #736).

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@890 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt
2012-11-02 18:16:28 +00:00
parent 202cdc4eb4
commit e599cc1fab
23 changed files with 613 additions and 14 deletions

View File

@@ -17,6 +17,7 @@ MSVC_POP_WARNING();
#include "libcef/common/content_client.h"
#include "libcef/renderer/browser_impl.h"
#include "libcef/renderer/chrome_bindings.h"
#include "libcef/renderer/render_message_filter.h"
#include "libcef/renderer/render_process_observer.h"
#include "libcef/renderer/thread_util.h"
#include "libcef/renderer/v8_impl.h"
@@ -71,7 +72,9 @@ struct CefContentRendererClient::SchemeInfo {
bool is_display_isolated;
};
CefContentRendererClient::CefContentRendererClient() {
CefContentRendererClient::CefContentRendererClient()
: devtools_agent_count_(0),
uncaught_exception_stack_size_(0) {
}
CefContentRendererClient::~CefContentRendererClient() {
@@ -148,12 +151,33 @@ void CefContentRendererClient::RegisterCustomSchemes() {
}
}
void CefContentRendererClient::DevToolsAgentAttached() {
CEF_REQUIRE_RT();
++devtools_agent_count_;
}
void CefContentRendererClient::DevToolsAgentDetached() {
CEF_REQUIRE_RT();
--devtools_agent_count_;
if (devtools_agent_count_ == 0 && uncaught_exception_stack_size_ > 0) {
// When the last DevToolsAgent is detached the stack size is set to 0.
// Restore the user-specified stack size here.
v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
uncaught_exception_stack_size_, v8::StackTrace::kDetailed);
}
}
void CefContentRendererClient::SetUncaughtExceptionStackSize(int stackSize) {
uncaught_exception_stack_size_ = stackSize;
}
void CefContentRendererClient::RenderThreadStarted() {
render_loop_ = base::MessageLoopProxy::current();
observer_.reset(new CefRenderProcessObserver());
content::RenderThread* thread = content::RenderThread::Get();
thread->AddObserver(observer_.get());
thread->GetChannel()->AddFilter(new CefRenderMessageFilter);
WebKit::WebPrerenderingSupport::initialize(new CefPrerenderingSupport());

View File

@@ -48,6 +48,10 @@ class CefContentRendererClient : public content::ContentRendererClient {
// Render thread message loop proxy.
base::MessageLoopProxy* render_loop() const { return render_loop_.get(); }
void DevToolsAgentAttached();
void DevToolsAgentDetached();
void SetUncaughtExceptionStackSize(int stackSize);
private:
// ContentRendererClient implementation.
virtual void RenderThreadStarted() OVERRIDE;
@@ -71,6 +75,9 @@ class CefContentRendererClient : public content::ContentRendererClient {
struct SchemeInfo;
typedef std::list<SchemeInfo> SchemeInfoList;
SchemeInfoList scheme_info_list_;
int devtools_agent_count_;
int uncaught_exception_stack_size_;
};
#endif // CEF_LIBCEF_RENDERER_CONTENT_RENDERER_CLIENT_H_

View File

@@ -0,0 +1,82 @@
/// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libcef/renderer/render_message_filter.h"
#include "libcef/renderer/thread_util.h"
#include "libcef/common/cef_messages.h"
#include "base/bind.h"
#include "base/message_loop.h"
#include "content/common/devtools_messages.h"
#include "googleurl/src/gurl.h"
#include "googleurl/src/url_util.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityPolicy.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
CefRenderMessageFilter::CefRenderMessageFilter()
: channel_(NULL) {
}
CefRenderMessageFilter::~CefRenderMessageFilter() {
}
void CefRenderMessageFilter::OnFilterAdded(IPC::Channel* channel) {
channel_ = channel;
}
void CefRenderMessageFilter::OnFilterRemoved() {
}
bool CefRenderMessageFilter::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
if (message.type() == DevToolsAgentMsg_Attach::ID ||
message.type() == DevToolsAgentMsg_Reattach::ID ||
message.type() == DevToolsAgentMsg_Detach::ID) {
// Observe the DevTools messages but don't handle them.
handled = false;
}
IPC_BEGIN_MESSAGE_MAP(CefRenderMessageFilter, message)
IPC_MESSAGE_HANDLER(DevToolsAgentMsg_Attach, OnDevToolsAgentAttach)
IPC_MESSAGE_HANDLER(DevToolsAgentMsg_Reattach, OnDevToolsAgentReattach)
IPC_MESSAGE_HANDLER(DevToolsAgentMsg_Detach, OnDevToolsAgentDetach)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void CefRenderMessageFilter::OnDevToolsAgentAttach() {
CEF_POST_TASK_RT(
base::Bind(&CefRenderMessageFilter::OnDevToolsAgentAttach_RT, this));
}
void CefRenderMessageFilter::OnDevToolsAgentReattach(
const std::string& agent_state) {
// Treat reattach the same as attach.
OnDevToolsAgentAttach();
}
void CefRenderMessageFilter::OnDevToolsAgentDetach() {
// CefContentRendererClient::DevToolsAgentDetached() needs to be called after
// the IPC message has been handled by DevToolsAgent. A workaround for this is
// to first post to the IO thread and then post to the renderer thread.
MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(&CefRenderMessageFilter::OnDevToolsAgentDetach_IOT, this));
}
void CefRenderMessageFilter::OnDevToolsAgentAttach_RT() {
CEF_REQUIRE_RT();
CefContentRendererClient::Get()->DevToolsAgentAttached();
}
void CefRenderMessageFilter::OnDevToolsAgentDetach_IOT() {
CEF_POST_TASK_RT(
base::Bind(&CefRenderMessageFilter::OnDevToolsAgentDetach_RT, this));
}
void CefRenderMessageFilter::OnDevToolsAgentDetach_RT() {
CEF_REQUIRE_RT();
CefContentRendererClient::Get()->DevToolsAgentDetached();
}

View File

@@ -0,0 +1,39 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CEF_LIBCEF_RENDERER_RENDER_MESSAGE_FILTER_H_
#define CEF_LIBCEF_RENDERER_RENDER_MESSAGE_FILTER_H_
#include <string>
#include "ipc/ipc_channel_proxy.h"
// This class sends and receives control messages on the renderer process.
class CefRenderMessageFilter : public IPC::ChannelProxy::MessageFilter {
public:
CefRenderMessageFilter();
virtual ~CefRenderMessageFilter();
// IPC::ChannelProxy::MessageFilter implementation.
virtual void OnFilterAdded(IPC::Channel* channel) OVERRIDE;
virtual void OnFilterRemoved() OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
private:
// Message handlers called on the IO thread.
void OnDevToolsAgentAttach();
void OnDevToolsAgentReattach(const std::string& agent_state);
void OnDevToolsAgentDetach();
void OnDevToolsAgentAttach_RT();
void OnDevToolsAgentDetach_IOT();
void OnDevToolsAgentDetach_RT();
IPC::Channel* channel_;
DISALLOW_COPY_AND_ASSIGN(CefRenderMessageFilter);
};
#endif // CEF_LIBCEF_RENDERER_RENDER_MESSAGE_FILTER_H_

View File

@@ -5,11 +5,15 @@
#include "libcef/renderer/render_process_observer.h"
#include "libcef/common/cef_messages.h"
#include "libcef/common/cef_switches.h"
#include "libcef/common/command_line_impl.h"
#include "libcef/common/content_client.h"
#include "libcef/renderer/content_renderer_client.h"
#include "libcef/renderer/v8_impl.h"
#include "base/bind.h"
#include "base/path_service.h"
#include "base/string_number_conversions.h"
#include "googleurl/src/gurl.h"
#include "googleurl/src/url_util.h"
#include "media/base/media.h"
@@ -53,6 +57,23 @@ void CefRenderProcessObserver::WebKitInitialized() {
// Register any custom schemes with WebKit.
CefContentRendererClient::Get()->RegisterCustomSchemes();
// The number of stack trace frames to capture for uncaught exceptions.
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kUncaughtExceptionStackSize)) {
int uncaught_exception_stack_size = 0;
base::StringToInt(
command_line.GetSwitchValueASCII(switches::kUncaughtExceptionStackSize),
&uncaught_exception_stack_size);
if (uncaught_exception_stack_size > 0) {
CefContentRendererClient::Get()->SetUncaughtExceptionStackSize(
uncaught_exception_stack_size);
v8::V8::AddMessageListener(&CefV8MessageHandler);
v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
uncaught_exception_stack_size, v8::StackTrace::kDetailed);
}
}
// Notify the render process handler.
CefRefPtr<CefApp> application = CefContentClient::Get()->application();
if (application.get()) {

View File

@@ -21,6 +21,7 @@ MSVC_POP_WARNING();
#include "libcef/renderer/v8_impl.h"
#include "libcef/common/cef_switches.h"
#include "libcef/common/content_client.h"
#include "libcef/common/tracker.h"
#include "libcef/renderer/browser_impl.h"
#include "libcef/renderer/thread_util.h"
@@ -1665,3 +1666,28 @@ bool CefV8StackFrameImpl::IsConstructor() {
v8::HandleScope handle_scope;
return GetHandle()->IsConstructor();
}
void CefV8MessageHandler(v8::Handle<v8::Message> message,
v8::Handle<v8::Value> data) {
CEF_REQUIRE_RT_RETURN(void());
CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
CefRefPtr<CefBrowser> browser = context->GetBrowser();
CefRefPtr<CefFrame> frame = context->GetFrame();
v8::Handle<v8::StackTrace> v8Stack = message->GetStackTrace();
DCHECK(!v8Stack.IsEmpty());
CefRefPtr<CefV8StackTrace> stackTrace = new CefV8StackTraceImpl(v8Stack);
CefRefPtr<CefApp> application = CefContentClient::Get()->application();
if (!application.get())
return;
CefRefPtr<CefRenderProcessHandler> handler =
application->GetRenderProcessHandler();
if (!handler.get())
return;
CefRefPtr<CefV8Exception> exception = new CefV8ExceptionImpl(message);
handler->OnUncaughtException(browser, frame, context, exception, stackTrace);
}

View File

@@ -293,4 +293,7 @@ class CefV8StackFrameImpl : public CefV8StackFrame {
DISALLOW_COPY_AND_ASSIGN(CefV8StackFrameImpl);
};
void CefV8MessageHandler(v8::Handle<v8::Message> message,
v8::Handle<v8::Value> data);
#endif // CEF_LIBCEF_RENDERER_V8_IMPL_H_