Index: extensions/renderer/user_script_slave.cc |
diff --git a/extensions/renderer/user_script_slave.cc b/extensions/renderer/user_script_slave.cc |
index eda1c0e28bf94552436ad5d9b9bdc68bd7fcf632..7e465c65d4e294b37e14444e12633c2cc2d076c6 100644 |
--- a/extensions/renderer/user_script_slave.cc |
+++ b/extensions/renderer/user_script_slave.cc |
@@ -31,7 +31,6 @@ using blink::WebFrame; |
using blink::WebSecurityOrigin; |
using blink::WebSecurityPolicy; |
using blink::WebString; |
-using blink::WebView; |
using content::RenderThread; |
namespace extensions { |
@@ -102,9 +101,9 @@ const Extension* UserScriptSlave::GetExtension( |
return extensions_->GetByID(extension_id); |
} |
-bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory) { |
- script_injections_.clear(); |
- |
+bool UserScriptSlave::UpdateScripts( |
+ base::SharedMemoryHandle shared_memory, |
+ const std::set<std::string>& changed_extensions) { |
bool only_inject_incognito = |
ExtensionsRendererClient::Get()->IsIncognitoProcess(); |
@@ -131,6 +130,26 @@ bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory) { |
PickleIterator iter(pickle); |
CHECK(pickle.ReadUInt64(&iter, &num_scripts)); |
+ // If we pass no explicit extension ids, we should refresh all extensions. |
+ bool include_all_extensions = changed_extensions.empty(); |
+ |
+ // If we include all extensions, then we clear the script injections and |
+ // start from scratch. If not, then clear only the scripts for extension ids |
+ // that we are updating. This is important to maintain pending script |
+ // injection state for each ScriptInjection. |
+ if (include_all_extensions) { |
+ script_injections_.clear(); |
+ } else { |
+ for (ScopedVector<ScriptInjection>::iterator iter = |
+ script_injections_.begin(); |
+ iter != script_injections_.end();) { |
+ if (changed_extensions.count((*iter)->extension_id()) > 0) |
+ iter = script_injections_.erase(iter); |
+ else |
+ ++iter; |
+ } |
+ } |
+ |
script_injections_.reserve(num_scripts); |
for (uint64 i = 0; i < num_scripts; ++i) { |
scoped_ptr<UserScript> script(new UserScript()); |
@@ -157,9 +176,31 @@ bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory) { |
if (only_inject_incognito && !script->is_incognito_enabled()) |
continue; // This script shouldn't run in an incognito tab. |
- script_injections_.push_back(new ScriptInjection(script.Pass(), this)); |
+ // If we include all extensions or the given extension changed, we add a |
+ // new script injection. |
+ if (include_all_extensions || |
+ changed_extensions.count(script->extension_id()) > 0) { |
+ script_injections_.push_back(new ScriptInjection(script.Pass(), this)); |
+ } else { |
+ // Otherwise, we need to update the existing script injection with the |
+ // new user script (since the old content was invalidated). |
+ // |
+ // Note: Yes, this is O(n^2). But vectors are faster than maps for |
+ // relatively few elements, and less than 1% of our users actually have |
+ // enough content scripts for it to matter. If this changes, or if |
+ // std::maps get a much faster implementation, we should look into |
+ // making a map for script injections. |
+ for (ScopedVector<ScriptInjection>::iterator iter = |
+ script_injections_.begin(); |
+ iter != script_injections_.end(); |
+ ++iter) { |
+ if ((*iter)->script()->id() == script->id()) { |
+ (*iter)->SetScript(script.Pass()); |
+ break; |
+ } |
+ } |
+ } |
} |
- |
return true; |
} |
@@ -169,40 +210,46 @@ void UserScriptSlave::InjectScripts(WebFrame* frame, |
if (document_url.is_empty()) |
return; |
- content::RenderView* top_render_view = |
- content::RenderView::FromWebView(frame->top()->view()); |
- |
ScriptInjection::ScriptsRunInfo scripts_run_info; |
for (ScopedVector<ScriptInjection>::const_iterator iter = |
script_injections_.begin(); |
iter != script_injections_.end(); |
++iter) { |
- ScriptInjection* injection = *iter; |
- if (!injection->WantsToRun(frame, location, document_url)) |
- continue; |
- |
- const Extension* extension = GetExtension(injection->extension_id()); |
- DCHECK(extension); |
- |
- if (PermissionsData::RequiresActionForScriptExecution( |
- extension, |
- ExtensionHelper::Get(top_render_view)->tab_id(), |
- document_url)) { |
- // TODO(rdevlin.cronin): Right now, this is just a notification, but soon |
- // we should block without user consent. |
- top_render_view->Send( |
- new ExtensionHostMsg_NotifyExtensionScriptExecution( |
- top_render_view->GetRoutingID(), |
- extension->id(), |
- top_render_view->GetPageId())); |
- } |
- |
- injection->Inject(frame, location, &scripts_run_info); |
+ (*iter)->InjectIfAllowed(frame, location, document_url, &scripts_run_info); |
} |
LogScriptsRun(frame, location, scripts_run_info); |
} |
+void UserScriptSlave::OnContentScriptGrantedPermission( |
+ content::RenderView* render_view, int request_id) { |
+ ScriptInjection::ScriptsRunInfo run_info; |
+ blink::WebFrame* frame = NULL; |
+ // Notify the injections that a request to inject has been granted. |
+ for (ScopedVector<ScriptInjection>::iterator iter = |
+ script_injections_.begin(); |
+ iter != script_injections_.end(); |
+ ++iter) { |
+ if ((*iter)->NotifyScriptPermitted(request_id, |
+ render_view, |
+ &run_info, |
+ &frame)) { |
+ DCHECK(frame); |
+ LogScriptsRun(frame, UserScript::RUN_DEFERRED, run_info); |
+ break; |
+ } |
+ } |
+} |
+ |
+void UserScriptSlave::FrameDetached(blink::WebFrame* frame) { |
+ for (ScopedVector<ScriptInjection>::iterator iter = |
+ script_injections_.begin(); |
+ iter != script_injections_.end(); |
+ ++iter) { |
+ (*iter)->FrameDetached(frame); |
+ } |
+} |
+ |
void UserScriptSlave::LogScriptsRun( |
blink::WebFrame* frame, |
UserScript::RunLocation location, |
@@ -218,22 +265,33 @@ void UserScriptSlave::LogScriptsRun( |
ScriptContext::GetDataSourceURLForFrame(frame))); |
} |
- if (location == UserScript::DOCUMENT_START) { |
- UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_CssCount", |
- info.num_css); |
- UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_ScriptCount", info.num_js); |
- if (info.num_css || info.num_js) |
- UMA_HISTOGRAM_TIMES("Extensions.InjectStart_Time", info.timer.Elapsed()); |
- } else if (location == UserScript::DOCUMENT_END) { |
- UMA_HISTOGRAM_COUNTS_100("Extensions.InjectEnd_ScriptCount", info.num_js); |
- if (info.num_js) |
- UMA_HISTOGRAM_TIMES("Extensions.InjectEnd_Time", info.timer.Elapsed()); |
- } else if (location == UserScript::DOCUMENT_IDLE) { |
- UMA_HISTOGRAM_COUNTS_100("Extensions.InjectIdle_ScriptCount", info.num_js); |
- if (info.num_js) |
- UMA_HISTOGRAM_TIMES("Extensions.InjectIdle_Time", info.timer.Elapsed()); |
- } else { |
- NOTREACHED(); |
+ switch (location) { |
+ case UserScript::DOCUMENT_START: |
+ UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_CssCount", |
+ info.num_css); |
+ UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_ScriptCount", |
+ info.num_js); |
+ if (info.num_css || info.num_js) |
+ UMA_HISTOGRAM_TIMES("Extensions.InjectStart_Time", |
+ info.timer.Elapsed()); |
+ break; |
+ case UserScript::DOCUMENT_END: |
+ UMA_HISTOGRAM_COUNTS_100("Extensions.InjectEnd_ScriptCount", info.num_js); |
+ if (info.num_js) |
+ UMA_HISTOGRAM_TIMES("Extensions.InjectEnd_Time", info.timer.Elapsed()); |
+ break; |
+ case UserScript::DOCUMENT_IDLE: |
+ UMA_HISTOGRAM_COUNTS_100("Extensions.InjectIdle_ScriptCount", |
+ info.num_js); |
+ if (info.num_js) |
+ UMA_HISTOGRAM_TIMES("Extensions.InjectIdle_Time", info.timer.Elapsed()); |
+ break; |
+ case UserScript::RUN_DEFERRED: |
+ // TODO(rdevlin.cronin): Add histograms. |
+ break; |
+ case UserScript::UNDEFINED: |
+ case UserScript::RUN_LOCATION_LAST: |
+ NOTREACHED(); |
} |
} |