mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-12-01 01:36:09 +03:00
361 lines
13 KiB
C++
361 lines
13 KiB
C++
|
// Copyright (c) 2012 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 "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"
|
||
|
|
||
|
using base::android::JavaParamRef;
|
||
|
using base::android::ScopedJavaLocalRef;
|
||
|
|
||
|
namespace net {
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
// Converts a Java side connection type (integer) to
|
||
|
// the native side NetworkChangeNotifier::ConnectionType.
|
||
|
NetworkChangeNotifier::ConnectionType ConvertConnectionType(
|
||
|
jint connection_type) {
|
||
|
switch (connection_type) {
|
||
|
case NetworkChangeNotifier::CONNECTION_UNKNOWN:
|
||
|
case NetworkChangeNotifier::CONNECTION_ETHERNET:
|
||
|
case NetworkChangeNotifier::CONNECTION_WIFI:
|
||
|
case NetworkChangeNotifier::CONNECTION_2G:
|
||
|
case NetworkChangeNotifier::CONNECTION_3G:
|
||
|
case NetworkChangeNotifier::CONNECTION_4G:
|
||
|
case NetworkChangeNotifier::CONNECTION_NONE:
|
||
|
case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
|
||
|
break;
|
||
|
default:
|
||
|
NOTREACHED() << "Unknown connection type received: " << connection_type;
|
||
|
return NetworkChangeNotifier::CONNECTION_UNKNOWN;
|
||
|
}
|
||
|
return static_cast<NetworkChangeNotifier::ConnectionType>(connection_type);
|
||
|
}
|
||
|
|
||
|
// Converts a Java side connection type (integer) to
|
||
|
// the native side NetworkChangeNotifier::ConnectionType.
|
||
|
NetworkChangeNotifier::ConnectionSubtype ConvertConnectionSubtype(
|
||
|
jint subtype) {
|
||
|
DCHECK(subtype >= 0 && subtype <= NetworkChangeNotifier::SUBTYPE_LAST);
|
||
|
|
||
|
return static_cast<NetworkChangeNotifier::ConnectionSubtype>(subtype);
|
||
|
}
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
// static
|
||
|
void NetworkChangeNotifierDelegateAndroid::JavaLongArrayToNetworkMap(
|
||
|
JNIEnv* env,
|
||
|
jlongArray long_array,
|
||
|
NetworkMap* network_map) {
|
||
|
std::vector<int64_t> int64_list;
|
||
|
base::android::JavaLongArrayToInt64Vector(env, long_array, &int64_list);
|
||
|
network_map->clear();
|
||
|
for (auto i = int64_list.begin(); i != int64_list.end(); ++i) {
|
||
|
NetworkChangeNotifier::NetworkHandle network_handle = *i;
|
||
|
CHECK(++i != int64_list.end());
|
||
|
(*network_map)[network_handle] = static_cast<ConnectionType>(*i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
NetworkChangeNotifierDelegateAndroid::NetworkChangeNotifierDelegateAndroid()
|
||
|
: observers_(new base::ObserverListThreadSafe<Observer>()) {
|
||
|
JNIEnv* env = base::android::AttachCurrentThread();
|
||
|
java_network_change_notifier_.Reset(Java_NetworkChangeNotifier_init(env));
|
||
|
Java_NetworkChangeNotifier_addNativeObserver(
|
||
|
env, java_network_change_notifier_, reinterpret_cast<intptr_t>(this));
|
||
|
SetCurrentConnectionType(
|
||
|
ConvertConnectionType(Java_NetworkChangeNotifier_getCurrentConnectionType(
|
||
|
env, java_network_change_notifier_)));
|
||
|
SetCurrentMaxBandwidth(
|
||
|
NetworkChangeNotifierAndroid::GetMaxBandwidthForConnectionSubtype(
|
||
|
GetCurrentConnectionSubtype()));
|
||
|
SetCurrentDefaultNetwork(Java_NetworkChangeNotifier_getCurrentDefaultNetId(
|
||
|
env, java_network_change_notifier_));
|
||
|
NetworkMap network_map;
|
||
|
ScopedJavaLocalRef<jlongArray> networks_and_types =
|
||
|
Java_NetworkChangeNotifier_getCurrentNetworksAndTypes(
|
||
|
env, java_network_change_notifier_);
|
||
|
JavaLongArrayToNetworkMap(env, networks_and_types.obj(), &network_map);
|
||
|
SetCurrentNetworksAndTypes(network_map);
|
||
|
}
|
||
|
|
||
|
NetworkChangeNotifierDelegateAndroid::~NetworkChangeNotifierDelegateAndroid() {
|
||
|
DCHECK(thread_checker_.CalledOnValidThread());
|
||
|
observers_->AssertEmpty();
|
||
|
JNIEnv* env = base::android::AttachCurrentThread();
|
||
|
Java_NetworkChangeNotifier_removeNativeObserver(
|
||
|
env, java_network_change_notifier_, reinterpret_cast<intptr_t>(this));
|
||
|
}
|
||
|
|
||
|
NetworkChangeNotifier::ConnectionType
|
||
|
NetworkChangeNotifierDelegateAndroid::GetCurrentConnectionType() const {
|
||
|
base::AutoLock auto_lock(connection_lock_);
|
||
|
return connection_type_;
|
||
|
}
|
||
|
|
||
|
NetworkChangeNotifier::ConnectionSubtype
|
||
|
NetworkChangeNotifierDelegateAndroid::GetCurrentConnectionSubtype() const {
|
||
|
DCHECK(thread_checker_.CalledOnValidThread());
|
||
|
return ConvertConnectionSubtype(
|
||
|
Java_NetworkChangeNotifier_getCurrentConnectionSubtype(
|
||
|
base::android::AttachCurrentThread(), java_network_change_notifier_));
|
||
|
}
|
||
|
|
||
|
void NetworkChangeNotifierDelegateAndroid::
|
||
|
GetCurrentMaxBandwidthAndConnectionType(
|
||
|
double* max_bandwidth_mbps,
|
||
|
ConnectionType* connection_type) const {
|
||
|
base::AutoLock auto_lock(connection_lock_);
|
||
|
*connection_type = connection_type_;
|
||
|
*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,
|
||
|
const JavaParamRef<jobject>& obj,
|
||
|
jint new_connection_type,
|
||
|
jlong 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);
|
||
|
}
|
||
|
|
||
|
jint NetworkChangeNotifierDelegateAndroid::GetConnectionType(JNIEnv*,
|
||
|
jobject) const {
|
||
|
DCHECK(thread_checker_.CalledOnValidThread());
|
||
|
return GetCurrentConnectionType();
|
||
|
}
|
||
|
|
||
|
void NetworkChangeNotifierDelegateAndroid::NotifyMaxBandwidthChanged(
|
||
|
JNIEnv* env,
|
||
|
const JavaParamRef<jobject>& obj,
|
||
|
jint subtype) {
|
||
|
DCHECK(thread_checker_.CalledOnValidThread());
|
||
|
double new_max_bandwidth =
|
||
|
NetworkChangeNotifierAndroid::GetMaxBandwidthForConnectionSubtype(
|
||
|
ConvertConnectionSubtype(subtype));
|
||
|
SetCurrentMaxBandwidth(new_max_bandwidth);
|
||
|
observers_->Notify(FROM_HERE, &Observer::OnMaxBandwidthChanged,
|
||
|
new_max_bandwidth, GetCurrentConnectionType());
|
||
|
}
|
||
|
|
||
|
void NetworkChangeNotifierDelegateAndroid::NotifyOfNetworkConnect(
|
||
|
JNIEnv* env,
|
||
|
const JavaParamRef<jobject>& obj,
|
||
|
jlong 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,
|
||
|
const JavaParamRef<jobject>& obj,
|
||
|
jlong 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,
|
||
|
const JavaParamRef<jobject>& obj,
|
||
|
jlong 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::NotifyPurgeActiveNetworkList(
|
||
|
JNIEnv* env,
|
||
|
const JavaParamRef<jobject>& obj,
|
||
|
const JavaParamRef<jlongArray>& active_networks) {
|
||
|
DCHECK(thread_checker_.CalledOnValidThread());
|
||
|
NetworkList active_network_list;
|
||
|
base::android::JavaLongArrayToInt64Vector(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);
|
||
|
}
|
||
|
|
||
|
void NetworkChangeNotifierDelegateAndroid::RemoveObserver(
|
||
|
Observer* observer) {
|
||
|
observers_->RemoveObserver(observer);
|
||
|
}
|
||
|
|
||
|
void NetworkChangeNotifierDelegateAndroid::SetCurrentConnectionType(
|
||
|
ConnectionType new_connection_type) {
|
||
|
base::AutoLock auto_lock(connection_lock_);
|
||
|
connection_type_ = new_connection_type;
|
||
|
}
|
||
|
|
||
|
void NetworkChangeNotifierDelegateAndroid::SetCurrentMaxBandwidth(
|
||
|
double max_bandwidth) {
|
||
|
base::AutoLock auto_lock(connection_lock_);
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
void NetworkChangeNotifierDelegateAndroid::SetOffline() {
|
||
|
JNIEnv* env = base::android::AttachCurrentThread();
|
||
|
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::FakePurgeActiveNetworkList(
|
||
|
NetworkChangeNotifier::NetworkList networks) {
|
||
|
JNIEnv* env = base::android::AttachCurrentThread();
|
||
|
Java_NetworkChangeNotifier_fakePurgeActiveNetworkList(
|
||
|
env, base::android::ToJavaLongArray(env, networks));
|
||
|
}
|
||
|
|
||
|
void NetworkChangeNotifierDelegateAndroid::FakeDefaultNetwork(
|
||
|
NetworkChangeNotifier::NetworkHandle network,
|
||
|
ConnectionType type) {
|
||
|
JNIEnv* env = base::android::AttachCurrentThread();
|
||
|
Java_NetworkChangeNotifier_fakeDefaultNetwork(env, network, type);
|
||
|
}
|
||
|
|
||
|
void NetworkChangeNotifierDelegateAndroid::FakeConnectionSubtypeChanged(
|
||
|
ConnectionSubtype subtype) {
|
||
|
JNIEnv* env = base::android::AttachCurrentThread();
|
||
|
Java_NetworkChangeNotifier_fakeConnectionSubtypeChanged(env, subtype);
|
||
|
}
|
||
|
|
||
|
} // namespace net
|