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

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

Powered by Google App Engine
This is Rietveld 408576698