Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(120)

Side by Side Diff: webrtc/api/android/jni/androidnetworkmonitor_jni.cc

Issue 2547483003: Move /webrtc/api/android files to /webrtc/sdk/android (Closed)
Patch Set: Move to api folder under Android instead of src Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/api/android/jni/androidnetworkmonitor_jni.h"
12
13 #include <dlfcn.h>
14 // This was added in Lollipop to dlfcn.h
15 #define RTLD_NOLOAD 4
16
17 #include "webrtc/api/android/jni/classreferenceholder.h"
18 #include "webrtc/api/android/jni/jni_helpers.h"
19 #include "webrtc/base/bind.h"
20 #include "webrtc/base/common.h"
21 #include "webrtc/base/ipaddress.h"
22
23 namespace webrtc_jni {
24
25 enum AndroidSdkVersion {
26 SDK_VERSION_LOLLIPOP = 21,
27 SDK_VERSION_MARSHMALLOW = 23
28 };
29
30 jobject AndroidNetworkMonitor::application_context_ = nullptr;
31 int AndroidNetworkMonitor::android_sdk_int_ = 0;
32
33 static NetworkType GetNetworkTypeFromJava(JNIEnv* jni, jobject j_network_type) {
34 std::string enum_name =
35 GetJavaEnumName(jni, "org/webrtc/NetworkMonitorAutoDetect$ConnectionType",
36 j_network_type);
37 if (enum_name == "CONNECTION_UNKNOWN") {
38 return NetworkType::NETWORK_UNKNOWN;
39 }
40 if (enum_name == "CONNECTION_ETHERNET") {
41 return NetworkType::NETWORK_ETHERNET;
42 }
43 if (enum_name == "CONNECTION_WIFI") {
44 return NetworkType::NETWORK_WIFI;
45 }
46 if (enum_name == "CONNECTION_4G") {
47 return NetworkType::NETWORK_4G;
48 }
49 if (enum_name == "CONNECTION_3G") {
50 return NetworkType::NETWORK_3G;
51 }
52 if (enum_name == "CONNECTION_2G") {
53 return NetworkType::NETWORK_2G;
54 }
55 if (enum_name == "CONNECTION_UNKNOWN_CELLULAR") {
56 return NetworkType::NETWORK_UNKNOWN_CELLULAR;
57 }
58 if (enum_name == "CONNECTION_BLUETOOTH") {
59 return NetworkType::NETWORK_BLUETOOTH;
60 }
61 if (enum_name == "CONNECTION_NONE") {
62 return NetworkType::NETWORK_NONE;
63 }
64 ASSERT(false);
65 return NetworkType::NETWORK_UNKNOWN;
66 }
67
68 static rtc::AdapterType AdapterTypeFromNetworkType(NetworkType network_type) {
69 switch (network_type) {
70 case NETWORK_UNKNOWN:
71 return rtc::ADAPTER_TYPE_UNKNOWN;
72 case NETWORK_ETHERNET:
73 return rtc::ADAPTER_TYPE_ETHERNET;
74 case NETWORK_WIFI:
75 return rtc::ADAPTER_TYPE_WIFI;
76 case NETWORK_4G:
77 case NETWORK_3G:
78 case NETWORK_2G:
79 case NETWORK_UNKNOWN_CELLULAR:
80 return rtc::ADAPTER_TYPE_CELLULAR;
81 case NETWORK_BLUETOOTH:
82 // There is no corresponding mapping for bluetooth networks.
83 // Map it to VPN for now.
84 return rtc::ADAPTER_TYPE_VPN;
85 default:
86 RTC_DCHECK(false) << "Invalid network type " << network_type;
87 return rtc::ADAPTER_TYPE_UNKNOWN;
88 }
89 }
90
91 static rtc::IPAddress GetIPAddressFromJava(JNIEnv* jni, jobject j_ip_address) {
92 jclass j_ip_address_class = GetObjectClass(jni, j_ip_address);
93 jfieldID j_address_id = GetFieldID(jni, j_ip_address_class, "address", "[B");
94 jbyteArray j_addresses =
95 static_cast<jbyteArray>(GetObjectField(jni, j_ip_address, j_address_id));
96 size_t address_length = jni->GetArrayLength(j_addresses);
97 jbyte* addr_array = jni->GetByteArrayElements(j_addresses, nullptr);
98 CHECK_EXCEPTION(jni) << "Error during GetIPAddressFromJava";
99 if (address_length == 4) {
100 // IP4
101 struct in_addr ip4_addr;
102 memcpy(&ip4_addr.s_addr, addr_array, 4);
103 jni->ReleaseByteArrayElements(j_addresses, addr_array, JNI_ABORT);
104 return rtc::IPAddress(ip4_addr);
105 }
106 // IP6
107 RTC_CHECK(address_length == 16);
108 struct in6_addr ip6_addr;
109 memcpy(ip6_addr.s6_addr, addr_array, address_length);
110 jni->ReleaseByteArrayElements(j_addresses, addr_array, JNI_ABORT);
111 return rtc::IPAddress(ip6_addr);
112 }
113
114 static void GetIPAddressesFromJava(JNIEnv* jni,
115 jobjectArray j_ip_addresses,
116 std::vector<rtc::IPAddress>* ip_addresses) {
117 ip_addresses->clear();
118 size_t num_addresses = jni->GetArrayLength(j_ip_addresses);
119 CHECK_EXCEPTION(jni) << "Error during GetArrayLength";
120 for (size_t i = 0; i < num_addresses; ++i) {
121 jobject j_ip_address = jni->GetObjectArrayElement(j_ip_addresses, i);
122 CHECK_EXCEPTION(jni) << "Error during GetObjectArrayElement";
123 rtc::IPAddress ip = GetIPAddressFromJava(jni, j_ip_address);
124 ip_addresses->push_back(ip);
125 }
126 }
127
128 static NetworkInformation GetNetworkInformationFromJava(
129 JNIEnv* jni,
130 jobject j_network_info) {
131 jclass j_network_info_class = GetObjectClass(jni, j_network_info);
132 jfieldID j_interface_name_id =
133 GetFieldID(jni, j_network_info_class, "name", "Ljava/lang/String;");
134 jfieldID j_handle_id = GetFieldID(jni, j_network_info_class, "handle", "J");
135 jfieldID j_type_id =
136 GetFieldID(jni, j_network_info_class, "type",
137 "Lorg/webrtc/NetworkMonitorAutoDetect$ConnectionType;");
138 jfieldID j_ip_addresses_id =
139 GetFieldID(jni, j_network_info_class, "ipAddresses",
140 "[Lorg/webrtc/NetworkMonitorAutoDetect$IPAddress;");
141
142 NetworkInformation network_info;
143 network_info.interface_name = JavaToStdString(
144 jni, GetStringField(jni, j_network_info, j_interface_name_id));
145 network_info.handle = static_cast<NetworkHandle>(
146 GetLongField(jni, j_network_info, j_handle_id));
147 network_info.type = GetNetworkTypeFromJava(
148 jni, GetObjectField(jni, j_network_info, j_type_id));
149 jobjectArray j_ip_addresses = static_cast<jobjectArray>(
150 GetObjectField(jni, j_network_info, j_ip_addresses_id));
151 GetIPAddressesFromJava(jni, j_ip_addresses, &network_info.ip_addresses);
152 return network_info;
153 }
154
155 std::string NetworkInformation::ToString() const {
156 std::stringstream ss;
157 ss << "NetInfo[name " << interface_name << "; handle " << handle << "; type "
158 << type << "; address";
159 for (const rtc::IPAddress address : ip_addresses) {
160 ss << " " << address.ToString();
161 }
162 ss << "]";
163 return ss.str();
164 }
165
166 // static
167 void AndroidNetworkMonitor::SetAndroidContext(JNIEnv* jni, jobject context) {
168 if (application_context_) {
169 jni->DeleteGlobalRef(application_context_);
170 }
171 application_context_ = NewGlobalRef(jni, context);
172 }
173
174 AndroidNetworkMonitor::AndroidNetworkMonitor()
175 : j_network_monitor_class_(jni(),
176 FindClass(jni(), "org/webrtc/NetworkMonitor")),
177 j_network_monitor_(
178 jni(),
179 jni()->CallStaticObjectMethod(
180 *j_network_monitor_class_,
181 GetStaticMethodID(
182 jni(),
183 *j_network_monitor_class_,
184 "init",
185 "(Landroid/content/Context;)Lorg/webrtc/NetworkMonitor;"),
186 application_context_)) {
187 ASSERT(application_context_ != nullptr);
188 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.init";
189 if (android_sdk_int_ <= 0) {
190 jmethodID m = GetStaticMethodID(jni(), *j_network_monitor_class_,
191 "androidSdkInt", "()I");
192 android_sdk_int_ = jni()->CallStaticIntMethod(*j_network_monitor_class_, m);
193 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.androidSdkInt";
194 }
195 }
196
197 void AndroidNetworkMonitor::Start() {
198 RTC_CHECK(thread_checker_.CalledOnValidThread());
199 if (started_) {
200 return;
201 }
202 started_ = true;
203
204 // This is kind of magic behavior, but doing this allows the SocketServer to
205 // use this as a NetworkBinder to bind sockets on a particular network when
206 // it creates sockets.
207 worker_thread()->socketserver()->set_network_binder(this);
208
209 jmethodID m =
210 GetMethodID(jni(), *j_network_monitor_class_, "startMonitoring", "(J)V");
211 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this));
212 CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod";
213 }
214
215 void AndroidNetworkMonitor::Stop() {
216 RTC_CHECK(thread_checker_.CalledOnValidThread());
217 if (!started_) {
218 return;
219 }
220 started_ = false;
221
222 // Once the network monitor stops, it will clear all network information and
223 // it won't find the network handle to bind anyway.
224 if (worker_thread()->socketserver()->network_binder() == this) {
225 worker_thread()->socketserver()->set_network_binder(nullptr);
226 }
227
228 jmethodID m =
229 GetMethodID(jni(), *j_network_monitor_class_, "stopMonitoring", "(J)V");
230 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this));
231 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.stopMonitoring";
232
233 network_handle_by_address_.clear();
234 network_info_by_handle_.clear();
235 }
236
237 // The implementation is largely taken from UDPSocketPosix::BindToNetwork in
238 // https://cs.chromium.org/chromium/src/net/udp/udp_socket_posix.cc
239 int AndroidNetworkMonitor::BindSocketToNetwork(int socket_fd,
240 const rtc::IPAddress& address) {
241 RTC_CHECK(thread_checker_.CalledOnValidThread());
242 // Android prior to Lollipop didn't have support for binding sockets to
243 // networks. In that case it should not have reached here because
244 // |network_handle_by_address_| is only populated in Android Lollipop
245 // and above.
246 if (android_sdk_int_ < SDK_VERSION_LOLLIPOP) {
247 LOG(LS_ERROR) << "BindSocketToNetwork is not supported in Android SDK "
248 << android_sdk_int_;
249 return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
250 }
251
252 auto iter = network_handle_by_address_.find(address);
253 if (iter == network_handle_by_address_.end()) {
254 return rtc::NETWORK_BIND_ADDRESS_NOT_FOUND;
255 }
256 NetworkHandle network_handle = iter->second;
257
258 int rv = 0;
259 if (android_sdk_int_ >= SDK_VERSION_MARSHMALLOW) {
260 // See declaration of android_setsocknetwork() here:
261 // http://androidxref.com/6.0.0_r1/xref/development/ndk/platforms/android-M/ include/android/multinetwork.h#65
262 // Function cannot be called directly as it will cause app to fail to load
263 // on pre-marshmallow devices.
264 typedef int (*MarshmallowSetNetworkForSocket)(NetworkHandle net,
265 int socket);
266 static MarshmallowSetNetworkForSocket marshmallowSetNetworkForSocket;
267 // This is not thread-safe, but we are running this only on the worker
268 // thread.
269 if (!marshmallowSetNetworkForSocket) {
270 const std::string android_native_lib_path = "libandroid.so";
271 void* lib = dlopen(android_native_lib_path.c_str(), RTLD_NOW);
272 if (lib == nullptr) {
273 LOG(LS_ERROR) << "Library " << android_native_lib_path << " not found!";
274 return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
275 }
276 marshmallowSetNetworkForSocket =
277 reinterpret_cast<MarshmallowSetNetworkForSocket>(
278 dlsym(lib, "android_setsocknetwork"));
279 }
280 if (!marshmallowSetNetworkForSocket) {
281 LOG(LS_ERROR) << "Symbol marshmallowSetNetworkForSocket is not found";
282 return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
283 }
284 rv = marshmallowSetNetworkForSocket(network_handle, socket_fd);
285 } else {
286 // NOTE: This relies on Android implementation details, but it won't change
287 // because Lollipop is already released.
288 typedef int (*LollipopSetNetworkForSocket)(unsigned net, int socket);
289 static LollipopSetNetworkForSocket lollipopSetNetworkForSocket;
290 // This is not threadsafe, but we are running this only on the worker
291 // thread.
292 if (!lollipopSetNetworkForSocket) {
293 // Android's netd client library should always be loaded in our address
294 // space as it shims libc functions like connect().
295 const std::string net_library_path = "libnetd_client.so";
296 // Use RTLD_NOW to match Android's prior loading of the library:
297 // http://androidxref.com/6.0.0_r5/xref/bionic/libc/bionic/NetdClient.cpp# 37
298 // Use RTLD_NOLOAD to assert that the library is already loaded and
299 // avoid doing any disk IO.
300 void* lib = dlopen(net_library_path.c_str(), RTLD_NOW | RTLD_NOLOAD);
301 if (lib == nullptr) {
302 LOG(LS_ERROR) << "Library " << net_library_path << " not found!";
303 return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
304 }
305 lollipopSetNetworkForSocket =
306 reinterpret_cast<LollipopSetNetworkForSocket>(
307 dlsym(lib, "setNetworkForSocket"));
308 }
309 if (!lollipopSetNetworkForSocket) {
310 LOG(LS_ERROR) << "Symbol lollipopSetNetworkForSocket is not found ";
311 return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
312 }
313 rv = lollipopSetNetworkForSocket(network_handle, socket_fd);
314 }
315
316 // If |network| has since disconnected, |rv| will be ENONET. Surface this as
317 // ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back
318 // the less descriptive ERR_FAILED.
319 if (rv == 0) {
320 return rtc::NETWORK_BIND_SUCCESS;
321 }
322 if (rv == ENONET) {
323 return rtc::NETWORK_BIND_NETWORK_CHANGED;
324 }
325 return rtc::NETWORK_BIND_FAILURE;
326 }
327
328 void AndroidNetworkMonitor::OnNetworkConnected(
329 const NetworkInformation& network_info) {
330 worker_thread()->Invoke<void>(
331 RTC_FROM_HERE, rtc::Bind(&AndroidNetworkMonitor::OnNetworkConnected_w,
332 this, network_info));
333 // Fire SignalNetworksChanged to update the list of networks.
334 OnNetworksChanged();
335 }
336
337 void AndroidNetworkMonitor::OnNetworkConnected_w(
338 const NetworkInformation& network_info) {
339 LOG(LS_INFO) << "Network connected: " << network_info.ToString();
340 adapter_type_by_name_[network_info.interface_name] =
341 AdapterTypeFromNetworkType(network_info.type);
342 network_info_by_handle_[network_info.handle] = network_info;
343 for (const rtc::IPAddress& address : network_info.ip_addresses) {
344 network_handle_by_address_[address] = network_info.handle;
345 }
346 }
347
348 void AndroidNetworkMonitor::OnNetworkDisconnected(NetworkHandle handle) {
349 LOG(LS_INFO) << "Network disconnected for handle " << handle;
350 worker_thread()->Invoke<void>(
351 RTC_FROM_HERE,
352 rtc::Bind(&AndroidNetworkMonitor::OnNetworkDisconnected_w, this, handle));
353 }
354
355 void AndroidNetworkMonitor::OnNetworkDisconnected_w(NetworkHandle handle) {
356 auto iter = network_info_by_handle_.find(handle);
357 if (iter != network_info_by_handle_.end()) {
358 for (const rtc::IPAddress& address : iter->second.ip_addresses) {
359 network_handle_by_address_.erase(address);
360 }
361 network_info_by_handle_.erase(iter);
362 }
363 }
364
365 void AndroidNetworkMonitor::SetNetworkInfos(
366 const std::vector<NetworkInformation>& network_infos) {
367 RTC_CHECK(thread_checker_.CalledOnValidThread());
368 network_handle_by_address_.clear();
369 network_info_by_handle_.clear();
370 LOG(LS_INFO) << "Android network monitor found " << network_infos.size()
371 << " networks";
372 for (NetworkInformation network : network_infos) {
373 OnNetworkConnected_w(network);
374 }
375 }
376
377 rtc::AdapterType AndroidNetworkMonitor::GetAdapterType(
378 const std::string& if_name) {
379 auto iter = adapter_type_by_name_.find(if_name);
380 rtc::AdapterType type = (iter == adapter_type_by_name_.end())
381 ? rtc::ADAPTER_TYPE_UNKNOWN
382 : iter->second;
383 if (type == rtc::ADAPTER_TYPE_UNKNOWN) {
384 LOG(LS_WARNING) << "Get an unknown type for the interface " << if_name;
385 }
386 return type;
387 }
388
389 rtc::NetworkMonitorInterface*
390 AndroidNetworkMonitorFactory::CreateNetworkMonitor() {
391 return new AndroidNetworkMonitor();
392 }
393
394 JOW(void, NetworkMonitor_nativeNotifyConnectionTypeChanged)(
395 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor) {
396 rtc::NetworkMonitorInterface* network_monitor =
397 reinterpret_cast<rtc::NetworkMonitorInterface*>(j_native_monitor);
398 network_monitor->OnNetworksChanged();
399 }
400
401 JOW(void, NetworkMonitor_nativeNotifyOfActiveNetworkList)(
402 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor,
403 jobjectArray j_network_infos) {
404 AndroidNetworkMonitor* network_monitor =
405 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor);
406 std::vector<NetworkInformation> network_infos;
407 size_t num_networks = jni->GetArrayLength(j_network_infos);
408 for (size_t i = 0; i < num_networks; ++i) {
409 jobject j_network_info = jni->GetObjectArrayElement(j_network_infos, i);
410 CHECK_EXCEPTION(jni) << "Error during GetObjectArrayElement";
411 network_infos.push_back(GetNetworkInformationFromJava(jni, j_network_info));
412 }
413 network_monitor->SetNetworkInfos(network_infos);
414 }
415
416 JOW(void, NetworkMonitor_nativeNotifyOfNetworkConnect)(
417 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor,
418 jobject j_network_info) {
419 AndroidNetworkMonitor* network_monitor =
420 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor);
421 NetworkInformation network_info =
422 GetNetworkInformationFromJava(jni, j_network_info);
423 network_monitor->OnNetworkConnected(network_info);
424 }
425
426 JOW(void, NetworkMonitor_nativeNotifyOfNetworkDisconnect)(
427 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor,
428 jlong network_handle) {
429 AndroidNetworkMonitor* network_monitor =
430 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor);
431 network_monitor->OnNetworkDisconnected(
432 static_cast<NetworkHandle>(network_handle));
433 }
434
435 } // namespace webrtc_jni
OLDNEW
« no previous file with comments | « webrtc/api/android/jni/androidnetworkmonitor_jni.h ('k') | webrtc/api/android/jni/androidvideotracksource.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698