Loading [MathJax]/jax/input/TeX/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >坎坷之下出新招:记一次应用带宽峰值测试的探索历程

坎坷之下出新招:记一次应用带宽峰值测试的探索历程

原创
作者头像
陈帅
发布于 2017-10-12 01:26:43
发布于 2017-10-12 01:26:43
2K00
代码可运行
举报
文章被收录于专栏:陈帅的专栏陈帅的专栏
运行总次数:0
代码可运行

测试前

最近在做一场流量性能测试,期望得到的结果,既不是应用关键场景需要使用的流量总量,也不是应用跑起来后的平均带宽值。而是一个叫带宽峰值的玩意儿,它代表一段时间内,这个应用1s内最高会收发多少数据。有什么特别的呢?

流量测试一般的测试方法:定义关键场景,关键场景前流量值– 场景后流量值= 流量总量。流量总量/时长 = 平均带宽。

测试手段:

  1. 流量卡。主要是记录流量起始点流量卡的流量值,和结束点流量卡的流量值。
  2. GT工具或Emmagee工具。都是每秒都在采样带宽值。
  3. DDMS。需要被测应用是debug包。

在接到需求后,认真分析了上面的测试方法和测试手段,发现只有GT或Emmagee基本能够满足,因为带宽峰值的含义就是一段时间内,带宽值曲线上的最高点。

开始撞墙

一开始我是很信赖GT的,毕竟是我大腾讯同事出品。直到测试开始,它给了我类似以下两组数据(一是负数,二是带宽一点点增加)。

GT输出的带宽测试报告

现有的工具无法满足需求,只能自己动手,丰衣足食了。首先理清楚我们可以从哪些地方拿到实时的流量数据:

  1. 从系统文件(/proc/net/xt_qtaguid/stats)中,可以很方便的拿出每个uid的流量数据,如下图,从0开始,第3列是uid,第五列是接收数据的bytes数,第七列是发送数据的bytes数。

Proc文件中的流量数据

  1. android.net.TrafficStats这个类中提供了一大堆方法用于获取流量数据的方法。其中主要包括:

a) getUidRxBytes(int uid)和getUidTxBytes(int uid);

b) getTotalRxBytes()和getTotalTxBytes();

c) getRxBytes(String iface)和getTxBytes(String iface);

第一次撞墙

需要准确获取一个应用的实时带宽,从字面意义上看,似乎选择以上第1点中的方法,或者第2点中的a更加合适,一个文件读取,一个系统接口获取,都是直接取出了对应uid的流量数据。于是根据1,我迅速的码出了如下代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static FileReader mReader = null;
static BufferedReader mBufReader = null;
public static long getTrafficInfo1(int uid) {
    String fileName = "/proc/net/xt_qtaguid/stats";
    long ret = 0;
        try{
mReader = new FileReader(fileName);
            mBufReader = new BufferedReader(mReader);
            String line = null;
            int count = 0;
            while ( (line = mBufReader.readLine()) != null){
                count++;
                if(count == 1 ) continue;
                String[] vecTemp = line.split("[:\\s]+");
                if(vecTemp[1].equals("wlan0") && Integer.valueOf(vecTemp[3]) == uid){
                    ret += Long.valueOf(vecTemp[5]) + Long.valueOf(vecTemp[7]);
                }
            }
        }catch (IOException e){
            Log.e(LOG_TAG,e.getMessage());
        }finally {
try {
if (mBufReader != null) {
mBufReader.close();
                }
if (mReader != null) {
mReader.close();
                }
            }catch (IOException e){
                Log.e(LOG_TAG,e.getMessage());
            }
        }
return ret;
}

然后悲催的发现,虽然通过命令:

adb shell cat /proc/net/xt_qtaguid/stats

能够看到一行行漂亮的数据,在应用程序中却始终都只能读取到title行。这个地方暂时没找到为什么,大概怀疑点是Android权限的问题。

当然我们可以写个运行在PC端的脚本程序,然后adb连接着被测手机,cat出该文件然后再分析,然而带宽峰值的测试,依赖于大样本量,连着ADB跑,这个就局限了,只能我一个人测试,想找其他人帮忙太麻烦。

第二次撞墙

第一种方法不行,马上换。TrafficStats中的getUidRxBytes(int uid)和getUidTxBytes(int uid)这两个接口是否可行呢?看了Emmagee的源码,关于流量的测试,它还真是用这两个接口实现的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static long getTrafficInfo(int uid) {
    Log.i(LOG_TAG, "get traffic information");
    long rcvTraffic = UNSUPPORTED;
    long sndTraffic = UNSUPPORTED;
    // Use getUidRxBytes and getUidTxBytes to get network traffic,these API
    // return both tcp and udp usage
    rcvTraffic = TrafficStats.getUidRxBytes(uid);
    sndTraffic = TrafficStats.getUidTxBytes(uid);
    if (rcvTraffic == UNSUPPORTED || sndTraffic == UNSUPPORTED) {
return UNSUPPORTED;
    } else
        return rcvTraffic + sndTraffic;
}

Copy好代码,然后冒出一个问号,为什么要特意标记一个UNSUPPORTED呢?瞄一眼源码,从注释和代码中可以看出,4.3以下这个接口是没有的;7.0及以上,这个接口只能用来拿应用本身的Traffic数据;要拿其他人的?详情请看NetworkStatsManager。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * Return number of bytes transmitted by the given UID since device boot.
 * Counts packets across all network interfaces, and always increases
 * monotonically since device boot. Statistics are measured at the network
 * layer, so they include both TCP and UDP usage.
 * <p>
 * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
 * return {@link #UNSUPPORTED} on devices where statistics aren't available.
 * <p>
 * Starting in {@link android.os.Build.VERSION_CODES#N} this will only
 * report traffic statistics for the calling UID. It will return
 * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access
 * historical network statistics belonging to other UIDs, use
 * {@link NetworkStatsManager}.
 *
 * @see android.os.Process#myUid()
 * @see android.content.pm.ApplicationInfo#uid
 */
public static long getUidTxBytes(int uid) {
// This isn't actually enforcing any security; it just returns the
    // unsupported value. The real filtering is done at the kernel level.
    final int callingUid = android.os.Process.myUid();
    if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
return nativeGetUidStat(uid, TYPE_TX_BYTES);
    } else {
return UNSUPPORTED;
    }
}

看来这是Android版本碎片化带来的坑,瞬间体会到了开发同学做兼容适配的痛苦。

最终方案

由于项目急需用了,最终决定不再纠结于用哪个API。直接使用以下两种方法来做,只是在测试前先杀掉其他应用,如果有手机管家的话,开启管家的禁止联网功能,保证只有被测应用在联网:

  1. getTotalRxBytes()和getTotalTxBytes();
  2. getRxBytes(String iface)和getTxBytes(String iface);

具体代码实现:

第一个比较简单,直接调用即可。第二个因为getRxBytes(String iface)是隐藏方法,所以需要通过反射拿到该方法进行invoke。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static {
try {
        Class<?> claxx = Class.forName("android.net.TrafficStats");
        mgetRxBytesMethod = claxx.getDeclaredMethod("getRxBytes", String.class);
        mgetTxBytesMethod = claxx.getDeclaredMethod("getTxBytes", String.class);
        mgetRxBytesMethod.setAccessible(true);
        mgetTxBytesMethod.setAccessible(true);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static long getRxBytes(String iface){
long ret = -1;
    try {
        ret = Long.valueOf(mgetRxBytesMethod.invoke(null,"wlan0").toString());
    }catch (Exception e){
        e.printStackTrace();
    }
return ret;
}

public static long getTxBytes(String iface){
long ret = -1;
    try {
        ret = Long.valueOf(mgetTxBytesMethod.invoke(null,"wlan0").toString());
    }catch (Exception e){
        e.printStackTrace();
    }
return ret;
}

计算逻辑:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class CountRunnable implements Runnable {
@Override
    public void run() {
        String dataSavePath = DataSaveHandler.getFilePath("band");
        //通知界面刷新
        notifyStart(dataSavePath);

        long current = 0;
        long last = 0;
        long lastSnd = 0;  //上次发
        long lastRcv = 0;  //上次收
        long currentSnd = 0;
        long currentRcv = 0;
        int count = 0;
        while (!isGoingToStop) {
            count++;
            //获取所有网卡的流量
            // currentSnd = TrafficStats.getTotalTxBytes();
            // currentRcv = TrafficStats.getTotalRxBytes();
            //获取wifi网卡上的流量
            currentSnd = TrafficInfo.getRxBytes("wlan0");
            currentRcv = TrafficInfo.getTxBytes("wlan0");
            current = System.currentTimeMillis();
            SystemClock.sleep(100);
            if (count == 1) {
                last = current;
                lastSnd = currentSnd;
                lastRcv = currentRcv;
                continue;  //首次只收集current数据
            }
if (current - last < 1000) {  continue; }
            last = current;
            long sndBand = currentSnd - lastSnd;
            long rcvBand = currentRcv - lastRcv;
            //每次都刷新并保存该文件,能够保证即使不停止,也会有数据
            DataSaveHandler.openFileWriter(dataSavePath);
            float bandInKB = ((float) (sndBand + rcvBand))/1000;
            DecimalFormat df = new DecimalFormat();
            df.applyPattern("0.000");
            DataSaveHandler.writeNewLine(mLogSdf.format(current) + "," + sndBand + "," + rcvBand+","+df.format(bandInKB));
            DataSaveHandler.saveAndCloseFile();

            lastSnd = currentSnd;
            lastRcv = currentRcv;
        }
//通知界面刷新
        notifyStop(dataSavePath);
    }
}

将代码输出为一个应用,实时收集流量数据,写到csv文件中。将这个测试APP发给大家。测试步骤:

  1. 将被测应用外其他应用关闭;
  2. 开启被测应用,进入关键场景;
  3. 打开测试APP,开始收集带宽数据;
  4. 关键场景结束时,打开测试APP,点击结束;
  5. 将结果adb pull出来发给测试;
  6. 分析取带宽峰值平均值。

这个方法虽然没有直接获取被测APP的流量,但是简单快捷,Android各个版本上的兼容性高,能够快速收集到较多的样本。当然也可以再结合NetworkStatsManager来做兼容适配。

参考文献

http://blog.csdn.net/w7849516230/article/details/71705835

文章来源于:腾讯移动品质中心 TMQ

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Android应用启动流量自动化测试
之前《Tcpdump流量自动化测试上篇》、《Tcpdump流量自动化测试下篇》这两篇文章里讨论了如何通过tcpdump命令行工具来实现Android应用的流量自动化采集和分析,今天再来跟大家分享一下如何针对应用启动场景来做流量测试,有人可能会问了为什么是启动场景?因为现在工信部要求在用户没有授权网络请求前,应用不得擅自进行网络请求,特别是当跟厂商合作提供预装包的时候对此项的检查很严格。
岛哥的质量效能笔记
2021/08/18
1.2K0
Android应用启动流量自动化测试
Android软件测试Monkey测试工具
前言: 最近开始研究Android自动化测试方法,对其中的一些工具、方法和框架做了一些简单的整理,其中包括android测试框架、CTS、Monkey、Monkeyrunner、benchmark、其它test tool等等。因接触时间很短,很多地方有不足之处,希望能和大家多多交流。 一、  什么是Monkey Monkey是Android中的一个命令行工具,可以运行在模拟器里或实际设备中。它向系统发送伪随机的用户事件流(如按键输入、触摸屏输入、手势输入等),实现对正在开发的应用程序进行压力测试。Monk
互联网金融打杂
2018/04/03
4.6K0
Android软件测试Monkey测试工具
网络延迟与带宽性能专项测试
文章主要介绍了移动应用性能测试中网络性能测试方法和相关的数据分析。作者通过一个实际的案例,展示了如何通过工具收集数据、进行网络性能测试,并利用统计方法分析数据。文章还介绍了网络性能测试的常用指标,如延迟、抖动、丢包率等,并阐述了这些指标在移动网络性能测试中的重要性。
陈帅
2017/10/11
7.7K0
网络延迟与带宽性能专项测试
Android APP性能及专项测试
1、运行Monkey进行压力测试: adb shell monkey -p cn.microinvestment.weitou --pct-touch 100 --ingore-crashes --throttle 1000 -s 100 -v -v 50 2、监控内存值,如果出现过大等递增异常则保存HPROF文件(hprof文件是Java 虚拟机的Heap快照)用于分析查看应用内存的命令: adb shell dumpsys meminfo cn.microinvestment.weitou(进程名) 如果发现内存过大,则保存HPROF文件:adb shell am dumpheap <进程名> <保存路径> 3、分析hprof文件 用工具MAT来查看,首先还要这个HPROF文件转换成MAT可读的文件 在Android SDK tool里面有个hprof-conv命令: hprof-conv <原HPROF文件路径> <转换后的HPROF路径> hprof-conv a.hprof b.hprof 4、用MAT工具打开转换后的HPROF文件 一般选择Leak Suspects Report(通过SQL语句来查询对象有没有被释放掉,如果有多个相同的对象,则会存在内存泄露的问题)
测试开发社区
2019/09/20
4K0
19.UI自动化测试框架搭建-性能数据采集
Android 性能稳定性测试工具 mobileperf 开源 (天猫精灵 Android 性能测试-线下篇)
zx钟
2022/12/01
5710
19.UI自动化测试框架搭建-性能数据采集
流量都去哪儿了 —— 三板斧搞定Android网络流量测试
流量是什么? 为什么要进行流量测试? 流量测试方法有哪些? 怎么统计流量并进行结果分析? 带着这些疑问,小编带您探寻Android网络流量的测试方法。 1 流量是什么? 随着智能手机的普及,移动互联网日新月异。人们在享受移动互联网带来的方便的同时,也需要向网络运营商支付昂贵的“流量”费用(在移动网络下)。下图的流量提醒的短信大家应该很熟悉: 事实上,这些流量都是手机里的应用在进行网络通信时所产生。很多流量工具都能帮我们统计各个应用所消耗的流量。下图为小米系统“安全中心”网络助手统计到的流量消耗情况
腾讯移动品质中心TMQ
2018/02/05
4.4K0
流量都去哪儿了 —— 三板斧搞定Android网络流量测试
Android11 WiFi连接流程梳理
一、可以看到点击连接以后,如果config不为null,则先保存网络,再进行连接,所以即使连接失败,此网络依然在已保存网络列表里。 packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java
用户7557625
2021/09/14
4.1K0
Android11 WiFi连接流程梳理
Android KitKat 4.4 Wifi移植AP模式和网络共享的调试日志
Tethering技术在移动平台上已经运用的越来越广泛了。它能够把移动设备当做一个接入点,其它的设备能够通过Wi-Fi。USB或是Bluetooth等方式连接到此移动设备。在Android中能够将Wifi设为AP模式作为WLAN接入点。从而与其它设备共享Android的互联网连接。Android成为接入点后。就无法通过WLAN连接使用Android的应用程序訪问互联网,但能够通过其它方式如以太网或移动网络訪问互联网。
全栈程序员站长
2022/07/05
1.2K0
Android自动化测试探索(一)adb详细介绍
adb,即Android Debug Bridge,它是Android开发/测试人员不可替代的强大工具
周希
2019/10/15
2.8K0
【Android 启动过程】Activity 启动源码分析 ( AMS -> ActivityThread、AMS 线程阶段 )
在 Instrumentation 中 , 通过调用 ActivityManagerService ( AMS ) 的 startActivity 方法 ,
韩曙亮
2023/03/29
1.7K0
【Android 启动过程】Activity 启动源码分析 ( AMS -> ActivityThread、AMS 线程阶段 )
盘点App测试会用到哪些工具
盘点App测试会用到哪些工具 目录 1、常见应用模式 2、常用平台工具 2.1、Android平台 2.2、iOS平台 3、常见的UI自动化框架 3.1、Android平台 3.2、iOS平台 4、常见的单元测试框架 4.1、Android平台 4.2、iOS平台 5、常用的抓包工具 6、弱网模拟 7、常用的专项测试工具 7.1、Android平台 7.2、iOS平台 8、静态代码分析 8.1、Android平台 8.2、iOS平台 9、代码覆盖率 10、常用的云测平
wangmcn
2022/07/26
1K0
玩转ADB命令(ADB命令使用大全)
我相信做Android开发的朋友都用过ADB命令,但是也只是限于安装应用push文件和设备重启相关,更深的就不知道了,其实我们完全可以了解多一点,有一些不常用的场景我们至少应该知道它可以做到,比如,我们知道adb install 却不知道adb shell am start。前者是用来安装软件,后者用来打开软件,后者的一个使用场景让我对他重视:公司定制Android系统,在调试屏幕的时候要看是否满屏验证驱动是否正常,比较麻烦的做法是要拿到Android开发者手里用eclipse或者其他ide安装打开。显然相对于驱动人员连上数据线使用adb命令要复杂得多。因此,了解多一点还是很有必要的。
全栈程序员站长
2022/08/27
10.1K0
玩转ADB命令(ADB命令使用大全)
Android自动化测试探索(四)uiautomator2简介和使用
项目Git地址: https://github.com/openatx/uiautomator2
周希
2019/10/15
6.4K0
支付宝二维码脱机认证库在android的app下测试过程记录
今天收到了第三方库(支付宝的二维码脱机认证库,用来脱机验证支付宝的支付二维码),于是兴奋着调用一下试试,如果测试成功,那么做应用自然也没太大问题。
杨永贞
2020/08/05
5060
支付宝二维码脱机认证库在android的app下测试过程记录
APK安装流程详解14——PMS中的新安装流程上(拷贝)补充
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null) 要看这个方法内部执行,首先要知道这个mContext是什么,我们知道这个mContext是通过PackageManagerService的main方法传入的,所以这个mContext就是SystemServer里面的mSystemContext。 代码在SystemServer.java 366行如下:
隔壁老李头
2018/08/30
3.2K0
APK安装流程详解14——PMS中的新安装流程上(拷贝)补充
测试开发进阶(四十七)
很多时候,手机发热发烫。是因为CPU使用率过高,CPU过于繁忙,会导致手机无法响应用户,整体性能降低,用户体验会很差,也容易引起ANR等一些列问题
zx钟
2019/12/20
7120
测试开发进阶(四十七)
支付宝二维码脱机认证库测试(linux_x86平台验证)
最近在调试支付宝给提供的二维码脱机认证库,他们给提供了几个文档和 libposoffline.so库文件。
杨永贞
2020/08/05
1.3K0
支付宝二维码脱机认证库测试(linux_x86平台验证)
安卓测试常用的 ADB 命令
    adb的工作方式比较特殊采用监听Socket TCP 5554等端口的方式让IDE和Qemu通讯,默认情况下adb会daemon相关的网络端口,所以当我们运行Eclipse时adb进程就会自动运行。  1.通过adb可以轻松的执行Linux Shell命令,如adb shell dir 就是列举目录,在Linux中根目录为/而不是Windows上的C盘、D盘。  2.安装apk程序到模拟器则执行adb install android123.apk,这样名为android123的安装包就会安装到Android模拟器中,前提是android123.apk文件需要放到SDK/Tools目录下。  3.向emulator传送文件, 使用adb push android123.txt /tmp/android123.txt命令可以把SDK/Tools下的android123.txt文件传输到模拟器的/tmp/文件夹中,需要注意的是/tmp/文件夹中内容会在Android模拟器重新启动时清空。  4.从Android仿真器中回传文件到电脑 
测试之道
2021/03/04
5.4K0
broadcast 学习
android的广播在应用开发中使用的场景很多,本篇就介绍下广播的基本内容,然后侧重介绍广播的几个关键流程,包含广播的注册,注销,还有广播的发送,本篇侧重的是流程的学习,希望通过学习该流程可以对Android的广播有一个清晰的过程了解,这块知识在分析anr问题的时候很有帮助。
一只小虾米
2022/10/25
5160
解开Android应用程序组件Activity的”singleTask”之谜
在Android应用程序中,可以配置Activity以四种方式来启动,其中最令人迷惑的就是”singleTask”这种方式了,官方文档称以这种方式启动的Activity总是属于一个任务的根Activity。果真如此吗?本文将为你解开Activity的”singleTask”之谜。
全栈程序员站长
2022/09/13
8970
推荐阅读
相关推荐
Android应用启动流量自动化测试
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验