summaryrefslogtreecommitdiffstats
path: root/net/android/network_change_notifier_delegate_android.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/android/network_change_notifier_delegate_android.cc')
-rw-r--r--net/android/network_change_notifier_delegate_android.cc199
1 files changed, 198 insertions, 1 deletions
diff --git a/net/android/network_change_notifier_delegate_android.cc b/net/android/network_change_notifier_delegate_android.cc
index be4c6b1..ea2ba93 100644
--- a/net/android/network_change_notifier_delegate_android.cc
+++ b/net/android/network_change_notifier_delegate_android.cc
@@ -4,6 +4,7 @@
#include "net/android/network_change_notifier_delegate_android.h"
+#include "base/android/jni_array.h"
#include "base/logging.h"
#include "jni/NetworkChangeNotifier_jni.h"
#include "net/android/network_change_notifier_android.h"
@@ -44,6 +45,21 @@ NetworkChangeNotifier::ConnectionSubtype ConvertConnectionSubtype(
} // namespace
+// static
+void NetworkChangeNotifierDelegateAndroid::JavaIntArrayToNetworkMap(
+ JNIEnv* env,
+ jintArray int_array,
+ NetworkMap* network_map) {
+ std::vector<int> int_list;
+ base::android::JavaIntArrayToIntVector(env, int_array, &int_list);
+ network_map->clear();
+ for (auto i = int_list.begin(); i != int_list.end(); ++i) {
+ NetworkChangeNotifier::NetworkHandle network_handle = *i;
+ CHECK(++i != int_list.end());
+ (*network_map)[network_handle] = static_cast<ConnectionType>(*i);
+ }
+}
+
jdouble GetMaxBandwidthForConnectionSubtype(JNIEnv* env,
const JavaParamRef<jclass>& caller,
jint subtype) {
@@ -67,6 +83,14 @@ NetworkChangeNotifierDelegateAndroid::NetworkChangeNotifierDelegateAndroid()
SetCurrentMaxBandwidth(
Java_NetworkChangeNotifier_getCurrentMaxBandwidthInMbps(
env, java_network_change_notifier_.obj()));
+ SetCurrentDefaultNetwork(Java_NetworkChangeNotifier_getCurrentDefaultNetId(
+ env, java_network_change_notifier_.obj()));
+ NetworkMap network_map;
+ ScopedJavaLocalRef<jintArray> networks_and_types =
+ Java_NetworkChangeNotifier_getCurrentNetworksAndTypes(
+ env, java_network_change_notifier_.obj());
+ JavaIntArrayToNetworkMap(env, networks_and_types.obj(), &network_map);
+ SetCurrentNetworksAndTypes(network_map);
}
NetworkChangeNotifierDelegateAndroid::~NetworkChangeNotifierDelegateAndroid() {
@@ -93,14 +117,60 @@ void NetworkChangeNotifierDelegateAndroid::
*max_bandwidth_mbps = connection_max_bandwidth_;
}
+NetworkChangeNotifier::ConnectionType
+NetworkChangeNotifierDelegateAndroid::GetNetworkConnectionType(
+ NetworkChangeNotifier::NetworkHandle network) const {
+ base::AutoLock auto_lock(connection_lock_);
+ auto network_entry = network_map_.find(network);
+ if (network_entry == network_map_.end())
+ return ConnectionType::CONNECTION_UNKNOWN;
+ return network_entry->second;
+}
+
+NetworkChangeNotifier::NetworkHandle
+NetworkChangeNotifierDelegateAndroid::GetCurrentDefaultNetwork() const {
+ base::AutoLock auto_lock(connection_lock_);
+ return default_network_;
+}
+
+void NetworkChangeNotifierDelegateAndroid::GetCurrentlyConnectedNetworks(
+ NetworkList* network_list) const {
+ network_list->clear();
+ base::AutoLock auto_lock(connection_lock_);
+ for (auto i : network_map_)
+ network_list->push_back(i.first);
+}
+
void NetworkChangeNotifierDelegateAndroid::NotifyConnectionTypeChanged(
JNIEnv* env,
jobject obj,
- jint new_connection_type) {
+ jint new_connection_type,
+ jint default_netid) {
DCHECK(thread_checker_.CalledOnValidThread());
const ConnectionType actual_connection_type = ConvertConnectionType(
new_connection_type);
SetCurrentConnectionType(actual_connection_type);
+ NetworkHandle default_network = default_netid;
+ if (default_network != GetCurrentDefaultNetwork()) {
+ SetCurrentDefaultNetwork(default_network);
+ bool default_exists;
+ {
+ base::AutoLock auto_lock(connection_lock_);
+ // |default_network| may be an invalid value (i.e. -1) in cases where
+ // the device is disconnected or when run on Android versions prior to L,
+ // in which case |default_exists| will correctly be false and no
+ // OnNetworkMadeDefault notification will be sent.
+ default_exists = network_map_.find(default_network) != network_map_.end();
+ }
+ // Android Lollipop had race conditions where CONNECTIVITY_ACTION intents
+ // were sent out before the network was actually made the default.
+ // Delay sending the OnNetworkMadeDefault notification until we are
+ // actually notified that the network connected in NotifyOfNetworkConnect.
+ if (default_exists) {
+ observers_->Notify(FROM_HERE, &Observer::OnNetworkMadeDefault,
+ default_network);
+ }
+ }
observers_->Notify(FROM_HERE, &Observer::OnConnectionTypeChanged);
}
@@ -121,6 +191,88 @@ void NetworkChangeNotifierDelegateAndroid::NotifyMaxBandwidthChanged(
new_max_bandwidth, GetCurrentConnectionType());
}
+void NetworkChangeNotifierDelegateAndroid::NotifyOfNetworkConnect(
+ JNIEnv* env,
+ jobject obj,
+ jint net_id,
+ jint connection_type) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ NetworkHandle network = net_id;
+ bool already_exists;
+ {
+ base::AutoLock auto_lock(connection_lock_);
+ already_exists = network_map_.find(network) != network_map_.end();
+ network_map_[network] = static_cast<ConnectionType>(connection_type);
+ }
+ // Android Lollipop would send many duplicate notifications.
+ // This was later fixed in Android Marshmallow.
+ // Deduplicate them here by avoiding sending duplicate notifications.
+ if (!already_exists) {
+ observers_->Notify(FROM_HERE, &Observer::OnNetworkConnected, network);
+ if (network == GetCurrentDefaultNetwork()) {
+ observers_->Notify(FROM_HERE, &Observer::OnNetworkMadeDefault, network);
+ }
+ }
+}
+
+void NetworkChangeNotifierDelegateAndroid::NotifyOfNetworkSoonToDisconnect(
+ JNIEnv* env,
+ jobject obj,
+ jint net_id) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ NetworkHandle network = net_id;
+ {
+ base::AutoLock auto_lock(connection_lock_);
+ if (network_map_.find(network) == network_map_.end())
+ return;
+ }
+ observers_->Notify(FROM_HERE, &Observer::OnNetworkSoonToDisconnect, network);
+}
+
+void NetworkChangeNotifierDelegateAndroid::NotifyOfNetworkDisconnect(
+ JNIEnv* env,
+ jobject obj,
+ jint net_id) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ NetworkHandle network = net_id;
+ {
+ base::AutoLock auto_lock(connection_lock_);
+ if (network == default_network_)
+ default_network_ = NetworkChangeNotifier::kInvalidNetworkHandle;
+ if (network_map_.erase(network) == 0)
+ return;
+ }
+ observers_->Notify(FROM_HERE, &Observer::OnNetworkDisconnected, network);
+}
+
+void NetworkChangeNotifierDelegateAndroid::NotifyUpdateActiveNetworkList(
+ JNIEnv* env,
+ jobject obj,
+ jintArray active_networks) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ NetworkList active_network_list;
+ base::android::JavaIntArrayToIntVector(env, active_networks,
+ &active_network_list);
+ NetworkList disconnected_networks;
+ {
+ base::AutoLock auto_lock(connection_lock_);
+ for (auto i : network_map_) {
+ bool found = false;
+ for (auto j : active_network_list) {
+ if (j == i.first) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ disconnected_networks.push_back(i.first);
+ }
+ }
+ }
+ for (auto disconnected_network : disconnected_networks)
+ NotifyOfNetworkDisconnect(env, obj, disconnected_network);
+}
+
void NetworkChangeNotifierDelegateAndroid::AddObserver(
Observer* observer) {
observers_->AddObserver(observer);
@@ -148,6 +300,18 @@ void NetworkChangeNotifierDelegateAndroid::SetCurrentMaxBandwidth(
connection_max_bandwidth_ = max_bandwidth;
}
+void NetworkChangeNotifierDelegateAndroid::SetCurrentDefaultNetwork(
+ NetworkHandle default_network) {
+ base::AutoLock auto_lock(connection_lock_);
+ default_network_ = default_network;
+}
+
+void NetworkChangeNotifierDelegateAndroid::SetCurrentNetworksAndTypes(
+ NetworkMap network_map) {
+ base::AutoLock auto_lock(connection_lock_);
+ network_map_ = network_map;
+}
+
void NetworkChangeNotifierDelegateAndroid::SetOnline() {
JNIEnv* env = base::android::AttachCurrentThread();
Java_NetworkChangeNotifier_forceConnectivityState(env, true);
@@ -158,4 +322,37 @@ void NetworkChangeNotifierDelegateAndroid::SetOffline() {
Java_NetworkChangeNotifier_forceConnectivityState(env, false);
}
+void NetworkChangeNotifierDelegateAndroid::FakeNetworkConnected(
+ NetworkChangeNotifier::NetworkHandle network,
+ ConnectionType type) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_NetworkChangeNotifier_fakeNetworkConnected(env, network, type);
+}
+
+void NetworkChangeNotifierDelegateAndroid::FakeNetworkSoonToBeDisconnected(
+ NetworkChangeNotifier::NetworkHandle network) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_NetworkChangeNotifier_fakeNetworkSoonToBeDisconnected(env, network);
+}
+
+void NetworkChangeNotifierDelegateAndroid::FakeNetworkDisconnected(
+ NetworkChangeNotifier::NetworkHandle network) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_NetworkChangeNotifier_fakeNetworkDisconnected(env, network);
+}
+
+void NetworkChangeNotifierDelegateAndroid::FakeUpdateActiveNetworkList(
+ NetworkChangeNotifier::NetworkList networks) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_NetworkChangeNotifier_fakeUpdateActiveNetworkList(
+ env, base::android::ToJavaIntArray(env, networks).obj());
+}
+
+void NetworkChangeNotifierDelegateAndroid::FakeDefaultNetwork(
+ NetworkChangeNotifier::NetworkHandle network,
+ ConnectionType type) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_NetworkChangeNotifier_fakeDefaultNetwork(env, network, type);
+}
+
} // namespace net