public_ip_address_location_notifier.cc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // Copyright 2017 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 "services/device/geolocation/public_ip_address_location_notifier.h"
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "net/traffic_annotation/network_traffic_annotation.h"
  8. #include "services/device/geolocation/wifi_data.h"
  9. #include "services/network/public/cpp/shared_url_loader_factory.h"
  10. namespace device {
  11. namespace {
  12. // Time to wait before issuing a network geolocation request in response to
  13. // network change notification. Network changes tend to occur in clusters.
  14. constexpr base::TimeDelta kNetworkChangeReactionDelay = base::Minutes(5);
  15. } // namespace
  16. PublicIpAddressLocationNotifier::PublicIpAddressLocationNotifier(
  17. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
  18. network::NetworkConnectionTracker* network_connection_tracker,
  19. const std::string& api_key)
  20. : network_changed_since_last_request_(true),
  21. api_key_(api_key),
  22. url_loader_factory_(url_loader_factory),
  23. network_connection_tracker_(network_connection_tracker),
  24. network_traffic_annotation_tag_(nullptr) {
  25. // Subscribe to notifications of changes in network configuration.
  26. network_connection_tracker_->AddNetworkConnectionObserver(this);
  27. }
  28. PublicIpAddressLocationNotifier::~PublicIpAddressLocationNotifier() {
  29. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  30. network_connection_tracker_->RemoveNetworkConnectionObserver(this);
  31. }
  32. void PublicIpAddressLocationNotifier::QueryNextPosition(
  33. base::Time time_of_prev_position,
  34. const net::PartialNetworkTrafficAnnotationTag& tag,
  35. QueryNextPositionCallback callback) {
  36. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  37. network_traffic_annotation_tag_ =
  38. std::make_unique<net::PartialNetworkTrafficAnnotationTag>(tag);
  39. // If a network location request is in flight, wait.
  40. if (network_location_request_) {
  41. callbacks_.push_back(std::move(callback));
  42. return;
  43. }
  44. // If a network change has occured since we last made a request, start a
  45. // request and wait.
  46. if (network_changed_since_last_request_) {
  47. callbacks_.push_back(std::move(callback));
  48. MakeNetworkLocationRequest();
  49. return;
  50. }
  51. if (latest_geoposition_.has_value() &&
  52. latest_geoposition_->timestamp > time_of_prev_position) {
  53. std::move(callback).Run(*latest_geoposition_);
  54. return;
  55. }
  56. // The cached geoposition is not new enough for this client, and
  57. // there hasn't been a recent network change, so add the client
  58. // to the list of clients waiting for a network change.
  59. callbacks_.push_back(std::move(callback));
  60. }
  61. void PublicIpAddressLocationNotifier::OnConnectionChanged(
  62. network::mojom::ConnectionType type) {
  63. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  64. // Post a cancelable task to react to this network change after a reasonable
  65. // delay, so that we only react once if multiple network changes occur in a
  66. // short span of time.
  67. react_to_network_change_closure_.Reset(
  68. base::BindOnce(&PublicIpAddressLocationNotifier::ReactToNetworkChange,
  69. base::Unretained(this)));
  70. base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
  71. FROM_HERE, react_to_network_change_closure_.callback(),
  72. kNetworkChangeReactionDelay);
  73. }
  74. void PublicIpAddressLocationNotifier::ReactToNetworkChange() {
  75. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  76. network_changed_since_last_request_ = true;
  77. // Invalidate the cached recent position.
  78. latest_geoposition_.reset();
  79. // If any clients are waiting, start a request.
  80. // (This will cancel any previous request, which is OK.)
  81. if (!callbacks_.empty())
  82. MakeNetworkLocationRequest();
  83. }
  84. void PublicIpAddressLocationNotifier::MakeNetworkLocationRequest() {
  85. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  86. network_changed_since_last_request_ = false;
  87. if (!url_loader_factory_)
  88. return;
  89. network_location_request_ = std::make_unique<NetworkLocationRequest>(
  90. url_loader_factory_, api_key_,
  91. base::BindRepeating(
  92. &PublicIpAddressLocationNotifier::OnNetworkLocationResponse,
  93. weak_ptr_factory_.GetWeakPtr()));
  94. DCHECK(network_traffic_annotation_tag_);
  95. network_location_request_->MakeRequest(WifiData(), base::Time::Now(),
  96. *network_traffic_annotation_tag_);
  97. }
  98. void PublicIpAddressLocationNotifier::OnNetworkLocationResponse(
  99. const mojom::Geoposition& position,
  100. const bool server_error,
  101. const WifiData& /* wifi_data */) {
  102. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  103. if (server_error) {
  104. network_changed_since_last_request_ = true;
  105. DCHECK(!latest_geoposition_.has_value());
  106. } else {
  107. latest_geoposition_ = absl::make_optional(position);
  108. }
  109. // Notify all clients.
  110. for (QueryNextPositionCallback& callback : callbacks_)
  111. std::move(callback).Run(position);
  112. callbacks_.clear();
  113. network_location_request_.reset();
  114. }
  115. } // namespace device