客户端专项测试

App专项测试

客户端专项测试主要测什么

  • 用户维度
    • 崩溃(crash,弱网)
    • 卡顿(掉帧,gc, cpu)
    • 响应慢(启动时间,交互响应,H5加载)
    • 发热(CPU,mem,io,network, gps等硬件使用)
      -耗电快(硬件占用)
    • 兼容性问题(机型覆盖,回归)
  • 技术维度
    -崩溃
    - 自动遍历、monkey测试,横竖屏切换,快速进退
    • 卡顿(掉帧,gc, cpu)
      -卡顿测试,内存泄漏测试,method profile
      -响应慢(启动时间,交互响应,h5加载)
      • 冷热启动、界面切换、h5性能
    • 发热(CPU、mem、io、network、gps等硬件使用)
      • method profile,gc统计,io统计,流量统计,硬件使用统计,耗电量分析
    • 兼容性问题(机型覆盖,回归)
      • 兼容性测试,自动化测试,自动遍历测试,monkey测试

APP启动性能分析

  • Activity启动流程

    • 主要流程
      -Application OnCreate
      - 加载第三方sdk
      • Activity OnCreate
        • 加载自身的逻辑
        • 发送远端数据请求 xxx.json
        • 渲染界面 List
    • App启动性能指标
      • 冷启动
      • 暖启动
      • 热启动
      • 首屏启动
    • 建议时间
      • Cold strtup takes 5 seconds or longer
      • Warm stsrts takes 2 seconds or longer
      • Hot starts takes 1.5 seconds or longer
  • 主要流程

    • adb logcat
    • 录屏+ 视频拆帧
    • uiautomator等自动化工具200ms巡检界面变化
    • tranceview
    • 硬埋点
      --
    • 使用adb logcat
      • package= com.xueqiu.android
      • 清理缓存数据:adb shell pm clear $package
      • 停止进程:adb shell am force-stop $ package
      • 启动app: adb shell am start -S -W $paackage/.view.WelcomeActivityAlias
      • 获取数据: adb logcat |grep -i displayed
    • adb logcat结果
      • startTime :记录刚准备调用startActivityAmdWait()的时间点;
      • endTime:记录startActivityAndWait()函数调用返回的时间点;
      • WaitTime: startActivityAndWait()调用耗时;
      • WaitTime = endTime - startTime
        --
    • 使用ffmpeg拆针
      • adb shell am force-stop $package
      • adb shell screenrecord --bugreport --time-limit 30
      • adb shell screenrecord --bugreport --time-limit 30
      • adb shell am start -S -W $pckage/.view.WelcomeActivityAlias
      • wait
      • adb pull / data/local/tmp.xueqiu.mp4.
      • ffmpeg -i xueqiu.mp4 xueqiu.gif
      • ffmpeg -i xueqiu.mp4 -r 10 frames_%03d.jpg
  • 接口性能

    • 接口性能常用的工具
      • 代理工具:Charles burpsuit
      • 抓包工具:tcpdump wireshark
      • 接口测试过程
  • Webview性能分析

    • Chrome自带的分析工具(62)
      • Disable cache:不加载缓存,从零载入
      • 蓝线:dom出现
      • 红线: 图片等资源已经加载完
    • 信息指标
      • Queueing :队列等待时间
      • Stalled:在队列中,停止请求
      • Waiting :服务等待时间
      • Content download: 下载时间
      • webView在真机中需要打开webView调试
  • H5性能分析

    • https://www.w3.org/TR/navigation-timing/
    • 资源加载指标
      • prompt for unload: 访问一个新的页面时,旧页面卸载完成的时间
      • redirect:重定向,用户注销登录时返回主页面和跳转到其它网站等
      • app cache:检查缓存,是否打开
      • DNS(域名系统):DNS查询的时间,如果是长连接或者请求文件来自缓存等本地存储则返回fetchStart时间点
      • TCP :与服务器建立连接的时间
      • request:浏览器发起请求的时间
      • response: 拿到第一个响应字节到最后一个响应字节的时间
      • processing:各种状态的时间点
      • load:触发load事件执行的时间
    • 自动化获取性能指标
      • appium/selenium的ExecuteScript APi
        • 注入js
          • return JSON.stringify(windows.performance.timing)
          • JSON.stringify(window.performance.timing)
          • JSON.stringify(window.performance.getEntriesByName)(document.querySelector("img").src[0],null,2)
        # w3 规定的“埋点操作”
        class TestData:
                def testData(self):
                    driver = webdriver.Chrome()
                    driver.get("https://baidu.com")
                    print(driver.excute_script("return JSON.stringify(window.performance.timing)"))
        
        
  • 卡顿分析

    • systrace
      • 这个图是怎么绘制的?
      • sdk/platform-tools/systrace (下载的AndroidStudio自带SDK:位置C:\Users\stormweb\AppData\Local\Android\Sdk\platform-tools\systrace)
      • 需要python 2.7
      • no module win32con
        • pip install pypiwin32
          -no six
        • pip2 install six
      • 使用
        • 启动设备
          • 输入命令与参数
            • python systrance -e 192.168.81.102:5555-1
          • 不加参数启动
            • 在命令行:python systrance.py -e 192.168.181.102:5555
            • 在设备上进行操作
            • 在命令行:按下enter
        • 详细信息
          • 帧点
            • 绿:16.6ms内,黄,红超过16.6ms
          • 任务状态
            • 灰:休眠,蓝色:可运行,绿色:运行,橙色:不响应信号
          • 函数调用
    • 卡顿影响因素
      • 内存问题(内存抖动,full gc)
      • CPU耗时
      • render(布局复杂,overdraw)
      • 帧分析
        • 冰冻帧:一个帧超过0.7s
        • 帧分析: adb -s devicesname shell dumpsys gfxinfo |less
  • CPU的统计

    • CPU与GPU的关系
      • 图形CPU不允许直接与GPU通信
      • 通过中间层来连接这两部分
      • 中间件维护一个队列
      • CPU把display list放入队列
      • GPU从队列中拉取数据进行绘制
      • GPU 渲染工具
        • Android开发者工具提供性能调优工具
          • GPU渲染分析:GPU-RENDRING-PROFILE
          • https://developer.android.google.cn/topic/performance/rendering/inspect-gpu-rendering?hl=zh_cn
          • GPR显示内容
            • 绘制每一帧所消耗的时间
            • 不同的颜色代表UI绘制的不同阶段
            • 并且在柱形图的中间还有一根绿色的横线代表16ms的绘制时间基准
            • GRP 会统计并显示app最近运行的128帧
            • 蓝色
              • View需要先转换为GPU能识别的格式
              • 蓝色较高
                • View突然无效(invalidate)
                • onDraw函数做了复杂的绘制逻辑
            • 红色
              • OpenGL处理DISPLAYLIST,将处理的结果传递给GPU
              • 红色较高
                • View过于复杂
                • view重复提交
            • 橙色
              • CPU在等待GPU完成工作
                -橙色较高
                • GPU任务太多,复杂的view绘制
  • mem 统计

    • 内存耗用名词解析
      • VSS Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
      • RSS Resident Set Size Resident Set Size实际使用物理内存(包含共享内存占用的内存)
      • PSS Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
      • USS Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
    • 内存占用规律
    • procastasts
      • adb shell dumpsys prostats --hours 3
      • 输出格式
        • 进程名/USER/VersionCode
        • 状态:(minPSS-avgPSS-maxPSS/minPSS-avgUSS-maxUSS over samples)
      • 输入字段解释
        • 百分比:表示在总的时间内,进程在各种状态下的消耗
        • TOTAL:表示了进程的综合占用情况
        • Img Fg: 加载到前台
        • Service:标识了是否是服务
        • Persistent: 标识了是否一直驻留在内存中,与Service一样,表示内存进驻的级别
        • Top: 标识了是否是顶层进程
        • Receiver:标识了是否是广播进程
      • meminfo内容
      • 做一个版本对比来测内存
  • 网络流量分析

    • 显示网络流量
      • adb shell dumpsys netstats
    • 分块展示
      • Activity interfaces :活动接口
      • Activity UID interfaces :活动UID 接口
      • Dev statistics: Xt 统计信息
      • UID statistics :UID 统计信息
      • UID tag statistics: UID 代码统计信息
    • 活动接口和活动UID接口
      • Activity interfaces:
        • iface = wlan() ident = [{type=WIFI, subType = COMBINED, networkId ="GoogleGuest"}]
    • 找到UID
      • adb shell dumpsys package com.xueqiu.android |grep userId
        • userId = 10007 gids = [3003, 1028, 1015]
    • 查看相关应用的流量情况
      • set = DEFAULT 表示前台网络使用情况
      • set = BACKGROUND 表示后台使用情况
      • set = ALL 表示上述两类使用情况
      • tag = 0x0 表示与流量关联的套接字代码
      • rxBytes 和rxPackets 表示在响应时间间隔内接受的字节数和数据包
      • txBytes和txPacksts 在响应时间间隔内发送的字节数和数据包数
  • 耗电量测试

    • 待机时间成关注指标
    • 提升用户体验
    • 通过不同的测试场景,找出APP高耗电的场景并解决
    • 安装工具
      • https://github.com/google/battery-historian
      • 注意编译版本 改为20190513
      • cd battery-historian
      • go get -d -u github.com/google/battery-historian/..
      • go run setup.go
      • go run cmd/battery-historian/battery-historian.go
    • 测试步骤
      • 使用batterystats 生成数据
      • 使用Battery historian 分析数据
      • batteryststs收集数据
        • 清理耗电量数据
          • adb shell dumpsys batterystats batterystats --reset
          • adb shell dumpsys batterystats -- enable full-wake-history
        • 运行测试用例/手工操作
        • 收集数据
          • Android 7.0 :adb bugreport bugreport.zip
          • Android 6.0 : adb bugreport > bugreport.txt
      • historian
        • 进入historian
        • x轴代表时间周期,默认以60s为一个周期
      • 指标含义
        • battery_level:电量
        • plugged: 充电状态及充电的时长
        • screen :屏幕是否被点亮
        • top:显示当前手机是运行APP
        • status: 电池信息,有充电,放电,未充电,已充满,未知等不同状态。
  • 弱网测试

    • 封闭环境,网速降低
      • 丢包
      • 数据无法加载
      • 消息更新不及时
    • 弱网速度
      • 低于2G
      • 3G
    • 弱网模拟
      • Charles
        • 字段解释
          • Bandwidth
            • 理论网速上限
          • Utilisation(利用)
            • 总带宽的百分比
          • Round-trip Latency(请求往返延迟)
            • 客户端与服务器第一次往返通信延迟,单位毫秒
          • MTU(最大传输单元)
            • 传输的TCP数据包的最大尺寸
          • Reliability(可靠性)
            • 衡量连接完全失败的可能性
          • 常用网速的展示
  • 健壮性测试

    • 用于测试系统出现故障时,是否能够自动恢复或者忽略故障继续运行
    • 操作过程
      • 对应用进行盲点
      • 网络不佳
      • 数据不通
    • 使用工具
      • Monkey, Maxim
      • Charles
      • Appcrawler
  • 兼容性测试

    • 几个硬件之间,软件之间,或者是软硬件之间的相互配合程度
    • APP兼容性测试
      • 移动设备型号多样
      • 测试APP在主流设备上能否正常运行
      • 测试APP在主流设备上崩溃卡顿现象
    • 兼容性测试作用
      • 进一步提高产品质量,提高用户体验
      • 尽可能达到平台无关性
      • 保证软件存在价值,是衡量软件质量的重要指标
      • 是产品的市场更广阔
    • 测试方法
      • 手工测试
      • 借助第三方工具
        • appcrawler

Android 功耗测试

功耗相关硬件

电池

  • 电池容量:电池容量越大手机越笨重
  • 充电时间:低电压高电流,高电压低电流
  • 寿命
  • 安全性

耗电硬件

  • 处理器芯片:CPU,GPU,NPU
  • 基带芯片:蜂窝网,WIFI,NFC
  • 传感器:加速度传感器陀螺仪,气压计,温度传感器
  • 外设:相机,麦克风,扬声器
  • 其他:GPS,内存,显示屏,闪存
    资源调度机制是厂商功耗优化的最重要的手段,手机基带,GPS,这些模块在不使用时也会进入低功耗或休眠模式,达到降低功耗的目的。
    手机厂商为了保证头部应用能有更好的体验,厂商愿意给他们分配更多的资源
    https://developer.qualcomm.com/software/snapdragon-power-optimization-sdk/quick-start-guide

耗电软件

如何评估软件的耗电情况: 电能 = 电压 * 电流 * 时间
如何监测软件耗电:手机的电压一般恒定,Adnroid 系统要求可以在/frameworks/base/core/res/xml/power_profile.xml找到电源配置文件
如何在不同厂商中获取耗电流

  1. 从手机中导出 /system/framework/framework-res.apk 文件
  2. 使用反编译工具对导出文件framework-res.apk 进行反编译
  3. 查看power_profile.xml 文件在frame-res 反编译目录路径: /res/xml/power_profile.xml
    https://source.android.com/devices/tech/power
    https://android.googlesource.com/platform/frameworks/base/+/master/core/res/res/xml/power_profile.xml
    如何监测系统的电量消耗:可以通过dumpsys batterystatus 导出
adb shell dumpsys batterystats > battery.txt
// 各个Uid的总耗电量,而且是粗略的电量计算估计。
Estimated power use (mAh):
    Capacity: 3450, Computed drain: 501, actual drain: 552-587
    ...
    Idle: 41.8
    Uid 0: 135 ( cpu=103 wake=31.5 wifi=0.346 )
    Uid u0a208: 17.8 ( cpu=17.7 wake=0.00460 wifi=0.0901 )
    Uid u0a65: 17.5 ( cpu=12.7 wake=4.11 wifi=0.436 gps=0.309 )
    ...
// reset电量统计
adb shell dumpsys batterystats --reset
编号 测试方法 适用场景 优点 缺点
1 稳压电源+ 电流仪 整机电流 以测试整机电流,而且数据精确 需要准确硬件工具,测试操作复杂,而且不能准确测试APP消耗电量
2 dumpsys batterystats App电量 有耗电量的详细数据 结果可读行比较差
3 系统“耗电排行” APP电量 直观,跟用户看到的一致 没有详细的数据
4 Battery History App电量 结果直观,有耗电量的详细数据 适用与Android 5.0及以上系统

bug report
Battery Historian

	//7.0和7.0以后
	$ adb bugreport bugreport.zip
	//6.0和6.0之前:
	$ adb bugreport > bugreport.txt
	//通过historian图形化展示结果
	python historian.py -a bugreport.txt > battery.html

Android 耗电优化历史

野蛮生长: Pre Android 5.0
image

特点: 电量问题排查复杂。无论是电量的测量,还是耗电问题的排查都异常艰难。

  1. 耗电与安装应用程序的数量有关,用户安装越多的应用程序,无论是否打开它们,手机耗电都会很快。
  2. App耗电量与APP使用时间无关,用户希望 App 的耗电量应该与它的使用时间相关,但是有些应用即使常年不打开,依然非常耗电
    逐步收紧:Android 5.0 ~ Android 8.0

https://developer.android.com/about/versions/android-5.0?hl=zh-cn

image

Android 6.0 开始~, Google开始着手清理后台应用和广播来进一步省电
特点:

  1. 省电模式不够省电
  2. 用户对应用控制力度不够
    3。 Target API 开发者响应不积极
    最严格:Android 9.0
    image

耗电优化与线上监控

耗电优化

  • 后台耗电(厂商预装项目要求最严格的正是应用后台待机耗电)
    • 用户认为应用的耗电量应该是和使用时间有关的
    • Camera, Audio, Video,Bluetooth, Network, Sensor. Radio, Screen,WiFi, CPU, GPS
  • 符合系统规范,让系统认为你耗电是正常的
    • Android Vitals
      耗电优化难点
  1. 缺乏现场,无法复现
  2. 信息不全,难以定位
  3. 无法评估结果
    耗电优化的方法
  • 常见的耗电方式
    • 某个需求场景
    • 代码的Bug
  • 优化方法
    • 利用厂商通道或定时拉去最新消息
      耗电监控
  1. Android Vistals
  2. 耗电监控应该监控什么
    • 监控信息---> 系统关心什么,我们就监控什么(后台耗电监控 ) Alarm wakeup、WakeLock、WiFi scans、Network
    • 现场信息---> 完整的对栈信息
    • 提炼规则---->将监控的内容抽象成规则
      常用的规范
      |APP活动|前台规则|后台规则|
      | ------------ | ------------ | ------------ |
      |Alarm|单个Alarm每小时不能启动超过20次|单个Alarm 每小时不能启动超过10次|
      |WakeLock|单个WakeLock每小时不能超过30分钟或者超过20次|1. WakeLock每 小时不能超过30分钟; 2.单个WakeLock每小时不能超过10分钟或12次 |
      |Sensor|不监控前台sensor使用|每小时使用不能超过30分钟|
      |WIFI scans|每小时扫描不允许超过10次|每小时扫描不允许超过4次|
      |Bluetooth scans|每小时扫描不能超过10次|每小时扫描不允许超过4次|
      |GPS|每小时使用不能超过30分钟|每小时使用不能超过15分钟|
      |Camera|不监控前台相机使用|后台不允许使用相机|
      |Network|不监控前台网络耗电|每小时后台网络数据量不能超过10MB|
      |CPU|不监控前台CPU|后台CPU持续超过30分钟|

如何监控耗电

Java Hook
WakeLock
1. https://androidxref.com/7.0.0_r1/xref/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
2. https://developer.android.com/training/scheduling/wakelock

// 代理PowerManagerService
ProxyHook().proxyHook(context.getSystemService(Context.POWER_SERVICE), "mService", this);
@Override
public void beforeInvoke(Method method, Object[] args) {
    // 申请Wakelock
    if (method.getName().equals("acquireWakeLock")) {
        if (isAppBackground()) {
            // 应用后台逻辑,获取应用堆栈等等     
         } else {
            // 应用前台逻辑,获取应用堆栈等等
         }
    // 释放Wakelock
    } else if (method.getName().equals("releaseWakeLock")) {
       // 释放的逻辑    
    }
}

**Alarm **: 用来执行定时的重复任务

// 代理AlarmManagerService
new ProxyHook().proxyHook(context.getSystemService
(Context.ALARM_SERVICE), "mService", this);


public void beforeInvoke(Method method, Object[] args) {
    // 设置Alarm
    if (method.getName().equals("set")) {
        // 不同版本参数类型的适配,获取应用堆栈等等
    // 清除Alarm
    } else if (method.getName().equals("remove")) {
        // 清除的逻辑
    }
}

后台CPU
对于 GPS 监控,我们可以通过 Hook 代理LOCATION_SERVICE。对于 Sensor,我们通过 Hook SENSOR_SERVICE中的“mSensorListeners”

通过 Hook,我们可以在申请资源的时候将堆栈信息保存起来。当我们触发某个规则上报问题的时候,可以将收集到的堆栈信息、电池是否充电、CPU 信息、应用前后台时间等辅助信息也一起带上
功耗测试通常看的是系统整体情况https://xie.infoq.cn/article/25fa818c88883056750982269

posted @ 2022-05-20 10:40  李老师家的狗  阅读(573)  评论(0编辑  收藏  举报