Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(153)

Side by Side Diff: chrome/renderer/extensions/dispatcher.cc

Issue 15961006: Regenerate Extensions API bindings when optional permissions change (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: try againto fix android Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/renderer/extensions/dispatcher.h" 5 #include "chrome/renderer/extensions/dispatcher.h"
6 6
7 #include "base/callback.h" 7 #include "base/callback.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/debug/alias.h" 9 #include "base/debug/alias.h"
10 #include "base/json/json_reader.h" 10 #include "base/json/json_reader.h"
(...skipping 578 matching lines...) Expand 10 before | Expand all | Expand 10 after
589 const std::string& v8_extension_name, 589 const std::string& v8_extension_name,
590 int extension_group, 590 int extension_group,
591 int world_id) { 591 int world_id) {
592 g_hack_extension_group = extension_group; 592 g_hack_extension_group = extension_group;
593 return true; 593 return true;
594 } 594 }
595 595
596 v8::Handle<v8::Object> Dispatcher::GetOrCreateObject( 596 v8::Handle<v8::Object> Dispatcher::GetOrCreateObject(
597 v8::Handle<v8::Object> object, 597 v8::Handle<v8::Object> object,
598 const std::string& field) { 598 const std::string& field) {
599 v8::HandleScope handle_scope;
600 v8::Handle<v8::String> key = v8::String::New(field.c_str()); 599 v8::Handle<v8::String> key = v8::String::New(field.c_str());
601 // If the object has a callback property, it is assumed it is an unavailable 600 // If the object has a callback property, it is assumed it is an unavailable
602 // API, so it is safe to delete. This is checked before GetOrCreateObject is 601 // API, so it is safe to delete. This is checked before GetOrCreateObject is
603 // called. 602 // called.
604 if (object->HasRealNamedCallbackProperty(key)) { 603 if (object->HasRealNamedCallbackProperty(key)) {
605 object->Delete(key); 604 object->Delete(key);
606 } else if (object->HasRealNamedProperty(key)) { 605 } else if (object->HasRealNamedProperty(key)) {
607 v8::Handle<v8::Value> value = object->Get(key); 606 v8::Handle<v8::Value> value = object->Get(key);
608 CHECK(value->IsObject()); 607 CHECK(value->IsObject());
609 return handle_scope.Close(v8::Handle<v8::Object>::Cast(value)); 608 return v8::Handle<v8::Object>::Cast(value);
610 } 609 }
611 610
612 v8::Handle<v8::Object> new_object = v8::Object::New(); 611 v8::Handle<v8::Object> new_object = v8::Object::New();
613 object->Set(key, new_object); 612 object->Set(key, new_object);
614 return handle_scope.Close(new_object); 613 return new_object;
615 } 614 }
616 615
617 void Dispatcher::RegisterSchemaGeneratedBindings( 616 void Dispatcher::AddOrRemoveBindings(ChromeV8Context* context) {
618 ModuleSystem* module_system, 617 v8::HandleScope handle_scope;
619 ChromeV8Context* context) { 618 v8::Context::Scope context_scope(context->v8_context());
619
620 std::set<std::string> apis = 620 std::set<std::string> apis =
621 ExtensionAPI::GetSharedInstance()->GetAllAPINames(); 621 ExtensionAPI::GetSharedInstance()->GetAllAPINames();
622 for (std::set<std::string>::iterator it = apis.begin(); 622 for (std::set<std::string>::iterator it = apis.begin();
623 it != apis.end(); ++it) { 623 it != apis.end(); ++it) {
624 const std::string& api_name = *it; 624 const std::string& api_name = *it;
625 if (!context->IsAnyFeatureAvailableToContext(api_name)) 625 if (!context->IsAnyFeatureAvailableToContext(api_name)) {
626 DeregisterBinding(api_name, context);
626 continue; 627 continue;
628 }
627 629
628 Feature* feature = 630 Feature* feature =
629 BaseFeatureProvider::GetByName("api")->GetFeature(api_name); 631 BaseFeatureProvider::GetByName("api")->GetFeature(api_name);
630 if (feature && feature->IsInternal()) 632 if (feature && feature->IsInternal())
631 continue; 633 continue;
632 634
633 std::vector<std::string> split; 635 RegisterBinding(api_name, context);
634 base::SplitString(api_name, '.', &split);
635
636 v8::Handle<v8::Object> bind_object =
637 GetOrCreateChrome(context->v8_context());
638
639 // Check if this API has an ancestor. If the API's ancestor is available and
640 // the API is not available, don't install the bindings for this API. If
641 // the API is available and its ancestor is not, delete the ancestor and
642 // install the bindings for the API. This is to prevent loading the ancestor
643 // API schema if it will not be needed.
644 //
645 // For example:
646 // If app is available and app.window is not, just install app.
647 // If app.window is available and app is not, delete app and install
648 // app.window on a new object so app does not have to be loaded.
649 std::string ancestor_name;
650 bool only_ancestor_available = false;
651 for (size_t i = 0; i < split.size() - 1; ++i) {
652 ancestor_name += (i ? ".": "") + split[i];
653 if (!ancestor_name.empty() &&
654 context->GetAvailability(ancestor_name).is_available() &&
655 !context->GetAvailability(api_name).is_available()) {
656 only_ancestor_available = true;
657 break;
658 }
659 bind_object = GetOrCreateObject(bind_object, split[i]);
660 }
661 if (only_ancestor_available)
662 continue;
663
664 if (lazy_bindings_map_.find(api_name) != lazy_bindings_map_.end()) {
665 InstallBindings(module_system, context->v8_context(), api_name);
666 } else if (!source_map_.Contains(api_name)) {
667 module_system->RegisterNativeHandler(
668 api_name,
669 scoped_ptr<NativeHandler>(new BindingGeneratingNativeHandler(
670 module_system,
671 api_name,
672 "binding")));
673 module_system->SetNativeLazyField(bind_object,
674 split.back(),
675 api_name,
676 "binding");
677 } else {
678 module_system->SetLazyField(bind_object,
679 split.back(),
680 api_name,
681 "binding");
682 }
683 } 636 }
684 } 637 }
685 638
639 void Dispatcher::DeregisterBinding(const std::string& api_name,
640 ChromeV8Context* context) {
641 std::string bind_name;
642 v8::Handle<v8::Object> bind_object =
643 GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context);
644 v8::Handle<v8::String> v8_bind_name = v8::String::New(bind_name.c_str());
645 if (!bind_object.IsEmpty() && bind_object->HasRealNamedProperty(v8_bind_name))
646 bind_object->Delete(v8_bind_name);
647 }
648
649 v8::Handle<v8::Object> Dispatcher::GetOrCreateBindObjectIfAvailable(
650 const std::string& api_name,
651 std::string* bind_name,
652 ChromeV8Context* context) {
653 std::vector<std::string> split;
654 base::SplitString(api_name, '.', &split);
655
656 v8::Handle<v8::Object> bind_object;
657
658 // Check if this API has an ancestor. If the API's ancestor is available and
659 // the API is not available, don't install the bindings for this API. If
660 // the API is available and its ancestor is not, delete the ancestor and
661 // install the bindings for the API. This is to prevent loading the ancestor
662 // API schema if it will not be needed.
663 //
664 // For example:
665 // If app is available and app.window is not, just install app.
666 // If app.window is available and app is not, delete app and install
667 // app.window on a new object so app does not have to be loaded.
668 std::string ancestor_name;
669 bool only_ancestor_available = false;
670 for (size_t i = 0; i < split.size() - 1; ++i) {
671 ancestor_name += (i ? ".": "") + split[i];
672 if (!ancestor_name.empty() &&
673 context->GetAvailability(ancestor_name).is_available() &&
674 !context->GetAvailability(api_name).is_available()) {
675 only_ancestor_available = true;
676 break;
677 }
678 if (bind_object.IsEmpty())
679 bind_object = GetOrCreateChrome(context->v8_context());
680 bind_object = GetOrCreateObject(bind_object, split[i]);
681 }
682 if (only_ancestor_available)
683 return v8::Handle<v8::Object>();
684 if (bind_name)
685 *bind_name = split.back();
686
687 return bind_object.IsEmpty() ?
688 GetOrCreateChrome(context->v8_context()) : bind_object;
689 }
690
691 void Dispatcher::RegisterBinding(const std::string& api_name,
692 ChromeV8Context* context) {
693 std::string bind_name;
694 v8::Handle<v8::Object> bind_object =
695 GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context);
696 if (bind_object.IsEmpty())
697 return;
698
699 ModuleSystem* module_system = context->module_system();
700 if (lazy_bindings_map_.find(api_name) != lazy_bindings_map_.end()) {
701 InstallBindings(module_system, context->v8_context(), api_name);
702 } else if (!source_map_.Contains(api_name)) {
703 module_system->RegisterNativeHandler(
704 api_name,
705 scoped_ptr<NativeHandler>(new BindingGeneratingNativeHandler(
706 module_system,
707 api_name,
708 "binding")));
709 module_system->SetNativeLazyField(bind_object,
710 bind_name,
711 api_name,
712 "binding");
713 } else {
714 module_system->SetLazyField(bind_object,
715 bind_name,
716 api_name,
717 "binding");
718 }
719 }
720
686 // NOTE: please use the naming convention "foo_natives" for these. 721 // NOTE: please use the naming convention "foo_natives" for these.
687 void Dispatcher::RegisterNativeHandlers(ModuleSystem* module_system, 722 void Dispatcher::RegisterNativeHandlers(ModuleSystem* module_system,
688 ChromeV8Context* context) { 723 ChromeV8Context* context) {
689 module_system->RegisterNativeHandler("event_natives", 724 module_system->RegisterNativeHandler("event_natives",
690 scoped_ptr<NativeHandler>(EventBindings::Create(this, context))); 725 scoped_ptr<NativeHandler>(EventBindings::Create(this, context)));
691 module_system->RegisterNativeHandler("miscellaneous_bindings_natives", 726 module_system->RegisterNativeHandler("miscellaneous_bindings_natives",
692 scoped_ptr<NativeHandler>(MiscellaneousBindings::Get(this, context))); 727 scoped_ptr<NativeHandler>(MiscellaneousBindings::Get(this, context)));
693 module_system->RegisterNativeHandler("apiDefinitions", 728 module_system->RegisterNativeHandler("apiDefinitions",
694 scoped_ptr<NativeHandler>(new ApiDefinitionsNatives(this, context))); 729 scoped_ptr<NativeHandler>(new ApiDefinitionsNatives(this, context)));
695 module_system->RegisterNativeHandler("sendRequest", 730 module_system->RegisterNativeHandler("sendRequest",
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
869 global->Get(v8::String::New("chrome"))->ToObject(); 904 global->Get(v8::String::New("chrome"))->ToObject();
870 (*lazy_binding->second)(module_system, chrome); 905 (*lazy_binding->second)(module_system, chrome);
871 } else { 906 } else {
872 module_system->Require(api); 907 module_system->Require(api);
873 } 908 }
874 } 909 }
875 910
876 void Dispatcher::DidCreateScriptContext( 911 void Dispatcher::DidCreateScriptContext(
877 WebFrame* frame, v8::Handle<v8::Context> v8_context, int extension_group, 912 WebFrame* frame, v8::Handle<v8::Context> v8_context, int extension_group,
878 int world_id) { 913 int world_id) {
879 // Extensions are not supported on Android, so don't register any bindings. 914 #if !defined(ENABLE_EXTENSIONS)
880 #if defined(OS_ANDROID)
881 return; 915 return;
882 #endif 916 #endif
883 917
884 // TODO(koz): If the caller didn't pass extension_group, use the last value. 918 // TODO(koz): If the caller didn't pass extension_group, use the last value.
885 if (extension_group == -1) 919 if (extension_group == -1)
886 extension_group = g_hack_extension_group; 920 extension_group = g_hack_extension_group;
887 921
888 std::string extension_id = GetExtensionID(frame, world_id); 922 std::string extension_id = GetExtensionID(frame, world_id);
889 923
890 const Extension* extension = extensions_.GetByID(extension_id); 924 const Extension* extension = extensions_.GetByID(extension_id);
(...skipping 13 matching lines...) Expand all
904 ExtensionURLInfo url_info(frame->document().securityOrigin(), 938 ExtensionURLInfo url_info(frame->document().securityOrigin(),
905 UserScriptSlave::GetDataSourceURLForFrame(frame)); 939 UserScriptSlave::GetDataSourceURLForFrame(frame));
906 940
907 Feature::Context context_type = 941 Feature::Context context_type =
908 ClassifyJavaScriptContext(extension_id, extension_group, url_info); 942 ClassifyJavaScriptContext(extension_id, extension_group, url_info);
909 943
910 ChromeV8Context* context = 944 ChromeV8Context* context =
911 new ChromeV8Context(v8_context, frame, extension, context_type); 945 new ChromeV8Context(v8_context, frame, extension, context_type);
912 v8_context_set_.Add(context); 946 v8_context_set_.Add(context);
913 947
914 scoped_ptr<ModuleSystem> module_system(new ModuleSystem(context, 948 {
915 &source_map_)); 949 scoped_ptr<ModuleSystem> module_system(new ModuleSystem(context,
950 &source_map_));
951 context->set_module_system(module_system.Pass());
952 }
953 ModuleSystem* module_system = context->module_system();
954
916 // Enable natives in startup. 955 // Enable natives in startup.
917 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system.get()); 956 ModuleSystem::NativesEnabledScope natives_enabled_scope(
957 module_system);
918 958
919 RegisterNativeHandlers(module_system.get(), context); 959 RegisterNativeHandlers(module_system, context);
920 960
921 module_system->RegisterNativeHandler("chrome", 961 module_system->RegisterNativeHandler("chrome",
922 scoped_ptr<NativeHandler>(new ChromeNativeHandler(context))); 962 scoped_ptr<NativeHandler>(new ChromeNativeHandler(context)));
923 module_system->RegisterNativeHandler("print", 963 module_system->RegisterNativeHandler("print",
924 scoped_ptr<NativeHandler>(new PrintNativeHandler(context))); 964 scoped_ptr<NativeHandler>(new PrintNativeHandler(context)));
925 module_system->RegisterNativeHandler("lazy_background_page", 965 module_system->RegisterNativeHandler("lazy_background_page",
926 scoped_ptr<NativeHandler>( 966 scoped_ptr<NativeHandler>(
927 new LazyBackgroundPageNativeHandler(this, context))); 967 new LazyBackgroundPageNativeHandler(this, context)));
928 module_system->RegisterNativeHandler("logging", 968 module_system->RegisterNativeHandler("logging",
929 scoped_ptr<NativeHandler>(new LoggingNativeHandler(context))); 969 scoped_ptr<NativeHandler>(new LoggingNativeHandler(context)));
(...skipping 20 matching lines...) Expand all
950 // chrome.Event is part of the public API (although undocumented). Make it 990 // chrome.Event is part of the public API (although undocumented). Make it
951 // lazily evalulate to Event from event_bindings.js. 991 // lazily evalulate to Event from event_bindings.js.
952 module_system->SetLazyField(chrome, "Event", kEventModule, "Event"); 992 module_system->SetLazyField(chrome, "Event", kEventModule, "Event");
953 993
954 // Loading JavaScript is expensive, so only run the full API bindings 994 // Loading JavaScript is expensive, so only run the full API bindings
955 // generation mechanisms in extension pages (NOT all web pages). 995 // generation mechanisms in extension pages (NOT all web pages).
956 switch (context_type) { 996 switch (context_type) {
957 case Feature::UNSPECIFIED_CONTEXT: 997 case Feature::UNSPECIFIED_CONTEXT:
958 case Feature::WEB_PAGE_CONTEXT: 998 case Feature::WEB_PAGE_CONTEXT:
959 // TODO(kalman): see comment below about ExtensionAPI. 999 // TODO(kalman): see comment below about ExtensionAPI.
960 InstallBindings(module_system.get(), v8_context, "app"); 1000 InstallBindings(module_system, v8_context, "app");
961 InstallBindings(module_system.get(), v8_context, "webstore"); 1001 InstallBindings(module_system, v8_context, "webstore");
962 break; 1002 break;
963 case Feature::BLESSED_EXTENSION_CONTEXT: 1003 case Feature::BLESSED_EXTENSION_CONTEXT:
964 case Feature::UNBLESSED_EXTENSION_CONTEXT: 1004 case Feature::UNBLESSED_EXTENSION_CONTEXT:
965 case Feature::CONTENT_SCRIPT_CONTEXT: 1005 case Feature::CONTENT_SCRIPT_CONTEXT:
966 module_system->Require("json"); // see paranoid comment in json.js 1006 module_system->Require("json"); // see paranoid comment in json.js
967 1007
968 // TODO(kalman): move this code back out of the switch and execute it 1008 // TODO(kalman): move this code back out of the switch and execute it
969 // regardless of |context_type|. ExtensionAPI knows how to return the 1009 // regardless of |context_type|. ExtensionAPI knows how to return the
970 // correct APIs, however, until it doesn't have a 2MB overhead we can't 1010 // correct APIs, however, until it doesn't have a 2MB overhead we can't
971 // load it in every process. 1011 // load it in every process.
972 RegisterSchemaGeneratedBindings(module_system.get(), context); 1012 AddOrRemoveBindings(context);
973 break; 1013 break;
974 } 1014 }
975 1015
976 bool is_within_platform_app = IsWithinPlatformApp(frame); 1016 bool is_within_platform_app = IsWithinPlatformApp(frame);
977 // Inject custom JS into the platform app context. 1017 // Inject custom JS into the platform app context.
978 if (is_within_platform_app) 1018 if (is_within_platform_app)
979 module_system->Require("platformApp"); 1019 module_system->Require("platformApp");
980 1020
981 // Only platform apps support the <webview> tag, because the "webView" and 1021 // Only platform apps support the <webview> tag, because the "webView" and
982 // "denyWebView" modules will affect the performance of DOM modifications 1022 // "denyWebView" modules will affect the performance of DOM modifications
(...skipping 20 matching lines...) Expand all
1003 switches::kEnableAdviewSrcAttribute)) { 1043 switches::kEnableAdviewSrcAttribute)) {
1004 module_system->Require("adViewCustom"); 1044 module_system->Require("adViewCustom");
1005 } 1045 }
1006 module_system->Require("adView"); 1046 module_system->Require("adView");
1007 } else { 1047 } else {
1008 module_system->Require("denyAdView"); 1048 module_system->Require("denyAdView");
1009 } 1049 }
1010 } 1050 }
1011 } 1051 }
1012 1052
1013 context->set_module_system(module_system.Pass());
1014
1015 VLOG(1) << "Num tracked contexts: " << v8_context_set_.size(); 1053 VLOG(1) << "Num tracked contexts: " << v8_context_set_.size();
1016 } 1054 }
1017 1055
1018 std::string Dispatcher::GetExtensionID(const WebFrame* frame, int world_id) { 1056 std::string Dispatcher::GetExtensionID(const WebFrame* frame, int world_id) {
1019 if (world_id != 0) { 1057 if (world_id != 0) {
1020 // Isolated worlds (content script). 1058 // Isolated worlds (content script).
1021 return user_script_slave_->GetExtensionIdForIsolatedWorld(world_id); 1059 return user_script_slave_->GetExtensionIdForIsolatedWorld(world_id);
1022 } 1060 }
1023 1061
1024 // Extension pages (chrome-extension:// URLs). 1062 // Extension pages (chrome-extension:// URLs).
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
1167 new_active = PermissionSet::CreateUnion(old_active.get(), delta.get()); 1205 new_active = PermissionSet::CreateUnion(old_active.get(), delta.get());
1168 break; 1206 break;
1169 case UpdatedExtensionPermissionsInfo::REMOVED: 1207 case UpdatedExtensionPermissionsInfo::REMOVED:
1170 new_active = 1208 new_active =
1171 PermissionSet::CreateDifference(old_active.get(), delta.get()); 1209 PermissionSet::CreateDifference(old_active.get(), delta.get());
1172 break; 1210 break;
1173 } 1211 }
1174 1212
1175 PermissionsData::SetActivePermissions(extension, new_active); 1213 PermissionsData::SetActivePermissions(extension, new_active);
1176 AddOrRemoveOriginPermissions(reason, extension, explicit_hosts); 1214 AddOrRemoveOriginPermissions(reason, extension, explicit_hosts);
1215 v8_context_set().ForEach(
1216 extension_id,
1217 NULL,
1218 base::Bind(&Dispatcher::AddOrRemoveBindings, base::Unretained(this)));
1177 } 1219 }
1178 1220
1179 void Dispatcher::OnUpdateTabSpecificPermissions( 1221 void Dispatcher::OnUpdateTabSpecificPermissions(
1180 int page_id, 1222 int page_id,
1181 int tab_id, 1223 int tab_id,
1182 const std::string& extension_id, 1224 const std::string& extension_id,
1183 const URLPatternSet& origin_set) { 1225 const URLPatternSet& origin_set) {
1184 RenderView* view = TabFinder::Find(tab_id); 1226 RenderView* view = TabFinder::Find(tab_id);
1185 1227
1186 // For now, the message should only be sent to the render view that contains 1228 // For now, the message should only be sent to the render view that contains
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
1394 RenderView* background_view = 1436 RenderView* background_view =
1395 ExtensionHelper::GetBackgroundPage(extension_id); 1437 ExtensionHelper::GetBackgroundPage(extension_id);
1396 if (background_view) { 1438 if (background_view) {
1397 background_view->Send(new ExtensionHostMsg_EventAck( 1439 background_view->Send(new ExtensionHostMsg_EventAck(
1398 background_view->GetRoutingID())); 1440 background_view->GetRoutingID()));
1399 } 1441 }
1400 } 1442 }
1401 } 1443 }
1402 1444
1403 } // namespace extensions 1445 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/renderer/extensions/dispatcher.h ('k') | chrome/test/data/extensions/api_test/permissions/optional/background.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698