| // Copyright 2017 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 "content/browser/frame_host/keep_alive_handle_factory.h" | 
 |  | 
 | #include "base/bind.h" | 
 | #include "base/metrics/field_trial.h" | 
 | #include "base/metrics/field_trial_params.h" | 
 | #include "base/task/post_task.h" | 
 | #include "content/public/browser/browser_task_traits.h" | 
 | #include "content/public/browser/browser_thread.h" | 
 | #include "content/public/browser/render_process_host.h" | 
 | #include "content/public/common/content_features.h" | 
 | #include "mojo/public/cpp/bindings/interface_request.h" | 
 | #include "mojo/public/cpp/bindings/strong_binding_set.h" | 
 |  | 
 | namespace content { | 
 |  | 
 | class KeepAliveHandleFactory::Context final : public base::RefCounted<Context> { | 
 |  public: | 
 |   explicit Context(int process_id) | 
 |       : process_id_(process_id), weak_ptr_factory_(this) { | 
 |     RenderProcessHost* process_host = RenderProcessHost::FromID(process_id_); | 
 |     if (!process_host || process_host->IsKeepAliveRefCountDisabled()) | 
 |       return; | 
 |     process_host->IncrementKeepAliveRefCount( | 
 |         RenderProcessHost::KeepAliveClientType::kFetch); | 
 |   } | 
 |  | 
 |   void Detach() { | 
 |     if (detached_) | 
 |       return; | 
 |     detached_ = true; | 
 |     RenderProcessHost* process_host = RenderProcessHost::FromID(process_id_); | 
 |     if (!process_host || process_host->IsKeepAliveRefCountDisabled()) | 
 |       return; | 
 |  | 
 |     process_host->DecrementKeepAliveRefCount( | 
 |         RenderProcessHost::KeepAliveClientType::kFetch); | 
 |   } | 
 |  | 
 |   void DetachLater(base::TimeDelta timeout) { | 
 |     DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |     base::PostDelayedTaskWithTraits( | 
 |         FROM_HERE, {BrowserThread::UI}, | 
 |         base::BindOnce(&Context::Detach, AsWeakPtr()), timeout); | 
 |   } | 
 |  | 
 |   void AddBinding(std::unique_ptr<mojom::KeepAliveHandle> impl, | 
 |                   mojom::KeepAliveHandleRequest request) { | 
 |     binding_set_.AddBinding(std::move(impl), std::move(request)); | 
 |   } | 
 |  | 
 |   base::WeakPtr<Context> AsWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } | 
 |  | 
 |  private: | 
 |   friend class base::RefCounted<Context>; | 
 |   ~Context() { Detach(); } | 
 |  | 
 |   mojo::StrongBindingSet<mojom::KeepAliveHandle> binding_set_; | 
 |   const int process_id_; | 
 |   bool detached_ = false; | 
 |  | 
 |   base::WeakPtrFactory<Context> weak_ptr_factory_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(Context); | 
 | }; | 
 |  | 
 | class KeepAliveHandleFactory::KeepAliveHandleImpl final | 
 |     : public mojom::KeepAliveHandle { | 
 |  public: | 
 |   explicit KeepAliveHandleImpl(scoped_refptr<Context> context) | 
 |       : context_(std::move(context)) {} | 
 |   ~KeepAliveHandleImpl() override {} | 
 |  | 
 |  private: | 
 |   scoped_refptr<Context> context_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(KeepAliveHandleImpl); | 
 | }; | 
 |  | 
 | KeepAliveHandleFactory::KeepAliveHandleFactory(RenderProcessHost* process_host) | 
 |     : process_id_(process_host->GetID()) {} | 
 |  | 
 | KeepAliveHandleFactory::~KeepAliveHandleFactory() { | 
 |   if (context_) | 
 |     context_->DetachLater(timeout_); | 
 | } | 
 |  | 
 | void KeepAliveHandleFactory::Create(mojom::KeepAliveHandleRequest request) { | 
 |   scoped_refptr<Context> context; | 
 |   if (context_) { | 
 |     context = context_.get(); | 
 |   } else { | 
 |     context = base::MakeRefCounted<Context>(process_id_); | 
 |     context_ = context->AsWeakPtr(); | 
 |   } | 
 |  | 
 |   context->AddBinding(std::make_unique<KeepAliveHandleImpl>(context), | 
 |                       std::move(request)); | 
 | } | 
 |  | 
 | void KeepAliveHandleFactory::SetTimeout(base::TimeDelta timeout) { | 
 |   timeout_ = timeout; | 
 | } | 
 |  | 
 | }  // namespace content |