Index: net/udp/udp_socket_posix.cc |
diff --git a/net/udp/udp_socket_posix.cc b/net/udp/udp_socket_posix.cc |
index b3972625edc48844318ecfba2b9c042080e9a7ba..797e1a0bc1352b5a4a9a43c8c663c7acb05ab374 100644 |
--- a/net/udp/udp_socket_posix.cc |
+++ b/net/udp/udp_socket_posix.cc |
@@ -346,27 +346,55 @@ int UDPSocketPosix::BindToNetwork( |
base::android::SDK_VERSION_LOLLIPOP) { |
return ERR_NOT_IMPLEMENTED; |
} |
- // NOTE(pauljensen): This does rely on Android implementation details, but |
- // these details are unlikely to change. |
- typedef int (*SetNetworkForSocket)(unsigned netId, int socketFd); |
- static SetNetworkForSocket setNetworkForSocket; |
- // This is racy, but all racers should come out with the same answer so it |
- // shouldn't matter. |
- if (!setNetworkForSocket) { |
- // Android's netd client library should always be loaded in our address |
- // space as it shims socket() which was used to create |socket_|. |
- base::FilePath file(base::GetNativeLibraryName("netd_client")); |
- // Use RTLD_NOW to match Android's prior loading of the library: |
- // http://androidxref.com/6.0.0_r5/xref/bionic/libc/bionic/NetdClient.cpp#37 |
- // Use RTLD_NOLOAD to assert that the library is already loaded and |
- // avoid doing any disk IO. |
- void* dl = dlopen(file.value().c_str(), RTLD_NOW | RTLD_NOLOAD); |
- setNetworkForSocket = |
- reinterpret_cast<SetNetworkForSocket>(dlsym(dl, "setNetworkForSocket")); |
+ int rv; |
+ // On Android M and newer releases use supported NDK API. On Android L use |
+ // setNetworkForSocket from libnetd_client.so. |
+ if (base::android::BuildInfo::GetInstance()->sdk_int() >= |
+ base::android::SDK_VERSION_MARSHMALLOW) { |
+ // See declaration of android_setsocknetwork() here: |
+ // http://androidxref.com/6.0.0_r1/xref/development/ndk/platforms/android-M/include/android/multinetwork.h#65 |
+ // Function cannot be called directly as it will cause app to fail to load |
+ // on pre-marshmallow devices. |
+ typedef int (*MarshmallowSetNetworkForSocket)(int64_t netId, int socketFd); |
+ static MarshmallowSetNetworkForSocket marshmallowSetNetworkForSocket; |
+ // This is racy, but all racers should come out with the same answer so it |
xunjieli
2016/07/20 17:55:49
One last question: why is this racy? If all socket
pauljensen
2016/07/20 18:02:16
There are multiple network threads but only one st
xunjieli
2016/07/20 18:08:03
Ah, i see. I always forget Cronet can have multipl
|
+ // shouldn't matter. |
+ if (!marshmallowSetNetworkForSocket) { |
+ base::FilePath file(base::GetNativeLibraryName("android")); |
+ void* dl = dlopen(file.value().c_str(), RTLD_NOW); |
+ marshmallowSetNetworkForSocket = |
+ reinterpret_cast<MarshmallowSetNetworkForSocket>( |
+ dlsym(dl, "android_setsocknetwork")); |
+ } |
+ if (!marshmallowSetNetworkForSocket) |
+ return ERR_NOT_IMPLEMENTED; |
+ rv = marshmallowSetNetworkForSocket(network, socket_); |
+ if (rv) |
+ rv = errno; |
+ } else { |
+ // NOTE(pauljensen): This does rely on Android implementation details, but |
+ // they won't change because Lollipop is already released. |
+ typedef int (*LollipopSetNetworkForSocket)(unsigned netId, int socketFd); |
+ static LollipopSetNetworkForSocket lollipopSetNetworkForSocket; |
+ // This is racy, but all racers should come out with the same answer so it |
+ // shouldn't matter. |
+ if (!lollipopSetNetworkForSocket) { |
+ // Android's netd client library should always be loaded in our address |
+ // space as it shims socket() which was used to create |socket_|. |
+ base::FilePath file(base::GetNativeLibraryName("netd_client")); |
+ // Use RTLD_NOW to match Android's prior loading of the library: |
+ // http://androidxref.com/6.0.0_r5/xref/bionic/libc/bionic/NetdClient.cpp#37 |
+ // Use RTLD_NOLOAD to assert that the library is already loaded and |
+ // avoid doing any disk IO. |
+ void* dl = dlopen(file.value().c_str(), RTLD_NOW | RTLD_NOLOAD); |
+ lollipopSetNetworkForSocket = |
+ reinterpret_cast<LollipopSetNetworkForSocket>( |
+ dlsym(dl, "setNetworkForSocket")); |
+ } |
+ if (!lollipopSetNetworkForSocket) |
+ return ERR_NOT_IMPLEMENTED; |
+ rv = -lollipopSetNetworkForSocket(network, socket_); |
} |
- if (!setNetworkForSocket) |
- return ERR_NOT_IMPLEMENTED; |
- int rv = setNetworkForSocket(network, socket_); |
// 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. |