Skip to content

Commit

Permalink
This CL adds routing info for content scripts from <webview>.
Browse files Browse the repository at this point in the history
To support dynamically added/removed content scripts in <webview>, 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 <webview>, once the content scripts are updated (added/removed),
browser will only notify the render process of the given <webview>, 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}
  • Loading branch information
hanxi authored and Commit bot committed Mar 3, 2015
1 parent db73fae commit ccff496
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 15 deletions.
23 changes: 18 additions & 5 deletions extensions/browser/user_script_loader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 <webview>, will only notify the
// RenderProcessHost of that <webview>; 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();

Expand Down
22 changes: 22 additions & 0 deletions extensions/common/user_script.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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_);
Expand All @@ -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());
Expand Down Expand Up @@ -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<ConsumerInstanceType>(consumer_instance_type);

UnpickleRoutingInfo(pickle, iter, &routing_info_);
UnpickleGlobs(pickle, iter, &globs_);
UnpickleGlobs(pickle, iter, &exclude_globs_);
UnpickleURLPatternSet(pickle, iter, &url_set_);
Expand Down Expand Up @@ -230,6 +245,13 @@ void UserScript::UnpickleHostID(const ::Pickle& pickle,
*host_id = HostID(static_cast<HostID::HostType>(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) {
Expand Down
37 changes: 37 additions & 0 deletions extensions/common/user_script.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,19 @@ class UserScript {

typedef std::vector<File> FileList;

// Render's routing info of a <webview> that the user script will be injected
// on. Only user scripts from <webview>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();
Expand Down Expand Up @@ -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; }

Expand All @@ -226,6 +252,8 @@ class UserScript {
void PickleGlobs(::Pickle* pickle,
const std::vector<std::string>& 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;
Expand All @@ -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,
Expand Down Expand Up @@ -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 <webview>.
RoutingInfo routing_info_;

// The globally-unique id associated with this user script. Defaults to
// -1 for invalid.
int user_script_id_;
Expand Down
13 changes: 9 additions & 4 deletions extensions/renderer/extension_injection_host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
19 changes: 13 additions & 6 deletions extensions/renderer/user_script_injector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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<blink::WebScriptSource> UserScriptInjector::GetJsSources(
Expand Down

0 comments on commit ccff496

Please sign in to comment.