summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/automation/extension_port_container.cc2
-rw-r--r--chrome/browser/automation/extension_port_container.h4
-rw-r--r--chrome/browser/debugger/extension_ports_remote_service.cc2
-rw-r--r--chrome/browser/debugger/extension_ports_remote_service.h4
-rw-r--r--chrome/browser/extensions/events_apitest.cc10
-rw-r--r--chrome/browser/extensions/extension_browser_event_router.cc35
-rw-r--r--chrome/browser/extensions/extension_event_router.cc147
-rw-r--r--chrome/browser/extensions/extension_event_router.h39
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc5
-rw-r--r--chrome/browser/extensions/extension_menu_manager.cc6
-rw-r--r--chrome/browser/extensions/extension_menu_manager_unittest.cc23
-rw-r--r--chrome/browser/extensions/extension_message_service.cc6
-rw-r--r--chrome/browser/extensions/extension_messages_browsertest.cc7
-rw-r--r--chrome/browser/extensions/extension_omnibox_api.cc7
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.cc6
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.h6
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/extensions/api/extension_api.json7
-rw-r--r--chrome/common/render_messages_internal.h24
-rw-r--r--chrome/renderer/extensions/bindings_utils.h4
-rw-r--r--chrome/renderer/extensions/event_bindings.cc65
-rw-r--r--chrome/renderer/extensions/event_bindings.h6
-rw-r--r--chrome/renderer/extensions/extension_process_bindings.cc25
-rw-r--r--chrome/renderer/extensions/extension_process_bindings.h9
-rw-r--r--chrome/renderer/extensions/renderer_extension_bindings.cc8
-rw-r--r--chrome/renderer/extensions/renderer_extension_bindings.h6
-rw-r--r--chrome/renderer/render_thread.cc14
-rw-r--r--chrome/renderer/render_thread.h8
-rw-r--r--chrome/renderer/render_view.cc6
-rw-r--r--chrome/renderer/render_view.h4
-rw-r--r--chrome/renderer/resources/event_bindings.js4
-rw-r--r--chrome/renderer/resources/extension_process_bindings.js9
-rw-r--r--chrome/test/data/extensions/api_test/events/background.html43
-rw-r--r--chrome/test/data/extensions/api_test/events/manifest.json7
34 files changed, 319 insertions, 240 deletions
diff --git a/chrome/browser/automation/extension_port_container.cc b/chrome/browser/automation/extension_port_container.cc
index cdae059..f6b502e 100644
--- a/chrome/browser/automation/extension_port_container.cc
+++ b/chrome/browser/automation/extension_port_container.cc
@@ -107,9 +107,9 @@ bool ExtensionPortContainer::Send(IPC::Message *message) {
}
void ExtensionPortContainer::OnExtensionMessageInvoke(
+ const std::string& extension_id,
const std::string& function_name,
const ListValue& args,
- bool requires_incognito_access,
const GURL& event_url) {
if (function_name == ExtensionMessageService::kDispatchOnMessage) {
DCHECK_EQ(args.GetSize(), 2u);
diff --git a/chrome/browser/automation/extension_port_container.h b/chrome/browser/automation/extension_port_container.h
index 1325303..d52e9a8 100644
--- a/chrome/browser/automation/extension_port_container.h
+++ b/chrome/browser/automation/extension_port_container.h
@@ -63,9 +63,9 @@ class ExtensionPortContainer : public IPC::Message::Sender {
// Sends a connect response to the external port.
void SendConnectionResponse(int connection_id, int port_id);
- void OnExtensionMessageInvoke(const std::string& function_name,
+ void OnExtensionMessageInvoke(const std::string& extension_id,
+ const std::string& function_name,
const ListValue& args,
- bool requires_incognito_access,
const GURL& event_url);
void OnExtensionHandleMessage(const std::string& message, int source_port_id);
void OnExtensionPortDisconnected(int source_port_id);
diff --git a/chrome/browser/debugger/extension_ports_remote_service.cc b/chrome/browser/debugger/extension_ports_remote_service.cc
index 4fc4c68..3596187 100644
--- a/chrome/browser/debugger/extension_ports_remote_service.cc
+++ b/chrome/browser/debugger/extension_ports_remote_service.cc
@@ -238,9 +238,9 @@ bool ExtensionPortsRemoteService::Send(IPC::Message *message) {
}
void ExtensionPortsRemoteService::OnExtensionMessageInvoke(
+ const std::string& extension_id,
const std::string& function_name,
const ListValue& args,
- bool requires_incognito_access,
const GURL& event_url) {
if (function_name == ExtensionMessageService::kDispatchOnMessage) {
DCHECK_EQ(args.GetSize(), 2u);
diff --git a/chrome/browser/debugger/extension_ports_remote_service.h b/chrome/browser/debugger/extension_ports_remote_service.h
index 0b4c892..bd9b792 100644
--- a/chrome/browser/debugger/extension_ports_remote_service.h
+++ b/chrome/browser/debugger/extension_ports_remote_service.h
@@ -75,9 +75,9 @@ class ExtensionPortsRemoteService : public DevToolsRemoteListener,
const std::string& destination);
// Handles a message from the ExtensionMessageService.
- void OnExtensionMessageInvoke(const std::string& function_name,
+ void OnExtensionMessageInvoke(const std::string& extension_id,
+ const std::string& function_name,
const ListValue& args,
- bool requires_incognito_access,
const GURL& event_url);
// Handles a message sent from an extension through the
// ExtensionMessageService, to be passed to the external client.
diff --git a/chrome/browser/extensions/events_apitest.cc b/chrome/browser/extensions/events_apitest.cc
new file mode 100644
index 0000000..8319ae6
--- /dev/null
+++ b/chrome/browser/extensions/events_apitest.cc
@@ -0,0 +1,10 @@
+// Copyright (c) 2010 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 "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/common/chrome_switches.h"
+
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Events) {
+ ASSERT_TRUE(RunExtensionTest("events")) << message_;
+}
diff --git a/chrome/browser/extensions/extension_browser_event_router.cc b/chrome/browser/extensions/extension_browser_event_router.cc
index b9ef775..ce58dc7 100644
--- a/chrome/browser/extensions/extension_browser_event_router.cc
+++ b/chrome/browser/extensions/extension_browser_event_router.cc
@@ -66,21 +66,36 @@ ExtensionBrowserEventRouter* ExtensionBrowserEventRouter::GetInstance() {
static void DispatchEvent(Profile* profile,
const char* event_name,
- const std::string json_args) {
+ const std::string& json_args) {
if (profile->GetExtensionEventRouter()) {
profile->GetExtensionEventRouter()->DispatchEventToRenderers(
event_name, json_args, profile, GURL());
}
}
+static void DispatchEventToExtension(Profile* profile,
+ const std::string& extension_id,
+ const char* event_name,
+ const std::string& json_args) {
+ if (profile->GetExtensionEventRouter()) {
+ profile->GetExtensionEventRouter()->DispatchEventToExtension(
+ extension_id, event_name, json_args, profile, GURL());
+ }
+}
+
static void DispatchEventWithTab(Profile* profile,
+ const std::string& extension_id,
const char* event_name,
const TabContents* tab_contents) {
ListValue args;
args.Append(ExtensionTabUtil::CreateTabValue(tab_contents));
std::string json_args;
base::JSONWriter::Write(&args, false, &json_args);
- DispatchEvent(profile, event_name, json_args);
+ if (!extension_id.empty()) {
+ DispatchEventToExtension(profile, extension_id, event_name, json_args);
+ } else {
+ DispatchEvent(profile, event_name, json_args);
+ }
}
static void DispatchSimpleBrowserEvent(Profile* profile,
@@ -244,7 +259,8 @@ void ExtensionBrowserEventRouter::OnBrowserSetLastActive(
void ExtensionBrowserEventRouter::TabCreatedAt(TabContents* contents,
int index,
bool foreground) {
- DispatchEventWithTab(contents->profile(), events::kOnTabCreated, contents);
+ DispatchEventWithTab(contents->profile(), "", events::kOnTabCreated,
+ contents);
RegisterForTabNotifications(contents);
}
@@ -460,8 +476,7 @@ void ExtensionBrowserEventRouter::DispatchOldPageActionEvent(
std::string json_args;
base::JSONWriter::Write(&args, false, &json_args);
- std::string event_name = std::string("pageActions/") + extension_id;
- DispatchEvent(profile, event_name.c_str(), json_args);
+ DispatchEventToExtension(profile, extension_id, "pageActions", json_args);
}
void ExtensionBrowserEventRouter::PageActionExecuted(
@@ -478,9 +493,8 @@ void ExtensionBrowserEventRouter::PageActionExecuted(
NULL, NULL, &tab_contents, NULL)) {
return;
}
- std::string event_name = ExtensionEventRouter::GetPerExtensionEventName(
- "pageAction.onClicked", extension_id);
- DispatchEventWithTab(profile, event_name.c_str(), tab_contents);
+ DispatchEventWithTab(profile, extension_id, "pageAction.onClicked",
+ tab_contents);
}
void ExtensionBrowserEventRouter::BrowserActionExecuted(
@@ -489,7 +503,6 @@ void ExtensionBrowserEventRouter::BrowserActionExecuted(
int tab_id = 0;
if (!ExtensionTabUtil::GetDefaultTab(browser, &tab_contents, &tab_id))
return;
- std::string event_name = ExtensionEventRouter::GetPerExtensionEventName(
- "browserAction.onClicked", extension_id);
- DispatchEventWithTab(profile, event_name.c_str(), tab_contents);
+ DispatchEventWithTab(profile, extension_id, "browserAction.onClicked",
+ tab_contents);
}
diff --git a/chrome/browser/extensions/extension_event_router.cc b/chrome/browser/extensions/extension_event_router.cc
index 5e2707e..9d22da7 100644
--- a/chrome/browser/extensions/extension_event_router.cc
+++ b/chrome/browser/extensions/extension_event_router.cc
@@ -10,6 +10,7 @@
#include "chrome/browser/extensions/extension_processes_api.h"
#include "chrome/browser/extensions/extension_processes_api_constants.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
+#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/extensions/extension.h"
@@ -21,26 +22,46 @@ namespace {
const char kDispatchEvent[] = "Event.dispatchJSON";
static void DispatchEvent(RenderProcessHost* renderer,
+ const std::string& extension_id,
const std::string& event_name,
const std::string& event_args,
- bool cross_incognito,
const GURL& event_url) {
ListValue args;
args.Set(0, Value::CreateStringValue(event_name));
args.Set(1, Value::CreateStringValue(event_args));
renderer->Send(new ViewMsg_ExtensionMessageInvoke(MSG_ROUTING_CONTROL,
- kDispatchEvent, args, cross_incognito, event_url));
+ extension_id, kDispatchEvent, args, event_url));
+}
+
+static bool CanCrossIncognito(Profile* profile,
+ const std::string& extension_id) {
+ // We allow the extension to see events and data from another profile iff it
+ // uses "spanning" behavior and it has incognito access. "split" mode
+ // extensions only see events for a matching profile.
+ Extension* extension =
+ profile->GetExtensionsService()->GetExtensionById(extension_id, false);
+ return (profile->GetExtensionsService()->IsIncognitoEnabled(extension) &&
+ !extension->incognito_split_mode());
}
} // namespace
-// static
-std::string ExtensionEventRouter::GetPerExtensionEventName(
- const std::string& event_name, const std::string& extension_id) {
- // This should match the method we use in extension_process_binding.js when
- // setting up the corresponding chrome.Event object.
- return event_name + "/" + extension_id;
-}
+struct ExtensionEventRouter::EventListener {
+ RenderProcessHost* process;
+ std::string extension_id;
+
+ explicit EventListener(RenderProcessHost* process,
+ const std::string& extension_id)
+ : process(process), extension_id(extension_id) {}
+
+ bool operator<(const EventListener& that) const {
+ if (process < that.process)
+ return true;
+ if (process == that.process && extension_id < that.extension_id)
+ return true;
+ return false;
+ }
+};
ExtensionEventRouter::ExtensionEventRouter(Profile* profile)
: profile_(profile),
@@ -56,14 +77,14 @@ ExtensionEventRouter::~ExtensionEventRouter() {
void ExtensionEventRouter::AddEventListener(
const std::string& event_name,
- int render_process_id) {
- DCHECK_EQ(listeners_[event_name].count(render_process_id), 0u) << event_name;
- listeners_[event_name].insert(render_process_id);
+ RenderProcessHost* process,
+ const std::string& extension_id) {
+ EventListener listener(process, extension_id);
+ DCHECK_EQ(listeners_[event_name].count(listener), 0u) << event_name;
+ listeners_[event_name].insert(listener);
- if (extension_devtools_manager_.get()) {
- extension_devtools_manager_->AddEventListener(event_name,
- render_process_id);
- }
+ if (extension_devtools_manager_.get())
+ extension_devtools_manager_->AddEventListener(event_name, process->id());
// We lazily tell the TaskManager to start updating when listeners to the
// processes.onUpdated event arrive.
@@ -73,15 +94,16 @@ void ExtensionEventRouter::AddEventListener(
void ExtensionEventRouter::RemoveEventListener(
const std::string& event_name,
- int render_process_id) {
- DCHECK_EQ(listeners_[event_name].count(render_process_id), 1u) <<
- " PID=" << render_process_id << " event=" << event_name;
- listeners_[event_name].erase(render_process_id);
-
- if (extension_devtools_manager_.get()) {
- extension_devtools_manager_->RemoveEventListener(event_name,
- render_process_id);
- }
+ RenderProcessHost* process,
+ const std::string& extension_id) {
+ EventListener listener(process, extension_id);
+ DCHECK_EQ(listeners_[event_name].count(listener), 1u) <<
+ " PID=" << process->id() << " extension=" << extension_id <<
+ " event=" << event_name;
+ listeners_[event_name].erase(listener);
+
+ if (extension_devtools_manager_.get())
+ extension_devtools_manager_->RemoveEventListener(event_name, process->id());
// If a processes.onUpdated event listener is removed (or a process with one
// exits), then we let the TaskManager know that it has one fewer listener.
@@ -94,9 +116,40 @@ bool ExtensionEventRouter::HasEventListener(const std::string& event_name) {
!listeners_[event_name].empty());
}
+bool ExtensionEventRouter::ExtensionHasEventListener(
+ const std::string& extension_id, const std::string& event_name) {
+ ListenerMap::iterator it = listeners_.find(event_name);
+ if (it == listeners_.end())
+ return false;
+
+ std::set<EventListener>& listeners = it->second;
+ for (std::set<EventListener>::iterator listener = listeners.begin();
+ listener != listeners.end(); ++listener) {
+ if (listener->extension_id == extension_id)
+ return true;
+ }
+ return false;
+}
+
void ExtensionEventRouter::DispatchEventToRenderers(
const std::string& event_name, const std::string& event_args,
Profile* restrict_to_profile, const GURL& event_url) {
+ DispatchEventImpl("", event_name, event_args, restrict_to_profile, event_url);
+}
+
+void ExtensionEventRouter::DispatchEventToExtension(
+ const std::string& extension_id,
+ const std::string& event_name, const std::string& event_args,
+ Profile* restrict_to_profile, const GURL& event_url) {
+ DCHECK(!extension_id.empty());
+ DispatchEventImpl(extension_id, event_name, event_args, restrict_to_profile,
+ event_url);
+}
+
+void ExtensionEventRouter::DispatchEventImpl(
+ const std::string& extension_id,
+ const std::string& event_name, const std::string& event_args,
+ Profile* restrict_to_profile, const GURL& event_url) {
if (!profile_)
return;
@@ -107,33 +160,30 @@ void ExtensionEventRouter::DispatchEventToRenderers(
if (it == listeners_.end())
return;
- std::set<int>& pids = it->second;
+ std::set<EventListener>& listeners = it->second;
// Send the event only to renderers that are listening for it.
- for (std::set<int>::iterator pid = pids.begin(); pid != pids.end(); ++pid) {
- RenderProcessHost* renderer = RenderProcessHost::FromID(*pid);
- if (!renderer)
- continue;
+ for (std::set<EventListener>::iterator listener = listeners.begin();
+ listener != listeners.end(); ++listener) {
if (!ChildProcessSecurityPolicy::GetInstance()->
- HasExtensionBindings(*pid)) {
+ HasExtensionBindings(listener->process->id())) {
// Don't send browser-level events to unprivileged processes.
continue;
}
+ if (!extension_id.empty() && extension_id != listener->extension_id)
+ continue;
+
// Is this event from a different profile than the renderer (ie, an
// incognito tab event sent to a normal process, or vice versa).
- bool cross_incognito =
- restrict_to_profile && renderer->profile() != restrict_to_profile;
- DispatchEvent(renderer, event_name, event_args, cross_incognito, event_url);
- }
-}
+ bool cross_incognito = restrict_to_profile &&
+ listener->process->profile() != restrict_to_profile;
+ if (cross_incognito && !CanCrossIncognito(profile_, listener->extension_id))
+ continue;
-void ExtensionEventRouter::DispatchEventToExtension(
- const std::string& extension_id,
- const std::string& event_name, const std::string& event_args,
- Profile* restrict_to_profile, const GURL& event_url) {
- DispatchEventToRenderers(GetPerExtensionEventName(event_name, extension_id),
- event_args, restrict_to_profile, event_url);
+ DispatchEvent(listener->process, listener->extension_id,
+ event_name, event_args, event_url);
+ }
}
void ExtensionEventRouter::Observe(NotificationType type,
@@ -146,9 +196,16 @@ void ExtensionEventRouter::Observe(NotificationType type,
// Remove all event listeners associated with this renderer
for (ListenerMap::iterator it = listeners_.begin();
it != listeners_.end(); ) {
- ListenerMap::iterator current = it++;
- if (current->second.count(renderer->id()) != 0)
- RemoveEventListener(current->first, renderer->id());
+ ListenerMap::iterator current_it = it++;
+ for (std::set<EventListener>::iterator jt = current_it->second.begin();
+ jt != current_it->second.end(); ) {
+ std::set<EventListener>::iterator current_jt = jt++;
+ if (current_jt->process == renderer) {
+ RemoveEventListener(current_it->first,
+ current_jt->process,
+ current_jt->extension_id);
+ }
+ }
}
break;
}
diff --git a/chrome/browser/extensions/extension_event_router.h b/chrome/browser/extensions/extension_event_router.h
index 5fb29e4..5e1ca97 100644
--- a/chrome/browser/extensions/extension_event_router.h
+++ b/chrome/browser/extensions/extension_event_router.h
@@ -24,37 +24,52 @@ class ExtensionEventRouter : public NotificationObserver {
explicit ExtensionEventRouter(Profile* profile);
~ExtensionEventRouter();
- // Returns the event name for an event that is extension-specific.
- static std::string GetPerExtensionEventName(const std::string& event_name,
- const std::string& extension_id);
-
- // Add or remove |render_process_id| as a listener for |event_name|.
+ // Add or remove the process/extension pair as a listener for |event_name|.
+ // Note that multiple extensions can share a process due to process
+ // collapsing. Also, a single extension can have 2 processes if it is a split
+ // mode extension.
void AddEventListener(const std::string& event_name,
- int render_process_id);
+ RenderProcessHost* process,
+ const std::string& extension_id);
void RemoveEventListener(const std::string& event_name,
- int render_process_id);
+ RenderProcessHost* process,
+ const std::string& extension_id);
// Returns true if there is at least one listener for the given event.
bool HasEventListener(const std::string& event_name);
+ // Returns true if the extension is listening to the given event.
+ bool ExtensionHasEventListener(const std::string& extension_id,
+ const std::string& event_name);
+
// Send an event to every registered extension renderer. If
// |restrict_to_profile| is non-NULL, then the event will not be sent to other
// profiles unless the extension has permission (e.g. incognito tab update ->
// normal profile only works if extension is allowed incognito access). If
// |event_url| is not empty, the event is only sent to extension with host
// permissions for this url.
- virtual void DispatchEventToRenderers(
+ void DispatchEventToRenderers(
const std::string& event_name, const std::string& event_args,
Profile* restrict_to_profile, const GURL& event_url);
- // Same as above, except use the extension-specific naming scheme for the
- // event. This is used by events that are per-extension.
+ // Same as above, except only send the event to the given extension.
void DispatchEventToExtension(
const std::string& extension_id,
const std::string& event_name, const std::string& event_args,
Profile* restrict_to_profile, const GURL& event_url);
+ protected:
+ // Shared by DispatchEvent*. If |extension_id| is empty, the event is
+ // broadcast.
+ virtual void DispatchEventImpl(
+ const std::string& extension_id,
+ const std::string& event_name, const std::string& event_args,
+ Profile* restrict_to_profile, const GURL& event_url);
+
private:
+ // An extension listening to an event.
+ struct EventListener;
+
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details);
@@ -65,9 +80,9 @@ class ExtensionEventRouter : public NotificationObserver {
scoped_refptr<ExtensionDevToolsManager> extension_devtools_manager_;
- // A map between an event name and a set of process id's that are listening
+ // A map between an event name and a set of extensions that are listening
// to that event.
- typedef std::map<std::string, std::set<int> > ListenerMap;
+ typedef std::map<std::string, std::set<EventListener> > ListenerMap;
ListenerMap listeners_;
DISALLOW_COPY_AND_ASSIGN(ExtensionEventRouter);
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 7a99137..e3ca590 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -373,9 +373,6 @@ ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
epm->RegisterExtensionProcess(extension_id(),
render_view_host->process()->id());
- bool incognito_enabled =
- profile()->GetExtensionsService()->IsIncognitoEnabled(extension);
-
// If the extension has permission to load chrome://favicon/ resources we need
// to make sure that the DOMUIFavIconSource is registered with the
// ChromeURLDataManager.
@@ -395,8 +392,6 @@ ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
extension->id(), extension->api_permissions()));
render_view_host->Send(new ViewMsg_Extension_SetHostPermissions(
extension->url(), extension->host_permissions()));
- render_view_host->Send(new ViewMsg_Extension_ExtensionSetIncognitoEnabled(
- extension->id(), incognito_enabled, extension->incognito_split_mode()));
NotificationService::current()->Notify(
NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED,
diff --git a/chrome/browser/extensions/extension_menu_manager.cc b/chrome/browser/extensions/extension_menu_manager.cc
index d5f33e6..307c339 100644
--- a/chrome/browser/extensions/extension_menu_manager.cc
+++ b/chrome/browser/extensions/extension_menu_manager.cc
@@ -440,9 +440,9 @@ void ExtensionMenuManager::ExecuteCommand(
std::string json_args;
base::JSONWriter::Write(&args, false, &json_args);
- std::string event_name = "contextMenus/" + item->extension_id();
- event_router->DispatchEventToRenderers(
- event_name, json_args, profile, GURL());
+ std::string event_name = "contextMenus";
+ event_router->DispatchEventToExtension(
+ item->extension_id(), event_name, json_args, profile, GURL());
}
void ExtensionMenuManager::Observe(NotificationType type,
diff --git a/chrome/browser/extensions/extension_menu_manager_unittest.cc b/chrome/browser/extensions/extension_menu_manager_unittest.cc
index 3dc6f69..0b653ba 100644
--- a/chrome/browser/extensions/extension_menu_manager_unittest.cc
+++ b/chrome/browser/extensions/extension_menu_manager_unittest.cc
@@ -336,10 +336,11 @@ class MockExtensionEventRouter : public ExtensionEventRouter {
explicit MockExtensionEventRouter(Profile* profile) :
ExtensionEventRouter(profile) {}
- MOCK_METHOD4(DispatchEventToRenderers, void(const std::string& event_name,
- const std::string& event_args,
- Profile* source_profile,
- const GURL& event_url));
+ MOCK_METHOD5(DispatchEventImpl, void(const std::string& extension_id,
+ const std::string& event_name,
+ const std::string& event_args,
+ Profile* source_profile,
+ const GURL& event_url));
private:
DISALLOW_COPY_AND_ASSIGN(MockExtensionEventRouter);
@@ -414,15 +415,17 @@ TEST_F(ExtensionMenuManagerTest, ExecuteCommand) {
.WillOnce(Return(mock_event_router.get()));
// Use the magic of googlemock to save a parameter to our mock's
- // DispatchEventToRenderers method into event_args.
+ // DispatchEventImpl method into event_args.
std::string event_args;
- std::string expected_event_name = "contextMenus/" + item->extension_id();
+ std::string expected_event_name = "contextMenus";
EXPECT_CALL(*mock_event_router.get(),
- DispatchEventToRenderers(expected_event_name, _,
- &profile,
- GURL()))
+ DispatchEventImpl(item->extension_id(),
+ expected_event_name,
+ _,
+ &profile,
+ GURL()))
.Times(1)
- .WillOnce(SaveArg<1>(&event_args));
+ .WillOnce(SaveArg<2>(&event_args));
manager_.ExecuteCommand(&profile, NULL /* tab_contents */, params, id);
diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc
index e8562ff..a3a13c1 100644
--- a/chrome/browser/extensions/extension_message_service.cc
+++ b/chrome/browser/extensions/extension_message_service.cc
@@ -70,7 +70,7 @@ static void DispatchOnConnect(const ExtensionMessageService::MessagePort& port,
args.Set(4, Value::CreateStringValue(target_extension_id));
CHECK(port.sender);
port.sender->Send(new ViewMsg_ExtensionMessageInvoke(port.routing_id,
- ExtensionMessageService::kDispatchOnConnect, args, false, GURL()));
+ "", ExtensionMessageService::kDispatchOnConnect, args, GURL()));
}
static void DispatchOnDisconnect(
@@ -78,7 +78,7 @@ static void DispatchOnDisconnect(
ListValue args;
args.Set(0, Value::CreateIntegerValue(source_port_id));
port.sender->Send(new ViewMsg_ExtensionMessageInvoke(port.routing_id,
- ExtensionMessageService::kDispatchOnDisconnect, args, false, GURL()));
+ "", ExtensionMessageService::kDispatchOnDisconnect, args, GURL()));
}
static void DispatchOnMessage(const ExtensionMessageService::MessagePort& port,
@@ -87,7 +87,7 @@ static void DispatchOnMessage(const ExtensionMessageService::MessagePort& port,
args.Set(0, Value::CreateStringValue(message));
args.Set(1, Value::CreateIntegerValue(source_port_id));
port.sender->Send(new ViewMsg_ExtensionMessageInvoke(port.routing_id,
- ExtensionMessageService::kDispatchOnMessage, args, false, GURL()));
+ "", ExtensionMessageService::kDispatchOnMessage, args, GURL()));
}
} // namespace
diff --git a/chrome/browser/extensions/extension_messages_browsertest.cc b/chrome/browser/extensions/extension_messages_browsertest.cc
index 5e78c79..bd36a80 100644
--- a/chrome/browser/extensions/extension_messages_browsertest.cc
+++ b/chrome/browser/extensions/extension_messages_browsertest.cc
@@ -22,15 +22,14 @@ static void DispatchOnConnect(int source_port_id, const std::string& name,
args.Set(3, Value::CreateStringValue(EventBindings::kTestingExtensionId));
args.Set(4, Value::CreateStringValue(EventBindings::kTestingExtensionId));
RendererExtensionBindings::Invoke(
- ExtensionMessageService::kDispatchOnConnect, args, NULL, false, GURL());
+ "", ExtensionMessageService::kDispatchOnConnect, args, NULL, GURL());
}
static void DispatchOnDisconnect(int source_port_id) {
ListValue args;
args.Set(0, Value::CreateIntegerValue(source_port_id));
RendererExtensionBindings::Invoke(
- ExtensionMessageService::kDispatchOnDisconnect, args, NULL, false,
- GURL());
+ "", ExtensionMessageService::kDispatchOnDisconnect, args, NULL, GURL());
}
static void DispatchOnMessage(const std::string& message, int source_port_id) {
@@ -38,7 +37,7 @@ static void DispatchOnMessage(const std::string& message, int source_port_id) {
args.Set(0, Value::CreateStringValue(message));
args.Set(1, Value::CreateIntegerValue(source_port_id));
RendererExtensionBindings::Invoke(
- ExtensionMessageService::kDispatchOnMessage, args, NULL, false, GURL());
+ "", ExtensionMessageService::kDispatchOnMessage, args, NULL, GURL());
}
// Tests that the bindings for opening a channel to an extension and sending
diff --git a/chrome/browser/extensions/extension_omnibox_api.cc b/chrome/browser/extensions/extension_omnibox_api.cc
index 6d9e4e4..3e4887d 100644
--- a/chrome/browser/extensions/extension_omnibox_api.cc
+++ b/chrome/browser/extensions/extension_omnibox_api.cc
@@ -43,9 +43,8 @@ void ExtensionOmniboxEventRouter::OnInputStarted(
bool ExtensionOmniboxEventRouter::OnInputChanged(
Profile* profile, const std::string& extension_id,
const std::string& input, int suggest_id) {
- std::string event_name = ExtensionEventRouter::GetPerExtensionEventName(
- events::kOnInputChanged, extension_id);
- if (!profile->GetExtensionEventRouter()->HasEventListener(event_name))
+ if (!profile->GetExtensionEventRouter()->ExtensionHasEventListener(
+ extension_id, events::kOnInputChanged))
return false;
ListValue args;
@@ -63,8 +62,6 @@ bool ExtensionOmniboxEventRouter::OnInputChanged(
void ExtensionOmniboxEventRouter::OnInputEntered(
Profile* profile, const std::string& extension_id,
const std::string& input) {
- std::string event_name = events::kOnInputEntered + extension_id;
-
ListValue args;
args.Set(0, Value::CreateStringValue(input));
std::string json_args;
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc
index 5e254e5..b7af07f 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.cc
+++ b/chrome/browser/renderer_host/browser_render_process_host.cc
@@ -1066,18 +1066,20 @@ void BrowserRenderProcessHost::OnProcessLaunched() {
}
void BrowserRenderProcessHost::OnExtensionAddListener(
+ const std::string& extension_id,
const std::string& event_name) {
if (profile()->GetExtensionEventRouter()) {
profile()->GetExtensionEventRouter()->AddEventListener(
- event_name, id());
+ event_name, this, extension_id);
}
}
void BrowserRenderProcessHost::OnExtensionRemoveListener(
+ const std::string& extension_id,
const std::string& event_name) {
if (profile()->GetExtensionEventRouter()) {
profile()->GetExtensionEventRouter()->RemoveEventListener(
- event_name, id());
+ event_name, this, extension_id);
}
}
diff --git a/chrome/browser/renderer_host/browser_render_process_host.h b/chrome/browser/renderer_host/browser_render_process_host.h
index 9983c84..639ba32 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.h
+++ b/chrome/browser/renderer_host/browser_render_process_host.h
@@ -108,8 +108,10 @@ class BrowserRenderProcessHost : public RenderProcessHost,
// Control message handlers.
void OnUpdatedCacheStats(const WebKit::WebCache::UsageStats& stats);
void SuddenTerminationChanged(bool enabled);
- void OnExtensionAddListener(const std::string& event_name);
- void OnExtensionRemoveListener(const std::string& event_name);
+ void OnExtensionAddListener(const std::string& extension_id,
+ const std::string& event_name);
+ void OnExtensionRemoveListener(const std::string& extension_id,
+ const std::string& event_name);
void OnExtensionCloseChannel(int port_id);
// Initialize support for visited links. Send the renderer process its initial
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index acdd862..e9b2fb3 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1915,6 +1915,7 @@
'browser/extensions/content_script_all_frames_apitest.cc',
'browser/extensions/content_script_extension_process_apitest.cc',
'browser/extensions/cross_origin_xhr_apitest.cc',
+ 'browser/extensions/events_apitest.cc',
'browser/extensions/extension_devtools_browsertest.cc',
'browser/extensions/extension_devtools_browsertest.h',
'browser/extensions/extension_devtools_browsertests.cc',
diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json
index af52b4f..3fdd1ce 100644
--- a/chrome/common/extensions/api/extension_api.json
+++ b/chrome/common/extensions/api/extension_api.json
@@ -1452,7 +1452,6 @@
"events": [
{
"name": "onClicked",
- "perExtensionEvent": true,
"type": "function",
"description": "Fired when a page action icon is clicked. This event will not fire if the page action has a popup.",
"parameters": [
@@ -1600,7 +1599,6 @@
"events": [
{
"name": "onClicked",
- "perExtensionEvent": true,
"type": "function",
"description": "Fired when a browser action icon is clicked. This event will not fire if the browser action has a popup.",
"parameters": [
@@ -3849,7 +3847,6 @@
"events": [
{
"name": "onStateChanged",
- "perExtensionEvent": true,
"unprivileged": true,
"type": "function",
"description": "Notifies about sidebar state changes.",
@@ -3950,14 +3947,12 @@
"events": [
{
"name": "onInputStarted",
- "perExtensionEvent": true,
"type": "function",
"description": "User has started a keyword input session by typing the extension's keyword. This is guaranteed to be sent exactly once per input session, and before any onInputChanged events.",
"parameters": []
},
{
"name": "onInputChanged",
- "perExtensionEvent": true,
"type": "function",
"description": "User has changed what is typed into the omnibox.",
"parameters": [
@@ -3984,7 +3979,6 @@
},
{
"name": "onInputEntered",
- "perExtensionEvent": true,
"type": "function",
"description": "User has accepted what is typed into the omnibox.",
"parameters": [
@@ -3996,7 +3990,6 @@
},
{
"name": "onInputCancelled",
- "perExtensionEvent": true,
"type": "function",
"description": "User has ended the keyword input session without accepting the input.",
"parameters": []
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 75eacdf..b8e9a70 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -750,11 +750,13 @@ IPC_BEGIN_MESSAGES(View)
// will call a javascript function in every registered context in the
// target process. If routed, it will be restricted to the contexts that
// are part of the target RenderView.
- // |args| is a list of primitive Value types that are passed to the function.
+ // If |extension_id| is non-empty, the function will be invoked only in
+ // contexts owned by the extension. |args| is a list of primitive Value types
+ // that are passed to the function.
IPC_MESSAGE_ROUTED4(ViewMsg_ExtensionMessageInvoke,
+ std::string /* extension_id */,
std::string /* function_name */,
ListValue /* args */,
- bool /* requires incognito access */,
GURL /* event URL */)
// Tell the renderer process all known extension function names.
@@ -773,13 +775,6 @@ IPC_BEGIN_MESSAGES(View)
GURL /* source extension's origin */,
std::vector<URLPattern> /* URLPatterns the extension can access */)
- // Tell the renderer process that the given extension is enabled or disabled
- // for incognito mode, and what kind of incognito behavior it has.
- IPC_MESSAGE_CONTROL3(ViewMsg_Extension_ExtensionSetIncognitoEnabled,
- std::string /* extension_id */,
- bool /* enabled */,
- bool /* incognito_split_mode */)
-
// Tell the renderer process all known page action ids for a particular
// extension.
IPC_MESSAGE_CONTROL2(ViewMsg_Extension_UpdatePageActions,
@@ -2125,12 +2120,15 @@ IPC_BEGIN_MESSAGES(ViewHost)
IPC_MESSAGE_ROUTED1(ViewHostMsg_ExtensionRequest,
ViewHostMsg_DomMessage_Params)
- // Notify the browser that this renderer added a listener to an event.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_ExtensionAddListener,
+ // Notify the browser that the given extension added a listener to an event.
+ IPC_MESSAGE_CONTROL2(ViewHostMsg_ExtensionAddListener,
+ std::string /* extension_id */,
std::string /* name */)
- // Notify the browser that this renderer removed a listener from an event.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_ExtensionRemoveListener,
+ // Notify the browser that the given extension removed a listener from an
+ // event.
+ IPC_MESSAGE_CONTROL2(ViewHostMsg_ExtensionRemoveListener,
+ std::string /* extension_id */,
std::string /* name */)
#if defined(OS_MACOSX)
diff --git a/chrome/renderer/extensions/bindings_utils.h b/chrome/renderer/extensions/bindings_utils.h
index 9432f91..b269ad1 100644
--- a/chrome/renderer/extensions/bindings_utils.h
+++ b/chrome/renderer/extensions/bindings_utils.h
@@ -78,6 +78,10 @@ struct ContextInfo {
// a valid pointer, and is used for comparisons only. Do not dereference.
RenderView* render_view;
+ // A map of event names to the number of listeners for that event. We notify
+ // the browser about event listeners when we transition between 0 and 1.
+ std::map<std::string, int> listener_counts;
+
// A count of the number of events that are listening in this context. When
// this is zero, |context| will be a weak handle.
int num_connected_events;
diff --git a/chrome/renderer/extensions/event_bindings.cc b/chrome/renderer/extensions/event_bindings.cc
index 9c3f421..a451953 100644
--- a/chrome/renderer/extensions/event_bindings.cc
+++ b/chrome/renderer/extensions/event_bindings.cc
@@ -51,18 +51,6 @@ static bool in_unit_tests = false;
// are disabled.
static bool bindings_registered = false;
-struct ExtensionData {
- std::map<std::string, int> listener_count;
-};
-int EventIncrementListenerCount(const std::string& event_name) {
- ExtensionData *data = Singleton<ExtensionData>::get();
- return ++(data->listener_count[event_name]);
-}
-int EventDecrementListenerCount(const std::string& event_name) {
- ExtensionData *data = Singleton<ExtensionData>::get();
- return --(data->listener_count[event_name]);
-}
-
class ExtensionImpl : public ExtensionBase {
public:
ExtensionImpl()
@@ -89,25 +77,25 @@ class ExtensionImpl : public ExtensionBase {
DCHECK(args[0]->IsString() || args[0]->IsUndefined());
if (args[0]->IsString()) {
+ ContextInfo* context_info = GetInfoForCurrentContext();
std::string event_name(*v8::String::AsciiValue(args[0]));
bool has_permission =
ExtensionProcessBindings::CurrentContextHasPermission(event_name);
- // Increment the count even if the caller doesn't have permission, so that
- // refcounts stay balanced.
- if (EventIncrementListenerCount(event_name) == 1 && has_permission) {
- EventBindings::GetRenderThread()->Send(
- new ViewHostMsg_ExtensionAddListener(event_name));
- }
-
- ContextInfo* current_context_info = GetInfoForCurrentContext();
- if (++current_context_info->num_connected_events == 1)
- current_context_info->context.ClearWeak();
-
if (!has_permission) {
return ExtensionProcessBindings::ThrowPermissionDeniedException(
event_name);
}
+
+ if (++context_info->listener_counts[event_name] == 1) {
+ EventBindings::GetRenderThread()->Send(
+ new ViewHostMsg_ExtensionAddListener(context_info->extension_id,
+ event_name));
+ }
+
+ if (++context_info->num_connected_events == 1)
+ context_info->context.ClearWeak();
+
}
return v8::Undefined();
@@ -119,17 +107,19 @@ class ExtensionImpl : public ExtensionBase {
DCHECK(args[0]->IsString() || args[0]->IsUndefined());
if (args[0]->IsString()) {
+ ContextInfo* context_info = GetInfoForCurrentContext();
+ if (!context_info)
+ return v8::Undefined();
+
std::string event_name(*v8::String::AsciiValue(args[0]));
- if (EventDecrementListenerCount(event_name) == 0) {
+ if (--context_info->listener_counts[event_name] == 0) {
EventBindings::GetRenderThread()->Send(
- new ViewHostMsg_ExtensionRemoveListener(event_name));
+ new ViewHostMsg_ExtensionRemoveListener(context_info->extension_id,
+ event_name));
}
- ContextInfo* current_context_info = GetInfoForCurrentContext();
- if (current_context_info &&
- --current_context_info->num_connected_events == 0) {
- current_context_info->context.MakeWeak(NULL,
- &ContextWeakReferenceCallback);
+ if (--context_info->num_connected_events == 0) {
+ context_info->context.MakeWeak(NULL, &ContextWeakReferenceCallback);
}
}
@@ -140,15 +130,9 @@ class ExtensionImpl : public ExtensionBase {
// Returns true if the extension running in the given |context| has sufficient
// permissions to access the data.
static bool HasSufficientPermissions(ContextInfo* context,
- bool cross_incognito,
const GURL& event_url) {
v8::Context::Scope context_scope(context->context);
- bool cross_profile_ok = (!cross_incognito ||
- ExtensionProcessBindings::AllowCrossIncognito(context->extension_id));
- if (!cross_profile_ok)
- return false;
-
// During unit tests, we might be invoked without a v8 context. In these
// cases, we only allow empty event_urls and short-circuit before retrieving
// the render view from the current context.
@@ -335,10 +319,10 @@ void EventBindings::HandleContextDestroyed(WebFrame* frame) {
}
// static
-void EventBindings::CallFunction(const std::string& function_name,
+void EventBindings::CallFunction(const std::string& extension_id,
+ const std::string& function_name,
int argc, v8::Handle<v8::Value>* argv,
RenderView* render_view,
- bool cross_incognito,
const GURL& event_url) {
// We copy the context list, because calling into javascript may modify it
// out from under us. We also guard against deleted contexts by checking if
@@ -350,10 +334,13 @@ void EventBindings::CallFunction(const std::string& function_name,
if (render_view && render_view != (*it)->render_view)
continue;
+ if (!extension_id.empty() && extension_id != (*it)->extension_id)
+ continue;
+
if ((*it)->context.IsEmpty())
continue;
- if (!HasSufficientPermissions(it->get(), cross_incognito, event_url))
+ if (!HasSufficientPermissions(it->get(), event_url))
continue;
v8::Handle<v8::Value> retval = CallFunctionInContext((*it)->context,
diff --git a/chrome/renderer/extensions/event_bindings.h b/chrome/renderer/extensions/event_bindings.h
index 788a25c..95b049e 100644
--- a/chrome/renderer/extensions/event_bindings.h
+++ b/chrome/renderer/extensions/event_bindings.h
@@ -41,10 +41,10 @@ class EventBindings {
// bindings_utils::CallFunctionInContext for more details.
// The called javascript function should not return a value other than
// v8::Undefined(). A DCHECK is setup to break if it is otherwise.
- static void CallFunction(const std::string& function_name, int argc,
- v8::Handle<v8::Value>* argv,
+ static void CallFunction(const std::string& extension_id,
+ const std::string& function_name,
+ int argc, v8::Handle<v8::Value>* argv,
RenderView* render_view,
- bool cross_incognito,
const GURL& event_url);
};
diff --git a/chrome/renderer/extensions/extension_process_bindings.cc b/chrome/renderer/extensions/extension_process_bindings.cc
index fed2fe3..bdbb9aa 100644
--- a/chrome/renderer/extensions/extension_process_bindings.cc
+++ b/chrome/renderer/extensions/extension_process_bindings.cc
@@ -63,10 +63,6 @@ typedef std::set<std::string> PermissionsList;
// A map of extension ID to permissions map.
typedef std::map<std::string, PermissionsList> ExtensionPermissionsList;
-// A map of extension ID to whether this extension can access data from other
-// profiles.
-typedef std::map<std::string, bool> CrossIncognitoAccessMap;
-
const char kExtensionName[] = "chrome/ExtensionProcessBindings";
const char* kExtensionDeps[] = {
BaseJsV8Extension::kName,
@@ -80,7 +76,6 @@ struct SingletonData {
std::set<std::string> function_names_;
PageActionIdMap page_action_ids_;
ExtensionPermissionsList permissions_;
- CrossIncognitoAccessMap cross_incognito_access_map_;
};
static std::set<std::string>* GetFunctionNameSet() {
@@ -95,10 +90,6 @@ static PermissionsList* GetPermissionsList(const std::string& extension_id) {
return &Singleton<SingletonData>()->permissions_[extension_id];
}
-static CrossIncognitoAccessMap* GetCrossIncognitoAccessMap() {
- return &Singleton<SingletonData>()->cross_incognito_access_map_;
-}
-
static void GetActiveExtensionIDs(std::set<std::string>* extension_ids) {
ExtensionPermissionsList& permissions =
Singleton<SingletonData>()->permissions_;
@@ -581,22 +572,6 @@ void ExtensionProcessBindings::SetFunctionNames(
ExtensionImpl::SetFunctionNames(names);
}
-void ExtensionProcessBindings::SetIncognitoEnabled(
- const std::string& extension_id, bool enabled, bool incognito_split_mode) {
- // We allow the extension to see events and data from another profile iff it
- // uses "spanning" behavior and it has incognito access. "split" mode
- // extensions only see events for a matching profile.
- (*GetCrossIncognitoAccessMap())[extension_id] =
- enabled && !incognito_split_mode;
-}
-
-// static
-bool ExtensionProcessBindings::AllowCrossIncognito(
- const std::string& extension_id) {
- return (!extension_id.empty() &&
- (*GetCrossIncognitoAccessMap())[extension_id]);
-}
-
// static
void ExtensionProcessBindings::HandleResponse(int request_id, bool success,
const std::string& response,
diff --git a/chrome/renderer/extensions/extension_process_bindings.h b/chrome/renderer/extensions/extension_process_bindings.h
index 251cdd9..4aa4140 100644
--- a/chrome/renderer/extensions/extension_process_bindings.h
+++ b/chrome/renderer/extensions/extension_process_bindings.h
@@ -47,15 +47,6 @@ class ExtensionProcessBindings {
static void SetHostPermissions(const GURL& extension_url,
const std::vector<URLPattern>& permissions);
- // Sets whether incognito is enabled for a particular extension.
- static void SetIncognitoEnabled(const std::string& extension_id,
- bool enabled,
- bool incognito_split_mode);
-
- // Checks whether the given extension can see events/data from another
- // profile (normal to incognito or vice versa).
- static bool AllowCrossIncognito(const std::string& extension_id);
-
// Check if the extension in the currently running context has permission to
// access the given extension function. Must be called with a valid V8
// context in scope.
diff --git a/chrome/renderer/extensions/renderer_extension_bindings.cc b/chrome/renderer/extensions/renderer_extension_bindings.cc
index 2e21c56..b109390 100644
--- a/chrome/renderer/extensions/renderer_extension_bindings.cc
+++ b/chrome/renderer/extensions/renderer_extension_bindings.cc
@@ -295,17 +295,17 @@ v8::Extension* RendererExtensionBindings::Get() {
return extension;
}
-void RendererExtensionBindings::Invoke(const std::string& function_name,
+void RendererExtensionBindings::Invoke(const std::string& extension_id,
+ const std::string& function_name,
const ListValue& args,
RenderView* renderview,
- bool cross_incognito,
const GURL& event_url) {
v8::HandleScope handle_scope;
std::vector< v8::Handle<v8::Value> > argv = ListValueToV8(args);
- EventBindings::CallFunction(function_name,
+ EventBindings::CallFunction(extension_id,
+ function_name,
argv.size(),
&argv[0],
renderview,
- cross_incognito,
event_url);
}
diff --git a/chrome/renderer/extensions/renderer_extension_bindings.h b/chrome/renderer/extensions/renderer_extension_bindings.h
index 7b4280f..194b0c8 100644
--- a/chrome/renderer/extensions/renderer_extension_bindings.h
+++ b/chrome/renderer/extensions/renderer_extension_bindings.h
@@ -25,8 +25,10 @@ class RendererExtensionBindings {
static v8::Extension* Get();
// Call the given javascript function with the specified arguments.
- static void Invoke(const std::string& function_name, const ListValue& args,
- RenderView* renderview, bool cross_incognito,
+ static void Invoke(const std::string& extension_id,
+ const std::string& function_name,
+ const ListValue& args,
+ RenderView* renderview,
const GURL& event_url);
};
diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc
index ebb8af7..4ce5f7f 100644
--- a/chrome/renderer/render_thread.cc
+++ b/chrome/renderer/render_thread.cc
@@ -551,12 +551,6 @@ void RenderThread::OnExtensionSetHostPermissions(
ExtensionProcessBindings::SetHostPermissions(extension_url, permissions);
}
-void RenderThread::OnExtensionSetIncognitoEnabled(
- const std::string& extension_id, bool enabled, bool incognito_split_mode) {
- ExtensionProcessBindings::SetIncognitoEnabled(extension_id, enabled,
- incognito_split_mode);
-}
-
void RenderThread::OnDOMStorageEvent(
const ViewMsg_DOMStorageEvent_Params& params) {
if (!dom_storage_event_dispatcher_.get())
@@ -617,8 +611,6 @@ void RenderThread::OnControlMessageReceived(const IPC::Message& msg) {
OnExtensionSetAPIPermissions)
IPC_MESSAGE_HANDLER(ViewMsg_Extension_SetHostPermissions,
OnExtensionSetHostPermissions)
- IPC_MESSAGE_HANDLER(ViewMsg_Extension_ExtensionSetIncognitoEnabled,
- OnExtensionSetIncognitoEnabled)
IPC_MESSAGE_HANDLER(ViewMsg_DOMStorageEvent,
OnDOMStorageEvent)
#if defined(IPC_MESSAGE_LOG_ENABLED)
@@ -974,12 +966,12 @@ void RenderThread::ScheduleIdleHandler(double initial_delay_s) {
this, &RenderThread::IdleHandler);
}
-void RenderThread::OnExtensionMessageInvoke(const std::string& function_name,
+void RenderThread::OnExtensionMessageInvoke(const std::string& extension_id,
+ const std::string& function_name,
const ListValue& args,
- bool cross_incognito,
const GURL& event_url) {
RendererExtensionBindings::Invoke(
- function_name, args, NULL, cross_incognito, event_url);
+ extension_id, function_name, args, NULL, event_url);
// Reset the idle handler each time there's any activity like event or message
// dispatch, for which Invoke is the chokepoint.
diff --git a/chrome/renderer/render_thread.h b/chrome/renderer/render_thread.h
index 9f2c4c0..a077c3b 100644
--- a/chrome/renderer/render_thread.h
+++ b/chrome/renderer/render_thread.h
@@ -267,10 +267,6 @@ class RenderThread : public RenderThreadBase,
void OnExtensionSetHostPermissions(
const GURL& extension_url,
const std::vector<URLPattern>& permissions);
- void OnExtensionSetIncognitoEnabled(
- const std::string& extension_id,
- bool enabled,
- bool incognito_split_mode);
void OnSetNextPageID(int32 next_page_id);
void OnSetIsIncognitoProcess(bool is_incognito_process);
void OnSetCSSColors(const std::vector<CSSColors::CSSColorMapping>& colors);
@@ -289,9 +285,9 @@ class RenderThread : public RenderThreadBase,
void OnGetRendererTcmalloc();
void OnGetV8HeapStats();
- void OnExtensionMessageInvoke(const std::string& function_name,
+ void OnExtensionMessageInvoke(const std::string& extension_id,
+ const std::string& function_name,
const ListValue& args,
- bool cross_incognito,
const GURL& event_url);
void OnPurgeMemory();
void OnPurgePluginListCache(bool reload_pages);
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 7b2e0a0..8c2a984 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -4947,12 +4947,12 @@ void RenderView::OnExtensionResponse(int request_id,
request_id, success, response, error);
}
-void RenderView::OnExtensionMessageInvoke(const std::string& function_name,
+void RenderView::OnExtensionMessageInvoke(const std::string& extension_id,
+ const std::string& function_name,
const ListValue& args,
- bool cross_incognito,
const GURL& event_url) {
RendererExtensionBindings::Invoke(
- function_name, args, this, cross_incognito, event_url);
+ extension_id, function_name, args, this, event_url);
}
// Dump all load time histograms.
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index 621a68c..57c26ff 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -811,9 +811,9 @@ class RenderView : public RenderWidget,
void OnEnableViewSourceMode();
void OnExecuteCode(const ViewMsg_ExecuteCode_Params& params);
void OnExecuteEditCommand(const std::string& name, const std::string& value);
- void OnExtensionMessageInvoke(const std::string& function_name,
+ void OnExtensionMessageInvoke(const std::string& extension_id,
+ const std::string& function_name,
const ListValue& args,
- bool cross_incognito,
const GURL& event_url);
void OnFileChooserResponse(const std::vector<FilePath>& paths);
void OnFind(int request_id, const string16&, const WebKit::WebFindOptions&);
diff --git a/chrome/renderer/resources/event_bindings.js b/chrome/renderer/resources/event_bindings.js
index f2a82d9..2b8cce8 100644
--- a/chrome/renderer/resources/event_bindings.js
+++ b/chrome/renderer/resources/event_bindings.js
@@ -110,10 +110,10 @@ var chrome = chrome || {};
// Registers a callback to be called when this event is dispatched.
chrome.Event.prototype.addListener = function(cb) {
- this.listeners_.push(cb);
- if (this.listeners_.length == 1) {
+ if (this.listeners_.length == 0) {
this.attach_();
}
+ this.listeners_.push(cb);
};
// Unregisters a callback.
diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js
index 8106782..de00b14 100644
--- a/chrome/renderer/resources/extension_process_bindings.js
+++ b/chrome/renderer/resources/extension_process_bindings.js
@@ -238,7 +238,7 @@ var chrome = chrome || {};
function setupPageActionEvents(extensionId) {
var pageActions = GetCurrentPageActions(extensionId);
- var oldStyleEventName = "pageActions/" + extensionId;
+ var oldStyleEventName = "pageActions";
// TODO(EXTENSIONS_DEPRECATED): only one page action
for (var i = 0; i < pageActions.length; ++i) {
// Setup events for each extension_id/page_action_id string we find.
@@ -264,7 +264,7 @@ var chrome = chrome || {};
chromeHidden.contextMenus = {};
chromeHidden.contextMenus.nextId = 1;
chromeHidden.contextMenus.handlers = {};
- var eventName = "contextMenus/" + extensionId;
+ var eventName = "contextMenus";
chromeHidden.contextMenus.event = new chrome.Event(eventName);
chromeHidden.contextMenus.ensureListenerSetup = function() {
if (chromeHidden.contextMenus.listening) {
@@ -382,8 +382,6 @@ var chrome = chrome || {};
return;
var eventName = apiDef.namespace + "." + eventDef.name;
- if (eventDef.perExtensionEvent)
- eventName = eventName + "/" + extensionId;
module[eventDef.name] = new chrome.Event(eventName,
eventDef.parameters);
});
@@ -422,8 +420,7 @@ var chrome = chrome || {};
if (connectInfo) {
name = connectInfo.name || name;
}
- var portId = OpenChannelToTab(
- tabId, chromeHidden.extensionId, name);
+ var portId = OpenChannelToTab(tabId, chromeHidden.extensionId, name);
return chromeHidden.Port.createPort(portId, name);
};
diff --git a/chrome/test/data/extensions/api_test/events/background.html b/chrome/test/data/extensions/api_test/events/background.html
new file mode 100644
index 0000000..edb2104
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/events/background.html
@@ -0,0 +1,43 @@
+<script>
+chrome.test.runTests([
+ // Tests that attaching and detaching to an event for which we don't have
+ // permission acts as expected (e.g. we don't DCHECK!).
+ function attachAndDetachNoPermisssions() {
+ function dummy() {};
+ try {
+ chrome.tabs.onUpdated.addListener(dummy);
+ chrome.test.fail();
+ } catch (e) {
+ chrome.test.assertTrue(
+ e.message.search("You do not have permission") >= 0,
+ e.message);
+ }
+ chrome.test.assertFalse(chrome.tabs.onUpdated.hasListeners());
+ chrome.tabs.onUpdated.removeListener(dummy); // browser should not DCHECK
+ chrome.test.succeed();
+ },
+
+ // Tests that attaching a named event twice will fail.
+ function doubleAttach() {
+ function dummy() {};
+ var onClicked = new chrome.Event("browserAction.onClicked");
+ var onClicked2 = new chrome.Event("browserAction.onClicked");
+ onClicked.addListener(dummy);
+ chrome.test.assertTrue(onClicked.hasListeners());
+ try {
+ onClicked2.addListener(dummy);
+ chrome.test.fail();
+ } catch (e) {
+ chrome.test.assertTrue(
+ e.message.search("already attached") >= 0,
+ e.message);
+ }
+ chrome.test.assertFalse(onClicked2.hasListeners());
+ onClicked2.removeListener(dummy);
+
+ onClicked.removeListener(dummy);
+ chrome.test.assertFalse(onClicked.hasListeners());
+ chrome.test.succeed();
+ }
+]);
+</script>
diff --git a/chrome/test/data/extensions/api_test/events/manifest.json b/chrome/test/data/extensions/api_test/events/manifest.json
new file mode 100644
index 0000000..dff8194
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/events/manifest.json
@@ -0,0 +1,7 @@
+{
+ "name": "permissions failure apitest",
+ "description": "permissions failure extension",
+ "version": "0.1",
+ "background_page": "background.html",
+ "permissions": [ ]
+}