| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/prerender/prerender_message_filter.h" |
| |
| #include "base/bind.h" |
| #include "base/macros.h" |
| #include "base/memory/singleton.h" |
| #include "chrome/browser/prerender/prerender_final_status.h" |
| #include "chrome/browser/prerender/prerender_link_manager.h" |
| #include "chrome/browser/prerender/prerender_link_manager_factory.h" |
| #include "chrome/browser/prerender/prerender_manager_factory.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/common/prerender_messages.h" |
| #include "components/keyed_service/content/browser_context_keyed_service_shutdown_notifier_factory.h" |
| |
| using content::BrowserThread; |
| |
| namespace prerender { |
| |
| namespace { |
| |
| class PrerenderMessageFilterShutdownNotifierFactory |
| : public BrowserContextKeyedServiceShutdownNotifierFactory { |
| public: |
| static PrerenderMessageFilterShutdownNotifierFactory* GetInstance() { |
| return base::Singleton< |
| PrerenderMessageFilterShutdownNotifierFactory>::get(); |
| } |
| |
| private: |
| friend struct base::DefaultSingletonTraits< |
| PrerenderMessageFilterShutdownNotifierFactory>; |
| |
| PrerenderMessageFilterShutdownNotifierFactory() |
| : BrowserContextKeyedServiceShutdownNotifierFactory( |
| "PrerenderMessageFilter") { |
| DependsOn(PrerenderLinkManagerFactory::GetInstance()); |
| } |
| ~PrerenderMessageFilterShutdownNotifierFactory() override {} |
| |
| DISALLOW_COPY_AND_ASSIGN(PrerenderMessageFilterShutdownNotifierFactory); |
| }; |
| |
| } // namespace |
| |
| PrerenderMessageFilter::PrerenderMessageFilter(int render_process_id, |
| Profile* profile) |
| : BrowserMessageFilter(PrerenderMsgStart), |
| prerender_manager_( |
| PrerenderManagerFactory::GetForBrowserContext(profile)), |
| render_process_id_(render_process_id), |
| prerender_link_manager_( |
| PrerenderLinkManagerFactory::GetForProfile(profile)) { |
| shutdown_notifier_ = |
| PrerenderMessageFilterShutdownNotifierFactory::GetInstance() |
| ->Get(profile) |
| ->Subscribe(base::Bind(&PrerenderMessageFilter::ShutdownOnUIThread, |
| base::Unretained(this))); |
| } |
| |
| PrerenderMessageFilter::~PrerenderMessageFilter() { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| } |
| |
| // static |
| void PrerenderMessageFilter::EnsureShutdownNotifierFactoryBuilt() { |
| PrerenderMessageFilterShutdownNotifierFactory::GetInstance(); |
| } |
| |
| bool PrerenderMessageFilter::OnMessageReceived(const IPC::Message& message) { |
| bool handled = true; |
| IPC_BEGIN_MESSAGE_MAP(PrerenderMessageFilter, message) |
| IPC_MESSAGE_HANDLER(PrerenderHostMsg_AddLinkRelPrerender, OnAddPrerender) |
| IPC_MESSAGE_HANDLER( |
| PrerenderHostMsg_CancelLinkRelPrerender, OnCancelPrerender) |
| IPC_MESSAGE_HANDLER( |
| PrerenderHostMsg_AbandonLinkRelPrerender, OnAbandonPrerender) |
| IPC_MESSAGE_HANDLER(PrerenderHostMsg_PrefetchFinished, OnPrefetchFinished) |
| IPC_MESSAGE_UNHANDLED(handled = false) |
| IPC_END_MESSAGE_MAP() |
| |
| return handled; |
| } |
| |
| void PrerenderMessageFilter::OverrideThreadForMessage( |
| const IPC::Message& message, content::BrowserThread::ID* thread) { |
| if (message.type() == PrerenderHostMsg_AddLinkRelPrerender::ID || |
| message.type() == PrerenderHostMsg_CancelLinkRelPrerender::ID || |
| message.type() == PrerenderHostMsg_AbandonLinkRelPrerender::ID || |
| message.type() == PrerenderHostMsg_PrefetchFinished::ID) { |
| *thread = BrowserThread::UI; |
| } |
| } |
| |
| void PrerenderMessageFilter::OnChannelClosing() { |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::BindOnce(&PrerenderMessageFilter::OnChannelClosingInUIThread, |
| this)); |
| } |
| |
| void PrerenderMessageFilter::OnDestruct() const { |
| // |shutdown_notifier_| needs to be destroyed on the UI thread. |
| BrowserThread::DeleteOnUIThread::Destruct(this); |
| } |
| |
| void PrerenderMessageFilter::OnAddPrerender( |
| int prerender_id, |
| const PrerenderAttributes& attributes, |
| const content::Referrer& referrer, |
| const gfx::Size& size, |
| int render_view_route_id) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| if (!prerender_link_manager_) |
| return; |
| prerender_link_manager_->OnAddPrerender( |
| render_process_id_, prerender_id, |
| attributes.url, attributes.rel_types, referrer, |
| size, render_view_route_id); |
| } |
| |
| void PrerenderMessageFilter::OnCancelPrerender( |
| int prerender_id) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| if (!prerender_link_manager_) |
| return; |
| prerender_link_manager_->OnCancelPrerender(render_process_id_, prerender_id); |
| } |
| |
| void PrerenderMessageFilter::OnAbandonPrerender( |
| int prerender_id) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| if (!prerender_link_manager_) |
| return; |
| prerender_link_manager_->OnAbandonPrerender(render_process_id_, prerender_id); |
| } |
| |
| void PrerenderMessageFilter::OnPrefetchFinished() { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| DCHECK(prerender_manager_); |
| // Kill the process doing the prefetch. Only one prefetch per renderer is |
| // possible, also prefetches are not shared with other renderer processes. |
| if (prerender_manager_) { |
| PrerenderContents* prerender_contents = |
| prerender_manager_->GetPrerenderContentsForProcess(render_process_id_); |
| if (prerender_contents) |
| prerender_contents->Destroy(FINAL_STATUS_NOSTATE_PREFETCH_FINISHED); |
| } |
| } |
| |
| void PrerenderMessageFilter::ShutdownOnUIThread() { |
| prerender_link_manager_ = nullptr; |
| shutdown_notifier_.reset(); |
| } |
| |
| void PrerenderMessageFilter::OnChannelClosingInUIThread() { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| if (!prerender_link_manager_) |
| return; |
| prerender_link_manager_->OnChannelClosing(render_process_id_); |
| } |
| |
| } // namespace prerender |
| |