diff options
16 files changed, 554 insertions, 155 deletions
diff --git a/chrome/browser/extensions/api/messaging/message_service.cc b/chrome/browser/extensions/api/messaging/message_service.cc index b5ef18d..36e1e32 100644 --- a/chrome/browser/extensions/api/messaging/message_service.cc +++ b/chrome/browser/extensions/api/messaging/message_service.cc @@ -23,6 +23,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/tab_util.h" #include "components/guest_view/common/guest_view_constants.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" @@ -51,6 +52,7 @@ #include "url/gurl.h" using content::BrowserContext; +using content::BrowserThread; using content::SiteInstance; using content::WebContents; @@ -71,6 +73,8 @@ namespace extensions { MessageService::PolicyPermission MessageService::IsNativeMessagingHostAllowed( const PrefService* pref_service, const std::string& native_host_name) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + PolicyPermission allow_result = ALLOW_ALL; if (pref_service->IsManagedPreference( pref_names::kNativeMessagingUserLevelHosts)) { @@ -190,6 +194,8 @@ content::RenderProcessHost* // static void MessageService::AllocatePortIdPair(int* port1, int* port2) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + unsigned channel_id = static_cast<unsigned>(g_next_channel_id.GetNext()) % (kint32max/2); unsigned port1_id = channel_id * 2; @@ -212,6 +218,8 @@ MessageService::MessageService(BrowserContext* context) : lazy_background_task_queue_( LazyBackgroundTaskQueue::Get(context)), weak_factory_(this) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, content::NotificationService::AllBrowserContextsAndSources()); registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, @@ -219,6 +227,8 @@ MessageService::MessageService(BrowserContext* context) } MessageService::~MessageService() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end()); channels_.clear(); } @@ -244,6 +254,8 @@ void MessageService::OpenChannelToExtension( const GURL& source_url, const std::string& channel_name, bool include_tls_channel_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + content::RenderProcessHost* source = content::RenderProcessHost::FromID(source_process_id); if (!source) @@ -399,6 +411,8 @@ void MessageService::OpenChannelToNativeApp( int receiver_port_id, const std::string& source_extension_id, const std::string& native_app_name) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + content::RenderProcessHost* source = content::RenderProcessHost::FromID(source_process_id); if (!source) @@ -477,6 +491,8 @@ void MessageService::OpenChannelToTab(int source_process_id, int frame_id, const std::string& extension_id, const std::string& channel_name) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + content::RenderProcessHost* source = content::RenderProcessHost::FromID(source_process_id); if (!source) @@ -516,8 +532,17 @@ void MessageService::OpenChannelToTab(int source_process_id, // frame's process can also receive the port. receiver_routing_id = MSG_ROUTING_CONTROL; } - receiver.reset(new ExtensionMessagePort( - contents->GetRenderProcessHost(), receiver_routing_id, extension_id)); + receiver.reset(new ExtensionMessagePort(contents->GetRenderProcessHost(), + receiver_routing_id, extension_id)); + + const Extension* extension = nullptr; + if (!extension_id.empty()) { + // Source extension == target extension so the extension must exist, or + // where did the IPC come from? + extension = ExtensionRegistry::Get(profile)->enabled_extensions().GetByID( + extension_id); + DCHECK(extension); + } scoped_ptr<OpenChannelParams> params(new OpenChannelParams( source_process_id, @@ -530,10 +555,17 @@ void MessageService::OpenChannelToTab(int source_process_id, channel_name, false, // Connections to tabs don't get TLS channel IDs. false)); // Connections to tabs aren't webview guests. - OpenChannelImpl(params.Pass()); + OpenChannelImpl(contents->GetBrowserContext(), params.Pass(), extension, + false /* did_enqueue */); } -void MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) { +void MessageService::OpenChannelImpl(BrowserContext* browser_context, + scoped_ptr<OpenChannelParams> params, + const Extension* target_extension, + bool did_enqueue) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_EQ(target_extension != nullptr, !params->target_extension_id.empty()); + content::RenderProcessHost* source = content::RenderProcessHost::FromID(params->source_process_id); if (!source) @@ -545,21 +577,12 @@ void MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) { return; } - // Add extra paranoid CHECKs, since we have crash reports of this being NULL. - // http://code.google.com/p/chromium/issues/detail?id=19067 - CHECK(params->receiver->GetRenderProcessHost()); - MessageChannel* channel(new MessageChannel); channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL, params->source_extension_id)); channel->receiver.reset(params->receiver.release()); - - CHECK(channel->receiver->GetRenderProcessHost()); - AddChannel(channel, params->receiver_port_id); - CHECK(channel->receiver->GetRenderProcessHost()); - int guest_process_id = content::ChildProcessHost::kInvalidUniqueID; int guest_render_frame_routing_id = MSG_ROUTING_NONE; if (params->include_guest_process_info) { @@ -577,17 +600,42 @@ void MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) { // Send the connect event to the receiver. Give it the opener's port ID (the // opener has the opposite port ID). - channel->receiver->DispatchOnConnect(params->receiver_port_id, - params->channel_name, - params->source_tab.Pass(), - params->source_frame_id, - params->target_frame_id, - guest_process_id, - guest_render_frame_routing_id, - params->source_extension_id, - params->target_extension_id, - params->source_url, - params->tls_channel_id); + channel->receiver->DispatchOnConnect( + params->receiver_port_id, params->channel_name, params->source_tab.Pass(), + params->source_frame_id, params->target_frame_id, guest_process_id, + guest_render_frame_routing_id, params->source_extension_id, + params->target_extension_id, params->source_url, params->tls_channel_id); + + // Report the event to the event router, if the target is an extension. + // + // First, determine what event this will be (runtime.onConnect vs + // runtime.onMessage etc), and what the event target is (view vs background + // page etc). + // + // Yes - even though this is opening a channel, they may actually be + // runtime.onRequest/onMessage events because those single-use events are + // built using the connect framework (see messaging.js). + // + // Likewise, if you're wondering about native messaging events, these are + // only initiated *by* the extension, so aren't really events, just the + // endpoint of a communication channel. + if (target_extension) { + events::HistogramValue histogram_value = events::UNKNOWN; + bool is_external = + params->source_extension_id != params->target_extension_id; + if (params->channel_name == "chrome.runtime.onRequest") { + histogram_value = is_external ? events::RUNTIME_ON_REQUEST_EXTERNAL + : events::RUNTIME_ON_REQUEST; + } else if (params->channel_name == "chrome.runtime.onMessage") { + histogram_value = is_external ? events::RUNTIME_ON_MESSAGE_EXTERNAL + : events::RUNTIME_ON_MESSAGE; + } else { + histogram_value = is_external ? events::RUNTIME_ON_CONNECT_EXTERNAL + : events::RUNTIME_ON_CONNECT; + } + EventRouter::Get(browser_context) + ->ReportEvent(histogram_value, target_extension, did_enqueue); + } // Keep both ends of the channel alive until the channel is closed. channel->opener->IncrementLazyKeepaliveCount(); @@ -595,6 +643,8 @@ void MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) { } void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + int channel_id = GET_CHANNEL_ID(receiver_port_id); CHECK(channels_.find(channel_id) == channels_.end()); channels_[channel_id] = channel; @@ -603,6 +653,8 @@ void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) { void MessageService::CloseChannel(int port_id, const std::string& error_message) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + // Note: The channel might be gone already, if the other side closed first. int channel_id = GET_CHANNEL_ID(port_id); MessageChannelMap::iterator it = channels_.find(channel_id); @@ -625,6 +677,8 @@ void MessageService::CloseChannelImpl( int closing_port_id, const std::string& error_message, bool notify_other_port) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + MessageChannel* channel = channel_iter->second; // Notify the other side. @@ -644,6 +698,8 @@ void MessageService::CloseChannelImpl( } void MessageService::PostMessage(int source_port_id, const Message& message) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + int channel_id = GET_CHANNEL_ID(source_port_id); MessageChannelMap::iterator iter = channels_.find(channel_id); if (iter == channels_.end()) { @@ -659,6 +715,8 @@ void MessageService::PostMessage(int source_port_id, const Message& message) { void MessageService::Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + switch (type) { case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { @@ -674,8 +732,10 @@ void MessageService::Observe(int type, } void MessageService::OnProcessClosed(content::RenderProcessHost* process) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + // Close any channels that share this renderer. We notify the opposite - // port that his pair has closed. + // port that its pair has closed. for (MessageChannelMap::iterator it = channels_.begin(); it != channels_.end(); ) { MessageChannelMap::iterator current = it++; @@ -702,6 +762,8 @@ void MessageService::OnProcessClosed(content::RenderProcessHost* process) { void MessageService::EnqueuePendingMessage(int source_port_id, int channel_id, const Message& message) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + PendingChannelMap::iterator pending_for_incognito = pending_incognito_channels_.find(channel_id); if (pending_for_incognito != pending_incognito_channels_.end()) { @@ -732,6 +794,8 @@ void MessageService::EnqueuePendingMessageForLazyBackgroundLoad( int source_port_id, int channel_id, const Message& message) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + PendingLazyBackgroundPageChannelMap::iterator pending = pending_lazy_background_page_channels_.find(channel_id); if (pending != pending_lazy_background_page_channels_.end()) { @@ -745,6 +809,8 @@ void MessageService::EnqueuePendingMessageForLazyBackgroundLoad( void MessageService::DispatchMessage(int source_port_id, MessageChannel* channel, const Message& message) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + // Figure out which port the ID corresponds to. int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id); MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ? @@ -758,6 +824,8 @@ bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask( const Extension* extension, scoped_ptr<OpenChannelParams>* params, const PendingMessagesQueue& pending_messages) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (!BackgroundInfo::HasLazyBackgroundPage(extension)) return false; @@ -788,6 +856,8 @@ bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask( void MessageService::OnOpenChannelAllowed(scoped_ptr<OpenChannelParams> params, bool allowed) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + int channel_id = GET_CHANNEL_ID(params->receiver_port_id); PendingChannelMap::iterator pending_for_incognito = @@ -852,13 +922,16 @@ void MessageService::OnOpenChannelAllowed(scoped_ptr<OpenChannelParams> params, // page. if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask( context, target_extension, ¶ms, pending_messages)) { - OpenChannelImpl(params.Pass()); + OpenChannelImpl(context, params.Pass(), target_extension, + false /* did_enqueue */); DispatchPendingMessages(pending_messages, channel_id); } } void MessageService::GotChannelID(scoped_ptr<OpenChannelParams> params, const std::string& tls_channel_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + params->tls_channel_id.assign(tls_channel_id); int channel_id = GET_CHANNEL_ID(params->receiver_port_id); @@ -891,7 +964,8 @@ void MessageService::GotChannelID(scoped_ptr<OpenChannelParams> params, if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask( context, target_extension, ¶ms, pending_messages)) { - OpenChannelImpl(params.Pass()); + OpenChannelImpl(context, params.Pass(), target_extension, + false /* did_enqueue */); DispatchPendingMessages(pending_messages, channel_id); } } @@ -900,24 +974,31 @@ void MessageService::PendingLazyBackgroundPageOpenChannel( scoped_ptr<OpenChannelParams> params, int source_process_id, ExtensionHost* host) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (!host) return; // TODO(mpcomplete): notify source of disconnect? params->receiver.reset(new ExtensionMessagePort(host->render_process_host(), MSG_ROUTING_CONTROL, params->target_extension_id)); - OpenChannelImpl(params.Pass()); + OpenChannelImpl(host->browser_context(), params.Pass(), host->extension(), + true /* did_enqueue */); } void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source, int port_id, const std::string& error_message) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, ""); port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message); } void MessageService::DispatchPendingMessages(const PendingMessagesQueue& queue, int channel_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + MessageChannelMap::iterator channel_iter = channels_.find(channel_id); if (channel_iter != channels_.end()) { for (const PendingMessage& message : queue) { diff --git a/chrome/browser/extensions/api/messaging/message_service.h b/chrome/browser/extensions/api/messaging/message_service.h index e68b19e..9d209b2 100644 --- a/chrome/browser/extensions/api/messaging/message_service.h +++ b/chrome/browser/extensions/api/messaging/message_service.h @@ -186,8 +186,17 @@ class MessageService : public BrowserContextKeyedAPI, typedef std::map<int, PendingLazyBackgroundPageChannel> PendingLazyBackgroundPageChannelMap; - // Common among OpenChannel* variants. - void OpenChannelImpl(scoped_ptr<OpenChannelParams> params); + // Common implementation for opening a channel configured by |params|. + // + // |target_extension| will be non-null if |params->target_extension_id| is + // non-empty, that is, if the target is an extension, it must exist. + // + // |did_enqueue| will be true if the channel opening was delayed while + // waiting for an event page to start, false otherwise. + void OpenChannelImpl(content::BrowserContext* browser_context, + scoped_ptr<OpenChannelParams> params, + const Extension* target_extension, + bool did_enqueue); void CloseChannelImpl(MessageChannelMap::iterator channel_iter, int port_id, diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc index b239c63..97c39d0 100644 --- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc +++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc @@ -227,12 +227,14 @@ TEST_F(ExtensionWebRequestTest, BlockingEventPrecedenceRedirect) { const std::string kEventName(web_request::OnBeforeRequest::kEventName); base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_); ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( - &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1", - filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0, + &profile_, extension1_id, extension1_id, events::FOR_TEST, kEventName, + kEventName + "/1", filter, + ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0, ipc_sender_factory.GetWeakPtr()); ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( - &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2", - filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0, + &profile_, extension2_id, extension2_id, events::FOR_TEST, kEventName, + kEventName + "/2", filter, + ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0, ipc_sender_factory.GetWeakPtr()); net::URLRequestJobFactoryImpl job_factory; @@ -363,13 +365,15 @@ TEST_F(ExtensionWebRequestTest, BlockingEventPrecedenceCancel) { const std::string kEventName(web_request::OnBeforeRequest::kEventName); base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_); ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( - &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1", - filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0, - ipc_sender_factory.GetWeakPtr()); + &profile_, extension1_id, extension1_id, events::FOR_TEST, kEventName, + kEventName + "/1", filter, + ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0, + ipc_sender_factory.GetWeakPtr()); ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( - &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2", - filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0, - ipc_sender_factory.GetWeakPtr()); + &profile_, extension2_id, extension2_id, events::FOR_TEST, kEventName, + kEventName + "/2", filter, + ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0, + ipc_sender_factory.GetWeakPtr()); GURL request_url("about:blank"); scoped_ptr<net::URLRequest> request(context_->CreateRequest( @@ -432,12 +436,13 @@ TEST_F(ExtensionWebRequestTest, SimulateChancelWhileBlocked) { const std::string kEventName2(web_request::OnErrorOccurred::kEventName); base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_); ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( - &profile_, extension_id, extension_id, kEventName, kEventName + "/1", - filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0, - ipc_sender_factory.GetWeakPtr()); + &profile_, extension_id, extension_id, events::FOR_TEST, kEventName, + kEventName + "/1", filter, + ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0, + ipc_sender_factory.GetWeakPtr()); ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( - &profile_, extension_id, extension_id, kEventName2, kEventName2 + "/1", - filter, 0, 0, 0, ipc_sender_factory.GetWeakPtr()); + &profile_, extension_id, extension_id, events::FOR_TEST, kEventName2, + kEventName2 + "/1", filter, 0, 0, 0, ipc_sender_factory.GetWeakPtr()); GURL request_url("about:blank"); scoped_ptr<net::URLRequest> request(context_->CreateRequest( @@ -632,8 +637,9 @@ TEST_F(ExtensionWebRequestTest, AccessRequestBodyData) { // Subscribe to OnBeforeRequest with requestBody requirement. ASSERT_TRUE(GenerateInfoSpec(string_spec_post, &extra_info_spec_body)); ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( - &profile_, extension_id, extension_id, kEventName, kEventName + "/1", - filter, extra_info_spec_body, 0, 0, ipc_sender_factory.GetWeakPtr()); + &profile_, extension_id, extension_id, events::FOR_TEST, kEventName, + kEventName + "/1", filter, extra_info_spec_body, 0, 0, + ipc_sender_factory.GetWeakPtr()); FireURLRequestWithData(kMethodPost, kMultipart, form_1, form_2); @@ -648,8 +654,9 @@ TEST_F(ExtensionWebRequestTest, AccessRequestBodyData) { ASSERT_TRUE( GenerateInfoSpec(string_spec_no_post, &extra_info_spec_empty)); ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( - &profile_, extension_id, extension_id, kEventName, kEventName + "/1", - filter, extra_info_spec_empty, 0, 0, ipc_sender_factory.GetWeakPtr()); + &profile_, extension_id, extension_id, events::FOR_TEST, kEventName, + kEventName + "/1", filter, extra_info_spec_empty, 0, 0, + ipc_sender_factory.GetWeakPtr()); FireURLRequestWithData(kMethodPost, kMultipart, form_1, form_2); @@ -658,8 +665,9 @@ TEST_F(ExtensionWebRequestTest, AccessRequestBodyData) { // Subscribe to OnBeforeRequest with requestBody requirement. ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( - &profile_, extension_id, extension_id, kEventName, kEventName + "/1", - filter, extra_info_spec_body, 0, 0, ipc_sender_factory.GetWeakPtr()); + &profile_, extension_id, extension_id, events::FOR_TEST, kEventName, + kEventName + "/1", filter, extra_info_spec_body, 0, 0, + ipc_sender_factory.GetWeakPtr()); // Part 3. // Now send a POST request with body which is not parseable as a form. @@ -716,8 +724,9 @@ TEST_F(ExtensionWebRequestTest, NoAccessRequestBodyData) { // Subscribe to OnBeforeRequest with requestBody requirement. ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( - &profile_, extension_id, extension_id, kEventName, kEventName + "/1", - filter, extra_info_spec, 0, 0, ipc_sender_factory.GetWeakPtr()); + &profile_, extension_id, extension_id, events::FOR_TEST, kEventName, + kEventName + "/1", filter, extra_info_spec, 0, 0, + ipc_sender_factory.GetWeakPtr()); // The request URL can be arbitrary but must have an HTTP or HTTPS scheme. const GURL request_url("http://www.example.com"); @@ -828,20 +837,22 @@ TEST_P(ExtensionWebRequestHeaderModificationTest, TestModifications) { // Install two extensions that can modify headers. Extension 2 has // higher precedence than extension 1. ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( - &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1", - filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0, + &profile_, extension1_id, extension1_id, events::FOR_TEST, kEventName, + kEventName + "/1", filter, + ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0, ipc_sender_factory.GetWeakPtr()); ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( - &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2", - filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0, + &profile_, extension2_id, extension2_id, events::FOR_TEST, kEventName, + kEventName + "/2", filter, + ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0, ipc_sender_factory.GetWeakPtr()); // Install one extension that observes the final headers. ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( - &profile_, extension3_id, extension3_id, keys::kOnSendHeadersEvent, - std::string(keys::kOnSendHeadersEvent) + "/3", filter, - ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS, 0, 0, - ipc_sender_factory.GetWeakPtr()); + &profile_, extension3_id, extension3_id, events::FOR_TEST, + keys::kOnSendHeadersEvent, std::string(keys::kOnSendHeadersEvent) + "/3", + filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS, 0, + 0, ipc_sender_factory.GetWeakPtr()); GURL request_url("http://doesnotexist/does_not_exist.html"); scoped_ptr<net::URLRequest> request(context_->CreateRequest( diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc index 04a2bed..6af3476 100644 --- a/extensions/browser/api/web_request/web_request_api.cc +++ b/extensions/browser/api/web_request/web_request_api.cc @@ -10,6 +10,7 @@ #include "base/bind_helpers.h" #include "base/json/json_writer.h" #include "base/lazy_instance.h" +#include "base/macros.h" #include "base/metrics/histogram.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" @@ -38,6 +39,7 @@ #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" #include "extensions/browser/extensions_browser_client.h" +#include "extensions/browser/guest_view/guest_view_events.h" #include "extensions/browser/guest_view/web_view/web_view_constants.h" #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h" #include "extensions/browser/info_map.h" @@ -96,8 +98,6 @@ const char* const kWebRequestEvents[] = { keys::kOnHeadersReceivedEvent, }; -const size_t kWebRequestEventsLength = arraysize(kWebRequestEvents); - const char* GetRequestStageAsString( ExtensionWebRequestEventRouter::EventTypes type) { switch (type) { @@ -138,10 +138,10 @@ bool IsWebRequestEvent(const std::string& event_name) { web_request_event_name.replace( 0, strlen(webview::kWebViewEventPrefix), kWebRequestEventPrefix); } - return std::find( - kWebRequestEvents, - kWebRequestEvents + kWebRequestEventsLength, - web_request_event_name) != (kWebRequestEvents + kWebRequestEventsLength); + auto web_request_events_end = + kWebRequestEvents + arraysize(kWebRequestEvents); + return std::find(kWebRequestEvents, web_request_events_end, + web_request_event_name) != web_request_events_end; } // Returns whether |request| has been triggered by an extension in @@ -372,6 +372,44 @@ void RemoveEventListenerOnIOThread( embedder_process_id, web_view_instance_id); } +events::HistogramValue GetEventHistogramValue(const std::string& event_name) { + // Event names will either be webRequest events, or guest view (probably web + // view) events that map to webRequest events. Check webRequest first. + static struct ValueAndName { + events::HistogramValue histogram_value; + const char* event_name; + } values_and_names[] = { + {events::WEB_REQUEST_ON_BEFORE_REDIRECT, keys::kOnBeforeRedirectEvent}, + {events::WEB_REQUEST_ON_BEFORE_REQUEST, + web_request::OnBeforeRequest::kEventName}, + {events::WEB_REQUEST_ON_BEFORE_SEND_HEADERS, + keys::kOnBeforeSendHeadersEvent}, + {events::WEB_REQUEST_ON_COMPLETED, keys::kOnCompletedEvent}, + {events::WEB_REQUEST_ON_ERROR_OCCURRED, + web_request::OnErrorOccurred::kEventName}, + {events::WEB_REQUEST_ON_SEND_HEADERS, keys::kOnSendHeadersEvent}, + {events::WEB_REQUEST_ON_AUTH_REQUIRED, keys::kOnAuthRequiredEvent}, + {events::WEB_REQUEST_ON_RESPONSE_STARTED, keys::kOnResponseStartedEvent}, + {events::WEB_REQUEST_ON_HEADERS_RECEIVED, keys::kOnHeadersReceivedEvent}}; + COMPILE_ASSERT(arraysize(kWebRequestEvents) == arraysize(values_and_names), + "kWebRequestEvents and values_and_names must be the same"); + for (const ValueAndName& value_and_name : values_and_names) { + if (value_and_name.event_name == event_name) + return value_and_name.histogram_value; + } + + // If there is no webRequest event, it might be a guest view webRequest event. + events::HistogramValue guest_view_histogram_value = + guest_view_events::GetEventHistogramValue(event_name); + if (guest_view_histogram_value != events::UNKNOWN) + return guest_view_histogram_value; + + // There is no histogram value for this event name. It should be added to + // either the mapping here, or in guest_view_events. + NOTREACHED() << "Event " << event_name << " must have a histogram value"; + return events::UNKNOWN; +}; + } // namespace WebRequestAPI::WebRequestAPI(content::BrowserContext* context) @@ -429,6 +467,7 @@ void WebRequestAPI::OnListenerRemoved(const EventListenerInfo& details) { struct ExtensionWebRequestEventRouter::EventListener { std::string extension_id; std::string extension_name; + events::HistogramValue histogram_value; std::string sub_event_name; RequestFilter filter; int extra_info_spec; @@ -463,10 +502,11 @@ struct ExtensionWebRequestEventRouter::EventListener { return false; } - EventListener() : - extra_info_spec(0), - embedder_process_id(0), - web_view_instance_id(0) {} + EventListener() + : histogram_value(events::UNKNOWN), + extra_info_spec(0), + embedder_process_id(0), + web_view_instance_id(0) {} }; // Contains info about requests that are blocked waiting for a response from @@ -1194,30 +1234,30 @@ bool ExtensionWebRequestEventRouter::DispatchEvent( // TODO(mpcomplete): Consider consolidating common (extension_id,json_args) // pairs into a single message sent to a list of sub_event_names. int num_handlers_blocking = 0; - for (std::vector<const EventListener*>::const_iterator it = listeners.begin(); - it != listeners.end(); ++it) { + for (const EventListener* listener : listeners) { // Filter out the optional keys that this listener didn't request. scoped_ptr<base::ListValue> args_filtered(args.DeepCopy()); base::DictionaryValue* dict = NULL; CHECK(args_filtered->GetDictionary(0, &dict) && dict); - if (!((*it)->extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)) + if (!(listener->extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)) dict->Remove(keys::kRequestHeadersKey, NULL); - if (!((*it)->extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS)) + if (!(listener->extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS)) dict->Remove(keys::kResponseHeadersKey, NULL); - EventRouter::DispatchEvent( - (*it)->ipc_sender.get(), browser_context, (*it)->extension_id, - (*it)->sub_event_name, args_filtered.Pass(), - EventRouter::USER_GESTURE_UNKNOWN, EventFilteringInfo()); - if ((*it)->extra_info_spec & + EventRouter::DispatchEventToSender( + listener->ipc_sender.get(), browser_context, listener->extension_id, + listener->histogram_value, listener->sub_event_name, + args_filtered.Pass(), EventRouter::USER_GESTURE_UNKNOWN, + EventFilteringInfo()); + if (listener->extra_info_spec & (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) { - (*it)->blocked_requests.insert(request->identifier()); + listener->blocked_requests.insert(request->identifier()); // If this is the first delegate blocking the request, go ahead and log // it. if (num_handlers_blocking == 0) { - std::string delegate_info = - l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION, - base::UTF8ToUTF16((*it)->extension_name)); + std::string delegate_info = l10n_util::GetStringFUTF8( + IDS_LOAD_STATE_PARAMETER_EXTENSION, + base::UTF8ToUTF16(listener->extension_name)); // LobAndReport allows extensions that block requests to be displayed in // the load status bar. request->LogAndReportBlockedBy(delegate_info.c_str()); @@ -1268,6 +1308,7 @@ bool ExtensionWebRequestEventRouter::AddEventListener( void* browser_context, const std::string& extension_id, const std::string& extension_name, + events::HistogramValue histogram_value, const std::string& event_name, const std::string& sub_event_name, const RequestFilter& filter, @@ -1281,6 +1322,7 @@ bool ExtensionWebRequestEventRouter::AddEventListener( EventListener listener; listener.extension_id = extension_id; listener.extension_name = extension_name; + listener.histogram_value = histogram_value; listener.sub_event_name = sub_event_name; listener.filter = filter; listener.extra_info_spec = extra_info_spec; @@ -2244,8 +2286,9 @@ bool WebRequestInternalAddEventListenerFunction::RunSync() { bool success = ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( profile_id(), extension_id_safe(), extension_name, - event_name, sub_event_name, filter, extra_info_spec, - embedder_process_id, web_view_instance_id, ipc_sender_weak()); + GetEventHistogramValue(event_name), event_name, sub_event_name, + filter, extra_info_spec, embedder_process_id, web_view_instance_id, + ipc_sender_weak()); EXTENSION_FUNCTION_VALIDATE(success); helpers::ClearCacheOnNavigation(); diff --git a/extensions/browser/api/web_request/web_request_api.h b/extensions/browser/api/web_request/web_request_api.h index 49bed01..06ffbff 100644 --- a/extensions/browser/api/web_request/web_request_api.h +++ b/extensions/browser/api/web_request/web_request_api.h @@ -271,17 +271,17 @@ class ExtensionWebRequestEventRouter // listened to. |sub_event_name| is an internal event uniquely generated in // the extension process to correspond to the given filter and // extra_info_spec. It returns true on success, false on failure. - bool AddEventListener( - void* browser_context, - const std::string& extension_id, - const std::string& extension_name, - const std::string& event_name, - const std::string& sub_event_name, - const RequestFilter& filter, - int extra_info_spec, - int embedder_process_id, - int web_view_instance_id, - base::WeakPtr<IPC::Sender> ipc_sender); + bool AddEventListener(void* browser_context, + const std::string& extension_id, + const std::string& extension_name, + events::HistogramValue histogram_value, + const std::string& event_name, + const std::string& sub_event_name, + const RequestFilter& filter, + int extra_info_spec, + int embedder_process_id, + int web_view_instance_id, + base::WeakPtr<IPC::Sender> ipc_sender); // Removes the listener for the given sub-event. void RemoveEventListener( diff --git a/extensions/browser/event_router.cc b/extensions/browser/event_router.cc index e70d02b..c483f45 100644 --- a/extensions/browser/event_router.cc +++ b/extensions/browser/event_router.cc @@ -26,6 +26,7 @@ #include "extensions/browser/notification_types.h" #include "extensions/browser/process_manager.h" #include "extensions/browser/process_map.h" +#include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "extensions/common/extension_api.h" #include "extensions/common/extension_messages.h" @@ -147,25 +148,28 @@ std::string EventRouter::GetBaseEventName(const std::string& full_event_name) { } // static -void EventRouter::DispatchEvent(IPC::Sender* ipc_sender, - void* browser_context_id, - const std::string& extension_id, - const std::string& event_name, - scoped_ptr<ListValue> event_args, - UserGestureState user_gesture, - const EventFilteringInfo& info) { +void EventRouter::DispatchEventToSender(IPC::Sender* ipc_sender, + void* browser_context_id, + const std::string& extension_id, + events::HistogramValue histogram_value, + const std::string& event_name, + scoped_ptr<ListValue> event_args, + UserGestureState user_gesture, + const EventFilteringInfo& info) { int event_id = g_extension_event_id.GetNext(); - if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { + if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { + DoDispatchEventToSenderBookkeepingOnUI(browser_context_id, extension_id, + event_id, histogram_value, + event_name); + } else { // This is called from WebRequest API. // TODO(lazyboy): Skip this entirely: http://crbug.com/488747. BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, - base::Bind(&EventRouter::IncrementInFlightEventsOnUI, - browser_context_id, extension_id, event_id, event_name)); - } else { - IncrementInFlightEventsOnUI(browser_context_id, extension_id, event_id, - event_name); + base::Bind(&EventRouter::DoDispatchEventToSenderBookkeepingOnUI, + browser_context_id, extension_id, event_id, histogram_value, + event_name)); } DispatchExtensionMessage(ipc_sender, browser_context_id, extension_id, @@ -500,9 +504,7 @@ void EventRouter::DispatchEventImpl(const std::string& restrict_to_extension_id, // background page, and as that event needs to be delivered before we dispatch // the event we are dispatching here, we dispatch to the lazy listeners here // first. - for (std::set<const EventListener*>::iterator it = listeners.begin(); - it != listeners.end(); it++) { - const EventListener* listener = *it; + for (const EventListener* listener : listeners) { if (restrict_to_extension_id.empty() || restrict_to_extension_id == listener->extension_id()) { if (listener->IsLazy()) { @@ -512,9 +514,7 @@ void EventRouter::DispatchEventImpl(const std::string& restrict_to_extension_id, } } - for (std::set<const EventListener*>::iterator it = listeners.begin(); - it != listeners.end(); it++) { - const EventListener* listener = *it; + for (const EventListener* listener : listeners) { if (restrict_to_extension_id.empty() || restrict_to_extension_id == listener->extension_id()) { if (listener->process()) { @@ -523,7 +523,8 @@ void EventRouter::DispatchEventImpl(const std::string& restrict_to_extension_id, if (!ContainsKey(already_dispatched, dispatch_id)) { DispatchEventToProcess(listener->extension_id(), listener->listener_url(), listener->process(), - event, listener->filter()); + event, listener->filter(), + false /* did_enqueue */); } } } @@ -567,7 +568,8 @@ void EventRouter::DispatchEventToProcess( const GURL& listener_url, content::RenderProcessHost* process, const linked_ptr<Event>& event, - const base::DictionaryValue* listener_filter) { + const base::DictionaryValue* listener_filter, + bool did_enqueue) { BrowserContext* listener_context = process->GetBrowserContext(); ProcessMap* process_map = ProcessMap::Get(listener_context); @@ -637,6 +639,7 @@ void EventRouter::DispatchEventToProcess( event->user_gesture, event->filter_info); if (extension) { + ReportEvent(event->histogram_value, extension, did_enqueue); IncrementInFlightEvents(listener_context, extension, event_id, event->event_name); } @@ -693,25 +696,27 @@ bool EventRouter::MaybeLoadLazyBackgroundPageToDispatchEvent( } // static -void EventRouter::IncrementInFlightEventsOnUI(void* browser_context_id, - const std::string& extension_id, - int event_id, - const std::string& event_name) { +void EventRouter::DoDispatchEventToSenderBookkeepingOnUI( + void* browser_context_id, + const std::string& extension_id, + int event_id, + events::HistogramValue histogram_value, + const std::string& event_name) { DCHECK_CURRENTLY_ON(BrowserThread::UI); BrowserContext* browser_context = reinterpret_cast<BrowserContext*>(browser_context_id); if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context)) return; - EventRouter* event_router = EventRouter::Get(browser_context); - if (!event_router) - return; const Extension* extension = ExtensionRegistry::Get(browser_context)->enabled_extensions().GetByID( extension_id); if (!extension) return; + EventRouter* event_router = EventRouter::Get(browser_context); event_router->IncrementInFlightEvents(browser_context, extension, event_id, event_name); + event_router->ReportEvent(histogram_value, extension, + false /* did_enqueue */); } void EventRouter::IncrementInFlightEvents(BrowserContext* context, @@ -747,6 +752,35 @@ void EventRouter::OnEventAck(BrowserContext* context, pm->DecrementLazyKeepaliveCount(host->extension()); } +void EventRouter::ReportEvent(events::HistogramValue histogram_value, + const Extension* extension, + bool did_enqueue) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + // TODO(kalman): UMA for dispatched event. + // TODO(kalman): UMA specifically for component extensions. + + // Note: for these, all we know is that the extension *has* a persistent or + // event page, not that the event is being dispatched *to* such a page. + // + // However, this is an academic distinction, since extensions with any + // background page have that background page running (or in the case of + // dormant event pages, must be started) regardless of where the event is + // being dispatched. Events are dispatched to a *process* not a *frame*. + if (BackgroundInfo::HasPersistentBackgroundPage(extension)) { + // TODO(kalman): UMA for dispatched event to an extension with a persistent + // background page. + } else if (BackgroundInfo::HasLazyBackgroundPage(extension)) { + if (did_enqueue) { + // TODO(kalman): UMA for dispatched event to an extension with an event + // page, and the event page was woken up to do so. + } else { + // TODO(kalman): UMA for dispatched event to an extension with an event + // page that was already running. + } + } +} + void EventRouter::DispatchPendingEvent(const linked_ptr<Event>& event, ExtensionHost* host) { if (!host) @@ -754,9 +788,9 @@ void EventRouter::DispatchPendingEvent(const linked_ptr<Event>& event, if (listeners_.HasProcessListener(host->render_process_host(), host->extension()->id())) { - // URL events cannot be lazy therefore can't be pending, hence the GURL(). - DispatchEventToProcess(host->extension()->id(), GURL(), - host->render_process_host(), event, nullptr); + DispatchEventToProcess(host->extension()->id(), host->GetURL(), + host->render_process_host(), event, nullptr, + true /* did_enqueue */); } } diff --git a/extensions/browser/event_router.h b/extensions/browser/event_router.h index 767dcbc..e7b6499 100644 --- a/extensions/browser/event_router.h +++ b/extensions/browser/event_router.h @@ -26,6 +26,7 @@ #include "extensions/browser/extension_registry_observer.h" #include "extensions/common/event_filtering_info.h" #include "ipc/ipc_sender.h" +#include "url/gurl.h" class GURL; class PrefService; @@ -85,13 +86,17 @@ class EventRouter : public KeyedService, // Sends an event via ipc_sender to the given extension. Can be called on any // thread. - static void DispatchEvent(IPC::Sender* ipc_sender, - void* browser_context_id, - const std::string& extension_id, - const std::string& event_name, - scoped_ptr<base::ListValue> event_args, - UserGestureState user_gesture, - const EventFilteringInfo& info); + // + // It is very rare to call this function directly. Instead use the instance + // methods BroadcastEvent or DispatchEventToExtension. + static void DispatchEventToSender(IPC::Sender* ipc_sender, + void* browser_context_id, + const std::string& extension_id, + events::HistogramValue histogram_value, + const std::string& event_name, + scoped_ptr<base::ListValue> event_args, + UserGestureState user_gesture, + const EventFilteringInfo& info); // An EventRouter is shared between |browser_context| and its associated // incognito context. |extension_prefs| may be NULL in tests. @@ -185,6 +190,15 @@ class EventRouter : public KeyedService, void OnEventAck(content::BrowserContext* context, const std::string& extension_id); + // Reports UMA for an event dispatched to |extension| with histogram value + // |histogram_value|. Must be called on the UI thread. + // + // |did_enqueue| should be true if the event was queued waiting for a process + // to start, like an event page. + void ReportEvent(events::HistogramValue histogram_value, + const Extension* extension, + bool did_enqueue); + private: friend class EventRouterTest; @@ -229,9 +243,9 @@ class EventRouter : public KeyedService, const std::string& extension_id, const std::string& event_name); - // Shared by DispatchEvent*. If |restrict_to_extension_id| is empty, the - // event is broadcast. - // An event that just came off the pending list may not be delayed again. + // Shared by all event dispatch methods. If |restrict_to_extension_id| is + // empty, the event is broadcast. An event that just came off the pending + // list may not be delayed again. void DispatchEventImpl(const std::string& restrict_to_extension_id, const linked_ptr<Event>& event); @@ -250,7 +264,8 @@ class EventRouter : public KeyedService, const GURL& listener_url, content::RenderProcessHost* process, const linked_ptr<Event>& event, - const base::DictionaryValue* listener_filter); + const base::DictionaryValue* listener_filter, + bool did_enqueue); // Returns false when the event is scoped to a context and the listening // extension does not have access to events from that context. Also fills @@ -292,10 +307,12 @@ class EventRouter : public KeyedService, const std::string& event_name); // static - static void IncrementInFlightEventsOnUI(void* browser_context_id, - const std::string& extension_id, - int event_id, - const std::string& event_name); + static void DoDispatchEventToSenderBookkeepingOnUI( + void* browser_context_id, + const std::string& extension_id, + int event_id, + events::HistogramValue histogram_value, + const std::string& event_name); void DispatchPendingEvent(const linked_ptr<Event>& event, ExtensionHost* host); diff --git a/extensions/browser/extension_event_histogram_value.h b/extensions/browser/extension_event_histogram_value.h index 92054c0..03bd28c 100644 --- a/extensions/browser/extension_event_histogram_value.h +++ b/extensions/browser/extension_event_histogram_value.h @@ -362,8 +362,39 @@ enum HistogramValue { SCREENLOCK_PRIVATE_ON_AUTH_ATTEMPTED, TYPES_CHROME_SETTING_ON_CHANGE, TYPES_PRIVATE_CHROME_DIRECT_SETTING_ON_CHANGE, - WEB_VIEW_INTERNAL_ON_MESSAGE, // TODO(kalman): where are the rest of the - // webview events? + WEB_VIEW_INTERNAL_ON_MESSAGE, + EXTENSION_VIEW_INTERNAL_ON_LOAD_COMMIT, + RUNTIME_ON_REQUEST, + RUNTIME_ON_REQUEST_EXTERNAL, + CHROME_WEB_VIEW_INTERNAL_ON_CONTEXT_MENU_SHOW, + WEB_VIEW_INTERNAL_ON_BEFORE_REQUEST, + WEB_VIEW_INTERNAL_ON_BEFORE_SEND_HEADERS, + WEB_VIEW_INTERNAL_ON_CLOSE, + WEB_VIEW_INTERNAL_ON_COMPLETED, + WEB_VIEW_INTERNAL_ON_CONSOLE_MESSAGE, + WEB_VIEW_INTERNAL_ON_CONTENT_LOAD, + WEB_VIEW_INTERNAL_ON_DIALOG, + WEB_VIEW_INTERNAL_ON_DROP_LINK, + WEB_VIEW_INTERNAL_ON_EXIT, + WEB_VIEW_INTERNAL_ON_EXIT_FULLSCREEN, + WEB_VIEW_INTERNAL_ON_FIND_REPLY, + WEB_VIEW_INTERNAL_ON_FRAME_NAME_CHANGED, + WEB_VIEW_INTERNAL_ON_HEADERS_RECEIVED, + WEB_VIEW_INTERNAL_ON_LOAD_ABORT, + WEB_VIEW_INTERNAL_ON_LOAD_COMMIT, + WEB_VIEW_INTERNAL_ON_LOAD_PROGRESS, + WEB_VIEW_INTERNAL_ON_LOAD_REDIRECT, + WEB_VIEW_INTERNAL_ON_LOAD_START, + WEB_VIEW_INTERNAL_ON_LOAD_STOP, + WEB_VIEW_INTERNAL_ON_NEW_WINDOW, + WEB_VIEW_INTERNAL_ON_PERMISSION_REQUEST, + WEB_VIEW_INTERNAL_ON_RESPONSE_STARTED, + WEB_VIEW_INTERNAL_ON_RESPONSIVE, + WEB_VIEW_INTERNAL_ON_SIZE_CHANGED, + WEB_VIEW_INTERNAL_ON_UNRESPONSIVE, + WEB_VIEW_INTERNAL_ON_ZOOM_CHANGE, + GUEST_VIEW_INTERNAL_ON_RESIZE, + // Last entry: Add new entries above, then run: // python tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY diff --git a/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc b/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc index c76988f..ac15622 100644 --- a/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc +++ b/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc @@ -6,6 +6,7 @@ #include "components/guest_view/browser/guest_view_base.h" #include "components/guest_view/browser/guest_view_manager.h" +#include "components/guest_view/common/guest_view_constants.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/render_process_host.h" #include "extensions/browser/api/extensions_api_client.h" @@ -13,6 +14,7 @@ #include "extensions/browser/guest_view/app_view/app_view_guest.h" #include "extensions/browser/guest_view/extension_options/extension_options_guest.h" #include "extensions/browser/guest_view/extension_view/extension_view_guest.h" +#include "extensions/browser/guest_view/guest_view_events.h" #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h" #include "extensions/browser/guest_view/surface_worker/surface_worker_guest.h" #include "extensions/browser/guest_view/web_view/web_view_guest.h" @@ -44,14 +46,19 @@ void ExtensionsGuestViewManagerDelegate::DispatchEvent( scoped_ptr<base::ListValue> event_args(new base::ListValue()); event_args->Append(args.release()); - EventRouter::DispatchEvent( - guest->owner_web_contents(), - guest->browser_context(), - guest->owner_host(), - event_name, - event_args.Pass(), - EventRouter::USER_GESTURE_UNKNOWN, - info); + // GetEventHistogramValue maps guest view event names to their histogram + // value. It needs to be like this because the guest view component doesn't + // know about extensions, so GuestViewEvent can't have an + // extensions::events::HistogramValue as an argument. + events::HistogramValue histogram_value = + guest_view_events::GetEventHistogramValue(event_name); + DCHECK_NE(events::UNKNOWN, histogram_value) << "Event " << event_name + << " must have a histogram value"; + + content::WebContents* owner = guest->owner_web_contents(); + EventRouter::DispatchEventToSender( + owner, guest->browser_context(), guest->owner_host(), histogram_value, + event_name, event_args.Pass(), EventRouter::USER_GESTURE_UNKNOWN, info); } bool ExtensionsGuestViewManagerDelegate::IsGuestAvailableToContext( diff --git a/extensions/browser/guest_view/guest_view_events.cc b/extensions/browser/guest_view/guest_view_events.cc new file mode 100644 index 0000000..843083b --- /dev/null +++ b/extensions/browser/guest_view/guest_view_events.cc @@ -0,0 +1,102 @@ +// Copyright 2015 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 "extensions/browser/guest_view/guest_view_events.h" + +#include <map> + +#include "base/lazy_instance.h" +#include "components/guest_view/common/guest_view_constants.h" +#include "extensions/browser/guest_view/extension_options/extension_options_constants.h" +#include "extensions/browser/guest_view/extension_view/extension_view_constants.h" +#include "extensions/browser/guest_view/web_view/web_view_constants.h" +#include "extensions/common/api/extension_options_internal.h" + +namespace extensions { +namespace guest_view_events { + +namespace { + +class EventMap { + public: + EventMap() { + struct NameAndValue { + const char* name; + events::HistogramValue value; + } names_and_values[] = { + {webview::kEventContextMenuShow, + events::CHROME_WEB_VIEW_INTERNAL_ON_CONTEXT_MENU_SHOW}, + {api::extension_options_internal::OnClose::kEventName, + events::EXTENSION_OPTIONS_INTERNAL_ON_CLOSE}, + {api::extension_options_internal::OnLoad::kEventName, + events::EXTENSION_OPTIONS_INTERNAL_ON_LOAD}, + {api::extension_options_internal::OnPreferredSizeChanged::kEventName, + events::EXTENSION_OPTIONS_INTERNAL_ON_PREFERRED_SIZE_CHANGED}, + {extensionview::kEventLoadCommit, + events::EXTENSION_VIEW_INTERNAL_ON_LOAD_COMMIT}, + {guest_view::kEventResize, events::GUEST_VIEW_INTERNAL_ON_RESIZE}, + {webview::kEventBeforeRequest, + events::WEB_VIEW_INTERNAL_ON_BEFORE_REQUEST}, + {webview::kEventBeforeSendHeaders, + events::WEB_VIEW_INTERNAL_ON_BEFORE_SEND_HEADERS}, + {webview::kEventClose, events::WEB_VIEW_INTERNAL_ON_CLOSE}, + {webview::kEventCompleted, events::WEB_VIEW_INTERNAL_ON_COMPLETED}, + {webview::kEventConsoleMessage, + events::WEB_VIEW_INTERNAL_ON_CONSOLE_MESSAGE}, + {webview::kEventContentLoad, events::WEB_VIEW_INTERNAL_ON_CONTENT_LOAD}, + {webview::kEventDialog, events::WEB_VIEW_INTERNAL_ON_DIALOG}, + {webview::kEventDropLink, events::WEB_VIEW_INTERNAL_ON_DROP_LINK}, + {webview::kEventExit, events::WEB_VIEW_INTERNAL_ON_EXIT}, + {webview::kEventExitFullscreen, + events::WEB_VIEW_INTERNAL_ON_EXIT_FULLSCREEN}, + {webview::kEventFindReply, events::WEB_VIEW_INTERNAL_ON_FIND_REPLY}, + {webview::kEventHeadersReceived, + events::WEB_VIEW_INTERNAL_ON_HEADERS_RECEIVED}, + {webview::kEventFrameNameChanged, + events::WEB_VIEW_INTERNAL_ON_FRAME_NAME_CHANGED}, + {webview::kEventLoadAbort, events::WEB_VIEW_INTERNAL_ON_LOAD_ABORT}, + {webview::kEventLoadCommit, events::WEB_VIEW_INTERNAL_ON_LOAD_COMMIT}, + {webview::kEventLoadProgress, + events::WEB_VIEW_INTERNAL_ON_LOAD_PROGRESS}, + {webview::kEventLoadRedirect, + events::WEB_VIEW_INTERNAL_ON_LOAD_REDIRECT}, + {webview::kEventLoadStart, events::WEB_VIEW_INTERNAL_ON_LOAD_START}, + {webview::kEventLoadStop, events::WEB_VIEW_INTERNAL_ON_LOAD_STOP}, + {webview::kEventNewWindow, events::WEB_VIEW_INTERNAL_ON_NEW_WINDOW}, + {webview::kEventPermissionRequest, + events::WEB_VIEW_INTERNAL_ON_PERMISSION_REQUEST}, + {webview::kEventResponseStarted, + events::WEB_VIEW_INTERNAL_ON_RESPONSE_STARTED}, + {webview::kEventResponsive, events::WEB_VIEW_INTERNAL_ON_RESPONSIVE}, + {webview::kEventSizeChanged, events::WEB_VIEW_INTERNAL_ON_SIZE_CHANGED}, + {webview::kEventUnresponsive, + events::WEB_VIEW_INTERNAL_ON_UNRESPONSIVE}, + {webview::kEventZoomChange, events::WEB_VIEW_INTERNAL_ON_ZOOM_CHANGE}, + }; + for (const auto& name_and_value : names_and_values) { + values_[name_and_value.name] = name_and_value.value; + } + } + + events::HistogramValue Get(const std::string& event_name) { + auto value = values_.find(event_name); + return value != values_.end() ? value->second : events::UNKNOWN; + } + + private: + std::map<std::string, events::HistogramValue> values_; + + DISALLOW_COPY_AND_ASSIGN(EventMap); +}; + +base::LazyInstance<EventMap> g_event_map = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +events::HistogramValue GetEventHistogramValue(const std::string& event_name) { + return g_event_map.Get().Get(event_name); +} + +} // namespace guest_view_events +} // namespace extensions diff --git a/extensions/browser/guest_view/guest_view_events.h b/extensions/browser/guest_view/guest_view_events.h new file mode 100644 index 0000000..ba7e496 --- /dev/null +++ b/extensions/browser/guest_view/guest_view_events.h @@ -0,0 +1,23 @@ +// Copyright 2015 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 EXTENSIONS_BROWSER_GUEST_VIEW_GUEST_VIEW_EVENTS_H_ +#define EXTENSIONS_BROWSER_GUEST_VIEW_GUEST_VIEW_EVENTS_H_ + +#include <string> + +#include "extensions/browser/extension_event_histogram_value.h" + +namespace extensions { +namespace guest_view_events { + +// Returns the events::HistogramValue for the |event_name| guest view event. +// This knows about all events for all guest view types, whether web view, +// extension options, the guest view base class, etc. +events::HistogramValue GetEventHistogramValue(const std::string& event_name); + +} // namespace guest_view_events +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_GUEST_VIEW_GUEST_VIEW_EVENTS_H_ diff --git a/extensions/browser/guest_view/web_view/web_view_constants.cc b/extensions/browser/guest_view/web_view/web_view_constants.cc index 18ae46f..52834fa 100644 --- a/extensions/browser/guest_view/web_view/web_view_constants.cc +++ b/extensions/browser/guest_view/web_view/web_view_constants.cc @@ -21,7 +21,10 @@ const char kAPILoadDataInvalidBaseURL[] = "Invalid base URL \"%s\"."; const char kAPILoadDataInvalidVirtualURL[] = "Invalid virtual URL \"%s\"."; // Events. +const char kEventBeforeRequest[] = "webViewInternal.onBeforeRequest"; +const char kEventBeforeSendHeaders[] = "webViewInternal.onBeforeSendHeaders"; const char kEventClose[] = "webViewInternal.onClose"; +const char kEventCompleted[] = "webViewInternal.onCompleted"; const char kEventConsoleMessage[] = "webViewInternal.onConsoleMessage"; const char kEventContentLoad[] = "webViewInternal.onContentLoad"; const char kEventContextMenuShow[] = "chromeWebViewInternal.onContextMenuShow"; @@ -31,6 +34,7 @@ const char kEventExit[] = "webViewInternal.onExit"; const char kEventExitFullscreen[] = "webViewInternal.onExitFullscreen"; const char kEventFindReply[] = "webViewInternal.onFindReply"; const char kEventFrameNameChanged[] = "webViewInternal.onFrameNameChanged"; +const char kEventHeadersReceived[] = "webViewInternal.onHeadersReceived"; const char kEventLoadAbort[] = "webViewInternal.onLoadAbort"; const char kEventLoadCommit[] = "webViewInternal.onLoadCommit"; const char kEventLoadProgress[] = "webViewInternal.onLoadProgress"; @@ -40,6 +44,7 @@ const char kEventLoadStop[] = "webViewInternal.onLoadStop"; const char kEventMessage[] = "webViewInternal.onMessage"; const char kEventNewWindow[] = "webViewInternal.onNewWindow"; const char kEventPermissionRequest[] = "webViewInternal.onPermissionRequest"; +const char kEventResponseStarted[] = "webViewInternal.onResponseStarted"; const char kEventResponsive[] = "webViewInternal.onResponsive"; const char kEventSizeChanged[] = "webViewInternal.onSizeChanged"; const char kEventUnresponsive[] = "webViewInternal.onUnresponsive"; diff --git a/extensions/browser/guest_view/web_view/web_view_constants.h b/extensions/browser/guest_view/web_view/web_view_constants.h index 8dfd287..7bc877b 100644 --- a/extensions/browser/guest_view/web_view/web_view_constants.h +++ b/extensions/browser/guest_view/web_view/web_view_constants.h @@ -27,7 +27,10 @@ extern const char kAPILoadDataInvalidBaseURL[]; extern const char kAPILoadDataInvalidVirtualURL[]; // Events. +extern const char kEventBeforeRequest[]; +extern const char kEventBeforeSendHeaders[]; extern const char kEventClose[]; +extern const char kEventCompleted[]; extern const char kEventConsoleMessage[]; extern const char kEventContentLoad[]; extern const char kEventContextMenuShow[]; @@ -37,6 +40,7 @@ extern const char kEventExit[]; extern const char kEventExitFullscreen[]; extern const char kEventFindReply[]; extern const char kEventFrameNameChanged[]; +extern const char kEventHeadersReceived[]; extern const char kEventLoadAbort[]; extern const char kEventLoadCommit[]; extern const char kEventLoadProgress[]; @@ -46,6 +50,7 @@ extern const char kEventLoadStop[]; extern const char kEventMessage[]; extern const char kEventNewWindow[]; extern const char kEventPermissionRequest[]; +extern const char kEventResponseStarted[]; extern const char kEventResponsive[]; extern const char kEventSizeChanged[]; extern const char kEventUnresponsive[]; diff --git a/extensions/extensions.gypi b/extensions/extensions.gypi index 1686c66..e690780 100644 --- a/extensions/extensions.gypi +++ b/extensions/extensions.gypi @@ -665,6 +665,8 @@ 'browser/guest_view/extensions_guest_view_manager_delegate.h', 'browser/guest_view/extensions_guest_view_message_filter.cc', 'browser/guest_view/extensions_guest_view_message_filter.h', + 'browser/guest_view/guest_view_events.cc', + 'browser/guest_view/guest_view_events.h', 'browser/guest_view/mime_handler_view/mime_handler_stream_manager.cc', 'browser/guest_view/mime_handler_view/mime_handler_stream_manager.h', 'browser/guest_view/mime_handler_view/mime_handler_view_constants.cc', diff --git a/extensions/renderer/resources/extension_custom_bindings.js b/extensions/renderer/resources/extension_custom_bindings.js index d114f52..155b762 100644 --- a/extensions/renderer/resources/extension_custom_bindings.js +++ b/extensions/renderer/resources/extension_custom_bindings.js @@ -9,8 +9,6 @@ var binding = require('binding').Binding.create('extension'); var messaging = require('messaging'); var runtimeNatives = requireNative('runtime'); var GetExtensionViews = runtimeNatives.GetExtensionViews; -var OpenChannelToExtension = runtimeNatives.OpenChannelToExtension; -var OpenChannelToNativeApp = runtimeNatives.OpenChannelToNativeApp; var chrome = requireNative('chrome').GetChrome(); var inIncognitoContext = requireNative('process').InIncognitoContext(); diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 0a816b7..c7fd3f5 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -56077,6 +56077,37 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries. <int value="342" label="TYPES_CHROME_SETTING_ON_CHANGE"/> <int value="343" label="TYPES_PRIVATE_CHROME_DIRECT_SETTING_ON_CHANGE"/> <int value="344" label="WEB_VIEW_INTERNAL_ON_MESSAGE"/> + <int value="345" label="EXTENSION_VIEW_INTERNAL_ON_LOAD_COMMIT"/> + <int value="346" label="RUNTIME_ON_REQUEST"/> + <int value="347" label="RUNTIME_ON_REQUEST_EXTERNAL"/> + <int value="348" label="CHROME_WEB_VIEW_INTERNAL_ON_CONTEXT_MENU_SHOW"/> + <int value="349" label="WEB_VIEW_INTERNAL_ON_BEFORE_REQUEST"/> + <int value="350" label="WEB_VIEW_INTERNAL_ON_BEFORE_SEND_HEADERS"/> + <int value="351" label="WEB_VIEW_INTERNAL_ON_CLOSE"/> + <int value="352" label="WEB_VIEW_INTERNAL_ON_COMPLETED"/> + <int value="353" label="WEB_VIEW_INTERNAL_ON_CONSOLE_MESSAGE"/> + <int value="354" label="WEB_VIEW_INTERNAL_ON_CONTENT_LOAD"/> + <int value="355" label="WEB_VIEW_INTERNAL_ON_DIALOG"/> + <int value="356" label="WEB_VIEW_INTERNAL_ON_DROP_LINK"/> + <int value="357" label="WEB_VIEW_INTERNAL_ON_EXIT"/> + <int value="358" label="WEB_VIEW_INTERNAL_ON_EXIT_FULLSCREEN"/> + <int value="359" label="WEB_VIEW_INTERNAL_ON_FIND_REPLY"/> + <int value="360" label="WEB_VIEW_INTERNAL_ON_FRAME_NAME_CHANGED"/> + <int value="361" label="WEB_VIEW_INTERNAL_ON_HEADERS_RECEIVED"/> + <int value="362" label="WEB_VIEW_INTERNAL_ON_LOAD_ABORT"/> + <int value="363" label="WEB_VIEW_INTERNAL_ON_LOAD_COMMIT"/> + <int value="364" label="WEB_VIEW_INTERNAL_ON_LOAD_PROGRESS"/> + <int value="365" label="WEB_VIEW_INTERNAL_ON_LOAD_REDIRECT"/> + <int value="366" label="WEB_VIEW_INTERNAL_ON_LOAD_START"/> + <int value="367" label="WEB_VIEW_INTERNAL_ON_LOAD_STOP"/> + <int value="368" label="WEB_VIEW_INTERNAL_ON_NEW_WINDOW"/> + <int value="369" label="WEB_VIEW_INTERNAL_ON_PERMISSION_REQUEST"/> + <int value="370" label="WEB_VIEW_INTERNAL_ON_RESPONSE_STARTED"/> + <int value="371" label="WEB_VIEW_INTERNAL_ON_RESPONSIVE"/> + <int value="372" label="WEB_VIEW_INTERNAL_ON_SIZE_CHANGED"/> + <int value="373" label="WEB_VIEW_INTERNAL_ON_UNRESPONSIVE"/> + <int value="374" label="WEB_VIEW_INTERNAL_ON_ZOOM_CHANGE"/> + <int value="375" label="GUEST_VIEW_INTERNAL_ON_RESIZE"/> </enum> <enum name="ExtensionFileWriteResult" type="int"> |