tile_service_scheduler_impl.cc 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/query_tiles/internal/tile_service_scheduler_impl.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "base/command_line.h"
  8. #include "base/rand_util.h"
  9. #include "base/time/default_tick_clock.h"
  10. #include "base/time/time.h"
  11. #include "components/prefs/pref_service.h"
  12. #include "components/query_tiles/internal/stats.h"
  13. #include "components/query_tiles/internal/tile_config.h"
  14. #include "components/query_tiles/switches.h"
  15. #include "net/base/backoff_entry_serializer.h"
  16. namespace query_tiles {
  17. namespace {
  18. // Schedule window params in instant schedule mode.
  19. const int kInstantScheduleWindowStartMs = 10 * 1000; // 10 seconds
  20. const int kInstantScheduleWindowEndMs = 20 * 1000; // 20 seconds
  21. bool IsInstantFetchMode() {
  22. return base::CommandLine::ForCurrentProcess()->HasSwitch(
  23. switches::kQueryTilesInstantBackgroundTask);
  24. }
  25. } // namespace
  26. TileServiceSchedulerImpl::TileServiceSchedulerImpl(
  27. background_task::BackgroundTaskScheduler* scheduler,
  28. PrefService* prefs,
  29. base::Clock* clock,
  30. const base::TickClock* tick_clock,
  31. std::unique_ptr<net::BackoffEntry::Policy> backoff_policy,
  32. LogSink* log_sink)
  33. : scheduler_(scheduler),
  34. prefs_(prefs),
  35. clock_(clock),
  36. tick_clock_(tick_clock),
  37. backoff_policy_(std::move(backoff_policy)),
  38. is_suspend_(false),
  39. delegate_(nullptr),
  40. fetcher_status_(TileInfoRequestStatus::kInit),
  41. group_status_(TileGroupStatus::kUninitialized),
  42. log_sink_(log_sink) {}
  43. TileServiceSchedulerImpl::~TileServiceSchedulerImpl() = default;
  44. void TileServiceSchedulerImpl::CancelTask() {
  45. scheduler_->Cancel(
  46. static_cast<int>(background_task::TaskIds::QUERY_TILE_JOB_ID));
  47. ResetBackoff();
  48. MarkFirstRunFinished();
  49. }
  50. void TileServiceSchedulerImpl::OnFetchStarted() {
  51. fetcher_status_ = TileInfoRequestStatus::kInit;
  52. if (!IsInstantFetchMode()) {
  53. base::Time::Exploded local_explode;
  54. base::Time::Now().LocalExplode(&local_explode);
  55. stats::RecordExplodeOnFetchStarted(local_explode.hour);
  56. }
  57. }
  58. void TileServiceSchedulerImpl::OnFetchCompleted(TileInfoRequestStatus status) {
  59. auto first_schedule_time = prefs_->GetTime(kFirstScheduleTimeKey);
  60. MarkFirstRunFinished();
  61. fetcher_status_ = status;
  62. if (IsInstantFetchMode())
  63. return;
  64. // If this task was marked at first attempting flow, record the duration, and
  65. // mark the flow is finished now.
  66. if (first_schedule_time != base::Time()) {
  67. auto hours_past = (clock_->Now() - first_schedule_time).InHours();
  68. if (hours_past >= 0) {
  69. stats::RecordFirstFetchFlowDuration(hours_past);
  70. }
  71. }
  72. if (status == TileInfoRequestStatus::kShouldSuspend) {
  73. ResetBackoff();
  74. is_suspend_ = true;
  75. } else if (status == TileInfoRequestStatus::kFailure) {
  76. AddBackoff();
  77. ScheduleTask(false);
  78. } else if (status == TileInfoRequestStatus::kSuccess && !is_suspend_) {
  79. ResetBackoff();
  80. ScheduleTask(true);
  81. }
  82. stats::RecordTileRequestStatus(status);
  83. PingLogSink();
  84. }
  85. void TileServiceSchedulerImpl::OnDbPurged(TileGroupStatus status) {
  86. CancelTask();
  87. group_status_ = status;
  88. PingLogSink();
  89. }
  90. void TileServiceSchedulerImpl::OnGroupDataSaved(TileGroupStatus status) {
  91. group_status_ = status;
  92. PingLogSink();
  93. }
  94. void TileServiceSchedulerImpl::OnTileManagerInitialized(
  95. TileGroupStatus status) {
  96. group_status_ = status;
  97. if (IsInstantFetchMode()) {
  98. ResetBackoff();
  99. ScheduleTask(true);
  100. return;
  101. }
  102. if (status == TileGroupStatus::kNoTiles && !is_suspend_ &&
  103. !IsDuringFirstFlow()) {
  104. ResetBackoff();
  105. ScheduleTask(true);
  106. MarkFirstRunScheduled();
  107. } else if (status == TileGroupStatus::kFailureDbOperation) {
  108. ResetBackoff();
  109. is_suspend_ = true;
  110. }
  111. stats::RecordTileGroupStatus(status);
  112. PingLogSink();
  113. }
  114. TileInfoRequestStatus TileServiceSchedulerImpl::GetFetcherStatus() {
  115. return fetcher_status_;
  116. }
  117. TileGroupStatus TileServiceSchedulerImpl::GetGroupStatus() {
  118. return group_status_;
  119. }
  120. TileGroup* TileServiceSchedulerImpl::GetTileGroup() {
  121. return delegate_ ? delegate_->GetTileGroup() : nullptr;
  122. }
  123. std::unique_ptr<net::BackoffEntry> TileServiceSchedulerImpl::GetBackoff() {
  124. const base::Value::List& value = prefs_->GetValueList(kBackoffEntryKey);
  125. std::unique_ptr<net::BackoffEntry> result =
  126. net::BackoffEntrySerializer::DeserializeFromList(
  127. value, backoff_policy_.get(), tick_clock_, clock_->Now());
  128. if (!result) {
  129. return std::make_unique<net::BackoffEntry>(backoff_policy_.get(),
  130. tick_clock_);
  131. }
  132. return result;
  133. }
  134. void TileServiceSchedulerImpl::ScheduleTask(bool is_init_schedule) {
  135. background_task::OneOffInfo one_off_task_info;
  136. if (IsInstantFetchMode()) {
  137. GetInstantTaskWindow(&one_off_task_info.window_start_time_ms,
  138. &one_off_task_info.window_end_time_ms,
  139. is_init_schedule);
  140. } else {
  141. GetTaskWindow(&one_off_task_info.window_start_time_ms,
  142. &one_off_task_info.window_end_time_ms, is_init_schedule);
  143. }
  144. background_task::TaskInfo task_info(
  145. static_cast<int>(background_task::TaskIds::QUERY_TILE_JOB_ID),
  146. one_off_task_info);
  147. task_info.is_persisted = true;
  148. task_info.update_current = true;
  149. task_info.network_type =
  150. TileConfig::GetIsUnMeteredNetworkRequired()
  151. ? background_task::TaskInfo::NetworkType::UNMETERED
  152. : background_task::TaskInfo::NetworkType::ANY;
  153. scheduler_->Schedule(task_info);
  154. }
  155. void TileServiceSchedulerImpl::AddBackoff() {
  156. std::unique_ptr<net::BackoffEntry> current = GetBackoff();
  157. current->InformOfRequest(false);
  158. UpdateBackoff(current.get());
  159. }
  160. void TileServiceSchedulerImpl::ResetBackoff() {
  161. std::unique_ptr<net::BackoffEntry> current = GetBackoff();
  162. current->Reset();
  163. UpdateBackoff(current.get());
  164. }
  165. int64_t TileServiceSchedulerImpl::GetDelaysFromBackoff() {
  166. return GetBackoff()->GetTimeUntilRelease().InMilliseconds();
  167. }
  168. // Schedule next task in next 10 to 20 seconds in debug mode.
  169. void TileServiceSchedulerImpl::GetInstantTaskWindow(int64_t* start_time_ms,
  170. int64_t* end_time_ms,
  171. bool is_init_schedule) {
  172. if (is_init_schedule) {
  173. *start_time_ms = kInstantScheduleWindowStartMs;
  174. } else {
  175. *start_time_ms = GetDelaysFromBackoff();
  176. }
  177. *end_time_ms = kInstantScheduleWindowEndMs;
  178. }
  179. void TileServiceSchedulerImpl::GetTaskWindow(int64_t* start_time_ms,
  180. int64_t* end_time_ms,
  181. bool is_init_schedule) {
  182. if (is_init_schedule) {
  183. *start_time_ms = TileConfig::GetScheduleIntervalInMs() +
  184. base::RandGenerator(TileConfig::GetMaxRandomWindowInMs());
  185. } else {
  186. *start_time_ms = GetDelaysFromBackoff();
  187. }
  188. *end_time_ms = *start_time_ms + TileConfig::GetOneoffTaskWindowInMs();
  189. }
  190. void TileServiceSchedulerImpl::UpdateBackoff(net::BackoffEntry* backoff) {
  191. base::Value value =
  192. net::BackoffEntrySerializer::SerializeToValue(*backoff, clock_->Now());
  193. prefs_->Set(kBackoffEntryKey, value);
  194. }
  195. void TileServiceSchedulerImpl::MarkFirstRunScheduled() {
  196. prefs_->SetTime(kFirstScheduleTimeKey, clock_->Now());
  197. }
  198. void TileServiceSchedulerImpl::MarkFirstRunFinished() {
  199. prefs_->SetTime(kFirstScheduleTimeKey, base::Time());
  200. }
  201. bool TileServiceSchedulerImpl::IsDuringFirstFlow() {
  202. return prefs_->GetTime(kFirstScheduleTimeKey) != base::Time();
  203. }
  204. void TileServiceSchedulerImpl::SetDelegate(Delegate* delegate) {
  205. delegate_ = delegate;
  206. }
  207. void TileServiceSchedulerImpl::PingLogSink() {
  208. log_sink_->OnServiceStatusChanged();
  209. log_sink_->OnTileDataAvailable();
  210. }
  211. } // namespace query_tiles