测试环境一般用真机,有一套系统,搭载在服务器上,很多usb出来,连接各手机进行测试。这里我们用模拟器进行讲解(安卓Linux,IOSUnix)
目录:
一、ADB
安装好模拟器,配置好环境变量啥的(已经在之前的博客内有介绍)
1、安装JDK
2、安装Android SDK(可以在这里下载:http://www.android-studio.org/)
3、配置环境变量:
ANDROID_HOME=.../sdk
PATH=%ANDROID_HOME%\tools;%ANDROID_HOME%\platform-tools;%ANDROID_HOME%\build-tools\android-4.4.2;
注意:JDK和SDK的位数必须一致。
介绍两个小工具:
1、百度:测试助手(简单)
2、腾讯:GT(详细)
测试助手:
结果:
内存泄漏:
内存一直升/GC回收之后,内存未降到底
adb命令(Android debug bridge-安卓调试桥-相当于USB线):
192.168.238.101.5555 是deviceid
出现这个情况,就可以直接用命令了:
1.adb help
2.adb devices 取得当前运行的模拟器/设备的实例的列表及每个实例的状态
3.adb install gzw.apk 安装应用程序(直接跟apk的路径以及文件名即可)
4.adb -s 123 install zw.apk 给指定的设备安装apk(123指的是deviceid)
5.adb pull <remote> <local> 从远程到本地,从手机下载文件到电脑(可以加-s 123 指定模拟器的id;remote/local是指的是路径)
6.adb push <local> <remote> 从本地到远程,从电脑上传文件到手机(可以加-s 123 指定模拟器的id;remote/local是指的是路径)
7.adb start-server 启动服务(可以加-s 123 指定模拟器的id)
8.adb kill-server 杀死服务(可以加-s 123 指定模拟器的id)
9.adb shell 必须是root才行 进入linux
10.adb logcat 日志(可以加-s 123 指定模拟器的id)
关于adb logcat:
优先级从低到高排列
V-Verbose(lowest priority)
D-Debug
I-Info
W-Warning
E-Error
F-Fatal
S-Silent(highest priority,on which nothing is ever printed)
下面的过滤语句只显示优先级为warning或更高的日志信息
adb logcat *:W(意思是显示W、E、F、S级别的日志)
二、Monkey
1、概念
monkey,是个啥?什么时候用呢?为什么要用monkey呢?
monkey=猴子,相当于是个猴子在操作你的手机,咔咔咔这里点那里点,随机操控app的工具,测试app是否稳定,关键在于测试稳定性。
运行时机:一般是产品稳定后,首轮功能测试完成后的夜间进行。测试稳定性,一般要改完一轮Bug之后。需要知道PackageName
为什么用?主要用来测试产品是否存在崩溃问题以及ANR(applicatuion no response)问题
2、获取PackageName
1、aapt
aapt dump badging apk名称
前提:aapt.exe要在环境变量路径下:
命令:aapt dump badging apk名称(apk名称为apk在电脑里面的路径以及名称)
比如:aapt dump badging F:\BaiduNetdiskDownload\软件\iBiliPlayer-bili.apk
PackageName:
ActivityName:
2、通过adb logcat获取
adb logcat | grep START ##这个是不行的,原因在于,grep是linux命令,| grep START认为是在window内操作的,所以会报错
所以, 用下面的语句:
adb shell “logcat | grep START”
在这个情况下,拉到底,然后去模拟器内打开你需要打开的APP,在cmd内查看日志变化:
我们可以发现,多了了一个cmp=tv.danmaku.bili/.ui.splash.SplashActivity……
tv.danmaku.bili是PackageName
tv.danmaku.bili.ui.splash.SplashActivity是ActivityName
比如说:计算器的PackageName为:com.android.calculator2
ActivityName为.Calculator
3、Monkey的基本命令
1、标准monkey命令:
adb shell monkey -p com.android.calculator2 -v 50
-p:packageName(这里用的是com.android.calculator2)
-v:日志级别
-v -v代表不认同的日志级别
-v -v -v代表不认同的日志级别
50:事件数
结果:对计算器进行了100次事件,但是是在计算其内部进行100次事件:
那些2:2.0%一直到10:13%指的是时间的类型比例,比如说:点击、滑动、轨迹球事件等
2、
adb shell monkey -p com.android.calculator2 -v -v --pct-touch 50 --throttle 600 88
--pct-touch 50 设置整个过程中点击操作所占的百分比
--throttle 600 每个事件间隔600ms
88 意思是 88个事件数
这样执行,每个事件中间有延时,可以看清操作
3、实际工作中营的命令,这里的packagename要更换,1000000的动作记得换掉,如果要执行一晚上一般设置100万,时间间隔500ms是为了防止动作太快导致异常;这些错误啥的都会忽略,不忽略会停止,但是执行的日只会存在文件内。ANR是无响应,操作太快容易出现ANR
adb shell monkey -p packagename --throttle 500 --ignore-crashes --ignore-timeouts --ignore-security-exceptions --ignore-native-crashes --monitor-native-crashes -v -v -v 1000000 > c:\monkey_test.log
4、关于日志级别
参数: -v
用于指定反馈信息级别(信息级别就是日志的详细程度),总共分3个级别,分别对应的参数如下表所示:
1、日志级别 Level0
示例 adb shellmonkey -p com.htc.Weather –v 100
说明 缺省值,仅提供启动提示、测试完成和最终结果等少量信息
2、日志级别 Level 1
示例 adb shellmonkey -p com.htc.Weather –v -v 100
说明 提供较为详细的日志,包括每个发送到Activity的事件信息
3、日志级别 Level 2
示例 adb shellmonkey -p com.htc.Weather –v -v –v 100
说明 最详细的日志,包括了测试中选中/未选中的Activity信息
5、Monkey的事件类型
- pct-touch:指定触摸事件的百分比,如:--pct-touch 5
- pct-motion <percent> (滑动事件)
- pct-trackball <percent> (轨迹球事件)
- pct-nav <percent> (导航事件 up/down/left/right)
- pct-majornav <percent> (主要导航事件 back key 、 menu key)
- pct-syskeys <percent> (系统按键事件 Home 、Back 、startCall 、 endCall 、 volumeControl)
- pct-appswitch <percent> (activity之间的切换)
- pct-anyevent <percent>(任意事件)
6、Monkey的参数 -s
参数: -s
用于指定伪随机数生成器的seed值,如果seed相同,则两次Monkey测试所产生的事件序列也相同的。
示例:
Monkey测试1:adb shell monkey -p com.htc.Weather –s 10 100
Monkey 测试2:adb shell monkey -p com.htc.Weather–s 10 100
两次测试的效果是相同的,因为模拟的用户操作序列(每次操作按照一定的先后顺序所组成的一系列操作,即一个序列)是一样的。操作序列虽然是随机生成的,但是只要我们指定了相同的Seed值,就可以保证两次测试产生的随机操作序列是完全相同的,所以这个操作序列伪随机的;
adb shell monkey -p com.android.calculator2 -s 10 -v -v -v 100 >c:monkey_test1.log
这里我们看到输出的日志,seed值都为10,seed是用来复现以及回归问题的;因为假设不用seed,你不知道问题出在哪,开发说解决了,你也不知道怎么回归,有了这个seed值,咱们就可以进行一模一样的操作,seed值可以跟日志编号对上,这样更直观;但是两次执行初始状态要一致,比如清空计算器内容。
这样有两种方式:1、第一次就指定 -s 的seed值;2、出现问题后,第二次执行找到第一次有问题的seed值,再执行
7、Monkey的其他参数
- --ignore-crashes 用于指定当应用程序崩溃时(Force& Close错误),Monkey是否停止运行。如果使用此参数,即使应用程序崩溃,Monkey依然会发送事件,直到事件计数完成。
- --ignore-timeouts 用于指定当应用程序发生ANR(Application No Responding)错误时,Monkey是否停止运行。如果使用此参数,即使应用程序发生ANR错误,Monkey依然会发送事件,直到事件计数完成。
- --ignore-security-exceptions 用于指定当应用程序发生许可错误时(如证书许可,网络许可等),Monkey是否停止运行。如果使用此参数,即使应用程序发生许可错误Monkey依然会发送事件,直到事件计数完成。
- --kill-process-after-error 用于指定当应用程序发生错误时,是否停止其运行。如果指定此参数,当应用程序发生错误时,应用程序停止运行并保持在当前状态(注意:应用程序仅是静止在发生错误时的状态,系统并不会结束该应用程序的进程)。
- --monitor-native-crashes 用于指定是否监视并报告应用程序发生崩溃的本地代码
8、Monkey的日志分析
- 按关键字进行搜索,ANR、Exception、Crash、Error。(有Crash一般有Exception)
- 找到有问题的地方,查看上下文信息。
- 注意第一个switch上下文信息。
- 查看monkey里面出错前的一些事件动作,可以手动执行该动作。
- 进行问题复现,可以使用之前执行的monkey命令在执行一遍,注意seed值要一样。
9、Crash专项
- 安装可以引起Crash的App
- 执行压力命令
- 析取Crash的Exception信息
资料里面有这个引起Crash的apk,我们如果以后出现Crash的错误,怎没去析取呢?
adb shell monkey -p cn.besttest.crashtest -v -v -v 1000 > c:\monkey_test3.log
首先可以在日志里面看一下时间数,我们这里是963<1000,说明有些事件没完成(Crash是停止运行,ANR是无响应)
提示堆栈信息,截图给开发就行
那么假如我们忽略Crash呢?
adb shell monkey -p cn.besttest.crashtest --ignore-crashes -v -v -v 1000 > c:\monkey_test4.log
忽略了Crash,就算触发了Crash之后,monkey会把app杀死重新打开再操作,所以日志内的事件数依旧为1000
但是日志内,依旧有Crash操作被记录下来:
10、ANR专项
- 安装可以引起ANR的App
- 执行压力命令
- 析取ANR的Exception信息
- 查看monkey的log
- /data/anr/traces.txt
- 查看logcat日志 ANR
同样的,安装引起ANR的apk
输入命令:
adb shell monkey -p cn.besttest.anrtest -v -v -v 1000 > c:\monkey_test_anr1.log
ANR是操作无响应
在/data/anr/traces.txt目录下,我们可以拉取出来看一下,把这个文件以及log问阿金给开发就成
三、Monkey Script
好处:可以规定干什么
- MonkeyScript是一组可以被Monkey识别的命令集合
- 优点:MonkeyScript可以完成重复固定的操作
- 使用:adb shell monkey -f <scriptfile> <event-count>(scriptfile指的是脚本;event-Count是事件数)
1、Monkey Script命令
1、DispatchTrackball-轨迹球事件
DispatchTrackball(long downtime,long eventtide,int action,float x,float y,float pressure,float size,int metastate,float xprecision,float yprecision,int device,int edgeflags)
注意:按一个键需要两个轨迹球事件
DispatchTrackball参数详解
- long downtime 指键最初被按下的时间
- long eventtide 指事件发生的时间
- int action 指具体操作的动作,如按下
- float x,float y 指x和y的坐标
- float pressure 压力事件的大小(0~1)
- float size 指触摸的记事值(0~1)
- int metastate 指当前按下mate键的标识
- float xprecision,float yprecision 指x和y坐标的精确值
- int device 事件的来源(0~x)
- int edgeflags 指超出屏幕了范围
- int action 0代表按下,1代表弹起
2、DispatchPointer-点击事件
DispatchPointer(long downtime,long eventtide,int action,float x,float y,float pressure,float size,int metastate,float xprecision,float yprecision,int device,int edgeflags)
注意:按一个键需要两个点击事件
参数详解见轨迹球事件
3、DispatchString-输入字符串命令
DispatchString(String text)
4、LaunchActivity-启动应用
LaunchActivity(package,Activity)
5、UserWait-等待事件(单位:ms)
UserWait(1000)
6、DispatchPress-按下键值(键值)
DispatchPress(int keycode)
#keycode 66 回车键
2、Monkey Script 实战
在浏览器的百度搜索框中输入查询词“besttest”并得出搜索结果
解答:要哪几步操作才能完成操作?
- 启动App
- 点击地址栏
- 删除原有地址
- 输入www.baidu.com
- 点击回车键,让新地址到地址栏中
- 点击回车
- 点击搜索框
- 输入besttest
- 点击回车键,让查询词到搜索框中
- 点击搜索按钮
- 等待结果
typ=user count=10 speed=1.0 start data >> LaunchActivity(com.android.browser,com.android.browser.BrowserActivity) UserWait(5000) DispatchPointer(10,10,0,256,100,1,1,-1,1,1,0,0) DispatchPointer(10,10,1,256,100,1,1,-1,1,1,0,0) DispatchPress(112) DispatchString(www.baidu.com) DispatchPress(66) UserWait(10000) DispatchPointer(10,10,0,125,500,1,1,-1,1,1,0,0) DispatchPointer(10,10,1,125,500,1,1,-1,1,1,0,0) UserWait(1000) DispatchString(besttest) UserWait(3000) DispatchPress(66) UserWait(10000)
注:前四行是必须要有的
写好了脚本之后,要把脚本拉取到移动端内执行:
接下来可以在adb shell内运行monkey,结果如图:
或者退出adb shell 用 adb shell monkey -f <scriptfile> <event-count> 运行,结果是一致的:
MonkeyScript注意
脚本需要push到手机中才可以
push monkey.script /data/local/tmp
没有调试的功能,需要自己仔细去找问题
如果启动时并不是自己要测试的App,需要开发在Android的配置文件中加入相关配置
android:exported=”true”
四、MonkeyRunner
- MonkeyRunner提供了系列的API
- MonkeyRunner可以完成模拟事件及截图操作
分为三块:
- MonkeyRunner:用来连接设备或模拟器的
- MonkeyDevice:提供安装、卸载应用,发送模拟事件
- MonkeyImage:完成图像保存及对比的操作
可以用来干什么?
- 多设备控制
- 功能测试
- 回归测试
1、MonkeyRunnerAPI
1、alert
警告框
MonkeyRunner.alert(string message, string title, string okTitle)
message: 弹出对话框内容
title: 对话框的标题栏显示内容,默认值为"Alert"
okTitle : 对话框的按钮,默认值为"OK"
试一下:首先要进入monkeyrunner,再敲命令,要退出这个命令按“Ctrl+d”
2、waitForConnection
等待设备连接,多个设备,需要指明哪个设备
MonkeyRunner.waitForConnection(float timeout, string deviceId)
timeout: 等待超时时间,默认值为永久等待.
deviceId: 通过设备ID去设别手机或模拟器.如果只有一台手机的时候,不需要输入
2、MonkeyDeviceAPI
1、drag
拖动
device.drag(tuple start, tuple end, float duration, integer steps)
(1,2) (3,4)
start:起始点位置
end:终点位置
duration:手势持续的时间
steps:插值点的步数,默认10
2、press
按键
device.press(string keycode,dictionary type)
type:DOWN、UP、DOWN_AND_UP
3、startActivity
启动应用
device.startActivity(package+'/'+activity)
4、touch
点击
device.touch(int x,int y,type)
type:DOWN、UP、DOWN_AND_UP
5、type
输入
device.type(string message)
6、takeSnapshot
截屏
device.takeSnapshot()
3、MonkeyImageAPI
1、sameAs
图像对比
picture.sameAs(MonkeyImage other,float percent)
percent:对比相似度
2、writetoFile
保存图像文件
picture.writeToFile(string path,string format)
string path,存储全路径,包括文件扩展名。
string format,存储格式
4、实例
还是刚刚那个例子,但是最后加一步截屏保存在本地
首先要知道所连接设备的端口号:192.168.238.101:5555
脚本如下(脚本为.py文件):
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice, MonkeyImage device = MonkeyRunner.waitForConnection(5,"192.168.238.101:5555") device.startActivity("com.android.browser/.BrowserActivity") MonkeyRunner.sleep(5) device.touch(200,100,'DOWN_AND_UP') MonkeyRunner.sleep(1) device.press('KEYCODE_FORWARD_DEL','DOWN_AND_UP') device.type('www.baidu.com') device.press('KEYCODE_ENTER','DOWN_AND_UP') MonkeyRunner.sleep(10) device.touch(150,500,'DOWN_AND_UP') MonkeyRunner.sleep(1) device.type('besttest') MonkeyRunner.sleep(3) device.press('KEYCODE_ENTER','DOWN_AND_UP') MonkeyRunner.sleep(10) image=device.takeSnapshot() image.writeToFile('C:\\monkeyrunnerscript1.png','png') MonkeyRunner.sleep(3)
注意:这里我们引用的而路径要为绝对路径:monkeyrunner c:\XXX.py
这是为什么呢?因为相对路径相对的是monkeyrunner.exe所在的位置是相对位置,而我们是放在C盘内的
Monkey和MonkeyRunner的区别
- Monkey:在adb shell中,生成用户或系统的伪随机事件
- MonkeyRunner:通过API定义特定命令和事件控制设备
MonkeyRunner没有事件数,MonkeyScript有事件数,相对来说,MonkeyRunner相对灵活,可以用Python语言。工作中,自动化测试基于坐标不是最优解决方案,最重要的是 Monkey ,其他的都不是很重要
五、监控分析专项
- 启动App。
- DDMS->update heap
- 操作app,点几次GC
- dump heap
- hprof-conv转化
- MAT分析
app 内存泄漏的案例:
准备工作:安装 MyMemoryDemo 的 apk ,电脑上装好 mat
这里我们不用 DDMS ,而是用功能更强大的 monitor 在 cmd 下输入 monitor(前提是要配置好环境变量),电脑会自动打开 Android Debug Monitor :
有些功能简单介绍:
1、截取手机当前屏幕
2、页面元素定位,Appium 做前端自动化,要用到这个
3、利用 Logcat 筛选日志:
保存好的过滤结果:
我们的案例主要讲内存的泄漏,重点关注 Heap,操作如下:
1、先打开 app:
2、选中我们 app 对应的 package,点击 "Update Heap",点击 "Cause GC",等到数据加载完成
3、操作 app ,点击“点我啊点我啊”,一次点击一下,别乱点,别超过10次
我们要关注的是 "data object" 内 的 "Total Size",如果我们点 app 的按钮,如果该值一直增加,我们点击 "Cause GC",该值不会减少或者说减小的幅度很小,那么说明存在内存泄漏
我们看看看结果:
把内存 dump 下来一份,路径:D:\adt-bundle-windows-x86_64-20140321\adt-bundle-windows-x86_64-20140321\sdk\tools\111,直接保存就好了。
dump 完 monitor 关闭就行
4、hprop-conv 转化,转化的命令如代码所示,转化后的文件不要跟之前的一样,这里我用的是 cn.besttest.mymemorydemobak.hprof
C:\Users\Admin>d: D:\>cd D:\adt-bundle-windows-x86_64-20140321\adt-bundle-windows-x86_64-20140321\sdk\tools\111 D:\adt-bundle-windows-x86_64-20140321\adt-bundle-windows-x86_64-20140321\sdk\tools\111>hprof-conv cn.besttest.mymemorydemo.hprof cn.besttest.mymemorydemobak.hprof
在路径下,应该会多出一个文件:
5、打开 mat ,对转化后的文件进行分析,出现提示直接点 "Finish":
直接看大对象,我们通常都看第一个 java.lang Object[] 数组,这个是我们程序创建的对象:Shallow Heap 是自己本身占用的内存,Retained Heap 还包括引用的内存
选中 java.lang Object[],右键
接下来,继续选中第一个,右键:
结果如图:
出现内存泄漏的点在于:我有一个 list ,而且这个 list 是一个 array 的 list ,这个 list 内的对象装的是 cn.besttest.mymemorydemo 里面的 BestTest ,其实代码里面确实是如此,BestTest 类产生的对象往一个 array list 内放,制空只是把对象制空,并没有把 list 制空,导致内存一直无法释放,这就是内存泄漏的原因
1、区分几种内存
- VSS- Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
- RSS- Resident Set Size 实际使用物理内存(包含共享库占用的内存)
- PSS- Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
- USS- Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS
监控首选 PSS ,如果没有 PSS ,那就看 RSS
2、监控-内存
一、通过Dumpsys 来取值
- adb shell dumpsys meminfo
- 详细信息:adb shell dumpsys meminfo pakagename or Pid
例如,我们看下 b站 的内存占用情况
C:\Users\Admin>adb shell dumpsys meminfo tv.danmaku.bili Applications Memory Usage (kB): Uptime: 1770422 Realtime: 1770422 ** MEMINFO in pid 1316 [tv.danmaku.bili] ** Pss Private Private Swapped Heap Heap Heap Total Dirty Clean Dirty Size Alloc Free ------ ------ ------ ------ ------ ------ ------ Native Heap 9370 9340 0 0 15992 14176 847 Dalvik Heap 9774 9712 0 0 15644 9452 6192 Dalvik Other 5475 5348 0 0 Stack 412 412 0 0 Ashmem 3668 3668 0 0 Other dev 8 0 8 0 .so mmap 3247 708 672 0 .apk mmap 776 0 460 0 .ttf mmap 1168 0 720 0 .dex mmap 7337 1280 2944 0 Other mmap 44 4 4 0 Unknown 244 244 0 0 TOTAL 41523 30716 4808 0 31636 23628 7039 Objects Views: 287 ViewRootImpl: 1 AppContexts: 3 Activities: 1 Assets: 3 AssetManagers: 3 Local Binders: 27 Proxy Binders: 23 Death Recipients: 0 OpenSSL Sockets: 5 SQL MEMORY_USED: 536 PAGECACHE_OVERFLOW: 110 MALLOC_SIZE: 62 DATABASES pgsz dbsz Lookaside(b) cache Dbname 4 16 123 9/20/6 /data/data/tv.danmaku.bili/databases/evernote_jobs.db 4 40 64 16/35/11 /data/data/tv.danmaku.bili/databases/tencent_analysis.db_tv.danmaku.bili 4 40 43 10/25/7 /data/data/tv.danmaku.bili/databases/pri_tencent_analysis.db_tv.danmaku.bili 4 52 144 51/32/18 /data/data/tv.danmaku.bili/databases/bugly_db_ 4 28 32 1/16/2 /data/data/tv.danmaku.bili/databases/unicom.db
我们要关注的就是:PSS 那一列以及Dalvik Heap 那一行 ,行有 Native Heap 和 Dalvik Heap 分别是:本地内存,Dalvik Heap 理解为 Java 堆内存。Heap Size 就是堆内存总共大小,Heap Alloc 就是使用了多少,Heap Free 就是空闲了多少,通常来讲:Alloc+Free≈Size。
二、用/system/xbin/procrank工具 来取值很直观
- adb shell procrank
C:\Users\Admin>adb shell procrank PID Vss Rss Pss Uss cmdline 1316 669004K 100300K 57039K 50464K tv.danmaku.bili 656 608348K 73200K 36666K 33108K com.android.systemui 828 598960K 58500K 21985K 18168K com.android.launcher 571 656748K 60900K 21861K 17364K system_server 225 77056K 24064K 17524K 14508K /system/bin/mediaserver 223 553436K 57596K 14812K 7320K zygote 1723 595072K 48832K 10099K 5856K tv.danmaku.bili:download ……------ ------ ------ 287994K 221172K TOTAL RAM: 2068968K total, 1584364K free, 8020K buffers, 230420K cached, 9928K shmem, 22820K slab
C:\Users\Admin>adb shell " procrank | grep tv.danmaku.bili " ## 看 b站 包的内存使用情况
1316 700552K 132196K 88959K 82368K tv.danmaku.bili
1723 595072K 48832K 10121K 5856K tv.danmaku.bili:download
1692 595392K 48088K 9763K 5700K tv.danmaku.bili:stats
1364 583192K 43364K 8764K 5896K tv.danmaku.bili:pushservice
这里,我们看 PSS 这一列就成,同样可以去利用这个,打点制图,取出监控数据
三、top
- top -d 1 | grep packageName
- adb shell top -d 1 | grep packageName
C:\Users\Admin>adb shell top ## 看整体的内存消耗 User 0%, System 0%, IOW 0%, IRQ 0% User 0 + Nice 0 + Sys 6 + Idle 1143 + IOW 0 + IRQ 0 + SIRQ 3 = 1152 PID PR CPU% S #THR VSS RSS PCY UID Name 1316 3 0% S 50 679964K 109572K fg u0_a60 tv.danmaku.bili 213 0 0% S 14 68032K 7552K root /system/bin/local_opengl 571 1 0% S 69 656752K 58972K fg system system_server 609 2 0% S 11 52120K 3436K fg system /system/bin/surfaceflinger 8 2 0% S 1 0K 0K root rcu_preempt 2062 0 0% R 1 1908K 504K root top 9 0 0% S 1 0K 0K root rcu_bh 10 0 0% S 1 0K 0K root rcu_sched
……
上述命令,可以看到整体的内存使用,如果我们要看单个的应用内存使用,就应该用下面的:
C:\Users\Admin>adb shell "top | grep tv.danmaku.bili" ## tv.danmaku.bili:pushservice 是我们不需要的,重点看 tv.danmaku.bili 1316 2 0% S 50 686768K 116224K fg u0_a60 tv.danmaku.bili 1364 1 0% S 13 584236K 43052K fg u0_a60 tv.danmaku.bili:pushservice 1692 0 0% S 22 595396K 47352K bg u0_a60 tv.danmaku.bili:stats 1723 1 0% S 22 595076K 48200K bg u0_a60 tv.danmaku.bili:download 1316 2 0% S 50 686900K 116224K fg u0_a60 tv.danmaku.bili 1364 1 0% S 13 584236K 43052K fg u0_a60 tv.danmaku.bili:pushservice 1692 0 0% S 22 595396K 47352K bg u0_a60 tv.danmaku.bili:stats 1723 1 0% S 22 595076K 48200K bg u0_a60 tv.danmaku.bili:download 1316 2 0% S 50 686900K 116488K fg u0_a60 tv.danmaku.bili 1364 1 0% S 13 584236K 43052K fg u0_a60 tv.danmaku.bili:pushservice 1692 0 0% S 22 595396K 47352K bg u0_a60 tv.danmaku.bili:stats 1723 1 0% S 22 595076K 48200K bg u0_a60 tv.danmaku.bili:download
……
C:\Users\Admin>adb shell "top | grep tv.danmaku.bili$" ## 加一个正则,表示以 tv.danmaku.bili 结尾的行打印出来,所以我们达到了效果
1316 0 0% S 50 692504K 121988K fg u0_a60 tv.danmaku.bili
1316 2 0% S 50 692504K 121988K fg u0_a60 tv.danmaku.bili
1316 3 0% S 50 692636K 121988K fg u0_a60 tv.danmaku.bili
1316 3 0% S 50 692636K 121988K fg u0_a60 tv.danmaku.bili
1316 0 0% S 50 692768K 122252K fg u0_a60 tv.danmaku.bili
……
C:\Users\Admin>adb shell "top -d 1 | grep tv.danmaku.bili$" ## -d 1 的意思是,每隔一秒显示一次,把数据取出来,打点制图,就知道了内存的使用情况
1316 3 0% S 50 694880K 124364K fg u0_a60 tv.danmaku.bili
1316 1 0% S 50 694880K 124364K fg u0_a60 tv.danmaku.bili
1316 1 0% S 50 694880K 124364K fg u0_a60 tv.danmaku.bili
1316 2 0% S 50 694880K 124364K fg u0_a60 tv.danmaku.bili
1316 2 0% S 50 695012K 124364K fg u0_a60 tv.danmaku.bili
1316 2 0% S 50 695012K 124364K fg u0_a60 tv.danmaku.bili
1316 1 0% S 50 695012K 124628K fg u0_a60 tv.danmaku.bili
1316 1 0% S 50 695012K 124628K fg u0_a60 tv.danmaku.bili
之前我们说过看 PSS ,没有 PSS 就看 RSS ,这里只有 RSS 可以看。Name 就是 PackageName,PID 就是应用的 pid,CPU% 就是 CPU 使用率,同样的可以打点制图,得出内存的使用趋势
3、关于单个应用内存占用量问题
#查看单个应用程序最大内存限制
adb shell getprop|grep heapgrowthlimit
#应用启动后分配的初始内存
adb shell getprop|grep dalvik.vm.heapstartsize
#单个java虚拟机最大的内存限制
adb shell getprop|grep dalvik.vm.heapsize
C:\Users\Admin>adb shell "getprop|grep heapgrowthlimit" [dalvik.vm.heapgrowthlimit]: [96m] C:\Users\Admin>adb shell "getprop|grep dalvik.vm.heapstartsize" [dalvik.vm.heapstartsize]: [8m] C:\Users\Admin>adb shell "getprop|grep dalvik.vm.heapsize" [dalvik.vm.heapsize]: [256m]
应用程序默认达到 heapgrowthlimit 限制的内存,就会爆出 OOM ,堆内存溢出
应用程序如果不想在 dalvik heap 达到 heapgrowthlimit 限制的时候出现OOM,需要在 Manifest 中的 application 标签中声明 android:largeHeap=“true”,声明后应用 dalvik heap 达到 heapsize 的时候才会出现OOM!
注:设备的不一样 最大内存限制也可能不一样
4、监控-CPU
一、通过Dumpsys 来取值
- adb shell dumpsys cpuinfo
C:\Users\Admin>adb shell dumpsys cpuinfo Load: 0.04 / 0.05 / 0.05 CPU usage from 16143ms to 4679ms ago: 1.2% 213/local_opengl: 0% user + 1.2% kernel 1% 1316/tv.danmaku.bili: 0.6% user + 0.3% kernel / faults: 64 minor 0.8% 609/surfaceflinger: 0.1% user + 0.6% kernel 0.5% 571/system_server: 0% user + 0.4% kernel 0.1% 84/redis: 0% user + 0.1% kernel 0% 8/rcu_preempt: 0% user + 0% kernel 0% 782/com.android.phone: 0% user + 0% kernel 0.7% TOTAL: 0.2% user + 0.4% kernel + 0% softirq
这里后面也可以加入 grep 到自己的 packagename,得到 cpu 的使用率,上述可以看到,1% 的 cpu 使用率,1316 为 进程 pid 号,用户态为 0.6%,内核态为 0.3%
二、top
- top -d 1 | grep packageName
C:\Users\Admin>adb shell "top -d 1 | grep tv.danmaku.bili$"
PID PR CPU% S #THR VSS RSS PCY UID Name 1316 2 0% S 50 736592K 166392K fg u0_a60 tv.danmaku.bili 1316 0 0% S 50 736592K 166392K fg u0_a60 tv.danmaku.bili 1316 0 0% S 50 736592K 166392K fg u0_a60 tv.danmaku.bili 1316 0 0% S 50 736724K 166392K fg u0_a60 tv.danmaku.bili
CPU% 就是 cpu 使用率
5、查看PID/UID
pid:
通过ps命令查看pid
ps | grep packageName
C:\Users\Admin>adb shell " ps |grep tv.danmaku.bili" u0_a60 1316 223 753032 182776 ffffffff b766c07b S tv.danmaku.bili u0_a60 1364 223 584236 42760 ffffffff b766c07b S tv.danmaku.bili:pushservice u0_a60 1692 223 595396 47352 ffffffff b766c07b S tv.danmaku.bili:stats u0_a60 1723 223 595076 48200 ffffffff b766c07b S tv.danmaku.bili:download
uid:
一、通过查看packages.list
adb shell cat /data/system/packages.list | grep packageName
二、查看status文件
adb shell cat /proc/<pid>/status
此处的<pid>需要替换成自己的pid的值
C:\Users\Admin>adb shell "cat /data/system/packages.list | grep tv.danmaku.bili" ## 这里面的 10060 就是 uid tv.danmaku.bili 10060 0 /data/data/tv.danmaku.bili default 1028,3003,1015 C:\Users\Admin>adb shell cat /proc/1316/status ## 1316 是 b站 的 pid,Uid 就是我们要的,这里是 10060 ,和上面的一致 Name: tv.danmaku.bili State: S (sleeping) Tgid: 1316 Pid: 1316 PPid: 223 TracerPid: 0 Uid: 10060 10060 10060 10060 Gid: 10060 10060 10060 10060 FDSize: 256 Groups: 1015 1028 3003 50060 VmPeak: 756624 kB VmSize: 755468 kB VmLck: 0 kB VmPin: 0 kB VmHWM: 184952 kB VmRSS: 184952 kB VmData: 177628 kB VmStk: 136 kB VmExe: 8 kB VmLib: 89148 kB VmPTE: 372 kB VmSwap: 0 kB Threads: 50 SigQ: 0/16154 SigPnd: 0000000000000000 ShdPnd: 0000000000000000 SigBlk: 0000000000001204 SigIgn: 0000000000000000 SigCgt: 00000002000094f8 CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 CapBnd: 0000000000000000 Cpus_allowed: f Cpus_allowed_list: 0-3 voluntary_ctxt_switches: 153465 nonvoluntary_ctxt_switches: 124897
6、监控-流量
一、通过查看对应 uid 目录下的 tcp_rcv 和 tcp_snd 两个人文件(模拟器内使用,真机内兼容性不好,所以尽量不使用)
- adb shell cat /proc/uid_stat/<uid>/tcp_snd
- adb shell cat /proc/uid_stat/<uid>/tcp_rcv
命令中的<uid>要替换成自己的 uid。这里统计的是总共的数据,如果要打点制图的话,需要用后一秒的数据减去前一秒的数据,就代表每秒发送/接收的,而且这俩值手机重启后是会被清零的
C:\Users\Admin>adb shell cat /proc/uid_stat/10060/tcp_snd ## 截止到现在,一共发送的 62365 C:\Users\Admin>adb shell cat /proc/uid_stat/10060/tcp_rcv ## 截止到现在,一共接收的 385664
二、通过 proc/net/xt_qtaguid/stats
- adb shell cat /proc/net/xt_qtaguid/stats | grep <uid>
命令中的<uid>要替换成自己的uid,这里的列太多,只需关注第 6 列的 rx_bytes 以及第 8 列的 tx_bytes 即可。这里的网络类型是 eth1 ,代表是本地网路连接,因为我们是用的虚拟机,所以会显示如此,但是真正用真机的过程中,一般是 wlan 以及 4G 之类的,我们可以根据不同的网络类型去进行过滤,出来我们的相关流量数据
而且,这里我们显示出来的是两行,将两行相加,就是对应的流量使用情况,例如 rx_bytes=6468+407121
C:\Users\Admin>adb shell "cat /proc/net/xt_qtaguid/stats | grep 10060"
idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets t
x_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets 8 eth1 0x0 10060 0 6468 50 10540 69 6468 50 0 0 0 0 10540 69 0 0 0 0 9 eth1 0x0 10060 1 407121 629 84821 697 407121 629 0 0 0 0 84821 697 0 0 0 0
三、通过PID下面的net/dev
- adb shell cat /proc/<Pid>/net/dev
命令中的 <pid> 要替换成自己的 pid
Receive 里面看 eth0 或eth1 的 bytes ,就是发送的数据量,如果有多个 eth0 或者 eth1,就把 eth0 的全部加起来或者 eth1 的全部加起来,不要把 eth0 + eth1;
Transmit 里面看 eth0 或eth1 的 bytes ,就是接收的数据量
C:\Users\Admin>adb shell "cat /proc/1316/net/dev" Inter-| Receive | Transmit face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 lo: 138333 1468 0 0 0 0 0 0 138333 1468 0 0 0 0 0 0 eth0: 67502526 876935 0 0 0 0 0 0 1093153548 639793 0 0 0 0 0 0 eth1: 440817 900 0 0 0 0 0 0 119085 920 0 0 0 0 0 0 ifb0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ifb1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
7、监控-启动时间
一、通过adb命令获取
- adb shell am start -W <packageName>/<activityName>
分为冷启动和热启动:冷启动就是把后台杀死,启动该 app 的时间;热启动就是不杀掉应用的情况下启动。我们这里记录的是冷启动过程,也就是把 APP 先杀死,再启动,一般热启动的时间为 0
而且,我们只关注 TotalTime
C:\Users\Admin>adb shell am start -W tv.danmaku.bili/tv.danmaku.bili.ui.splash.SplashActivity Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=tv.danmaku.bili/.ui.splash.SplashActivity } Status: ok Activity: tv.danmaku.bili/.ui.splash.SplashActivity ThisTime: 1264 TotalTime: 1264 Complete
看到结果如图:
8、监控-电量
获取手机电池信息,有很多方式,adb 命令不一定要通过数据线,通过 wifi 也可以
- adb shell dumpsys battery
- adb shell dumpsys battery set status 1
- adb shell dumpsys battery set level 100
C:\Users\Admin>adb shell dumpsys battery ## 获取手机当前的电量信息 Current Battery Service state: AC powered: true USB powered: false Wireless powered: false status: 5 ## 电池状态:2:充电状态 ,其他数字为非充电状态 health: 1 ## 电池健康状态:只有数字2表示good present: true ## 电池是否安装在机身 level: 100 ## 电量: 百分比 scale: 100 voltage: 0 ## 电池电压
current now: -335232 ## 电流值,负数表示正在充电 temperature: 0 ## 电池温度,单位是0.1摄氏度 technology: ## 电池种类 C:\Users\Admin>adb shell dumpsys battery set status 1 C:\Users\Admin>adb shell dumpsys battery set level 100 C:\Users\Admin>adb shell dumpsys battery Current Battery Service state: (UPDATES STOPPED -- use 'reset' to restart) AC powered: true USB powered: false Wireless powered: false status: 1 health: 1 present: true level: 100 scale: 100 voltage: 0 temperature: 0 technology:
获取电量消耗信息
- adb shell dumpsys batterystats
- adb shell dumpsys batterystats com.Package.name