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.在此处打断点,调试
rawSocket为
所以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();
}
public Socket() {
this.impl = factory != null ? factory.createSocketImpl() : new PlainSocketImpl();
this.proxy = null;
}
public PlainSocketImpl() {
this(new FileDescriptor());
}
7.以上步骤还没通过jni调用libc.so,真正创建socket是在connectSocket中
okhttp3.internal.io.RealConnection#connect
connectSocket(connectTimeout, readTimeout, writeTimeout, connectionSpecSelector);
/** 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);
/**
* 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));
}
/**
* 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);
}
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); }
public native FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException;
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_errno
END(socket)