Chromium Code Reviews| 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. |