Index: chrome/renderer/extensions/dispatcher.cc |
diff --git a/chrome/renderer/extensions/dispatcher.cc b/chrome/renderer/extensions/dispatcher.cc |
index 0de79aa6b47c1912c244d9dfee4e372a4eb6ac1c..af6a2b031e88d6f63e2056ca93013832727b1ad9 100644 |
--- a/chrome/renderer/extensions/dispatcher.cc |
+++ b/chrome/renderer/extensions/dispatcher.cc |
@@ -596,7 +596,6 @@ bool Dispatcher::AllowScriptExtension(WebFrame* frame, |
v8::Handle<v8::Object> Dispatcher::GetOrCreateObject( |
v8::Handle<v8::Object> object, |
const std::string& field) { |
- v8::HandleScope handle_scope; |
v8::Handle<v8::String> key = v8::String::New(field.c_str()); |
// If the object has a callback property, it is assumed it is an unavailable |
// API, so it is safe to delete. This is checked before GetOrCreateObject is |
@@ -606,80 +605,116 @@ v8::Handle<v8::Object> Dispatcher::GetOrCreateObject( |
} else if (object->HasRealNamedProperty(key)) { |
v8::Handle<v8::Value> value = object->Get(key); |
CHECK(value->IsObject()); |
- return handle_scope.Close(v8::Handle<v8::Object>::Cast(value)); |
+ return v8::Handle<v8::Object>::Cast(value); |
} |
v8::Handle<v8::Object> new_object = v8::Object::New(); |
object->Set(key, new_object); |
- return handle_scope.Close(new_object); |
+ return new_object; |
} |
-void Dispatcher::RegisterSchemaGeneratedBindings( |
- ModuleSystem* module_system, |
- ChromeV8Context* context) { |
+void Dispatcher::AddOrRemoveBindings(ChromeV8Context* context) { |
+ v8::HandleScope handle_scope; |
+ v8::Context::Scope context_scope(context->v8_context()); |
+ |
std::set<std::string> apis = |
ExtensionAPI::GetSharedInstance()->GetAllAPINames(); |
for (std::set<std::string>::iterator it = apis.begin(); |
it != apis.end(); ++it) { |
const std::string& api_name = *it; |
- if (!context->IsAnyFeatureAvailableToContext(api_name)) |
+ if (!context->IsAnyFeatureAvailableToContext(api_name)) { |
+ DeregisterBinding(api_name, context); |
continue; |
+ } |
Feature* feature = |
BaseFeatureProvider::GetByName("api")->GetFeature(api_name); |
if (feature && feature->IsInternal()) |
continue; |
- std::vector<std::string> split; |
- base::SplitString(api_name, '.', &split); |
- |
- v8::Handle<v8::Object> bind_object = |
- GetOrCreateChrome(context->v8_context()); |
- |
- // Check if this API has an ancestor. If the API's ancestor is available and |
- // the API is not available, don't install the bindings for this API. If |
- // the API is available and its ancestor is not, delete the ancestor and |
- // install the bindings for the API. This is to prevent loading the ancestor |
- // API schema if it will not be needed. |
- // |
- // For example: |
- // If app is available and app.window is not, just install app. |
- // If app.window is available and app is not, delete app and install |
- // app.window on a new object so app does not have to be loaded. |
- std::string ancestor_name; |
- bool only_ancestor_available = false; |
- for (size_t i = 0; i < split.size() - 1; ++i) { |
- ancestor_name += (i ? ".": "") + split[i]; |
- if (!ancestor_name.empty() && |
- context->GetAvailability(ancestor_name).is_available() && |
- !context->GetAvailability(api_name).is_available()) { |
- only_ancestor_available = true; |
- break; |
- } |
- bind_object = GetOrCreateObject(bind_object, split[i]); |
- } |
- if (only_ancestor_available) |
- continue; |
+ RegisterBinding(api_name, context); |
+ } |
+} |
- if (lazy_bindings_map_.find(api_name) != lazy_bindings_map_.end()) { |
- InstallBindings(module_system, context->v8_context(), api_name); |
- } else if (!source_map_.Contains(api_name)) { |
- module_system->RegisterNativeHandler( |
- api_name, |
- scoped_ptr<NativeHandler>(new BindingGeneratingNativeHandler( |
- module_system, |
- api_name, |
- "binding"))); |
- module_system->SetNativeLazyField(bind_object, |
- split.back(), |
- api_name, |
- "binding"); |
- } else { |
- module_system->SetLazyField(bind_object, |
- split.back(), |
- api_name, |
- "binding"); |
+void Dispatcher::DeregisterBinding(const std::string& api_name, |
+ ChromeV8Context* context) { |
+ std::string bind_name; |
+ v8::Handle<v8::Object> bind_object = |
+ GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context); |
+ v8::Handle<v8::String> v8_bind_name = v8::String::New(bind_name.c_str()); |
+ if (!bind_object.IsEmpty() && bind_object->HasRealNamedProperty(v8_bind_name)) |
+ bind_object->Delete(v8_bind_name); |
+} |
+ |
+v8::Handle<v8::Object> Dispatcher::GetOrCreateBindObjectIfAvailable( |
+ const std::string& api_name, |
+ std::string* bind_name, |
+ ChromeV8Context* context) { |
+ std::vector<std::string> split; |
+ base::SplitString(api_name, '.', &split); |
+ |
+ v8::Handle<v8::Object> bind_object; |
+ |
+ // Check if this API has an ancestor. If the API's ancestor is available and |
+ // the API is not available, don't install the bindings for this API. If |
+ // the API is available and its ancestor is not, delete the ancestor and |
+ // install the bindings for the API. This is to prevent loading the ancestor |
+ // API schema if it will not be needed. |
+ // |
+ // For example: |
+ // If app is available and app.window is not, just install app. |
+ // If app.window is available and app is not, delete app and install |
+ // app.window on a new object so app does not have to be loaded. |
+ std::string ancestor_name; |
+ bool only_ancestor_available = false; |
+ for (size_t i = 0; i < split.size() - 1; ++i) { |
+ ancestor_name += (i ? ".": "") + split[i]; |
+ if (!ancestor_name.empty() && |
+ context->GetAvailability(ancestor_name).is_available() && |
+ !context->GetAvailability(api_name).is_available()) { |
+ only_ancestor_available = true; |
+ break; |
} |
+ if (bind_object.IsEmpty()) |
+ bind_object = GetOrCreateChrome(context->v8_context()); |
+ bind_object = GetOrCreateObject(bind_object, split[i]); |
+ } |
+ if (only_ancestor_available) |
+ return v8::Handle<v8::Object>(); |
+ if (bind_name) |
+ *bind_name = split.back(); |
+ |
+ return bind_object.IsEmpty() ? |
+ GetOrCreateChrome(context->v8_context()) : bind_object; |
+} |
+ |
+void Dispatcher::RegisterBinding(const std::string& api_name, |
+ ChromeV8Context* context) { |
+ std::string bind_name; |
+ v8::Handle<v8::Object> bind_object = |
+ GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context); |
+ if (bind_object.IsEmpty()) |
+ return; |
+ |
+ ModuleSystem* module_system = context->module_system(); |
+ if (lazy_bindings_map_.find(api_name) != lazy_bindings_map_.end()) { |
+ InstallBindings(module_system, context->v8_context(), api_name); |
+ } else if (!source_map_.Contains(api_name)) { |
+ module_system->RegisterNativeHandler( |
+ api_name, |
+ scoped_ptr<NativeHandler>(new BindingGeneratingNativeHandler( |
+ module_system, |
+ api_name, |
+ "binding"))); |
+ module_system->SetNativeLazyField(bind_object, |
+ bind_name, |
+ api_name, |
+ "binding"); |
+ } else { |
+ module_system->SetLazyField(bind_object, |
+ bind_name, |
+ api_name, |
+ "binding"); |
} |
} |
@@ -876,8 +911,7 @@ void Dispatcher::InstallBindings(ModuleSystem* module_system, |
void Dispatcher::DidCreateScriptContext( |
WebFrame* frame, v8::Handle<v8::Context> v8_context, int extension_group, |
int world_id) { |
-// Extensions are not supported on Android, so don't register any bindings. |
-#if defined(OS_ANDROID) |
+#if !defined(ENABLE_EXTENSIONS) |
return; |
#endif |
@@ -911,12 +945,18 @@ void Dispatcher::DidCreateScriptContext( |
new ChromeV8Context(v8_context, frame, extension, context_type); |
v8_context_set_.Add(context); |
- scoped_ptr<ModuleSystem> module_system(new ModuleSystem(context, |
- &source_map_)); |
+ { |
+ scoped_ptr<ModuleSystem> module_system(new ModuleSystem(context, |
+ &source_map_)); |
+ context->set_module_system(module_system.Pass()); |
+ } |
+ ModuleSystem* module_system = context->module_system(); |
+ |
// Enable natives in startup. |
- ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system.get()); |
+ ModuleSystem::NativesEnabledScope natives_enabled_scope( |
+ module_system); |
- RegisterNativeHandlers(module_system.get(), context); |
+ RegisterNativeHandlers(module_system, context); |
module_system->RegisterNativeHandler("chrome", |
scoped_ptr<NativeHandler>(new ChromeNativeHandler(context))); |
@@ -957,8 +997,8 @@ void Dispatcher::DidCreateScriptContext( |
case Feature::UNSPECIFIED_CONTEXT: |
case Feature::WEB_PAGE_CONTEXT: |
// TODO(kalman): see comment below about ExtensionAPI. |
- InstallBindings(module_system.get(), v8_context, "app"); |
- InstallBindings(module_system.get(), v8_context, "webstore"); |
+ InstallBindings(module_system, v8_context, "app"); |
+ InstallBindings(module_system, v8_context, "webstore"); |
break; |
case Feature::BLESSED_EXTENSION_CONTEXT: |
case Feature::UNBLESSED_EXTENSION_CONTEXT: |
@@ -969,7 +1009,7 @@ void Dispatcher::DidCreateScriptContext( |
// regardless of |context_type|. ExtensionAPI knows how to return the |
// correct APIs, however, until it doesn't have a 2MB overhead we can't |
// load it in every process. |
- RegisterSchemaGeneratedBindings(module_system.get(), context); |
+ AddOrRemoveBindings(context); |
break; |
} |
@@ -1010,8 +1050,6 @@ void Dispatcher::DidCreateScriptContext( |
} |
} |
- context->set_module_system(module_system.Pass()); |
- |
VLOG(1) << "Num tracked contexts: " << v8_context_set_.size(); |
} |
@@ -1174,6 +1212,10 @@ void Dispatcher::OnUpdatePermissions(int reason_id, |
PermissionsData::SetActivePermissions(extension, new_active); |
AddOrRemoveOriginPermissions(reason, extension, explicit_hosts); |
+ v8_context_set().ForEach( |
+ extension_id, |
+ NULL, |
+ base::Bind(&Dispatcher::AddOrRemoveBindings, base::Unretained(this))); |
} |
void Dispatcher::OnUpdateTabSpecificPermissions( |