| 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" |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 | 70 |
| 71 bool RequestCoordinator::SavePageLater( | 71 bool RequestCoordinator::SavePageLater( |
| 72 const GURL& url, const ClientId& client_id, bool user_requested) { | 72 const GURL& url, const ClientId& client_id, bool user_requested) { |
| 73 DVLOG(2) << "URL is " << url << " " << __func__; | 73 DVLOG(2) << "URL is " << url << " " << __func__; |
| 74 | 74 |
| 75 if (!OfflinePageModel::CanSaveURL(url)) { | 75 if (!OfflinePageModel::CanSaveURL(url)) { |
| 76 DVLOG(1) << "Not able to save page for requested url: " << url; | 76 DVLOG(1) << "Not able to save page for requested url: " << url; |
| 77 return false; | 77 return false; |
| 78 } | 78 } |
| 79 | 79 |
| 80 // TODO(petewil): We need a robust scheme for allocating new IDs. | 80 // TODO(petewil): Use an int64_t random number for this, pass it to the |
| 81 // offliner, and eventually use it as the offline_id - that way the client |
| 82 // uses offline_id everywhere. |
| 81 static int64_t id = 0; | 83 static int64_t id = 0; |
| 82 | 84 |
| 83 // Build a SavePageRequest. | 85 // Build a SavePageRequest. |
| 84 offline_pages::SavePageRequest request( | 86 offline_pages::SavePageRequest request( |
| 85 id++, url, client_id, base::Time::Now(), user_requested); | 87 id++, url, client_id, base::Time::Now(), user_requested); |
| 86 | 88 |
| 87 // Put the request on the request queue. | 89 // Put the request on the request queue. |
| 88 queue_->AddRequest(request, | 90 queue_->AddRequest(request, |
| 89 base::Bind(&RequestCoordinator::AddRequestResultCallback, | 91 base::Bind(&RequestCoordinator::AddRequestResultCallback, |
| 90 weak_ptr_factory_.GetWeakPtr())); | 92 weak_ptr_factory_.GetWeakPtr())); |
| 93 NotifyAdded(request); |
| 91 return true; | 94 return true; |
| 92 } | 95 } |
| 93 void RequestCoordinator::GetAllRequests(const GetRequestsCallback& callback) { | 96 void RequestCoordinator::GetAllRequests(const GetRequestsCallback& callback) { |
| 94 // Get all matching requests from the request queue, send them to our | 97 // Get all matching requests from the request queue, send them to our |
| 95 // callback. We bind the namespace and callback to the front of the callback | 98 // callback. We bind the namespace and callback to the front of the callback |
| 96 // param set. | 99 // param set. |
| 97 queue_->GetRequests(base::Bind(&RequestCoordinator::GetQueuedRequestsCallback, | 100 queue_->GetRequests(base::Bind(&RequestCoordinator::GetQueuedRequestsCallback, |
| 98 weak_ptr_factory_.GetWeakPtr(), callback)); | 101 weak_ptr_factory_.GetWeakPtr(), callback)); |
| 99 } | 102 } |
| 100 | 103 |
| 101 void RequestCoordinator::GetQueuedRequestsCallback( | 104 void RequestCoordinator::GetQueuedRequestsCallback( |
| 102 const GetRequestsCallback& callback, | 105 const GetRequestsCallback& callback, |
| 103 RequestQueue::GetRequestsResult result, | 106 RequestQueue::GetRequestsResult result, |
| 104 const std::vector<SavePageRequest>& requests) { | 107 const std::vector<SavePageRequest>& requests) { |
| 105 callback.Run(requests); | 108 callback.Run(requests); |
| 106 } | 109 } |
| 107 | 110 |
| 108 void RequestCoordinator::RemoveRequests( | 111 void RequestCoordinator::RemoveRequests( |
| 109 const std::vector<int64_t>& request_ids) { | 112 const std::vector<int64_t>& request_ids) { |
| 110 queue_->RemoveRequests(request_ids, | 113 queue_->RemoveRequests(request_ids, |
| 111 base::Bind(&RequestCoordinator::RemoveRequestsCallback, | 114 base::Bind(&RequestCoordinator::RemoveRequestsCallback, |
| 112 weak_ptr_factory_.GetWeakPtr())); | 115 weak_ptr_factory_.GetWeakPtr())); |
| 113 } | 116 } |
| 114 | 117 |
| 115 void RequestCoordinator::PauseRequests( | 118 void RequestCoordinator::PauseRequests( |
| 116 const std::vector<int64_t>& request_ids) { | 119 const std::vector<int64_t>& request_ids) { |
| 117 queue_->ChangeRequestsState( | 120 queue_->ChangeRequestsState( |
| 118 request_ids, SavePageRequest::RequestState::PAUSED, | 121 request_ids, SavePageRequest::RequestState::PAUSED, |
| 119 base::Bind(&RequestCoordinator::UpdateMultipleRequestCallback, | 122 base::Bind(&RequestCoordinator::UpdateMultipleRequestsCallback, |
| 120 weak_ptr_factory_.GetWeakPtr())); | 123 weak_ptr_factory_.GetWeakPtr())); |
| 121 } | 124 } |
| 122 | 125 |
| 123 void RequestCoordinator::ResumeRequests( | 126 void RequestCoordinator::ResumeRequests( |
| 124 const std::vector<int64_t>& request_ids) { | 127 const std::vector<int64_t>& request_ids) { |
| 125 queue_->ChangeRequestsState( | 128 queue_->ChangeRequestsState( |
| 126 request_ids, SavePageRequest::RequestState::AVAILABLE, | 129 request_ids, SavePageRequest::RequestState::AVAILABLE, |
| 127 base::Bind(&RequestCoordinator::UpdateMultipleRequestCallback, | 130 base::Bind(&RequestCoordinator::UpdateMultipleRequestsCallback, |
| 128 weak_ptr_factory_.GetWeakPtr())); | 131 weak_ptr_factory_.GetWeakPtr())); |
| 129 // TODO: Should we also schedule a task, in case there is not one scheduled? | 132 // TODO: Should we also schedule a task, in case there is not one scheduled? |
| 130 } | 133 } |
| 131 | 134 |
| 132 void RequestCoordinator::AddRequestResultCallback( | 135 void RequestCoordinator::AddRequestResultCallback( |
| 133 RequestQueue::AddRequestResult result, | 136 RequestQueue::AddRequestResult result, |
| 134 const SavePageRequest& request) { | 137 const SavePageRequest& request) { |
| 135 | |
| 136 // Inform the scheduler that we have an outstanding task.. | 138 // Inform the scheduler that we have an outstanding task.. |
| 137 scheduler_->Schedule(GetTriggerConditionsForUserRequest()); | 139 scheduler_->Schedule(GetTriggerConditionsForUserRequest()); |
| 138 } | 140 } |
| 139 | 141 |
| 140 // Called in response to updating a request in the request queue. | 142 // Called in response to updating a request in the request queue. |
| 141 void RequestCoordinator::UpdateRequestCallback( | 143 void RequestCoordinator::UpdateRequestCallback( |
| 142 const ClientId& client_id, | 144 const ClientId& client_id, |
| 143 RequestQueue::UpdateRequestResult result) { | 145 RequestQueue::UpdateRequestResult result) { |
| 144 // If the request succeeded, nothing to do. If it failed, we can't really do | 146 // If the request succeeded, nothing to do. If it failed, we can't really do |
| 145 // much, so just log it. | 147 // much, so just log it. |
| 146 if (result != RequestQueue::UpdateRequestResult::SUCCESS) { | 148 if (result != RequestQueue::UpdateRequestResult::SUCCESS) { |
| 147 DVLOG(1) << "Failed to update request attempt details. " | 149 DVLOG(1) << "Failed to update request attempt details. " |
| 148 << static_cast<int>(result); | 150 << static_cast<int>(result); |
| 149 event_logger_.RecordUpdateRequestFailed(client_id.name_space, result); | 151 event_logger_.RecordUpdateRequestFailed(client_id.name_space, result); |
| 150 } | 152 } |
| 151 } | 153 } |
| 152 | 154 |
| 153 // Called in response to updating multiple requests in the request queue. | 155 // Called in response to updating multiple requests in the request queue. |
| 154 void RequestCoordinator::UpdateMultipleRequestCallback( | 156 void RequestCoordinator::UpdateMultipleRequestsCallback( |
| 155 RequestQueue::UpdateRequestResult result) { | 157 const RequestQueue::UpdateMultipleRequestResults& results, |
| 156 // If the request succeeded, nothing to do. If it failed, we can't really do | 158 const std::vector<SavePageRequest>& requests) { |
| 157 // much, so just log it. | 159 for (SavePageRequest request : requests) |
| 158 if (result != RequestQueue::UpdateRequestResult::SUCCESS) { | 160 NotifyChanged(request); |
| 159 DVLOG(1) << "Failed to update request attempt details. " | |
| 160 << static_cast<int>(result); | |
| 161 } | |
| 162 } | 161 } |
| 163 | 162 |
| 164 void RequestCoordinator::RemoveRequestsCallback( | 163 void RequestCoordinator::RemoveRequestsCallback( |
| 165 const RequestQueue::UpdateMultipleRequestResults& results) { | 164 const RequestQueue::UpdateMultipleRequestResults& results, |
| 166 // TODO(petewil): Today the RemoveRequests API does not come with a callback. | 165 const std::vector<SavePageRequest>& requests) { |
| 167 // Should we add one? Perhaps the notifications from the observer will be | 166 for (SavePageRequest request : requests) |
| 168 // sufficient. | 167 NotifyRemoved(request); |
| 169 } | 168 } |
| 170 | 169 |
| 171 void RequestCoordinator::StopProcessing() { | 170 void RequestCoordinator::StopProcessing() { |
| 172 is_canceled_ = true; | 171 is_canceled_ = true; |
| 173 if (offliner_ && is_busy_) { | 172 if (offliner_ && is_busy_) { |
| 174 // TODO(dougarnett): Find current request and mark attempt aborted. | 173 // TODO(dougarnett): Find current request and mark attempt aborted. |
| 175 offliner_->Cancel(); | 174 offliner_->Cancel(); |
| 176 } | 175 } |
| 177 | 176 |
| 178 // Stopping offliner means it will not call callback. | 177 // Stopping offliner means it will not call callback. |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 306 if (status == Offliner::RequestStatus::FOREGROUND_CANCELED) { | 305 if (status == Offliner::RequestStatus::FOREGROUND_CANCELED) { |
| 307 // Update the request for the canceled attempt. | 306 // Update the request for the canceled attempt. |
| 308 // TODO(dougarnett): See if we can conclusively identify other attempt | 307 // TODO(dougarnett): See if we can conclusively identify other attempt |
| 309 // aborted cases to treat this way (eg, for Render Process Killed). | 308 // aborted cases to treat this way (eg, for Render Process Killed). |
| 310 SavePageRequest updated_request(request); | 309 SavePageRequest updated_request(request); |
| 311 updated_request.MarkAttemptAborted(); | 310 updated_request.MarkAttemptAborted(); |
| 312 queue_->UpdateRequest(updated_request, | 311 queue_->UpdateRequest(updated_request, |
| 313 base::Bind(&RequestCoordinator::UpdateRequestCallback, | 312 base::Bind(&RequestCoordinator::UpdateRequestCallback, |
| 314 weak_ptr_factory_.GetWeakPtr(), | 313 weak_ptr_factory_.GetWeakPtr(), |
| 315 updated_request.client_id())); | 314 updated_request.client_id())); |
| 315 NotifyFailed(updated_request, SavePageStatus::FOREGROUND_CANCELED); |
| 316 | 316 |
| 317 } else if (status == Offliner::RequestStatus::SAVED || | 317 } else if (status == Offliner::RequestStatus::SAVED) { |
| 318 request.completed_attempt_count() + 1 >= | 318 // Remove the request from the queue if it succeeded. |
| 319 policy_->GetMaxCompletedTries()) { | |
| 320 // Remove the request from the queue if it either succeeded or exceeded the | |
| 321 // max number of retries. The +1 represents the request that just | |
| 322 // completed. Since we call MarkAttemptCompleted within the if branches, | |
| 323 // the completed_attempt_count has not yet been updated when we are checking | |
| 324 // the if condition. | |
| 325 std::vector<int64_t> remove_requests; | 319 std::vector<int64_t> remove_requests; |
| 326 remove_requests.push_back(request.request_id()); | 320 remove_requests.push_back(request.request_id()); |
| 327 queue_->RemoveRequests( | 321 queue_->RemoveRequests( |
| 328 remove_requests, base::Bind(&RequestCoordinator::RemoveRequestsCallback, | 322 remove_requests, base::Bind(&RequestCoordinator::RemoveRequestsCallback, |
| 329 weak_ptr_factory_.GetWeakPtr())); | 323 weak_ptr_factory_.GetWeakPtr())); |
| 324 NotifySucceeded(request); |
| 325 } else if (request.completed_attempt_count() + 1 >= |
| 326 policy_->GetMaxCompletedTries()) { |
| 327 // Remove from the request queue if we exceeeded max retries. The +1 |
| 328 // represents the request that just completed. Since we call |
| 329 // MarkAttemptCompleted within the if branches, the completed_attempt_count |
| 330 // has not yet been updated when we are checking the if condition. |
| 331 std::vector<int64_t> remove_requests; |
| 332 remove_requests.push_back(request.request_id()); |
| 333 queue_->RemoveRequests( |
| 334 remove_requests, base::Bind(&RequestCoordinator::RemoveRequestsCallback, |
| 335 weak_ptr_factory_.GetWeakPtr())); |
| 336 NotifyFailed(request, SavePageStatus::RETRY_COUNT_EXCEEDED); |
| 330 } else { | 337 } else { |
| 331 // If we failed, but are not over the limit, update the request in the | 338 // If we failed, but are not over the limit, update the request in the |
| 332 // queue. | 339 // queue. |
| 333 SavePageRequest updated_request(request); | 340 SavePageRequest updated_request(request); |
| 334 updated_request.MarkAttemptCompleted(); | 341 updated_request.MarkAttemptCompleted(); |
| 335 queue_->UpdateRequest(updated_request, | 342 queue_->UpdateRequest(updated_request, |
| 336 base::Bind(&RequestCoordinator::UpdateRequestCallback, | 343 base::Bind(&RequestCoordinator::UpdateRequestCallback, |
| 337 weak_ptr_factory_.GetWeakPtr(), | 344 weak_ptr_factory_.GetWeakPtr(), |
| 338 updated_request.client_id())); | 345 updated_request.client_id())); |
| 346 NotifyChanged(updated_request); |
| 339 } | 347 } |
| 340 | 348 |
| 341 // Determine whether we might try another request in this | 349 // Determine whether we might try another request in this |
| 342 // processing window based on how the previous request completed. | 350 // processing window based on how the previous request completed. |
| 343 // | 351 // |
| 344 // TODO(dougarnett): Need to split PRERENDERING_FAILED into separate | 352 // TODO(dougarnett): Need to split PRERENDERING_FAILED into separate |
| 345 // codes as to whether we should try another request or not. | 353 // codes as to whether we should try another request or not. |
| 346 switch (status) { | 354 switch (status) { |
| 347 case Offliner::RequestStatus::SAVED: | 355 case Offliner::RequestStatus::SAVED: |
| 348 case Offliner::RequestStatus::SAVE_FAILED: | 356 case Offliner::RequestStatus::SAVE_FAILED: |
| (...skipping 15 matching lines...) Expand all Loading... |
| 364 | 372 |
| 365 const Scheduler::TriggerConditions | 373 const Scheduler::TriggerConditions |
| 366 RequestCoordinator::GetTriggerConditionsForUserRequest() { | 374 RequestCoordinator::GetTriggerConditionsForUserRequest() { |
| 367 Scheduler::TriggerConditions trigger_conditions( | 375 Scheduler::TriggerConditions trigger_conditions( |
| 368 policy_->PowerRequiredForUserRequestedPage(), | 376 policy_->PowerRequiredForUserRequestedPage(), |
| 369 policy_->BatteryPercentageRequiredForUserRequestedPage(), | 377 policy_->BatteryPercentageRequiredForUserRequestedPage(), |
| 370 policy_->UnmeteredNetworkRequiredForUserRequestedPage()); | 378 policy_->UnmeteredNetworkRequiredForUserRequestedPage()); |
| 371 return trigger_conditions; | 379 return trigger_conditions; |
| 372 } | 380 } |
| 373 | 381 |
| 382 void RequestCoordinator::AddObserver(Observer* observer) { |
| 383 DCHECK(observer); |
| 384 observers_.AddObserver(observer); |
| 385 } |
| 386 |
| 387 void RequestCoordinator::RemoveObserver(Observer* observer) { |
| 388 observers_.RemoveObserver(observer); |
| 389 } |
| 390 |
| 391 void RequestCoordinator::NotifyAdded(const SavePageRequest& request) { |
| 392 FOR_EACH_OBSERVER(Observer, observers_, OnAdded(request)); |
| 393 } |
| 394 |
| 395 void RequestCoordinator::NotifySucceeded(const SavePageRequest& request) { |
| 396 FOR_EACH_OBSERVER(Observer, observers_, OnSucceeded(request)); |
| 397 } |
| 398 |
| 399 void RequestCoordinator::NotifyFailed(const SavePageRequest& request, |
| 400 SavePageStatus status) { |
| 401 FOR_EACH_OBSERVER(Observer, observers_, OnFailed(request, status)); |
| 402 } |
| 403 |
| 404 void RequestCoordinator::NotifyChanged(const SavePageRequest& request) { |
| 405 FOR_EACH_OBSERVER(Observer, observers_, OnChanged(request)); |
| 406 } |
| 407 |
| 408 void RequestCoordinator::NotifyRemoved(const SavePageRequest& request) { |
| 409 FOR_EACH_OBSERVER(Observer, observers_, |
| 410 OnRemoved(request, SavePageStatus::REMOVED_BY_CLIENT)); |
| 411 } |
| 412 |
| 374 void RequestCoordinator::GetOffliner() { | 413 void RequestCoordinator::GetOffliner() { |
| 375 if (!offliner_) { | 414 if (!offliner_) { |
| 376 offliner_ = factory_->GetOffliner(policy_.get()); | 415 offliner_ = factory_->GetOffliner(policy_.get()); |
| 377 } | 416 } |
| 378 } | 417 } |
| 379 | 418 |
| 380 } // namespace offline_pages | 419 } // namespace offline_pages |
| OLD | NEW |