Remove permission warnings from most tabs and windows APIs.

Patch contributed by 'Chris Hebert <[email protected]>'.
See http://codereview.chromium.org/10829186/

BUG=137404
TBR=jennb,derat,chebert

Review URL: https://chromiumcodereview.appspot.com/10920070

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@154730 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/all_urls_apitest.cc b/chrome/browser/extensions/all_urls_apitest.cc
index e22e8ec..6320644 100644
--- a/chrome/browser/extensions/all_urls_apitest.cc
+++ b/chrome/browser/extensions/all_urls_apitest.cc
@@ -83,7 +83,7 @@
 // Test that an extension NOT whitelisted for scripting can ask for <all_urls>
 // and run scripts on non-restricted all pages.
 IN_PROC_BROWSER_TEST_F(AllUrlsApiTest, RegularExtensions) {
-  // First load the two extension.
+  // First load the two extensions.
   FilePath extension_dir1 = test_data_dir_.AppendASCII("all_urls")
                                           .AppendASCII("content_script");
   FilePath extension_dir2 = test_data_dir_.AppendASCII("all_urls")
diff --git a/chrome/browser/extensions/api/messaging/message_service.cc b/chrome/browser/extensions/api/messaging/message_service.cc
index 807cc4d9..b5ed615 100644
--- a/chrome/browser/extensions/api/messaging/message_service.cc
+++ b/chrome/browser/extensions/api/messaging/message_service.cc
@@ -219,8 +219,10 @@
   // Include info about the opener's tab (if it was a tab).
   std::string tab_json = "null";
   if (source_contents) {
-    scoped_ptr<DictionaryValue> tab_value(
-        ExtensionTabUtil::CreateTabValue(source_contents));
+    scoped_ptr<DictionaryValue> tab_value(ExtensionTabUtil::CreateTabValue(
+            source_contents,
+            profile->GetExtensionService()->extensions()->GetByID(
+                source_extension_id)));
     base::JSONWriter::Write(tab_value.get(), &tab_json);
   }
 
@@ -271,8 +273,10 @@
   // Include info about the opener's tab (if it was a tab).
   std::string tab_json = "null";
   if (source_contents) {
-    scoped_ptr<DictionaryValue> tab_value(
-        ExtensionTabUtil::CreateTabValue(source_contents));
+    scoped_ptr<DictionaryValue> tab_value(ExtensionTabUtil::CreateTabValue(
+            source_contents,
+            profile->GetExtensionService()->extensions()->GetByID(
+                extension_id)));
     base::JSONWriter::Write(tab_value.get(), &tab_json);
   }
 
diff --git a/chrome/browser/extensions/api/permissions/permissions_apitest.cc b/chrome/browser/extensions/api/permissions/permissions_apitest.cc
index 3744a85..3e856ab 100644
--- a/chrome/browser/extensions/api/permissions/permissions_apitest.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_apitest.cc
@@ -73,7 +73,7 @@
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, OptionalPermissionsGranted) {
   // Mark all the tested APIs as granted to bypass the confirmation UI.
   APIPermissionSet apis;
-  apis.insert(APIPermission::kTab);
+  apis.insert(APIPermission::kBookmark);
   URLPatternSet explicit_hosts;
   AddPattern(&explicit_hosts, "http://*.c.com/*");
   scoped_refptr<PermissionSet> granted_permissions =
diff --git a/chrome/browser/extensions/api/tabs/tabs.cc b/chrome/browser/extensions/api/tabs/tabs.cc
index 78d1881a..45cb0972 100644
--- a/chrome/browser/extensions/api/tabs/tabs.cc
+++ b/chrome/browser/extensions/api/tabs/tabs.cc
@@ -263,7 +263,7 @@
     return false;
 
   if (populate_tabs)
-    SetResult(controller->CreateWindowValueWithTabs());
+    SetResult(controller->CreateWindowValueWithTabs(GetExtension()));
   else
     SetResult(controller->CreateWindowValue());
   return true;
@@ -284,7 +284,7 @@
     return false;
   }
   if (populate_tabs)
-    SetResult(controller->CreateWindowValueWithTabs());
+    SetResult(controller->CreateWindowValueWithTabs(GetExtension()));
   else
     SetResult(controller->CreateWindowValue());
   return true;
@@ -311,7 +311,7 @@
   WindowController* controller =
       browser->extension_window_controller();
   if (populate_tabs)
-    SetResult(controller->CreateWindowValueWithTabs());
+    SetResult(controller->CreateWindowValueWithTabs(GetExtension()));
   else
     SetResult(controller->CreateWindowValue());
   return true;
@@ -334,7 +334,7 @@
     if (!this->CanOperateOnWindow(*iter))
       continue;
     if (populate_tabs)
-      window_list->Append((*iter)->CreateWindowValueWithTabs());
+      window_list->Append((*iter)->CreateWindowValueWithTabs(GetExtension()));
     else
       window_list->Append((*iter)->CreateWindowValue());
   }
@@ -586,7 +586,8 @@
         panel->Show();
 
     SetResult(
-        panel->extension_window_controller()->CreateWindowValueWithTabs());
+        panel->extension_window_controller()->CreateWindowValueWithTabs(
+            GetExtension()));
     return true;
   }
 #endif
@@ -638,7 +639,8 @@
     SetResult(Value::CreateNullValue());
   } else {
     SetResult(
-        new_window->extension_window_controller()->CreateWindowValueWithTabs());
+        new_window->extension_window_controller()->CreateWindowValueWithTabs(
+            GetExtension()));
   }
 
   return true;
@@ -819,7 +821,8 @@
   }
   SetResult(ExtensionTabUtil::CreateTabValue(contents->web_contents(),
                                              tab_strip,
-                                             tab_strip->active_index()));
+                                             tab_strip->active_index(),
+                                             GetExtension()));
   return true;
 }
 
@@ -833,7 +836,7 @@
   if (!GetBrowserFromWindowID(this, window_id, &browser))
     return false;
 
-  SetResult(ExtensionTabUtil::CreateTabList(browser));
+  SetResult(ExtensionTabUtil::CreateTabList(browser, GetExtension()));
 
   return true;
 }
@@ -944,7 +947,7 @@
         continue;
 
       result->Append(ExtensionTabUtil::CreateTabValue(
-          web_contents, tab_strip, i));
+          web_contents, tab_strip, i, GetExtension()));
     }
   }
 
@@ -1019,13 +1022,11 @@
   // be used instead).
   bool active = true;
   if (args->HasKey(keys::kSelectedKey))
-    EXTENSION_FUNCTION_VALIDATE(
-        args->GetBoolean(keys::kSelectedKey, &active));
+    EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kSelectedKey, &active));
 
   // The 'active' property has replaced the 'selected' property.
   if (args->HasKey(keys::kActiveKey))
-    EXTENSION_FUNCTION_VALIDATE(
-        args->GetBoolean(keys::kActiveKey, &active));
+    EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kActiveKey, &active));
 
   // Default to not pinning the tab. Setting the 'pinned' property to true
   // will override this default.
@@ -1081,7 +1082,7 @@
   if (has_callback()) {
     SetResult(ExtensionTabUtil::CreateTabValue(
         params.target_contents->web_contents(),
-        tab_strip, new_index));
+        tab_strip, new_index, GetExtension()));
   }
 
   return true;
@@ -1100,7 +1101,8 @@
 
   SetResult(ExtensionTabUtil::CreateTabValue(contents->web_contents(),
                                              tab_strip,
-                                             tab_index));
+                                             tab_index,
+                                             GetExtension()));
   return true;
 }
 
@@ -1109,7 +1111,7 @@
 
   WebContents* contents = dispatcher()->delegate()->GetAssociatedWebContents();
   if (contents)
-    SetResult(ExtensionTabUtil::CreateTabValue(contents));
+    SetResult(ExtensionTabUtil::CreateTabValue(contents, GetExtension()));
 
   return true;
 }
@@ -1166,7 +1168,8 @@
   selection.set_active(active_index);
   browser->tab_strip_model()->SetSelectionFromModel(selection);
   SetResult(
-      browser->extension_window_controller()->CreateWindowValueWithTabs());
+      browser->extension_window_controller()->CreateWindowValueWithTabs(
+          GetExtension()));
   return true;
 }
 
@@ -1342,11 +1345,8 @@
   if (!has_callback())
     return;
 
-  if (GetExtension()->HasAPIPermission(extensions::APIPermission::kTab)) {
-    SetResult(ExtensionTabUtil::CreateTabValue(tab_contents_->web_contents()));
-  } else {
-    SetResult(Value::CreateNullValue());
-  }
+  SetResult(ExtensionTabUtil::CreateTabValue(tab_contents_->web_contents(),
+                                             GetExtension()));
 }
 
 void UpdateTabFunction::OnExecuteCodeFinished(const std::string& error,
@@ -1438,9 +1438,13 @@
         target_tab_strip->InsertTabContentsAt(
             new_index, contents, TabStripModel::ADD_NONE);
 
-        if (has_callback())
+        if (has_callback()) {
           tab_values.Append(ExtensionTabUtil::CreateTabValue(
-              contents->web_contents(), target_tab_strip, new_index));
+              contents->web_contents(),
+              target_tab_strip,
+              new_index,
+              GetExtension()));
+        }
 
         continue;
       }
@@ -1456,9 +1460,11 @@
     if (new_index != tab_index)
       source_tab_strip->MoveTabContentsAt(tab_index, new_index, false);
 
-    if (has_callback())
+    if (has_callback()) {
       tab_values.Append(ExtensionTabUtil::CreateTabValue(
-          contents->web_contents(), source_tab_strip, new_index));
+          contents->web_contents(), source_tab_strip, new_index,
+          GetExtension()));
+    }
   }
 
   if (!has_callback())
diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc
index 1f74f52..dfe8f62 100644
--- a/chrome/browser/extensions/api/tabs/tabs_test.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_test.cc
@@ -37,6 +37,8 @@
 
   // Invalid window ID error.
   scoped_refptr<GetWindowFunction> function = new GetWindowFunction();
+  scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension());
+  function->set_extension(extension.get());
   EXPECT_TRUE(MatchPattern(
       utils::RunFunctionAndReturnError(
           function.get(),
@@ -52,6 +54,7 @@
     bounds = browser()->window()->GetBounds();
 
   function = new GetWindowFunction();
+  function->set_extension(extension.get());
   scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
       utils::RunFunctionAndReturnSingleResult(
           function.get(),
@@ -67,6 +70,7 @@
 
   // With "populate" enabled.
   function = new GetWindowFunction();
+  function->set_extension(extension.get());
   result.reset(utils::ToDictionary(
       utils::RunFunctionAndReturnSingleResult(
           function.get(),
@@ -91,6 +95,7 @@
   Browser* popup_browser = new Browser(
       Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile()));
   function = new GetWindowFunction();
+  function->set_extension(extension.get());
   result.reset(utils::ToDictionary(
       utils::RunFunctionAndReturnSingleResult(
           function.get(),
@@ -103,6 +108,7 @@
   Browser* panel_browser = new Browser(
       Browser::CreateParams(Browser::TYPE_PANEL, browser()->profile()));
   function = new GetWindowFunction();
+  function->set_extension(extension.get());
   result.reset(utils::ToDictionary(
       utils::RunFunctionAndReturnSingleResult(
           function.get(),
@@ -117,6 +123,7 @@
 
   // Without "include_incognito".
   function = new GetWindowFunction();
+  function->set_extension(extension.get());
   EXPECT_TRUE(MatchPattern(
       utils::RunFunctionAndReturnError(
           function.get(),
@@ -126,6 +133,7 @@
 
   // With "include_incognito".
   function = new GetWindowFunction();
+  function->set_extension(extension.get());
   result.reset(utils::ToDictionary(
       utils::RunFunctionAndReturnSingleResult(
           function.get(),
@@ -143,6 +151,8 @@
   // Get the current window using new_browser.
   scoped_refptr<GetCurrentWindowFunction> function =
       new GetCurrentWindowFunction();
+  scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension());
+  function->set_extension(extension.get());
   scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
       utils::RunFunctionAndReturnSingleResult(function.get(),
                                               "[]",
@@ -156,6 +166,7 @@
 
   // Get the current window using the old window and make the tabs populated.
   function = new GetCurrentWindowFunction();
+  function->set_extension(extension.get());
   result.reset(utils::ToDictionary(
       utils::RunFunctionAndReturnSingleResult(function.get(),
                                               "[{\"populate\": true}]",
@@ -176,6 +187,8 @@
 
   scoped_refptr<GetLastFocusedWindowFunction> function =
       new GetLastFocusedWindowFunction();
+  scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension());
+  function->set_extension(extension.get());
   scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
       utils::RunFunctionAndReturnSingleResult(function.get(),
                                               "[]",
@@ -188,6 +201,7 @@
   EXPECT_FALSE(result.get()->GetList(keys::kTabsKey, &tabs));
 
   function = new GetLastFocusedWindowFunction();
+  function->set_extension(extension.get());
   result.reset(utils::ToDictionary(
       utils::RunFunctionAndReturnSingleResult(function.get(),
                                               "[{\"populate\": true}]",
@@ -212,6 +226,8 @@
   }
 
   scoped_refptr<GetAllWindowsFunction> function = new GetAllWindowsFunction();
+  scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension());
+  function->set_extension(extension.get());
   scoped_ptr<base::ListValue> result(utils::ToList(
       utils::RunFunctionAndReturnSingleResult(function.get(),
                                               "[]",
@@ -233,6 +249,7 @@
 
   result_ids.clear();
   function = new GetAllWindowsFunction();
+  function->set_extension(extension.get());
   result.reset(utils::ToList(
       utils::RunFunctionAndReturnSingleResult(function.get(),
                                               "[{\"populate\": true}]",
@@ -263,11 +280,14 @@
   // Without a callback the function will not generate a result.
   update_tab_function->set_has_callback(true);
 
-  scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult(
+  scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
+      utils::RunFunctionAndReturnSingleResult(
           update_tab_function.get(),
-          "[null, {\"url\": \"neutrinos\"}]",
-          browser()));
-  EXPECT_EQ(base::Value::TYPE_NULL, result->GetType());
+          "[null, {\"url\": \"about:blank\", \"pinned\": true}]",
+          browser())));
+  // The url is stripped since the extension does not have tab permissions.
+  EXPECT_FALSE(result->HasKey("url"));
+  EXPECT_TRUE(utils::GetBoolean(result.get(), "pinned"));
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,
@@ -278,7 +298,9 @@
   IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(),
                                       IncognitoModePrefs::FORCED);
   // Run without an explicit "incognito" param.
-  scoped_refptr<CreateWindowFunction> function = new CreateWindowFunction();
+  scoped_refptr<CreateWindowFunction> function(new CreateWindowFunction());
+  scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension());
+  function->set_extension(extension.get());
   scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
       utils::RunFunctionAndReturnSingleResult(
           function.get(),
@@ -296,6 +318,7 @@
   Browser* incognito_browser = CreateIncognitoBrowser();
   // Run without an explicit "incognito" param.
   function = new CreateWindowFunction();
+  function->set_extension(extension.get());
   result.reset(utils::ToDictionary(
       utils::RunFunctionAndReturnSingleResult(
           function.get(),
@@ -317,6 +340,8 @@
                                       IncognitoModePrefs::FORCED);
   // Run without an explicit "incognito" param.
   scoped_refptr<CreateWindowFunction> function = new CreateWindowFunction();
+  scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension());
+  function->set_extension(extension.get());
   scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
       utils::RunFunctionAndReturnSingleResult(function.get(),
                                               kEmptyArgs,
@@ -333,6 +358,7 @@
   Browser* incognito_browser = CreateIncognitoBrowser();
   // Run without an explicit "incognito" param.
   function = new CreateWindowFunction();
+  function->set_extension(extension.get());
   result.reset(utils::ToDictionary(
       utils::RunFunctionAndReturnSingleResult(function.get(),
                                               kEmptyArgs,
@@ -355,6 +381,8 @@
 
   // Run with an explicit "incognito" param.
   scoped_refptr<CreateWindowFunction> function = new CreateWindowFunction();
+  scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension());
+  function->set_extension(extension.get());
   EXPECT_TRUE(MatchPattern(
       utils::RunFunctionAndReturnError(function.get(),
                                        kArgsWithExplicitIncognitoParam,
@@ -365,6 +393,7 @@
   Browser* incognito_browser = CreateIncognitoBrowser();
   // Run with an explicit "incognito" param.
   function = new CreateWindowFunction();
+  function->set_extension(extension.get());
   EXPECT_TRUE(MatchPattern(
       utils::RunFunctionAndReturnError(function.get(),
                                        kArgsWithExplicitIncognitoParam,
@@ -383,6 +412,8 @@
                                       IncognitoModePrefs::DISABLED);
   // Run in normal window.
   scoped_refptr<CreateWindowFunction> function = new CreateWindowFunction();
+  scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension());
+  function->set_extension(extension.get());
   EXPECT_TRUE(MatchPattern(
       utils::RunFunctionAndReturnError(function.get(),
                                        kArgs,
@@ -391,6 +422,7 @@
 
   // Run in incognito window.
   function = new CreateWindowFunction();
+  function->set_extension(extension.get());
   EXPECT_TRUE(MatchPattern(
       utils::RunFunctionAndReturnError(function.get(),
                                        kArgs,
@@ -409,6 +441,7 @@
 
   // Get tabs in the 'current' window called from non-focused browser.
   scoped_refptr<QueryTabsFunction> function = new QueryTabsFunction();
+  function->set_extension(utils::CreateEmptyExtension().get());
   scoped_ptr<base::ListValue> result(utils::ToList(
       utils::RunFunctionAndReturnSingleResult(function.get(),
                                               "[{\"currentWindow\":true}]",
@@ -425,6 +458,7 @@
 
   // Get tabs NOT in the 'current' window called from non-focused browser.
   function = new QueryTabsFunction();
+  function->set_extension(utils::CreateEmptyExtension().get());
   result.reset(utils::ToList(
       utils::RunFunctionAndReturnSingleResult(function.get(),
                                               "[{\"currentWindow\":false}]",
@@ -506,6 +540,7 @@
   chrome::CloseWindow(popup_browser);
 
   scoped_refptr<CreateTabFunction> create_tab_function(new CreateTabFunction());
+  create_tab_function->set_extension(utils::CreateEmptyExtension().get());
   // Without a callback the function will not generate a result.
   create_tab_function->set_has_callback(true);
 
@@ -527,6 +562,8 @@
   static const char kArgsMinimizedWithFocus[] =
       "[%u, {\"state\": \"minimized\", \"focused\": true}]";
   scoped_refptr<UpdateWindowFunction> function = new UpdateWindowFunction();
+  scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension());
+  function->set_extension(extension.get());
   EXPECT_TRUE(MatchPattern(
       utils::RunFunctionAndReturnError(
           function.get(),
@@ -537,6 +574,7 @@
   static const char kArgsMaximizedWithoutFocus[] =
       "[%u, {\"state\": \"maximized\", \"focused\": false}]";
   function = new UpdateWindowFunction();
+  function->set_extension(extension.get());
   EXPECT_TRUE(MatchPattern(
       utils::RunFunctionAndReturnError(
           function.get(),
@@ -547,6 +585,7 @@
   static const char kArgsMinimizedWithBounds[] =
       "[%u, {\"state\": \"minimized\", \"width\": 500}]";
   function = new UpdateWindowFunction();
+  function->set_extension(extension.get());
   EXPECT_TRUE(MatchPattern(
       utils::RunFunctionAndReturnError(
           function.get(),
@@ -557,6 +596,7 @@
   static const char kArgsMaximizedWithBounds[] =
       "[%u, {\"state\": \"maximized\", \"width\": 500}]";
   function = new UpdateWindowFunction();
+  function->set_extension(extension.get());
   EXPECT_TRUE(MatchPattern(
       utils::RunFunctionAndReturnError(
           function.get(),
diff --git a/chrome/browser/extensions/browser_event_router.cc b/chrome/browser/extensions/browser_event_router.cc
index 1aa89c5..af5cf9b 100644
--- a/chrome/browser/extensions/browser_event_router.cc
+++ b/chrome/browser/extensions/browser_event_router.cc
@@ -384,18 +384,35 @@
     const char* event_name,
     const WebContents* web_contents,
     bool active,
-    EventRouter::UserGestureState user_gesture) {
+    EventRouter::UserGestureState user_gesture,
+    scoped_ptr<ListValue> event_args) {
   if (!profile_->IsSameProfile(profile))
     return;
 
-  scoped_ptr<ListValue> args(new ListValue());
-  args->Append(ExtensionTabUtil::CreateTabValueActive(
-      web_contents, active));
   if (!extension_id.empty()) {
-    DispatchEventToExtension(profile, extension_id, event_name, args.Pass(),
-                             user_gesture);
+    event_args->Append(ExtensionTabUtil::CreateTabValueActive(
+        web_contents,
+        active,
+        profile->GetExtensionService()->extensions()->GetByID(extension_id)));
+    DispatchEventToExtension(profile, extension_id, event_name,
+                             event_args.Pass(), user_gesture);
   } else {
-    DispatchEvent(profile, event_name, args.Pass(), user_gesture);
+    const EventListenerMap::ListenerList& listeners(
+        ExtensionSystem::Get(profile)->event_router()->
+        listeners().GetEventListenersByName(event_name));
+
+    for (EventListenerMap::ListenerList::const_iterator it = listeners.begin();
+         it != listeners.end();
+         ++it) {
+      scoped_ptr<ListValue> args(event_args->DeepCopy());
+      args->Append(ExtensionTabUtil::CreateTabValueActive(
+          web_contents,
+          active,
+          profile->GetExtensionService()->extensions()->GetByID(
+              (*it)->extension_id)));
+      DispatchEventToExtension(profile, (*it)->extension_id, event_name,
+                               args.Pass(), user_gesture);
+    }
   }
 }
 
@@ -427,11 +444,10 @@
   args->Append(changed_properties);
 
   // Third arg: An object containing the state of the tab.
-  args->Append(ExtensionTabUtil::CreateTabValue(contents));
-
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
-  DispatchEvent(profile, events::kOnTabUpdated, args.Pass(),
-                EventRouter::USER_GESTURE_UNKNOWN);
+
+  DispatchEventWithTab(profile, "", events::kOnTabUpdated, contents, true,
+                       EventRouter::USER_GESTURE_UNKNOWN, args.Pass());
 }
 
 BrowserEventRouter::TabEntry* BrowserEventRouter::GetTabEntry(
diff --git a/chrome/browser/extensions/browser_event_router.h b/chrome/browser/extensions/browser_event_router.h
index c9edaee..69732c2 100644
--- a/chrome/browser/extensions/browser_event_router.h
+++ b/chrome/browser/extensions/browser_event_router.h
@@ -127,7 +127,20 @@
                             const char* event_name,
                             const content::WebContents* web_contents,
                             bool active,
-                            EventRouter::UserGestureState user_gesture);
+                            EventRouter::UserGestureState user_gesture,
+                            scoped_ptr<ListValue> event_args);
+
+  // DispatchEvent with a tab value appended as the last argument.
+  void DispatchEventWithTab(Profile* profile,
+                            const std::string& extension_id,
+                            const char* event_name,
+                            const content::WebContents* web_contents,
+                            bool active,
+                            EventRouter::UserGestureState user_gesture) {
+    DispatchEventWithTab(profile, extension_id, event_name, web_contents,
+                         active, user_gesture,
+                         scoped_ptr<ListValue>(new ListValue).Pass());
+  }
 
   void DispatchSimpleBrowserEvent(Profile* profile,
                                   const int window_id,
diff --git a/chrome/browser/extensions/browser_extension_window_controller.cc b/chrome/browser/extensions/browser_extension_window_controller.cc
index 54792bc..817971df 100644
--- a/chrome/browser/extensions/browser_extension_window_controller.cc
+++ b/chrome/browser/extensions/browser_extension_window_controller.cc
@@ -48,10 +48,12 @@
 }
 
 base::DictionaryValue*
-BrowserExtensionWindowController::CreateWindowValueWithTabs() const {
+BrowserExtensionWindowController::CreateWindowValueWithTabs(
+    const extensions::Extension* extension) const {
   DictionaryValue* result = CreateWindowValue();
 
-  result->Set(keys::kTabsKey, ExtensionTabUtil::CreateTabList(browser_));
+  result->Set(keys::kTabsKey, ExtensionTabUtil::CreateTabList(browser_,
+                                                              extension));
 
   return result;
 }
diff --git a/chrome/browser/extensions/browser_extension_window_controller.h b/chrome/browser/extensions/browser_extension_window_controller.h
index 9837422d..a1e220a 100644
--- a/chrome/browser/extensions/browser_extension_window_controller.h
+++ b/chrome/browser/extensions/browser_extension_window_controller.h
@@ -9,6 +9,10 @@
 
 class Browser;
 
+namespace extensions {
+class Extension;
+}
+
 class BrowserExtensionWindowController : public extensions::WindowController {
  public:
   explicit BrowserExtensionWindowController(Browser* browser);
@@ -18,7 +22,8 @@
   virtual int GetWindowId() const OVERRIDE;
   virtual std::string GetWindowTypeText() const OVERRIDE;
   virtual base::DictionaryValue* CreateWindowValue() const OVERRIDE;
-  virtual base::DictionaryValue* CreateWindowValueWithTabs() const OVERRIDE;
+  virtual base::DictionaryValue* CreateWindowValueWithTabs(
+      const extensions::Extension* extension) const OVERRIDE;
   virtual bool CanClose(Reason* reason) const OVERRIDE;
   virtual void SetFullscreenMode(bool is_fullscreen,
                                  const GURL& extension_url) const OVERRIDE;
diff --git a/chrome/browser/extensions/event_listener_map.h b/chrome/browser/extensions/event_listener_map.h
index 6c5c304..d252900 100644
--- a/chrome/browser/extensions/event_listener_map.h
+++ b/chrome/browser/extensions/event_listener_map.h
@@ -93,8 +93,11 @@
   bool RemoveListener(const EventListener* listener);
 
   // Returns the set of listeners that want to be notified of |event|.
-  std::set<const EventListener*> GetEventListeners(
-      const Event& event);
+  std::set<const EventListener*> GetEventListeners(const Event& event);
+
+  const ListenerList& GetEventListenersByName(const std::string& event_name) {
+    return listeners_[event_name];
+  }
 
   // Removes all listeners with process equal to |process|.
   void RemoveListenersForProcess(const content::RenderProcessHost* process);
diff --git a/chrome/browser/extensions/event_router.cc b/chrome/browser/extensions/event_router.cc
index 8be11a65..4e65e6da 100644
--- a/chrome/browser/extensions/event_router.cc
+++ b/chrome/browser/extensions/event_router.cc
@@ -523,9 +523,10 @@
     return;
 
   if (listeners_.HasProcessListener(host->render_process_host(),
-                                    host->extension()->id()))
+                                    host->extension()->id())) {
     DispatchEventToProcess(host->extension()->id(),
                            host->render_process_host(), event);
+  }
 }
 
 void EventRouter::Observe(int type,
diff --git a/chrome/browser/extensions/event_router.h b/chrome/browser/extensions/event_router.h
index 97d2254..891f34da 100644
--- a/chrome/browser/extensions/event_router.h
+++ b/chrome/browser/extensions/event_router.h
@@ -68,6 +68,8 @@
                            content::RenderProcessHost* process,
                            const std::string& extension_id);
 
+  EventListenerMap& listeners() { return listeners_; }
+
   // Add or remove the extension as having a lazy background page that listens
   // to the event. The difference from the above methods is that these will be
   // remembered even after the process goes away. We use this list to decide
diff --git a/chrome/browser/extensions/execute_script_apitest.cc b/chrome/browser/extensions/execute_script_apitest.cc
index 1edb4403..c441644 100644
--- a/chrome/browser/extensions/execute_script_apitest.cc
+++ b/chrome/browser/extensions/execute_script_apitest.cc
@@ -36,8 +36,7 @@
 }
 
 // If failing, mark disabled and update http://crbug.com/84760.
-IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest,
-                       ExecuteScriptFileAfterClose) {
+IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest, ExecuteScriptFileAfterClose) {
   host_resolver()->AddRule("b.com", "127.0.0.1");
   ASSERT_TRUE(StartTestServer());
   ASSERT_TRUE(RunExtensionTest("executescript/file_after_close")) << message_;
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc
index 8d49ea7..7af6607 100644
--- a/chrome/browser/extensions/extension_tab_util.cc
+++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
+#include "chrome/common/extensions/permissions/api_permission.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/favicon_status.h"
 #include "content/public/browser/navigation_entry.h"
@@ -30,6 +31,8 @@
 
 using content::NavigationEntry;
 using content::WebContents;
+using extensions::APIPermission;
+using extensions::Extension;
 
 int ExtensionTabUtil::GetWindowId(const Browser* browser) {
   return browser->session_id().id();
@@ -58,38 +61,49 @@
       TabContents::FromWebContents(web_contents));
 }
 
-DictionaryValue* ExtensionTabUtil::CreateTabValue(const WebContents* contents) {
+DictionaryValue* ExtensionTabUtil::CreateTabValue(
+    const WebContents* contents,
+    const Extension* extension) {
   // Find the tab strip and index of this guy.
   TabStripModel* tab_strip = NULL;
   int tab_index;
-  if (ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index))
-    return ExtensionTabUtil::CreateTabValue(contents, tab_strip, tab_index);
+  if (ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index)) {
+    return ExtensionTabUtil::CreateTabValue(contents,
+                                            tab_strip,
+                                            tab_index,
+                                            extension);
+  }
 
   // Couldn't find it.  This can happen if the tab is being dragged.
-  return ExtensionTabUtil::CreateTabValue(contents, NULL, -1);
+  return ExtensionTabUtil::CreateTabValue(contents, NULL, -1, extension);
 }
 
-ListValue* ExtensionTabUtil::CreateTabList(const Browser* browser) {
+ListValue* ExtensionTabUtil::CreateTabList(
+    const Browser* browser,
+    const Extension* extension) {
   ListValue* tab_list = new ListValue();
   TabStripModel* tab_strip = browser->tab_strip_model();
   for (int i = 0; i < tab_strip->count(); ++i) {
-    tab_list->Append(ExtensionTabUtil::CreateTabValue(
-        tab_strip->GetTabContentsAt(i)->web_contents(), tab_strip, i));
+    tab_list->Append(CreateTabValue(
+        tab_strip->GetTabContentsAt(i)->web_contents(),
+        tab_strip,
+        i,
+        extension));
   }
 
   return tab_list;
 }
 
-DictionaryValue* ExtensionTabUtil::CreateTabValue(const WebContents* contents,
-                                                  TabStripModel* tab_strip,
-                                                  int tab_index) {
+DictionaryValue* ExtensionTabUtil::CreateTabValue(
+    const WebContents* contents,
+    TabStripModel* tab_strip,
+    int tab_index,
+    const Extension* extension) {
   DictionaryValue* result = new DictionaryValue();
   bool is_loading = contents->IsLoading();
-  result->SetInteger(keys::kIdKey, ExtensionTabUtil::GetTabId(contents));
+  result->SetInteger(keys::kIdKey, GetTabId(contents));
   result->SetInteger(keys::kIndexKey, tab_index);
-  result->SetInteger(keys::kWindowIdKey,
-                     ExtensionTabUtil::GetWindowIdOfTab(contents));
-  result->SetString(keys::kUrlKey, contents->GetURL().spec());
+  result->SetInteger(keys::kWindowIdKey, GetWindowIdOfTab(contents));
   result->SetString(keys::kStatusKey, GetTabStatusText(is_loading));
   result->SetBoolean(keys::kActiveKey,
                      tab_strip && tab_index == tab_strip->active_index());
@@ -99,24 +113,42 @@
                    tab_strip && tab_strip->IsTabSelected(tab_index));
   result->SetBoolean(keys::kPinnedKey,
                      tab_strip && tab_strip->IsTabPinned(tab_index));
-  result->SetString(keys::kTitleKey, contents->GetTitle());
   result->SetBoolean(keys::kIncognitoKey,
                      contents->GetBrowserContext()->IsOffTheRecord());
 
+  // Only add privacy-sensitive data if the requesting extension has the tabs
+  // permission.
+  bool has_permission = false;
+  if (extension) {
+    if (tab_index >= 0) {
+      has_permission =
+          extension->HasAPIPermissionForTab(
+              tab_index, APIPermission::kTab) ||
+          extension->HasAPIPermissionForTab(
+              tab_index, APIPermission::kWebNavigation);
+    } else {
+      has_permission =
+          extension->HasAPIPermission(APIPermission::kTab) ||
+          extension->HasAPIPermission(APIPermission::kWebNavigation);
+    }
+  }
+
+  if (has_permission) {
+    result->SetString(keys::kUrlKey, contents->GetURL().spec());
+    result->SetString(keys::kTitleKey, contents->GetTitle());
+    if (!is_loading) {
+      NavigationEntry* entry = contents->GetController().GetActiveEntry();
+      if (entry && entry->GetFavicon().valid)
+        result->SetString(keys::kFaviconUrlKey, entry->GetFavicon().url.spec());
+    }
+  }
+
   if (tab_strip) {
     content::NavigationController* opener =
         tab_strip->GetOpenerOfTabContentsAt(tab_index);
     if (opener) {
       result->SetInteger(keys::kOpenerTabIdKey,
-                         ExtensionTabUtil::GetTabId(opener->GetWebContents()));
-    }
-  }
-
-  if (!is_loading) {
-    NavigationEntry* entry = contents->GetController().GetActiveEntry();
-    if (entry) {
-      if (entry->GetFavicon().valid)
-        result->SetString(keys::kFaviconUrlKey, entry->GetFavicon().url.spec());
+                         GetTabId(opener->GetWebContents()));
     }
   }
 
@@ -125,8 +157,9 @@
 
 DictionaryValue* ExtensionTabUtil::CreateTabValueActive(
     const WebContents* contents,
-    bool active) {
-  DictionaryValue* result = ExtensionTabUtil::CreateTabValue(contents);
+    bool active,
+    const extensions::Extension* extension) {
+  DictionaryValue* result = CreateTabValue(contents, extension);
   result->SetBoolean(keys::kSelectedKey, active);
   return result;
 }
@@ -161,7 +194,7 @@
   *contents = chrome::GetActiveTabContents(browser);
   if (*contents) {
     if (tab_id)
-      *tab_id = ExtensionTabUtil::GetTabId((*contents)->web_contents());
+      *tab_id = GetTabId((*contents)->web_contents());
     return true;
   }
 
diff --git a/chrome/browser/extensions/extension_tab_util.h b/chrome/browser/extensions/extension_tab_util.h
index ec87b266..0261164 100644
--- a/chrome/browser/extensions/extension_tab_util.h
+++ b/chrome/browser/extensions/extension_tab_util.h
@@ -42,17 +42,22 @@
   static int GetTabId(const content::WebContents* web_contents);
   static std::string GetTabStatusText(bool is_loading);
   static int GetWindowIdOfTab(const content::WebContents* web_contents);
-  static base::ListValue* CreateTabList(const Browser* browser);
+  static base::ListValue* CreateTabList(
+      const Browser* browser,
+      const extensions::Extension* extension);
   static base::DictionaryValue* CreateTabValue(
-      const content::WebContents* web_contents);
+      const content::WebContents* web_contents,
+      const extensions::Extension* extension);
   static base::DictionaryValue* CreateTabValue(
       const content::WebContents* web_contents,
       TabStripModel* tab_strip,
-      int tab_index);
+      int tab_index,
+      const extensions::Extension* extension);
   // Create a tab value, overriding its kSelectedKey to the provided boolean.
   static base::DictionaryValue* CreateTabValueActive(
       const content::WebContents* web_contents,
-      bool active);
+      bool active,
+      const extensions::Extension* extension);
 
   // Gets the |tab_strip_model| and |tab_index| for the given |web_contents|.
   static bool GetTabStripModel(const content::WebContents* web_contents,
diff --git a/chrome/browser/extensions/extension_tab_util_android.cc b/chrome/browser/extensions/extension_tab_util_android.cc
index 2d8d641..2e0b51a 100644
--- a/chrome/browser/extensions/extension_tab_util_android.cc
+++ b/chrome/browser/extensions/extension_tab_util_android.cc
@@ -32,26 +32,33 @@
   return -1;
 }
 
-DictionaryValue* ExtensionTabUtil::CreateTabValue(const WebContents* contents) {
+DictionaryValue* ExtensionTabUtil::CreateTabValue(
+    const WebContents* contents,
+    const extensions::Extension* extension) {
   NOTIMPLEMENTED();
   return NULL;
 }
 
-ListValue* ExtensionTabUtil::CreateTabList(const Browser* browser) {
+ListValue* ExtensionTabUtil::CreateTabList(
+    const Browser* browser,
+    const extensions::Extension* extension) {
   NOTIMPLEMENTED();
   return NULL;
 }
 
-DictionaryValue* ExtensionTabUtil::CreateTabValue(const WebContents* contents,
-                                                  TabStripModel* tab_strip,
-                                                  int tab_index) {
+DictionaryValue* ExtensionTabUtil::CreateTabValue(
+    const WebContents* contents,
+    TabStripModel* tab_strip,
+    int tab_index,
+    const extensions::Extension* extension) {
   NOTIMPLEMENTED();
   return NULL;
 }
 
 DictionaryValue* ExtensionTabUtil::CreateTabValueActive(
     const WebContents* contents,
-    bool active) {
+    bool active,
+    const extensions::Extension* extension) {
   NOTIMPLEMENTED();
   return NULL;
 }
diff --git a/chrome/browser/extensions/extension_tabs_apitest.cc b/chrome/browser/extensions/extension_tabs_apitest.cc
index f08f8ef..4c921aa5 100644
--- a/chrome/browser/extensions/extension_tabs_apitest.cc
+++ b/chrome/browser/extensions/extension_tabs_apitest.cc
@@ -237,6 +237,5 @@
 }
 
 // Adding a new test? Awesome. But API tests are the old hotness. The
-// new hotness is extension_test_utils. See extension_tabs_test.cc for
-// an example. We are trying to phase out many uses of API tests as
-// they tend to be flaky.
+// new hotness is extension_test_utils. See tabs_test.cc for an example.
+// We are trying to phase out many uses of API tests as they tend to be flaky.
diff --git a/chrome/browser/extensions/menu_manager.cc b/chrome/browser/extensions/menu_manager.cc
index 9e29835..e8d36898 100644
--- a/chrome/browser/extensions/menu_manager.cc
+++ b/chrome/browser/extensions/menu_manager.cc
@@ -644,7 +644,7 @@
   if (!extension || !extension->is_platform_app()) {
     // Note: web_contents only NULL in unit tests :(
     if (web_contents)
-      args->Append(ExtensionTabUtil::CreateTabValue(web_contents));
+      args->Append(ExtensionTabUtil::CreateTabValue(web_contents, extension));
     else
       args->Append(new DictionaryValue());
   }
diff --git a/chrome/browser/extensions/window_controller.h b/chrome/browser/extensions/window_controller.h
index e6e45541..ec9f6e2 100644
--- a/chrome/browser/extensions/window_controller.h
+++ b/chrome/browser/extensions/window_controller.h
@@ -57,7 +57,8 @@
   virtual base::DictionaryValue* CreateWindowValue() const;
 
   // Populates a dictionary for the Window object, including a list of tabs.
-  virtual base::DictionaryValue* CreateWindowValueWithTabs() const = 0;
+  virtual base::DictionaryValue* CreateWindowValueWithTabs(
+      const extensions::Extension* extension) const = 0;
 
   // Returns false if the window is in a state where closing the window is not
   // permitted and sets |reason| if not NULL.
diff --git a/chrome/browser/ui/panels/panel.cc b/chrome/browser/ui/panels/panel.cc
index af6adf1..0dac7b5 100644
--- a/chrome/browser/ui/panels/panel.cc
+++ b/chrome/browser/ui/panels/panel.cc
@@ -38,6 +38,10 @@
 using content::RenderViewHost;
 using content::UserMetricsAction;
 
+namespace extensions {
+class Extension;
+}
+
 namespace panel_internal {
 
 class PanelExtensionWindowController : public extensions::WindowController {
@@ -48,7 +52,8 @@
   // Overridden from extensions::WindowController.
   virtual int GetWindowId() const OVERRIDE;
   virtual std::string GetWindowTypeText() const OVERRIDE;
-  virtual base::DictionaryValue* CreateWindowValueWithTabs() const OVERRIDE;
+  virtual base::DictionaryValue* CreateWindowValueWithTabs(
+      const extensions::Extension* extension) const OVERRIDE;
   virtual bool CanClose(Reason* reason) const OVERRIDE;
   virtual void SetFullscreenMode(bool is_fullscreen,
                                  const GURL& extension_url) const OVERRIDE;
@@ -80,12 +85,11 @@
 }
 
 base::DictionaryValue*
-PanelExtensionWindowController::CreateWindowValueWithTabs() const {
+PanelExtensionWindowController::CreateWindowValueWithTabs(
+    const extensions::Extension* extension) const {
   base::DictionaryValue* result = CreateWindowValue();
 
-  // Safe to include info about the web contents as this is only called
-  // by the extension that owns this window. See IsVisibleToExtension().
-  // TODO(jennb): DCHECK this after chebert's patch 10829186 lands.
+  DCHECK(IsVisibleToExtension(extension));
   content::WebContents* web_contents = panel_->GetWebContents();
   if (web_contents) {
     DictionaryValue* tab_value = new DictionaryValue();
diff --git a/chrome/browser/ui/views/ash/panel_view_aura.cc b/chrome/browser/ui/views/ash/panel_view_aura.cc
index bc5346d..cda8cab 100644
--- a/chrome/browser/ui/views/ash/panel_view_aura.cc
+++ b/chrome/browser/ui/views/ash/panel_view_aura.cc
@@ -189,7 +189,8 @@
   virtual int GetWindowId() const OVERRIDE;
   virtual std::string GetWindowTypeText() const OVERRIDE;
   virtual base::DictionaryValue* CreateWindowValue() const OVERRIDE;
-  virtual base::DictionaryValue* CreateWindowValueWithTabs() const OVERRIDE;
+  virtual base::DictionaryValue* CreateWindowValueWithTabs(
+      const extensions::Extension* extension) const OVERRIDE;
   virtual bool CanClose(Reason* reason) const OVERRIDE;
   virtual void SetFullscreenMode(bool is_fullscreen,
                                  const GURL& extension_url) const OVERRIDE;
@@ -231,7 +232,8 @@
 }
 
 base::DictionaryValue*
-PanelExtensionWindowController::CreateWindowValueWithTabs() const {
+PanelExtensionWindowController::CreateWindowValueWithTabs(
+    const extensions::Extension* extension) const {
   DictionaryValue* result = CreateWindowValue();
 
   // TODO(stevenjb): Implement tab interface for Aura panels.