Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/renderer/extensions/dispatcher.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/command_line.h"
      9 #include "base/debug/alias.h"
     10 #include "base/json/json_reader.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/sha1.h"
     13 #include "base/strings/string_number_conversions.h"
     14 #include "base/strings/string_piece.h"
     15 #include "base/strings/string_split.h"
     16 #include "base/strings/string_util.h"
     17 #include "chrome/common/child_process_logging.h"
     18 #include "chrome/common/chrome_switches.h"
     19 #include "chrome/common/chrome_version_info.h"
     20 #include "chrome/common/extensions/api/extension_api.h"
     21 #include "chrome/common/extensions/background_info.h"
     22 #include "chrome/common/extensions/extension.h"
     23 #include "chrome/common/extensions/extension_constants.h"
     24 #include "chrome/common/extensions/extension_manifest_constants.h"
     25 #include "chrome/common/extensions/extension_messages.h"
     26 #include "chrome/common/extensions/features/feature.h"
     27 #include "chrome/common/extensions/features/feature_channel.h"
     28 #include "chrome/common/extensions/manifest.h"
     29 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h"
     30 #include "chrome/common/extensions/manifest_handlers/sandboxed_page_info.h"
     31 #include "chrome/common/extensions/message_bundle.h"
     32 #include "chrome/common/extensions/permissions/permission_set.h"
     33 #include "chrome/common/extensions/permissions/permissions_data.h"
     34 #include "chrome/common/url_constants.h"
     35 #include "chrome/renderer/chrome_render_process_observer.h"
     36 #include "chrome/renderer/extensions/api_activity_logger.h"
     37 #include "chrome/renderer/extensions/api_definitions_natives.h"
     38 #include "chrome/renderer/extensions/app_bindings.h"
     39 #include "chrome/renderer/extensions/app_runtime_custom_bindings.h"
     40 #include "chrome/renderer/extensions/app_window_custom_bindings.h"
     41 #include "chrome/renderer/extensions/binding_generating_native_handler.h"
     42 #include "chrome/renderer/extensions/chrome_v8_context.h"
     43 #include "chrome/renderer/extensions/chrome_v8_extension.h"
     44 #include "chrome/renderer/extensions/content_watcher.h"
     45 #include "chrome/renderer/extensions/context_menus_custom_bindings.h"
     46 #include "chrome/renderer/extensions/dom_activity_logger.h"
     47 #include "chrome/renderer/extensions/event_bindings.h"
     48 #include "chrome/renderer/extensions/extension_custom_bindings.h"
     49 #include "chrome/renderer/extensions/extension_groups.h"
     50 #include "chrome/renderer/extensions/extension_helper.h"
     51 #include "chrome/renderer/extensions/feedback_private_custom_bindings.h"
     52 #include "chrome/renderer/extensions/file_browser_handler_custom_bindings.h"
     53 #include "chrome/renderer/extensions/file_browser_private_custom_bindings.h"
     54 #include "chrome/renderer/extensions/file_system_natives.h"
     55 #include "chrome/renderer/extensions/i18n_custom_bindings.h"
     56 #include "chrome/renderer/extensions/logging_native_handler.h"
     57 #include "chrome/renderer/extensions/media_galleries_custom_bindings.h"
     58 #include "chrome/renderer/extensions/messaging_bindings.h"
     59 #include "chrome/renderer/extensions/module_system.h"
     60 #include "chrome/renderer/extensions/object_backed_native_handler.h"
     61 #include "chrome/renderer/extensions/page_actions_custom_bindings.h"
     62 #include "chrome/renderer/extensions/page_capture_custom_bindings.h"
     63 #include "chrome/renderer/extensions/render_view_observer_natives.h"
     64 #include "chrome/renderer/extensions/request_sender.h"
     65 #include "chrome/renderer/extensions/runtime_custom_bindings.h"
     66 #include "chrome/renderer/extensions/safe_builtins.h"
     67 #include "chrome/renderer/extensions/send_request_natives.h"
     68 #include "chrome/renderer/extensions/set_icon_natives.h"
     69 #include "chrome/renderer/extensions/sync_file_system_custom_bindings.h"
     70 #include "chrome/renderer/extensions/tab_finder.h"
     71 #include "chrome/renderer/extensions/tabs_custom_bindings.h"
     72 #include "chrome/renderer/extensions/tts_custom_bindings.h"
     73 #include "chrome/renderer/extensions/user_script_slave.h"
     74 #include "chrome/renderer/extensions/web_request_custom_bindings.h"
     75 #include "chrome/renderer/extensions/webstore_bindings.h"
     76 #include "chrome/renderer/resource_bundle_source_map.h"
     77 #include "content/public/renderer/render_thread.h"
     78 #include "content/public/renderer/render_view.h"
     79 #include "content/public/renderer/v8_value_converter.h"
     80 #include "extensions/common/constants.h"
     81 #include "extensions/common/features/feature_provider.h"
     82 #include "extensions/common/view_type.h"
     83 #include "grit/common_resources.h"
     84 #include "grit/renderer_resources.h"
     85 #include "third_party/WebKit/public/platform/WebString.h"
     86 #include "third_party/WebKit/public/platform/WebURLRequest.h"
     87 #include "third_party/WebKit/public/web/WebCustomElement.h"
     88 #include "third_party/WebKit/public/web/WebDataSource.h"
     89 #include "third_party/WebKit/public/web/WebDocument.h"
     90 #include "third_party/WebKit/public/web/WebFrame.h"
     91 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
     92 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
     93 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
     94 #include "third_party/WebKit/public/web/WebView.h"
     95 #include "ui/base/layout.h"
     96 #include "ui/base/resource/resource_bundle.h"
     97 #include "v8/include/v8.h"
     98 
     99 using WebKit::WebDataSource;
    100 using WebKit::WebDocument;
    101 using WebKit::WebFrame;
    102 using WebKit::WebScopedUserGesture;
    103 using WebKit::WebSecurityPolicy;
    104 using WebKit::WebString;
    105 using WebKit::WebVector;
    106 using WebKit::WebView;
    107 using content::RenderThread;
    108 using content::RenderView;
    109 
    110 namespace extensions {
    111 
    112 namespace {
    113 
    114 static const int64 kInitialExtensionIdleHandlerDelayMs = 5*1000;
    115 static const int64 kMaxExtensionIdleHandlerDelayMs = 5*60*1000;
    116 static const char kEventModule[] = "event_bindings";
    117 static const char kEventDispatchFunction[] = "dispatchEvent";
    118 static const char kOnSuspendEvent[] = "runtime.onSuspend";
    119 static const char kOnSuspendCanceledEvent[] = "runtime.onSuspendCanceled";
    120 
    121 // Returns the global value for "chrome" from |context|. If one doesn't exist
    122 // creates a new object for it.
    123 //
    124 // Note that this isn't necessarily an object, since webpages can write, for
    125 // example, "window.chrome = true".
    126 v8::Handle<v8::Value> GetOrCreateChrome(ChromeV8Context* context) {
    127   v8::Handle<v8::String> chrome_string(v8::String::New("chrome"));
    128   v8::Handle<v8::Object> global(context->v8_context()->Global());
    129   v8::Handle<v8::Value> chrome(global->Get(chrome_string));
    130   if (chrome->IsUndefined()) {
    131     chrome = v8::Object::New();
    132     global->Set(chrome_string, chrome);
    133   }
    134   return chrome;
    135 }
    136 
    137 // Returns |value| cast to an object if possible, else an empty handle.
    138 v8::Handle<v8::Object> AsObjectOrEmpty(v8::Handle<v8::Value> value) {
    139   return value->IsObject() ? value.As<v8::Object>() : v8::Handle<v8::Object>();
    140 }
    141 
    142 class TestFeaturesNativeHandler : public ObjectBackedNativeHandler {
    143  public:
    144   explicit TestFeaturesNativeHandler(ChromeV8Context* context)
    145       : ObjectBackedNativeHandler(context) {
    146     RouteFunction("GetAPIFeatures",
    147         base::Bind(&TestFeaturesNativeHandler::GetAPIFeatures,
    148                    base::Unretained(this)));
    149   }
    150 
    151  private:
    152   void GetAPIFeatures(const v8::FunctionCallbackInfo<v8::Value>& args) {
    153     base::Value* value = base::JSONReader::Read(
    154         ResourceBundle::GetSharedInstance().GetRawDataResource(
    155             IDR_EXTENSION_API_FEATURES).as_string());
    156     scoped_ptr<content::V8ValueConverter> converter(
    157         content::V8ValueConverter::create());
    158     args.GetReturnValue().Set(
    159         converter->ToV8Value(value, context()->v8_context()));
    160   }
    161 };
    162 
    163 class V8ContextNativeHandler : public ObjectBackedNativeHandler {
    164  public:
    165   V8ContextNativeHandler(ChromeV8Context* context, Dispatcher* dispatcher)
    166       : ObjectBackedNativeHandler(context),
    167         context_(context),
    168         dispatcher_(dispatcher) {
    169     RouteFunction("GetAvailability",
    170         base::Bind(&V8ContextNativeHandler::GetAvailability,
    171                    base::Unretained(this)));
    172     RouteFunction("GetModuleSystem",
    173         base::Bind(&V8ContextNativeHandler::GetModuleSystem,
    174                    base::Unretained(this)));
    175   }
    176 
    177  private:
    178   void GetAvailability(const v8::FunctionCallbackInfo<v8::Value>& args) {
    179     CHECK_EQ(args.Length(), 1);
    180     std::string api_name = *v8::String::AsciiValue(args[0]->ToString());
    181     Feature::Availability availability = context_->GetAvailability(api_name);
    182 
    183     v8::Handle<v8::Object> ret = v8::Object::New();
    184     ret->Set(v8::String::New("is_available"),
    185              v8::Boolean::New(availability.is_available()));
    186     ret->Set(v8::String::New("message"),
    187              v8::String::New(availability.message().c_str()));
    188     ret->Set(v8::String::New("result"),
    189              v8::Integer::New(availability.result()));
    190     args.GetReturnValue().Set(ret);
    191   }
    192 
    193   void GetModuleSystem(const v8::FunctionCallbackInfo<v8::Value>& args) {
    194     CHECK_EQ(args.Length(), 1);
    195     CHECK(args[0]->IsObject());
    196     v8::Handle<v8::Context> v8_context =
    197         v8::Handle<v8::Object>::Cast(args[0])->CreationContext();
    198     ChromeV8Context* context = dispatcher_->v8_context_set().GetByV8Context(
    199         v8_context);
    200     args.GetReturnValue().Set(context->module_system()->NewInstance());
    201   }
    202 
    203   ChromeV8Context* context_;
    204   Dispatcher* dispatcher_;
    205 };
    206 
    207 class ChromeNativeHandler : public ObjectBackedNativeHandler {
    208  public:
    209   explicit ChromeNativeHandler(ChromeV8Context* context)
    210       : ObjectBackedNativeHandler(context) {
    211     RouteFunction("GetChrome",
    212         base::Bind(&ChromeNativeHandler::GetChrome, base::Unretained(this)));
    213   }
    214 
    215   void GetChrome(const v8::FunctionCallbackInfo<v8::Value>& args) {
    216     args.GetReturnValue().Set(GetOrCreateChrome(context()));
    217   }
    218 };
    219 
    220 class PrintNativeHandler : public ObjectBackedNativeHandler {
    221  public:
    222   explicit PrintNativeHandler(ChromeV8Context* context)
    223       : ObjectBackedNativeHandler(context) {
    224     RouteFunction("Print",
    225         base::Bind(&PrintNativeHandler::Print,
    226                    base::Unretained(this)));
    227   }
    228 
    229   void Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
    230     if (args.Length() < 1)
    231       return;
    232 
    233     std::vector<std::string> components;
    234     for (int i = 0; i < args.Length(); ++i)
    235       components.push_back(*v8::String::Utf8Value(args[i]->ToString()));
    236 
    237     LOG(ERROR) << JoinString(components, ',');
    238   }
    239 };
    240 
    241 class LazyBackgroundPageNativeHandler : public ChromeV8Extension {
    242  public:
    243   LazyBackgroundPageNativeHandler(Dispatcher* dispatcher,
    244                                   ChromeV8Context* context)
    245       : ChromeV8Extension(dispatcher, context) {
    246     RouteFunction("IncrementKeepaliveCount",
    247         base::Bind(&LazyBackgroundPageNativeHandler::IncrementKeepaliveCount,
    248                    base::Unretained(this)));
    249     RouteFunction("DecrementKeepaliveCount",
    250         base::Bind(&LazyBackgroundPageNativeHandler::DecrementKeepaliveCount,
    251                    base::Unretained(this)));
    252   }
    253 
    254   void IncrementKeepaliveCount(
    255       const v8::FunctionCallbackInfo<v8::Value>& args) {
    256     if (!context())
    257       return;
    258     RenderView* render_view = context()->GetRenderView();
    259     if (IsContextLazyBackgroundPage(render_view, context()->extension())) {
    260       render_view->Send(new ExtensionHostMsg_IncrementLazyKeepaliveCount(
    261           render_view->GetRoutingID()));
    262     }
    263   }
    264 
    265   void DecrementKeepaliveCount(
    266       const v8::FunctionCallbackInfo<v8::Value>& args) {
    267     if (!context())
    268       return;
    269     RenderView* render_view = context()->GetRenderView();
    270     if (IsContextLazyBackgroundPage(render_view, context()->extension())) {
    271       render_view->Send(new ExtensionHostMsg_DecrementLazyKeepaliveCount(
    272           render_view->GetRoutingID()));
    273     }
    274   }
    275 
    276  private:
    277   bool IsContextLazyBackgroundPage(RenderView* render_view,
    278                                    const Extension* extension) {
    279     if (!render_view)
    280       return false;
    281 
    282     ExtensionHelper* helper = ExtensionHelper::Get(render_view);
    283     return (extension && BackgroundInfo::HasLazyBackgroundPage(extension) &&
    284             helper->view_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
    285   }
    286 };
    287 
    288 class ProcessInfoNativeHandler : public ChromeV8Extension {
    289  public:
    290   ProcessInfoNativeHandler(Dispatcher* dispatcher,
    291                            ChromeV8Context* context,
    292                            const std::string& extension_id,
    293                            const std::string& context_type,
    294                            bool is_incognito_context,
    295                            int manifest_version,
    296                            bool send_request_disabled)
    297       : ChromeV8Extension(dispatcher, context),
    298         extension_id_(extension_id),
    299         context_type_(context_type),
    300         is_incognito_context_(is_incognito_context),
    301         manifest_version_(manifest_version),
    302         send_request_disabled_(send_request_disabled) {
    303     RouteFunction("GetExtensionId",
    304         base::Bind(&ProcessInfoNativeHandler::GetExtensionId,
    305                    base::Unretained(this)));
    306     RouteFunction("GetContextType",
    307         base::Bind(&ProcessInfoNativeHandler::GetContextType,
    308                    base::Unretained(this)));
    309     RouteFunction("InIncognitoContext",
    310         base::Bind(&ProcessInfoNativeHandler::InIncognitoContext,
    311                    base::Unretained(this)));
    312     RouteFunction("GetManifestVersion",
    313         base::Bind(&ProcessInfoNativeHandler::GetManifestVersion,
    314                    base::Unretained(this)));
    315     RouteFunction("IsSendRequestDisabled",
    316         base::Bind(&ProcessInfoNativeHandler::IsSendRequestDisabled,
    317                    base::Unretained(this)));
    318     RouteFunction("HasSwitch",
    319         base::Bind(&ProcessInfoNativeHandler::HasSwitch,
    320                    base::Unretained(this)));
    321   }
    322 
    323  private:
    324   void GetExtensionId(const v8::FunctionCallbackInfo<v8::Value>& args) {
    325     args.GetReturnValue().Set(v8::String::New(extension_id_.c_str()));
    326   }
    327 
    328   void GetContextType(const v8::FunctionCallbackInfo<v8::Value>& args) {
    329     args.GetReturnValue().Set(v8::String::New(context_type_.c_str()));
    330   }
    331 
    332   void InIncognitoContext(const v8::FunctionCallbackInfo<v8::Value>& args) {
    333     args.GetReturnValue().Set(is_incognito_context_);
    334   }
    335 
    336   void GetManifestVersion(const v8::FunctionCallbackInfo<v8::Value>& args) {
    337     args.GetReturnValue().Set(static_cast<int32_t>(manifest_version_));
    338   }
    339 
    340   void IsSendRequestDisabled(const v8::FunctionCallbackInfo<v8::Value>& args) {
    341     if (send_request_disabled_) {
    342       args.GetReturnValue().Set(v8::String::New(
    343           "sendRequest and onRequest are obsolete."
    344           " Please use sendMessage and onMessage instead."));
    345     }
    346   }
    347 
    348   void HasSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
    349     CHECK(args.Length() == 1 && args[0]->IsString());
    350     bool has_switch = CommandLine::ForCurrentProcess()->HasSwitch(
    351         *v8::String::AsciiValue(args[0]));
    352     args.GetReturnValue().Set(v8::Boolean::New(has_switch));
    353   }
    354 
    355   std::string extension_id_;
    356   std::string context_type_;
    357   bool is_incognito_context_;
    358   int manifest_version_;
    359   bool send_request_disabled_;
    360 };
    361 
    362 void InstallAppBindings(ModuleSystem* module_system,
    363                         v8::Handle<v8::Object> chrome) {
    364   module_system->SetLazyField(chrome, "app", "app", "chromeApp");
    365 }
    366 
    367 void InstallWebstoreBindings(ModuleSystem* module_system,
    368                              v8::Handle<v8::Object> chrome) {
    369   module_system->SetLazyField(chrome, "webstore", "webstore", "chromeWebstore");
    370 }
    371 
    372 // Calls a method |method_name| in a module |module_name| belonging to the
    373 // module system from |context|. Intended as a callback target from
    374 // ChromeV8ContextSet::ForEach.
    375 void CallModuleMethod(const std::string& module_name,
    376                       const std::string& method_name,
    377                       const base::ListValue* args,
    378                       ChromeV8Context* context) {
    379   v8::HandleScope handle_scope;
    380   v8::Context::Scope context_scope(context->v8_context());
    381 
    382   scoped_ptr<content::V8ValueConverter> converter(
    383       content::V8ValueConverter::create());
    384 
    385   std::vector<v8::Handle<v8::Value> > arguments;
    386   for (base::ListValue::const_iterator it = args->begin(); it != args->end();
    387        ++it) {
    388     arguments.push_back(converter->ToV8Value(*it, context->v8_context()));
    389   }
    390 
    391   context->module_system()->CallModuleMethod(
    392       module_name, method_name, &arguments);
    393 }
    394 
    395 }  // namespace
    396 
    397 Dispatcher::Dispatcher()
    398     : content_watcher_(new ContentWatcher(this)),
    399       is_webkit_initialized_(false),
    400       webrequest_adblock_(false),
    401       webrequest_adblock_plus_(false),
    402       webrequest_other_(false),
    403       source_map_(&ResourceBundle::GetSharedInstance()),
    404       v8_schema_registry_(new V8SchemaRegistry) {
    405   const CommandLine& command_line = *(CommandLine::ForCurrentProcess());
    406   is_extension_process_ =
    407       command_line.HasSwitch(switches::kExtensionProcess) ||
    408       command_line.HasSwitch(switches::kSingleProcess);
    409 
    410   if (is_extension_process_) {
    411     RenderThread::Get()->SetIdleNotificationDelayInMs(
    412         kInitialExtensionIdleHandlerDelayMs);
    413   }
    414 
    415   RenderThread::Get()->RegisterExtension(SafeBuiltins::CreateV8Extension());
    416 
    417   user_script_slave_.reset(new UserScriptSlave(&extensions_));
    418   request_sender_.reset(new RequestSender(this));
    419   PopulateSourceMap();
    420   PopulateLazyBindingsMap();
    421 }
    422 
    423 Dispatcher::~Dispatcher() {
    424 }
    425 
    426 bool Dispatcher::OnControlMessageReceived(const IPC::Message& message) {
    427   bool handled = true;
    428   IPC_BEGIN_MESSAGE_MAP(Dispatcher, message)
    429     IPC_MESSAGE_HANDLER(ExtensionMsg_SetChannel, OnSetChannel)
    430     IPC_MESSAGE_HANDLER(ExtensionMsg_MessageInvoke, OnMessageInvoke)
    431     IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnConnect, OnDispatchOnConnect)
    432     IPC_MESSAGE_HANDLER(ExtensionMsg_DeliverMessage, OnDeliverMessage)
    433     IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnDisconnect,
    434                         OnDispatchOnDisconnect)
    435     IPC_MESSAGE_HANDLER(ExtensionMsg_SetFunctionNames, OnSetFunctionNames)
    436     IPC_MESSAGE_HANDLER(ExtensionMsg_SetSystemFont, OnSetSystemFont)
    437     IPC_MESSAGE_HANDLER(ExtensionMsg_Loaded, OnLoaded)
    438     IPC_MESSAGE_HANDLER(ExtensionMsg_Unloaded, OnUnloaded)
    439     IPC_MESSAGE_HANDLER(ExtensionMsg_SetScriptingWhitelist,
    440                         OnSetScriptingWhitelist)
    441     IPC_MESSAGE_HANDLER(ExtensionMsg_ActivateExtension, OnActivateExtension)
    442     IPC_MESSAGE_HANDLER(ExtensionMsg_UpdatePermissions, OnUpdatePermissions)
    443     IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateTabSpecificPermissions,
    444                         OnUpdateTabSpecificPermissions)
    445     IPC_MESSAGE_HANDLER(ExtensionMsg_ClearTabSpecificPermissions,
    446                         OnClearTabSpecificPermissions)
    447     IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
    448     IPC_MESSAGE_HANDLER(ExtensionMsg_UsingWebRequestAPI, OnUsingWebRequestAPI)
    449     IPC_MESSAGE_HANDLER(ExtensionMsg_ShouldSuspend, OnShouldSuspend)
    450     IPC_MESSAGE_HANDLER(ExtensionMsg_Suspend, OnSuspend)
    451     IPC_MESSAGE_HANDLER(ExtensionMsg_CancelSuspend, OnCancelSuspend)
    452     IPC_MESSAGE_FORWARD(ExtensionMsg_WatchPages,
    453                         content_watcher_.get(), ContentWatcher::OnWatchPages)
    454     IPC_MESSAGE_UNHANDLED(handled = false)
    455   IPC_END_MESSAGE_MAP()
    456 
    457   return handled;
    458 }
    459 
    460 void Dispatcher::WebKitInitialized() {
    461   // For extensions, we want to ensure we call the IdleHandler every so often,
    462   // even if the extension keeps up activity.
    463   if (is_extension_process_) {
    464     forced_idle_timer_.Start(FROM_HERE,
    465         base::TimeDelta::FromMilliseconds(kMaxExtensionIdleHandlerDelayMs),
    466         RenderThread::Get(), &RenderThread::IdleHandler);
    467   }
    468 
    469   // Initialize host permissions for any extensions that were activated before
    470   // WebKit was initialized.
    471   for (std::set<std::string>::iterator iter = active_extension_ids_.begin();
    472        iter != active_extension_ids_.end(); ++iter) {
    473     const Extension* extension = extensions_.GetByID(*iter);
    474     CHECK(extension);
    475     InitOriginPermissions(extension);
    476   }
    477 
    478   if (IsWithinPlatformApp())
    479     EnableCustomElementWhiteList();
    480 
    481   is_webkit_initialized_ = true;
    482 }
    483 
    484 void Dispatcher::IdleNotification() {
    485   if (is_extension_process_) {
    486     // Dampen the forced delay as well if the extension stays idle for long
    487     // periods of time.
    488     int64 forced_delay_ms = std::max(
    489         RenderThread::Get()->GetIdleNotificationDelayInMs(),
    490         kMaxExtensionIdleHandlerDelayMs);
    491     forced_idle_timer_.Stop();
    492     forced_idle_timer_.Start(FROM_HERE,
    493         base::TimeDelta::FromMilliseconds(forced_delay_ms),
    494         RenderThread::Get(), &RenderThread::IdleHandler);
    495   }
    496 }
    497 
    498 void Dispatcher::OnRenderProcessShutdown() {
    499   v8_schema_registry_.reset();
    500 }
    501 
    502 void Dispatcher::OnSetFunctionNames(
    503     const std::vector<std::string>& names) {
    504   function_names_.clear();
    505   for (size_t i = 0; i < names.size(); ++i)
    506     function_names_.insert(names[i]);
    507 }
    508 
    509 void Dispatcher::OnSetSystemFont(const std::string& font_family,
    510                                  const std::string& font_size) {
    511   system_font_family_ = font_family;
    512   system_font_size_ = font_size;
    513 }
    514 
    515 void Dispatcher::OnSetChannel(int channel) {
    516   extensions::SetCurrentChannel(
    517       static_cast<chrome::VersionInfo::Channel>(channel));
    518 }
    519 
    520 void Dispatcher::OnMessageInvoke(const std::string& extension_id,
    521                                  const std::string& module_name,
    522                                  const std::string& function_name,
    523                                  const base::ListValue& args,
    524                                  bool user_gesture) {
    525   InvokeModuleSystemMethod(
    526       NULL, extension_id, module_name, function_name, args, user_gesture);
    527 }
    528 
    529 void Dispatcher::OnDispatchOnConnect(
    530     int target_port_id,
    531     const std::string& channel_name,
    532     const base::DictionaryValue& source_tab,
    533     const ExtensionMsg_ExternalConnectionInfo& info) {
    534   MessagingBindings::DispatchOnConnect(
    535       v8_context_set_.GetAll(),
    536       target_port_id, channel_name, source_tab,
    537       info.source_id, info.target_id, info.source_url,
    538       NULL);  // All render views.
    539 }
    540 
    541 void Dispatcher::OnDeliverMessage(int target_port_id,
    542                                   const std::string& message) {
    543   MessagingBindings::DeliverMessage(
    544       v8_context_set_.GetAll(),
    545       target_port_id,
    546       message,
    547       NULL);  // All render views.
    548 }
    549 
    550 void Dispatcher::OnDispatchOnDisconnect(int port_id,
    551                                         const std::string& error_message) {
    552   MessagingBindings::DispatchOnDisconnect(
    553       v8_context_set_.GetAll(),
    554       port_id, error_message,
    555       NULL);  // All render views.
    556 }
    557 
    558 void Dispatcher::OnLoaded(
    559     const std::vector<ExtensionMsg_Loaded_Params>& loaded_extensions) {
    560   std::vector<ExtensionMsg_Loaded_Params>::const_iterator i;
    561   for (i = loaded_extensions.begin(); i != loaded_extensions.end(); ++i) {
    562     std::string error;
    563     scoped_refptr<const Extension> extension = i->ConvertToExtension(&error);
    564     if (!extension.get()) {
    565       extension_load_errors_[i->id] = error;
    566       continue;
    567     }
    568     OnLoadedInternal(extension);
    569   }
    570   // Update the available bindings for all contexts. These may have changed if
    571   // an externally_connectable extension was loaded that can connect to an
    572   // open webpage.
    573   AddOrRemoveBindings("");
    574 }
    575 
    576 void Dispatcher::OnLoadedInternal(scoped_refptr<const Extension> extension) {
    577   extensions_.Insert(extension);
    578 }
    579 
    580 void Dispatcher::OnUnloaded(const std::string& id) {
    581   extensions_.Remove(id);
    582   active_extension_ids_.erase(id);
    583 
    584   // If the extension is later reloaded with a different set of permissions,
    585   // we'd like it to get a new isolated world ID, so that it can pick up the
    586   // changed origin whitelist.
    587   user_script_slave_->RemoveIsolatedWorld(id);
    588 
    589   // Invalidate all of the contexts that were removed.
    590   // TODO(kalman): add an invalidation observer interface to ChromeV8Context.
    591   ChromeV8ContextSet::ContextSet removed_contexts =
    592       v8_context_set_.OnExtensionUnloaded(id);
    593   for (ChromeV8ContextSet::ContextSet::iterator it = removed_contexts.begin();
    594        it != removed_contexts.end(); ++it) {
    595     request_sender_->InvalidateSource(*it);
    596   }
    597 
    598   // Update the available bindings for the remaining contexts. These may have
    599   // changed if an externally_connectable extension is unloaded and a webpage
    600   // is no longer accessible.
    601   AddOrRemoveBindings("");
    602 
    603   // Invalidates the messages map for the extension in case the extension is
    604   // reloaded with a new messages map.
    605   EraseL10nMessagesMap(id);
    606 
    607   // We don't do anything with existing platform-app stylesheets. They will
    608   // stay resident, but the URL pattern corresponding to the unloaded
    609   // extension's URL just won't match anything anymore.
    610 }
    611 
    612 void Dispatcher::OnSetScriptingWhitelist(
    613     const Extension::ScriptingWhitelist& extension_ids) {
    614   Extension::SetScriptingWhitelist(extension_ids);
    615 }
    616 
    617 bool Dispatcher::IsExtensionActive(
    618     const std::string& extension_id) const {
    619   bool is_active =
    620       active_extension_ids_.find(extension_id) != active_extension_ids_.end();
    621   if (is_active)
    622     CHECK(extensions_.Contains(extension_id));
    623   return is_active;
    624 }
    625 
    626 v8::Handle<v8::Object> Dispatcher::GetOrCreateObject(
    627     v8::Handle<v8::Object> object,
    628     const std::string& field) {
    629   v8::Handle<v8::String> key = v8::String::New(field.c_str());
    630   // If the object has a callback property, it is assumed it is an unavailable
    631   // API, so it is safe to delete. This is checked before GetOrCreateObject is
    632   // called.
    633   if (object->HasRealNamedCallbackProperty(key)) {
    634     object->Delete(key);
    635   } else if (object->HasRealNamedProperty(key)) {
    636     v8::Handle<v8::Value> value = object->Get(key);
    637     CHECK(value->IsObject());
    638     return v8::Handle<v8::Object>::Cast(value);
    639   }
    640 
    641   v8::Handle<v8::Object> new_object = v8::Object::New();
    642   object->Set(key, new_object);
    643   return new_object;
    644 }
    645 
    646 void Dispatcher::AddOrRemoveBindingsForContext(ChromeV8Context* context) {
    647   v8::HandleScope handle_scope;
    648   v8::Context::Scope context_scope(context->v8_context());
    649 
    650   // TODO(kalman): Make the bindings registration have zero overhead then run
    651   // the same code regardless of context type.
    652   switch (context->context_type()) {
    653     case Feature::UNSPECIFIED_CONTEXT:
    654     case Feature::WEB_PAGE_CONTEXT: {
    655       // Web page context; it's too expensive to run the full bindings code.
    656       // Hard-code that the app and webstore APIs are available...
    657       RegisterBinding("app", context);
    658       RegisterBinding("webstore", context);
    659 
    660       // ... and that the runtime API might be available if any extension can
    661       // connect to it.
    662       bool runtime_is_available = false;
    663       for (ExtensionSet::const_iterator it = extensions_.begin();
    664            it != extensions_.end(); ++it) {
    665         ExternallyConnectableInfo* info =
    666             static_cast<ExternallyConnectableInfo*>((*it)->GetManifestData(
    667                 extension_manifest_keys::kExternallyConnectable));
    668         if (info && info->matches.MatchesURL(context->GetURL())) {
    669           runtime_is_available = true;
    670           break;
    671         }
    672       }
    673       if (runtime_is_available)
    674         RegisterBinding("runtime", context);
    675       break;
    676     }
    677 
    678     case Feature::BLESSED_EXTENSION_CONTEXT:
    679     case Feature::UNBLESSED_EXTENSION_CONTEXT:
    680     case Feature::CONTENT_SCRIPT_CONTEXT: {
    681       // Extension context; iterate through all the APIs and bind the available
    682       // ones.
    683       FeatureProvider* feature_provider = FeatureProvider::GetByName("api");
    684       const std::vector<std::string>& apis =
    685           feature_provider->GetAllFeatureNames();
    686       for (std::vector<std::string>::const_iterator it = apis.begin();
    687           it != apis.end(); ++it) {
    688         const std::string& api_name = *it;
    689         Feature* feature = feature_provider->GetFeature(api_name);
    690         DCHECK(feature);
    691         if (feature->IsInternal())
    692           continue;
    693 
    694         // If this API name has parent features, then this must be a function or
    695         // event, so we should not register.
    696         bool parent_feature_available = false;
    697         for (Feature* parent = feature_provider->GetParent(feature);
    698              parent != NULL; parent = feature_provider->GetParent(parent)) {
    699           if (context->IsAnyFeatureAvailableToContext(parent->name())) {
    700             parent_feature_available = true;
    701             break;
    702           }
    703         }
    704         if (parent_feature_available)
    705           continue;
    706 
    707         if (!context->IsAnyFeatureAvailableToContext(api_name)) {
    708           DeregisterBinding(api_name, context);
    709           continue;
    710         }
    711 
    712         RegisterBinding(api_name, context);
    713       }
    714       break;
    715     }
    716   }
    717 }
    718 
    719 void Dispatcher::DeregisterBinding(const std::string& api_name,
    720                                    ChromeV8Context* context) {
    721   std::string bind_name;
    722   v8::Handle<v8::Object> bind_object =
    723       GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context);
    724   v8::Handle<v8::String> v8_bind_name = v8::String::New(bind_name.c_str());
    725   if (!bind_object.IsEmpty() && bind_object->HasRealNamedProperty(v8_bind_name))
    726     bind_object->Delete(v8_bind_name);
    727 }
    728 
    729 v8::Handle<v8::Object> Dispatcher::GetOrCreateBindObjectIfAvailable(
    730     const std::string& api_name,
    731     std::string* bind_name,
    732     ChromeV8Context* context) {
    733   std::vector<std::string> split;
    734   base::SplitString(api_name, '.', &split);
    735 
    736   v8::Handle<v8::Object> bind_object;
    737 
    738   // Check if this API has an ancestor. If the API's ancestor is available and
    739   // the API is not available, don't install the bindings for this API. If
    740   // the API is available and its ancestor is not, delete the ancestor and
    741   // install the bindings for the API. This is to prevent loading the ancestor
    742   // API schema if it will not be needed.
    743   //
    744   // For example:
    745   //  If app is available and app.window is not, just install app.
    746   //  If app.window is available and app is not, delete app and install
    747   //  app.window on a new object so app does not have to be loaded.
    748   FeatureProvider* feature_provider = FeatureProvider::GetByName("api");
    749   std::string ancestor_name;
    750   bool only_ancestor_available = false;
    751 
    752   for (size_t i = 0; i < split.size() - 1; ++i) {
    753     ancestor_name += (i ? ".": "") + split[i];
    754     if (feature_provider->GetFeature(ancestor_name) &&
    755         context->GetAvailability(ancestor_name).is_available() &&
    756         !context->GetAvailability(api_name).is_available()) {
    757       only_ancestor_available = true;
    758       break;
    759     }
    760 
    761     if (bind_object.IsEmpty()) {
    762       bind_object = AsObjectOrEmpty(GetOrCreateChrome(context));
    763       if (bind_object.IsEmpty())
    764         return v8::Handle<v8::Object>();
    765     }
    766     bind_object = GetOrCreateObject(bind_object, split[i]);
    767   }
    768 
    769   if (only_ancestor_available)
    770     return v8::Handle<v8::Object>();
    771 
    772   if (bind_name)
    773     *bind_name = split.back();
    774 
    775   return bind_object.IsEmpty() ?
    776       AsObjectOrEmpty(GetOrCreateChrome(context)) : bind_object;
    777 }
    778 
    779 void Dispatcher::RegisterBinding(const std::string& api_name,
    780                                  ChromeV8Context* context) {
    781   std::string bind_name;
    782   v8::Handle<v8::Object> bind_object =
    783       GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context);
    784 
    785   // Empty if the bind object failed to be created, probably because the
    786   // extension overrode chrome with a non-object, e.g. window.chrome = true.
    787   if (bind_object.IsEmpty())
    788     return;
    789 
    790   v8::Local<v8::String> v8_api_name = v8::String::New(api_name.c_str());
    791   if (bind_object->HasRealNamedProperty(v8_api_name)) {
    792     // The bind object may already have the property if the API has been
    793     // registered before (or if the extension has put something there already,
    794     // but, whatevs).
    795     //
    796     // In the former case, we need to re-register the bindings for the APIs
    797     // which the extension now has permissions for (if any), but not touch any
    798     // others so that we don't destroy state such as event listeners.
    799     //
    800     // TODO(kalman): Only register available APIs to make this all moot.
    801     if (bind_object->HasRealNamedCallbackProperty(v8_api_name))
    802       return;  // lazy binding still there, nothing to do
    803     if (bind_object->Get(v8_api_name)->IsObject())
    804       return;  // binding has already been fully installed
    805   }
    806 
    807   ModuleSystem* module_system = context->module_system();
    808   if (lazy_bindings_map_.find(api_name) != lazy_bindings_map_.end()) {
    809     InstallBindings(module_system, context->v8_context(), api_name);
    810   } else if (!source_map_.Contains(api_name)) {
    811     module_system->RegisterNativeHandler(
    812         api_name,
    813         scoped_ptr<NativeHandler>(new BindingGeneratingNativeHandler(
    814             module_system,
    815             api_name,
    816             "binding")));
    817     module_system->SetNativeLazyField(bind_object,
    818                                       bind_name,
    819                                       api_name,
    820                                       "binding");
    821   } else {
    822     module_system->SetLazyField(bind_object,
    823                                 bind_name,
    824                                 api_name,
    825                                 "binding");
    826   }
    827 }
    828 
    829 // NOTE: please use the naming convention "foo_natives" for these.
    830 void Dispatcher::RegisterNativeHandlers(ModuleSystem* module_system,
    831                                         ChromeV8Context* context) {
    832   module_system->RegisterNativeHandler("event_natives",
    833       scoped_ptr<NativeHandler>(EventBindings::Create(this, context)));
    834   module_system->RegisterNativeHandler("messaging_natives",
    835       scoped_ptr<NativeHandler>(MessagingBindings::Get(this, context)));
    836   module_system->RegisterNativeHandler("apiDefinitions",
    837       scoped_ptr<NativeHandler>(new ApiDefinitionsNatives(this, context)));
    838   module_system->RegisterNativeHandler("sendRequest",
    839       scoped_ptr<NativeHandler>(
    840           new SendRequestNatives(this, request_sender_.get(), context)));
    841   module_system->RegisterNativeHandler("setIcon",
    842       scoped_ptr<NativeHandler>(
    843           new SetIconNatives(this, request_sender_.get(), context)));
    844   module_system->RegisterNativeHandler(
    845       "contentWatcherNative",
    846       content_watcher_->MakeNatives(context));
    847   module_system->RegisterNativeHandler("activityLogger",
    848       scoped_ptr<NativeHandler>(new APIActivityLogger(this, context)));
    849   module_system->RegisterNativeHandler("renderViewObserverNatives",
    850       scoped_ptr<NativeHandler>(new RenderViewObserverNatives(this, context)));
    851 
    852   // Natives used by multiple APIs.
    853   module_system->RegisterNativeHandler("file_system_natives",
    854       scoped_ptr<NativeHandler>(new FileSystemNatives(context)));
    855 
    856   // Custom bindings.
    857   module_system->RegisterNativeHandler("app",
    858       scoped_ptr<NativeHandler>(new AppBindings(this, context)));
    859   module_system->RegisterNativeHandler("app_runtime",
    860       scoped_ptr<NativeHandler>(
    861           new AppRuntimeCustomBindings(this, context)));
    862   module_system->RegisterNativeHandler("app_window_natives",
    863       scoped_ptr<NativeHandler>(
    864           new AppWindowCustomBindings(this, context)));
    865   module_system->RegisterNativeHandler("context_menus",
    866       scoped_ptr<NativeHandler>(
    867           new ContextMenusCustomBindings(this, context)));
    868   module_system->RegisterNativeHandler("extension",
    869       scoped_ptr<NativeHandler>(
    870           new ExtensionCustomBindings(this, context)));
    871   module_system->RegisterNativeHandler("sync_file_system",
    872       scoped_ptr<NativeHandler>(
    873           new SyncFileSystemCustomBindings(this, context)));
    874   module_system->RegisterNativeHandler("feedback_private",
    875       scoped_ptr<NativeHandler>(new FeedbackPrivateCustomBindings(
    876           this, context)));
    877   module_system->RegisterNativeHandler("file_browser_handler",
    878       scoped_ptr<NativeHandler>(new FileBrowserHandlerCustomBindings(
    879           this, context)));
    880   module_system->RegisterNativeHandler("file_browser_private",
    881       scoped_ptr<NativeHandler>(new FileBrowserPrivateCustomBindings(
    882           this, context)));
    883   module_system->RegisterNativeHandler("i18n",
    884       scoped_ptr<NativeHandler>(
    885           new I18NCustomBindings(this, context)));
    886   module_system->RegisterNativeHandler("mediaGalleries",
    887       scoped_ptr<NativeHandler>(
    888           new MediaGalleriesCustomBindings(this, context)));
    889   module_system->RegisterNativeHandler("page_actions",
    890       scoped_ptr<NativeHandler>(
    891           new PageActionsCustomBindings(this, context)));
    892   module_system->RegisterNativeHandler("page_capture",
    893       scoped_ptr<NativeHandler>(
    894           new PageCaptureCustomBindings(this, context)));
    895   module_system->RegisterNativeHandler("runtime",
    896       scoped_ptr<NativeHandler>(new RuntimeCustomBindings(this, context)));
    897   module_system->RegisterNativeHandler("tabs",
    898       scoped_ptr<NativeHandler>(new TabsCustomBindings(this, context)));
    899   module_system->RegisterNativeHandler("tts",
    900       scoped_ptr<NativeHandler>(new TTSCustomBindings(this, context)));
    901   module_system->RegisterNativeHandler("web_request",
    902       scoped_ptr<NativeHandler>(
    903           new WebRequestCustomBindings(this, context)));
    904   module_system->RegisterNativeHandler("webstore",
    905       scoped_ptr<NativeHandler>(new WebstoreBindings(this, context)));
    906 }
    907 
    908 void Dispatcher::PopulateSourceMap() {
    909   // Libraries.
    910   source_map_.RegisterSource("contentWatcher", IDR_CONTENT_WATCHER_JS);
    911   source_map_.RegisterSource("entryIdManager", IDR_ENTRY_ID_MANAGER);
    912   source_map_.RegisterSource(kEventModule, IDR_EVENT_BINDINGS_JS);
    913   source_map_.RegisterSource("imageUtil", IDR_IMAGE_UTIL_JS);
    914   source_map_.RegisterSource("json_schema", IDR_JSON_SCHEMA_JS);
    915   source_map_.RegisterSource("lastError", IDR_LAST_ERROR_JS);
    916   source_map_.RegisterSource("messaging", IDR_MESSAGING_JS);
    917   source_map_.RegisterSource("schemaUtils", IDR_SCHEMA_UTILS_JS);
    918   source_map_.RegisterSource("sendRequest", IDR_SEND_REQUEST_JS);
    919   source_map_.RegisterSource("setIcon", IDR_SET_ICON_JS);
    920   source_map_.RegisterSource("test", IDR_TEST_CUSTOM_BINDINGS_JS);
    921   source_map_.RegisterSource("unload_event", IDR_UNLOAD_EVENT_JS);
    922   source_map_.RegisterSource("utils", IDR_UTILS_JS);
    923 
    924   // Custom bindings.
    925   source_map_.RegisterSource("app", IDR_APP_CUSTOM_BINDINGS_JS);
    926   source_map_.RegisterSource("app.runtime", IDR_APP_RUNTIME_CUSTOM_BINDINGS_JS);
    927   source_map_.RegisterSource("app.window", IDR_APP_WINDOW_CUSTOM_BINDINGS_JS);
    928   source_map_.RegisterSource("bluetooth", IDR_BLUETOOTH_CUSTOM_BINDINGS_JS);
    929   source_map_.RegisterSource("browserAction",
    930                              IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS);
    931   source_map_.RegisterSource("contextMenus",
    932                              IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS);
    933   source_map_.RegisterSource("declarativeContent",
    934                              IDR_DECLARATIVE_CONTENT_CUSTOM_BINDINGS_JS);
    935   source_map_.RegisterSource("declarativeWebRequest",
    936                              IDR_DECLARATIVE_WEBREQUEST_CUSTOM_BINDINGS_JS);
    937   source_map_.RegisterSource("downloads",
    938                              IDR_DOWNLOADS_CUSTOM_BINDINGS_JS);
    939   source_map_.RegisterSource("experimental.offscreen",
    940                              IDR_EXPERIMENTAL_OFFSCREENTABS_CUSTOM_BINDINGS_JS);
    941   source_map_.RegisterSource("extension", IDR_EXTENSION_CUSTOM_BINDINGS_JS);
    942   source_map_.RegisterSource("feedbackPrivate",
    943                              IDR_FEEDBACK_PRIVATE_CUSTOM_BINDINGS_JS);
    944   source_map_.RegisterSource("fileBrowserHandler",
    945                              IDR_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_JS);
    946   source_map_.RegisterSource("fileBrowserPrivate",
    947                              IDR_FILE_BROWSER_PRIVATE_CUSTOM_BINDINGS_JS);
    948   source_map_.RegisterSource("fileSystem",
    949                              IDR_FILE_SYSTEM_CUSTOM_BINDINGS_JS);
    950   source_map_.RegisterSource("i18n", IDR_I18N_CUSTOM_BINDINGS_JS);
    951   source_map_.RegisterSource("input.ime", IDR_INPUT_IME_CUSTOM_BINDINGS_JS);
    952   source_map_.RegisterSource("mediaGalleries",
    953                              IDR_MEDIA_GALLERIES_CUSTOM_BINDINGS_JS);
    954   source_map_.RegisterSource("notifications",
    955                              IDR_NOTIFICATIONS_CUSTOM_BINDINGS_JS);
    956   source_map_.RegisterSource("omnibox", IDR_OMNIBOX_CUSTOM_BINDINGS_JS);
    957   source_map_.RegisterSource("pageActions",
    958                              IDR_PAGE_ACTIONS_CUSTOM_BINDINGS_JS);
    959   source_map_.RegisterSource("pageAction", IDR_PAGE_ACTION_CUSTOM_BINDINGS_JS);
    960   source_map_.RegisterSource("pageCapture",
    961                              IDR_PAGE_CAPTURE_CUSTOM_BINDINGS_JS);
    962   source_map_.RegisterSource("permissions", IDR_PERMISSIONS_CUSTOM_BINDINGS_JS);
    963   source_map_.RegisterSource("runtime", IDR_RUNTIME_CUSTOM_BINDINGS_JS);
    964   source_map_.RegisterSource("syncFileSystem",
    965                              IDR_SYNC_FILE_SYSTEM_CUSTOM_BINDINGS_JS);
    966   source_map_.RegisterSource("systemIndicator",
    967                              IDR_SYSTEM_INDICATOR_CUSTOM_BINDINGS_JS);
    968   source_map_.RegisterSource("tabCapture", IDR_TAB_CAPTURE_CUSTOM_BINDINGS_JS);
    969   source_map_.RegisterSource("tabs", IDR_TABS_CUSTOM_BINDINGS_JS);
    970   source_map_.RegisterSource("tts", IDR_TTS_CUSTOM_BINDINGS_JS);
    971   source_map_.RegisterSource("ttsEngine", IDR_TTS_ENGINE_CUSTOM_BINDINGS_JS);
    972   source_map_.RegisterSource("webRequest", IDR_WEB_REQUEST_CUSTOM_BINDINGS_JS);
    973   source_map_.RegisterSource("webRequestInternal",
    974                              IDR_WEB_REQUEST_INTERNAL_CUSTOM_BINDINGS_JS);
    975   source_map_.RegisterSource("webstore", IDR_WEBSTORE_CUSTOM_BINDINGS_JS);
    976   source_map_.RegisterSource("windowControls", IDR_WINDOW_CONTROLS_JS);
    977   source_map_.RegisterSource("binding", IDR_BINDING_JS);
    978 
    979   // Custom types sources.
    980   source_map_.RegisterSource("ChromeSetting", IDR_CHROME_SETTING_JS);
    981   source_map_.RegisterSource("StorageArea", IDR_STORAGE_AREA_JS);
    982   source_map_.RegisterSource("ContentSetting", IDR_CONTENT_SETTING_JS);
    983   source_map_.RegisterSource("ChromeDirectSetting",
    984                              IDR_CHROME_DIRECT_SETTING_JS);
    985 
    986   // Platform app sources that are not API-specific..
    987   source_map_.RegisterSource("tagWatcher", IDR_TAG_WATCHER_JS);
    988   // Note: webView not webview so that this doesn't interfere with the
    989   // chrome.webview API bindings.
    990   source_map_.RegisterSource("webView", IDR_WEB_VIEW_JS);
    991   source_map_.RegisterSource("webViewExperimental",
    992                              IDR_WEB_VIEW_EXPERIMENTAL_JS);
    993   source_map_.RegisterSource("denyWebView", IDR_WEB_VIEW_DENY_JS);
    994   source_map_.RegisterSource("adView", IDR_AD_VIEW_JS);
    995   source_map_.RegisterSource("denyAdView", IDR_AD_VIEW_DENY_JS);
    996   source_map_.RegisterSource("platformApp", IDR_PLATFORM_APP_JS);
    997   source_map_.RegisterSource("injectAppTitlebar", IDR_INJECT_APP_TITLEBAR_JS);
    998 }
    999 
   1000 void Dispatcher::PopulateLazyBindingsMap() {
   1001   lazy_bindings_map_["app"] = InstallAppBindings;
   1002   lazy_bindings_map_["webstore"] = InstallWebstoreBindings;
   1003 }
   1004 
   1005 void Dispatcher::InstallBindings(ModuleSystem* module_system,
   1006                                  v8::Handle<v8::Context> v8_context,
   1007                                  const std::string& api) {
   1008   std::map<std::string, BindingInstaller>::const_iterator lazy_binding =
   1009       lazy_bindings_map_.find(api);
   1010   if (lazy_binding != lazy_bindings_map_.end()) {
   1011     v8::Handle<v8::Object> global(v8_context->Global());
   1012     v8::Handle<v8::Object> chrome =
   1013         global->Get(v8::String::New("chrome"))->ToObject();
   1014     (*lazy_binding->second)(module_system, chrome);
   1015   } else {
   1016     module_system->Require(api);
   1017   }
   1018 }
   1019 
   1020 void Dispatcher::DidCreateScriptContext(
   1021     WebFrame* frame, v8::Handle<v8::Context> v8_context, int extension_group,
   1022     int world_id) {
   1023 #if !defined(ENABLE_EXTENSIONS)
   1024   return;
   1025 #endif
   1026 
   1027   std::string extension_id = GetExtensionID(frame, world_id);
   1028 
   1029   const Extension* extension = extensions_.GetByID(extension_id);
   1030   if (!extension && !extension_id.empty()) {
   1031     // There are conditions where despite a context being associated with an
   1032     // extension, no extension actually gets found.  Ignore "invalid" because
   1033     // CSP blocks extension page loading by switching the extension ID to
   1034     // "invalid". This isn't interesting.
   1035     if (extension_id != "invalid") {
   1036       LOG(ERROR) << "Extension \"" << extension_id << "\" not found";
   1037       RenderThread::Get()->RecordUserMetrics("ExtensionNotFound_ED");
   1038     }
   1039 
   1040     extension_id = "";
   1041   }
   1042 
   1043   Feature::Context context_type = ClassifyJavaScriptContext(
   1044       extension_id, extension_group,
   1045       UserScriptSlave::GetDataSourceURLForFrame(frame),
   1046       frame->document().securityOrigin());
   1047 
   1048   ChromeV8Context* context =
   1049       new ChromeV8Context(v8_context, frame, extension, context_type);
   1050   v8_context_set_.Add(context);
   1051 
   1052   {
   1053     scoped_ptr<ModuleSystem> module_system(new ModuleSystem(context,
   1054                                                             &source_map_));
   1055     context->set_module_system(module_system.Pass());
   1056   }
   1057   ModuleSystem* module_system = context->module_system();
   1058 
   1059   // Enable natives in startup.
   1060   ModuleSystem::NativesEnabledScope natives_enabled_scope(
   1061       module_system);
   1062 
   1063   RegisterNativeHandlers(module_system, context);
   1064 
   1065   module_system->RegisterNativeHandler("chrome",
   1066       scoped_ptr<NativeHandler>(new ChromeNativeHandler(context)));
   1067   module_system->RegisterNativeHandler("print",
   1068       scoped_ptr<NativeHandler>(new PrintNativeHandler(context)));
   1069   module_system->RegisterNativeHandler("lazy_background_page",
   1070       scoped_ptr<NativeHandler>(
   1071           new LazyBackgroundPageNativeHandler(this, context)));
   1072   module_system->RegisterNativeHandler("logging",
   1073       scoped_ptr<NativeHandler>(new LoggingNativeHandler(context)));
   1074   module_system->RegisterNativeHandler("schema_registry",
   1075       v8_schema_registry_->AsNativeHandler());
   1076   module_system->RegisterNativeHandler("v8_context",
   1077       scoped_ptr<NativeHandler>(new V8ContextNativeHandler(context, this)));
   1078   module_system->RegisterNativeHandler("test_features",
   1079       scoped_ptr<NativeHandler>(new TestFeaturesNativeHandler(context)));
   1080 
   1081   int manifest_version = extension ? extension->manifest_version() : 1;
   1082   bool send_request_disabled =
   1083       (extension && Manifest::IsUnpackedLocation(extension->location()) &&
   1084        BackgroundInfo::HasLazyBackgroundPage(extension));
   1085   module_system->RegisterNativeHandler("process",
   1086       scoped_ptr<NativeHandler>(new ProcessInfoNativeHandler(
   1087           this, context, context->GetExtensionID(),
   1088           context->GetContextTypeDescription(),
   1089           ChromeRenderProcessObserver::is_incognito_process(),
   1090           manifest_version, send_request_disabled)));
   1091 
   1092   // chrome.Event is part of the public API (although undocumented). Make it
   1093   // lazily evalulate to Event from event_bindings.js. For extensions only
   1094   // though, not all webpages!
   1095   if (context->extension()) {
   1096     v8::Handle<v8::Object> chrome = AsObjectOrEmpty(GetOrCreateChrome(context));
   1097     if (!chrome.IsEmpty())
   1098       module_system->SetLazyField(chrome, "Event", kEventModule, "Event");
   1099   }
   1100 
   1101   AddOrRemoveBindingsForContext(context);
   1102 
   1103   bool is_within_platform_app = IsWithinPlatformApp();
   1104   // Inject custom JS into the platform app context.
   1105   if (is_within_platform_app) {
   1106     module_system->Require("platformApp");
   1107   }
   1108 
   1109   if (context_type == Feature::BLESSED_EXTENSION_CONTEXT &&
   1110       is_within_platform_app &&
   1111       GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV &&
   1112       CommandLine::ForCurrentProcess()->HasSwitch(
   1113           switches::kEnableAppWindowControls)) {
   1114     module_system->Require("windowControls");
   1115   }
   1116 
   1117   // Only platform apps support the <webview> tag, because the "webView" and
   1118   // "denyWebView" modules will affect the performance of DOM modifications
   1119   // (http://crbug.com/196453).
   1120   if (context_type == Feature::BLESSED_EXTENSION_CONTEXT &&
   1121       is_within_platform_app) {
   1122     // Note: setting up the WebView class here, not the chrome.webview API.
   1123     // The API will be automatically set up when first used.
   1124     if (extension->HasAPIPermission(APIPermission::kWebView)) {
   1125       module_system->Require("webView");
   1126       // TODO(mtomasz): Remove the Files app from the whitelist in M-31.
   1127       // crbug.com/297936
   1128       bool includeExperimental =
   1129           GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV ||
   1130           extension->id() == extension_misc::kIdentityApiUiAppId ||
   1131           extension->id() == "hhaomjibdihmijegdhdafkllkbggdgoj";  // Files App.
   1132       if (!includeExperimental) {
   1133         // TODO(asargent) We need a whitelist for webview experimental.
   1134         // crbug.com/264852
   1135         std::string id_hash = base::SHA1HashString(extension->id());
   1136         std::string hexencoded_id_hash = base::HexEncode(id_hash.c_str(),
   1137                                                          id_hash.length());
   1138         if (hexencoded_id_hash == "8C3741E3AF0B93B6E8E0DDD499BB0B74839EA578" ||
   1139             hexencoded_id_hash == "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB")
   1140           includeExperimental = true;
   1141       }
   1142       if (includeExperimental)
   1143         module_system->Require("webViewExperimental");
   1144     } else {
   1145       module_system->Require("denyWebView");
   1146     }
   1147   }
   1148 
   1149   // Same comment as above for <adview> tag.
   1150   if (context_type == Feature::BLESSED_EXTENSION_CONTEXT &&
   1151       is_within_platform_app) {
   1152     if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAdview)) {
   1153       if (extension->HasAPIPermission(APIPermission::kAdView)) {
   1154         module_system->Require("adView");
   1155       } else {
   1156         module_system->Require("denyAdView");
   1157       }
   1158     }
   1159   }
   1160 
   1161   VLOG(1) << "Num tracked contexts: " << v8_context_set_.size();
   1162 }
   1163 
   1164 std::string Dispatcher::GetExtensionID(const WebFrame* frame, int world_id) {
   1165   if (world_id != 0) {
   1166     // Isolated worlds (content script).
   1167     return user_script_slave_->GetExtensionIdForIsolatedWorld(world_id);
   1168   }
   1169 
   1170   // TODO(kalman): Delete this check.
   1171   if (frame->document().securityOrigin().isUnique())
   1172     return std::string();
   1173 
   1174   // Extension pages (chrome-extension:// URLs).
   1175   GURL frame_url = UserScriptSlave::GetDataSourceURLForFrame(frame);
   1176   return extensions_.GetExtensionOrAppIDByURL(frame_url);
   1177 }
   1178 
   1179 bool Dispatcher::IsWithinPlatformApp() {
   1180   for (std::set<std::string>::iterator iter = active_extension_ids_.begin();
   1181        iter != active_extension_ids_.end(); ++iter) {
   1182     const Extension* extension = extensions_.GetByID(*iter);
   1183     if (extension && extension->is_platform_app())
   1184       return true;
   1185   }
   1186   return false;
   1187 }
   1188 
   1189 void Dispatcher::WillReleaseScriptContext(
   1190     WebFrame* frame, v8::Handle<v8::Context> v8_context, int world_id) {
   1191   ChromeV8Context* context = v8_context_set_.GetByV8Context(v8_context);
   1192   if (!context)
   1193     return;
   1194 
   1195   context->DispatchOnUnloadEvent();
   1196   // TODO(kalman): add an invalidation observer interface to ChromeV8Context.
   1197   request_sender_->InvalidateSource(context);
   1198 
   1199   v8_context_set_.Remove(context);
   1200   VLOG(1) << "Num tracked contexts: " << v8_context_set_.size();
   1201 }
   1202 
   1203 void Dispatcher::DidCreateDocumentElement(WebKit::WebFrame* frame) {
   1204   if (IsWithinPlatformApp()) {
   1205     // WebKit doesn't let us define an additional user agent stylesheet, so we
   1206     // insert the default platform app stylesheet into all documents that are
   1207     // loaded in each app.
   1208     std::string stylesheet =
   1209         ResourceBundle::GetSharedInstance().
   1210             GetRawDataResource(IDR_PLATFORM_APP_CSS).as_string();
   1211     ReplaceFirstSubstringAfterOffset(&stylesheet, 0,
   1212                                      "$FONTFAMILY", system_font_family_);
   1213     ReplaceFirstSubstringAfterOffset(&stylesheet, 0,
   1214                                      "$FONTSIZE", system_font_size_);
   1215     frame->document().insertUserStyleSheet(
   1216         WebString::fromUTF8(stylesheet), WebDocument::UserStyleUserLevel);
   1217   }
   1218 
   1219   content_watcher_->DidCreateDocumentElement(frame);
   1220 }
   1221 
   1222 void Dispatcher::OnActivateExtension(const std::string& extension_id) {
   1223   const Extension* extension = extensions_.GetByID(extension_id);
   1224   if (!extension) {
   1225     // Extension was activated but was never loaded. This probably means that
   1226     // the renderer failed to load it (or the browser failed to tell us when it
   1227     // did). Failures shouldn't happen, but instead of crashing there (which
   1228     // executes on all renderers) be conservative and only crash in the renderer
   1229     // of the extension which failed to load; this one.
   1230     std::string& error = extension_load_errors_[extension_id];
   1231     char minidump[256];
   1232     base::debug::Alias(&minidump);
   1233     base::snprintf(minidump, arraysize(minidump),
   1234         "e::dispatcher:%s:%s", extension_id.c_str(), error.c_str());
   1235     CHECK(extension) << extension_id << " was never loaded: " << error;
   1236   }
   1237 
   1238   active_extension_ids_.insert(extension_id);
   1239 
   1240   // This is called when starting a new extension page, so start the idle
   1241   // handler ticking.
   1242   RenderThread::Get()->ScheduleIdleHandler(kInitialExtensionIdleHandlerDelayMs);
   1243 
   1244   UpdateActiveExtensions();
   1245 
   1246   if (is_webkit_initialized_) {
   1247     InitOriginPermissions(extension);
   1248     // DOMActivity logger for a main world controlled by an extension (as in
   1249     // the case of an extension background page, options page, popup etc.)
   1250     // gets an empty title.
   1251     DOMActivityLogger::AttachToWorld(DOMActivityLogger::kMainWorldId,
   1252                                      extension_id,
   1253                                      extension->url(),
   1254                                      string16());
   1255 
   1256     if (IsWithinPlatformApp())
   1257       EnableCustomElementWhiteList();
   1258   }
   1259 }
   1260 
   1261 void Dispatcher::InitOriginPermissions(const Extension* extension) {
   1262   // TODO(jstritar): We should try to remove this special case. Also, these
   1263   // whitelist entries need to be updated when the kManagement permission
   1264   // changes.
   1265   if (extension->HasAPIPermission(APIPermission::kManagement)) {
   1266     WebSecurityPolicy::addOriginAccessWhitelistEntry(
   1267         extension->url(),
   1268         WebString::fromUTF8(chrome::kChromeUIScheme),
   1269         WebString::fromUTF8(chrome::kChromeUIExtensionIconHost),
   1270         false);
   1271   }
   1272 
   1273   AddOrRemoveOriginPermissions(
   1274       UpdatedExtensionPermissionsInfo::ADDED,
   1275       extension,
   1276       extension->GetActivePermissions()->explicit_hosts());
   1277 }
   1278 
   1279 void Dispatcher::AddOrRemoveOriginPermissions(
   1280     UpdatedExtensionPermissionsInfo::Reason reason,
   1281     const Extension* extension,
   1282     const URLPatternSet& origins) {
   1283   for (URLPatternSet::const_iterator i = origins.begin();
   1284        i != origins.end(); ++i) {
   1285     const char* schemes[] = {
   1286       chrome::kHttpScheme,
   1287       chrome::kHttpsScheme,
   1288       chrome::kFileScheme,
   1289       chrome::kChromeUIScheme,
   1290     };
   1291     for (size_t j = 0; j < arraysize(schemes); ++j) {
   1292       if (i->MatchesScheme(schemes[j])) {
   1293         ((reason == UpdatedExtensionPermissionsInfo::REMOVED) ?
   1294          WebSecurityPolicy::removeOriginAccessWhitelistEntry :
   1295          WebSecurityPolicy::addOriginAccessWhitelistEntry)(
   1296               extension->url(),
   1297               WebString::fromUTF8(schemes[j]),
   1298               WebString::fromUTF8(i->host()),
   1299               i->match_subdomains());
   1300       }
   1301     }
   1302   }
   1303 }
   1304 
   1305 void Dispatcher::EnableCustomElementWhiteList() {
   1306   WebKit::WebRuntimeFeatures::enableCustomElements(true);
   1307   WebKit::WebCustomElement::allowTagName("webview");
   1308   // TODO(fsamuel): Add <adview> to the whitelist once it has been converted
   1309   // into a custom element.
   1310   WebKit::WebCustomElement::allowTagName("browser-plugin");
   1311 }
   1312 
   1313 void Dispatcher::AddOrRemoveBindings(const std::string& extension_id) {
   1314   v8_context_set().ForEach(
   1315       extension_id,
   1316       NULL,  // all render views
   1317       base::Bind(&Dispatcher::AddOrRemoveBindingsForContext,
   1318                  base::Unretained(this)));
   1319 }
   1320 
   1321 void Dispatcher::OnUpdatePermissions(int reason_id,
   1322                                      const std::string& extension_id,
   1323                                      const APIPermissionSet& apis,
   1324                                      const URLPatternSet& explicit_hosts,
   1325                                      const URLPatternSet& scriptable_hosts) {
   1326   const Extension* extension = extensions_.GetByID(extension_id);
   1327   if (!extension)
   1328     return;
   1329 
   1330   scoped_refptr<const PermissionSet> delta =
   1331       new PermissionSet(apis, explicit_hosts, scriptable_hosts);
   1332   scoped_refptr<const PermissionSet> old_active =
   1333       extension->GetActivePermissions();
   1334   UpdatedExtensionPermissionsInfo::Reason reason =
   1335       static_cast<UpdatedExtensionPermissionsInfo::Reason>(reason_id);
   1336 
   1337   const PermissionSet* new_active = NULL;
   1338   switch (reason) {
   1339     case UpdatedExtensionPermissionsInfo::ADDED:
   1340       new_active = PermissionSet::CreateUnion(old_active.get(), delta.get());
   1341       break;
   1342     case UpdatedExtensionPermissionsInfo::REMOVED:
   1343       new_active =
   1344           PermissionSet::CreateDifference(old_active.get(), delta.get());
   1345       break;
   1346   }
   1347 
   1348   PermissionsData::SetActivePermissions(extension, new_active);
   1349   AddOrRemoveOriginPermissions(reason, extension, explicit_hosts);
   1350   AddOrRemoveBindings(extension->id());
   1351 }
   1352 
   1353 void Dispatcher::OnUpdateTabSpecificPermissions(
   1354     int page_id,
   1355     int tab_id,
   1356     const std::string& extension_id,
   1357     const URLPatternSet& origin_set) {
   1358   RenderView* view = TabFinder::Find(tab_id);
   1359 
   1360   // For now, the message should only be sent to the render view that contains
   1361   // the target tab. This may change. Either way, if this is the target tab it
   1362   // gives us the chance to check against the page ID to avoid races.
   1363   DCHECK(view);
   1364   if (view && view->GetPageId() != page_id)
   1365     return;
   1366 
   1367   const Extension* extension = extensions_.GetByID(extension_id);
   1368   if (!extension)
   1369     return;
   1370 
   1371   PermissionsData::UpdateTabSpecificPermissions(
   1372       extension,
   1373       tab_id,
   1374       new PermissionSet(APIPermissionSet(), origin_set, URLPatternSet()));
   1375 }
   1376 
   1377 void Dispatcher::OnClearTabSpecificPermissions(
   1378     int tab_id,
   1379     const std::vector<std::string>& extension_ids) {
   1380   for (std::vector<std::string>::const_iterator it = extension_ids.begin();
   1381        it != extension_ids.end(); ++it) {
   1382     const Extension* extension = extensions_.GetByID(*it);
   1383     if (extension)
   1384       PermissionsData::ClearTabSpecificPermissions(extension, tab_id);
   1385   }
   1386 }
   1387 
   1388 void Dispatcher::OnUpdateUserScripts(
   1389     base::SharedMemoryHandle scripts) {
   1390   DCHECK(base::SharedMemory::IsHandleValid(scripts)) << "Bad scripts handle";
   1391   user_script_slave_->UpdateScripts(scripts);
   1392   UpdateActiveExtensions();
   1393 }
   1394 
   1395 void Dispatcher::UpdateActiveExtensions() {
   1396   // In single-process mode, the browser process reports the active extensions.
   1397   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess))
   1398     return;
   1399 
   1400   std::set<std::string> active_extensions = active_extension_ids_;
   1401   user_script_slave_->GetActiveExtensions(&active_extensions);
   1402   child_process_logging::SetActiveExtensions(active_extensions);
   1403 }
   1404 
   1405 void Dispatcher::OnUsingWebRequestAPI(
   1406     bool adblock, bool adblock_plus, bool other) {
   1407   webrequest_adblock_ = adblock;
   1408   webrequest_adblock_plus_ = adblock_plus;
   1409   webrequest_other_ = other;
   1410 }
   1411 
   1412 void Dispatcher::OnShouldSuspend(const std::string& extension_id,
   1413                                  int sequence_id) {
   1414   RenderThread::Get()->Send(
   1415       new ExtensionHostMsg_ShouldSuspendAck(extension_id, sequence_id));
   1416 }
   1417 
   1418 void Dispatcher::OnSuspend(const std::string& extension_id) {
   1419   // Dispatch the suspend event. This doesn't go through the standard event
   1420   // dispatch machinery because it requires special handling. We need to let
   1421   // the browser know when we are starting and stopping the event dispatch, so
   1422   // that it still considers the extension idle despite any activity the suspend
   1423   // event creates.
   1424   DispatchEvent(extension_id, kOnSuspendEvent);
   1425   RenderThread::Get()->Send(new ExtensionHostMsg_SuspendAck(extension_id));
   1426 }
   1427 
   1428 void Dispatcher::OnCancelSuspend(const std::string& extension_id) {
   1429   DispatchEvent(extension_id, kOnSuspendCanceledEvent);
   1430 }
   1431 
   1432 // TODO(kalman): This is checking for the wrong thing, it should be checking if
   1433 // the frame's security origin is unique. The extension sandbox directive is
   1434 // checked for in chrome/common/extensions/csp_handler.cc.
   1435 bool Dispatcher::IsSandboxedPage(const GURL& url) const {
   1436   if (url.SchemeIs(extensions::kExtensionScheme)) {
   1437     const Extension* extension = extensions_.GetByID(url.host());
   1438     if (extension) {
   1439       return extensions::SandboxedPageInfo::IsSandboxedPage(extension,
   1440                                                             url.path());
   1441     }
   1442   }
   1443   return false;
   1444 }
   1445 
   1446 Feature::Context Dispatcher::ClassifyJavaScriptContext(
   1447     const std::string& extension_id,
   1448     int extension_group,
   1449     const GURL& url,
   1450     const WebKit::WebSecurityOrigin& origin) {
   1451   DCHECK_GE(extension_group, 0);
   1452   if (extension_group == EXTENSION_GROUP_CONTENT_SCRIPTS) {
   1453     return extensions_.Contains(extension_id) ?
   1454         Feature::CONTENT_SCRIPT_CONTEXT : Feature::UNSPECIFIED_CONTEXT;
   1455   }
   1456 
   1457   // We have an explicit check for sandboxed pages before checking whether the
   1458   // extension is active in this process because:
   1459   // 1. Sandboxed pages run in the same process as regular extension pages, so
   1460   //    the extension is considered active.
   1461   // 2. ScriptContext creation (which triggers bindings injection) happens
   1462   //    before the SecurityContext is updated with the sandbox flags (after
   1463   //    reading the CSP header), so the caller can't check if the context's
   1464   //    security origin is unique yet.
   1465   if (IsSandboxedPage(url))
   1466     return Feature::WEB_PAGE_CONTEXT;
   1467 
   1468   if (IsExtensionActive(extension_id))
   1469     return Feature::BLESSED_EXTENSION_CONTEXT;
   1470 
   1471   // TODO(kalman): This isUnique() check is wrong, it should be performed as
   1472   // part of IsSandboxedPage().
   1473   if (!origin.isUnique() && extensions_.ExtensionBindingsAllowed(url)) {
   1474     return extensions_.Contains(extension_id) ?
   1475         Feature::UNBLESSED_EXTENSION_CONTEXT : Feature::UNSPECIFIED_CONTEXT;
   1476   }
   1477 
   1478   if (url.is_valid())
   1479     return Feature::WEB_PAGE_CONTEXT;
   1480 
   1481   return Feature::UNSPECIFIED_CONTEXT;
   1482 }
   1483 
   1484 void Dispatcher::OnExtensionResponse(int request_id,
   1485                                      bool success,
   1486                                      const base::ListValue& response,
   1487                                      const std::string& error) {
   1488   request_sender_->HandleResponse(request_id, success, response, error);
   1489 }
   1490 
   1491 bool Dispatcher::CheckContextAccessToExtensionAPI(
   1492     const std::string& function_name, ChromeV8Context* context) const {
   1493   if (!context) {
   1494     DLOG(ERROR) << "Not in a v8::Context";
   1495     return false;
   1496   }
   1497 
   1498   if (!context->extension()) {
   1499     v8::ThrowException(
   1500         v8::Exception::Error(v8::String::New("Not in an extension.")));
   1501     return false;
   1502   }
   1503 
   1504   // Theoretically we could end up with bindings being injected into sandboxed
   1505   // frames, for example content scripts. Don't let them execute API functions.
   1506   WebKit::WebFrame* frame = context->web_frame();
   1507   if (IsSandboxedPage(UserScriptSlave::GetDataSourceURLForFrame(frame))) {
   1508     static const char kMessage[] =
   1509         "%s cannot be used within a sandboxed frame.";
   1510     std::string error_msg = base::StringPrintf(kMessage, function_name.c_str());
   1511     v8::ThrowException(
   1512         v8::Exception::Error(v8::String::New(error_msg.c_str())));
   1513     return false;
   1514   }
   1515 
   1516   Feature::Availability availability = context->GetAvailability(function_name);
   1517   if (!availability.is_available()) {
   1518     APIActivityLogger::LogBlockedCall(context->extension()->id(),
   1519                                       function_name,
   1520                                       availability.result());
   1521     v8::ThrowException(v8::Exception::Error(
   1522         v8::String::New(availability.message().c_str())));
   1523   }
   1524 
   1525   return availability.is_available();
   1526 }
   1527 
   1528 void Dispatcher::DispatchEvent(const std::string& extension_id,
   1529                                const std::string& event_name) const {
   1530   base::ListValue args;
   1531   args.Set(0, new base::StringValue(event_name));
   1532   args.Set(1, new base::ListValue());
   1533   v8_context_set_.ForEach(
   1534       extension_id,
   1535       NULL,  // all render views
   1536       base::Bind(&CallModuleMethod,
   1537                  kEventModule,
   1538                  kEventDispatchFunction,
   1539                  &args));
   1540 }
   1541 
   1542 void Dispatcher::InvokeModuleSystemMethod(
   1543       content::RenderView* render_view,
   1544       const std::string& extension_id,
   1545       const std::string& module_name,
   1546       const std::string& function_name,
   1547       const base::ListValue& args,
   1548       bool user_gesture) {
   1549   scoped_ptr<WebScopedUserGesture> web_user_gesture;
   1550   if (user_gesture)
   1551     web_user_gesture.reset(new WebScopedUserGesture);
   1552 
   1553   v8_context_set_.ForEach(
   1554       extension_id,
   1555       render_view,
   1556       base::Bind(&CallModuleMethod, module_name, function_name, &args));
   1557 
   1558   // Reset the idle handler each time there's any activity like event or message
   1559   // dispatch, for which Invoke is the chokepoint.
   1560   if (is_extension_process_) {
   1561     RenderThread::Get()->ScheduleIdleHandler(
   1562         kInitialExtensionIdleHandlerDelayMs);
   1563   }
   1564 
   1565   // Tell the browser process when an event has been dispatched with a lazy
   1566   // background page active.
   1567   const Extension* extension = extensions_.GetByID(extension_id);
   1568   if (extension && BackgroundInfo::HasLazyBackgroundPage(extension) &&
   1569       module_name == kEventModule &&
   1570       function_name == kEventDispatchFunction) {
   1571     RenderView* background_view =
   1572         ExtensionHelper::GetBackgroundPage(extension_id);
   1573     if (background_view) {
   1574       background_view->Send(new ExtensionHostMsg_EventAck(
   1575           background_view->GetRoutingID()));
   1576     }
   1577   }
   1578 }
   1579 
   1580 }  // namespace extensions
   1581