Android 流量优化(一):模块化流量统计

有个用户说一夜间跑了几百兆的移动流量,流量是哪里产生的?是不是哪里有代码缺陷?怎样定位到问题? 于是想着把流量划分模块的统计下来,以便优化App的整体健康;
    如果仅统计应用总流量,TrafficStats 类提供的接口就足以实现了;
    现在我们需要分析流量的成分,一直没有发现比较好的方法。TrafficStats类的方法setThreadStatsTag(int)可以标记线程,那么这个标记什么时候使用呢?Android monitor里面获取的流量数据是包含有tag的,系统肯定将tag信息存储在了某个地方。后来发现Android系统将放流量数据信息保存在文件/proc/net/xt_qtaguid/stats 中(见源码),于是我们可以通过下面的方式,分析流量来源!


模块划分


     首先要对应用进行模块划分,模块值Tag区间[0,0xFFFFFF00)。使用位表示模块与子模块之间的关系,例如0xGGPPCC00,GG一级模块、PP一级模块下的子模块,类推;
千牛是按照API接口划分的,当然也可以按照业务场景划分模块;


标记流量源

     使用TrafficStats.setThreadTag(int tag)方法标记的产生流量的线程,参数tag是上面模块相关的tag;@See TrafficStats;
     NOTE:1、一个线程同时只会有一个有效的tag,并且不会传递,依赖包启动了新线程访问网络则需要依赖方提供标记支持;2、
native层socket、webview产生的流量无法使用此方法标记;
      标记流量后,可以在monitor网络界面查看流量变化,不同的tag会绘制为不同的颜色,可以先在本地分析下,使用的时候网络请求是否有冗余;<此处应有配图>

获取统计值


通过adb命令可以查看流量内容 adb shell cat /proc/net/xt_qtaguid/stats :

Android 流量优化(一):模块化流量统计_第1张图片

iface:网络性质[vlan-wifi流量 lo-本地流量 rmnet0-3g/2g流量 ...]

acct_tag_hex: 线程标记,也就是上面我们做的标记

uid_tag_int: 应用UID,据此判断是否是某应用统计的流量数据

cnt_set: 应用前后台标志位:1-前台,0-后台

rx_bytes: read 总接受字节

tx_bytes:  transfer总发送字节

其中acct_tag_hex 为0x0的一行为某应用开机以来产生的总流量;
搞明白字段意思了解析起来也就比较容易了,直接贴代码
NOTE:这里统计的流量是开机之后所有的流量统计

try {
            FileReader stream = new FileReader(DEV_FILE);
            BufferedReader in = new BufferedReader(stream, 500);
            String line;
            String[] dataStrings;
            while ((line = in.readLine()) != null) {
                dataStrings = line.split(" ");
                if (StringUtils.equals(uid, dataStrings[3])) {
                    TrafficData dataTotal = new TrafficData();
                    TrafficData dataDiff = new TrafficData();

                    dataTotal.iface = dataDiff.iface = dataStrings[1];
                    dataTotal.moduleTag = dataDiff.moduleTag = dataStrings[2];
                    dataTotal.cnt_set = dataDiff.cnt_set = dataStrings[4];

                    dataTotal.rx_bytes = Integer.parseInt(dataStrings[5]);
                    dataTotal.tx_bytes = Integer.parseInt(dataStrings[6]);

                    //全量
                    if (dataTotal.rx_bytes + dataTotal.tx_bytes > 0) {
                        trafficDataList.add(dataTotal);

                        //需要根据存储值计算增量
                        
                    }
                }
            }
            FileStoreProxy.setListValue(trafficDataList);
            in.close();
            stream.close();
        } catch (Exception e) {
        }

 

你可能感兴趣的:(Android)