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