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

Side by Side Diff: content/browser/background_fetch/background_fetch_job_controller.cc

Issue 2781623009: Migrate part of the BackgroundFetchJobController to the UI thread (Closed)
Patch Set: Migrate part of the BackgroundFetchJobController to the UI thread Created 3 years, 8 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 unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 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 "content/browser/background_fetch/background_fetch_job_controller.h" 5 #include "content/browser/background_fetch/background_fetch_job_controller.h"
6 6
7 #include <string> 7 #include <string>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/memory/ptr_util.h" 11 #include "base/memory/ptr_util.h"
12 #include "content/browser/background_fetch/background_fetch_constants.h" 12 #include "content/browser/background_fetch/background_fetch_constants.h"
13 #include "content/browser/background_fetch/background_fetch_data_manager.h" 13 #include "content/browser/background_fetch/background_fetch_data_manager.h"
14 #include "content/public/browser/browser_context.h" 14 #include "content/public/browser/browser_context.h"
15 #include "content/public/browser/browser_thread.h" 15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/download_interrupt_reasons.h" 16 #include "content/public/browser/download_interrupt_reasons.h"
17 #include "content/public/browser/download_manager.h" 17 #include "content/public/browser/download_manager.h"
18 #include "content/public/browser/storage_partition.h" 18 #include "net/url_request/url_request_context_getter.h"
19 19
20 namespace content { 20 namespace content {
21 21
22 // Internal functionality of the BackgroundFetchJobController that lives on the
23 // UI thread, where all interaction with the download manager must happen.
24 class BackgroundFetchJobController::Core : public DownloadItem::Observer {
25 public:
26 Core(const base::WeakPtr<BackgroundFetchJobController>& io_parent,
27 BrowserContext* browser_context,
28 scoped_refptr<net::URLRequestContextGetter> request_context)
29 : io_parent_(io_parent),
30 browser_context_(browser_context),
31 request_context_(std::move(request_context)),
32 weak_ptr_factory_(this) {}
33
34 ~Core() final {
35 for (const auto& pair : downloads_)
36 pair.first->RemoveObserver(this);
37 }
38
39 // Returns a weak pointer that can be used to talk to |this|.
40 base::WeakPtr<Core> GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); }
41
42 // Starts fetching the |request| with the download manager.
43 void StartRequest(const BackgroundFetchRequestInfo& request) {
44 DCHECK(request_context_);
45
46 DownloadManager* download_manager =
47 BrowserContext::GetDownloadManager(browser_context_);
48 DCHECK(download_manager);
49
50 std::unique_ptr<DownloadUrlParameters> download_parameters(
51 base::MakeUnique<DownloadUrlParameters>(request.GetURL(),
52 request_context_.get()));
53
54 // TODO(peter): The |download_parameters| should be populated with all the
55 // properties set in the |request|'s ServiceWorkerFetchRequest member.
56
57 download_parameters->set_callback(base::Bind(
58 &Core::DidStartRequest, weak_ptr_factory_.GetWeakPtr(), request));
59
60 download_manager->DownloadUrl(std::move(download_parameters));
61 }
62
63 // DownloadItem::Observer overrides:
64 void OnDownloadUpdated(DownloadItem* item) override {
65 auto iter = downloads_.find(item);
66 DCHECK(iter != downloads_.end());
67
68 const BackgroundFetchRequestInfo& request = iter->second;
69
70 switch (item->GetState()) {
71 case DownloadItem::DownloadState::COMPLETE:
72 // TODO(peter): Populate the responses' information in the |request|.
73
74 item->RemoveObserver(this);
75
76 // Inform the host about |host| having completed.
77 BrowserThread::PostTask(
78 BrowserThread::IO, FROM_HERE,
79 base::Bind(&BackgroundFetchJobController::DidCompleteRequest,
80 io_parent_, request));
81
82 // Clear the local state for the |request|, it no longer is our concern.
83 downloads_.erase(iter);
84 break;
85 case DownloadItem::DownloadState::CANCELLED:
86 // TODO(harkness): Consider how we want to handle cancelled downloads.
87 break;
88 case DownloadItem::DownloadState::INTERRUPTED:
89 // TODO(harkness): Just update the notification that it is paused.
90 break;
91 case DownloadItem::DownloadState::IN_PROGRESS:
92 // TODO(harkness): If the download was previously paused, this should
93 // now unpause the notification.
94 break;
95 case DownloadItem::DownloadState::MAX_DOWNLOAD_STATE:
96 NOTREACHED();
97 break;
98 }
99 }
100
101 void OnDownloadDestroyed(DownloadItem* item) override {
102 DCHECK_EQ(downloads_.count(item), 1u);
103 downloads_.erase(item);
104
105 item->RemoveObserver(this);
106 }
107
108 private:
109 // Called when the download manager has started the given |request|. The
110 // |download_item| continues to be owned by the download system. The
111 // |interrupt_reason| will indicate when a request could not be started.
112 void DidStartRequest(const BackgroundFetchRequestInfo& request,
113 DownloadItem* download_item,
114 DownloadInterruptReason interrupt_reason) {
115 DCHECK_EQ(interrupt_reason, DOWNLOAD_INTERRUPT_REASON_NONE);
116 DCHECK(download_item);
117
118 // TODO(peter): The above two DCHECKs are assumptions our implementation
119 // currently makes, but are not fit for production. We need to handle such
120 // failures gracefully.
121
122 // Register for updates on the download's progress.
123 download_item->AddObserver(this);
124
125 // Inform the host about the |request| having started.
126 BrowserThread::PostTask(
127 BrowserThread::IO, FROM_HERE,
128 base::Bind(&BackgroundFetchJobController::DidStartRequest, io_parent_,
129 request, download_item->GetGuid()));
130
131 // Associate the |download_item| with the |request| so that we can retrieve
132 // it's information when further updates happen.
133 downloads_.insert(std::make_pair(download_item, request));
134 }
135
136 // Weak reference to the BackgroundFetchJobController instance that owns us.
137 base::WeakPtr<BackgroundFetchJobController> io_parent_;
138
139 // The BrowserContext that owns the JobController, and thereby us.
140 BrowserContext* browser_context_;
141
142 // The URL request context to use when issuing the requests.
143 scoped_refptr<net::URLRequestContextGetter> request_context_;
144
145 // Map from DownloadItem* to the request info for the in-progress downloads.
146 std::unordered_map<DownloadItem*, BackgroundFetchRequestInfo> downloads_;
147
148 base::WeakPtrFactory<Core> weak_ptr_factory_;
149
150 DISALLOW_COPY_AND_ASSIGN(Core);
151 };
152
22 BackgroundFetchJobController::BackgroundFetchJobController( 153 BackgroundFetchJobController::BackgroundFetchJobController(
23 const BackgroundFetchRegistrationId& registration_id, 154 const BackgroundFetchRegistrationId& registration_id,
24 const BackgroundFetchOptions& options, 155 const BackgroundFetchOptions& options,
156 BackgroundFetchDataManager* data_manager,
25 BrowserContext* browser_context, 157 BrowserContext* browser_context,
26 StoragePartition* storage_partition, 158 scoped_refptr<net::URLRequestContextGetter> request_context,
27 BackgroundFetchDataManager* data_manager,
28 CompletedCallback completed_callback) 159 CompletedCallback completed_callback)
29 : registration_id_(registration_id), 160 : registration_id_(registration_id),
30 options_(options), 161 options_(options),
31 browser_context_(browser_context),
32 storage_partition_(storage_partition),
33 data_manager_(data_manager), 162 data_manager_(data_manager),
34 completed_callback_(std::move(completed_callback)), 163 completed_callback_(std::move(completed_callback)),
35 weak_ptr_factory_(this) {} 164 weak_ptr_factory_(this) {
165 DCHECK_CURRENTLY_ON(BrowserThread::IO);
36 166
37 BackgroundFetchJobController::~BackgroundFetchJobController() { 167 // Create the core, containing the internal functionality that will have to
38 // TODO(harkness): Write final status to the DataManager. 168 // be run on the UI thread. It will respond to this class with a weak pointer.
169 ui_core_.reset(new Core(weak_ptr_factory_.GetWeakPtr(), browser_context,
170 std::move(request_context)));
39 171
40 for (const auto& pair : downloads_) 172 // Get a WeakPtr over which we can talk to the |ui_core_|.
41 pair.first->RemoveObserver(this); 173 ui_core_ptr_ = ui_core_->GetWeakPtr();
42 } 174 }
43 175
176 BackgroundFetchJobController::~BackgroundFetchJobController() = default;
177
44 void BackgroundFetchJobController::Start( 178 void BackgroundFetchJobController::Start(
45 std::vector<BackgroundFetchRequestInfo> initial_requests) { 179 std::vector<BackgroundFetchRequestInfo> initial_requests) {
180 DCHECK_CURRENTLY_ON(BrowserThread::IO);
46 DCHECK_LE(initial_requests.size(), kMaximumBackgroundFetchParallelRequests); 181 DCHECK_LE(initial_requests.size(), kMaximumBackgroundFetchParallelRequests);
47 DCHECK_EQ(state_, State::INITIALIZED); 182 DCHECK_EQ(state_, State::INITIALIZED);
48 183
49 state_ = State::FETCHING; 184 state_ = State::FETCHING;
50 185
51 for (const BackgroundFetchRequestInfo& request : initial_requests) 186 for (const BackgroundFetchRequestInfo& request : initial_requests)
52 StartRequest(request); 187 StartRequest(request);
53 } 188 }
54 189
55 void BackgroundFetchJobController::StartRequest( 190 void BackgroundFetchJobController::StartRequest(
56 const BackgroundFetchRequestInfo& request) { 191 const BackgroundFetchRequestInfo& request) {
192 DCHECK_CURRENTLY_ON(BrowserThread::IO);
57 DCHECK_EQ(state_, State::FETCHING); 193 DCHECK_EQ(state_, State::FETCHING);
58 194 BrowserThread::PostTask(
59 std::unique_ptr<DownloadUrlParameters> download_parameters( 195 BrowserThread::UI, FROM_HERE,
60 base::MakeUnique<DownloadUrlParameters>( 196 base::Bind(&Core::StartRequest, ui_core_ptr_, request));
61 request.GetURL(), storage_partition_->GetURLRequestContext()));
62
63 // TODO(peter): The |download_parameters| should be populated with all the
64 // properties set in the |request|'s ServiceWorkerFetchRequest member.
65
66 download_parameters->set_callback(
67 base::Bind(&BackgroundFetchJobController::DidStartRequest,
68 weak_ptr_factory_.GetWeakPtr(), request));
69
70 // TODO(peter): Move this call to the UI thread.
71 // See https://codereview.chromium.org/2781623009/
72 DownloadManager* download_manager =
73 BrowserContext::GetDownloadManager(browser_context_);
74 DCHECK(download_manager);
75
76 download_manager->DownloadUrl(std::move(download_parameters));
77 } 197 }
78 198
79 void BackgroundFetchJobController::DidStartRequest( 199 void BackgroundFetchJobController::DidStartRequest(
80 const BackgroundFetchRequestInfo& request, 200 const BackgroundFetchRequestInfo& request,
81 DownloadItem* download_item, 201 const std::string& download_guid) {
82 DownloadInterruptReason interrupt_reason) { 202 DCHECK_CURRENTLY_ON(BrowserThread::IO);
83 DCHECK_EQ(interrupt_reason, DOWNLOAD_INTERRUPT_REASON_NONE); 203 data_manager_->MarkRequestAsStarted(registration_id_, request, download_guid);
84 DCHECK(download_item);
85
86 // Update the |request|'s download GUID in the DataManager.
87 data_manager_->MarkRequestAsStarted(registration_id_, request,
88 download_item->GetGuid());
89
90 // Register for updates on the download's progress.
91 download_item->AddObserver(this);
92
93 // Associate the |download_item| with the |request| so that we can retrieve
94 // it's information when further updates happen.
95 downloads_.insert(std::make_pair(download_item, request));
96 } 204 }
97 205
98 void BackgroundFetchJobController::UpdateUI(const std::string& title) { 206 void BackgroundFetchJobController::DidCompleteRequest(
99 // TODO(harkness): Update the user interface with |title|. 207 const BackgroundFetchRequestInfo& request) {
100 } 208 DCHECK_CURRENTLY_ON(BrowserThread::IO);
101 209
102 void BackgroundFetchJobController::Abort() { 210 // The DataManager must acknowledge that it stored the data and that there are
103 // TODO(harkness): Abort all in-progress downloads. 211 // no more pending requests to avoid marking this job as completed too early.
212 pending_completed_file_acknowledgements_++;
104 213
105 state_ = State::ABORTED; 214 data_manager_->MarkRequestAsCompleteAndGetNextRequest(
106 215 registration_id_, request,
107 // Inform the owner of the controller about the job having completed. 216 base::BindOnce(&BackgroundFetchJobController::DidGetNextRequest,
108 std::move(completed_callback_).Run(this); 217 weak_ptr_factory_.GetWeakPtr()));
109 }
110
111 void BackgroundFetchJobController::OnDownloadUpdated(DownloadItem* item) {
112 auto iter = downloads_.find(item);
113 DCHECK(iter != downloads_.end());
114
115 const BackgroundFetchRequestInfo& request = iter->second;
116
117 switch (item->GetState()) {
118 case DownloadItem::DownloadState::COMPLETE:
119 // TODO(peter): Populate the responses' information in the |request|.
120
121 // Remove the |item| from the list of active downloads. Expect one more
122 // completed file acknowledgement too, to prevent race conditions.
123 pending_completed_file_acknowledgements_++;
124 downloads_.erase(iter);
125
126 item->RemoveObserver(this);
127
128 // Mark the |request| as having completed and fetch the next request from
129 // storage. This may also mean that we've completed the job.
130 data_manager_->MarkRequestAsCompleteAndGetNextRequest(
131 registration_id_, request,
132 base::BindOnce(&BackgroundFetchJobController::DidGetNextRequest,
133 weak_ptr_factory_.GetWeakPtr()));
134 break;
135 case DownloadItem::DownloadState::CANCELLED:
136 // TODO(harkness): Consider how we want to handle cancelled downloads.
137 break;
138 case DownloadItem::DownloadState::INTERRUPTED:
139 // TODO(harkness): Just update the notification that it is paused.
140 break;
141 case DownloadItem::DownloadState::IN_PROGRESS:
142 // TODO(harkness): If the download was previously paused, this should now
143 // unpause the notification.
144 break;
145 case DownloadItem::DownloadState::MAX_DOWNLOAD_STATE:
146 NOTREACHED();
147 break;
148 }
149 } 218 }
150 219
151 void BackgroundFetchJobController::DidGetNextRequest( 220 void BackgroundFetchJobController::DidGetNextRequest(
152 const base::Optional<BackgroundFetchRequestInfo>& request) { 221 const base::Optional<BackgroundFetchRequestInfo>& request) {
153 DCHECK_LE(pending_completed_file_acknowledgements_, 1); 222 DCHECK_LE(pending_completed_file_acknowledgements_, 1);
154 pending_completed_file_acknowledgements_--; 223 pending_completed_file_acknowledgements_--;
155 224
156 // If a |request| has been given, start downloading the file and bail. 225 // If a |request| has been given, start downloading the file and bail.
157 if (request) { 226 if (request) {
158 StartRequest(request.value()); 227 StartRequest(request.value());
159 return; 228 return;
160 } 229 }
161 230
162 // If there are outstanding completed file acknowlegements, bail as well. 231 // If there are outstanding completed file acknowlegements, bail as well.
163 if (pending_completed_file_acknowledgements_ > 0) 232 if (pending_completed_file_acknowledgements_ > 0)
164 return; 233 return;
165 234
166 state_ = State::COMPLETED; 235 state_ = State::COMPLETED;
167 236
168 // Otherwise the job this controller is responsible for has completed. 237 // Otherwise the job this controller is responsible for has completed.
169 std::move(completed_callback_).Run(this); 238 std::move(completed_callback_).Run(this);
170 } 239 }
171 240
172 void BackgroundFetchJobController::OnDownloadDestroyed(DownloadItem* item) { 241 void BackgroundFetchJobController::UpdateUI(const std::string& title) {
173 DCHECK_EQ(downloads_.count(item), 1u); 242 DCHECK_CURRENTLY_ON(BrowserThread::IO);
174 downloads_.erase(item);
175 243
176 item->RemoveObserver(this); 244 // TODO(harkness): Update the user interface with |title|.
245 }
246
247 void BackgroundFetchJobController::Abort() {
248 DCHECK_CURRENTLY_ON(BrowserThread::IO);
249
250 // TODO(harkness): Abort all in-progress downloads.
251
252 state_ = State::ABORTED;
253
254 // Inform the owner of the controller about the job having completed.
255 std::move(completed_callback_).Run(this);
177 } 256 }
178 257
179 } // namespace content 258 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698