Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(617)

Unified Diff: content/browser/background_fetch/background_fetch_job_controller.cc

Issue 2781623009: Migrate part of the BackgroundFetchJobController to the UI thread (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 60e3cb0a71da3a4c83647cadb3e50edd7887cd8b..a776163e6cdf35f5f1685feda3a928e2b545778c 100644
--- a/content/browser/background_fetch/background_fetch_job_controller.cc
+++ b/content/browser/background_fetch/background_fetch_job_controller.cc
@@ -15,33 +15,167 @@
#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 {
harkness 2017/03/29 22:31:10 I don't have any objections to this approach, but
Peter Beverloo 2017/03/29 22:37:56 This is what we do with push. It creates a cleaner
+ public:
+ Core(const base::WeakPtr<BackgroundFetchJobController>& io_parent,
+ DownloadManager* download_manager,
+ scoped_refptr<net::URLRequestContextGetter> request_context)
+ : io_parent_(io_parent),
+ download_manager_(download_manager),
+ 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(); }
harkness 2017/03/29 22:31:10 nit: Never called?
Peter Beverloo 2017/03/29 22:37:56 BackgroundFetchJobController::ctor calls it
+
+ // Starts fetching the |request| with the download manager.
+ void StartRequest(const BackgroundFetchRequestInfo& request) {
+ DCHECK(download_manager_);
+ DCHECK(request_context_);
+
+ 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 DownloadManager that Background Fetch dispatches downloads to.
+ // The instance is owned by the profile.
+ DownloadManager* download_manager_;
+
+ // 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,
- DownloadManager* download_manager,
- StoragePartition* storage_partition,
BackgroundFetchDataManager* data_manager,
+ DownloadManager* download_manager,
+ scoped_refptr<net::URLRequestContextGetter> request_context,
CompletedCallback completed_callback)
: registration_id_(registration_id),
options_(options),
- download_manager_(download_manager),
- 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(), download_manager,
+ std::move(request_context)));
harkness 2017/03/29 22:31:10 why not MakeUnique?
Peter Beverloo 2017/03/29 22:37:56 Because our unique_ptr has deletion traits. (Core
- 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);
@@ -53,92 +187,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));
-
- 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.
-
- state_ = State::ABORTED;
+void BackgroundFetchJobController::DidCompleteRequest(
+ const BackgroundFetchRequestInfo& request) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // Inform the owner of the controller about the job having completed.
- std::move(completed_callback_).Run(this);
-}
+ // 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_++;
-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(
@@ -162,11 +236,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

Powered by Google App Engine
This is Rietveld 408576698