From ccff496a48cdf435d59ef79f3fe9ae1e6914ed22 Mon Sep 17 00:00:00 2001 From: hanxi Date: Tue, 3 Mar 2015 15:14:06 -0800 Subject: [PATCH] This CL adds routing info for content scripts from . To support dynamically added/removed content scripts in , we store these content scripts in the same shared memory where user scripts from declarative content API are stored, but the decision for injection will be made in the render once the url pattern is matched. Since render doesn't need to send IPCs to ask a decision from browser, it makes a precise time injection possible. Special to , once the content scripts are updated (added/removed), browser will only notify the render process of the given , rather than all of the renders (which is the case for user scripts). BUG=437566 Committed: https://crrev.com/f853287c95cf818d0b5b02d7f4a6588761096d1c Cr-Commit-Position: refs/heads/master@{#318774} Review URL: https://codereview.chromium.org/906493004 Cr-Commit-Position: refs/heads/master@{#318959} --- extensions/browser/user_script_loader.cc | 23 +++++++++--- extensions/common/user_script.cc | 22 +++++++++++ extensions/common/user_script.h | 37 +++++++++++++++++++ .../renderer/extension_injection_host.cc | 13 +++++-- extensions/renderer/user_script_injector.cc | 19 +++++++--- 5 files changed, 99 insertions(+), 15 deletions(-) diff --git a/extensions/browser/user_script_loader.cc b/extensions/browser/user_script_loader.cc index 2b836332feba54..cc0ce00cf82f4c 100644 --- a/extensions/browser/user_script_loader.cc +++ b/extensions/browser/user_script_loader.cc @@ -444,11 +444,24 @@ void UserScriptLoader::OnScriptsLoaded( // We've got scripts ready to go. shared_memory_.reset(shared_memory.release()); - for (content::RenderProcessHost::iterator i( - content::RenderProcessHost::AllHostsIterator()); - !i.IsAtEnd(); - i.Advance()) { - SendUpdate(i.GetCurrentValue(), shared_memory_.get(), changed_hosts_); + // If user scripts are comming from a , will only notify the + // RenderProcessHost of that ; otherwise will notify all of the + // RenderProcessHosts. + if (user_scripts && !user_scripts->empty() && + (*user_scripts)[0].consumer_instance_type() == + UserScript::ConsumerInstanceType::WEBVIEW) { + DCHECK_EQ(1u, user_scripts->size()); + int render_process_id = (*user_scripts)[0].routing_info().render_process_id; + content::RenderProcessHost* host = + content::RenderProcessHost::FromID(render_process_id); + if (host) + SendUpdate(host, shared_memory_.get(), changed_hosts_); + } else { + for (content::RenderProcessHost::iterator i( + content::RenderProcessHost::AllHostsIterator()); + !i.IsAtEnd(); i.Advance()) { + SendUpdate(i.GetCurrentValue(), shared_memory_.get(), changed_hosts_); + } } changed_hosts_.clear(); diff --git a/extensions/common/user_script.cc b/extensions/common/user_script.cc index b8ba22e1d76395..7859e75f244cb0 100644 --- a/extensions/common/user_script.cc +++ b/extensions/common/user_script.cc @@ -145,6 +145,8 @@ void UserScript::Pickle(::Pickle* pickle) const { pickle->WriteBool(is_incognito_enabled()); PickleHostID(pickle, host_id_); + pickle->WriteInt(consumer_instance_type()); + PickleRoutingInfo(pickle, routing_info_); PickleGlobs(pickle, globs_); PickleGlobs(pickle, exclude_globs_); PickleURLPatternSet(pickle, url_set_); @@ -167,6 +169,12 @@ void UserScript::PickleHostID(::Pickle* pickle, const HostID& host_id) const { pickle->WriteString(host_id.id()); } +void UserScript::PickleRoutingInfo(::Pickle* pickle, + const RoutingInfo& routing_info) const { + pickle->WriteInt(routing_info.render_process_id); + pickle->WriteInt(routing_info.render_view_id); +} + void UserScript::PickleURLPatternSet(::Pickle* pickle, const URLPatternSet& pattern_list) const { pickle->WriteSizeT(pattern_list.patterns().size()); @@ -200,6 +208,13 @@ void UserScript::Unpickle(const ::Pickle& pickle, PickleIterator* iter) { CHECK(iter->ReadBool(&incognito_enabled_)); UnpickleHostID(pickle, iter, &host_id_); + + int consumer_instance_type = 0; + CHECK(iter->ReadInt(&consumer_instance_type)); + consumer_instance_type_ = + static_cast(consumer_instance_type); + + UnpickleRoutingInfo(pickle, iter, &routing_info_); UnpickleGlobs(pickle, iter, &globs_); UnpickleGlobs(pickle, iter, &exclude_globs_); UnpickleURLPatternSet(pickle, iter, &url_set_); @@ -230,6 +245,13 @@ void UserScript::UnpickleHostID(const ::Pickle& pickle, *host_id = HostID(static_cast(type), id); } +void UserScript::UnpickleRoutingInfo(const ::Pickle& pickle, + PickleIterator* iter, + RoutingInfo* routing_info) { + CHECK(iter->ReadInt(&routing_info->render_process_id)); + CHECK(iter->ReadInt(&routing_info->render_view_id)); +} + void UserScript::UnpickleURLPatternSet(const ::Pickle& pickle, PickleIterator* iter, URLPatternSet* pattern_list) { diff --git a/extensions/common/user_script.h b/extensions/common/user_script.h index 6069161e8fb4dc..e0de3f7e2af93a 100644 --- a/extensions/common/user_script.h +++ b/extensions/common/user_script.h @@ -126,6 +126,19 @@ class UserScript { typedef std::vector FileList; + // Render's routing info of a that the user script will be injected + // on. Only user scripts from s have a custom routing info. + struct RoutingInfo { + RoutingInfo() : render_process_id(-1), render_view_id(-1) {}; + ~RoutingInfo() {}; + + int render_process_id; + int render_view_id; + }; + + // Type of a API consumer instance that user scripts will be injected on. + enum ConsumerInstanceType { TAB, WEBVIEW }; + // Constructor. Default the run location to document end, which is like // Greasemonkey and probably more useful for typical scripts. UserScript(); @@ -200,6 +213,19 @@ class UserScript { const HostID& host_id() const { return host_id_; } void set_host_id(const HostID& host_id) { host_id_ = host_id; } + const ConsumerInstanceType& consumer_instance_type() const { + return consumer_instance_type_; + } + void set_consumer_instance_type( + const ConsumerInstanceType& consumer_instance_type) { + consumer_instance_type_ = consumer_instance_type; + } + + const RoutingInfo& routing_info() const { return routing_info_; } + void set_routing_info(const RoutingInfo& routing_info) { + routing_info_ = routing_info; + } + int id() const { return user_script_id_; } void set_id(int id) { user_script_id_ = id; } @@ -226,6 +252,8 @@ class UserScript { void PickleGlobs(::Pickle* pickle, const std::vector& globs) const; void PickleHostID(::Pickle* pickle, const HostID& host_id) const; + void PickleRoutingInfo(::Pickle* pickle, + const RoutingInfo& routing_info) const; void PickleURLPatternSet(::Pickle* pickle, const URLPatternSet& pattern_list) const; void PickleScripts(::Pickle* pickle, const FileList& scripts) const; @@ -236,6 +264,9 @@ class UserScript { void UnpickleHostID(const ::Pickle& pickle, PickleIterator* iter, HostID* host_id); + void UnpickleRoutingInfo(const ::Pickle& pickle, + PickleIterator* iter, + RoutingInfo* routing_info); void UnpickleURLPatternSet(const ::Pickle& pickle, PickleIterator* iter, URLPatternSet* pattern_list); void UnpickleScripts(const ::Pickle& pickle, PickleIterator* iter, @@ -278,6 +309,12 @@ class UserScript { // |host_id| can be empty if the script is a "standlone" user script. HostID host_id_; + // The type of the consumer instance that the script will be injected. + ConsumerInstanceType consumer_instance_type_; + + // The render side's rounting info for content_scripts of . + RoutingInfo routing_info_; + // The globally-unique id associated with this user script. Defaults to // -1 for invalid. int user_script_id_; diff --git a/extensions/renderer/extension_injection_host.cc b/extensions/renderer/extension_injection_host.cc index 5b3c463b0b8e90..55ee1cc6b4dec0 100644 --- a/extensions/renderer/extension_injection_host.cc +++ b/extensions/renderer/extension_injection_host.cc @@ -29,10 +29,15 @@ const std::string& ExtensionInjectionHost::name() const { } PermissionsData::AccessType ExtensionInjectionHost::CanExecuteOnFrame( - const GURL& document_url, - const GURL& top_frame_url, - int tab_id, - bool is_declarative) const { + const GURL& document_url, + const GURL& top_frame_url, + int tab_id, + bool is_declarative) const { + // If we don't have a tab id, we have no UI surface to ask for user consent. + // For now, we treat this as an automatic allow. + if (tab_id == -1) + return PermissionsData::ACCESS_ALLOWED; + // Declarative user scripts use "page access" (from "permissions" section in // manifest) whereas non-declarative user scripts use custom // "content script access" logic. diff --git a/extensions/renderer/user_script_injector.cc b/extensions/renderer/user_script_injector.cc index c3e15ef36e909c..e620a7c65e4ec7 100644 --- a/extensions/renderer/user_script_injector.cc +++ b/extensions/renderer/user_script_injector.cc @@ -8,6 +8,7 @@ #include "base/lazy_instance.h" #include "content/public/common/url_constants.h" +#include "content/public/renderer/render_view.h" #include "extensions/common/extension.h" #include "extensions/common/permissions/permissions_data.h" #include "extensions/renderer/injection_host.h" @@ -127,15 +128,21 @@ PermissionsData::AccessType UserScriptInjector::CanExecuteOnFrame( blink::WebFrame* web_frame, int tab_id, const GURL& top_url) const { - // If we don't have a tab id, we have no UI surface to ask for user consent. - // For now, we treat this as an automatic allow. - if (tab_id == -1) - return PermissionsData::ACCESS_ALLOWED; - GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL( web_frame, web_frame->document().url(), script_->match_about_blank()); - return injection_host->CanExecuteOnFrame( + PermissionsData::AccessType can_execute = injection_host->CanExecuteOnFrame( effective_document_url, top_url, tab_id, is_declarative_); + + if (script_->consumer_instance_type() != + UserScript::ConsumerInstanceType::WEBVIEW || + can_execute == PermissionsData::ACCESS_DENIED) + return can_execute; + + int routing_id = content::RenderView::FromWebView(web_frame->top()->view()) + ->GetRoutingID(); + return script_->routing_info().render_view_id == routing_id + ? PermissionsData::ACCESS_ALLOWED + : PermissionsData::ACCESS_DENIED; } std::vector UserScriptInjector::GetJsSources(