Android App常用性能指标测试方法
获取应用的包名和activity
- 使用命令
adb logcat|findstr START
手机成功连接电脑,确认adb devices成功,使用命令adb logcat|findstr START
.打开对应的APP,如图标红为对应app的包名和启动activity
adb logcat | findstr START
I/ActivityManager( 785): START u0 {act=android.intent.action.MAIN cat=[android.
intent.category.LAUNCHER] flg=0x10200000 cmp=com.xxx.ordersystem/.activity.We
lcomeActivity bnds=[540,960][798,1248]} from uid 10015 on display 0 from pid 177
4
- 使用aapt工具获取
使用.apk的包,在android sdk/build-tools的aapt.exe文件夹目录下,执行命令aapt dump badging xxx.apk
,如图所示标红的为对应app的包名和启动activity
aapt dump badging xxx.apk
package: name='com.xxx.ordersystem' versionCode='123' versionName='1.6.0'
sdkVersion:'14'
launchable-activity: name='com.xxx.ordersystem.activity.WelcomeActivity' lab
el='' icon=''
启动时间
冷启动
每次杀掉应用进程启动
- 启动app命令
adb shell am start -W -n package/activity
Starting: Intent { cmp=com.xxx.ordersystem/.activity.WelcomeActivity }
Status: ok
Activity: com.xxx.ordersystem/.activity.WelcomeActivity
ThisTime: 317
TotalTime: 317
WaitTime: 326
Complete
ThisTime的值为启动时间
- 停止app命令
adb shell am force-stop package
热启动
每次从后台启动应用
- 启动app命令
adb shell am start -W -n package/activity
- 停止app命令
adb shell input keyevent 3
编写Python脚本自动获取启动时间
可以有两种方式
- 使用
adb shell am start -W -n package/activity
命令中的this time的值作为启动时间 - 运行启动命令前后分别加上时间戳,通过计算两个时间戳的差值做为启动时间
脚本如下:
import os
import time
import csv
class App:
def __init__(self):
self.package = 'com.xxx.xxx'
self.activity = '/.xxx.xxxActivity'
self.content = ''
self.start_time = None
def launch_app(self):
"启动app"
cmd = r'adb shell am start -W -n {package}{activity}'.format(package=self.package,
activity=self.activity)
self.content = os.popen(cmd).readlines()
def stop_app(self):
'停止app'
# cmd = r'adb shell am force-stop {}'.format(self.package) # 冷启动杀进程
cmd = r'adb shell input keyevent 3' #热启动返回
os.popen(cmd)
def get_launch_time(self):
"得到启动时间"
for i in self.content:
if i.startswith('ThisTime'):
self.start_time = i.split(':')[1].strip()
break
return self.start_time
class Controller:
def __init__(self, count):
self.app = App()
self.count = count
self.data = [('timestramp', 'start_time')]
def test_process(self):
"单次运行"
self.app.launch_app()
time.sleep(5)
starttime, ctime = self.app.get_launch_time(), time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
self.app.stop_app()
time.sleep(3)
self.data.append((ctime, starttime))
def run(self):
"执行入口"
for i in range(self.count):
self.test_process()
self.save_date()
def save_date(self):
"保存数据"
csvfile = open('start_time1.csv', 'w')
writer = csv.writer(csvfile)
writer.writerows(self.data)
csvfile.close()
if __name__ == '__main__':
p = Controller(10)
p.run()
cpu
获取cpu数据命令
adb shell dumpsys cpuinfo | findstr "packagename TOTAL"
30% 14862/com.xxx.xxx: 29% user + 0.7% kernel / faults: 4976 minor
4.5% TOTAL: 4.1% user + 0.4% kernel + 0% softirq
这里表示:当前cpu的总占用为4.5%, com.xxx.xxx的cpu占用为4.5% * 30%
流量
获取流量数据
- 获取app的pid
adb shell ps | findstr com.xxx.ordersystem
USER PID PPID VSIZE RSS WCHAN PC NAME
u0_a592 24393 360 2291360 174244 ffffffff 00000000 S com.xxx.ordersystem
24393为应用的PID
- 获取流量数据命令
adb shell cat /proc/PID/net/dev
adb shell cat /proc/24393/net/dev
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packe
ts errs drop fifo colls carrier compressed
ifb0: 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0
ccmni1: 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0
lo: 20395732 183421 0 0 0 0 0 0 20395732 183
421 0 0 0 0 0 0
tunl0: 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0
ccmni0: 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0
sit0: 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0
wlan0: 1230072037 4221335 0 236 0 0 0 0 45807333 5
91022 971 0 0 0 0 0
ifb1: 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0
ccmni2: 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0
ip6tnl0: 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0
p2p0: 0 0 0 0 0 0 0 0 168
2 0 0 0 0 0 0
wlan0中的Receive和transmit之和为当前流量数据,运行app一段时间后再次获取流量数据,计算差值即可得到当前时间段内的流量消耗值
电量
获取电量数据
- 切换非充电状态
adb shell dumpsys battery set status 1
status 2为充电状态,非2即为非充电状态 - 获取电量信息
adb shell dumpsys battery
Current Battery Service state:
(UPDATES STOPPED -- use 'reset' to restart)
AC powered: false
USB powered: true
Wireless powered: false
status: 1
health: 2
present: true
level: 32
scale: 100
voltage: 3819
temperature: 218
technology: Li-poly
level值为电量信息
内存
获取内存数据
adb shell top | findstr package
adb shell top -d 1 | findstr com.xxx.xxx # -d 刷新间隔时间 1s
PID PR CPU% S #THR VSS RSS PCY UID Name
14862 5 5% S 56 2404772K 176380K tv u0_a149 com.xxx.xxx
14862 5 4% S 56 2404772K 166136K tv u0_a149 com.xxx.xxx
VSS - Virtual Set Size 虚拟耗用内存,单个进程全部可访问的地址空间
RSS - Resident Set Size 实际使用物理内存,单个进程实际占用的内存大小
关注这两个值变化即可
FPS和过度渲染
-
FPS 是每秒传输的帧数,每秒传输的帧数越多,则画面看起来越流畅,一般定义60帧/s为流畅,即每帧执行时间为16ms,每帧执行时间大于16ms即为卡顿
fps.png
设置-开发者选项-GPU呈现模式分析-在屏幕上显示为条形图
打开应用app会看到有一条绿线,为FPS基准值,即16ms,每个柱形条为每一帧的绘图耗时,高于绿线即表示这一帧执行时间大于16ms,低于绿线表示这一帧绘图耗时小于16ms,当有大部分柱形图高于路线时,表示出现了卡顿
使用命令获取fps信息
adb shell dumpsys gfxinfo 'com.xxx.ordersystem' > fps.txt
查看fps.txt下的Profile data in ms中的数据,将其放到excel中使用柱状图查看
-
过度渲染描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次
设置-调试GPU过度绘制-显示过度绘制区域
打开应用app,会看到页面出现不同的颜色,颜色越深表示当前位置层数过度,可能存在过度绘制