diff options
author | rdevlin.cronin@chromium.org <rdevlin.cronin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-03 22:41:02 +0000 |
---|---|---|
committer | rdevlin.cronin@chromium.org <rdevlin.cronin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-03 22:41:02 +0000 |
commit | 0d8d69767a1ff6becad7e25442ccdf94cac7290e (patch) | |
tree | bf080b49953ed8bf895e5bc9de306b64fb3dba37 /extensions/renderer | |
parent | e8daf71e4ad7e36b52267316c7f33b754356a01c (diff) | |
download | chromium_src-0d8d69767a1ff6becad7e25442ccdf94cac7290e.zip chromium_src-0d8d69767a1ff6becad7e25442ccdf94cac7290e.tar.gz chromium_src-0d8d69767a1ff6becad7e25442ccdf94cac7290e.tar.bz2 |
Resubmit: Block content scripts from executing until user grants permission
Original CL: https://codereview.chromium.org/288053002/
Original Description:
Prevent extensions with <all_urls> from running content scripts without user
consent if the scripts-require-action switch is on.
-----------------------------------------------
This had a problem in that when user scripts are updated, the old versions
are invalidated (as they rely on StringPieces, which do not actually own
content). Fix is to update all user scripts, even if they didn't actually
change.
Also add in ActiveScriptController removing actions for unloaded extensions.
TBR=jschuh@chromium.org (for extension_messages.h, no change from original patch)
BUG=362353
Review URL: https://codereview.chromium.org/313453002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274659 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'extensions/renderer')
-rw-r--r-- | extensions/renderer/dispatcher.cc | 21 | ||||
-rw-r--r-- | extensions/renderer/dispatcher.h | 3 | ||||
-rw-r--r-- | extensions/renderer/extension_helper.cc | 11 | ||||
-rw-r--r-- | extensions/renderer/extension_helper.h | 1 | ||||
-rw-r--r-- | extensions/renderer/script_injection.cc | 155 | ||||
-rw-r--r-- | extensions/renderer/script_injection.h | 59 | ||||
-rw-r--r-- | extensions/renderer/user_script_slave.cc | 150 | ||||
-rw-r--r-- | extensions/renderer/user_script_slave.h | 14 |
8 files changed, 351 insertions, 63 deletions
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index 04de939..0d11726 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc @@ -764,9 +764,24 @@ void Dispatcher::OnUpdateTabSpecificPermissions( this, page_id, tab_id, extension_id, origin_set); } -void Dispatcher::OnUpdateUserScripts(base::SharedMemoryHandle scripts) { - DCHECK(base::SharedMemory::IsHandleValid(scripts)) << "Bad scripts handle"; - user_script_slave_->UpdateScripts(scripts); +void Dispatcher::OnUpdateUserScripts( + base::SharedMemoryHandle scripts, + const std::set<std::string>& extension_ids) { + if (!base::SharedMemory::IsHandleValid(scripts)) { + NOTREACHED() << "Bad scripts handle"; + return; + } + + for (std::set<std::string>::const_iterator iter = extension_ids.begin(); + iter != extension_ids.end(); + ++iter) { + if (!Extension::IdIsValid(*iter)) { + NOTREACHED() << "Invalid extension id: " << *iter; + return; + } + } + + user_script_slave_->UpdateScripts(scripts, extension_ids); UpdateActiveExtensions(); } diff --git a/extensions/renderer/dispatcher.h b/extensions/renderer/dispatcher.h index 6878e20..7358607 100644 --- a/extensions/renderer/dispatcher.h +++ b/extensions/renderer/dispatcher.h @@ -180,7 +180,8 @@ class Dispatcher : public content::RenderProcessObserver { int tab_id, const std::string& extension_id, const URLPatternSet& origin_set); - void OnUpdateUserScripts(base::SharedMemoryHandle scripts); + void OnUpdateUserScripts(base::SharedMemoryHandle scripts, + const std::set<std::string>& extension_ids); void OnUsingWebRequestAPI(bool adblock, bool adblock_plus, bool other_webrequest); diff --git a/extensions/renderer/extension_helper.cc b/extensions/renderer/extension_helper.cc index 915097b..a3d4362 100644 --- a/extensions/renderer/extension_helper.cc +++ b/extensions/renderer/extension_helper.cc @@ -158,7 +158,9 @@ bool ExtensionHelper::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(ExtensionMsg_AddMessageToConsole, OnAddMessageToConsole) IPC_MESSAGE_HANDLER(ExtensionMsg_AppWindowClosed, - OnAppWindowClosed); + OnAppWindowClosed) + IPC_MESSAGE_HANDLER(ExtensionMsg_GrantContentScriptPermission, + OnGrantContentScriptPermission) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -217,6 +219,8 @@ void ExtensionHelper::FrameDetached(WebFrame* frame) { delete i->second; g_schedulers.Get().erase(i); + + dispatcher_->user_script_slave()->FrameDetached(frame); } void ExtensionHelper::DidMatchCSS( @@ -346,4 +350,9 @@ void ExtensionHelper::OnAppWindowClosed() { "onAppWindowClosed"); } +void ExtensionHelper::OnGrantContentScriptPermission(int request_id) { + dispatcher_->user_script_slave()->OnContentScriptGrantedPermission( + render_view(), request_id); +} + } // namespace extensions diff --git a/extensions/renderer/extension_helper.h b/extensions/renderer/extension_helper.h index 486db54..7bc489f 100644 --- a/extensions/renderer/extension_helper.h +++ b/extensions/renderer/extension_helper.h @@ -93,6 +93,7 @@ class ExtensionHelper void OnAddMessageToConsole(content::ConsoleMessageLevel level, const std::string& message); void OnAppWindowClosed(); + void OnGrantContentScriptPermission(int request_id); Dispatcher* dispatcher_; diff --git a/extensions/renderer/script_injection.cc b/extensions/renderer/script_injection.cc index 4db534a..d3113cd 100644 --- a/extensions/renderer/script_injection.cc +++ b/extensions/renderer/script_injection.cc @@ -9,17 +9,21 @@ #include "base/lazy_instance.h" #include "base/metrics/histogram.h" #include "content/public/common/url_constants.h" +#include "content/public/renderer/render_view.h" #include "extensions/common/extension.h" #include "extensions/common/extension_messages.h" +#include "extensions/common/feature_switch.h" #include "extensions/common/permissions/permissions_data.h" #include "extensions/renderer/dom_activity_logger.h" #include "extensions/renderer/extension_groups.h" +#include "extensions/renderer/extension_helper.h" #include "extensions/renderer/script_context.h" #include "extensions/renderer/user_script_slave.h" #include "grit/renderer_resources.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebScriptSource.h" +#include "third_party/WebKit/public/web/WebView.h" #include "ui/base/resource/resource_bundle.h" #include "url/gurl.h" @@ -27,6 +31,13 @@ namespace extensions { namespace { +// The id of the next pending injection. +int64 g_next_pending_id = 0; + +// The number of an invalid request, which is used if the feature to delay +// script injection is not enabled. +const int64 kInvalidRequestId = -1; + // These two strings are injected before and after the Greasemonkey API and // user script to wrap it in an anonymous scope. const char kUserScriptHead[] = "(function (unsafeWindow) {\n"; @@ -57,6 +68,42 @@ ScriptInjection::ScriptsRunInfo::ScriptsRunInfo() : num_css(0u), num_js(0u) { ScriptInjection::ScriptsRunInfo::~ScriptsRunInfo() { } +struct ScriptInjection::PendingInjection { + PendingInjection(blink::WebFrame* web_frame, + UserScript::RunLocation run_location, + int page_id); + ~PendingInjection(); + + // The globally-unique id of this request. + int64 id; + + // The pointer to the web frame into which the script should be injected. + // This is weak, but safe because we remove pending requests when a frame is + // terminated. + blink::WebFrame* web_frame; + + // The run location to inject at. + // Note: This could be a lie - we might inject well after this run location + // has come and gone. But we need to know it to know which scripts to inject. + UserScript::RunLocation run_location; + + // The corresponding page id, to protect against races. + int page_id; +}; + +ScriptInjection::PendingInjection::PendingInjection( + blink::WebFrame* web_frame, + UserScript::RunLocation run_location, + int page_id) + : id(g_next_pending_id++), + web_frame(web_frame), + run_location(run_location), + page_id(page_id) { +} + +ScriptInjection::PendingInjection::~PendingInjection() { +} + // static GURL ScriptInjection::GetDocumentUrlForFrame(blink::WebFrame* frame) { GURL data_source_url = ScriptContext::GetDataSourceURLForFrame(frame); @@ -81,6 +128,114 @@ ScriptInjection::ScriptInjection( ScriptInjection::~ScriptInjection() { } +void ScriptInjection::InjectIfAllowed(blink::WebFrame* frame, + UserScript::RunLocation run_location, + const GURL& document_url, + ScriptsRunInfo* scripts_run_info) { + if (!WantsToRun(frame, run_location, document_url)) + return; + + const Extension* extension = user_script_slave_->GetExtension(extension_id_); + DCHECK(extension); // WantsToRun() should be false if there's no extension. + + // We use the top render view here (instead of the render view for the + // frame), because script injection on any frame requires permission for + // the top frame. Additionally, if we have to show any UI for permissions, + // it should only be done on the top frame. + content::RenderView* top_render_view = + content::RenderView::FromWebView(frame->top()->view()); + + int tab_id = ExtensionHelper::Get(top_render_view)->tab_id(); + + // By default, we allow injection. + bool should_inject = true; + + // Check if the extension requires user consent for injection *and* we have a + // valid tab id (if we don't have a tab id, we have no UI surface to ask for + // user consent). + if (tab_id != -1 && + PermissionsData::RequiresActionForScriptExecution( + extension, + tab_id, + frame->top()->document().url())) { + int64 request_id = kInvalidRequestId; + int page_id = top_render_view->GetPageId(); + + // We only delay the injection if the feature is enabled. + // Otherwise, we simply treat this as a notification by passing an invalid + // id. + if (FeatureSwitch::scripts_require_action()->IsEnabled()) { + should_inject = false; + ScopedVector<PendingInjection>::iterator pending_injection = + pending_injections_.insert( + pending_injections_.end(), + new PendingInjection(frame, run_location, page_id)); + request_id = (*pending_injection)->id; + } + + top_render_view->Send( + new ExtensionHostMsg_RequestContentScriptPermission( + top_render_view->GetRoutingID(), + extension->id(), + page_id, + request_id)); + } + + if (should_inject) + Inject(frame, run_location, scripts_run_info); +} + +bool ScriptInjection::NotifyScriptPermitted( + int64 request_id, + content::RenderView* render_view, + ScriptsRunInfo* scripts_run_info, + blink::WebFrame** frame_out) { + ScopedVector<PendingInjection>::iterator iter = pending_injections_.begin(); + while (iter != pending_injections_.end() && (*iter)->id != request_id) + ++iter; + + // No matching request. + if (iter == pending_injections_.end()) + return false; + + // We found the request, so pull it out of the pending list. + scoped_ptr<PendingInjection> pending_injection(*iter); + pending_injections_.weak_erase(iter); + + // Ensure the Page ID and Extension are still valid. Otherwise, don't inject. + if (render_view->GetPageId() != pending_injection->page_id) + return false; + + const Extension* extension = user_script_slave_->GetExtension(extension_id_); + if (!extension) + return false; + + // Everything matches! Inject the script. + if (frame_out) + *frame_out = pending_injection->web_frame; + Inject(pending_injection->web_frame, + pending_injection->run_location, + scripts_run_info); + return true; +} + +void ScriptInjection::FrameDetached(blink::WebFrame* frame) { + // Any pending injections associated with the given frame will never run. + // Remove them. + for (ScopedVector<PendingInjection>::iterator iter = + pending_injections_.begin(); + iter != pending_injections_.end();) { + if ((*iter)->web_frame == frame) + iter = pending_injections_.erase(iter); + else + ++iter; + } +} + +void ScriptInjection::SetScript(scoped_ptr<UserScript> script) { + script_.reset(script.release()); +} + bool ScriptInjection::WantsToRun(blink::WebFrame* frame, UserScript::RunLocation run_location, const GURL& document_url) const { diff --git a/extensions/renderer/script_injection.h b/extensions/renderer/script_injection.h index 813fbb4..17c18de 100644 --- a/extensions/renderer/script_injection.h +++ b/extensions/renderer/script_injection.h @@ -9,8 +9,10 @@ #include <set> #include <string> +#include "base/basictypes.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" #include "base/timer/elapsed_timer.h" #include "extensions/common/user_script.h" @@ -20,6 +22,10 @@ namespace blink { class WebFrame; } +namespace content { +class RenderView; +} + namespace extensions { class UserScriptSlave; @@ -56,6 +62,39 @@ class ScriptInjection { UserScriptSlave* user_script_slave); ~ScriptInjection(); + // Inject the script into the given |frame| if the script should run on the + // frame and has permission to do so. If the script requires user consent, + // this will register a pending request to inject at a later time. + // If the script is run immediately, |scripts_run_info| is updated with + // information about the run. + void InjectIfAllowed(blink::WebFrame* frame, + UserScript::RunLocation location, + const GURL& document_url, + ScriptsRunInfo* scripts_run_info); + + // If a request with the given |request_id| exists, runs that request and + // modifies |scripts_run_info| with information about the run. Otherwise, does + // nothing. + // If |frame_out| is non-NULL and a script was run, |frame_out| will be + // populated with the frame in which the script was run. + // Returns true if the request was found *and* the script was run. + bool NotifyScriptPermitted(int64 request_id, + content::RenderView* render_view, + ScriptsRunInfo* scripts_run_info, + blink::WebFrame** frame_out); + + // Notififies the Injection that the frame has been detached (i.e. is about + // to be destroyed). + void FrameDetached(blink::WebFrame* frame); + + void SetScript(scoped_ptr<UserScript> script); + + const std::string& extension_id() { return extension_id_; } + const UserScript* script() { return script_.get(); } + + private: + struct PendingInjection; + // Returns true if this ScriptInjection wants to run on the given |frame| at // the given |run_location| (i.e., if this script would inject either JS or // CSS). @@ -63,20 +102,17 @@ class ScriptInjection { UserScript::RunLocation run_location, const GURL& document_url) const; + // Returns true if the script will inject [css|js] at the given + // |run_location|. + bool ShouldInjectJS(UserScript::RunLocation run_location) const; + bool ShouldInjectCSS(UserScript::RunLocation run_location) const; + // Injects the script into the given |frame|, and updates |scripts_run_info| // information about the run. void Inject(blink::WebFrame* frame, UserScript::RunLocation run_location, ScriptsRunInfo* scripts_run_info) const; - const std::string& extension_id() { return extension_id_; } - - private: - // Returns true if the script will inject [css|js] at the given - // |run_location|. - bool ShouldInjectJS(UserScript::RunLocation run_location) const; - bool ShouldInjectCSS(UserScript::RunLocation run_location) const; - // Injects the [css|js] scripts into the frame, and stores the results of // the run in |scripts_run_info|. void InjectJS(blink::WebFrame* frame, ScriptsRunInfo* scripts_run_info) const; @@ -86,9 +122,8 @@ class ScriptInjection { // The UserScript this is injecting. scoped_ptr<UserScript> script_; - // The associated extension's id. This is a safe const&, since it is owned by - // the |user_script_|. - const std::string& extension_id_; + // The associated extension's id. + std::string extension_id_; // The associated UserScriptSlave. // It's unfortunate that this is needed, but we use it to get the isolated @@ -99,6 +134,8 @@ class ScriptInjection { // True if the script is a standalone script or emulates greasemonkey. bool is_standalone_or_emulate_greasemonkey_; + ScopedVector<PendingInjection> pending_injections_; + DISALLOW_COPY_AND_ASSIGN(ScriptInjection); }; diff --git a/extensions/renderer/user_script_slave.cc b/extensions/renderer/user_script_slave.cc index eda1c0e..7e465c6 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(); } } diff --git a/extensions/renderer/user_script_slave.h b/extensions/renderer/user_script_slave.h index 4dd1029..70bfdb1 100644 --- a/extensions/renderer/user_script_slave.h +++ b/extensions/renderer/user_script_slave.h @@ -46,7 +46,11 @@ class UserScriptSlave { const Extension* GetExtension(const std::string& extension_id); // Update the parsed scripts from shared memory. - bool UpdateScripts(base::SharedMemoryHandle shared_memory); + // If |changed_extensions| is not empty, only those extensions will be + // updated. + // Otherwise, all extensions will be updated. + bool UpdateScripts(base::SharedMemoryHandle shared_memory, + const std::set<std::string>& changed_extensions); // Gets the isolated world ID to use for the given |extension| in the given // |frame|. If no isolated world has been created for that extension, @@ -66,6 +70,14 @@ class UserScriptSlave { // testability. void InjectScripts(blink::WebFrame* frame, UserScript::RunLocation location); + // Allow an extension to inject scripts that were previously delayed for user + // approval. + void OnContentScriptGrantedPermission( + content::RenderView* render_view, int request_id); + + // Notify the UserScriptSlave that the |frame| is detached, and about to die. + void FrameDetached(blink::WebFrame* frame); + private: // Log the data from scripts being run, including doing UMA and notifying the // browser. |