| 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 <limits> | 7 #include <limits> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/callback.h" | 11 #include "base/callback.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/metrics/histogram_macros.h" | 13 #include "base/metrics/histogram_macros.h" |
| 14 #include "base/rand_util.h" | 14 #include "base/rand_util.h" |
| 15 #include "base/sys_info.h" | 15 #include "base/sys_info.h" |
| 16 #include "base/time/time.h" | 16 #include "base/time/time.h" |
| 17 #include "components/offline_pages/background/offliner_factory.h" | 17 #include "components/offline_pages/background/offliner_factory.h" |
| 18 #include "components/offline_pages/background/offliner_policy.h" | 18 #include "components/offline_pages/background/offliner_policy.h" |
| 19 #include "components/offline_pages/background/save_page_request.h" | 19 #include "components/offline_pages/background/save_page_request.h" |
| 20 #include "components/offline_pages/client_policy_controller.h" | 20 #include "components/offline_pages/client_policy_controller.h" |
| 21 #include "components/offline_pages/offline_page_feature.h" | 21 #include "components/offline_pages/offline_page_feature.h" |
| 22 #include "components/offline_pages/offline_page_item.h" | 22 #include "components/offline_pages/offline_page_item.h" |
| 23 #include "components/offline_pages/offline_page_model.h" | 23 #include "components/offline_pages/offline_page_model.h" |
| 24 | 24 |
| 25 namespace offline_pages { | 25 namespace offline_pages { |
| 26 | 26 |
| 27 namespace { | 27 namespace { |
| 28 const bool kUserRequest = true; | 28 const bool kUserRequest = true; |
| 29 const bool kStartOfProcessing = true; |
| 29 const int kMinDurationSeconds = 1; | 30 const int kMinDurationSeconds = 1; |
| 30 const int kMaxDurationSeconds = 7 * 24 * 60 * 60; // 7 days | 31 const int kMaxDurationSeconds = 7 * 24 * 60 * 60; // 7 days |
| 31 const int kDurationBuckets = 50; | 32 const int kDurationBuckets = 50; |
| 32 const int kDisabledTaskRecheckSeconds = 5; | 33 const int kDisabledTaskRecheckSeconds = 5; |
| 33 | 34 |
| 34 // TODO(dougarnett): Move to util location and share with model impl. | 35 // TODO(dougarnett): Move to util location and share with model impl. |
| 35 std::string AddHistogramSuffix(const ClientId& client_id, | 36 std::string AddHistogramSuffix(const ClientId& client_id, |
| 36 const char* histogram_name) { | 37 const char* histogram_name) { |
| 37 if (client_id.name_space.empty()) { | 38 if (client_id.name_space.empty()) { |
| 38 NOTREACHED(); | 39 NOTREACHED(); |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 | 365 |
| 365 // Record the network quality when this request is made. | 366 // Record the network quality when this request is made. |
| 366 if (network_quality_estimator_) { | 367 if (network_quality_estimator_) { |
| 367 UMA_HISTOGRAM_ENUMERATION( | 368 UMA_HISTOGRAM_ENUMERATION( |
| 368 "OfflinePages.Background.EffectiveConnectionType.RemoveRequests", | 369 "OfflinePages.Background.EffectiveConnectionType.RemoveRequests", |
| 369 network_quality_estimator_->GetEffectiveConnectionType(), | 370 network_quality_estimator_->GetEffectiveConnectionType(), |
| 370 net::EFFECTIVE_CONNECTION_TYPE_LAST); | 371 net::EFFECTIVE_CONNECTION_TYPE_LAST); |
| 371 } | 372 } |
| 372 | 373 |
| 373 if (canceled) | 374 if (canceled) |
| 374 TryNextRequest(); | 375 TryNextRequest(!kStartOfProcessing); |
| 375 } | 376 } |
| 376 | 377 |
| 377 void RequestCoordinator::PauseRequests( | 378 void RequestCoordinator::PauseRequests( |
| 378 const std::vector<int64_t>& request_ids) { | 379 const std::vector<int64_t>& request_ids) { |
| 379 bool canceled = CancelActiveRequestIfItMatches(request_ids); | 380 bool canceled = CancelActiveRequestIfItMatches(request_ids); |
| 380 queue_->ChangeRequestsState( | 381 queue_->ChangeRequestsState( |
| 381 request_ids, SavePageRequest::RequestState::PAUSED, | 382 request_ids, SavePageRequest::RequestState::PAUSED, |
| 382 base::Bind(&RequestCoordinator::UpdateMultipleRequestsCallback, | 383 base::Bind(&RequestCoordinator::UpdateMultipleRequestsCallback, |
| 383 weak_ptr_factory_.GetWeakPtr())); | 384 weak_ptr_factory_.GetWeakPtr())); |
| 384 | 385 |
| 385 // Record the network quality when this request is made. | 386 // Record the network quality when this request is made. |
| 386 if (network_quality_estimator_) { | 387 if (network_quality_estimator_) { |
| 387 UMA_HISTOGRAM_ENUMERATION( | 388 UMA_HISTOGRAM_ENUMERATION( |
| 388 "OfflinePages.Background.EffectiveConnectionType.PauseRequests", | 389 "OfflinePages.Background.EffectiveConnectionType.PauseRequests", |
| 389 network_quality_estimator_->GetEffectiveConnectionType(), | 390 network_quality_estimator_->GetEffectiveConnectionType(), |
| 390 net::EFFECTIVE_CONNECTION_TYPE_LAST); | 391 net::EFFECTIVE_CONNECTION_TYPE_LAST); |
| 391 } | 392 } |
| 392 | 393 |
| 393 if (canceled) | 394 if (canceled) |
| 394 TryNextRequest(); | 395 TryNextRequest(!kStartOfProcessing); |
| 395 } | 396 } |
| 396 | 397 |
| 397 void RequestCoordinator::ResumeRequests( | 398 void RequestCoordinator::ResumeRequests( |
| 398 const std::vector<int64_t>& request_ids) { | 399 const std::vector<int64_t>& request_ids) { |
| 399 queue_->ChangeRequestsState( | 400 queue_->ChangeRequestsState( |
| 400 request_ids, SavePageRequest::RequestState::AVAILABLE, | 401 request_ids, SavePageRequest::RequestState::AVAILABLE, |
| 401 base::Bind(&RequestCoordinator::UpdateMultipleRequestsCallback, | 402 base::Bind(&RequestCoordinator::UpdateMultipleRequestsCallback, |
| 402 weak_ptr_factory_.GetWeakPtr())); | 403 weak_ptr_factory_.GetWeakPtr())); |
| 403 | 404 |
| 404 // Record the network quality when this request is made. | 405 // Record the network quality when this request is made. |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 464 } | 465 } |
| 465 | 466 |
| 466 if (available_user_request) | 467 if (available_user_request) |
| 467 StartImmediatelyIfConnected(); | 468 StartImmediatelyIfConnected(); |
| 468 } | 469 } |
| 469 | 470 |
| 470 // When we successfully remove a request that completed successfully, move on to | 471 // When we successfully remove a request that completed successfully, move on to |
| 471 // the next request. | 472 // the next request. |
| 472 void RequestCoordinator::CompletedRequestCallback( | 473 void RequestCoordinator::CompletedRequestCallback( |
| 473 const MultipleItemStatuses& status) { | 474 const MultipleItemStatuses& status) { |
| 474 TryNextRequest(); | 475 TryNextRequest(!kStartOfProcessing); |
| 475 } | 476 } |
| 476 | 477 |
| 477 void RequestCoordinator::HandleRemovedRequestsAndCallback( | 478 void RequestCoordinator::HandleRemovedRequestsAndCallback( |
| 478 const RemoveRequestsCallback& callback, | 479 const RemoveRequestsCallback& callback, |
| 479 RequestNotifier::BackgroundSavePageResult status, | 480 RequestNotifier::BackgroundSavePageResult status, |
| 480 std::unique_ptr<UpdateRequestsResult> result) { | 481 std::unique_ptr<UpdateRequestsResult> result) { |
| 481 // TODO(dougarnett): Define status code for user/api cancel and use here | 482 // TODO(dougarnett): Define status code for user/api cancel and use here |
| 482 // to determine whether to record cancel time UMA. | 483 // to determine whether to record cancel time UMA. |
| 483 for (const auto& request : result->updated_items) | 484 for (const auto& request : result->updated_items) |
| 484 RecordCancelTimeUMA(request); | 485 RecordCancelTimeUMA(request); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 506 StopPrerendering(stop_status); | 507 StopPrerendering(stop_status); |
| 507 | 508 |
| 508 // Let the scheduler know we are done processing. | 509 // Let the scheduler know we are done processing. |
| 509 scheduler_callback_.Run(true); | 510 scheduler_callback_.Run(true); |
| 510 } | 511 } |
| 511 | 512 |
| 512 void RequestCoordinator::HandleWatchdogTimeout() { | 513 void RequestCoordinator::HandleWatchdogTimeout() { |
| 513 Offliner::RequestStatus watchdog_status = | 514 Offliner::RequestStatus watchdog_status = |
| 514 Offliner::REQUEST_COORDINATOR_TIMED_OUT; | 515 Offliner::REQUEST_COORDINATOR_TIMED_OUT; |
| 515 StopPrerendering(watchdog_status); | 516 StopPrerendering(watchdog_status); |
| 516 TryNextRequest(); | 517 TryNextRequest(!kStartOfProcessing); |
| 517 } | 518 } |
| 518 | 519 |
| 519 // Returns true if the caller should expect a callback, false otherwise. For | 520 // Returns true if the caller should expect a callback, false otherwise. For |
| 520 // instance, this would return false if a request is already in progress. | 521 // instance, this would return false if a request is already in progress. |
| 521 bool RequestCoordinator::StartProcessing( | 522 bool RequestCoordinator::StartProcessing( |
| 522 const DeviceConditions& device_conditions, | 523 const DeviceConditions& device_conditions, |
| 523 const base::Callback<void(bool)>& callback) { | 524 const base::Callback<void(bool)>& callback) { |
| 524 DVLOG(2) << "Scheduled " << __func__; | 525 DVLOG(2) << "Scheduled " << __func__; |
| 525 return StartProcessingInternal(ProcessingWindowState::SCHEDULED_WINDOW, | 526 return StartProcessingInternal(ProcessingWindowState::SCHEDULED_WINDOW, |
| 526 device_conditions, callback); | 527 device_conditions, callback); |
| 527 } | 528 } |
| 528 | 529 |
| 529 bool RequestCoordinator::StartProcessingInternal( | 530 bool RequestCoordinator::StartProcessingInternal( |
| 530 const ProcessingWindowState processing_state, | 531 const ProcessingWindowState processing_state, |
| 531 const DeviceConditions& device_conditions, | 532 const DeviceConditions& device_conditions, |
| 532 const base::Callback<void(bool)>& callback) { | 533 const base::Callback<void(bool)>& callback) { |
| 533 current_conditions_.reset(new DeviceConditions(device_conditions)); | 534 current_conditions_.reset(new DeviceConditions(device_conditions)); |
| 534 if (is_starting_ || is_busy_) | 535 if (is_starting_ || is_busy_) |
| 535 return false; | 536 return false; |
| 536 processing_state_ = processing_state; | 537 processing_state_ = processing_state; |
| 537 scheduler_callback_ = callback; | 538 scheduler_callback_ = callback; |
| 538 | 539 |
| 539 // Mark the time at which we started processing so we can check our time | 540 // Mark the time at which we started processing so we can check our time |
| 540 // budget. | 541 // budget. |
| 541 operation_start_time_ = base::Time::Now(); | 542 operation_start_time_ = base::Time::Now(); |
| 542 | 543 |
| 543 TryNextRequest(); | 544 TryNextRequest(kStartOfProcessing); |
| 544 | 545 |
| 545 return true; | 546 return true; |
| 546 } | 547 } |
| 547 | 548 |
| 548 void RequestCoordinator::StartImmediatelyIfConnected() { | 549 void RequestCoordinator::StartImmediatelyIfConnected() { |
| 549 OfflinerImmediateStartStatus immediate_start_status = TryImmediateStart(); | 550 OfflinerImmediateStartStatus immediate_start_status = TryImmediateStart(); |
| 550 UMA_HISTOGRAM_ENUMERATION( | 551 UMA_HISTOGRAM_ENUMERATION( |
| 551 "OfflinePages.Background.ImmediateStartStatus", immediate_start_status, | 552 "OfflinePages.Background.ImmediateStartStatus", immediate_start_status, |
| 552 RequestCoordinator::OfflinerImmediateStartStatus::STATUS_COUNT); | 553 RequestCoordinator::OfflinerImmediateStartStatus::STATUS_COUNT); |
| 553 } | 554 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 577 // TODO(dougarnett): Obtain actual battery conditions (from Android/Java). | 578 // TODO(dougarnett): Obtain actual battery conditions (from Android/Java). |
| 578 | 579 |
| 579 DeviceConditions device_conditions(false, 0, GetConnectionType()); | 580 DeviceConditions device_conditions(false, 0, GetConnectionType()); |
| 580 if (StartProcessingInternal(ProcessingWindowState::IMMEDIATE_WINDOW, | 581 if (StartProcessingInternal(ProcessingWindowState::IMMEDIATE_WINDOW, |
| 581 device_conditions, immediate_schedule_callback_)) | 582 device_conditions, immediate_schedule_callback_)) |
| 582 return OfflinerImmediateStartStatus::STARTED; | 583 return OfflinerImmediateStartStatus::STARTED; |
| 583 else | 584 else |
| 584 return OfflinerImmediateStartStatus::NOT_ACCEPTED; | 585 return OfflinerImmediateStartStatus::NOT_ACCEPTED; |
| 585 } | 586 } |
| 586 | 587 |
| 587 void RequestCoordinator::TryNextRequest() { | 588 void RequestCoordinator::TryNextRequest(bool is_start_of_processing) { |
| 588 is_starting_ = true; | 589 is_starting_ = true; |
| 589 base::TimeDelta processing_time_budget; | 590 base::TimeDelta processing_time_budget; |
| 590 if (processing_state_ == ProcessingWindowState::SCHEDULED_WINDOW) { | 591 if (processing_state_ == ProcessingWindowState::SCHEDULED_WINDOW) { |
| 591 processing_time_budget = base::TimeDelta::FromSeconds( | 592 processing_time_budget = base::TimeDelta::FromSeconds( |
| 592 policy_->GetProcessingTimeBudgetWhenBackgroundScheduledInSeconds()); | 593 policy_->GetProcessingTimeBudgetWhenBackgroundScheduledInSeconds()); |
| 593 } else { | 594 } else { |
| 594 DCHECK(processing_state_ == ProcessingWindowState::IMMEDIATE_WINDOW); | 595 DCHECK(processing_state_ == ProcessingWindowState::IMMEDIATE_WINDOW); |
| 595 processing_time_budget = base::TimeDelta::FromSeconds( | 596 processing_time_budget = base::TimeDelta::FromSeconds( |
| 596 policy_->GetProcessingTimeBudgetForImmediateLoadInSeconds()); | 597 policy_->GetProcessingTimeBudgetForImmediateLoadInSeconds()); |
| 597 } | 598 } |
| 598 | 599 |
| 600 // Determine connection type. If just starting processing, the best source is |
| 601 // from the current device conditions (they are fresh and motivated starting |
| 602 // processing whereas NetworkChangeNotifier may lag reality). |
| 603 net::NetworkChangeNotifier::ConnectionType connection_type; |
| 604 if (is_start_of_processing) |
| 605 connection_type = current_conditions_->GetNetConnectionType(); |
| 606 else |
| 607 connection_type = GetConnectionType(); |
| 608 |
| 599 // If there is no network or no time left in the budget, return to the | 609 // If there is no network or no time left in the budget, return to the |
| 600 // scheduler. We do not remove the pending scheduler task that was set | 610 // scheduler. We do not remove the pending scheduler task that was set |
| 601 // up earlier in case we run out of time, so the background scheduler | 611 // up earlier in case we run out of time, so the background scheduler |
| 602 // will return to us at the next opportunity to run background tasks. | 612 // will return to us at the next opportunity to run background tasks. |
| 603 if (GetConnectionType() == | 613 if (connection_type == |
| 604 net::NetworkChangeNotifier::ConnectionType::CONNECTION_NONE || | 614 net::NetworkChangeNotifier::ConnectionType::CONNECTION_NONE || |
| 605 (base::Time::Now() - operation_start_time_) > processing_time_budget) { | 615 (base::Time::Now() - operation_start_time_) > processing_time_budget) { |
| 606 is_starting_ = false; | 616 is_starting_ = false; |
| 607 | 617 |
| 608 // Let the scheduler know we are done processing. | 618 // Let the scheduler know we are done processing. |
| 609 // TODO: Make sure the scheduler callback is valid before running it. | 619 // TODO: Make sure the scheduler callback is valid before running it. |
| 610 scheduler_callback_.Run(true); | 620 scheduler_callback_.Run(true); |
| 611 DVLOG(2) << " out of time, giving up. " << __func__; | 621 DVLOG(2) << " out of time, giving up. " << __func__; |
| 612 | 622 |
| 613 return; | 623 return; |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 752 request.request_id()); | 762 request.request_id()); |
| 753 last_offlining_status_ = status; | 763 last_offlining_status_ = status; |
| 754 RecordOfflinerResultUMA(request.client_id(), request.creation_time(), | 764 RecordOfflinerResultUMA(request.client_id(), request.creation_time(), |
| 755 last_offlining_status_); | 765 last_offlining_status_); |
| 756 watchdog_timer_.Stop(); | 766 watchdog_timer_.Stop(); |
| 757 is_busy_ = false; | 767 is_busy_ = false; |
| 758 active_request_.reset(nullptr); | 768 active_request_.reset(nullptr); |
| 759 | 769 |
| 760 UpdateRequestForCompletedAttempt(request, status); | 770 UpdateRequestForCompletedAttempt(request, status); |
| 761 if (ShouldTryNextRequest(status)) | 771 if (ShouldTryNextRequest(status)) |
| 762 TryNextRequest(); | 772 TryNextRequest(!kStartOfProcessing); |
| 763 else | 773 else |
| 764 scheduler_callback_.Run(true); | 774 scheduler_callback_.Run(true); |
| 765 } | 775 } |
| 766 | 776 |
| 767 void RequestCoordinator::UpdateRequestForCompletedAttempt( | 777 void RequestCoordinator::UpdateRequestForCompletedAttempt( |
| 768 const SavePageRequest& request, | 778 const SavePageRequest& request, |
| 769 Offliner::RequestStatus status) { | 779 Offliner::RequestStatus status) { |
| 770 if (status == Offliner::RequestStatus::FOREGROUND_CANCELED || | 780 if (status == Offliner::RequestStatus::FOREGROUND_CANCELED || |
| 771 status == Offliner::RequestStatus::PRERENDERING_CANCELED) { | 781 status == Offliner::RequestStatus::PRERENDERING_CANCELED) { |
| 772 // Update the request for the canceled attempt. | 782 // Update the request for the canceled attempt. |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 894 | 904 |
| 895 ClientPolicyController* RequestCoordinator::GetPolicyController() { | 905 ClientPolicyController* RequestCoordinator::GetPolicyController() { |
| 896 return policy_controller_.get(); | 906 return policy_controller_.get(); |
| 897 } | 907 } |
| 898 | 908 |
| 899 void RequestCoordinator::Shutdown() { | 909 void RequestCoordinator::Shutdown() { |
| 900 network_quality_estimator_ = nullptr; | 910 network_quality_estimator_ = nullptr; |
| 901 } | 911 } |
| 902 | 912 |
| 903 } // namespace offline_pages | 913 } // namespace offline_pages |
| OLD | NEW |