Commit 10f13475 authored by Lei Zhang's avatar Lei Zhang Committed by Commit Bot

Make PrivetTrafficDetector live on the UI thread.

Split all IO thread code into a separate helper class. Now there is no
refcounting, so ownership is clearer. Now only the helper class has a
WeakPtrFactory, so WeakPtrs are only used on the IO thread.

BUG=873529

Change-Id: I326aa6f69839c193507df4c63250aa1560bbd0ef
Reviewed-on: https://chromium-review.googlesource.com/1177444
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: default avatarRobbie McElrath <rmcelrath@chromium.org>
Cr-Commit-Position: refs/heads/master@{#583813}
parent dbc446be
...@@ -210,10 +210,6 @@ PrivetNotificationService::PrivetNotificationService( ...@@ -210,10 +210,6 @@ PrivetNotificationService::PrivetNotificationService(
PrivetNotificationService::~PrivetNotificationService() { PrivetNotificationService::~PrivetNotificationService() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
#if BUILDFLAG(ENABLE_MDNS)
if (traffic_detector_)
traffic_detector_->Stop();
#endif
} }
void PrivetNotificationService::DeviceChanged( void PrivetNotificationService::DeviceChanged(
...@@ -329,18 +325,15 @@ void PrivetNotificationService::Start() { ...@@ -329,18 +325,15 @@ void PrivetNotificationService::Start() {
void PrivetNotificationService::OnNotificationsEnabledChanged() { void PrivetNotificationService::OnNotificationsEnabledChanged() {
#if BUILDFLAG(ENABLE_MDNS) #if BUILDFLAG(ENABLE_MDNS)
if (traffic_detector_) traffic_detector_.reset();
traffic_detector_->Stop();
traffic_detector_ = nullptr;
if (IsForced()) { if (IsForced()) {
StartLister(); StartLister();
} else if (*enable_privet_notification_member_) { } else if (*enable_privet_notification_member_) {
ReportPrivetUmaEvent(PRIVET_SERVICE_STARTED); ReportPrivetUmaEvent(PRIVET_SERVICE_STARTED);
traffic_detector_ = base::MakeRefCounted<PrivetTrafficDetector>( traffic_detector_ = std::make_unique<PrivetTrafficDetector>(
profile_, base::BindRepeating(&PrivetNotificationService::StartLister, profile_, base::BindRepeating(&PrivetNotificationService::StartLister,
AsWeakPtr())); AsWeakPtr()));
traffic_detector_->Start();
} else { } else {
device_lister_.reset(); device_lister_.reset();
service_discovery_client_ = nullptr; service_discovery_client_ = nullptr;
......
...@@ -140,7 +140,7 @@ class PrivetNotificationService ...@@ -140,7 +140,7 @@ class PrivetNotificationService
BooleanPrefMember enable_privet_notification_member_; BooleanPrefMember enable_privet_notification_member_;
#if BUILDFLAG(ENABLE_MDNS) #if BUILDFLAG(ENABLE_MDNS)
scoped_refptr<PrivetTrafficDetector> traffic_detector_; std::unique_ptr<PrivetTrafficDetector> traffic_detector_;
#endif #endif
}; };
......
...@@ -7,12 +7,12 @@ ...@@ -7,12 +7,12 @@
#include <utility> #include <utility>
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
#include "base/sys_byteorder.h" #include "base/sys_byteorder.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "base/threading/thread_restrictions.h" #include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/network_service_instance.h" #include "content/public/browser/network_service_instance.h"
#include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_partition.h"
#include "net/base/address_family.h" #include "net/base/address_family.h"
...@@ -73,33 +73,47 @@ namespace cloud_print { ...@@ -73,33 +73,47 @@ namespace cloud_print {
PrivetTrafficDetector::PrivetTrafficDetector( PrivetTrafficDetector::PrivetTrafficDetector(
content::BrowserContext* profile, content::BrowserContext* profile,
const base::RepeatingClosure& on_traffic_detected) const base::RepeatingClosure& on_traffic_detected)
: on_traffic_detected_(on_traffic_detected), : helper_(new Helper(profile, on_traffic_detected)) {
restart_attempts_(kMaxRestartAttempts),
receiver_binding_(this),
profile_(profile),
weak_ptr_factory_(this) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::BindOnce(&PrivetTrafficDetector::Helper::ScheduleRestart,
base::Unretained(helper_)));
} }
PrivetTrafficDetector::~PrivetTrafficDetector() { PrivetTrafficDetector::~PrivetTrafficDetector() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this);
content::BrowserThread::DeleteSoon(content::BrowserThread::IO, FROM_HERE,
helper_);
} }
void PrivetTrafficDetector::Start() { void PrivetTrafficDetector::OnConnectionChanged(
network::mojom::ConnectionType type) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE, content::BrowserThread::IO, FROM_HERE,
base::BindOnce(&PrivetTrafficDetector::ScheduleRestart, base::BindOnce(&PrivetTrafficDetector::Helper::HandleConnectionChanged,
weak_ptr_factory_.GetWeakPtr())); base::Unretained(helper_), type));
} }
void PrivetTrafficDetector::Stop() { PrivetTrafficDetector::Helper::Helper(
content::BrowserContext* profile,
const base::RepeatingClosure& on_traffic_detected)
: profile_(profile),
on_traffic_detected_(on_traffic_detected),
restart_attempts_(kMaxRestartAttempts),
receiver_binding_(this),
weak_ptr_factory_(this) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this);
} }
void PrivetTrafficDetector::HandleConnectionChanged( PrivetTrafficDetector::Helper::~Helper() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
}
void PrivetTrafficDetector::Helper::HandleConnectionChanged(
network::mojom::ConnectionType type) { network::mojom::ConnectionType type) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
restart_attempts_ = kMaxRestartAttempts; restart_attempts_ = kMaxRestartAttempts;
...@@ -108,25 +122,26 @@ void PrivetTrafficDetector::HandleConnectionChanged( ...@@ -108,25 +122,26 @@ void PrivetTrafficDetector::HandleConnectionChanged(
} }
} }
void PrivetTrafficDetector::ScheduleRestart() { void PrivetTrafficDetector::Helper::ScheduleRestart() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
ResetConnection(); ResetConnection();
weak_ptr_factory_.InvalidateWeakPtrs(); weak_ptr_factory_.InvalidateWeakPtrs();
base::PostDelayedTaskWithTraits( base::PostDelayedTaskWithTraits(
FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()}, FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
base::BindOnce(&GetNetworkListInBackground, base::BindOnce(
base::BindOnce(&PrivetTrafficDetector::Restart, &GetNetworkListInBackground,
weak_ptr_factory_.GetWeakPtr())), base::BindOnce(&Helper::Restart, weak_ptr_factory_.GetWeakPtr())),
base::TimeDelta::FromSeconds(3)); base::TimeDelta::FromSeconds(3));
} }
void PrivetTrafficDetector::Restart(net::NetworkInterfaceList networks) { void PrivetTrafficDetector::Helper::Restart(
net::NetworkInterfaceList networks) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
networks_ = std::move(networks); networks_ = std::move(networks);
Bind(); Bind();
} }
void PrivetTrafficDetector::Bind() { void PrivetTrafficDetector::Helper::Bind() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (!start_time_.is_null()) { if (!start_time_.is_null()) {
base::TimeDelta time_delta = base::Time::Now() - start_time_; base::TimeDelta time_delta = base::Time::Now() - start_time_;
...@@ -155,19 +170,19 @@ void PrivetTrafficDetector::Bind() { ...@@ -155,19 +170,19 @@ void PrivetTrafficDetector::Bind() {
socket_options->multicast_loopback_mode = false; socket_options->multicast_loopback_mode = false;
socket_->Bind(bind_endpoint, std::move(socket_options), socket_->Bind(bind_endpoint, std::move(socket_options),
base::BindOnce(&PrivetTrafficDetector::OnBindComplete, this, base::BindOnce(&Helper::OnBindComplete,
multicast_addr)); weak_ptr_factory_.GetWeakPtr(), multicast_addr));
} }
void PrivetTrafficDetector::OnBindComplete( void PrivetTrafficDetector::Helper::OnBindComplete(
net::IPEndPoint multicast_addr, net::IPEndPoint multicast_addr,
int rv, int rv,
const base::Optional<net::IPEndPoint>& ip_endpoint) { const base::Optional<net::IPEndPoint>& ip_endpoint) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (rv == net::OK) { if (rv == net::OK) {
socket_->JoinGroup( socket_->JoinGroup(multicast_addr.address(),
multicast_addr.address(), base::BindOnce(&Helper::OnJoinGroupComplete,
base::BindOnce(&PrivetTrafficDetector::OnJoinGroupComplete, this)); weak_ptr_factory_.GetWeakPtr()));
return; return;
} }
...@@ -175,7 +190,7 @@ void PrivetTrafficDetector::OnBindComplete( ...@@ -175,7 +190,7 @@ void PrivetTrafficDetector::OnBindComplete(
ScheduleRestart(); ScheduleRestart();
} }
bool PrivetTrafficDetector::IsSourceAcceptable() const { bool PrivetTrafficDetector::Helper::IsSourceAcceptable() const {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
for (const auto& network : networks_) { for (const auto& network : networks_) {
if (net::IPAddressMatchesPrefix(recv_addr_.address(), network.address, if (net::IPAddressMatchesPrefix(recv_addr_.address(), network.address,
...@@ -186,7 +201,7 @@ bool PrivetTrafficDetector::IsSourceAcceptable() const { ...@@ -186,7 +201,7 @@ bool PrivetTrafficDetector::IsSourceAcceptable() const {
return false; return false;
} }
bool PrivetTrafficDetector::IsPrivetPacket( bool PrivetTrafficDetector::Helper::IsPrivetPacket(
base::span<const uint8_t> data) const { base::span<const uint8_t> data) const {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (data.size() <= sizeof(net::dns_protocol::Header) || if (data.size() <= sizeof(net::dns_protocol::Header) ||
...@@ -211,7 +226,7 @@ bool PrivetTrafficDetector::IsPrivetPacket( ...@@ -211,7 +226,7 @@ bool PrivetTrafficDetector::IsPrivetPacket(
substring_end) != buffer_end; substring_end) != buffer_end;
} }
void PrivetTrafficDetector::OnJoinGroupComplete(int rv) { void PrivetTrafficDetector::Helper::OnJoinGroupComplete(int rv) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (rv == net::OK) { if (rv == net::OK) {
// Reset on success. // Reset on success.
...@@ -224,22 +239,13 @@ void PrivetTrafficDetector::OnJoinGroupComplete(int rv) { ...@@ -224,22 +239,13 @@ void PrivetTrafficDetector::OnJoinGroupComplete(int rv) {
ScheduleRestart(); ScheduleRestart();
} }
void PrivetTrafficDetector::ResetConnection() { void PrivetTrafficDetector::Helper::ResetConnection() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
socket_.reset(); socket_.reset();
receiver_binding_.Close(); receiver_binding_.Close();
} }
void PrivetTrafficDetector::OnConnectionChanged( void PrivetTrafficDetector::Helper::OnReceived(
network::mojom::ConnectionType type) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::BindOnce(&PrivetTrafficDetector::HandleConnectionChanged,
weak_ptr_factory_.GetWeakPtr(), type));
}
void PrivetTrafficDetector::OnReceived(
int32_t result, int32_t result,
const base::Optional<net::IPEndPoint>& src_addr, const base::Optional<net::IPEndPoint>& src_addr,
base::Optional<base::span<const uint8_t>> data) { base::Optional<base::span<const uint8_t>> data) {
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/macros.h" #include "base/macros.h"
#include "content/public/browser/browser_thread.h"
#include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/binding.h"
#include "net/base/ip_endpoint.h" #include "net/base/ip_endpoint.h"
#include "services/network/public/cpp/network_connection_tracker.h" #include "services/network/public/cpp/network_connection_tracker.h"
...@@ -28,69 +27,70 @@ namespace cloud_print { ...@@ -28,69 +27,70 @@ namespace cloud_print {
// listening for traffic. // listening for traffic.
// When the network changes, restarts itself to start listening for traffic // When the network changes, restarts itself to start listening for traffic
// again on the new network(s). // again on the new network(s).
// The class lives on the UI thread, with a helper that lives on the IO thread.
class PrivetTrafficDetector class PrivetTrafficDetector
: public base::RefCountedThreadSafe< : public network::NetworkConnectionTracker::NetworkConnectionObserver {
PrivetTrafficDetector,
content::BrowserThread::DeleteOnIOThread>,
private network::NetworkConnectionTracker::NetworkConnectionObserver,
public network::mojom::UDPSocketReceiver {
public: public:
// Called on the UI thread. // Called on the UI thread.
PrivetTrafficDetector(content::BrowserContext* profile, PrivetTrafficDetector(content::BrowserContext* profile,
const base::RepeatingClosure& on_traffic_detected); const base::RepeatingClosure& on_traffic_detected);
// Called on the UI thread.
void Start();
void Stop();
private:
friend struct content::BrowserThread::DeleteOnThread<
content::BrowserThread::IO>;
friend class base::DeleteHelper<PrivetTrafficDetector>;
~PrivetTrafficDetector() override; ~PrivetTrafficDetector() override;
// Unless otherwise noted, all methods are called on the IO thread.
void HandleConnectionChanged(network::mojom::ConnectionType type);
void ScheduleRestart();
void Restart(net::NetworkInterfaceList networks);
void Bind();
void OnBindComplete(net::IPEndPoint multicast_addr,
int rv,
const base::Optional<net::IPEndPoint>& ip_address);
bool IsSourceAcceptable() const;
bool IsPrivetPacket(base::span<const uint8_t> data) const;
void OnJoinGroupComplete(int rv);
void ResetConnection();
// network::NetworkConnectionTracker::NetworkConnectionObserver: // network::NetworkConnectionTracker::NetworkConnectionObserver:
// Called on the UI thread.
void OnConnectionChanged(network::mojom::ConnectionType type) override; void OnConnectionChanged(network::mojom::ConnectionType type) override;
// network::mojom::UDPSocketReceiver implementation private:
void OnReceived(int32_t result, // Constructed by PrivetTrafficDetector on the UI thread. but lives on the IO
const base::Optional<net::IPEndPoint>& src_addr, // thread and destroyed on the IO thread.
base::Optional<base::span<const uint8_t>> data) override; class Helper : public network::mojom::UDPSocketReceiver {
public:
// Initialized on the UI thread, but only accessed on the IO thread. Helper(content::BrowserContext* profile,
base::RepeatingClosure on_traffic_detected_; const base::RepeatingClosure& on_traffic_detected);
int restart_attempts_; ~Helper() override;
// Only accessed on the IO thread. // network::mojom::UDPSocketReceiver:
net::NetworkInterfaceList networks_; void OnReceived(int32_t result,
net::IPEndPoint recv_addr_; const base::Optional<net::IPEndPoint>& src_addr,
base::Time start_time_; base::Optional<base::span<const uint8_t>> data) override;
network::mojom::UDPSocketPtr socket_;
void HandleConnectionChanged(network::mojom::ConnectionType type);
// Implementation of socket receiver callback. void ScheduleRestart();
// Initialized on the UI thread, but only accessed on the IO thread.
mojo::Binding<network::mojom::UDPSocketReceiver> receiver_binding_; private:
void Restart(net::NetworkInterfaceList networks);
// Initialized on the UI thread, but only accessed on the IO thread for the void Bind();
// purpose of passing it back to the UI thread. Safe because it is const. void OnBindComplete(net::IPEndPoint multicast_addr,
content::BrowserContext* const profile_; int rv,
const base::Optional<net::IPEndPoint>& ip_address);
base::WeakPtrFactory<PrivetTrafficDetector> weak_ptr_factory_; bool IsSourceAcceptable() const;
bool IsPrivetPacket(base::span<const uint8_t> data) const;
void OnJoinGroupComplete(int rv);
void ResetConnection();
// Initialized on the UI thread, but only accessed on the IO thread for the
// purpose of passing it back to the UI thread. Safe because it is const.
content::BrowserContext* const profile_;
// Initialized on the UI thread, but only accessed on the IO thread.
base::RepeatingClosure on_traffic_detected_;
int restart_attempts_;
// Only accessed on the IO thread.
net::NetworkInterfaceList networks_;
net::IPEndPoint recv_addr_;
base::Time start_time_;
network::mojom::UDPSocketPtr socket_;
// Implementation of socket receiver callback.
// Initialized on the UI thread, but only accessed on the IO thread.
mojo::Binding<network::mojom::UDPSocketReceiver> receiver_binding_;
base::WeakPtrFactory<Helper> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(Helper);
};
Helper* const helper_;
DISALLOW_COPY_AND_ASSIGN(PrivetTrafficDetector); DISALLOW_COPY_AND_ASSIGN(PrivetTrafficDetector);
}; };
......
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