1.概述

OkHttp3的最底层是Socket,而不是URLConnection,它通过Platform的Class.forName()反射获得当前Runtime使用的socket库,调用栈如下

okhttp//实现HTTP协议
==>framwork//JRE,实现JDK中Socket封装
    ==>jvm//JDK的实现,本质对libc标准库的native封装
        ==>bionic//android下的libc标准库
            ==>systemcall//用户态切换入内核
                ==>kernel//实现下协议栈(L4,L3)与网络驱动(一般是L2,L1)

注:需求决定,Android版本4.4.4 okhttp 3.2.0


2.因为底层使用Socket,所以在okhttp3源码全局搜索"new Socket"这个关键词,定位在:

okhttp3.internal.io.RealConnection#connect

rawSocket = proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP            ? address.socketFactory().createSocket()            : new Socket(proxy);

3.在此处打断点,调试

Android okhttp3 创建Socket的底层实现追踪_第1张图片


rawSocket为

Android okhttp3 创建Socket的底层实现追踪_第2张图片

所以address.socketFactory()返回的是DefaultSocketFactory.java


4./libcore/luni/src/main/java/javax/net/DefaultSocketFactory.java

/** * Default implementation of {@link javax.net.SocketFactory} */final class DefaultSocketFactory extends SocketFactory {    DefaultSocketFactory() {    }    @Override    public Socket createSocket() throws IOException {        return new Socket();    }


5./ libcore/ luni/ src/ main/ java/ java/ net/ Socket.java

    public Socket() {        this.impl = factory != null ? factory.createSocketImpl() : new PlainSocketImpl();        this.proxy = null;    }

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

    public PlainSocketImpl() {        this(new FileDescriptor());    }

7.以上步骤还没通过jni调用libc.so,真正创建socket是在connectSocket中

okhttp3.internal.io.RealConnection#connect

   
connectSocket(connectTimeout, readTimeout, writeTimeout, connectionSpecSelector);


8.okhttp3.internal.io.RealConnection#connectSocket
  /** Does all the work necessary to build a full HTTP or HTTPS connection on a raw socket. */  private void connectSocket(int connectTimeout, int readTimeout, int writeTimeout,      ConnectionSpecSelector connectionSpecSelector) throws IOException {    rawSocket.setSoTimeout(readTimeout);


9./ libcore/ luni/ src/ main/ java/ java/ net/ Socket.java#setSoTimeout

    /**     * Sets this socket's {@link SocketOptions#SO_TIMEOUT read timeout} in milliseconds.     * Use 0 for no timeout.     * To take effect, this option must be set before the blocking method was called.     */    public synchronized void setSoTimeout(int timeout) throws SocketException {        checkOpenAndCreate(true);        if (timeout < 0) {            throw new IllegalArgumentException("timeout < 0");        }        impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout));    }

10./ libcore/ luni/ src/ main/ java/ java/ net/ Socket.java#checkOpenAndCreate

    /**     * Checks whether the socket is closed, and throws an exception. Otherwise     * creates the underlying SocketImpl.     *     * @throws SocketException     *             if the socket is closed.     */    private void checkOpenAndCreate(boolean create) throws SocketException {        if (isClosed()) {            throw new SocketException("Socket is closed");        }        if (!create) {            if (!isConnected()) {                throw new SocketException("Socket is not connected");                // a connected socket must be created            }            /*             * return directly to fix a possible bug, if !create, should return             * here             */            return;        }        if (isCreated) {            return;        }        synchronized (this) {            if (isCreated) {                return;            }            try {                impl.create(true);            } catch (SocketException e) {                throw e;            } catch (IOException e) {                throw new SocketException(e.toString());            }            isCreated = true;        }    }

最后调用PlainSocketImpl.java的create


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

    protected void create(boolean streaming) throws IOException {        this.streaming = streaming;        this.fd = IoBridge.socket(streaming);    }

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

    public static FileDescriptor socket(boolean stream) throws SocketException {        FileDescriptor fd;        try {            fd = Libcore.os.socket(AF_INET6, stream ? SOCK_STREAM : SOCK_DGRAM, 0);            // The RFC (http://www.ietf.org/rfc/rfc3493.txt) says that IPV6_MULTICAST_HOPS defaults            // to 1. The Linux kernel (at least up to 2.6.38) accidentally defaults to 64 (which            // would be correct for the *unicast* hop limit).            // See http://www.spinics.net/lists/netdev/msg129022.html, though no patch appears to            // have been applied as a result of that discussion. If that bug is ever fixed, we can            // remove this code. Until then, we manually set the hop limit on IPv6 datagram sockets.            // (IPv4 is already correct.)            if (!stream) {                Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 1);            }            return fd;        } catch (ErrnoException errnoException) {            throw errnoException.rethrowAsSocketException();        }    }
总算往jni方向去了:Libcore.os.socket(AF_INET6, stream ? SOCK_STREAM : SOCK_DGRAM, 0)

可见:创建socket时,domain为AF_INET6,类型为SOCK_STREAM(对于http来说)

在c层可以用这两个条件来过滤http的socket创建


12.

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

public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException {        return tagSocket(os.socket(domain, type, protocol));    }

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

public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException {  return os.socket(domain, type, protocol); }


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

public native FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException;


14. / libcore / luni / src / main / native / libcore_io_Posix.cpp       JNI层,此方法为java的代理

static jobject Posix_socket(JNIEnv* env, jobject, jint domain, jint type, jint protocol) {    int fd = throwIfMinusOne(env, "socket", TEMP_FAILURE_RETRY(socket(domain, type, protocol)));    return fd != -1 ? jniCreateFileDescriptor(env, fd) : NULL;}

NATIVE_METHOD(Posix, socket, "(III)Ljava/io/FileDescriptor;"),


15./bionic/libc/arch-arm/syscalls/socket.S

socket通过汇编实现,汇编代码中通过swi调用中断号实现功能

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

至此,socket创建跟踪完毕~











更多相关文章

  1. Android AdbCommandRejectedException和cannot bind to套接字地
  2. Android分别使用HTTP协议和TCP协议实现上传文件
  3. Android底层驱动开发 -驱动配置篇
  4. Android底层开发技术实战详解——内核、移植和驱动
  5. 蓝牙协议栈调试记录

随机推荐

  1. android studio 3.1.1 创建项目编译不过
  2. Android各个版本API的区别
  3. 64位Ubuntu Kylin14编译android内核
  4. Android(安卓)Tab 控件详解及实例
  5. Android学习笔记之TabHost
  6. Android的MediaRecorder架构介绍
  7. Android快速开发02之仿京东底部Tab
  8. android studio ndk开发遇到的问题
  9. android Ant批打包学习(一):生成没有签名
  10. Android中的DownloadManager