polling_proxy_config_service.cc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // Copyright (c) 2012 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/proxy_resolution/polling_proxy_config_service.h"
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/location.h"
  8. #include "base/observer_list.h"
  9. #include "base/synchronization/lock.h"
  10. #include "base/task/single_thread_task_runner.h"
  11. #include "base/task/thread_pool.h"
  12. #include "base/threading/thread_task_runner_handle.h"
  13. #include "net/proxy_resolution/proxy_config_with_annotation.h"
  14. namespace net {
  15. // Reference-counted wrapper that does all the work (needs to be
  16. // reference-counted since we post tasks between threads; may outlive
  17. // the parent PollingProxyConfigService).
  18. class PollingProxyConfigService::Core
  19. : public base::RefCountedThreadSafe<PollingProxyConfigService::Core> {
  20. public:
  21. Core(base::TimeDelta poll_interval,
  22. GetConfigFunction get_config_func,
  23. const NetworkTrafficAnnotationTag& traffic_annotation)
  24. : get_config_func_(get_config_func),
  25. poll_interval_(poll_interval),
  26. traffic_annotation_(traffic_annotation) {}
  27. // Called when the parent PollingProxyConfigService is destroyed
  28. // (observers should not be called past this point).
  29. void Orphan() {
  30. base::AutoLock lock(lock_);
  31. origin_task_runner_ = nullptr;
  32. }
  33. bool GetLatestProxyConfig(ProxyConfigWithAnnotation* config) {
  34. LazyInitializeOriginLoop();
  35. DCHECK(origin_task_runner_->BelongsToCurrentThread());
  36. OnLazyPoll();
  37. // If we have already retrieved the proxy settings (on worker thread)
  38. // then return what we last saw.
  39. if (has_config_) {
  40. *config = last_config_;
  41. return true;
  42. }
  43. return false;
  44. }
  45. void AddObserver(Observer* observer) {
  46. LazyInitializeOriginLoop();
  47. DCHECK(origin_task_runner_->BelongsToCurrentThread());
  48. observers_.AddObserver(observer);
  49. }
  50. void RemoveObserver(Observer* observer) {
  51. DCHECK(origin_task_runner_->BelongsToCurrentThread());
  52. observers_.RemoveObserver(observer);
  53. }
  54. // Check for a new configuration if enough time has elapsed.
  55. void OnLazyPoll() {
  56. LazyInitializeOriginLoop();
  57. DCHECK(origin_task_runner_->BelongsToCurrentThread());
  58. if (last_poll_time_.is_null() ||
  59. (base::TimeTicks::Now() - last_poll_time_) > poll_interval_) {
  60. CheckForChangesNow();
  61. }
  62. }
  63. void CheckForChangesNow() {
  64. LazyInitializeOriginLoop();
  65. DCHECK(origin_task_runner_->BelongsToCurrentThread());
  66. if (poll_task_outstanding_) {
  67. // Only allow one task to be outstanding at a time. If we get a poll
  68. // request while we are busy, we will defer it until the current poll
  69. // completes.
  70. poll_task_queued_ = true;
  71. return;
  72. }
  73. last_poll_time_ = base::TimeTicks::Now();
  74. poll_task_outstanding_ = true;
  75. poll_task_queued_ = false;
  76. base::ThreadPool::PostTask(
  77. FROM_HERE,
  78. {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
  79. base::BindOnce(&Core::PollAsync, this, get_config_func_));
  80. }
  81. private:
  82. friend class base::RefCountedThreadSafe<Core>;
  83. ~Core() = default;
  84. void PollAsync(GetConfigFunction func) {
  85. ProxyConfigWithAnnotation config;
  86. func(traffic_annotation_, &config);
  87. base::AutoLock lock(lock_);
  88. if (origin_task_runner_.get()) {
  89. origin_task_runner_->PostTask(
  90. FROM_HERE, base::BindOnce(&Core::GetConfigCompleted, this, config));
  91. }
  92. }
  93. // Called after the worker thread has finished retrieving a configuration.
  94. void GetConfigCompleted(const ProxyConfigWithAnnotation& config) {
  95. DCHECK(poll_task_outstanding_);
  96. poll_task_outstanding_ = false;
  97. if (!origin_task_runner_.get())
  98. return; // Was orphaned (parent has already been destroyed).
  99. DCHECK(origin_task_runner_->BelongsToCurrentThread());
  100. if (!has_config_ || !last_config_.value().Equals(config.value())) {
  101. // If the configuration has changed, notify the observers.
  102. has_config_ = true;
  103. last_config_ = config;
  104. for (auto& observer : observers_)
  105. observer.OnProxyConfigChanged(config, ProxyConfigService::CONFIG_VALID);
  106. }
  107. if (poll_task_queued_)
  108. CheckForChangesNow();
  109. }
  110. void LazyInitializeOriginLoop() {
  111. // TODO(eroman): Really this should be done in the constructor, but some
  112. // consumers constructing the ProxyConfigService on threads
  113. // other than the ProxyConfigService's main thread, so we
  114. // can't cache the main thread for the purpose of DCHECKs
  115. // until the first call is made.
  116. if (!have_initialized_origin_runner_) {
  117. origin_task_runner_ = base::ThreadTaskRunnerHandle::Get();
  118. have_initialized_origin_runner_ = true;
  119. }
  120. }
  121. GetConfigFunction get_config_func_;
  122. base::ObserverList<Observer>::Unchecked observers_;
  123. ProxyConfigWithAnnotation last_config_;
  124. base::TimeTicks last_poll_time_;
  125. base::TimeDelta poll_interval_;
  126. const NetworkTrafficAnnotationTag traffic_annotation_;
  127. base::Lock lock_;
  128. scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
  129. bool have_initialized_origin_runner_ = false;
  130. bool has_config_ = false;
  131. bool poll_task_outstanding_ = false;
  132. bool poll_task_queued_ = false;
  133. };
  134. void PollingProxyConfigService::AddObserver(Observer* observer) {
  135. core_->AddObserver(observer);
  136. }
  137. void PollingProxyConfigService::RemoveObserver(Observer* observer) {
  138. core_->RemoveObserver(observer);
  139. }
  140. ProxyConfigService::ConfigAvailability
  141. PollingProxyConfigService::GetLatestProxyConfig(
  142. ProxyConfigWithAnnotation* config) {
  143. return core_->GetLatestProxyConfig(config) ? CONFIG_VALID : CONFIG_PENDING;
  144. }
  145. void PollingProxyConfigService::OnLazyPoll() {
  146. core_->OnLazyPoll();
  147. }
  148. PollingProxyConfigService::PollingProxyConfigService(
  149. base::TimeDelta poll_interval,
  150. GetConfigFunction get_config_func,
  151. const NetworkTrafficAnnotationTag& traffic_annotation)
  152. : core_(base::MakeRefCounted<Core>(poll_interval,
  153. get_config_func,
  154. traffic_annotation)) {}
  155. PollingProxyConfigService::~PollingProxyConfigService() {
  156. core_->Orphan();
  157. }
  158. void PollingProxyConfigService::CheckForChangesNow() {
  159. core_->CheckForChangesNow();
  160. }
  161. } // namespace net