Chromium Code Reviews| Index: talk/app/webrtc/java/jni/androidnetworkmonitor_jni.cc |
| diff --git a/talk/app/webrtc/java/jni/androidnetworkmonitor_jni.cc b/talk/app/webrtc/java/jni/androidnetworkmonitor_jni.cc |
| index 1716c19cf8be84344a3ef1bff3f7bebf8a7d5647..27eb5427d38424544a87fab34951211784a925bc 100644 |
| --- a/talk/app/webrtc/java/jni/androidnetworkmonitor_jni.cc |
| +++ b/talk/app/webrtc/java/jni/androidnetworkmonitor_jni.cc |
| @@ -71,6 +71,29 @@ static NetworkType GetNetworkTypeFromJava(JNIEnv* jni, jobject j_network_type) { |
| return NetworkType::NETWORK_UNKNOWN; |
| } |
| +static rtc::AdapterType AdapterTypeFromNetworkType(NetworkType network_type) { |
| + switch (network_type) { |
| + case NETWORK_UNKNOWN: |
| + RTC_DCHECK(false) << "Unknown network type "; |
| + return rtc::ADAPTER_TYPE_UNKNOWN; |
| + case NETWORK_ETHERNET: |
| + return rtc::ADAPTER_TYPE_ETHERNET; |
| + case NETWORK_WIFI: |
| + return rtc::ADAPTER_TYPE_WIFI; |
| + case NETWORK_4G: |
| + case NETWORK_3G: |
| + case NETWORK_2G: |
| + return rtc::ADAPTER_TYPE_CELLULAR; |
| + case NETWORK_BLUETOOTH: |
| + // There is no corresponding mapping for bluetooth networks. |
| + // Map it to VPN for now. |
| + return rtc::ADAPTER_TYPE_VPN; |
| + default: |
| + RTC_DCHECK(false) << "Invalid network type " << network_type; |
| + return rtc::ADAPTER_TYPE_UNKNOWN; |
| + } |
| +} |
| + |
| static rtc::IPAddress GetIPAddressFromJava(JNIEnv* jni, jobject j_ip_address) { |
| jclass j_ip_address_class = GetObjectClass(jni, j_ip_address); |
| jfieldID j_address_id = GetFieldID(jni, j_ip_address_class, "address", "[B"); |
| @@ -186,7 +209,7 @@ void AndroidNetworkMonitor::Start() { |
| jmethodID m = |
| GetMethodID(jni(), *j_network_monitor_class_, "startMonitoring", "(J)V"); |
| jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this)); |
| - CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.startMonitoring"; |
| + CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod"; |
| } |
| void AndroidNetworkMonitor::Stop() { |
| @@ -207,21 +230,39 @@ void AndroidNetworkMonitor::Stop() { |
| jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this)); |
| CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.stopMonitoring"; |
| - network_info_by_address_.clear(); |
| + network_info_by_handle_.clear(); |
| +} |
| + |
| +NetworkInformation* AndroidNetworkMonitor::GetNetworkInfoFromAddress( |
| + const rtc::IPAddress& address) { |
| + // Network handles (IDs) are created by the Android OS in the increasing |
|
pthatcher1
2016/01/30 02:22:07
in the increasing order => in increasing order
honghaiz3
2016/02/02 04:07:42
This is removed.
|
| + // order. By searching in the reverse direction, the one that was created most |
| + // recently is found first in the (unlikely) case that two handles have the |
| + // same IP address (e.g., caused by accidentally not deleting the old handle). |
| + auto& networks = network_info_by_handle_; |
| + auto it = std::find_if( |
| + networks.rbegin(), networks.rend(), |
| + [address](const std::pair<NetworkHandle, NetworkInformation>& pos) { |
|
pthatcher1
2016/01/30 02:22:07
"pos"? Why not "it" or "kv"?
honghaiz3
2016/02/02 04:07:42
This part is removed.
|
| + auto& addresses = pos.second.ip_addresses; |
| + return std::find(addresses.begin(), addresses.end(), address) != |
| + addresses.end(); |
| + }); |
|
pthatcher1
2016/01/30 02:22:07
Could we not have both a network_info_by_address_
honghaiz3
2016/02/02 04:07:42
Done.
honghaiz3
2016/02/02 17:44:13
Note, I used network_handle_by_address instead of
|
| + return (it != networks.rend()) ? &(it->second) : nullptr; |
| } |
| int AndroidNetworkMonitor::BindSocketToNetwork(int socket_fd, |
| const rtc::IPAddress& address) { |
| RTC_CHECK(thread_checker_.CalledOnValidThread()); |
| - auto it = network_info_by_address_.find(address); |
| - if (it == network_info_by_address_.end()) { |
| - return rtc::NETWORK_BIND_ADDRESS_NOT_FOUND; |
| - } |
| // Android prior to Lollipop didn't have support for binding sockets to |
| // networks. However, in that case it should not have reached here because |
| - // |network_info_by_address_| should only be populated in Android Lollipop |
| + // |network_info_by_handle_| should only be populated in Android Lollipop |
| // and above. |
| - NetworkInformation network = it->second; |
| + // TODO(honghaiz): Add a check for Android version here so that it won't try |
| + // to look for handle if the Android version is before Lollipop. |
| + NetworkInformation* network = GetNetworkInfoFromAddress(address); |
| + if (network == nullptr) { |
| + return rtc::NETWORK_BIND_ADDRESS_NOT_FOUND; |
| + } |
| // NOTE: This does rely on Android implementation details, but |
| // these details are unlikely to change. |
| @@ -244,7 +285,7 @@ int AndroidNetworkMonitor::BindSocketToNetwork(int socket_fd, |
| LOG(LS_ERROR) << "Symbol setNetworkForSocket not found "; |
| return rtc::NETWORK_BIND_NOT_IMPLEMENTED; |
| } |
| - int rv = setNetworkForSocket(network.handle, socket_fd); |
| + int rv = setNetworkForSocket(network->handle, socket_fd); |
| // If |network| has since disconnected, |rv| will be ENONET. Surface this as |
| // ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back |
| // the less descriptive ERR_FAILED. |
| @@ -257,20 +298,45 @@ int AndroidNetworkMonitor::BindSocketToNetwork(int socket_fd, |
| return rtc::NETWORK_BIND_FAILURE; |
| } |
| -void AndroidNetworkMonitor::OnNetworkAvailable( |
| +void AndroidNetworkMonitor::OnNetworkConnected( |
| const NetworkInformation& network_info) { |
| + LOG(LS_INFO) << "Network connected: " << network_info.ToString(); |
| worker_thread()->Invoke<void>(rtc::Bind( |
| - &AndroidNetworkMonitor::OnNetworkAvailable_w, this, network_info)); |
| + &AndroidNetworkMonitor::OnNetworkConnected_w, this, network_info)); |
| } |
| -void AndroidNetworkMonitor::OnNetworkAvailable_w( |
| +void AndroidNetworkMonitor::OnNetworkConnected_w( |
| const NetworkInformation& network_info) { |
| - LOG(LS_INFO) << "Network available: " << network_info.ToString(); |
| - for (rtc::IPAddress address : network_info.ip_addresses) { |
| - network_info_by_address_[address] = network_info; |
| + network_info_by_handle_[network_info.handle] = network_info; |
| + adapter_type_by_name_[network_info.interface_name] = |
| + AdapterTypeFromNetworkType(network_info.type); |
| +} |
| + |
| +void AndroidNetworkMonitor::OnNetworkDisconnected(NetworkHandle handle) { |
| + LOG(LS_INFO) << "Network disconnected for handle " << handle; |
| + worker_thread()->Invoke<void>( |
| + rtc::Bind(&AndroidNetworkMonitor::OnNetworkDisconnected_w, this, handle)); |
| +} |
| + |
| +void AndroidNetworkMonitor::OnNetworkDisconnected_w(NetworkHandle handle) { |
| + network_info_by_handle_.erase(handle); |
|
pthatcher1
2016/01/30 02:22:07
You'd just need to do:
iter = network_info_by_han
honghaiz3
2016/02/02 04:07:42
Done.
|
| +} |
| + |
| +void AndroidNetworkMonitor::SetNetworkInfos( |
| + const std::vector<NetworkInformation>& network_infos) { |
| + RTC_CHECK(thread_checker_.CalledOnValidThread()); |
| + network_info_by_handle_.clear(); |
| + for (NetworkInformation network : network_infos) { |
| + OnNetworkConnected_w(network); |
| } |
| } |
| +rtc::AdapterType AndroidNetworkMonitor::GetAdapterType( |
| + const std::string& if_name) { |
| + // If not found, the default type is 0 (ADAPTER_TYPE_UNKNOWN). |
| + return adapter_type_by_name_[if_name]; |
|
pthatcher1
2016/01/30 02:22:07
I think that's a little too subtle. Doing somethi
honghaiz3
2016/02/02 04:07:42
Done.
|
| +} |
| + |
| rtc::NetworkMonitorInterface* |
| AndroidNetworkMonitorFactory::CreateNetworkMonitor() { |
| return new AndroidNetworkMonitor(); |
| @@ -283,6 +349,21 @@ JOW(void, NetworkMonitor_nativeNotifyConnectionTypeChanged)( |
| network_monitor->OnNetworksChanged(); |
| } |
| +JOW(void, NetworkMonitor_nativeNotifyOfActiveNetworkList)( |
| + JNIEnv* jni, jobject j_monitor, jlong j_native_monitor, |
| + jobjectArray j_network_infos) { |
| + AndroidNetworkMonitor* network_monitor = |
| + reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor); |
| + std::vector<NetworkInformation> network_infos; |
| + size_t num_networks = jni->GetArrayLength(j_network_infos); |
| + for (size_t i = 0; i < num_networks; ++i) { |
| + jobject j_network_info = jni->GetObjectArrayElement(j_network_infos, i); |
| + CHECK_EXCEPTION(jni) << "Error during GetObjectArrayElement"; |
| + network_infos.push_back(GetNetworkInformationFromJava(jni, j_network_info)); |
| + } |
| + network_monitor->SetNetworkInfos(network_infos); |
| +} |
| + |
| JOW(void, NetworkMonitor_nativeNotifyOfNetworkConnect)( |
| JNIEnv* jni, jobject j_monitor, jlong j_native_monitor, |
| jobject j_network_info) { |
| @@ -290,7 +371,16 @@ JOW(void, NetworkMonitor_nativeNotifyOfNetworkConnect)( |
| reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor); |
| NetworkInformation network_info = |
| GetNetworkInformationFromJava(jni, j_network_info); |
| - network_monitor->OnNetworkAvailable(network_info); |
| + network_monitor->OnNetworkConnected(network_info); |
| +} |
| + |
| +JOW(void, NetworkMonitor_nativeNotifyOfNetworkDisconnect)( |
| + JNIEnv* jni, jobject j_monitor, jlong j_native_monitor, |
| + jint network_handle) { |
| + AndroidNetworkMonitor* network_monitor = |
| + reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor); |
| + network_monitor->OnNetworkDisconnected( |
| + static_cast<NetworkHandle>(network_handle)); |
| } |
| } // namespace webrtc_jni |