OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/browser/extension_function_dispatcher.h" | 5 #include "extensions/browser/extension_function_dispatcher.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/json/json_string_value_serializer.h" | 10 #include "base/json/json_string_value_serializer.h" |
11 #include "base/lazy_instance.h" | 11 #include "base/lazy_instance.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/macros.h" | 13 #include "base/macros.h" |
14 #include "base/memory/ref_counted.h" | 14 #include "base/memory/ref_counted.h" |
15 #include "base/metrics/histogram_macros.h" | 15 #include "base/metrics/histogram_macros.h" |
16 #include "base/metrics/sparse_histogram.h" | 16 #include "base/metrics/sparse_histogram.h" |
17 #include "base/process/process.h" | 17 #include "base/process/process.h" |
18 #include "base/profiler/scoped_profile.h" | 18 #include "base/profiler/scoped_profile.h" |
| 19 #include "base/scoped_observer.h" |
19 #include "base/values.h" | 20 #include "base/values.h" |
20 #include "build/build_config.h" | 21 #include "build/build_config.h" |
21 #include "content/public/browser/browser_thread.h" | 22 #include "content/public/browser/browser_thread.h" |
22 #include "content/public/browser/render_frame_host.h" | 23 #include "content/public/browser/render_frame_host.h" |
23 #include "content/public/browser/render_process_host.h" | 24 #include "content/public/browser/render_process_host.h" |
| 25 #include "content/public/browser/render_process_host_observer.h" |
24 #include "content/public/browser/render_view_host.h" | 26 #include "content/public/browser/render_view_host.h" |
25 #include "content/public/browser/user_metrics.h" | 27 #include "content/public/browser/user_metrics.h" |
26 #include "content/public/browser/web_contents.h" | 28 #include "content/public/browser/web_contents.h" |
27 #include "content/public/browser/web_contents_observer.h" | 29 #include "content/public/browser/web_contents_observer.h" |
28 #include "content/public/common/result_codes.h" | 30 #include "content/public/common/result_codes.h" |
29 #include "extensions/browser/api_activity_monitor.h" | 31 #include "extensions/browser/api_activity_monitor.h" |
30 #include "extensions/browser/extension_function_registry.h" | 32 #include "extensions/browser/extension_function_registry.h" |
31 #include "extensions/browser/extension_registry.h" | 33 #include "extensions/browser/extension_registry.h" |
32 #include "extensions/browser/extension_system.h" | 34 #include "extensions/browser/extension_system.h" |
33 #include "extensions/browser/extensions_browser_client.h" | 35 #include "extensions/browser/extensions_browser_client.h" |
34 #include "extensions/browser/io_thread_extension_message_filter.h" | 36 #include "extensions/browser/io_thread_extension_message_filter.h" |
35 #include "extensions/browser/process_manager.h" | 37 #include "extensions/browser/process_manager.h" |
36 #include "extensions/browser/process_map.h" | 38 #include "extensions/browser/process_map.h" |
37 #include "extensions/browser/quota_service.h" | 39 #include "extensions/browser/quota_service.h" |
38 #include "extensions/common/extension_api.h" | 40 #include "extensions/common/extension_api.h" |
39 #include "extensions/common/extension_messages.h" | 41 #include "extensions/common/extension_messages.h" |
40 #include "extensions/common/extension_set.h" | 42 #include "extensions/common/extension_set.h" |
| 43 #include "extensions/common/extensions_client.h" |
41 #include "ipc/ipc_message.h" | 44 #include "ipc/ipc_message.h" |
42 #include "ipc/ipc_message_macros.h" | 45 #include "ipc/ipc_message_macros.h" |
43 | 46 |
44 using content::BrowserThread; | 47 using content::BrowserThread; |
45 using content::RenderViewHost; | 48 using content::RenderViewHost; |
46 | 49 |
47 namespace extensions { | 50 namespace extensions { |
48 namespace { | 51 namespace { |
49 | 52 |
50 // Notifies the ApiActivityMonitor that an extension API function has been | 53 // Notifies the ApiActivityMonitor that an extension API function has been |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 Static() : api(ExtensionAPI::CreateWithDefaultConfiguration()) {} | 85 Static() : api(ExtensionAPI::CreateWithDefaultConfiguration()) {} |
83 std::unique_ptr<ExtensionAPI> api; | 86 std::unique_ptr<ExtensionAPI> api; |
84 }; | 87 }; |
85 base::LazyInstance<Static> g_global_io_data = LAZY_INSTANCE_INITIALIZER; | 88 base::LazyInstance<Static> g_global_io_data = LAZY_INSTANCE_INITIALIZER; |
86 | 89 |
87 // Kills the specified process because it sends us a malformed message. | 90 // Kills the specified process because it sends us a malformed message. |
88 // Track the specific function's |histogram_value|, as this may indicate a bug | 91 // Track the specific function's |histogram_value|, as this may indicate a bug |
89 // in that API's implementation on the renderer. | 92 // in that API's implementation on the renderer. |
90 void KillBadMessageSender(const base::Process& process, | 93 void KillBadMessageSender(const base::Process& process, |
91 functions::HistogramValue histogram_value) { | 94 functions::HistogramValue histogram_value) { |
| 95 // The renderer has done validation before sending extension api requests. |
| 96 // Therefore, we should never receive a request that is invalid in a way |
| 97 // that JSON validation in the renderer should have caught. It could be an |
| 98 // attacker trying to exploit the browser, so we crash the renderer instead. |
| 99 LOG(ERROR) << "Terminating renderer because of malformed extension message."; |
| 100 if (content::RenderProcessHost::run_renderer_in_process()) { |
| 101 // In single process mode it is better if we don't suicide but just crash. |
| 102 CHECK(false); |
| 103 return; |
| 104 } |
| 105 |
92 NOTREACHED(); | 106 NOTREACHED(); |
93 content::RecordAction(base::UserMetricsAction("BadMessageTerminate_EFD")); | 107 content::RecordAction(base::UserMetricsAction("BadMessageTerminate_EFD")); |
94 UMA_HISTOGRAM_ENUMERATION("Extensions.BadMessageFunctionName", | 108 UMA_HISTOGRAM_ENUMERATION("Extensions.BadMessageFunctionName", |
95 histogram_value, functions::ENUM_BOUNDARY); | 109 histogram_value, functions::ENUM_BOUNDARY); |
96 if (process.IsValid()) | 110 if (process.IsValid()) |
97 process.Terminate(content::RESULT_CODE_KILLED_BAD_MESSAGE, false); | 111 process.Terminate(content::RESULT_CODE_KILLED_BAD_MESSAGE, false); |
98 } | 112 } |
99 | 113 |
| 114 void KillBadMessageSenderRPH(content::RenderProcessHost* sender_process_host, |
| 115 functions::HistogramValue histogram_value) { |
| 116 base::Process peer_process = |
| 117 content::RenderProcessHost::run_renderer_in_process() |
| 118 ? base::Process::Current() |
| 119 : base::Process::DeprecatedGetProcessFromHandle( |
| 120 sender_process_host->GetHandle()); |
| 121 KillBadMessageSender(peer_process, histogram_value); |
| 122 } |
| 123 |
100 void CommonResponseCallback(IPC::Sender* ipc_sender, | 124 void CommonResponseCallback(IPC::Sender* ipc_sender, |
101 int routing_id, | 125 int routing_id, |
102 const base::Process& peer_process, | 126 const base::Process& peer_process, |
103 int request_id, | 127 int request_id, |
104 ExtensionFunction::ResponseType type, | 128 ExtensionFunction::ResponseType type, |
105 const base::ListValue& results, | 129 const base::ListValue& results, |
106 const std::string& error, | 130 const std::string& error, |
107 functions::HistogramValue histogram_value) { | 131 functions::HistogramValue histogram_value) { |
108 DCHECK(ipc_sender); | 132 DCHECK(ipc_sender); |
109 | 133 |
110 if (type == ExtensionFunction::BAD_MESSAGE) { | 134 if (type == ExtensionFunction::BAD_MESSAGE) { |
111 // The renderer has done validation before sending extension api requests. | 135 KillBadMessageSender(peer_process, histogram_value); |
112 // Therefore, we should never receive a request that is invalid in a way | |
113 // that JSON validation in the renderer should have caught. It could be an | |
114 // attacker trying to exploit the browser, so we crash the renderer instead. | |
115 LOG(ERROR) << | |
116 "Terminating renderer because of malformed extension message."; | |
117 if (content::RenderProcessHost::run_renderer_in_process()) { | |
118 // In single process mode it is better if we don't suicide but just crash. | |
119 CHECK(false); | |
120 } else { | |
121 KillBadMessageSender(peer_process, histogram_value); | |
122 } | |
123 return; | 136 return; |
124 } | 137 } |
125 | 138 |
126 ipc_sender->Send(new ExtensionMsg_Response( | 139 ipc_sender->Send(new ExtensionMsg_Response( |
127 routing_id, request_id, type == ExtensionFunction::SUCCEEDED, results, | 140 routing_id, request_id, type == ExtensionFunction::SUCCEEDED, results, |
128 error)); | 141 error)); |
129 } | 142 } |
130 | 143 |
131 void IOThreadResponseCallback( | 144 void IOThreadResponseCallback( |
132 const base::WeakPtr<IOThreadExtensionMessageFilter>& ipc_sender, | 145 const base::WeakPtr<IOThreadExtensionMessageFilter>& ipc_sender, |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 histogram_value); | 214 histogram_value); |
202 } | 215 } |
203 | 216 |
204 base::WeakPtr<ExtensionFunctionDispatcher> dispatcher_; | 217 base::WeakPtr<ExtensionFunctionDispatcher> dispatcher_; |
205 content::RenderFrameHost* render_frame_host_; | 218 content::RenderFrameHost* render_frame_host_; |
206 base::WeakPtrFactory<UIThreadResponseCallbackWrapper> weak_ptr_factory_; | 219 base::WeakPtrFactory<UIThreadResponseCallbackWrapper> weak_ptr_factory_; |
207 | 220 |
208 DISALLOW_COPY_AND_ASSIGN(UIThreadResponseCallbackWrapper); | 221 DISALLOW_COPY_AND_ASSIGN(UIThreadResponseCallbackWrapper); |
209 }; | 222 }; |
210 | 223 |
| 224 class ExtensionFunctionDispatcher::UIThreadWorkerResponseCallbackWrapper |
| 225 : public content::RenderProcessHostObserver { |
| 226 public: |
| 227 UIThreadWorkerResponseCallbackWrapper( |
| 228 const base::WeakPtr<ExtensionFunctionDispatcher>& dispatcher, |
| 229 int render_process_id, |
| 230 int worker_thread_id) |
| 231 : dispatcher_(dispatcher), |
| 232 observer_(this), |
| 233 render_process_id_(render_process_id), |
| 234 worker_thread_id_(worker_thread_id), |
| 235 weak_ptr_factory_(this) { |
| 236 observer_.Add(content::RenderProcessHost::FromID(render_process_id_)); |
| 237 DCHECK(ExtensionsClient::Get() |
| 238 ->ExtensionAPIEnabledInExtensionServiceWorkers()); |
| 239 } |
| 240 |
| 241 ~UIThreadWorkerResponseCallbackWrapper() override {} |
| 242 |
| 243 // content::RenderProcessHostObserver override. |
| 244 void RenderProcessExited(content::RenderProcessHost* rph, |
| 245 base::TerminationStatus status, |
| 246 int exit_code) override { |
| 247 CleanUp(); |
| 248 } |
| 249 |
| 250 // content::RenderProcessHostObserver override. |
| 251 void RenderProcessHostDestroyed(content::RenderProcessHost* rph) override { |
| 252 CleanUp(); |
| 253 } |
| 254 |
| 255 ExtensionFunction::ResponseCallback CreateCallback(int request_id) { |
| 256 return base::Bind( |
| 257 &UIThreadWorkerResponseCallbackWrapper::OnExtensionFunctionCompleted, |
| 258 weak_ptr_factory_.GetWeakPtr(), request_id); |
| 259 } |
| 260 |
| 261 private: |
| 262 void CleanUp() { |
| 263 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 264 if (dispatcher_) |
| 265 dispatcher_->RemoveWorkerCallbacksForProcess(render_process_id_); |
| 266 // Note: we are deleted here! |
| 267 } |
| 268 |
| 269 void OnExtensionFunctionCompleted(int request_id, |
| 270 ExtensionFunction::ResponseType type, |
| 271 const base::ListValue& results, |
| 272 const std::string& error, |
| 273 functions::HistogramValue histogram_value) { |
| 274 content::RenderProcessHost* sender = |
| 275 content::RenderProcessHost::FromID(render_process_id_); |
| 276 if (type == ExtensionFunction::BAD_MESSAGE) { |
| 277 KillBadMessageSenderRPH(sender, histogram_value); |
| 278 return; |
| 279 } |
| 280 DCHECK(sender); |
| 281 sender->Send(new ExtensionMsg_ResponseWorker( |
| 282 worker_thread_id_, request_id, type == ExtensionFunction::SUCCEEDED, |
| 283 results, error)); |
| 284 } |
| 285 |
| 286 base::WeakPtr<ExtensionFunctionDispatcher> dispatcher_; |
| 287 ScopedObserver<content::RenderProcessHost, |
| 288 UIThreadWorkerResponseCallbackWrapper> |
| 289 observer_; |
| 290 const int render_process_id_; |
| 291 const int worker_thread_id_; |
| 292 base::WeakPtrFactory<UIThreadWorkerResponseCallbackWrapper> weak_ptr_factory_; |
| 293 |
| 294 DISALLOW_COPY_AND_ASSIGN(UIThreadWorkerResponseCallbackWrapper); |
| 295 }; |
| 296 |
| 297 struct ExtensionFunctionDispatcher::WorkerResponseCallbackMapKey { |
| 298 WorkerResponseCallbackMapKey(int render_process_id, int embedded_worker_id) |
| 299 : render_process_id(render_process_id), |
| 300 embedded_worker_id(embedded_worker_id) {} |
| 301 |
| 302 bool operator<(const WorkerResponseCallbackMapKey& other) const { |
| 303 return std::tie(render_process_id, embedded_worker_id) < |
| 304 std::tie(other.render_process_id, other.embedded_worker_id); |
| 305 } |
| 306 |
| 307 int render_process_id; |
| 308 int embedded_worker_id; |
| 309 }; |
| 310 |
211 WindowController* | 311 WindowController* |
212 ExtensionFunctionDispatcher::Delegate::GetExtensionWindowController() const { | 312 ExtensionFunctionDispatcher::Delegate::GetExtensionWindowController() const { |
213 return nullptr; | 313 return nullptr; |
214 } | 314 } |
215 | 315 |
216 content::WebContents* | 316 content::WebContents* |
217 ExtensionFunctionDispatcher::Delegate::GetAssociatedWebContents() const { | 317 ExtensionFunctionDispatcher::Delegate::GetAssociatedWebContents() const { |
218 return nullptr; | 318 return nullptr; |
219 } | 319 } |
220 | 320 |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
309 | 409 |
310 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher( | 410 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher( |
311 content::BrowserContext* browser_context) | 411 content::BrowserContext* browser_context) |
312 : browser_context_(browser_context), delegate_(nullptr) {} | 412 : browser_context_(browser_context), delegate_(nullptr) {} |
313 | 413 |
314 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() { | 414 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() { |
315 } | 415 } |
316 | 416 |
317 void ExtensionFunctionDispatcher::Dispatch( | 417 void ExtensionFunctionDispatcher::Dispatch( |
318 const ExtensionHostMsg_Request_Params& params, | 418 const ExtensionHostMsg_Request_Params& params, |
319 content::RenderFrameHost* render_frame_host) { | 419 content::RenderFrameHost* render_frame_host, |
320 UIThreadResponseCallbackWrapperMap::const_iterator | 420 int render_process_id) { |
321 iter = ui_thread_response_callback_wrappers_.find(render_frame_host); | 421 if (render_frame_host) { |
322 UIThreadResponseCallbackWrapper* callback_wrapper = nullptr; | 422 // Extension API from a non Service Worker context, e.g. extension page, |
323 if (iter == ui_thread_response_callback_wrappers_.end()) { | 423 // background page, content script. |
324 callback_wrapper = new UIThreadResponseCallbackWrapper(AsWeakPtr(), | 424 UIThreadResponseCallbackWrapperMap::const_iterator iter = |
325 render_frame_host); | 425 ui_thread_response_callback_wrappers_.find(render_frame_host); |
326 ui_thread_response_callback_wrappers_[render_frame_host] = callback_wrapper; | 426 UIThreadResponseCallbackWrapper* callback_wrapper = nullptr; |
| 427 if (iter == ui_thread_response_callback_wrappers_.end()) { |
| 428 callback_wrapper = |
| 429 new UIThreadResponseCallbackWrapper(AsWeakPtr(), render_frame_host); |
| 430 ui_thread_response_callback_wrappers_[render_frame_host] = |
| 431 callback_wrapper; |
| 432 } else { |
| 433 callback_wrapper = iter->second; |
| 434 } |
| 435 DispatchWithCallbackInternal( |
| 436 params, render_frame_host, render_process_id, |
| 437 callback_wrapper->CreateCallback(params.request_id)); |
327 } else { | 438 } else { |
328 callback_wrapper = iter->second; | 439 // Extension API from Service Worker. |
| 440 DCHECK_GE(params.embedded_worker_id, 0); |
| 441 WorkerResponseCallbackMapKey key(render_process_id, |
| 442 params.embedded_worker_id); |
| 443 UIThreadWorkerResponseCallbackWrapperMap::const_iterator iter = |
| 444 ui_thread_response_callback_wrappers_for_worker_.find(key); |
| 445 UIThreadWorkerResponseCallbackWrapper* callback_wrapper = nullptr; |
| 446 if (iter == ui_thread_response_callback_wrappers_for_worker_.end()) { |
| 447 callback_wrapper = new UIThreadWorkerResponseCallbackWrapper( |
| 448 AsWeakPtr(), render_process_id, params.worker_thread_id); |
| 449 ui_thread_response_callback_wrappers_for_worker_[key] = |
| 450 base::WrapUnique(callback_wrapper); |
| 451 } else { |
| 452 callback_wrapper = iter->second.get(); |
| 453 } |
| 454 DispatchWithCallbackInternal( |
| 455 params, nullptr, render_process_id, |
| 456 callback_wrapper->CreateCallback(params.request_id)); |
329 } | 457 } |
330 | |
331 DispatchWithCallbackInternal( | |
332 params, render_frame_host, | |
333 callback_wrapper->CreateCallback(params.request_id)); | |
334 } | 458 } |
335 | 459 |
336 void ExtensionFunctionDispatcher::DispatchWithCallbackInternal( | 460 void ExtensionFunctionDispatcher::DispatchWithCallbackInternal( |
337 const ExtensionHostMsg_Request_Params& params, | 461 const ExtensionHostMsg_Request_Params& params, |
338 content::RenderFrameHost* render_frame_host, | 462 content::RenderFrameHost* render_frame_host, |
| 463 int render_process_id, |
339 const ExtensionFunction::ResponseCallback& callback) { | 464 const ExtensionFunction::ResponseCallback& callback) { |
340 DCHECK(render_frame_host); | |
341 // TODO(yzshen): There is some shared logic between this method and | 465 // TODO(yzshen): There is some shared logic between this method and |
342 // DispatchOnIOThread(). It is nice to deduplicate. | 466 // DispatchOnIOThread(). It is nice to deduplicate. |
343 ProcessMap* process_map = ProcessMap::Get(browser_context_); | 467 ProcessMap* process_map = ProcessMap::Get(browser_context_); |
344 if (!process_map) | 468 if (!process_map) |
345 return; | 469 return; |
346 | 470 |
347 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_); | 471 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_); |
348 const Extension* extension = | 472 const Extension* extension = |
349 registry->enabled_extensions().GetByID(params.extension_id); | 473 registry->enabled_extensions().GetByID(params.extension_id); |
350 if (!extension) { | 474 if (!extension) { |
351 extension = | 475 extension = |
352 registry->enabled_extensions().GetHostedAppByURL(params.source_url); | 476 registry->enabled_extensions().GetHostedAppByURL(params.source_url); |
353 } | 477 } |
354 | 478 |
355 int process_id = render_frame_host->GetProcess()->GetID(); | 479 if (render_frame_host) |
356 scoped_refptr<ExtensionFunction> function( | 480 DCHECK_EQ(render_process_id, render_frame_host->GetProcess()->GetID()); |
357 CreateExtensionFunction(params, | 481 |
358 extension, | 482 scoped_refptr<ExtensionFunction> function(CreateExtensionFunction( |
359 process_id, | 483 params, extension, render_process_id, *process_map, |
360 *process_map, | 484 ExtensionAPI::GetSharedInstance(), browser_context_, callback)); |
361 ExtensionAPI::GetSharedInstance(), | |
362 browser_context_, | |
363 callback)); | |
364 if (!function.get()) | 485 if (!function.get()) |
365 return; | 486 return; |
366 | 487 |
367 UIThreadExtensionFunction* function_ui = | 488 UIThreadExtensionFunction* function_ui = |
368 function->AsUIThreadExtensionFunction(); | 489 function->AsUIThreadExtensionFunction(); |
369 if (!function_ui) { | 490 if (!function_ui) { |
370 NOTREACHED(); | 491 NOTREACHED(); |
371 return; | 492 return; |
372 } | 493 } |
373 function_ui->SetRenderFrameHost(render_frame_host); | 494 function_ui->SetRenderFrameHost(render_frame_host); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
429 // if function->Run() ended up closing the tab that owns us. | 550 // if function->Run() ended up closing the tab that owns us. |
430 | 551 |
431 // Check if extension was uninstalled by management.uninstall. | 552 // Check if extension was uninstalled by management.uninstall. |
432 if (!registry->enabled_extensions().GetByID(params.extension_id)) | 553 if (!registry->enabled_extensions().GetByID(params.extension_id)) |
433 return; | 554 return; |
434 | 555 |
435 // We only adjust the keepalive count for UIThreadExtensionFunction for | 556 // We only adjust the keepalive count for UIThreadExtensionFunction for |
436 // now, largely for simplicity's sake. This is OK because currently, only | 557 // now, largely for simplicity's sake. This is OK because currently, only |
437 // the webRequest API uses IOThreadExtensionFunction, and that API is not | 558 // the webRequest API uses IOThreadExtensionFunction, and that API is not |
438 // compatible with lazy background pages. | 559 // compatible with lazy background pages. |
| 560 // TODO(lazyboy): API functions from extension Service Worker will incorrectly |
| 561 // change keepalive count below. |
439 process_manager->IncrementLazyKeepaliveCount(extension); | 562 process_manager->IncrementLazyKeepaliveCount(extension); |
440 } | 563 } |
441 | 564 |
| 565 void ExtensionFunctionDispatcher::RemoveWorkerCallbacksForProcess( |
| 566 int render_process_id) { |
| 567 UIThreadWorkerResponseCallbackWrapperMap& map = |
| 568 ui_thread_response_callback_wrappers_for_worker_; |
| 569 for (UIThreadWorkerResponseCallbackWrapperMap::iterator it = map.begin(); |
| 570 it != map.end();) { |
| 571 if (it->first.render_process_id == render_process_id) { |
| 572 it = map.erase(it); |
| 573 continue; |
| 574 } |
| 575 ++it; |
| 576 } |
| 577 } |
| 578 |
442 void ExtensionFunctionDispatcher::OnExtensionFunctionCompleted( | 579 void ExtensionFunctionDispatcher::OnExtensionFunctionCompleted( |
443 const Extension* extension) { | 580 const Extension* extension) { |
| 581 // TODO(lazyboy): API functions from extension Service Worker will incorrectly |
| 582 // change keepalive count below. |
444 if (extension) { | 583 if (extension) { |
445 ProcessManager::Get(browser_context_) | 584 ProcessManager::Get(browser_context_) |
446 ->DecrementLazyKeepaliveCount(extension); | 585 ->DecrementLazyKeepaliveCount(extension); |
447 } | 586 } |
448 } | 587 } |
449 | 588 |
450 WindowController* | 589 WindowController* |
451 ExtensionFunctionDispatcher::GetExtensionWindowController() const { | 590 ExtensionFunctionDispatcher::GetExtensionWindowController() const { |
452 return delegate_ ? delegate_->GetExtensionWindowController() : nullptr; | 591 return delegate_ ? delegate_->GetExtensionWindowController() : nullptr; |
453 } | 592 } |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
512 // static | 651 // static |
513 void ExtensionFunctionDispatcher::SendAccessDenied( | 652 void ExtensionFunctionDispatcher::SendAccessDenied( |
514 const ExtensionFunction::ResponseCallback& callback, | 653 const ExtensionFunction::ResponseCallback& callback, |
515 functions::HistogramValue histogram_value) { | 654 functions::HistogramValue histogram_value) { |
516 base::ListValue empty_list; | 655 base::ListValue empty_list; |
517 callback.Run(ExtensionFunction::FAILED, empty_list, | 656 callback.Run(ExtensionFunction::FAILED, empty_list, |
518 "Access to extension API denied.", histogram_value); | 657 "Access to extension API denied.", histogram_value); |
519 } | 658 } |
520 | 659 |
521 } // namespace extensions | 660 } // namespace extensions |
OLD | NEW |