由《Android okhttp3 创建Socket的底层实现追踪》可知,okhttp3在okhttp3.internal.io.RealConnection#connectSocket中通过rawSocket.setSoTimeout(readTimeout)调用java.net.Socket#checkOpenAndCreate创建了socket,底层是在/bionic/libc/arch-arm/syscalls/socket.S汇编代码中调用系统调用实现的,其中rawSocket是PlainSocketImpl.java的实例。

下面跟踪socket connect的底层实现
1.okhttp3.internal.io.RealConnection#connectSocket

try {      Platform.get().connectSocket(rawSocket, route.socketAddress(), connectTimeout);    } catch (ConnectException e) {      throw new ConnectException("Failed to connect to " + route.socketAddress());    }

2.
okhttp3.internal#connectSocket

public void connectSocket(Socket socket, InetSocketAddress address,      int connectTimeout) throws IOException {    socket.connect(address, connectTimeout);}

/libcore/luni/src/main/java/java/net/Socket.java#connect

    public void connect(SocketAddress remoteAddr, int timeout) throws IOException {        。。。。        synchronized (connectLock) {            try {                。。。。                impl.connect(remoteAddr, timeout);                isConnected = true;                cacheLocalAddress();            } catch (IOException e) {                impl.close();                throw e;            }        }    }

3./libcore/luni/src/main/java/java/net/PlainSocketImpl.java

protected void connect(SocketAddress remoteAddr, int timeout) throws IOException {        InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;        connect(inetAddr.getAddress(), inetAddr.getPort(), timeout);}private void connect(InetAddress anAddr, int aPort, int timeout) throws IOException {        InetAddress normalAddr = anAddr.isAnyLocalAddress() ? InetAddress.getLocalHost() : anAddr;        if (streaming && usingSocks()) {            socksConnect(anAddr, aPort, 0);        } else {            IoBridge.connect(fd, normalAddr, aPort, timeout);        }        super.address = normalAddr;        super.port = aPort;}

4./libcore/luni/src/main/java/libcore/io/IoBridge.java

    public static boolean connect(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs) throws SocketException, SocketTimeoutException {        try {            return connectErrno(fd, inetAddress, port, timeoutMs);        } catch (ErrnoException errnoException) {            throw new ConnectException(connectDetail(inetAddress, port, timeoutMs, errnoException), errnoException);        } catch (SocketException ex) {            throw ex; // We don't want to doubly wrap these.        } catch (SocketTimeoutException ex) {            throw ex; // We don't want to doubly wrap these.        } catch (IOException ex) {            throw new SocketException(ex);        }    }

5./libcore/luni/src/main/java/libcore/io/IoBridge.java#connectErrno

    private static boolean connectErrno(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs) throws ErrnoException, IOException {        // With no timeout, just call connect(2) directly.        if (timeoutMs == 0) {            Libcore.os.connect(fd, inetAddress, port);            return true;        }        // For connect with a timeout, we:        //   1. set the socket to non-blocking,        //   2. connect(2),        //   3. loop using poll(2) to decide whether we're connected, whether we should keep        //      waiting, or whether we've seen a permanent failure and should give up,        //   4. set the socket back to blocking.        // 1. set the socket to non-blocking.        IoUtils.setBlocking(fd, false);        // 2. call connect(2) non-blocking.        long finishTimeMs = System.currentTimeMillis() + timeoutMs;        try {            Libcore.os.connect(fd, inetAddress, port);            IoUtils.setBlocking(fd, true); // 4. set the socket back to blocking.            return true; // We connected immediately.        } catch (ErrnoException errnoException) {            if (errnoException.errno != EINPROGRESS) {                throw errnoException;            }            // EINPROGRESS means we should keep trying...        }        // 3. loop using poll(2).        int remainingTimeoutMs;        do {            remainingTimeoutMs = (int) (finishTimeMs - System.currentTimeMillis());            if (remainingTimeoutMs <= 0) {                throw new SocketTimeoutException(connectDetail(inetAddress, port, timeoutMs, null));            }        } while (!IoBridge.isConnected(fd, inetAddress, port, timeoutMs, remainingTimeoutMs));        IoUtils.setBlocking(fd, true); // 4. set the socket back to blocking.        return true; // Or we'd have thrown.    }

connectErrno实现了connect+poll的逻辑,注释已经说明的很清楚了。
有timeout的时候,进行非阻塞connect,然后用poll进行事件轮询直到timeout

6.
/libcore/luni/src/main/java/libcore/io/BlockGuardOs.java

public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException {        BlockGuard.getThreadPolicy().onNetwork();        os.connect(fd, address, port);    }

/libcore/luni/src/main/java/libcore/io/ForwardingOs.java

public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException { os.connect(fd, address, port); }

7./libcore/luni/src/main/java/libcore/io/Posix.java

public native void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;

8./libcore/luni/src/main/native/libcore_io_Posix.cpp

static void Posix_connect(JNIEnv* env, jobject, jobject javaFd, jobject javaAddress, jint port) {    sockaddr_storage ss;    socklen_t sa_len;    if (!inetAddressToSockaddr(env, javaAddress, port, ss, sa_len)) {        return;    }    const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);    // We don't need the return value because we'll already have thrown.    (void) NET_FAILURE_RETRY(env, int, connect, javaFd, sa, sa_len);}#define NET_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ...) ({ \    return_type _rc = -1; \    do { \        { \            int _fd = jniGetFDFromFileDescriptor(jni_env, java_fd); \            AsynchronousSocketCloseMonitor _monitor(_fd); \            _rc = syscall_name(_fd, __VA_ARGS__); \        } \        if (_rc == -1) { \            if (jniGetFDFromFileDescriptor(jni_env, java_fd) == -1) { \                jniThrowException(jni_env, "java/net/SocketException", "Socket closed"); \                break; \            } else if (errno != EINTR) { \                /* TODO: with a format string we could show the arguments too, like strace(1). */ \                throwErrnoException(jni_env, # syscall_name); \                break; \            } \        } \    } while (_rc == -1); \    _rc; })

9./bionic/libc/arch-arm/syscalls/connect.S

ENTRY(connect)    mov     ip, r7    ldr     r7, =__NR_connect    swi     #0    mov     r7, ip    cmn     r0, #(MAX_ERRNO + 1)    bxls    lr    neg     r0, r0    b       __set_errnoEND(connect)

可以看出,最终socket的connect也是在汇编代码中调用系统调用实现的。
接着看下poll的实现。

10./libcore/luni/src/main/java/libcore/io/IoBridge.java#isConnected

    public static boolean isConnected(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs, int remainingTimeoutMs) throws IOException {        ErrnoException cause;        try {            StructPollfd[] pollFds = new StructPollfd[] { new StructPollfd() };            pollFds[0].fd = fd;            pollFds[0].events = (short) POLLOUT;            int rc = Libcore.os.poll(pollFds, remainingTimeoutMs);            if (rc == 0) {                return false; // Timeout.            }            int connectError = Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_ERROR);            if (connectError == 0) {                return true; // Success!            }            throw new ErrnoException("isConnected", connectError); // The connect(2) failed.        } catch (ErrnoException errnoException) {            if (!fd.valid()) {                throw new SocketException("Socket closed");            }            if (errnoException.errno == EINTR) {                return false; // Punt and ask the caller to try again.            } else {                cause = errnoException;            }        }        String detail = connectDetail(inetAddress, port, timeoutMs, cause);        if (cause.errno == ETIMEDOUT) {            throw new SocketTimeoutException(detail, cause);        }        throw new ConnectException(detail, cause);    }

通过poll监控fd可写(POLLOUT)这个事件

11.
/libcore/luni/src/main/java/libcore/io/BlockGuardOs.java

public int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException {        // Greater than 0 is a timeout in milliseconds and -1 means "block forever",        // but 0 means "poll and return immediately", which shouldn't be subject to BlockGuard.        if (timeoutMs != 0) {            BlockGuard.getThreadPolicy().onNetwork();        }        return os.poll(fds, timeoutMs);    }

/libcore/luni/src/main/java/libcore/io/ForwardingOs.java

public int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException { return os.poll(fds, timeoutMs); }

12./libcore/luni/src/main/java/libcore/io/Posix.java

public native int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException;

13./libcore/luni/src/main/native/libcore_io_Posix.cpp

static jint Posix_poll(JNIEnv* env, jobject, jobjectArray javaStructs, jint timeoutMs) {    static jfieldID fdFid = env->GetFieldID(JniConstants::structPollfdClass, "fd", "Ljava/io/FileDescriptor;");    static jfieldID eventsFid = env->GetFieldID(JniConstants::structPollfdClass, "events", "S");    static jfieldID reventsFid = env->GetFieldID(JniConstants::structPollfdClass, "revents", "S");    // Turn the Java libcore.io.StructPollfd[] into a C++ struct pollfd[].    size_t arrayLength = env->GetArrayLength(javaStructs);    UniquePtr<struct pollfd[]> fds(new struct pollfd[arrayLength]);    memset(fds.get(), 0, sizeof(struct pollfd) * arrayLength);    size_t count = 0; // Some trailing array elements may be irrelevant. (See below.)    for (size_t i = 0; i < arrayLength; ++i) {        ScopedLocalRef javaStruct(env, env->GetObjectArrayElement(javaStructs, i));        if (javaStruct.get() == NULL) {            break; // We allow trailing nulls in the array for caller convenience.        }        ScopedLocalRef javaFd(env, env->GetObjectField(javaStruct.get(), fdFid));        if (javaFd.get() == NULL) {            break; // We also allow callers to just clear the fd field (this is what Selector does).        }        fds[count].fd = jniGetFDFromFileDescriptor(env, javaFd.get());        fds[count].events = env->GetShortField(javaStruct.get(), eventsFid);        ++count;    }    // Since we don't know which fds -- if any -- are sockets, be conservative and register    // all fds for asynchronous socket close monitoring.    std::vector monitors;    for (size_t i = 0; i < count; ++i) {        monitors.push_back(new AsynchronousSocketCloseMonitor(fds[i].fd));    }    int rc = poll(fds.get(), count, timeoutMs);    for (size_t i = 0; i < monitors.size(); ++i) {        delete monitors[i];    }    if (rc == -1) {        throwErrnoException(env, "poll");        return -1;    }    // Update the revents fields in the Java libcore.io.StructPollfd[].    for (size_t i = 0; i < count; ++i) {        ScopedLocalRef javaStruct(env, env->GetObjectArrayElement(javaStructs, i));        if (javaStruct.get() == NULL) {            return -1;        }        env->SetShortField(javaStruct.get(), reventsFid, fds[i].revents);    }    return rc;}

14./bionic/libc/arch-arm/syscalls/poll.S

ENTRY(poll)    mov     ip, r7    ldr     r7, =__NR_poll    swi     #0    mov     r7, ip    cmn     r0, #(MAX_ERRNO + 1)    bxls    lr    neg     r0, r0    b       __set_errnoEND(poll)

跟connect一样,最后也是汇编实现系统调用

更多相关文章

  1. Android系统(168)---Android(安卓)开源项目分类汇总
  2. tiny210 android 移植过程中的几个问题
  3. Android(安卓)sdk version and API level
  4. Android(安卓)输入系统解析 (2)
  5. EventBus源码解析(基于Android(安卓)O)
  6. android系统进程重要等级
  7. 耳机插拔
  8. Android退出监听
  9. Android(安卓)7.1 系统 部分功能修改 汇总

随机推荐

  1. 为你的Android(安卓)App实现自签名的 SSL
  2. android 6.0 Launcher3 去掉抽屉式,显示
  3. Android采用SharedPreferences保存用户登
  4. Android:解决全屏界面到带有状态栏界面切
  5. ScrollView 的一些属性
  6. android将图片转成字符串,再将字符串转成
  7. Tasker, Android系统增强神器
  8. Android(安卓)基于Socket.io即时通讯IM实
  9. Android静态安全检测 -> 明文数字证书风
  10. Genymotion安装