android 网络框架 源码分析

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 函数, 至此,我们分析完毕

来自为知笔记(Wiz)

时间: 2024-12-04 16:35:53

android 网络框架 源码分析的相关文章

Android网络框架源码分析一---Volley

转载自 http://www.jianshu.com/p/9e17727f31a1?utm_campaign=maleskine&utm_content=note&utm_medium=mobile_author_hots&utm_source=recommendation 公司最近新起了一个项目,对喜欢尝鲜的我们来说,好处就是我们可以在真实的项目中想尝试一些新技术,验证想法.新项目对网络框架的选取,我们存在三种方案: 1.和我们之前的项目一样,使用Loader + HttpCli

Android Small插件化框架源码分析

Android Small插件化框架源码分析 目录 概述 Small如何使用 插件加载流程 待改进的地方 一.概述 Small是一个写得非常简洁的插件化框架,工程源码位置:https://github.com/wequick/Small 插件化的方案,说到底要解决的核心问题只有三个: 1.1 插件类的加载 这个问题的解决和其它插件化框架的解决方法差不多.Android的类是由DexClassLoader加载的,通过反射可以将插件包动态加载进去.Small的gradle插件生成的是.so包,在初始

携程DynamicAPK插件化框架源码分析

携程DynamicAPK插件化框架源码分析 Author:莫川 插件核心思想 1.aapt的改造 分别对不同的插件项目分配不同的packageId,然后对各个插件的资源进行编译,生成R文件,然后与宿主项目的R文件进行id的合并. 要求:由于最终会将所有的资源文件id进行合并,因此,所有的资源名称均不能相同. 2.运行ClassLoader加载各Bundle 和MultiDex的思路是一样的,所有的插件都被加载到同一个ClassLoader当中,因此,不同插件中的Class必须保持包名和类名的唯一

子墨庖丁Android的ActionBar源码分析 (一)实例化

如果你从事过Android客户端开发,相信你对ActionBar这套框架并不陌生,或者说你并不了解它,但是你应该时不时的要跟它打交道.抛开ActionBar的实现不说,ActionBar实际上是对Android的TitleBar行为的抽象,这种框架可以适用于这种模式的应用,是对需要的行为视图的抽象.当然或许你也和我一样,对ActionBar的实现效率并不满意,因为你打开它的视图,你会发现它的实现非常的ugly.不过我们庆幸的看到的是,ActionBar在设计的时候就并不是以一个强类型的姿态存在,

iOS常用框架源码分析

SDWebImage NSCache 类似可变字典,线程安全,使用可变字典自定义实现缓存时需要考虑加锁和释放锁 在内存不足时NSCache会自动释放存储的对象,不需要手动干预 NSCache的key不会被复制,所以key不需要实现NSCopying协议 第三方框架 网络 1.PPNetworkHelper 对AFNetworking 3.x 与YYCache的二次封装 简单易用,包含了缓存机制,控制台可以直接打印json中文字符 2..YTKNetwork 猿题库研发团队基于AFNetworki

YII框架源码分析(百度PHP大牛创作-原版-无广告无水印)

                        YII 框架源码分析             百度联盟事业部--黄银锋   目 录 1. 引言 3 1.1.Yii 简介 3 1.2.本文内容与结构 3 2.组件化与模块化 4 2.1.框架加载和运行流程 4 2.2.YiiBase 静态类 5 2.3.组件 6 2.4.模块 9 2.5 .App 应用   10 2.6 .WebApp 应用   11 3.系统组件 13 3.1.日志路由组件  13 3.2.Url 管理组件  15 3.3.异常

Android 开源项目源码分析第一期正式发布

由 Trinea 发起.几十名 Android 开发者参与的Android 开源项目源码分析第一期正式发布. 从简介.总体设计.流程图.详细设计全方面分析开源库源码,第一期包括 10 个著名开源库及 5 个公共技术点的全面介绍. 分析文档 作者 Volley 源码解析 grumoon Universal Image Loader 源码分析 huxian99 Dagger 源码解析 扔物线 EventBus 源码解析 Trinea xUtils 源码解析 Caij ViewPagerindicat

Android -- 消息处理机制源码分析(Looper,Handler,Message)

android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因此我没将其作为核心类.下面一一介绍: Looper Looper的字面意思是“循环者”,它被设计用来使一个普通线程变成Looper线程.所谓Looper线程就是循环工作的线程.在程序开发中(尤其是GUI开发中),我们经常会需要一个线程不断循环,一旦有新任务则执行,执行完继续等待下一个任务,这就是Lo

介绍开源的.net通信框架NetworkComms框架 源码分析

原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 售价249英镑 我曾经花了2千多购买过此通讯框架, 目前作者已经开源  许可是:Apache License v2 开源地址是:https://github.com/MarcFletcher/NetworkComms.Net 这个框架给我的感觉是,代码很优美,运行很稳定,我有一个项目使用此框架已经稳定运行1年多.这个框架能够