| /* |
| * Copyright (C) 2008 Apple Inc. All Rights Reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #ifndef NetworkStateNotifier_h |
| #define NetworkStateNotifier_h |
| |
| #include "core/CoreExport.h" |
| #include "core/dom/ExecutionContext.h" |
| #include "public/platform/WebConnectionType.h" |
| #include "wtf/Allocator.h" |
| #include "wtf/HashMap.h" |
| #include "wtf/Noncopyable.h" |
| #include "wtf/ThreadingPrimitives.h" |
| #include "wtf/Vector.h" |
| #include <memory> |
| |
| namespace blink { |
| |
| class CORE_EXPORT NetworkStateNotifier { |
| WTF_MAKE_NONCOPYABLE(NetworkStateNotifier); |
| USING_FAST_MALLOC(NetworkStateNotifier); |
| |
| public: |
| class NetworkStateObserver { |
| public: |
| // Will be called on the thread of the context passed in addObserver. |
| virtual void connectionChange(WebConnectionType, |
| double maxBandwidthMbps) = 0; |
| }; |
| |
| NetworkStateNotifier() : m_hasOverride(false) {} |
| |
| // Can be called on any thread. |
| bool onLine() const { |
| MutexLocker locker(m_mutex); |
| const NetworkState& state = m_hasOverride ? m_override : m_state; |
| DCHECK(state.onLineInitialized); |
| return state.onLine; |
| } |
| |
| void setOnLine(bool); |
| |
| // Can be called on any thread. |
| WebConnectionType connectionType() const { |
| MutexLocker locker(m_mutex); |
| const NetworkState& state = m_hasOverride ? m_override : m_state; |
| DCHECK(state.connectionInitialized); |
| return state.type; |
| } |
| |
| // Can be called on any thread. |
| bool isCellularConnectionType() const { |
| switch (connectionType()) { |
| case WebConnectionTypeCellular2G: |
| case WebConnectionTypeCellular3G: |
| case WebConnectionTypeCellular4G: |
| return true; |
| case WebConnectionTypeBluetooth: |
| case WebConnectionTypeEthernet: |
| case WebConnectionTypeWifi: |
| case WebConnectionTypeWimax: |
| case WebConnectionTypeOther: |
| case WebConnectionTypeNone: |
| case WebConnectionTypeUnknown: |
| return false; |
| } |
| ASSERT_NOT_REACHED(); |
| return false; |
| } |
| |
| // Can be called on any thread. |
| double maxBandwidth() const { |
| MutexLocker locker(m_mutex); |
| const NetworkState& state = m_hasOverride ? m_override : m_state; |
| DCHECK(state.connectionInitialized); |
| return state.maxBandwidthMbps; |
| } |
| |
| void setWebConnection(WebConnectionType, double maxBandwidthMbps); |
| |
| // When called, successive setWebConnectionType/setOnLine calls are stored, |
| // and supplied overridden values are used instead until clearOverride() is |
| // called. This is used for layout tests (see crbug.com/377736) and inspector |
| // emulation. |
| // |
| // Since this class is a singleton, tests must clear override when completed |
| // to avoid indeterminate state across the test harness. |
| void setOverride(bool onLine, WebConnectionType, double maxBandwidthMbps); |
| void clearOverride(); |
| |
| // Must be called on the context's thread. An added observer must be removed |
| // before its ExecutionContext is deleted. It's possible for an observer to |
| // be called twice for the same event if it is first removed and then added |
| // during notification. |
| void addObserver(NetworkStateObserver*, ExecutionContext*); |
| void removeObserver(NetworkStateObserver*, ExecutionContext*); |
| |
| private: |
| struct ObserverList { |
| ObserverList() : iterating(false) {} |
| bool iterating; |
| Vector<NetworkStateObserver*> observers; |
| Vector<size_t> zeroedObservers; // Indices in observers that are 0. |
| }; |
| |
| struct NetworkState { |
| static const int kInvalidMaxBandwidth = -1; |
| bool onLineInitialized = false; |
| bool onLine = true; |
| bool connectionInitialized = false; |
| WebConnectionType type = WebConnectionTypeOther; |
| double maxBandwidthMbps = kInvalidMaxBandwidth; |
| }; |
| |
| // This helper scope issues required notifications when mutating the state if |
| // something has changed. It's only possible to mutate the state on the main |
| // thread. Note that ScopedNotifier must be destroyed when not holding a lock |
| // so that onLine notifications can be dispatched without a deadlock. |
| class ScopedNotifier { |
| public: |
| explicit ScopedNotifier(NetworkStateNotifier&); |
| ~ScopedNotifier(); |
| |
| private: |
| NetworkStateNotifier& m_notifier; |
| NetworkState m_before; |
| }; |
| |
| // The ObserverListMap is cross-thread accessed, adding/removing Observers |
| // running within an ExecutionContext. Kept off-heap to ease cross-thread |
| // allocation and use; the observers are (already) responsible for explicitly |
| // unregistering while finalizing. |
| using ObserverListMap = |
| HashMap<UntracedMember<ExecutionContext>, std::unique_ptr<ObserverList>>; |
| |
| void notifyObservers(WebConnectionType, double maxBandwidthMbps); |
| void notifyObserversOfConnectionChangeOnContext(WebConnectionType, |
| double maxBandwidthMbps, |
| ExecutionContext*); |
| |
| ObserverList* lockAndFindObserverList(ExecutionContext*); |
| |
| // Removed observers are nulled out in the list in case the list is being |
| // iterated over. Once done iterating, call this to clean up nulled |
| // observers. |
| void collectZeroedObservers(ObserverList*, ExecutionContext*); |
| |
| mutable Mutex m_mutex; |
| NetworkState m_state; |
| bool m_hasOverride; |
| NetworkState m_override; |
| ObserverListMap m_observers; |
| }; |
| |
| CORE_EXPORT NetworkStateNotifier& networkStateNotifier(); |
| |
| } // namespace blink |
| |
| #endif // NetworkStateNotifier_h |