| Index: content/browser/background_fetch/background_fetch_job_controller.cc
|
| diff --git a/content/browser/background_fetch/background_fetch_job_controller.cc b/content/browser/background_fetch/background_fetch_job_controller.cc
|
| index 3ad2822493b6dfd853be94c14c40d22fc275baec..284ecd65d719370ad6780356e9adbae60e9f81e0 100644
|
| --- a/content/browser/background_fetch/background_fetch_job_controller.cc
|
| +++ b/content/browser/background_fetch/background_fetch_job_controller.cc
|
| @@ -15,34 +15,169 @@
|
| #include "content/public/browser/browser_thread.h"
|
| #include "content/public/browser/download_interrupt_reasons.h"
|
| #include "content/public/browser/download_manager.h"
|
| -#include "content/public/browser/storage_partition.h"
|
| +#include "net/url_request/url_request_context_getter.h"
|
|
|
| namespace content {
|
|
|
| +// Internal functionality of the BackgroundFetchJobController that lives on the
|
| +// UI thread, where all interaction with the download manager must happen.
|
| +class BackgroundFetchJobController::Core : public DownloadItem::Observer {
|
| + public:
|
| + Core(const base::WeakPtr<BackgroundFetchJobController>& io_parent,
|
| + BrowserContext* browser_context,
|
| + scoped_refptr<net::URLRequestContextGetter> request_context)
|
| + : io_parent_(io_parent),
|
| + browser_context_(browser_context),
|
| + request_context_(std::move(request_context)),
|
| + weak_ptr_factory_(this) {}
|
| +
|
| + ~Core() final {
|
| + for (const auto& pair : downloads_)
|
| + pair.first->RemoveObserver(this);
|
| + }
|
| +
|
| + // Returns a weak pointer that can be used to talk to |this|.
|
| + base::WeakPtr<Core> GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); }
|
| +
|
| + // Starts fetching the |request| with the download manager.
|
| + void StartRequest(const BackgroundFetchRequestInfo& request) {
|
| + DCHECK(request_context_);
|
| +
|
| + DownloadManager* download_manager =
|
| + BrowserContext::GetDownloadManager(browser_context_);
|
| + DCHECK(download_manager);
|
| +
|
| + std::unique_ptr<DownloadUrlParameters> download_parameters(
|
| + base::MakeUnique<DownloadUrlParameters>(request.GetURL(),
|
| + request_context_.get()));
|
| +
|
| + // TODO(peter): The |download_parameters| should be populated with all the
|
| + // properties set in the |request|'s ServiceWorkerFetchRequest member.
|
| +
|
| + download_parameters->set_callback(base::Bind(
|
| + &Core::DidStartRequest, weak_ptr_factory_.GetWeakPtr(), request));
|
| +
|
| + download_manager->DownloadUrl(std::move(download_parameters));
|
| + }
|
| +
|
| + // DownloadItem::Observer overrides:
|
| + void OnDownloadUpdated(DownloadItem* item) override {
|
| + auto iter = downloads_.find(item);
|
| + DCHECK(iter != downloads_.end());
|
| +
|
| + const BackgroundFetchRequestInfo& request = iter->second;
|
| +
|
| + switch (item->GetState()) {
|
| + case DownloadItem::DownloadState::COMPLETE:
|
| + // TODO(peter): Populate the responses' information in the |request|.
|
| +
|
| + item->RemoveObserver(this);
|
| +
|
| + // Inform the host about |host| having completed.
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&BackgroundFetchJobController::DidCompleteRequest,
|
| + io_parent_, request));
|
| +
|
| + // Clear the local state for the |request|, it no longer is our concern.
|
| + downloads_.erase(iter);
|
| + break;
|
| + case DownloadItem::DownloadState::CANCELLED:
|
| + // TODO(harkness): Consider how we want to handle cancelled downloads.
|
| + break;
|
| + case DownloadItem::DownloadState::INTERRUPTED:
|
| + // TODO(harkness): Just update the notification that it is paused.
|
| + break;
|
| + case DownloadItem::DownloadState::IN_PROGRESS:
|
| + // TODO(harkness): If the download was previously paused, this should
|
| + // now unpause the notification.
|
| + break;
|
| + case DownloadItem::DownloadState::MAX_DOWNLOAD_STATE:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| + }
|
| +
|
| + void OnDownloadDestroyed(DownloadItem* item) override {
|
| + DCHECK_EQ(downloads_.count(item), 1u);
|
| + downloads_.erase(item);
|
| +
|
| + item->RemoveObserver(this);
|
| + }
|
| +
|
| + private:
|
| + // Called when the download manager has started the given |request|. The
|
| + // |download_item| continues to be owned by the download system. The
|
| + // |interrupt_reason| will indicate when a request could not be started.
|
| + void DidStartRequest(const BackgroundFetchRequestInfo& request,
|
| + DownloadItem* download_item,
|
| + DownloadInterruptReason interrupt_reason) {
|
| + DCHECK_EQ(interrupt_reason, DOWNLOAD_INTERRUPT_REASON_NONE);
|
| + DCHECK(download_item);
|
| +
|
| + // TODO(peter): The above two DCHECKs are assumptions our implementation
|
| + // currently makes, but are not fit for production. We need to handle such
|
| + // failures gracefully.
|
| +
|
| + // Register for updates on the download's progress.
|
| + download_item->AddObserver(this);
|
| +
|
| + // Inform the host about the |request| having started.
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&BackgroundFetchJobController::DidStartRequest, io_parent_,
|
| + request, download_item->GetGuid()));
|
| +
|
| + // Associate the |download_item| with the |request| so that we can retrieve
|
| + // it's information when further updates happen.
|
| + downloads_.insert(std::make_pair(download_item, request));
|
| + }
|
| +
|
| + // Weak reference to the BackgroundFetchJobController instance that owns us.
|
| + base::WeakPtr<BackgroundFetchJobController> io_parent_;
|
| +
|
| + // The BrowserContext that owns the JobController, and thereby us.
|
| + BrowserContext* browser_context_;
|
| +
|
| + // The URL request context to use when issuing the requests.
|
| + scoped_refptr<net::URLRequestContextGetter> request_context_;
|
| +
|
| + // Map from DownloadItem* to the request info for the in-progress downloads.
|
| + std::unordered_map<DownloadItem*, BackgroundFetchRequestInfo> downloads_;
|
| +
|
| + base::WeakPtrFactory<Core> weak_ptr_factory_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(Core);
|
| +};
|
| +
|
| BackgroundFetchJobController::BackgroundFetchJobController(
|
| const BackgroundFetchRegistrationId& registration_id,
|
| const BackgroundFetchOptions& options,
|
| - BrowserContext* browser_context,
|
| - StoragePartition* storage_partition,
|
| BackgroundFetchDataManager* data_manager,
|
| + BrowserContext* browser_context,
|
| + scoped_refptr<net::URLRequestContextGetter> request_context,
|
| CompletedCallback completed_callback)
|
| : registration_id_(registration_id),
|
| options_(options),
|
| - browser_context_(browser_context),
|
| - storage_partition_(storage_partition),
|
| data_manager_(data_manager),
|
| completed_callback_(std::move(completed_callback)),
|
| - weak_ptr_factory_(this) {}
|
| + weak_ptr_factory_(this) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
| -BackgroundFetchJobController::~BackgroundFetchJobController() {
|
| - // TODO(harkness): Write final status to the DataManager.
|
| + // Create the core, containing the internal functionality that will have to
|
| + // be run on the UI thread. It will respond to this class with a weak pointer.
|
| + ui_core_.reset(new Core(weak_ptr_factory_.GetWeakPtr(), browser_context,
|
| + std::move(request_context)));
|
|
|
| - for (const auto& pair : downloads_)
|
| - pair.first->RemoveObserver(this);
|
| + // Get a WeakPtr over which we can talk to the |ui_core_|.
|
| + ui_core_ptr_ = ui_core_->GetWeakPtr();
|
| }
|
|
|
| +BackgroundFetchJobController::~BackgroundFetchJobController() = default;
|
| +
|
| void BackgroundFetchJobController::Start(
|
| std::vector<BackgroundFetchRequestInfo> initial_requests) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| DCHECK_LE(initial_requests.size(), kMaximumBackgroundFetchParallelRequests);
|
| DCHECK_EQ(state_, State::INITIALIZED);
|
|
|
| @@ -54,98 +189,32 @@ void BackgroundFetchJobController::Start(
|
|
|
| void BackgroundFetchJobController::StartRequest(
|
| const BackgroundFetchRequestInfo& request) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| DCHECK_EQ(state_, State::FETCHING);
|
| -
|
| - std::unique_ptr<DownloadUrlParameters> download_parameters(
|
| - base::MakeUnique<DownloadUrlParameters>(
|
| - request.GetURL(), storage_partition_->GetURLRequestContext()));
|
| -
|
| - // TODO(peter): The |download_parameters| should be populated with all the
|
| - // properties set in the |request|'s ServiceWorkerFetchRequest member.
|
| -
|
| - download_parameters->set_callback(
|
| - base::Bind(&BackgroundFetchJobController::DidStartRequest,
|
| - weak_ptr_factory_.GetWeakPtr(), request));
|
| -
|
| - // TODO(peter): Move this call to the UI thread.
|
| - // See https://codereview.chromium.org/2781623009/
|
| - DownloadManager* download_manager =
|
| - BrowserContext::GetDownloadManager(browser_context_);
|
| - DCHECK(download_manager);
|
| -
|
| - download_manager->DownloadUrl(std::move(download_parameters));
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&Core::StartRequest, ui_core_ptr_, request));
|
| }
|
|
|
| void BackgroundFetchJobController::DidStartRequest(
|
| const BackgroundFetchRequestInfo& request,
|
| - DownloadItem* download_item,
|
| - DownloadInterruptReason interrupt_reason) {
|
| - DCHECK_EQ(interrupt_reason, DOWNLOAD_INTERRUPT_REASON_NONE);
|
| - DCHECK(download_item);
|
| -
|
| - // Update the |request|'s download GUID in the DataManager.
|
| - data_manager_->MarkRequestAsStarted(registration_id_, request,
|
| - download_item->GetGuid());
|
| -
|
| - // Register for updates on the download's progress.
|
| - download_item->AddObserver(this);
|
| -
|
| - // Associate the |download_item| with the |request| so that we can retrieve
|
| - // it's information when further updates happen.
|
| - downloads_.insert(std::make_pair(download_item, request));
|
| -}
|
| -
|
| -void BackgroundFetchJobController::UpdateUI(const std::string& title) {
|
| - // TODO(harkness): Update the user interface with |title|.
|
| + const std::string& download_guid) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + data_manager_->MarkRequestAsStarted(registration_id_, request, download_guid);
|
| }
|
|
|
| -void BackgroundFetchJobController::Abort() {
|
| - // TODO(harkness): Abort all in-progress downloads.
|
| +void BackgroundFetchJobController::DidCompleteRequest(
|
| + const BackgroundFetchRequestInfo& request) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
| - state_ = State::ABORTED;
|
| + // The DataManager must acknowledge that it stored the data and that there are
|
| + // no more pending requests to avoid marking this job as completed too early.
|
| + pending_completed_file_acknowledgements_++;
|
|
|
| - // Inform the owner of the controller about the job having completed.
|
| - std::move(completed_callback_).Run(this);
|
| -}
|
| -
|
| -void BackgroundFetchJobController::OnDownloadUpdated(DownloadItem* item) {
|
| - auto iter = downloads_.find(item);
|
| - DCHECK(iter != downloads_.end());
|
| -
|
| - const BackgroundFetchRequestInfo& request = iter->second;
|
| -
|
| - switch (item->GetState()) {
|
| - case DownloadItem::DownloadState::COMPLETE:
|
| - // TODO(peter): Populate the responses' information in the |request|.
|
| -
|
| - // Remove the |item| from the list of active downloads. Expect one more
|
| - // completed file acknowledgement too, to prevent race conditions.
|
| - pending_completed_file_acknowledgements_++;
|
| - downloads_.erase(iter);
|
| -
|
| - item->RemoveObserver(this);
|
| -
|
| - // Mark the |request| as having completed and fetch the next request from
|
| - // storage. This may also mean that we've completed the job.
|
| - data_manager_->MarkRequestAsCompleteAndGetNextRequest(
|
| - registration_id_, request,
|
| - base::BindOnce(&BackgroundFetchJobController::DidGetNextRequest,
|
| - weak_ptr_factory_.GetWeakPtr()));
|
| - break;
|
| - case DownloadItem::DownloadState::CANCELLED:
|
| - // TODO(harkness): Consider how we want to handle cancelled downloads.
|
| - break;
|
| - case DownloadItem::DownloadState::INTERRUPTED:
|
| - // TODO(harkness): Just update the notification that it is paused.
|
| - break;
|
| - case DownloadItem::DownloadState::IN_PROGRESS:
|
| - // TODO(harkness): If the download was previously paused, this should now
|
| - // unpause the notification.
|
| - break;
|
| - case DownloadItem::DownloadState::MAX_DOWNLOAD_STATE:
|
| - NOTREACHED();
|
| - break;
|
| - }
|
| + data_manager_->MarkRequestAsCompleteAndGetNextRequest(
|
| + registration_id_, request,
|
| + base::BindOnce(&BackgroundFetchJobController::DidGetNextRequest,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| }
|
|
|
| void BackgroundFetchJobController::DidGetNextRequest(
|
| @@ -169,11 +238,21 @@ void BackgroundFetchJobController::DidGetNextRequest(
|
| std::move(completed_callback_).Run(this);
|
| }
|
|
|
| -void BackgroundFetchJobController::OnDownloadDestroyed(DownloadItem* item) {
|
| - DCHECK_EQ(downloads_.count(item), 1u);
|
| - downloads_.erase(item);
|
| +void BackgroundFetchJobController::UpdateUI(const std::string& title) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + // TODO(harkness): Update the user interface with |title|.
|
| +}
|
| +
|
| +void BackgroundFetchJobController::Abort() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + // TODO(harkness): Abort all in-progress downloads.
|
|
|
| - item->RemoveObserver(this);
|
| + state_ = State::ABORTED;
|
| +
|
| + // Inform the owner of the controller about the job having completed.
|
| + std::move(completed_callback_).Run(this);
|
| }
|
|
|
| } // namespace content
|
|
|