android 网络框架 源码分析
导语:
最近想开发一个协议分析工具,来监控android app 所有的网络操作行为, 由于android 开发分为Java层,和Native层, 对于Native层我们只要对linux下所有网络I/O接口进行拦截即可,对于java 层,笔者对android 网络框架不是很了解,所以这个工具开发之前,笔者需要对android 的网络框架进行一个简单的分析。
分析结论:
1. android 的网络框架都是基于Socket类实现的
2. java 层Socket具体实现和平台喜相关,最终I/O操作实现调用C库函数完成
3. 我们可以在Native层 拦截Linux下接网络I/O 接口来完成对android app 所有网络操作行为的捕获
分析情景1:
android很多框架都是基于Socket类基础进行的,所以我们从Socket类开始分析, 一下是一个我们常用使用Socket的案例
<span data-wiz-span="data-wiz-span" style="font-family: ‘Courier New‘;">Sokect client = new Socket("127.0.0.1", 5555);
PrintWriter out = new PrintWriter(client.getOutputStream());
out.println("hello world");</span>
我们发现关键函数实现是是getOutputStream, 如何获取一个输出流。
Socket. getOutputStream:
<span data-wiz-span="data-wiz-span" style="font-family: ‘Courier New‘;">public OutputStream getOutputStream() throws IOException {
checkOpenAndCreate(false);
if (isOutputShutdown()) {
throw new SocketException("Socket output is shutdown");
}
return impl.getOutputStream();
}</span>
从这个方法的实现,主要在于 我们 final SocketImpl impl, 我们看看这个的对象初始化, 参见够默认构造函数
Socket.Socket: \libcore\luni\src\main\java\java\net\Socket.java
<span data-wiz-span="data-wiz-span" style="font-family: ‘Courier New‘;"> /**
* Creates a new unconnected socket. When a SocketImplFactory is defined it
* creates the internal socket implementation, otherwise the default socket
* implementation will be used for this socket.
*
* @see SocketImplFactory
* @see SocketImpl
*/
public Socket() {
this.impl = factory != null ? factory.createSocketImpl() : new PlainSocketImpl();
this.proxy = null;
}</span>
我们看看PlainSocketImpl.getOutstream
<span data-wiz-span="data-wiz-span" style="font-family: ‘Courier New‘;"> @Override
protected synchronized OutputStream getOutputStream() throws IOException {
checkNotClosed();
return new SocketOutputStream(this);
}</span>
所以我们调用Soccket.getOutstream 返回的是一个SocketOutputStream。然后通过这个对象进行I/O 操作, 我们分析其中一个I/O操作------write.
SocketOutputStream.write: \libcore\luni\src\main\java\org\apache\harmony\luni\net\SocketOutputStream.java
<span data-wiz-span="data-wiz-span" style="font-family: ‘Courier New‘;"> @Override
public void write(byte[] buffer, int offset, int count) throws IOException {
if (buffer == null) {
throw new NullPointerException("buffer == null");
}
if (0 <= offset && offset <= buffer.length && 0 <= count && count <= buffer.length - offset) {
socket.write(buffer, offset, count);
} else {
throw new ArrayIndexOutOfBoundsException();
}
}</span>
发现具体实现在Line 7,socket.write(buffer, offset, count) , 这个 socket的声明: private PlainSocketImpl socket; 初始化在构造函数中
<span data-wiz-span="data-wiz-span" style="font-family: ‘Courier New‘;"> public SocketOutputStream(SocketImpl socket) {
super();
this.socket = (PlainSocketImpl) socket;
}</span>
继续分析PlainSocketImpl.write
<span data-wiz-span="data-wiz-span" style="font-family: ‘Courier New‘;"> int write(byte[] buffer, int offset, int count) throws IOException {
if (streaming) {
return netImpl.write(fd, buffer, offset, count);
} else {
return netImpl.send(fd, buffer, offset, count, port, address);
}
}</span>
stream 默认为true即(TCP), netImpl 是一个和平台相关的对象, 如下
<span data-wiz-span="data-wiz-span" style="font-family: ‘Courier New‘;">protected INetworkSystem netImpl = Platform.getNetworkSystem();
private boolean streaming = true;</span>
我们看看 Platform.getNetworkSystem()
<span data-wiz-span="data-wiz-span" style="font-family: ‘Courier New‘;"> public static INetworkSystem getNetworkSystem() {
accessCheck();
// TODO: use BlockGuard here too, like in getFileSystem() above.
return NETWORK_SYSTEM;
}</span>
NETWORK_SYSTEM 参见
<span data-wiz-span="data-wiz-span" style="font-family: ‘Courier New‘;"> private static final INetworkSystem NETWORK_SYSTEM =
new BlockGuard.WrappedNetworkSystem(OSNetworkSystem.getOSNetworkSystem());</span>
BlockGuard.WrappedNetworkSystem 只是对对象进行简单的封装,具体实现在OSNetworkSystem.getOSNetworkSystem()
分析:OSNetworkSystem.getOSNetworkSystem
<span data-wiz-span="data-wiz-span" style="font-family: ‘Courier New‘;">/**
* This wraps native code that implements the INetworkSystem interface.
* Address length was changed from long to int for performance reasons.
*/
final class OSNetworkSystem implements INetworkSystem {
private static final OSNetworkSystem singleton = new OSNetworkSystem();
public static OSNetworkSystem getOSNetworkSystem() {
return singleton;
}
private OSNetworkSystem() {
}
public native void accept(FileDescriptor serverFd, SocketImpl newSocket, FileDescriptor clientFd) throws IOException;
public native void bind(FileDescriptor fd, InetAddress inetAddress, int port) throws SocketException;
public native void connect(FileDescriptor fd, InetAddress inetAddress, int port, int timeout) throws SocketException;
public native boolean connectNonBlocking(FileDescriptor fd, InetAddress inetAddress, int port) throws IOException;
public native boolean isConnected(FileDescriptor fd, int timeout) throws IOException;
public native void socket(FileDescriptor fd, boolean stream) throws SocketException;
public native void disconnectDatagram(FileDescriptor fd) throws SocketException;
public native InetAddress getSocketLocalAddress(FileDescriptor fd);
public native int getSocketLocalPort(FileDescriptor fd);
public native Object getSocketOption(FileDescriptor fd, int opt) throws SocketException;
public native void listen(FileDescriptor fd, int backlog) throws SocketException;
public native int read(FileDescriptor fd, byte[] data, int offset, int count) throws IOException;
public native int readDirect(FileDescriptor fd, int address, int count) throws IOException;
public native int recv(FileDescriptor fd, DatagramPacket packet, byte[] data, int offset, int length, boolean peek, boolean connected) throws IOException;
public native int recvDirect(FileDescriptor fd, DatagramPacket packet, int address, int offset, int length, boolean peek, boolean connected) throws IOException;
static native boolean selectImpl(FileDescriptor[] readfd,FileDescriptor[] writefd, int cread, int cwirte, int[] flags, long timeout);
public native int send(FileDescriptor fd, byte[] data, int offset, int length, int port, InetAddress inetAddress) throws IOException;
public native int sendDirect(FileDescriptor fd, int address, int offset, int length, int port, InetAddress inetAddress) throws IOException;
public native void sendUrgentData(FileDescriptor fd, byte value);
public native void setInetAddress(InetAddress sender, byte[] address);
public native void setSocketOption(FileDescriptor fd, int opt, Object optVal) throws SocketException;
public native void shutdownInput(FileDescriptor fd) throws IOException;
public native void shutdownOutput(FileDescriptor fd) throws IOException;
public native void close(FileDescriptor fd) throws IOException;
public native int write(FileDescriptor fd, byte[] data, int offset, int count) throws IOException;
public native int writeDirect(FileDescriptor fd, int address, int offset, int count) throws IOException;
}</span>
这里提供所有关网络操作的接口,这些函数在本地代码实现,是文件中实现:libcore\luni\src\main\native\org_apache_harmony_luni_platform_OSNetworkSystem.cpp, 我们分析其中一个I/O操作---- write:OSNetworkSystem_write
OSNetworkSystem_write:libcore\luni\src\main\native\org_apache_harmony_luni_platform_OSNetworkSystem.cpp
<span data-wiz-span="data-wiz-span" style="font-family: ‘Courier New‘;">static jint OSNetworkSystem_write(JNIEnv* env, jobject,
jobject fileDescriptor, jbyteArray byteArray, jint offset, jint count) {
ScopedByteArrayRW bytes(env, byteArray);
if (bytes.get() == NULL) {
return -1;
}
jint address = static_cast<jint>(reinterpret_cast<uintptr_t>(bytes.get()));
int result = OSNetworkSystem_writeDirect(env, NULL, fileDescriptor, address, offset, count);
return result;
}</span>
Line 8:调用OSNetworkSystem_writeDirect 完成操作
<span data-wiz-span="data-wiz-span" style="font-family: ‘Courier New‘;">static jint OSNetworkSystem_writeDirect(JNIEnv* env, jobject,
jobject fileDescriptor, jint address, jint offset, jint count) {
if (count <= 0) {
return 0;
}
NetFd fd(env, fileDescriptor);
if (fd.isClosed()) {
return 0;
}
jbyte* src = reinterpret_cast<jbyte*>(static_cast<uintptr_t>(address + offset));
ssize_t bytesSent;
{
int intFd = fd.get();
AsynchronousSocketCloseMonitor monitor(intFd);
bytesSent = NET_FAILURE_RETRY(fd, write(intFd, src, count));
}
if (env->ExceptionOccurred()) {
return -1;
}
if (bytesSent == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// We were asked to write to a non-blocking socket, but were told
// it would block, so report "no bytes written".
return 0;
} else {
jniThrowSocketException(env, errno);
return 0;
}
}
return bytesSent;
}</span>
line 18: 具体调用libc 含糊write 函数, 至此,我们分析完毕