network_qualities_prefs_manager.cc 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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
  3. // found in the LICENSE file.
  4. #include "net/nqe/network_qualities_prefs_manager.h"
  5. #include <string>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/metrics/histogram_macros_local.h"
  9. #include "base/rand_util.h"
  10. #include "base/task/sequenced_task_runner.h"
  11. #include "base/threading/thread_task_runner_handle.h"
  12. #include "net/nqe/network_quality_estimator.h"
  13. #include "third_party/abseil-cpp/absl/types/optional.h"
  14. namespace net {
  15. namespace {
  16. // Maximum size of the prefs that hold the qualities of different networks.
  17. // A single entry in the cache consists of three tuples:
  18. // (i) SSID or MCCMNC of the network. SSID is at most 32 characters in length
  19. // (but is typically shorter than that). MCCMNC is at most 6 characters
  20. // long.
  21. // (ii) Connection type of the network as reported by network
  22. // change notifier (an enum).
  23. // (iii) Effective connection type of the network (an enum).
  24. constexpr size_t kMaxCacheSize = 20u;
  25. // Parses |value| into a map of NetworkIDs and CachedNetworkQualities,
  26. // and returns the map.
  27. ParsedPrefs ConvertDictionaryValueToMap(const base::Value::Dict& value) {
  28. DCHECK_GE(kMaxCacheSize, value.size());
  29. ParsedPrefs read_prefs;
  30. for (auto it : value) {
  31. nqe::internal::NetworkID network_id =
  32. nqe::internal::NetworkID::FromString(it.first);
  33. if (!it.second.is_string())
  34. continue;
  35. absl::optional<EffectiveConnectionType> effective_connection_type =
  36. GetEffectiveConnectionTypeForName(it.second.GetString());
  37. DCHECK(effective_connection_type.has_value());
  38. nqe::internal::CachedNetworkQuality cached_network_quality(
  39. effective_connection_type.value_or(EFFECTIVE_CONNECTION_TYPE_UNKNOWN));
  40. read_prefs[network_id] = cached_network_quality;
  41. }
  42. return read_prefs;
  43. }
  44. } // namespace
  45. NetworkQualitiesPrefsManager::NetworkQualitiesPrefsManager(
  46. std::unique_ptr<PrefDelegate> pref_delegate)
  47. : pref_delegate_(std::move(pref_delegate)),
  48. prefs_(pref_delegate_->GetDictionaryValue()) {
  49. DCHECK(pref_delegate_);
  50. DCHECK_GE(kMaxCacheSize, prefs_.size());
  51. }
  52. NetworkQualitiesPrefsManager::~NetworkQualitiesPrefsManager() {
  53. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  54. ShutdownOnPrefSequence();
  55. if (network_quality_estimator_)
  56. network_quality_estimator_->RemoveNetworkQualitiesCacheObserver(this);
  57. }
  58. void NetworkQualitiesPrefsManager::InitializeOnNetworkThread(
  59. NetworkQualityEstimator* network_quality_estimator) {
  60. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  61. DCHECK(network_quality_estimator);
  62. // Read |prefs_| again since they have now been fully initialized. This
  63. // overwrites any values that may have been added to |prefs_| since
  64. // construction of |this| via OnChangeInCachedNetworkQuality(). However, it's
  65. // expected that InitializeOnNetworkThread will be called soon after
  66. // construction of |this|. So, any loss of values would be minimal.
  67. prefs_ = pref_delegate_->GetDictionaryValue();
  68. read_prefs_startup_ = ConvertDictionaryValueToMap(prefs_);
  69. network_quality_estimator_ = network_quality_estimator;
  70. network_quality_estimator_->AddNetworkQualitiesCacheObserver(this);
  71. // Notify network quality estimator of the read prefs.
  72. network_quality_estimator_->OnPrefsRead(read_prefs_startup_);
  73. }
  74. void NetworkQualitiesPrefsManager::ShutdownOnPrefSequence() {
  75. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  76. pref_delegate_.reset();
  77. }
  78. void NetworkQualitiesPrefsManager::ClearPrefs() {
  79. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  80. LOCAL_HISTOGRAM_COUNTS_100("NQE.PrefsSizeOnClearing", prefs_.size());
  81. prefs_.clear();
  82. DCHECK_EQ(0u, prefs_.size());
  83. pref_delegate_->SetDictionaryValue(prefs_);
  84. }
  85. void NetworkQualitiesPrefsManager::OnChangeInCachedNetworkQuality(
  86. const nqe::internal::NetworkID& network_id,
  87. const nqe::internal::CachedNetworkQuality& cached_network_quality) {
  88. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  89. DCHECK_GE(kMaxCacheSize, prefs_.size());
  90. std::string network_id_string = network_id.ToString();
  91. // If the network ID contains a period, then return early since the dictionary
  92. // prefs cannot contain period in the path.
  93. if (network_id_string.find('.') != std::string::npos)
  94. return;
  95. prefs_.Set(network_id_string,
  96. GetNameForEffectiveConnectionType(
  97. cached_network_quality.effective_connection_type()));
  98. if (prefs_.size() > kMaxCacheSize) {
  99. // Delete one randomly selected value that has a key that is different from
  100. // |network_id|.
  101. DCHECK_EQ(kMaxCacheSize + 1, prefs_.size());
  102. // Generate a random number in the range [0, |kMaxCacheSize| - 1] since the
  103. // number of network IDs in |prefs_| other than |network_id| is
  104. // |kMaxCacheSize|.
  105. int index_to_delete = base::RandInt(0, kMaxCacheSize - 1);
  106. for (auto it : prefs_) {
  107. // Delete the kth element in the dictionary, not including the element
  108. // that represents the current network. k == |index_to_delete|.
  109. if (nqe::internal::NetworkID::FromString(it.first) == network_id)
  110. continue;
  111. if (index_to_delete == 0) {
  112. prefs_.Remove(it.first);
  113. break;
  114. }
  115. index_to_delete--;
  116. }
  117. }
  118. DCHECK_GE(kMaxCacheSize, prefs_.size());
  119. // Notify the pref delegate so that it updates the prefs on the disk.
  120. pref_delegate_->SetDictionaryValue(prefs_);
  121. }
  122. ParsedPrefs NetworkQualitiesPrefsManager::ForceReadPrefsForTesting() const {
  123. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  124. base::Value::Dict value = pref_delegate_->GetDictionaryValue();
  125. return ConvertDictionaryValueToMap(value);
  126. }
  127. } // namespace net