Commit 84fe619b authored by btolsch's avatar btolsch Committed by Commit Bot

Remove UI thread WeakPtrFactory from DialService

A previous change to use the network service introduced two
WeakPtrFactory members to DialServiceImpl.  Although this gets around
the advice to only use WeakPtrs from one factory on a single sequence,
it doesn't actually solve the problem: ~DialServiceImpl still runs on
the IO thread, which may cause some UI thread WeakPtrs to be
invalidated, resulting in a DCHECK (or a race).  The UI thread doesn't
actually need any of DialServiceImpl's data though, so this change just
makes the functions previously using it into free functions which then
call back onto the IO thread with a proper WeakPtr.

Bug: 934611, 936531
Change-Id: Iee1612cd9934bef109bbfa79d497685dbd275d8a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1504980
Commit-Queue: Brandon Tolsch <btolsch@chromium.org>
Reviewed-by: default avatarmark a. foltz <mfoltz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#638283}
parent 901ef74c
...@@ -58,6 +58,17 @@ using net::UDPSocket; ...@@ -58,6 +58,17 @@ using net::UDPSocket;
namespace media_router { namespace media_router {
#if !defined(OS_CHROMEOS)
void PostSendNetworkList(
base::WeakPtr<DialServiceImpl> impl,
const base::Optional<net::NetworkInterfaceList>& networks) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::PostTaskWithTraits(FROM_HERE, {BrowserThread::IO},
base::BindOnce(&DialServiceImpl::SendNetworkList,
std::move(impl), networks));
}
#endif // !defined(OS_CHROMEOS)
namespace { namespace {
// The total number of requests to make per discovery cycle. // The total number of requests to make per discovery cycle.
...@@ -153,6 +164,24 @@ net::IPAddressList GetBestBindAddressOnUIThread() { ...@@ -153,6 +164,24 @@ net::IPAddressList GetBestBindAddressOnUIThread() {
} }
return bind_address_list; return bind_address_list;
} }
#else
// This function and PostSendNetworkList together handle DialServiceImpl's use
// of the network service, while keeping all of DialServiceImpl running on the
// IO thread. DialServiceImpl has a legacy threading model, where it was
// designed to be called from the UI thread and run on the IO thread. Although
// a WeakPtr is desired for safety when posting tasks, they are not
// thread/sequence-safe. DialServiceImpl's simple use of the network service,
// however, doesn't actually require that any of its state be accessed on the UI
// thread. Therefore, the UI thread functions can be free functions which just
// pass-through an IO thread WeakPtr which will be used when passing the network
// service result back to the IO thread. This model will change when the
// network service is fully launched and this code is updated.
void GetNetworkListOnUIThread(base::WeakPtr<DialServiceImpl> impl) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
content::GetNetworkService()->GetNetworkList(
net::INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES,
base::BindOnce(&PostSendNetworkList, std::move(impl)));
}
#endif // defined(OS_CHROMEOS) #endif // defined(OS_CHROMEOS)
} // namespace } // namespace
...@@ -385,6 +414,7 @@ DialServiceImpl::DialServiceImpl(net::NetLog* net_log) ...@@ -385,6 +414,7 @@ DialServiceImpl::DialServiceImpl(net::NetLog* net_log)
TimeDelta::FromSeconds(kDialResponseTimeoutSecs)), TimeDelta::FromSeconds(kDialResponseTimeoutSecs)),
request_interval_( request_interval_(
TimeDelta::FromMilliseconds(kDialRequestIntervalMillis)) { TimeDelta::FromMilliseconds(kDialRequestIntervalMillis)) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
IPAddress address; IPAddress address;
bool success = address.AssignFromIPLiteral(kDialRequestAddress); bool success = address.AssignFromIPLiteral(kDialRequestAddress);
DCHECK(success); DCHECK(success);
...@@ -443,69 +473,55 @@ void DialServiceImpl::StartDiscovery() { ...@@ -443,69 +473,55 @@ void DialServiceImpl::StartDiscovery() {
base::BindOnce(&DialServiceImpl::DiscoverOnAddresses, base::BindOnce(&DialServiceImpl::DiscoverOnAddresses,
base::Unretained(this))); base::Unretained(this)));
#else #else
task_tracker_.PostTask( task_tracker_.PostTask(task_runner.get(), FROM_HERE,
task_runner.get(), FROM_HERE, base::BindOnce(&GetNetworkListOnUIThread,
base::BindOnce(&DialServiceImpl::GetNetworkListOnUIThread, weak_ptr_factory_.GetWeakPtr()));
base::Unretained(this)));
#endif #endif
} }
void DialServiceImpl::GetNetworkListOnUIThread() { void DialServiceImpl::SendNetworkList(
DCHECK_CURRENTLY_ON(BrowserThread::UI); const base::Optional<NetworkInterfaceList>& networks) {
content::GetNetworkService()->GetNetworkList(
net::INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES,
base::BindOnce(&DialServiceImpl::PostSendNetworkList,
weak_ptr_factory_for_ui_.GetWeakPtr()));
}
void DialServiceImpl::PostSendNetworkList(
const base::Optional<net::NetworkInterfaceList>& networks) {
if (!networks.has_value())
VLOG(1) << "Could not retrieve network list!";
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(
&DialServiceImpl::SendNetworkList,
weak_ptr_factory_for_io_.GetWeakPtr(),
networks.has_value() ? *networks : net::NetworkInterfaceList()));
}
void DialServiceImpl::SendNetworkList(const NetworkInterfaceList& networks) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
using InterfaceIndexAddressFamily = std::pair<uint32_t, net::AddressFamily>; using InterfaceIndexAddressFamily = std::pair<uint32_t, net::AddressFamily>;
std::set<InterfaceIndexAddressFamily> interface_index_addr_family_seen; std::set<InterfaceIndexAddressFamily> interface_index_addr_family_seen;
net::IPAddressList ip_addresses; net::IPAddressList ip_addresses;
// Binds a socket to each IPv4 network interface found. Note that if (networks.has_value()) {
// there may be duplicates in |networks|, so address family + interface index // Binds a socket to each IPv4 network interface found. Note that
// is used to identify unique interfaces. // there may be duplicates in |networks|, so address family + interface
// TODO(mfoltz): Support IPV6 multicast. http://crbug.com/165286 // index is used to identify unique interfaces.
for (const auto& network : networks) { // TODO(mfoltz): Support IPV6 multicast. http://crbug.com/165286
net::AddressFamily addr_family = net::GetAddressFamily(network.address); for (const auto& network : *networks) {
VLOG(2) << "Found " << network.name << ", " << network.address.ToString() net::AddressFamily addr_family = net::GetAddressFamily(network.address);
<< ", address family: " << addr_family; VLOG(2) << "Found " << network.name << ", " << network.address.ToString()
if (addr_family == net::ADDRESS_FAMILY_IPV4) { << ", address family: " << addr_family;
InterfaceIndexAddressFamily interface_index_addr_family = if (addr_family == net::ADDRESS_FAMILY_IPV4) {
std::make_pair(network.interface_index, addr_family); InterfaceIndexAddressFamily interface_index_addr_family =
bool inserted = std::make_pair(network.interface_index, addr_family);
interface_index_addr_family_seen.insert(interface_index_addr_family) bool inserted =
.second; interface_index_addr_family_seen.insert(interface_index_addr_family)
// We have not seen this interface before, so add its IP address to the .second;
// discovery list. // We have not seen this interface before, so add its IP address to the
if (inserted) { // discovery list.
VLOG(2) << "Encountered " if (inserted) {
<< "interface index: " << network.interface_index << ", " VLOG(2) << "Encountered "
<< "address family: " << addr_family << " for the first time, " << "interface index: " << network.interface_index << ", "
<< "adding IP address " << network.address.ToString() << "address family: " << addr_family
<< " to list."; << " for the first time, "
ip_addresses.push_back(network.address); << "adding IP address " << network.address.ToString()
} else { << " to list.";
VLOG(2) << "Already encountered " ip_addresses.push_back(network.address);
<< "interface index: " << network.interface_index << ", " } else {
<< "address family: " << addr_family << " before, not adding."; VLOG(2) << "Already encountered "
<< "interface index: " << network.interface_index << ", "
<< "address family: " << addr_family
<< " before, not adding.";
}
} }
} }
} else {
VLOG(1) << "Could not retrieve network list!";
} }
DiscoverOnAddresses(ip_addresses); DiscoverOnAddresses(ip_addresses);
......
...@@ -21,7 +21,7 @@ namespace net { ...@@ -21,7 +21,7 @@ namespace net {
class IPEndPoint; class IPEndPoint;
class StringIOBuffer; class StringIOBuffer;
class NetLog; class NetLog;
} } // namespace net
namespace media_router { namespace media_router {
...@@ -106,6 +106,10 @@ class DialServiceImpl : public DialService { ...@@ -106,6 +106,10 @@ class DialServiceImpl : public DialService {
bool HasObserver(const Observer* observer) const override; bool HasObserver(const Observer* observer) const override;
private: private:
friend void PostSendNetworkList(
base::WeakPtr<DialServiceImpl> impl,
const base::Optional<net::NetworkInterfaceList>& networks);
// Represents a socket binding to a single network interface. // Represents a socket binding to a single network interface.
// DialSocket lives on the IO thread. // DialSocket lives on the IO thread.
class DialSocket { class DialSocket {
...@@ -185,16 +189,9 @@ class DialServiceImpl : public DialService { ...@@ -185,16 +189,9 @@ class DialServiceImpl : public DialService {
// Starts the control flow for one discovery cycle. // Starts the control flow for one discovery cycle.
void StartDiscovery(); void StartDiscovery();
// Task to retrieve networks on UI thread.
void GetNetworkListOnUIThread();
// Callback invoked to send retrieved networks on IO thread.
void PostSendNetworkList(
const base::Optional<net::NetworkInterfaceList>& networks);
// For each network interface in |list|, finds all unqiue IPv4 network // For each network interface in |list|, finds all unqiue IPv4 network
// interfaces and call |DiscoverOnAddresses()| with their IP addresses. // interfaces and call |DiscoverOnAddresses()| with their IP addresses.
void SendNetworkList(const net::NetworkInterfaceList& list); void SendNetworkList(const base::Optional<net::NetworkInterfaceList>& list);
// Calls |BindAndAddSocket()| for each address in |ip_addresses|, calls // Calls |BindAndAddSocket()| for each address in |ip_addresses|, calls
// |SendOneRequest()|, and start the timer to finish discovery if needed. // |SendOneRequest()|, and start the timer to finish discovery if needed.
...@@ -269,11 +266,8 @@ class DialServiceImpl : public DialService { ...@@ -269,11 +266,8 @@ class DialServiceImpl : public DialService {
base::CancelableTaskTracker task_tracker_; base::CancelableTaskTracker task_tracker_;
// WeakPrtFactory for WeakPtrs that are invalidated on UI thread. // WeakPtrFactory for WeakPtrs that are invalidated on IO thread.
base::WeakPtrFactory<DialServiceImpl> weak_ptr_factory_for_ui_{this}; base::WeakPtrFactory<DialServiceImpl> weak_ptr_factory_{this};
// WeakPrtFactory for WeakPtrs that are invalidated on IO thread.
base::WeakPtrFactory<DialServiceImpl> weak_ptr_factory_for_io_{this};
friend class DialServiceTest; friend class DialServiceTest;
FRIEND_TEST_ALL_PREFIXES(DialServiceTest, TestSendMultipleRequests); FRIEND_TEST_ALL_PREFIXES(DialServiceTest, TestSendMultipleRequests);
......
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