context.cc 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. // Copyright 2014 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/domain_reliability/context.h"
  5. #include <algorithm>
  6. #include <limits>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/json/json_writer.h"
  10. #include "base/logging.h"
  11. #include "base/metrics/histogram_macros.h"
  12. #include "base/metrics/sparse_histogram.h"
  13. #include "base/rand_util.h"
  14. #include "base/values.h"
  15. #include "components/domain_reliability/dispatcher.h"
  16. #include "components/domain_reliability/uploader.h"
  17. #include "components/domain_reliability/util.h"
  18. #include "net/base/net_errors.h"
  19. namespace domain_reliability {
  20. // static
  21. const int DomainReliabilityContext::kMaxUploadDepthToSchedule = 1;
  22. // static
  23. const size_t DomainReliabilityContext::kMaxQueuedBeacons = 150;
  24. DomainReliabilityContext::DomainReliabilityContext(
  25. const MockableTime* time,
  26. const DomainReliabilityScheduler::Params& scheduler_params,
  27. const std::string& upload_reporter_string,
  28. const base::TimeTicks* last_network_change_time,
  29. const UploadAllowedCallback& upload_allowed_callback,
  30. DomainReliabilityDispatcher* dispatcher,
  31. DomainReliabilityUploader* uploader,
  32. std::unique_ptr<const DomainReliabilityConfig> config)
  33. : config_(std::move(config)),
  34. time_(time),
  35. upload_reporter_string_(upload_reporter_string),
  36. scheduler_(time,
  37. config_->collectors.size(),
  38. scheduler_params,
  39. base::BindRepeating(&DomainReliabilityContext::ScheduleUpload,
  40. base::Unretained(this))),
  41. dispatcher_(dispatcher),
  42. uploader_(uploader),
  43. uploading_beacons_size_(0),
  44. last_network_change_time_(last_network_change_time),
  45. upload_allowed_callback_(upload_allowed_callback) {}
  46. DomainReliabilityContext::~DomainReliabilityContext() {
  47. for (auto& beacon_ptr : beacons_) {
  48. beacon_ptr->outcome = DomainReliabilityBeacon::Outcome::kContextShutDown;
  49. }
  50. }
  51. void DomainReliabilityContext::OnBeacon(
  52. std::unique_ptr<DomainReliabilityBeacon> beacon) {
  53. bool success = (beacon->status == "ok");
  54. double sample_rate = beacon->details.quic_port_migration_detected
  55. ? 1.0
  56. : config().GetSampleRate(success);
  57. if (base::RandDouble() >= sample_rate)
  58. return;
  59. beacon->sample_rate = sample_rate;
  60. // Allow beacons about reports, but don't schedule an upload for more than
  61. // one layer of recursion, to avoid infinite report loops.
  62. if (beacon->upload_depth <= kMaxUploadDepthToSchedule)
  63. scheduler_.OnBeaconAdded();
  64. beacons_.push_back(std::move(beacon));
  65. bool should_evict = beacons_.size() > kMaxQueuedBeacons;
  66. if (should_evict)
  67. RemoveOldestBeacon();
  68. }
  69. void DomainReliabilityContext::ClearBeacons() {
  70. for (auto& beacon_ptr : beacons_) {
  71. beacon_ptr->outcome = DomainReliabilityBeacon::Outcome::kCleared;
  72. }
  73. beacons_.clear();
  74. uploading_beacons_size_ = 0;
  75. }
  76. void DomainReliabilityContext::GetQueuedBeaconsForTesting(
  77. std::vector<const DomainReliabilityBeacon*>* beacons_out) const {
  78. DCHECK(beacons_out);
  79. beacons_out->clear();
  80. for (const auto& beacon : beacons_)
  81. beacons_out->push_back(beacon.get());
  82. }
  83. void DomainReliabilityContext::ScheduleUpload(
  84. base::TimeDelta min_delay,
  85. base::TimeDelta max_delay) {
  86. dispatcher_->ScheduleTask(
  87. base::BindOnce(&DomainReliabilityContext::CallUploadAllowedCallback,
  88. weak_factory_.GetWeakPtr()),
  89. min_delay, max_delay);
  90. }
  91. void DomainReliabilityContext::CallUploadAllowedCallback() {
  92. RemoveExpiredBeacons();
  93. if (beacons_.empty())
  94. return;
  95. upload_allowed_callback_.Run(
  96. config().origin,
  97. base::BindOnce(&DomainReliabilityContext::OnUploadAllowedCallbackComplete,
  98. weak_factory_.GetWeakPtr()));
  99. }
  100. void DomainReliabilityContext::OnUploadAllowedCallbackComplete(bool allowed) {
  101. if (allowed)
  102. StartUpload();
  103. }
  104. void DomainReliabilityContext::StartUpload() {
  105. RemoveExpiredBeacons();
  106. if (beacons_.empty())
  107. return;
  108. // Find the first beacon with an `upload_depth` of at most
  109. // kMaxUploadDepthToSchedule, in preparation to create a report containing all
  110. // beacons with matching NetworkIsolationKeys.
  111. bool found_beacon_to_upload = false;
  112. for (const auto& beacon : beacons_) {
  113. if (beacon->upload_depth <= kMaxUploadDepthToSchedule) {
  114. uploading_beacons_network_isolation_key_ = beacon->network_isolation_key;
  115. found_beacon_to_upload = true;
  116. break;
  117. }
  118. }
  119. if (!found_beacon_to_upload)
  120. return;
  121. size_t collector_index = scheduler_.OnUploadStart();
  122. const GURL& collector_url = *config().collectors[collector_index];
  123. DCHECK(upload_time_.is_null());
  124. upload_time_ = time_->NowTicks();
  125. std::string report_json = "{}";
  126. int max_upload_depth = -1;
  127. bool wrote = base::JSONWriter::Write(
  128. CreateReport(upload_time_, collector_url, &max_upload_depth),
  129. &report_json);
  130. DCHECK(wrote);
  131. DCHECK_NE(-1, max_upload_depth);
  132. uploader_->UploadReport(
  133. report_json, max_upload_depth, collector_url,
  134. uploading_beacons_network_isolation_key_,
  135. base::BindOnce(&DomainReliabilityContext::OnUploadComplete,
  136. weak_factory_.GetWeakPtr()));
  137. }
  138. void DomainReliabilityContext::OnUploadComplete(
  139. const DomainReliabilityUploader::UploadResult& result) {
  140. if (result.is_success())
  141. CommitUpload();
  142. else
  143. RollbackUpload();
  144. scheduler_.OnUploadComplete(result);
  145. DCHECK(!upload_time_.is_null());
  146. last_upload_time_ = upload_time_;
  147. upload_time_ = base::TimeTicks();
  148. // If there are pending beacons with a low enough depth, inform the scheduler
  149. // - it's possible only some beacons were added because of NetworkIsolationKey
  150. // mismatches, rather than due to new beacons being created.
  151. if (GetMinBeaconUploadDepth() <= kMaxUploadDepthToSchedule)
  152. scheduler_.OnBeaconAdded();
  153. }
  154. base::Value DomainReliabilityContext::CreateReport(base::TimeTicks upload_time,
  155. const GURL& collector_url,
  156. int* max_upload_depth_out) {
  157. DCHECK_GT(beacons_.size(), 0u);
  158. DCHECK_EQ(0u, uploading_beacons_size_);
  159. int max_upload_depth = 0;
  160. base::Value beacons_value(base::Value::Type::LIST);
  161. for (const auto& beacon : beacons_) {
  162. // Only include beacons with a matching NetworkIsolationKey in the report.
  163. if (beacon->network_isolation_key !=
  164. uploading_beacons_network_isolation_key_) {
  165. continue;
  166. }
  167. beacons_value.Append(
  168. beacon->ToValue(upload_time, *last_network_change_time_, collector_url,
  169. config().path_prefixes));
  170. if (beacon->upload_depth > max_upload_depth)
  171. max_upload_depth = beacon->upload_depth;
  172. ++uploading_beacons_size_;
  173. }
  174. DCHECK_GT(uploading_beacons_size_, 0u);
  175. base::Value report_value(base::Value::Type::DICTIONARY);
  176. report_value.SetStringKey("reporter", upload_reporter_string_);
  177. report_value.SetKey("entries", std::move(beacons_value));
  178. *max_upload_depth_out = max_upload_depth;
  179. return report_value;
  180. }
  181. void DomainReliabilityContext::CommitUpload() {
  182. auto current = beacons_.begin();
  183. while (uploading_beacons_size_ > 0) {
  184. DCHECK(current != beacons_.end());
  185. auto last = current;
  186. ++current;
  187. if ((*last)->network_isolation_key ==
  188. uploading_beacons_network_isolation_key_) {
  189. (*last)->outcome = DomainReliabilityBeacon::Outcome::kUploaded;
  190. beacons_.erase(last);
  191. --uploading_beacons_size_;
  192. }
  193. }
  194. }
  195. void DomainReliabilityContext::RollbackUpload() {
  196. uploading_beacons_size_ = 0;
  197. }
  198. void DomainReliabilityContext::RemoveOldestBeacon() {
  199. DCHECK(!beacons_.empty());
  200. DVLOG(1) << "Beacon queue for " << config().origin << " full; "
  201. << "removing oldest beacon";
  202. // If the beacon being removed has a NetworkIsolationKey that matches that of
  203. // the current upload, decrement |uploading_beacons_size_|.
  204. if (uploading_beacons_size_ > 0 &&
  205. beacons_.front()->network_isolation_key ==
  206. uploading_beacons_network_isolation_key_) {
  207. --uploading_beacons_size_;
  208. }
  209. beacons_.front()->outcome = DomainReliabilityBeacon::Outcome::kEvicted;
  210. beacons_.pop_front();
  211. }
  212. void DomainReliabilityContext::RemoveExpiredBeacons() {
  213. base::TimeTicks now = time_->NowTicks();
  214. const base::TimeDelta kMaxAge = base::Hours(1);
  215. while (!beacons_.empty() && now - beacons_.front()->start_time >= kMaxAge) {
  216. beacons_.front()->outcome = DomainReliabilityBeacon::Outcome::kExpired;
  217. beacons_.pop_front();
  218. }
  219. }
  220. // Gets the minimum depth of all entries in |beacons_|.
  221. int DomainReliabilityContext::GetMinBeaconUploadDepth() const {
  222. int min = std::numeric_limits<int>::max();
  223. for (const auto& beacon : beacons_) {
  224. if (beacon->upload_depth < min)
  225. min = beacon->upload_depth;
  226. }
  227. return min;
  228. }
  229. } // namespace domain_reliability