Commit 4e043583 authored by Matt Reynolds's avatar Matt Reynolds Committed by Commit Bot

Reland "Move WifiPollingPolicy to a global instance"

This is a reland of bd9b9ea0
Original change's description:
> Move WifiPollingPolicy to a global instance
> 
> The WifiPollingPolicy controls how frequently the network location
> provider will initiate Wi-Fi scans. Previously, the policy was attached
> to the WifiDataProvider, which is destroyed when there are no active
> geolocation API calls. Destruction of the provider causes us to lose track
> of our polling policy.
> 
> The policy allows the first scan to be performed immediately and schedules
> subsequent scans at regular intervals. When the provider is destroyed and
> recreated rapidly it considers each scan to be "first", which allows many
> Wi-Fi scans to be performed in a short window.
> 
> This change moves the policy state to a global instance so it can be saved
> when the provider is destroyed and recreated. The new policy allows the
> first-ever scan to be performed immediately, and subsequent scans may also
> be performed immediately if enough time has lapsed since the previous scan.
> In all other situations, the configured polling interval is enforced.
> 
> The global policy instance is leaked at shutdown.
> 
> BUG=764954
> 
> Change-Id: If16c73dfd7d6535346e86d0fab5df24f0c7b297d
> Reviewed-on: https://chromium-review.googlesource.com/850444
> Commit-Queue: Matt Reynolds <mattreynolds@chromium.org>
> Reviewed-by: Reilly Grant <reillyg@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#527219}

Bug: 764954
Change-Id: I394a671cdbcdb58d6e80c201777465d1d304987b
Reviewed-on: https://chromium-review.googlesource.com/860778Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Commit-Queue: Matt Reynolds <mattreynolds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#528466}
parent 10c1f701
...@@ -53,6 +53,7 @@ component("geolocation") { ...@@ -53,6 +53,7 @@ component("geolocation") {
"wifi_data_provider_manager.h", "wifi_data_provider_manager.h",
"wifi_data_provider_win.cc", "wifi_data_provider_win.cc",
"wifi_data_provider_win.h", "wifi_data_provider_win.h",
"wifi_polling_policy.cc",
"wifi_polling_policy.h", "wifi_polling_policy.h",
] ]
......
...@@ -36,20 +36,16 @@ WifiDataProviderChromeOs::~WifiDataProviderChromeOs() = default; ...@@ -36,20 +36,16 @@ WifiDataProviderChromeOs::~WifiDataProviderChromeOs() = default;
void WifiDataProviderChromeOs::StartDataProvider() { void WifiDataProviderChromeOs::StartDataProvider() {
DCHECK(CalledOnClientThread()); DCHECK(CalledOnClientThread());
DCHECK(polling_policy_ == nullptr); if (!WifiPollingPolicy::IsInitialized())
polling_policy_.reset( WifiPollingPolicy::Initialize(CreatePollingPolicy());
new GenericWifiPollingPolicy<kDefaultPollingIntervalMilliseconds, DCHECK(WifiPollingPolicy::IsInitialized());
kNoChangePollingIntervalMilliseconds,
kTwoNoChangePollingIntervalMilliseconds, ScheduleStart(WifiPollingPolicy::Get()->PollingInterval());
kNoWifiPollingIntervalMilliseconds>);
ScheduleStart();
} }
void WifiDataProviderChromeOs::StopDataProvider() { void WifiDataProviderChromeOs::StopDataProvider() {
DCHECK(CalledOnClientThread()); DCHECK(CalledOnClientThread());
polling_policy_.reset();
ScheduleStop(); ScheduleStop();
} }
...@@ -83,7 +79,7 @@ void WifiDataProviderChromeOs::DidWifiScanTaskNoResults() { ...@@ -83,7 +79,7 @@ void WifiDataProviderChromeOs::DidWifiScanTaskNoResults() {
// Schedule next scan if started (StopDataProvider could have been called // Schedule next scan if started (StopDataProvider could have been called
// in between DoWifiScanTaskOnNetworkHandlerThread and this method). // in between DoWifiScanTaskOnNetworkHandlerThread and this method).
if (started_) if (started_)
ScheduleNextScan(polling_policy_->NoWifiInterval()); ScheduleNextScan(WifiPollingPolicy::Get()->NoWifiInterval());
} }
void WifiDataProviderChromeOs::DidWifiScanTask(const WifiData& new_data) { void WifiDataProviderChromeOs::DidWifiScanTask(const WifiData& new_data) {
...@@ -93,8 +89,8 @@ void WifiDataProviderChromeOs::DidWifiScanTask(const WifiData& new_data) { ...@@ -93,8 +89,8 @@ void WifiDataProviderChromeOs::DidWifiScanTask(const WifiData& new_data) {
// Schedule next scan if started (StopDataProvider could have been called // Schedule next scan if started (StopDataProvider could have been called
// in between DoWifiScanTaskOnNetworkHandlerThread and this method). // in between DoWifiScanTaskOnNetworkHandlerThread and this method).
if (started_) { if (started_) {
polling_policy_->UpdatePollingInterval(update_available); WifiPollingPolicy::Get()->UpdatePollingInterval(update_available);
ScheduleNextScan(polling_policy_->PollingInterval()); ScheduleNextScan(WifiPollingPolicy::Get()->PollingInterval());
} }
if (update_available || !is_first_scan_complete_) { if (update_available || !is_first_scan_complete_) {
...@@ -124,7 +120,7 @@ void WifiDataProviderChromeOs::ScheduleStop() { ...@@ -124,7 +120,7 @@ void WifiDataProviderChromeOs::ScheduleStop() {
started_ = false; started_ = false;
} }
void WifiDataProviderChromeOs::ScheduleStart() { void WifiDataProviderChromeOs::ScheduleStart(int interval) {
DCHECK(CalledOnClientThread()); DCHECK(CalledOnClientThread());
DCHECK(!started_); DCHECK(!started_);
if (!NetworkHandler::IsInitialized()) { if (!NetworkHandler::IsInitialized()) {
...@@ -132,13 +128,12 @@ void WifiDataProviderChromeOs::ScheduleStart() { ...@@ -132,13 +128,12 @@ void WifiDataProviderChromeOs::ScheduleStart() {
return; return;
} }
started_ = true; started_ = true;
// Perform first scan ASAP regardless of the polling policy. If this scan NetworkHandler::Get()->task_runner()->PostDelayedTask(
// fails we'll retry at a rate in line with the polling policy.
NetworkHandler::Get()->task_runner()->PostTask(
FROM_HERE, FROM_HERE,
base::Bind( base::Bind(
&WifiDataProviderChromeOs::DoWifiScanTaskOnNetworkHandlerThread, &WifiDataProviderChromeOs::DoWifiScanTaskOnNetworkHandlerThread,
this)); this),
base::TimeDelta::FromMilliseconds(interval));
} }
bool WifiDataProviderChromeOs::GetAccessPointData( bool WifiDataProviderChromeOs::GetAccessPointData(
...@@ -176,6 +171,14 @@ bool WifiDataProviderChromeOs::GetAccessPointData( ...@@ -176,6 +171,14 @@ bool WifiDataProviderChromeOs::GetAccessPointData(
return true; return true;
} }
std::unique_ptr<WifiPollingPolicy>
WifiDataProviderChromeOs::CreatePollingPolicy() {
return std::make_unique<GenericWifiPollingPolicy<
kDefaultPollingIntervalMilliseconds, kNoChangePollingIntervalMilliseconds,
kTwoNoChangePollingIntervalMilliseconds,
kNoWifiPollingIntervalMilliseconds>>();
}
// static // static
WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() { WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() {
return new WifiDataProviderChromeOs(); return new WifiDataProviderChromeOs();
......
...@@ -39,7 +39,7 @@ class DEVICE_GEOLOCATION_EXPORT WifiDataProviderChromeOs ...@@ -39,7 +39,7 @@ class DEVICE_GEOLOCATION_EXPORT WifiDataProviderChromeOs
void ScheduleNextScan(int interval); void ScheduleNextScan(int interval);
// Will schedule starting of the scanning process. // Will schedule starting of the scanning process.
void ScheduleStart(); void ScheduleStart(int interval);
// Will schedule stopping of the scanning process. // Will schedule stopping of the scanning process.
void ScheduleStop(); void ScheduleStop();
...@@ -47,8 +47,8 @@ class DEVICE_GEOLOCATION_EXPORT WifiDataProviderChromeOs ...@@ -47,8 +47,8 @@ class DEVICE_GEOLOCATION_EXPORT WifiDataProviderChromeOs
// Get access point data from chromeos. // Get access point data from chromeos.
bool GetAccessPointData(WifiData::AccessPointDataSet* data); bool GetAccessPointData(WifiData::AccessPointDataSet* data);
// Controls the polling update interval. (client thread) // Create the policy for controlling the polling update interval.
std::unique_ptr<WifiPollingPolicy> polling_policy_; std::unique_ptr<WifiPollingPolicy> CreatePollingPolicy();
// The latest wifi data. (client thread) // The latest wifi data. (client thread)
WifiData wifi_data_; WifiData wifi_data_;
......
...@@ -35,18 +35,15 @@ void WifiDataProviderCommon::StartDataProvider() { ...@@ -35,18 +35,15 @@ void WifiDataProviderCommon::StartDataProvider() {
return; return;
} }
DCHECK(!polling_policy_); if (!WifiPollingPolicy::IsInitialized())
polling_policy_ = CreatePollingPolicy(); WifiPollingPolicy::Initialize(CreatePollingPolicy());
DCHECK(polling_policy_); DCHECK(WifiPollingPolicy::IsInitialized());
// Perform first scan ASAP regardless of the polling policy. If this scan ScheduleNextScan(WifiPollingPolicy::Get()->PollingInterval());
// fails we'll retry at a rate in line with the polling policy.
ScheduleNextScan(0);
} }
void WifiDataProviderCommon::StopDataProvider() { void WifiDataProviderCommon::StopDataProvider() {
wlan_api_.reset(); wlan_api_.reset();
polling_policy_.reset();
} }
bool WifiDataProviderCommon::GetData(WifiData* data) { bool WifiDataProviderCommon::GetData(WifiData* data) {
...@@ -64,12 +61,12 @@ void WifiDataProviderCommon::DoWifiScanTask() { ...@@ -64,12 +61,12 @@ void WifiDataProviderCommon::DoWifiScanTask() {
bool update_available = false; bool update_available = false;
WifiData new_data; WifiData new_data;
if (!wlan_api_->GetAccessPointData(&new_data.access_point_data)) { if (!wlan_api_->GetAccessPointData(&new_data.access_point_data)) {
ScheduleNextScan(polling_policy_->NoWifiInterval()); ScheduleNextScan(WifiPollingPolicy::Get()->NoWifiInterval());
} else { } else {
update_available = wifi_data_.DiffersSignificantly(new_data); update_available = wifi_data_.DiffersSignificantly(new_data);
wifi_data_ = new_data; wifi_data_ = new_data;
polling_policy_->UpdatePollingInterval(update_available); WifiPollingPolicy::Get()->UpdatePollingInterval(update_available);
ScheduleNextScan(polling_policy_->PollingInterval()); ScheduleNextScan(WifiPollingPolicy::Get()->PollingInterval());
} }
if (update_available || !is_first_scan_complete_) { if (update_available || !is_first_scan_complete_) {
is_first_scan_complete_ = true; is_first_scan_complete_ = true;
......
...@@ -72,9 +72,6 @@ class DEVICE_GEOLOCATION_EXPORT WifiDataProviderCommon ...@@ -72,9 +72,6 @@ class DEVICE_GEOLOCATION_EXPORT WifiDataProviderCommon
// Underlying OS wifi API. // Underlying OS wifi API.
std::unique_ptr<WlanApiInterface> wlan_api_; std::unique_ptr<WlanApiInterface> wlan_api_;
// Controls the polling update interval.
std::unique_ptr<WifiPollingPolicy> polling_policy_;
// Holder for delayed tasks; takes care of cleanup. // Holder for delayed tasks; takes care of cleanup.
base::WeakPtrFactory<WifiDataProviderCommon> weak_factory_; base::WeakPtrFactory<WifiDataProviderCommon> weak_factory_;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/third_party/dynamic_annotations/dynamic_annotations.h" #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "device/geolocation/wifi_data_provider_manager.h" #include "device/geolocation/wifi_data_provider_manager.h"
#include "device/geolocation/wifi_polling_policy.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -60,7 +61,8 @@ class MockPollingPolicy : public WifiPollingPolicy { ...@@ -60,7 +61,8 @@ class MockPollingPolicy : public WifiPollingPolicy {
class WifiDataProviderCommonWithMock : public WifiDataProviderCommon { class WifiDataProviderCommonWithMock : public WifiDataProviderCommon {
public: public:
WifiDataProviderCommonWithMock() WifiDataProviderCommonWithMock()
: wlan_api_(new MockWlanApi), polling_policy_(new MockPollingPolicy) {} : wlan_api_(new MockWlanApi),
polling_policy_(std::make_unique<MockPollingPolicy>()) {}
// WifiDataProviderCommon // WifiDataProviderCommon
std::unique_ptr<WlanApiInterface> CreateWlanApi() override { std::unique_ptr<WlanApiInterface> CreateWlanApi() override {
...@@ -97,6 +99,7 @@ class GeolocationWifiDataProviderCommonTest : public testing::Test { ...@@ -97,6 +99,7 @@ class GeolocationWifiDataProviderCommonTest : public testing::Test {
void TearDown() override { void TearDown() override {
provider_->RemoveCallback(&wifi_data_callback_); provider_->RemoveCallback(&wifi_data_callback_);
provider_->StopDataProvider(); provider_->StopDataProvider();
WifiPollingPolicy::Shutdown();
} }
protected: protected:
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/geolocation/wifi_polling_policy.h"
namespace device {
namespace {
// Leaks at exit.
WifiPollingPolicy* g_wifi_polling_policy;
} // namespace
// static
void WifiPollingPolicy::Initialize(std::unique_ptr<WifiPollingPolicy> policy) {
DCHECK(!g_wifi_polling_policy);
g_wifi_polling_policy = policy.release();
}
// static
void WifiPollingPolicy::Shutdown() {
if (g_wifi_polling_policy)
delete g_wifi_polling_policy;
g_wifi_polling_policy = nullptr;
}
// static
WifiPollingPolicy* WifiPollingPolicy::Get() {
DCHECK(g_wifi_polling_policy);
return g_wifi_polling_policy;
}
// static
bool WifiPollingPolicy::IsInitialized() {
return g_wifi_polling_policy != nullptr;
}
} // namespace device
...@@ -5,21 +5,36 @@ ...@@ -5,21 +5,36 @@
#ifndef DEVICE_GEOLOCATION_WIFI_POLLING_POLICY_H_ #ifndef DEVICE_GEOLOCATION_WIFI_POLLING_POLICY_H_
#define DEVICE_GEOLOCATION_WIFI_POLLING_POLICY_H_ #define DEVICE_GEOLOCATION_WIFI_POLLING_POLICY_H_
#include <memory>
#include "base/macros.h" #include "base/macros.h"
#include "base/time/time.h"
#include "device/geolocation/geolocation_export.h"
namespace device { namespace device {
// Allows sharing and mocking of the update polling policy function. // Allows sharing and mocking of the update polling policy function.
class WifiPollingPolicy { class DEVICE_GEOLOCATION_EXPORT WifiPollingPolicy {
public: public:
WifiPollingPolicy() {} virtual ~WifiPollingPolicy() = default;
virtual ~WifiPollingPolicy() {}
// Methods for managing the single instance of WifiPollingPolicy. The WiFi
// policy is global so it can outlive the WifiDataProvider instance, which is
// shut down and destroyed when no WiFi scanning is active.
static void Initialize(std::unique_ptr<WifiPollingPolicy>);
static void Shutdown();
static WifiPollingPolicy* Get();
static bool IsInitialized();
// Calculates the new polling interval for wiFi scans, given the previous // Calculates the new polling interval for wiFi scans, given the previous
// interval and whether the last scan produced new results. // interval and whether the last scan produced new results.
virtual void UpdatePollingInterval(bool scan_results_differ) = 0; virtual void UpdatePollingInterval(bool scan_results_differ) = 0;
virtual int PollingInterval() = 0; virtual int PollingInterval() = 0;
virtual int NoWifiInterval() = 0; virtual int NoWifiInterval() = 0;
protected:
WifiPollingPolicy() = default;
private: private:
DISALLOW_COPY_AND_ASSIGN(WifiPollingPolicy); DISALLOW_COPY_AND_ASSIGN(WifiPollingPolicy);
}; };
...@@ -33,6 +48,7 @@ template <int DEFAULT_INTERVAL, ...@@ -33,6 +48,7 @@ template <int DEFAULT_INTERVAL,
class GenericWifiPollingPolicy : public WifiPollingPolicy { class GenericWifiPollingPolicy : public WifiPollingPolicy {
public: public:
GenericWifiPollingPolicy() : polling_interval_(DEFAULT_INTERVAL) {} GenericWifiPollingPolicy() : polling_interval_(DEFAULT_INTERVAL) {}
// WifiPollingPolicy // WifiPollingPolicy
void UpdatePollingInterval(bool scan_results_differ) override { void UpdatePollingInterval(bool scan_results_differ) override {
if (scan_results_differ) { if (scan_results_differ) {
...@@ -45,11 +61,37 @@ class GenericWifiPollingPolicy : public WifiPollingPolicy { ...@@ -45,11 +61,37 @@ class GenericWifiPollingPolicy : public WifiPollingPolicy {
polling_interval_ = TWO_NO_CHANGE_INTERVAL; polling_interval_ = TWO_NO_CHANGE_INTERVAL;
} }
} }
int PollingInterval() override { return polling_interval_; } int PollingInterval() override { return ComputeInterval(polling_interval_); }
int NoWifiInterval() override { return NO_WIFI_INTERVAL; } int NoWifiInterval() override { return ComputeInterval(NO_WIFI_INTERVAL); }
private: private:
int ComputeInterval(int polling_interval) {
base::Time now = base::Time::Now();
int64_t remaining_millis = 0;
if (!next_scan_.is_null()) {
// Compute the remaining duration of the current interval. If the interval
// is not yet complete, we will schedule a scan to occur once it is.
base::TimeDelta remaining = next_scan_ - now;
remaining_millis = remaining.InMilliseconds();
}
// If the current interval is complete (or if this is our first scan), scan
// now and schedule the next scan to occur at |polling_interval|
// milliseconds into the future.
if (remaining_millis <= 0) {
next_scan_ = now + base::TimeDelta::FromMilliseconds(polling_interval);
remaining_millis = 0;
}
return remaining_millis;
}
int polling_interval_; int polling_interval_;
// The scheduled time of the next scan, or a null value if no scan has
// occurred yet.
base::Time next_scan_;
}; };
} // namespace device } // namespace device
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment