Android 5.1
Socket 的实现
libcore/luni/src/main/java/java/net/Socket.java
public class Socket implements Closeable {
private static SocketImplFactory factory;
final SocketImpl impl;
public Socket() {
this.impl = factory != null ? factory.createSocketImpl() : new PlainSocketImpl();
this.proxy = null;
}
public void connect(SocketAddress remoteAddr, int timeout) throws IOException {
checkOpenAndCreate(true);
if (timeout < 0) {
throw new IllegalArgumentException("timeout < 0");
}
if (isConnected()) {
throw new SocketException("Already connected");
}
if (remoteAddr == null) {
throw new IllegalArgumentException("remoteAddr == null");
}
if (!(remoteAddr instanceof InetSocketAddress)) {
throw new IllegalArgumentException("Remote address not an InetSocketAddress: " +
remoteAddr.getClass());
}
InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
InetAddress addr;
if ((addr = inetAddr.getAddress()) == null) {
throw new UnknownHostException("Host is unresolved: " + inetAddr.getHostName());
}
int port = inetAddr.getPort();
checkDestination(addr, port);
synchronized (connectLock) {
try {
if (!isBound()) {
// socket already created at this point by earlier call or
// checkOpenAndCreate this caused us to lose socket
// options on create
// impl.create(true);
if (!usingSocks()) {
impl.bind(Inet4Address.ANY, 0);
}
isBound = true;
}
impl.connect(remoteAddr, timeout);
isConnected = true;
cacheLocalAddress();
} catch (IOException e) {
impl.close();
throw e;
}
}
}
}
实际由PlainSocketImpl调用IoBridge类完成功能,
luni/src/main/java/java/net/PlainSocketImpl.java
protected void create(boolean streaming) throws IOException {
this.streaming = streaming;
this.fd = IoBridge.socket(streaming);
}
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);
}
address = normalAddr;
port = aPort;
}
IoBridge.connect(fd, normalAddr, aPort, timeout);
\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();
}
}
libcore\luni\src\main\java\libcore\io\Libcore.java
public final class Libcore {
private Libcore() { }
public static Os os = new BlockGuardOs(new Posix());
}
真正工作类,通过系统条用,调用内核的实现
libcore\luni\src\main\java\libcore\io\Posix.java
libcore\luni\src\main\native\libcore_io_Posix.cpp
/* Used to retry syscalls that can return EINTR. */
#define TEMP_FAILURE_RETRY(exp) ({ \
__typeof__(exp) _rc; \
do { \
_rc = (exp); \
} while (_rc == -1 && errno == EINTR); \
_rc; })
#define NET_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ...) ({ \
return_type _rc = -1; \
do { \
bool _wasSignaled; \
int _syscallErrno; \
{ \
int _fd = jniGetFDFromFileDescriptor(jni_env, java_fd); \
AsynchronousCloseMonitor _monitor(_fd); \
_rc = syscall_name(_fd, __VA_ARGS__); \
_syscallErrno = errno; \
_wasSignaled = _monitor.wasSignaled(); \
} \
if (_wasSignaled) { \
jniThrowException(jni_env, "java/net/SocketException", "Socket closed"); \
_rc = -1; \
break; \
} \
if (_rc == -1 && _syscallErrno != EINTR) { \
/* TODO: with a format string we could show the arguments too, like strace(1). */ \
throwErrnoException(jni_env, # syscall_name); \
break; \
} \
} while (_rc == -1); /* _syscallErrno == EINTR && !_wasSignaled */ \
_rc; })
bionic\libc\arch-arm\syscalls包涵了系统调用命令
\bionic\libc\bionic\socket.cpp
int socket(int domain, int type, int protocol) {
return __netdClientDispatch.socket(domain, type, protocol);
}
bionic\libc\private\NetdClientDispatch.h
bionic\libc\bionic\NetdClientDispatch.cpp
struct NetdClientDispatch {
int (*accept4)(int, struct sockaddr*, socklen_t*, int);
int (*connect)(int, const struct sockaddr*, socklen_t);
int (*socket)(int, int, int);
unsigned (*netIdForResolv)(unsigned);
};
// This structure is modified only at startup (when libc.so is loaded) and never
// afterwards, so it's okay that it's read later at runtime without a lock.
__LIBC_HIDDEN__ NetdClientDispatch __netdClientDispatch __attribute__((aligned(32))) = {
__accept4,
__connect,
__socket,
fallBackNetIdForResolv,
};
bionic\libc\kernel\arch-arm\asm\unistd.h