| 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
|
| + // 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.
|
|
|