| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "components/offline_pages/background/request_coordinator.h" | 5 #include "components/offline_pages/background/request_coordinator.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/metrics/histogram_macros.h" | 12 #include "base/metrics/histogram_macros.h" |
| 13 #include "base/rand_util.h" | 13 #include "base/rand_util.h" |
| 14 #include "base/time/time.h" | 14 #include "base/time/time.h" |
| 15 #include "components/offline_pages/background/offliner_factory.h" | 15 #include "components/offline_pages/background/offliner_factory.h" |
| 16 #include "components/offline_pages/background/offliner_policy.h" | 16 #include "components/offline_pages/background/offliner_policy.h" |
| 17 #include "components/offline_pages/background/request_picker.h" | 17 #include "components/offline_pages/background/request_picker.h" |
| 18 #include "components/offline_pages/background/save_page_request.h" | 18 #include "components/offline_pages/background/save_page_request.h" |
| 19 #include "components/offline_pages/offline_page_item.h" | 19 #include "components/offline_pages/offline_page_item.h" |
| 20 #include "components/offline_pages/offline_page_model.h" | 20 #include "components/offline_pages/offline_page_model.h" |
| 21 | 21 |
| 22 namespace offline_pages { | 22 namespace offline_pages { |
| 23 | 23 |
| 24 namespace { | 24 namespace { |
| 25 const bool kUserRequest = true; |
| 25 | 26 |
| 26 // Records the final request status UMA for an offlining request. This should | 27 // Records the final request status UMA for an offlining request. This should |
| 27 // only be called once per Offliner::LoadAndSave request. | 28 // only be called once per Offliner::LoadAndSave request. |
| 28 void RecordOfflinerResultUMA(const ClientId& client_id, | 29 void RecordOfflinerResultUMA(const ClientId& client_id, |
| 29 Offliner::RequestStatus request_status) { | 30 Offliner::RequestStatus request_status) { |
| 30 // TODO(dougarnett): Consider exposing AddHistogramSuffix from | 31 // TODO(dougarnett): Consider exposing AddHistogramSuffix from |
| 31 // offline_page_model_impl.cc as visible utility method. | 32 // offline_page_model_impl.cc as visible utility method. |
| 32 std::string histogram_name("OfflinePages.Background.OfflinerRequestStatus"); | 33 std::string histogram_name("OfflinePages.Background.OfflinerRequestStatus"); |
| 33 if (!client_id.name_space.empty()) { | 34 if (!client_id.name_space.empty()) { |
| 34 histogram_name += "." + client_id.name_space; | 35 histogram_name += "." + client_id.name_space; |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED; | 129 Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED; |
| 129 | 130 |
| 130 if (active_request_) { | 131 if (active_request_) { |
| 131 RecordOfflinerResultUMA(active_request_->client_id(), | 132 RecordOfflinerResultUMA(active_request_->client_id(), |
| 132 last_offlining_status_); | 133 last_offlining_status_); |
| 133 active_request_.reset(); | 134 active_request_.reset(); |
| 134 } | 135 } |
| 135 | 136 |
| 136 } | 137 } |
| 137 | 138 |
| 139 void RequestCoordinator::GetRequestsForSchedulingCallback( |
| 140 RequestQueue::GetRequestsResult result, |
| 141 const std::vector<SavePageRequest>& requests) { |
| 142 bool user_requested = false; |
| 143 |
| 144 // Examine all requests, if we find a user requested one, we will use the less |
| 145 // restrictive conditions for user_requested requests. Otherwise we will use |
| 146 // the more restrictive non-user-requested conditions. |
| 147 for (const SavePageRequest& request : requests) { |
| 148 if (request.user_requested()) { |
| 149 user_requested = true; |
| 150 break; |
| 151 } |
| 152 } |
| 153 |
| 154 // In the get callback, determine the least restrictive, and call |
| 155 // GetTriggerConditions based on that. |
| 156 scheduler_->Schedule(GetTriggerConditions(user_requested)); |
| 157 } |
| 158 |
| 138 bool RequestCoordinator::CancelActiveRequestIfItMatches( | 159 bool RequestCoordinator::CancelActiveRequestIfItMatches( |
| 139 const std::vector<int64_t>& request_ids) { | 160 const std::vector<int64_t>& request_ids) { |
| 140 // If we have a request in progress and need to cancel it, call the | 161 // If we have a request in progress and need to cancel it, call the |
| 141 // pre-renderer to cancel. TODO Make sure we remove any page created by the | 162 // pre-renderer to cancel. TODO Make sure we remove any page created by the |
| 142 // prerenderer if it doesn't get the cancel in time. | 163 // prerenderer if it doesn't get the cancel in time. |
| 143 if (active_request_ != nullptr) { | 164 if (active_request_ != nullptr) { |
| 144 if (request_ids.end() != std::find(request_ids.begin(), request_ids.end(), | 165 if (request_ids.end() != std::find(request_ids.begin(), request_ids.end(), |
| 145 active_request_->request_id())) { | 166 active_request_->request_id())) { |
| 146 StopPrerendering(); | 167 StopPrerendering(); |
| 147 return true; | 168 return true; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 174 if (canceled) | 195 if (canceled) |
| 175 TryNextRequest(); | 196 TryNextRequest(); |
| 176 } | 197 } |
| 177 | 198 |
| 178 void RequestCoordinator::ResumeRequests( | 199 void RequestCoordinator::ResumeRequests( |
| 179 const std::vector<int64_t>& request_ids) { | 200 const std::vector<int64_t>& request_ids) { |
| 180 queue_->ChangeRequestsState( | 201 queue_->ChangeRequestsState( |
| 181 request_ids, SavePageRequest::RequestState::AVAILABLE, | 202 request_ids, SavePageRequest::RequestState::AVAILABLE, |
| 182 base::Bind(&RequestCoordinator::UpdateMultipleRequestsCallback, | 203 base::Bind(&RequestCoordinator::UpdateMultipleRequestsCallback, |
| 183 weak_ptr_factory_.GetWeakPtr())); | 204 weak_ptr_factory_.GetWeakPtr())); |
| 184 // TODO: Should we also schedule a task, in case there is not one scheduled? | 205 // Schedule a task, in case there is not one scheduled. |
| 206 ScheduleAsNeeded(); |
| 185 } | 207 } |
| 186 | 208 |
| 187 void RequestCoordinator::AddRequestResultCallback( | 209 void RequestCoordinator::AddRequestResultCallback( |
| 188 RequestQueue::AddRequestResult result, | 210 RequestQueue::AddRequestResult result, |
| 189 const SavePageRequest& request) { | 211 const SavePageRequest& request) { |
| 190 // Inform the scheduler that we have an outstanding task.. | 212 // Inform the scheduler that we have an outstanding task.. |
| 191 scheduler_->Schedule(GetTriggerConditionsForUserRequest()); | 213 ScheduleAsNeeded(); |
| 192 } | 214 } |
| 193 | 215 |
| 194 // Called in response to updating a request in the request queue. | 216 // Called in response to updating a request in the request queue. |
| 195 void RequestCoordinator::UpdateRequestCallback( | 217 void RequestCoordinator::UpdateRequestCallback( |
| 196 const ClientId& client_id, | 218 const ClientId& client_id, |
| 197 RequestQueue::UpdateRequestResult result) { | 219 RequestQueue::UpdateRequestResult result) { |
| 198 // If the request succeeded, nothing to do. If it failed, we can't really do | 220 // If the request succeeded, nothing to do. If it failed, we can't really do |
| 199 // much, so just log it. | 221 // much, so just log it. |
| 200 if (result != RequestQueue::UpdateRequestResult::SUCCESS) { | 222 if (result != RequestQueue::UpdateRequestResult::SUCCESS) { |
| 201 DVLOG(1) << "Failed to update request attempt details. " | 223 DVLOG(1) << "Failed to update request attempt details. " |
| (...skipping 18 matching lines...) Expand all Loading... |
| 220 HandleRemovedRequests(results, requests); | 242 HandleRemovedRequests(results, requests); |
| 221 } | 243 } |
| 222 | 244 |
| 223 void RequestCoordinator::HandleRemovedRequests( | 245 void RequestCoordinator::HandleRemovedRequests( |
| 224 const RequestQueue::UpdateMultipleRequestResults& results, | 246 const RequestQueue::UpdateMultipleRequestResults& results, |
| 225 const std::vector<SavePageRequest>& requests) { | 247 const std::vector<SavePageRequest>& requests) { |
| 226 for (SavePageRequest request : requests) | 248 for (SavePageRequest request : requests) |
| 227 NotifyCompleted(request, SavePageStatus::REMOVED); | 249 NotifyCompleted(request, SavePageStatus::REMOVED); |
| 228 } | 250 } |
| 229 | 251 |
| 252 void RequestCoordinator::ScheduleAsNeeded() { |
| 253 // Get all requests from queue (there is no filtering mechanism). |
| 254 queue_->GetRequests( |
| 255 base::Bind(&RequestCoordinator::GetRequestsForSchedulingCallback, |
| 256 weak_ptr_factory_.GetWeakPtr())); |
| 257 } |
| 258 |
| 230 void RequestCoordinator::StopProcessing() { | 259 void RequestCoordinator::StopProcessing() { |
| 231 is_stopped_ = true; | 260 is_stopped_ = true; |
| 232 StopPrerendering(); | 261 StopPrerendering(); |
| 233 | 262 |
| 234 // Let the scheduler know we are done processing. | 263 // Let the scheduler know we are done processing. |
| 235 scheduler_callback_.Run(true); | 264 scheduler_callback_.Run(true); |
| 236 } | 265 } |
| 237 | 266 |
| 238 // Returns true if the caller should expect a callback, false otherwise. For | 267 // Returns true if the caller should expect a callback, false otherwise. For |
| 239 // instance, this would return false if a request is already in progress. | 268 // instance, this would return false if a request is already in progress. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 264 base::TimeDelta::FromSeconds( | 293 base::TimeDelta::FromSeconds( |
| 265 policy_->GetBackgroundProcessingTimeBudgetSeconds())) { | 294 policy_->GetBackgroundProcessingTimeBudgetSeconds())) { |
| 266 // Let the scheduler know we are done processing. | 295 // Let the scheduler know we are done processing. |
| 267 scheduler_callback_.Run(true); | 296 scheduler_callback_.Run(true); |
| 268 | 297 |
| 269 return; | 298 return; |
| 270 } | 299 } |
| 271 | 300 |
| 272 // Choose a request to process that meets the available conditions. | 301 // Choose a request to process that meets the available conditions. |
| 273 // This is an async call, and returns right away. | 302 // This is an async call, and returns right away. |
| 274 picker_->ChooseNextRequest( | 303 picker_->ChooseNextRequest(base::Bind(&RequestCoordinator::RequestPicked, |
| 275 base::Bind(&RequestCoordinator::RequestPicked, | 304 weak_ptr_factory_.GetWeakPtr()), |
| 276 weak_ptr_factory_.GetWeakPtr()), | 305 base::Bind(&RequestCoordinator::RequestNotPicked, |
| 277 base::Bind(&RequestCoordinator::RequestQueueEmpty, | 306 weak_ptr_factory_.GetWeakPtr()), |
| 278 weak_ptr_factory_.GetWeakPtr()), | 307 current_conditions_.get()); |
| 279 current_conditions_.get()); | |
| 280 } | 308 } |
| 281 | 309 |
| 282 // Called by the request picker when a request has been picked. | 310 // Called by the request picker when a request has been picked. |
| 283 void RequestCoordinator::RequestPicked(const SavePageRequest& request) { | 311 void RequestCoordinator::RequestPicked(const SavePageRequest& request) { |
| 284 // Send the request on to the offliner. | 312 // Send the request on to the offliner. |
| 285 SendRequestToOffliner(request); | 313 SendRequestToOffliner(request); |
| 286 } | 314 } |
| 287 | 315 |
| 288 void RequestCoordinator::RequestQueueEmpty() { | 316 void RequestCoordinator::RequestNotPicked( |
| 317 bool non_user_requested_tasks_remaining) { |
| 289 // Clear the outstanding "safety" task in the scheduler. | 318 // Clear the outstanding "safety" task in the scheduler. |
| 290 scheduler_->Unschedule(); | 319 scheduler_->Unschedule(); |
| 320 |
| 321 if (non_user_requested_tasks_remaining) |
| 322 scheduler_->Schedule(GetTriggerConditions(!kUserRequest)); |
| 291 // Let the scheduler know we are done processing. | 323 // Let the scheduler know we are done processing. |
| 292 scheduler_callback_.Run(true); | 324 scheduler_callback_.Run(true); |
| 293 } | 325 } |
| 294 | 326 |
| 295 void RequestCoordinator::SendRequestToOffliner(const SavePageRequest& request) { | 327 void RequestCoordinator::SendRequestToOffliner(const SavePageRequest& request) { |
| 296 // Check that offlining didn't get cancelled while performing some async | 328 // Check that offlining didn't get cancelled while performing some async |
| 297 // steps. | 329 // steps. |
| 298 if (is_stopped_) | 330 if (is_stopped_) |
| 299 return; | 331 return; |
| 300 | 332 |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 410 case Offliner::RequestStatus::PRERENDERING_FAILED: | 442 case Offliner::RequestStatus::PRERENDERING_FAILED: |
| 411 // No further processing in this service window. | 443 // No further processing in this service window. |
| 412 break; | 444 break; |
| 413 default: | 445 default: |
| 414 // Make explicit choice about new status codes that actually reach here. | 446 // Make explicit choice about new status codes that actually reach here. |
| 415 // Their default is no further processing in this service window. | 447 // Their default is no further processing in this service window. |
| 416 DCHECK(false); | 448 DCHECK(false); |
| 417 } | 449 } |
| 418 } | 450 } |
| 419 | 451 |
| 420 const Scheduler::TriggerConditions | 452 const Scheduler::TriggerConditions RequestCoordinator::GetTriggerConditions( |
| 421 RequestCoordinator::GetTriggerConditionsForUserRequest() { | 453 const bool user_requested) { |
| 422 Scheduler::TriggerConditions trigger_conditions( | 454 return Scheduler::TriggerConditions( |
| 423 policy_->PowerRequiredForUserRequestedPage(), | 455 policy_->PowerRequired(user_requested), |
| 424 policy_->BatteryPercentageRequiredForUserRequestedPage(), | 456 policy_->BatteryPercentageRequired(user_requested), |
| 425 policy_->UnmeteredNetworkRequiredForUserRequestedPage()); | 457 policy_->UnmeteredNetworkRequired(user_requested)); |
| 426 return trigger_conditions; | |
| 427 } | 458 } |
| 428 | 459 |
| 429 void RequestCoordinator::AddObserver(Observer* observer) { | 460 void RequestCoordinator::AddObserver(Observer* observer) { |
| 430 DCHECK(observer); | 461 DCHECK(observer); |
| 431 observers_.AddObserver(observer); | 462 observers_.AddObserver(observer); |
| 432 } | 463 } |
| 433 | 464 |
| 434 void RequestCoordinator::RemoveObserver(Observer* observer) { | 465 void RequestCoordinator::RemoveObserver(Observer* observer) { |
| 435 observers_.RemoveObserver(observer); | 466 observers_.RemoveObserver(observer); |
| 436 } | 467 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 448 FOR_EACH_OBSERVER(Observer, observers_, OnChanged(request)); | 479 FOR_EACH_OBSERVER(Observer, observers_, OnChanged(request)); |
| 449 } | 480 } |
| 450 | 481 |
| 451 void RequestCoordinator::GetOffliner() { | 482 void RequestCoordinator::GetOffliner() { |
| 452 if (!offliner_) { | 483 if (!offliner_) { |
| 453 offliner_ = factory_->GetOffliner(policy_.get()); | 484 offliner_ = factory_->GetOffliner(policy_.get()); |
| 454 } | 485 } |
| 455 } | 486 } |
| 456 | 487 |
| 457 } // namespace offline_pages | 488 } // namespace offline_pages |
| OLD | NEW |