1 // Copyright 2014 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.
5 #include "extensions/renderer/dispatcher.h"
7 #include "base/callback.h"
8 #include "base/command_line.h"
9 #include "base/debug/alias.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/metrics/user_metrics_action.h"
12 #include "base/strings/string_piece.h"
13 #include "base/strings/string_split.h"
14 #include "base/strings/string_util.h"
15 #include "base/values.h"
16 #include "content/public/common/content_switches.h"
17 #include "content/public/common/url_constants.h"
18 #include "content/public/renderer/render_thread.h"
19 #include "content/public/renderer/render_view.h"
20 #include "content/public/renderer/v8_value_converter.h"
21 #include "extensions/common/api/messaging/message.h"
22 #include "extensions/common/constants.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/extension_api.h"
25 #include "extensions/common/extension_messages.h"
26 #include "extensions/common/extension_urls.h"
27 #include "extensions/common/features/feature.h"
28 #include "extensions/common/features/feature_provider.h"
29 #include "extensions/common/manifest.h"
30 #include "extensions/common/manifest_constants.h"
31 #include "extensions/common/manifest_handlers/background_info.h"
32 #include "extensions/common/manifest_handlers/externally_connectable.h"
33 #include "extensions/common/manifest_handlers/sandboxed_page_info.h"
34 #include "extensions/common/message_bundle.h"
35 #include "extensions/common/permissions/permission_set.h"
36 #include "extensions/common/permissions/permissions_data.h"
37 #include "extensions/common/switches.h"
38 #include "extensions/common/view_type.h"
39 #include "extensions/renderer/api_activity_logger.h"
40 #include "extensions/renderer/api_definitions_natives.h"
41 #include "extensions/renderer/app_runtime_custom_bindings.h"
42 #include "extensions/renderer/binding_generating_native_handler.h"
43 #include "extensions/renderer/blob_native_handler.h"
44 #include "extensions/renderer/content_watcher.h"
45 #include "extensions/renderer/context_menus_custom_bindings.h"
46 #include "extensions/renderer/css_native_handler.h"
47 #include "extensions/renderer/dispatcher_delegate.h"
48 #include "extensions/renderer/document_custom_bindings.h"
49 #include "extensions/renderer/dom_activity_logger.h"
50 #include "extensions/renderer/event_bindings.h"
51 #include "extensions/renderer/extension_groups.h"
52 #include "extensions/renderer/extension_helper.h"
53 #include "extensions/renderer/extensions_renderer_client.h"
54 #include "extensions/renderer/file_system_natives.h"
55 #include "extensions/renderer/i18n_custom_bindings.h"
56 #include "extensions/renderer/id_generator_custom_bindings.h"
57 #include "extensions/renderer/lazy_background_page_native_handler.h"
58 #include "extensions/renderer/logging_native_handler.h"
59 #include "extensions/renderer/messaging_bindings.h"
60 #include "extensions/renderer/module_system.h"
61 #include "extensions/renderer/print_native_handler.h"
62 #include "extensions/renderer/process_info_native_handler.h"
63 #include "extensions/renderer/render_view_observer_natives.h"
64 #include "extensions/renderer/request_sender.h"
65 #include "extensions/renderer/runtime_custom_bindings.h"
66 #include "extensions/renderer/safe_builtins.h"
67 #include "extensions/renderer/script_context.h"
68 #include "extensions/renderer/script_context_set.h"
69 #include "extensions/renderer/send_request_natives.h"
70 #include "extensions/renderer/set_icon_natives.h"
71 #include "extensions/renderer/test_features_native_handler.h"
72 #include "extensions/renderer/user_gestures_native_handler.h"
73 #include "extensions/renderer/user_script_slave.h"
74 #include "extensions/renderer/utils_native_handler.h"
75 #include "extensions/renderer/v8_context_native_handler.h"
76 #include "grit/common_resources.h"
77 #include "grit/renderer_resources.h"
78 #include "third_party/WebKit/public/platform/WebString.h"
79 #include "third_party/WebKit/public/platform/WebURLRequest.h"
80 #include "third_party/WebKit/public/web/WebCustomElement.h"
81 #include "third_party/WebKit/public/web/WebDataSource.h"
82 #include "third_party/WebKit/public/web/WebDocument.h"
83 #include "third_party/WebKit/public/web/WebFrame.h"
84 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
85 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
86 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
87 #include "third_party/WebKit/public/web/WebView.h"
88 #include "ui/base/layout.h"
89 #include "ui/base/resource/resource_bundle.h"
90 #include "v8/include/v8.h"
92 using base::UserMetricsAction
;
93 using blink::WebDataSource
;
94 using blink::WebDocument
;
95 using blink::WebFrame
;
96 using blink::WebScopedUserGesture
;
97 using blink::WebSecurityPolicy
;
98 using blink::WebString
;
99 using blink::WebVector
;
100 using blink::WebView
;
101 using content::RenderThread
;
102 using content::RenderView
;
104 namespace extensions
{
108 static const int64 kInitialExtensionIdleHandlerDelayMs
= 5 * 1000;
109 static const int64 kMaxExtensionIdleHandlerDelayMs
= 5 * 60 * 1000;
110 static const char kEventDispatchFunction
[] = "dispatchEvent";
111 static const char kOnSuspendEvent
[] = "runtime.onSuspend";
112 static const char kOnSuspendCanceledEvent
[] = "runtime.onSuspendCanceled";
114 // Returns the global value for "chrome" from |context|. If one doesn't exist
115 // creates a new object for it.
117 // Note that this isn't necessarily an object, since webpages can write, for
118 // example, "window.chrome = true".
119 v8::Handle
<v8::Value
> GetOrCreateChrome(ScriptContext
* context
) {
120 v8::Handle
<v8::String
> chrome_string(
121 v8::String::NewFromUtf8(context
->isolate(), "chrome"));
122 v8::Handle
<v8::Object
> global(context
->v8_context()->Global());
123 v8::Handle
<v8::Value
> chrome(global
->Get(chrome_string
));
124 if (chrome
->IsUndefined()) {
125 chrome
= v8::Object::New(context
->isolate());
126 global
->Set(chrome_string
, chrome
);
131 // Returns |value| cast to an object if possible, else an empty handle.
132 v8::Handle
<v8::Object
> AsObjectOrEmpty(v8::Handle
<v8::Value
> value
) {
133 return value
->IsObject() ? value
.As
<v8::Object
>() : v8::Handle
<v8::Object
>();
136 // Calls a method |method_name| in a module |module_name| belonging to the
137 // module system from |context|. Intended as a callback target from
138 // ScriptContextSet::ForEach.
139 void CallModuleMethod(const std::string
& module_name
,
140 const std::string
& method_name
,
141 const base::ListValue
* args
,
142 ScriptContext
* context
) {
143 v8::HandleScope
handle_scope(context
->isolate());
144 v8::Context::Scope
context_scope(context
->v8_context());
146 scoped_ptr
<content::V8ValueConverter
> converter(
147 content::V8ValueConverter::create());
149 std::vector
<v8::Handle
<v8::Value
> > arguments
;
150 for (base::ListValue::const_iterator it
= args
->begin(); it
!= args
->end();
152 arguments
.push_back(converter
->ToV8Value(*it
, context
->v8_context()));
155 context
->module_system()->CallModuleMethod(
156 module_name
, method_name
, &arguments
);
159 // This handles the "chrome." root API object in script contexts.
160 class ChromeNativeHandler
: public ObjectBackedNativeHandler
{
162 explicit ChromeNativeHandler(ScriptContext
* context
)
163 : ObjectBackedNativeHandler(context
) {
166 base::Bind(&ChromeNativeHandler::GetChrome
, base::Unretained(this)));
169 void GetChrome(const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
170 args
.GetReturnValue().Set(GetOrCreateChrome(context()));
176 Dispatcher::Dispatcher(DispatcherDelegate
* delegate
)
177 : delegate_(delegate
),
178 content_watcher_(new ContentWatcher()),
179 source_map_(&ResourceBundle::GetSharedInstance()),
180 v8_schema_registry_(new V8SchemaRegistry
),
181 is_webkit_initialized_(false) {
182 const CommandLine
& command_line
= *(CommandLine::ForCurrentProcess());
183 is_extension_process_
=
184 command_line
.HasSwitch(extensions::switches::kExtensionProcess
) ||
185 command_line
.HasSwitch(::switches::kSingleProcess
);
187 if (is_extension_process_
) {
188 RenderThread::Get()->SetIdleNotificationDelayInMs(
189 kInitialExtensionIdleHandlerDelayMs
);
192 RenderThread::Get()->RegisterExtension(SafeBuiltins::CreateV8Extension());
194 user_script_slave_
.reset(new UserScriptSlave(&extensions_
));
195 request_sender_
.reset(new RequestSender(this));
199 Dispatcher::~Dispatcher() {
202 bool Dispatcher::IsExtensionActive(const std::string
& extension_id
) const {
204 active_extension_ids_
.find(extension_id
) != active_extension_ids_
.end();
206 CHECK(extensions_
.Contains(extension_id
));
210 std::string
Dispatcher::GetExtensionID(const WebFrame
* frame
, int world_id
) {
212 // Isolated worlds (content script).
213 return user_script_slave_
->GetExtensionIdForIsolatedWorld(world_id
);
216 // TODO(kalman): Delete this check.
217 if (frame
->document().securityOrigin().isUnique())
218 return std::string();
220 // Extension pages (chrome-extension:// URLs).
221 GURL frame_url
= ScriptContext::GetDataSourceURLForFrame(frame
);
222 return extensions_
.GetExtensionOrAppIDByURL(frame_url
);
225 void Dispatcher::DidCreateScriptContext(
227 const v8::Handle
<v8::Context
>& v8_context
,
230 #if !defined(ENABLE_EXTENSIONS)
234 std::string extension_id
= GetExtensionID(frame
, world_id
);
236 const Extension
* extension
= extensions_
.GetByID(extension_id
);
237 if (!extension
&& !extension_id
.empty()) {
238 // There are conditions where despite a context being associated with an
239 // extension, no extension actually gets found. Ignore "invalid" because
240 // CSP blocks extension page loading by switching the extension ID to
241 // "invalid". This isn't interesting.
242 if (extension_id
!= "invalid") {
243 LOG(ERROR
) << "Extension \"" << extension_id
<< "\" not found";
244 RenderThread::Get()->RecordAction(
245 UserMetricsAction("ExtensionNotFound_ED"));
251 Feature::Context context_type
=
252 ClassifyJavaScriptContext(extension
,
254 ScriptContext::GetDataSourceURLForFrame(frame
),
255 frame
->document().securityOrigin());
257 ScriptContext
* context
=
258 delegate_
->CreateScriptContext(v8_context
, frame
, extension
, context_type
)
260 script_context_set_
.Add(context
);
263 InitOriginPermissions(extension
, context_type
);
267 scoped_ptr
<ModuleSystem
> module_system(
268 new ModuleSystem(context
, &source_map_
));
269 context
->set_module_system(module_system
.Pass());
271 ModuleSystem
* module_system
= context
->module_system();
273 // Enable natives in startup.
274 ModuleSystem::NativesEnabledScope
natives_enabled_scope(module_system
);
276 RegisterNativeHandlers(module_system
, context
);
278 // chrome.Event is part of the public API (although undocumented). Make it
279 // lazily evalulate to Event from event_bindings.js. For extensions only
280 // though, not all webpages!
281 if (context
->extension()) {
282 v8::Handle
<v8::Object
> chrome
= AsObjectOrEmpty(GetOrCreateChrome(context
));
283 if (!chrome
.IsEmpty())
284 module_system
->SetLazyField(chrome
, "Event", kEventBindings
, "Event");
287 UpdateBindingsForContext(context
);
289 bool is_within_platform_app
= IsWithinPlatformApp();
290 // Inject custom JS into the platform app context.
291 if (is_within_platform_app
) {
292 module_system
->Require("platformApp");
295 delegate_
->RequireAdditionalModules(
296 module_system
, extension
, context_type
, is_within_platform_app
);
298 VLOG(1) << "Num tracked contexts: " << script_context_set_
.size();
301 void Dispatcher::WillReleaseScriptContext(
303 const v8::Handle
<v8::Context
>& v8_context
,
305 ScriptContext
* context
= script_context_set_
.GetByV8Context(v8_context
);
309 context
->DispatchOnUnloadEvent();
310 // TODO(kalman): add an invalidation observer interface to ScriptContext.
311 request_sender_
->InvalidateSource(context
);
313 script_context_set_
.Remove(context
);
314 VLOG(1) << "Num tracked contexts: " << script_context_set_
.size();
317 void Dispatcher::DidCreateDocumentElement(blink::WebFrame
* frame
) {
318 if (IsWithinPlatformApp()) {
319 // WebKit doesn't let us define an additional user agent stylesheet, so we
320 // insert the default platform app stylesheet into all documents that are
321 // loaded in each app.
322 std::string stylesheet
= ResourceBundle::GetSharedInstance()
323 .GetRawDataResource(IDR_PLATFORM_APP_CSS
)
325 ReplaceFirstSubstringAfterOffset(
326 &stylesheet
, 0, "$FONTFAMILY", system_font_family_
);
327 ReplaceFirstSubstringAfterOffset(
328 &stylesheet
, 0, "$FONTSIZE", system_font_size_
);
329 frame
->document().insertStyleSheet(WebString::fromUTF8(stylesheet
));
332 content_watcher_
->DidCreateDocumentElement(frame
);
335 void Dispatcher::DidMatchCSS(
336 blink::WebFrame
* frame
,
337 const blink::WebVector
<blink::WebString
>& newly_matching_selectors
,
338 const blink::WebVector
<blink::WebString
>& stopped_matching_selectors
) {
339 content_watcher_
->DidMatchCSS(
340 frame
, newly_matching_selectors
, stopped_matching_selectors
);
343 void Dispatcher::OnExtensionResponse(int request_id
,
345 const base::ListValue
& response
,
346 const std::string
& error
) {
347 request_sender_
->HandleResponse(request_id
, success
, response
, error
);
350 bool Dispatcher::CheckContextAccessToExtensionAPI(
351 const std::string
& function_name
,
352 ScriptContext
* context
) const {
354 DLOG(ERROR
) << "Not in a v8::Context";
358 if (!context
->extension()) {
359 context
->isolate()->ThrowException(v8::Exception::Error(
360 v8::String::NewFromUtf8(context
->isolate(), "Not in an extension.")));
364 // Theoretically we could end up with bindings being injected into sandboxed
365 // frames, for example content scripts. Don't let them execute API functions.
366 blink::WebFrame
* frame
= context
->web_frame();
367 if (IsSandboxedPage(ScriptContext::GetDataSourceURLForFrame(frame
))) {
368 static const char kMessage
[] =
369 "%s cannot be used within a sandboxed frame.";
370 std::string error_msg
= base::StringPrintf(kMessage
, function_name
.c_str());
371 context
->isolate()->ThrowException(v8::Exception::Error(
372 v8::String::NewFromUtf8(context
->isolate(), error_msg
.c_str())));
376 Feature::Availability availability
= context
->GetAvailability(function_name
);
377 if (!availability
.is_available()) {
378 context
->isolate()->ThrowException(
379 v8::Exception::Error(v8::String::NewFromUtf8(
380 context
->isolate(), availability
.message().c_str())));
383 return availability
.is_available();
386 void Dispatcher::DispatchEvent(const std::string
& extension_id
,
387 const std::string
& event_name
) const {
388 base::ListValue args
;
389 args
.Set(0, new base::StringValue(event_name
));
390 args
.Set(1, new base::ListValue());
392 // Needed for Windows compilation, since kEventBindings is declared extern.
393 const char* local_event_bindings
= kEventBindings
;
394 script_context_set_
.ForEach(extension_id
,
395 NULL
, // all render views
396 base::Bind(&CallModuleMethod
,
397 local_event_bindings
,
398 kEventDispatchFunction
,
402 void Dispatcher::InvokeModuleSystemMethod(content::RenderView
* render_view
,
403 const std::string
& extension_id
,
404 const std::string
& module_name
,
405 const std::string
& function_name
,
406 const base::ListValue
& args
,
408 scoped_ptr
<WebScopedUserGesture
> web_user_gesture
;
410 web_user_gesture
.reset(new WebScopedUserGesture
);
412 script_context_set_
.ForEach(
415 base::Bind(&CallModuleMethod
, module_name
, function_name
, &args
));
417 // Reset the idle handler each time there's any activity like event or message
418 // dispatch, for which Invoke is the chokepoint.
419 if (is_extension_process_
) {
420 RenderThread::Get()->ScheduleIdleHandler(
421 kInitialExtensionIdleHandlerDelayMs
);
424 // Tell the browser process when an event has been dispatched with a lazy
425 // background page active.
426 const Extension
* extension
= extensions_
.GetByID(extension_id
);
427 if (extension
&& BackgroundInfo::HasLazyBackgroundPage(extension
) &&
428 module_name
== kEventBindings
&&
429 function_name
== kEventDispatchFunction
) {
430 RenderView
* background_view
=
431 ExtensionHelper::GetBackgroundPage(extension_id
);
432 if (background_view
) {
433 background_view
->Send(
434 new ExtensionHostMsg_EventAck(background_view
->GetRoutingID()));
439 void Dispatcher::ClearPortData(int port_id
) {
440 // Only the target port side has entries in |port_to_tab_id_map_|. If
441 // |port_id| is a source port, std::map::erase() will just silently fail
443 port_to_tab_id_map_
.erase(port_id
);
446 bool Dispatcher::OnControlMessageReceived(const IPC::Message
& message
) {
448 IPC_BEGIN_MESSAGE_MAP(Dispatcher
, message
)
449 IPC_MESSAGE_HANDLER(ExtensionMsg_ActivateExtension
, OnActivateExtension
)
450 IPC_MESSAGE_HANDLER(ExtensionMsg_CancelSuspend
, OnCancelSuspend
)
451 IPC_MESSAGE_HANDLER(ExtensionMsg_ClearTabSpecificPermissions
,
452 OnClearTabSpecificPermissions
)
453 IPC_MESSAGE_HANDLER(ExtensionMsg_DeliverMessage
, OnDeliverMessage
)
454 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnConnect
, OnDispatchOnConnect
)
455 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnDisconnect
, OnDispatchOnDisconnect
)
456 IPC_MESSAGE_HANDLER(ExtensionMsg_Loaded
, OnLoaded
)
457 IPC_MESSAGE_HANDLER(ExtensionMsg_MessageInvoke
, OnMessageInvoke
)
458 IPC_MESSAGE_HANDLER(ExtensionMsg_SetChannel
, OnSetChannel
)
459 IPC_MESSAGE_HANDLER(ExtensionMsg_SetFunctionNames
, OnSetFunctionNames
)
460 IPC_MESSAGE_HANDLER(ExtensionMsg_SetScriptingWhitelist
,
461 OnSetScriptingWhitelist
)
462 IPC_MESSAGE_HANDLER(ExtensionMsg_SetSystemFont
, OnSetSystemFont
)
463 IPC_MESSAGE_HANDLER(ExtensionMsg_ShouldSuspend
, OnShouldSuspend
)
464 IPC_MESSAGE_HANDLER(ExtensionMsg_Suspend
, OnSuspend
)
465 IPC_MESSAGE_HANDLER(ExtensionMsg_Unloaded
, OnUnloaded
)
466 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdatePermissions
, OnUpdatePermissions
)
467 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateTabSpecificPermissions
,
468 OnUpdateTabSpecificPermissions
)
469 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts
, OnUpdateUserScripts
)
470 IPC_MESSAGE_HANDLER(ExtensionMsg_UsingWebRequestAPI
, OnUsingWebRequestAPI
)
471 IPC_MESSAGE_FORWARD(ExtensionMsg_WatchPages
,
472 content_watcher_
.get(),
473 ContentWatcher::OnWatchPages
)
474 IPC_MESSAGE_UNHANDLED(handled
= false)
475 IPC_END_MESSAGE_MAP()
480 void Dispatcher::WebKitInitialized() {
481 // For extensions, we want to ensure we call the IdleHandler every so often,
482 // even if the extension keeps up activity.
483 if (is_extension_process_
) {
484 forced_idle_timer_
.reset(new base::RepeatingTimer
<content::RenderThread
>);
485 forced_idle_timer_
->Start(
487 base::TimeDelta::FromMilliseconds(kMaxExtensionIdleHandlerDelayMs
),
489 &RenderThread::IdleHandler
);
492 // Initialize host permissions for any extensions that were activated before
493 // WebKit was initialized.
494 for (std::set
<std::string
>::iterator iter
= active_extension_ids_
.begin();
495 iter
!= active_extension_ids_
.end();
497 const Extension
* extension
= extensions_
.GetByID(*iter
);
501 EnableCustomElementWhiteList();
503 is_webkit_initialized_
= true;
506 void Dispatcher::IdleNotification() {
507 if (is_extension_process_
) {
508 // Dampen the forced delay as well if the extension stays idle for long
510 int64 forced_delay_ms
=
511 std::max(RenderThread::Get()->GetIdleNotificationDelayInMs(),
512 kMaxExtensionIdleHandlerDelayMs
);
513 forced_idle_timer_
->Stop();
514 forced_idle_timer_
->Start(
516 base::TimeDelta::FromMilliseconds(forced_delay_ms
),
518 &RenderThread::IdleHandler
);
522 void Dispatcher::OnRenderProcessShutdown() {
523 v8_schema_registry_
.reset();
524 forced_idle_timer_
.reset();
527 void Dispatcher::OnActivateExtension(const std::string
& extension_id
) {
528 const Extension
* extension
= extensions_
.GetByID(extension_id
);
530 // Extension was activated but was never loaded. This probably means that
531 // the renderer failed to load it (or the browser failed to tell us when it
532 // did). Failures shouldn't happen, but instead of crashing there (which
533 // executes on all renderers) be conservative and only crash in the renderer
534 // of the extension which failed to load; this one.
535 std::string
& error
= extension_load_errors_
[extension_id
];
537 base::debug::Alias(&minidump
);
538 base::snprintf(minidump
,
540 "e::dispatcher:%s:%s",
541 extension_id
.c_str(),
543 CHECK(extension
) << extension_id
<< " was never loaded: " << error
;
546 active_extension_ids_
.insert(extension_id
);
548 // This is called when starting a new extension page, so start the idle
550 RenderThread::Get()->ScheduleIdleHandler(kInitialExtensionIdleHandlerDelayMs
);
552 if (is_webkit_initialized_
) {
553 extensions::DOMActivityLogger::AttachToWorld(
554 extensions::DOMActivityLogger::kMainWorldId
, extension_id
);
557 UpdateActiveExtensions();
560 void Dispatcher::OnCancelSuspend(const std::string
& extension_id
) {
561 DispatchEvent(extension_id
, kOnSuspendCanceledEvent
);
564 void Dispatcher::OnClearTabSpecificPermissions(
566 const std::vector
<std::string
>& extension_ids
) {
567 delegate_
->ClearTabSpecificPermissions(this, tab_id
, extension_ids
);
570 void Dispatcher::OnDeliverMessage(int target_port_id
, const Message
& message
) {
571 scoped_ptr
<RequestSender::ScopedTabID
> scoped_tab_id
;
572 std::map
<int, int>::const_iterator it
=
573 port_to_tab_id_map_
.find(target_port_id
);
574 if (it
!= port_to_tab_id_map_
.end()) {
576 new RequestSender::ScopedTabID(request_sender(), it
->second
));
579 MessagingBindings::DeliverMessage(script_context_set_
.GetAll(),
582 NULL
); // All render views.
585 void Dispatcher::OnDispatchOnConnect(
587 const std::string
& channel_name
,
588 const base::DictionaryValue
& source_tab
,
589 const ExtensionMsg_ExternalConnectionInfo
& info
,
590 const std::string
& tls_channel_id
) {
591 DCHECK(!ContainsKey(port_to_tab_id_map_
, target_port_id
));
592 DCHECK_EQ(1, target_port_id
% 2); // target renderer ports have odd IDs.
593 int sender_tab_id
= -1;
594 source_tab
.GetInteger("id", &sender_tab_id
);
595 port_to_tab_id_map_
[target_port_id
] = sender_tab_id
;
597 MessagingBindings::DispatchOnConnect(script_context_set_
.GetAll(),
605 NULL
); // All render views.
608 void Dispatcher::OnDispatchOnDisconnect(int port_id
,
609 const std::string
& error_message
) {
610 MessagingBindings::DispatchOnDisconnect(script_context_set_
.GetAll(),
613 NULL
); // All render views.
616 void Dispatcher::OnLoaded(
617 const std::vector
<ExtensionMsg_Loaded_Params
>& loaded_extensions
) {
618 std::vector
<ExtensionMsg_Loaded_Params
>::const_iterator i
;
619 for (i
= loaded_extensions
.begin(); i
!= loaded_extensions
.end(); ++i
) {
621 scoped_refptr
<const Extension
> extension
= i
->ConvertToExtension(&error
);
622 if (!extension
.get()) {
623 extension_load_errors_
[i
->id
] = error
;
626 OnLoadedInternal(extension
);
628 // Update the available bindings for all contexts. These may have changed if
629 // an externally_connectable extension was loaded that can connect to an
634 void Dispatcher::OnLoadedInternal(scoped_refptr
<const Extension
> extension
) {
635 extensions_
.Insert(extension
);
638 void Dispatcher::OnMessageInvoke(const std::string
& extension_id
,
639 const std::string
& module_name
,
640 const std::string
& function_name
,
641 const base::ListValue
& args
,
643 InvokeModuleSystemMethod(
644 NULL
, extension_id
, module_name
, function_name
, args
, user_gesture
);
647 void Dispatcher::OnSetChannel(int channel
) {
648 delegate_
->SetChannel(channel
);
651 void Dispatcher::OnSetFunctionNames(const std::vector
<std::string
>& names
) {
652 function_names_
.clear();
653 for (size_t i
= 0; i
< names
.size(); ++i
)
654 function_names_
.insert(names
[i
]);
657 void Dispatcher::OnSetScriptingWhitelist(
658 const ExtensionsClient::ScriptingWhitelist
& extension_ids
) {
659 ExtensionsClient::Get()->SetScriptingWhitelist(extension_ids
);
662 void Dispatcher::OnSetSystemFont(const std::string
& font_family
,
663 const std::string
& font_size
) {
664 system_font_family_
= font_family
;
665 system_font_size_
= font_size
;
668 void Dispatcher::OnShouldSuspend(const std::string
& extension_id
,
670 RenderThread::Get()->Send(
671 new ExtensionHostMsg_ShouldSuspendAck(extension_id
, sequence_id
));
674 void Dispatcher::OnSuspend(const std::string
& extension_id
) {
675 // Dispatch the suspend event. This doesn't go through the standard event
676 // dispatch machinery because it requires special handling. We need to let
677 // the browser know when we are starting and stopping the event dispatch, so
678 // that it still considers the extension idle despite any activity the suspend
680 DispatchEvent(extension_id
, kOnSuspendEvent
);
681 RenderThread::Get()->Send(new ExtensionHostMsg_SuspendAck(extension_id
));
684 void Dispatcher::OnUnloaded(const std::string
& id
) {
685 extensions_
.Remove(id
);
686 active_extension_ids_
.erase(id
);
688 // If the extension is later reloaded with a different set of permissions,
689 // we'd like it to get a new isolated world ID, so that it can pick up the
690 // changed origin whitelist.
691 user_script_slave_
->RemoveIsolatedWorld(id
);
693 // Invalidate all of the contexts that were removed.
694 // TODO(kalman): add an invalidation observer interface to ScriptContext.
695 ScriptContextSet::ContextSet removed_contexts
=
696 script_context_set_
.OnExtensionUnloaded(id
);
697 for (ScriptContextSet::ContextSet::iterator it
= removed_contexts
.begin();
698 it
!= removed_contexts
.end();
700 request_sender_
->InvalidateSource(*it
);
703 // Update the available bindings for the remaining contexts. These may have
704 // changed if an externally_connectable extension is unloaded and a webpage
705 // is no longer accessible.
708 // Invalidates the messages map for the extension in case the extension is
709 // reloaded with a new messages map.
710 EraseL10nMessagesMap(id
);
712 // We don't do anything with existing platform-app stylesheets. They will
713 // stay resident, but the URL pattern corresponding to the unloaded
714 // extension's URL just won't match anything anymore.
717 void Dispatcher::OnUpdatePermissions(
718 const ExtensionMsg_UpdatePermissions_Params
& params
) {
719 int reason_id
= params
.reason_id
;
720 const std::string
& extension_id
= params
.extension_id
;
721 const APIPermissionSet
& apis
= params
.apis
;
722 const ManifestPermissionSet
& manifest_permissions
=
723 params
.manifest_permissions
;
724 const URLPatternSet
& explicit_hosts
= params
.explicit_hosts
;
725 const URLPatternSet
& scriptable_hosts
= params
.scriptable_hosts
;
727 const Extension
* extension
= extensions_
.GetByID(extension_id
);
731 scoped_refptr
<const PermissionSet
> delta
= new PermissionSet(
732 apis
, manifest_permissions
, explicit_hosts
, scriptable_hosts
);
733 scoped_refptr
<const PermissionSet
> old_active
=
734 extension
->GetActivePermissions();
735 UpdatedExtensionPermissionsInfo::Reason reason
=
736 static_cast<UpdatedExtensionPermissionsInfo::Reason
>(reason_id
);
738 const PermissionSet
* new_active
= NULL
;
740 case UpdatedExtensionPermissionsInfo::ADDED
:
741 new_active
= PermissionSet::CreateUnion(old_active
.get(), delta
.get());
743 case UpdatedExtensionPermissionsInfo::REMOVED
:
745 PermissionSet::CreateDifference(old_active
.get(), delta
.get());
749 PermissionsData::SetActivePermissions(extension
, new_active
);
750 UpdateOriginPermissions(reason
, extension
, explicit_hosts
);
751 UpdateBindings(extension
->id());
754 void Dispatcher::OnUpdateTabSpecificPermissions(
757 const std::string
& extension_id
,
758 const URLPatternSet
& origin_set
) {
759 delegate_
->UpdateTabSpecificPermissions(
760 this, page_id
, tab_id
, extension_id
, origin_set
);
763 void Dispatcher::OnUpdateUserScripts(base::SharedMemoryHandle scripts
) {
764 DCHECK(base::SharedMemory::IsHandleValid(scripts
)) << "Bad scripts handle";
765 user_script_slave_
->UpdateScripts(scripts
);
766 UpdateActiveExtensions();
769 void Dispatcher::OnUsingWebRequestAPI(bool adblock
,
771 bool other_webrequest
) {
772 delegate_
->HandleWebRequestAPIUsage(adblock
, adblock_plus
, other_webrequest
);
775 void Dispatcher::UpdateActiveExtensions() {
776 std::set
<std::string
> active_extensions
= active_extension_ids_
;
777 user_script_slave_
->GetActiveExtensions(&active_extensions
);
778 delegate_
->OnActiveExtensionsUpdated(active_extensions
);
781 void Dispatcher::InitOriginPermissions(const Extension
* extension
,
782 Feature::Context context_type
) {
783 delegate_
->InitOriginPermissions(extension
, context_type
);
784 UpdateOriginPermissions(
785 UpdatedExtensionPermissionsInfo::ADDED
,
787 PermissionsData::GetEffectiveHostPermissions(extension
));
790 void Dispatcher::UpdateOriginPermissions(
791 UpdatedExtensionPermissionsInfo::Reason reason
,
792 const Extension
* extension
,
793 const URLPatternSet
& origins
) {
794 for (URLPatternSet::const_iterator i
= origins
.begin(); i
!= origins
.end();
796 const char* schemes
[] = {
797 content::kHttpScheme
, content::kHttpsScheme
, content::kFileScheme
,
798 content::kChromeUIScheme
, content::kFtpScheme
,
800 for (size_t j
= 0; j
< arraysize(schemes
); ++j
) {
801 if (i
->MatchesScheme(schemes
[j
])) {
802 ((reason
== UpdatedExtensionPermissionsInfo::REMOVED
)
803 ? WebSecurityPolicy::removeOriginAccessWhitelistEntry
804 : WebSecurityPolicy::addOriginAccessWhitelistEntry
)(
806 WebString::fromUTF8(schemes
[j
]),
807 WebString::fromUTF8(i
->host()),
808 i
->match_subdomains());
814 void Dispatcher::EnableCustomElementWhiteList() {
815 blink::WebCustomElement::addEmbedderCustomElementName("webview");
816 // TODO(fsamuel): Add <adview> to the whitelist once it has been converted
817 // into a custom element.
818 blink::WebCustomElement::addEmbedderCustomElementName("browser-plugin");
821 void Dispatcher::UpdateBindings(const std::string
& extension_id
) {
822 script_context_set().ForEach(extension_id
,
823 NULL
, // all render views
824 base::Bind(&Dispatcher::UpdateBindingsForContext
,
825 base::Unretained(this)));
828 void Dispatcher::UpdateBindingsForContext(ScriptContext
* context
) {
829 v8::HandleScope
handle_scope(context
->isolate());
830 v8::Context::Scope
context_scope(context
->v8_context());
832 // TODO(kalman): Make the bindings registration have zero overhead then run
833 // the same code regardless of context type.
834 switch (context
->context_type()) {
835 case Feature::UNSPECIFIED_CONTEXT
:
836 case Feature::WEB_PAGE_CONTEXT
:
837 case Feature::BLESSED_WEB_PAGE_CONTEXT
: {
838 // Web page context; it's too expensive to run the full bindings code.
839 // Hard-code that the app and webstore APIs are available...
840 RegisterBinding("app", context
);
841 RegisterBinding("webstore", context
);
843 // ... and that the runtime API might be available if any extension can
845 bool runtime_is_available
= false;
846 for (ExtensionSet::const_iterator it
= extensions_
.begin();
847 it
!= extensions_
.end();
849 ExternallyConnectableInfo
* info
=
850 static_cast<ExternallyConnectableInfo
*>(
851 (*it
)->GetManifestData(manifest_keys::kExternallyConnectable
));
852 if (info
&& info
->matches
.MatchesURL(context
->GetURL())) {
853 runtime_is_available
= true;
857 if (runtime_is_available
)
858 RegisterBinding("runtime", context
);
862 case Feature::BLESSED_EXTENSION_CONTEXT
:
863 case Feature::UNBLESSED_EXTENSION_CONTEXT
:
864 case Feature::CONTENT_SCRIPT_CONTEXT
: {
865 // Extension context; iterate through all the APIs and bind the available
867 FeatureProvider
* api_feature_provider
= FeatureProvider::GetAPIFeatures();
868 const std::vector
<std::string
>& apis
=
869 api_feature_provider
->GetAllFeatureNames();
870 for (std::vector
<std::string
>::const_iterator it
= apis
.begin();
873 const std::string
& api_name
= *it
;
874 Feature
* feature
= api_feature_provider
->GetFeature(api_name
);
877 // Internal APIs are included via require(api_name) from internal code
878 // rather than chrome[api_name].
879 if (feature
->IsInternal())
882 // If this API has a parent feature (and isn't marked 'noparent'),
883 // then this must be a function or event, so we should not register.
884 if (api_feature_provider
->GetParent(feature
) != NULL
)
887 if (context
->IsAnyFeatureAvailableToContext(*feature
))
888 RegisterBinding(api_name
, context
);
890 if (CommandLine::ForCurrentProcess()->HasSwitch(::switches::kTestType
)) {
891 RegisterBinding("test", context
);
898 void Dispatcher::RegisterBinding(const std::string
& api_name
,
899 ScriptContext
* context
) {
900 std::string bind_name
;
901 v8::Handle
<v8::Object
> bind_object
=
902 GetOrCreateBindObjectIfAvailable(api_name
, &bind_name
, context
);
904 // Empty if the bind object failed to be created, probably because the
905 // extension overrode chrome with a non-object, e.g. window.chrome = true.
906 if (bind_object
.IsEmpty())
909 v8::Local
<v8::String
> v8_api_name
=
910 v8::String::NewFromUtf8(context
->isolate(), api_name
.c_str());
911 if (bind_object
->HasRealNamedProperty(v8_api_name
)) {
912 // The bind object may already have the property if the API has been
913 // registered before (or if the extension has put something there already,
916 // In the former case, we need to re-register the bindings for the APIs
917 // which the extension now has permissions for (if any), but not touch any
918 // others so that we don't destroy state such as event listeners.
920 // TODO(kalman): Only register available APIs to make this all moot.
921 if (bind_object
->HasRealNamedCallbackProperty(v8_api_name
))
922 return; // lazy binding still there, nothing to do
923 if (bind_object
->Get(v8_api_name
)->IsObject())
924 return; // binding has already been fully installed
927 ModuleSystem
* module_system
= context
->module_system();
928 if (!source_map_
.Contains(api_name
)) {
929 module_system
->RegisterNativeHandler(
931 scoped_ptr
<NativeHandler
>(new BindingGeneratingNativeHandler(
932 module_system
, api_name
, "binding")));
933 module_system
->SetNativeLazyField(
934 bind_object
, bind_name
, api_name
, "binding");
936 module_system
->SetLazyField(bind_object
, bind_name
, api_name
, "binding");
940 // NOTE: please use the naming convention "foo_natives" for these.
941 void Dispatcher::RegisterNativeHandlers(ModuleSystem
* module_system
,
942 ScriptContext
* context
) {
943 module_system
->RegisterNativeHandler(
944 "chrome", scoped_ptr
<NativeHandler
>(new ChromeNativeHandler(context
)));
945 module_system
->RegisterNativeHandler(
946 "lazy_background_page",
947 scoped_ptr
<NativeHandler
>(new LazyBackgroundPageNativeHandler(context
)));
948 module_system
->RegisterNativeHandler(
949 "logging", scoped_ptr
<NativeHandler
>(new LoggingNativeHandler(context
)));
950 module_system
->RegisterNativeHandler("schema_registry",
951 v8_schema_registry_
->AsNativeHandler());
952 module_system
->RegisterNativeHandler(
953 "print", scoped_ptr
<NativeHandler
>(new PrintNativeHandler(context
)));
954 module_system
->RegisterNativeHandler(
956 scoped_ptr
<NativeHandler
>(new TestFeaturesNativeHandler(context
)));
957 module_system
->RegisterNativeHandler(
959 scoped_ptr
<NativeHandler
>(new UserGesturesNativeHandler(context
)));
960 module_system
->RegisterNativeHandler(
961 "utils", scoped_ptr
<NativeHandler
>(new UtilsNativeHandler(context
)));
962 module_system
->RegisterNativeHandler(
964 scoped_ptr
<NativeHandler
>(new V8ContextNativeHandler(context
, this)));
966 const Extension
* extension
= context
->extension();
967 int manifest_version
= extension
? extension
->manifest_version() : 1;
968 bool send_request_disabled
=
969 (extension
&& Manifest::IsUnpackedLocation(extension
->location()) &&
970 BackgroundInfo::HasLazyBackgroundPage(extension
));
971 module_system
->RegisterNativeHandler(
973 scoped_ptr
<NativeHandler
>(new ProcessInfoNativeHandler(
975 context
->GetExtensionID(),
976 context
->GetContextTypeDescription(),
977 ExtensionsRendererClient::Get()->IsIncognitoProcess(),
979 send_request_disabled
)));
981 module_system
->RegisterNativeHandler(
983 scoped_ptr
<NativeHandler
>(new EventBindings(this, context
)));
984 module_system
->RegisterNativeHandler(
986 scoped_ptr
<NativeHandler
>(MessagingBindings::Get(this, context
)));
987 module_system
->RegisterNativeHandler(
989 scoped_ptr
<NativeHandler
>(new ApiDefinitionsNatives(this, context
)));
990 module_system
->RegisterNativeHandler(
992 scoped_ptr
<NativeHandler
>(
993 new SendRequestNatives(request_sender_
.get(), context
)));
994 module_system
->RegisterNativeHandler(
996 scoped_ptr
<NativeHandler
>(
997 new SetIconNatives(request_sender_
.get(), context
)));
998 module_system
->RegisterNativeHandler(
1000 scoped_ptr
<NativeHandler
>(new APIActivityLogger(context
)));
1001 module_system
->RegisterNativeHandler(
1002 "renderViewObserverNatives",
1003 scoped_ptr
<NativeHandler
>(new RenderViewObserverNatives(context
)));
1005 // Natives used by multiple APIs.
1006 module_system
->RegisterNativeHandler(
1007 "file_system_natives",
1008 scoped_ptr
<NativeHandler
>(new FileSystemNatives(context
)));
1011 module_system
->RegisterNativeHandler(
1013 scoped_ptr
<NativeHandler
>(new AppRuntimeCustomBindings(context
)));
1014 module_system
->RegisterNativeHandler(
1016 scoped_ptr
<NativeHandler
>(new BlobNativeHandler(context
)));
1017 module_system
->RegisterNativeHandler(
1019 scoped_ptr
<NativeHandler
>(new ContextMenusCustomBindings(context
)));
1020 module_system
->RegisterNativeHandler(
1021 "css_natives", scoped_ptr
<NativeHandler
>(new CssNativeHandler(context
)));
1022 module_system
->RegisterNativeHandler(
1024 scoped_ptr
<NativeHandler
>(new DocumentCustomBindings(context
)));
1025 module_system
->RegisterNativeHandler(
1026 "i18n", scoped_ptr
<NativeHandler
>(new I18NCustomBindings(context
)));
1027 module_system
->RegisterNativeHandler(
1029 scoped_ptr
<NativeHandler
>(new IdGeneratorCustomBindings(context
)));
1030 module_system
->RegisterNativeHandler(
1031 "runtime", scoped_ptr
<NativeHandler
>(new RuntimeCustomBindings(context
)));
1033 delegate_
->RegisterNativeHandlers(this, module_system
, context
);
1036 void Dispatcher::PopulateSourceMap() {
1038 source_map_
.RegisterSource("entryIdManager", IDR_ENTRY_ID_MANAGER
);
1039 source_map_
.RegisterSource(kEventBindings
, IDR_EVENT_BINDINGS_JS
);
1040 source_map_
.RegisterSource("imageUtil", IDR_IMAGE_UTIL_JS
);
1041 source_map_
.RegisterSource("json_schema", IDR_JSON_SCHEMA_JS
);
1042 source_map_
.RegisterSource("lastError", IDR_LAST_ERROR_JS
);
1043 source_map_
.RegisterSource("messaging", IDR_MESSAGING_JS
);
1044 source_map_
.RegisterSource("messaging_utils", IDR_MESSAGING_UTILS_JS
);
1045 source_map_
.RegisterSource(kSchemaUtils
, IDR_SCHEMA_UTILS_JS
);
1046 source_map_
.RegisterSource("sendRequest", IDR_SEND_REQUEST_JS
);
1047 source_map_
.RegisterSource("setIcon", IDR_SET_ICON_JS
);
1048 source_map_
.RegisterSource("test", IDR_TEST_CUSTOM_BINDINGS_JS
);
1049 source_map_
.RegisterSource("unload_event", IDR_UNLOAD_EVENT_JS
);
1050 source_map_
.RegisterSource("utils", IDR_UTILS_JS
);
1053 source_map_
.RegisterSource("app.runtime", IDR_APP_RUNTIME_CUSTOM_BINDINGS_JS
);
1054 source_map_
.RegisterSource("contextMenus",
1055 IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS
);
1056 source_map_
.RegisterSource("extension", IDR_EXTENSION_CUSTOM_BINDINGS_JS
);
1057 source_map_
.RegisterSource("i18n", IDR_I18N_CUSTOM_BINDINGS_JS
);
1058 source_map_
.RegisterSource("permissions", IDR_PERMISSIONS_CUSTOM_BINDINGS_JS
);
1059 source_map_
.RegisterSource("runtime", IDR_RUNTIME_CUSTOM_BINDINGS_JS
);
1060 source_map_
.RegisterSource("binding", IDR_BINDING_JS
);
1062 // Custom types sources.
1063 source_map_
.RegisterSource("StorageArea", IDR_STORAGE_AREA_JS
);
1065 // Platform app sources that are not API-specific..
1066 source_map_
.RegisterSource("platformApp", IDR_PLATFORM_APP_JS
);
1068 delegate_
->PopulateSourceMap(&source_map_
);
1071 bool Dispatcher::IsWithinPlatformApp() {
1072 for (std::set
<std::string
>::iterator iter
= active_extension_ids_
.begin();
1073 iter
!= active_extension_ids_
.end();
1075 const Extension
* extension
= extensions_
.GetByID(*iter
);
1076 if (extension
&& extension
->is_platform_app())
1082 // TODO(kalman): This is checking for the wrong thing, it should be checking if
1083 // the frame's security origin is unique. The extension sandbox directive is
1084 // checked for in extensions/common/manifest_handlers/csp_info.cc.
1085 bool Dispatcher::IsSandboxedPage(const GURL
& url
) const {
1086 if (url
.SchemeIs(kExtensionScheme
)) {
1087 const Extension
* extension
= extensions_
.GetByID(url
.host());
1089 return SandboxedPageInfo::IsSandboxedPage(extension
, url
.path());
1095 Feature::Context
Dispatcher::ClassifyJavaScriptContext(
1096 const Extension
* extension
,
1097 int extension_group
,
1099 const blink::WebSecurityOrigin
& origin
) {
1100 DCHECK_GE(extension_group
, 0);
1101 if (extension_group
== EXTENSION_GROUP_CONTENT_SCRIPTS
) {
1102 return extension
? // TODO(kalman): when does this happen?
1103 Feature::CONTENT_SCRIPT_CONTEXT
1104 : Feature::UNSPECIFIED_CONTEXT
;
1107 // We have an explicit check for sandboxed pages before checking whether the
1108 // extension is active in this process because:
1109 // 1. Sandboxed pages run in the same process as regular extension pages, so
1110 // the extension is considered active.
1111 // 2. ScriptContext creation (which triggers bindings injection) happens
1112 // before the SecurityContext is updated with the sandbox flags (after
1113 // reading the CSP header), so the caller can't check if the context's
1114 // security origin is unique yet.
1115 if (IsSandboxedPage(url
))
1116 return Feature::WEB_PAGE_CONTEXT
;
1118 if (extension
&& IsExtensionActive(extension
->id())) {
1119 // |extension| is active in this process, but it could be either a true
1120 // extension process or within the extent of a hosted app. In the latter
1121 // case this would usually be considered a (blessed) web page context,
1122 // unless the extension in question is a component extension, in which case
1123 // we cheat and call it blessed.
1124 return (extension
->is_hosted_app() &&
1125 extension
->location() != Manifest::COMPONENT
)
1126 ? Feature::BLESSED_WEB_PAGE_CONTEXT
1127 : Feature::BLESSED_EXTENSION_CONTEXT
;
1130 // TODO(kalman): This isUnique() check is wrong, it should be performed as
1131 // part of IsSandboxedPage().
1132 if (!origin
.isUnique() && extensions_
.ExtensionBindingsAllowed(url
)) {
1133 if (!extension
) // TODO(kalman): when does this happen?
1134 return Feature::UNSPECIFIED_CONTEXT
;
1135 return extension
->is_hosted_app() ? Feature::BLESSED_WEB_PAGE_CONTEXT
1136 : Feature::UNBLESSED_EXTENSION_CONTEXT
;
1140 return Feature::WEB_PAGE_CONTEXT
;
1142 return Feature::UNSPECIFIED_CONTEXT
;
1145 v8::Handle
<v8::Object
> Dispatcher::GetOrCreateObject(
1146 const v8::Handle
<v8::Object
>& object
,
1147 const std::string
& field
,
1148 v8::Isolate
* isolate
) {
1149 v8::Handle
<v8::String
> key
= v8::String::NewFromUtf8(isolate
, field
.c_str());
1150 // If the object has a callback property, it is assumed it is an unavailable
1151 // API, so it is safe to delete. This is checked before GetOrCreateObject is
1153 if (object
->HasRealNamedCallbackProperty(key
)) {
1154 object
->Delete(key
);
1155 } else if (object
->HasRealNamedProperty(key
)) {
1156 v8::Handle
<v8::Value
> value
= object
->Get(key
);
1157 CHECK(value
->IsObject());
1158 return v8::Handle
<v8::Object
>::Cast(value
);
1161 v8::Handle
<v8::Object
> new_object
= v8::Object::New(isolate
);
1162 object
->Set(key
, new_object
);
1166 v8::Handle
<v8::Object
> Dispatcher::GetOrCreateBindObjectIfAvailable(
1167 const std::string
& api_name
,
1168 std::string
* bind_name
,
1169 ScriptContext
* context
) {
1170 std::vector
<std::string
> split
;
1171 base::SplitString(api_name
, '.', &split
);
1173 v8::Handle
<v8::Object
> bind_object
;
1175 // Check if this API has an ancestor. If the API's ancestor is available and
1176 // the API is not available, don't install the bindings for this API. If
1177 // the API is available and its ancestor is not, delete the ancestor and
1178 // install the bindings for the API. This is to prevent loading the ancestor
1179 // API schema if it will not be needed.
1182 // If app is available and app.window is not, just install app.
1183 // If app.window is available and app is not, delete app and install
1184 // app.window on a new object so app does not have to be loaded.
1185 FeatureProvider
* api_feature_provider
= FeatureProvider::GetAPIFeatures();
1186 std::string ancestor_name
;
1187 bool only_ancestor_available
= false;
1189 for (size_t i
= 0; i
< split
.size() - 1; ++i
) {
1190 ancestor_name
+= (i
? "." : "") + split
[i
];
1191 if (api_feature_provider
->GetFeature(ancestor_name
) &&
1192 context
->GetAvailability(ancestor_name
).is_available() &&
1193 !context
->GetAvailability(api_name
).is_available()) {
1194 only_ancestor_available
= true;
1198 if (bind_object
.IsEmpty()) {
1199 bind_object
= AsObjectOrEmpty(GetOrCreateChrome(context
));
1200 if (bind_object
.IsEmpty())
1201 return v8::Handle
<v8::Object
>();
1203 bind_object
= GetOrCreateObject(bind_object
, split
[i
], context
->isolate());
1206 if (only_ancestor_available
)
1207 return v8::Handle
<v8::Object
>();
1210 *bind_name
= split
.back();
1212 return bind_object
.IsEmpty() ? AsObjectOrEmpty(GetOrCreateChrome(context
))
1216 } // namespace extensions