blob: ad112f584108c2dfcd5e1c9fe4a90b68068ca10d [file] [log] [blame]
[email protected]39ef0a7c52014-05-11 01:40:001// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
rdevlin.cronin8408b4f92016-03-15 19:14:145#include "chrome/browser/extensions/extension_action_runner.h"
[email protected]39ef0a7c52014-05-11 01:40:006
dchengc963c7142016-04-08 03:55:227#include <memory>
8
rdevlin.cronin4a78c48b2016-03-24 00:02:299#include "base/auto_reset.h"
[email protected]ac02ac52014-05-20 01:11:2610#include "base/bind.h"
11#include "base/bind_helpers.h"
fdoray283082bd2016-06-02 20:18:4612#include "base/location.h"
dchengc963c7142016-04-08 03:55:2213#include "base/memory/ptr_util.h"
[email protected]39ef0a7c52014-05-11 01:40:0014#include "base/metrics/histogram.h"
fdoray283082bd2016-06-02 20:18:4615#include "base/single_thread_task_runner.h"
[email protected]39ef0a7c52014-05-11 01:40:0016#include "base/stl_util.h"
fdoray283082bd2016-06-02 20:18:4617#include "base/threading/thread_task_runner_handle.h"
[email protected]78cd68e2014-05-22 20:33:5218#include "chrome/browser/extensions/active_tab_permission_granter.h"
rdevlin.croninaeffd182014-08-26 17:04:0019#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
[email protected]39ef0a7c52014-05-11 01:40:0020#include "chrome/browser/extensions/extension_action.h"
[email protected]6a24a0392014-08-12 21:31:3321#include "chrome/browser/extensions/extension_action_manager.h"
[email protected]e1670582014-08-15 23:05:4122#include "chrome/browser/extensions/permissions_updater.h"
[email protected]eac223a2014-05-13 17:39:5723#include "chrome/browser/extensions/tab_helper.h"
[email protected]6a24a0392014-08-12 21:31:3324#include "chrome/browser/profiles/profile.h"
[email protected]e3f90c602014-08-18 12:41:5925#include "chrome/browser/sessions/session_tab_helper.h"
rdevlin.cronin4a78c48b2016-03-24 00:02:2926#include "chrome/browser/ui/browser_finder.h"
27#include "chrome/browser/ui/browser_window.h"
28#include "chrome/browser/ui/extensions/blocked_action_bubble_delegate.h"
29#include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
[email protected]39ef0a7c52014-05-11 01:40:0030#include "chrome/common/extensions/api/extension_action/action_info.h"
[email protected]fdd28372014-08-21 02:27:2631#include "components/crx_file/id_util.h"
[email protected]39ef0a7c52014-05-11 01:40:0032#include "content/public/browser/navigation_controller.h"
rdevlin.cronin50942232014-08-27 17:40:5633#include "content/public/browser/navigation_details.h"
[email protected]39ef0a7c52014-05-11 01:40:0034#include "content/public/browser/navigation_entry.h"
[email protected]ac02ac52014-05-20 01:11:2635#include "content/public/browser/render_view_host.h"
[email protected]39ef0a7c52014-05-11 01:40:0036#include "content/public/browser/web_contents.h"
37#include "extensions/browser/extension_registry.h"
38#include "extensions/common/extension.h"
39#include "extensions/common/extension_messages.h"
40#include "extensions/common/extension_set.h"
[email protected]23a85362014-07-07 23:26:1941#include "extensions/common/manifest.h"
[email protected]e1670582014-08-15 23:05:4142#include "extensions/common/permissions/permission_set.h"
[email protected]39ef0a7c52014-05-11 01:40:0043#include "extensions/common/permissions/permissions_data.h"
44#include "ipc/ipc_message_macros.h"
45
46namespace extensions {
47
rdevlin.cronin4a78c48b2016-03-24 00:02:2948namespace {
49
50// The blocked actions that require a page refresh to run.
51const int kRefreshRequiredActionsMask =
52 BLOCKED_ACTION_WEB_REQUEST | BLOCKED_ACTION_SCRIPT_AT_START;
53}
54
rdevlin.cronin8408b4f92016-03-15 19:14:1455ExtensionActionRunner::PendingScript::PendingScript(
rdevlin.cronin8d034e52016-02-02 22:46:3256 UserScript::RunLocation run_location,
57 const base::Closure& permit_script)
58 : run_location(run_location), permit_script(permit_script) {}
59
rdevlin.cronin8408b4f92016-03-15 19:14:1460ExtensionActionRunner::PendingScript::PendingScript(
vmpstrb8aacbe2016-02-26 02:00:4861 const PendingScript& other) = default;
62
rdevlin.cronin8408b4f92016-03-15 19:14:1463ExtensionActionRunner::PendingScript::~PendingScript() {}
rdevlin.cronin8d034e52016-02-02 22:46:3264
rdevlin.cronin8408b4f92016-03-15 19:14:1465ExtensionActionRunner::ExtensionActionRunner(content::WebContents* web_contents)
[email protected]39ef0a7c52014-05-11 01:40:0066 : content::WebContentsObserver(web_contents),
rdevlin.cronin1f877032015-02-20 00:12:4267 num_page_requests_(0),
rdevlin.cronin699ca6ff2014-09-29 23:59:5768 browser_context_(web_contents->GetBrowserContext()),
rdevlin.croninb8dffe562015-02-07 00:58:0169 was_used_on_page_(false),
rdevlin.cronin4a78c48b2016-03-24 00:02:2970 ignore_active_tab_granted_(false),
71 extension_registry_observer_(this),
72 weak_factory_(this) {
[email protected]ac02ac52014-05-20 01:11:2673 CHECK(web_contents);
rdevlin.cronin699ca6ff2014-09-29 23:59:5774 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
[email protected]39ef0a7c52014-05-11 01:40:0075}
76
rdevlin.cronin8408b4f92016-03-15 19:14:1477ExtensionActionRunner::~ExtensionActionRunner() {
[email protected]39ef0a7c52014-05-11 01:40:0078 LogUMA();
79}
80
[email protected]eac223a2014-05-13 17:39:5781// static
rdevlin.cronin8408b4f92016-03-15 19:14:1482ExtensionActionRunner* ExtensionActionRunner::GetForWebContents(
[email protected]eac223a2014-05-13 17:39:5783 content::WebContents* web_contents) {
84 if (!web_contents)
85 return NULL;
86 TabHelper* tab_helper = TabHelper::FromWebContents(web_contents);
rdevlin.cronin8408b4f92016-03-15 19:14:1487 return tab_helper ? tab_helper->extension_action_runner() : NULL;
[email protected]eac223a2014-05-13 17:39:5788}
89
rdevlin.cronin343fd102016-03-17 00:24:5490ExtensionAction::ShowAction ExtensionActionRunner::RunAction(
91 const Extension* extension,
92 bool grant_tab_permissions) {
rdevlin.cronin343fd102016-03-17 00:24:5493 if (grant_tab_permissions) {
rdevlin.cronin4a78c48b2016-03-24 00:02:2994 int blocked = GetBlockedActions(extension);
95 if ((blocked & kRefreshRequiredActionsMask) != 0) {
96 ShowBlockedActionBubble(extension);
97 return ExtensionAction::ACTION_NONE;
98 }
rdevlin.cronin343fd102016-03-17 00:24:5499 TabHelper::FromWebContents(web_contents())
100 ->active_tab_permission_granter()
101 ->GrantIfRequested(extension);
102 // If the extension had blocked actions, granting active tab will have
103 // run the extension. Don't execute further since clicking should run
104 // blocked actions *or* the normal extension action, not both.
rdevlin.cronin4a78c48b2016-03-24 00:02:29105 if (blocked != BLOCKED_ACTION_NONE)
rdevlin.cronin343fd102016-03-17 00:24:54106 return ExtensionAction::ACTION_NONE;
107 }
108
109 ExtensionAction* extension_action =
110 ExtensionActionManager::Get(browser_context_)
111 ->GetExtensionAction(*extension);
112
113 // Anything that gets here should have a page or browser action.
114 DCHECK(extension_action);
115 int tab_id = SessionTabHelper::IdForTab(web_contents());
116 if (!extension_action->GetIsVisible(tab_id))
117 return ExtensionAction::ACTION_NONE;
118
119 if (extension_action->HasPopup(tab_id))
120 return ExtensionAction::ACTION_SHOW_POPUP;
121
122 ExtensionActionAPI::Get(browser_context_)
123 ->DispatchExtensionActionClicked(*extension_action, web_contents());
124 return ExtensionAction::ACTION_NONE;
[email protected]11814f52014-05-23 06:50:35125}
126
rdevlin.cronin343fd102016-03-17 00:24:54127void ExtensionActionRunner::RunBlockedActions(const Extension* extension) {
rdevlin.croninacb745922016-02-17 20:37:44128 DCHECK(ContainsKey(pending_scripts_, extension->id()) ||
129 web_request_blocked_.count(extension->id()) != 0);
130
131 // Clicking to run the extension counts as granting it permission to run on
132 // the given tab.
133 // The extension may already have active tab at this point, but granting
134 // it twice is essentially a no-op.
135 TabHelper::FromWebContents(web_contents())
136 ->active_tab_permission_granter()
137 ->GrantIfRequested(extension);
138
139 RunPendingScriptsForExtension(extension);
140 web_request_blocked_.erase(extension->id());
141
142 // The extension ran, so we need to tell the ExtensionActionAPI that we no
143 // longer want to act.
144 NotifyChange(extension);
rdevlin.cronine9c71122014-08-25 23:47:21145}
146
rdevlin.cronin343fd102016-03-17 00:24:54147void ExtensionActionRunner::OnActiveTabPermissionGranted(
148 const Extension* extension) {
rdevlin.cronin4a78c48b2016-03-24 00:02:29149 if (!ignore_active_tab_granted_ && WantsToRun(extension))
rdevlin.cronin343fd102016-03-17 00:24:54150 RunBlockedActions(extension);
151}
152
rdevlin.cronin8408b4f92016-03-15 19:14:14153void ExtensionActionRunner::OnWebRequestBlocked(const Extension* extension) {
rdevlin.cronin8d034e52016-02-02 22:46:32154 web_request_blocked_.insert(extension->id());
155}
156
rdevlin.cronin8408b4f92016-03-15 19:14:14157int ExtensionActionRunner::GetBlockedActions(const Extension* extension) {
rdevlin.cronin8d034e52016-02-02 22:46:32158 int blocked_actions = BLOCKED_ACTION_NONE;
159 if (web_request_blocked_.count(extension->id()) != 0)
160 blocked_actions |= BLOCKED_ACTION_WEB_REQUEST;
161 auto iter = pending_scripts_.find(extension->id());
162 if (iter != pending_scripts_.end()) {
163 for (const PendingScript& script : iter->second) {
164 switch (script.run_location) {
165 case UserScript::DOCUMENT_START:
166 blocked_actions |= BLOCKED_ACTION_SCRIPT_AT_START;
167 break;
168 case UserScript::DOCUMENT_END:
169 case UserScript::DOCUMENT_IDLE:
170 case UserScript::BROWSER_DRIVEN:
171 blocked_actions |= BLOCKED_ACTION_SCRIPT_OTHER;
172 break;
173 case UserScript::UNDEFINED:
174 case UserScript::RUN_DEFERRED:
175 case UserScript::RUN_LOCATION_LAST:
176 NOTREACHED();
177 }
178 }
179 }
180
181 return blocked_actions;
182}
183
rdevlin.cronin8408b4f92016-03-15 19:14:14184bool ExtensionActionRunner::WantsToRun(const Extension* extension) {
rdevlin.cronin8d034e52016-02-02 22:46:32185 return GetBlockedActions(extension) != BLOCKED_ACTION_NONE;
[email protected]e1670582014-08-15 23:05:41186}
187
rdevlin.cronin4a78c48b2016-03-24 00:02:29188void ExtensionActionRunner::RunForTesting(const Extension* extension) {
189 if (WantsToRun(extension)) {
190 TabHelper::FromWebContents(web_contents())
191 ->active_tab_permission_granter()
192 ->GrantIfRequested(extension);
193 }
194}
195
[email protected]23a85362014-07-07 23:26:19196PermissionsData::AccessType
rdevlin.cronin8408b4f92016-03-15 19:14:14197ExtensionActionRunner::RequiresUserConsentForScriptInjection(
[email protected]23a85362014-07-07 23:26:19198 const Extension* extension,
199 UserScript::InjectionType type) {
200 CHECK(extension);
201
[email protected]23a85362014-07-07 23:26:19202 // Allow the extension if it's been explicitly granted permission.
203 if (permitted_extensions_.count(extension->id()) > 0)
204 return PermissionsData::ACCESS_ALLOWED;
205
206 GURL url = web_contents()->GetVisibleURL();
[email protected]e3f90c602014-08-18 12:41:59207 int tab_id = SessionTabHelper::IdForTab(web_contents());
[email protected]23a85362014-07-07 23:26:19208 switch (type) {
209 case UserScript::CONTENT_SCRIPT:
210 return extension->permissions_data()->GetContentScriptAccess(
rob889ceeb2016-01-25 19:41:08211 extension, url, tab_id, nullptr);
[email protected]23a85362014-07-07 23:26:19212 case UserScript::PROGRAMMATIC_SCRIPT:
rob889ceeb2016-01-25 19:41:08213 return extension->permissions_data()->GetPageAccess(extension, url,
214 tab_id, nullptr);
[email protected]23a85362014-07-07 23:26:19215 }
216
217 NOTREACHED();
218 return PermissionsData::ACCESS_DENIED;
219}
220
rdevlin.cronin8408b4f92016-03-15 19:14:14221void ExtensionActionRunner::RequestScriptInjection(
[email protected]23a85362014-07-07 23:26:19222 const Extension* extension,
rdevlin.cronin8d034e52016-02-02 22:46:32223 UserScript::RunLocation run_location,
[email protected]23a85362014-07-07 23:26:19224 const base::Closure& callback) {
225 CHECK(extension);
rdevlin.cronin8d034e52016-02-02 22:46:32226 PendingScriptList& list = pending_scripts_[extension->id()];
227 list.push_back(PendingScript(run_location, callback));
[email protected]23a85362014-07-07 23:26:19228
rdevlin.cronin699ca6ff2014-09-29 23:59:57229 // If this was the first entry, we need to notify that a new extension wants
230 // to run.
231 if (list.size() == 1u)
232 NotifyChange(extension);
rdevlin.croninb8dffe562015-02-07 00:58:01233
234 was_used_on_page_ = true;
[email protected]23a85362014-07-07 23:26:19235}
236
rdevlin.cronin8408b4f92016-03-15 19:14:14237void ExtensionActionRunner::RunPendingScriptsForExtension(
[email protected]11814f52014-05-23 06:50:35238 const Extension* extension) {
[email protected]ac02ac52014-05-20 01:11:26239 DCHECK(extension);
[email protected]ac02ac52014-05-20 01:11:26240
241 content::NavigationEntry* visible_entry =
242 web_contents()->GetController().GetVisibleEntry();
243 // Refuse to run if there's no visible entry, because we have no idea of
244 // determining if it's the proper page. This should rarely, if ever, happen.
245 if (!visible_entry)
[email protected]11814f52014-05-23 06:50:35246 return;
[email protected]ac02ac52014-05-20 01:11:26247
[email protected]ac02ac52014-05-20 01:11:26248 // We add this to the list of permitted extensions and erase pending entries
249 // *before* running them to guard against the crazy case where running the
250 // callbacks adds more entries.
251 permitted_extensions_.insert(extension->id());
[email protected]23a85362014-07-07 23:26:19252
rdevlin.cronin8d034e52016-02-02 22:46:32253 PendingScriptMap::iterator iter = pending_scripts_.find(extension->id());
254 if (iter == pending_scripts_.end())
[email protected]23a85362014-07-07 23:26:19255 return;
256
rdevlin.cronin8d034e52016-02-02 22:46:32257 PendingScriptList scripts;
258 iter->second.swap(scripts);
259 pending_scripts_.erase(extension->id());
[email protected]ac02ac52014-05-20 01:11:26260
261 // Run all pending injections for the given extension.
rdevlin.cronin8d034e52016-02-02 22:46:32262 for (PendingScript& pending_script : scripts)
263 pending_script.permit_script.Run();
[email protected]ac02ac52014-05-20 01:11:26264}
265
rdevlin.cronin8408b4f92016-03-15 19:14:14266void ExtensionActionRunner::OnRequestScriptInjectionPermission(
[email protected]ac02ac52014-05-20 01:11:26267 const std::string& extension_id,
[email protected]23a85362014-07-07 23:26:19268 UserScript::InjectionType script_type,
rdevlin.cronin8d034e52016-02-02 22:46:32269 UserScript::RunLocation run_location,
avia2f4804a2015-12-24 23:11:13270 int64_t request_id) {
[email protected]fdd28372014-08-21 02:27:26271 if (!crx_file::id_util::IdIsValid(extension_id)) {
[email protected]ac02ac52014-05-20 01:11:26272 NOTREACHED() << "'" << extension_id << "' is not a valid id.";
273 return;
274 }
275
rdevlin.cronin8408b4f92016-03-15 19:14:14276 const Extension* extension = ExtensionRegistry::Get(browser_context_)
277 ->enabled_extensions()
278 .GetByID(extension_id);
[email protected]ac02ac52014-05-20 01:11:26279 // We shouldn't allow extensions which are no longer enabled to run any
280 // scripts. Ignore the request.
281 if (!extension)
282 return;
283
rdevlin.cronin1f877032015-02-20 00:12:42284 ++num_page_requests_;
285
[email protected]23a85362014-07-07 23:26:19286 switch (RequiresUserConsentForScriptInjection(extension, script_type)) {
287 case PermissionsData::ACCESS_ALLOWED:
288 PermitScriptInjection(request_id);
289 break;
290 case PermissionsData::ACCESS_WITHHELD:
291 // This base::Unretained() is safe, because the callback is only invoked
292 // by this object.
293 RequestScriptInjection(
rdevlin.cronin8d034e52016-02-02 22:46:32294 extension, run_location,
rdevlin.cronin8408b4f92016-03-15 19:14:14295 base::Bind(&ExtensionActionRunner::PermitScriptInjection,
rdevlin.cronin8d034e52016-02-02 22:46:32296 base::Unretained(this), request_id));
[email protected]23a85362014-07-07 23:26:19297 break;
298 case PermissionsData::ACCESS_DENIED:
299 // We should usually only get a "deny access" if the page changed (as the
300 // renderer wouldn't have requested permission if the answer was always
301 // "no"). Just let the request fizzle and die.
302 break;
[email protected]0d8d6972014-06-03 22:41:02303 }
304}
305
rdevlin.cronin8408b4f92016-03-15 19:14:14306void ExtensionActionRunner::PermitScriptInjection(int64_t request_id) {
[email protected]23a85362014-07-07 23:26:19307 // This only sends the response to the renderer - the process of adding the
308 // extension to the list of |permitted_extensions_| is done elsewhere.
rdevlin.cronin4bb32d72015-06-02 21:55:01309 // TODO(devlin): Instead of sending this to all frames, we should include the
310 // routing_id in the permission request message, and send only to the proper
311 // frame (sending it to all frames doesn't hurt, but isn't as efficient).
312 web_contents()->SendToAllFrames(new ExtensionMsg_PermitScriptInjection(
313 MSG_ROUTING_NONE, // Routing id is set by the |web_contents|.
314 request_id));
[email protected]39ef0a7c52014-05-11 01:40:00315}
316
rdevlin.cronin8408b4f92016-03-15 19:14:14317void ExtensionActionRunner::NotifyChange(const Extension* extension) {
rdevlin.cronin699ca6ff2014-09-29 23:59:57318 ExtensionActionAPI* extension_action_api =
319 ExtensionActionAPI::Get(browser_context_);
320 ExtensionAction* extension_action =
rdevlin.cronin8408b4f92016-03-15 19:14:14321 ExtensionActionManager::Get(browser_context_)
322 ->GetExtensionAction(*extension);
rdevlin.cronin699ca6ff2014-09-29 23:59:57323 // If the extension has an action, we need to notify that it's updated.
324 if (extension_action) {
rdevlin.cronin8408b4f92016-03-15 19:14:14325 extension_action_api->NotifyChange(extension_action, web_contents(),
326 browser_context_);
rdevlin.cronin699ca6ff2014-09-29 23:59:57327 }
328
329 // We also notify that page actions may have changed.
330 extension_action_api->NotifyPageActionsChanged(web_contents());
331}
332
rdevlin.cronin8408b4f92016-03-15 19:14:14333void ExtensionActionRunner::LogUMA() const {
rdevlin.croninb8dffe562015-02-07 00:58:01334 // We only log the permitted extensions metric if the feature was used at all
335 // on the page, because otherwise the data will be boring.
336 if (was_used_on_page_) {
[email protected]ac02ac52014-05-20 01:11:26337 UMA_HISTOGRAM_COUNTS_100(
338 "Extensions.ActiveScriptController.PermittedExtensions",
339 permitted_extensions_.size());
340 UMA_HISTOGRAM_COUNTS_100(
341 "Extensions.ActiveScriptController.DeniedExtensions",
rdevlin.cronin8d034e52016-02-02 22:46:32342 pending_scripts_.size());
[email protected]ac02ac52014-05-20 01:11:26343 }
[email protected]39ef0a7c52014-05-11 01:40:00344}
345
rdevlin.cronin4a78c48b2016-03-24 00:02:29346void ExtensionActionRunner::ShowBlockedActionBubble(
347 const Extension* extension) {
348 Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
349 ToolbarActionsBar* toolbar_actions_bar =
350 browser ? browser->window()->GetToolbarActionsBar() : nullptr;
351 if (toolbar_actions_bar) {
352 auto callback =
353 base::Bind(&ExtensionActionRunner::OnBlockedActionBubbleClosed,
354 weak_factory_.GetWeakPtr(), extension->id());
355 if (default_bubble_close_action_for_testing_) {
fdoray283082bd2016-06-02 20:18:46356 base::ThreadTaskRunnerHandle::Get()->PostTask(
rdevlin.cronin4a78c48b2016-03-24 00:02:29357 FROM_HERE,
358 base::Bind(callback, *default_bubble_close_action_for_testing_));
359 } else {
dchengc963c7142016-04-08 03:55:22360 toolbar_actions_bar->ShowToolbarActionBubble(base::WrapUnique(
rdevlin.cronin4a78c48b2016-03-24 00:02:29361 new BlockedActionBubbleDelegate(callback, extension->id())));
362 }
363 }
364}
365
366void ExtensionActionRunner::OnBlockedActionBubbleClosed(
367 const std::string& extension_id,
368 ToolbarActionsBarBubbleDelegate::CloseAction action) {
369 // If the user agreed to refresh the page, do so.
370 if (action == ToolbarActionsBarBubbleDelegate::CLOSE_EXECUTE) {
371 const Extension* extension = ExtensionRegistry::Get(browser_context_)
372 ->enabled_extensions()
373 .GetByID(extension_id);
374 if (!extension)
375 return;
376 {
377 // Ignore the active tab permission being granted because we don't want
378 // to run scripts right before we refresh the page.
379 base::AutoReset<bool> ignore_active_tab(&ignore_active_tab_granted_,
380 true);
381 TabHelper::FromWebContents(web_contents())
382 ->active_tab_permission_granter()
383 ->GrantIfRequested(extension);
384 }
385 web_contents()->GetController().Reload(false);
386 }
387}
388
rdevlin.cronin8408b4f92016-03-15 19:14:14389bool ExtensionActionRunner::OnMessageReceived(
rdevlin.cronin45dca7f2015-06-08 19:47:03390 const IPC::Message& message,
391 content::RenderFrameHost* render_frame_host) {
rdevlin.cronin6e7e5edc2014-08-29 16:23:23392 bool handled = true;
rdevlin.cronin8408b4f92016-03-15 19:14:14393 IPC_BEGIN_MESSAGE_MAP(ExtensionActionRunner, message)
rdevlin.cronin6e7e5edc2014-08-29 16:23:23394 IPC_MESSAGE_HANDLER(ExtensionHostMsg_RequestScriptInjectionPermission,
395 OnRequestScriptInjectionPermission)
396 IPC_MESSAGE_UNHANDLED(handled = false)
397 IPC_END_MESSAGE_MAP()
398 return handled;
399}
400
rdevlin.cronin8408b4f92016-03-15 19:14:14401void ExtensionActionRunner::DidNavigateMainFrame(
rdevlin.cronin50942232014-08-27 17:40:56402 const content::LoadCommittedDetails& details,
403 const content::FrameNavigateParams& params) {
404 if (details.is_in_page)
405 return;
406
407 LogUMA();
rdevlin.cronin1f877032015-02-20 00:12:42408 num_page_requests_ = 0;
rdevlin.cronin50942232014-08-27 17:40:56409 permitted_extensions_.clear();
rdevlin.cronin8d034e52016-02-02 22:46:32410 pending_scripts_.clear();
411 web_request_blocked_.clear();
rdevlin.croninb8dffe562015-02-07 00:58:01412 was_used_on_page_ = false;
rdevlin.cronin4a78c48b2016-03-24 00:02:29413 weak_factory_.InvalidateWeakPtrs();
rdevlin.cronin50942232014-08-27 17:40:56414}
415
rdevlin.cronin8408b4f92016-03-15 19:14:14416void ExtensionActionRunner::OnExtensionUnloaded(
rdevlin.cronin6e7e5edc2014-08-29 16:23:23417 content::BrowserContext* browser_context,
418 const Extension* extension,
419 UnloadedExtensionInfo::Reason reason) {
rdevlin.cronin8d034e52016-02-02 22:46:32420 PendingScriptMap::iterator iter = pending_scripts_.find(extension->id());
421 if (iter != pending_scripts_.end()) {
422 pending_scripts_.erase(iter);
rdevlin.cronin8408b4f92016-03-15 19:14:14423 ExtensionActionAPI::Get(browser_context_)
424 ->NotifyPageActionsChanged(web_contents());
rdevlin.cronin6e7e5edc2014-08-29 16:23:23425 }
426}
427
[email protected]39ef0a7c52014-05-11 01:40:00428} // namespace extensions