Android心跳检测,为何要心跳检测,什么是心跳检测,这篇文章我给大家讲解下思路,以免跟我一样走过不少的弯路。
android终端心跳检测是跟系统侧进行交互,用作长连接用的,终端隔断时间给系统发包,告诉系统我还在,若是系统没有收到终端的心跳包,就会断掉终端连接,默认该终端已经挂了。说到这里就这都此android终端非公网机,而是有与系统交互的机器。详细相关心跳解析百度下
心跳检测时间设置是有讲究的,时间设置很长才发送一次,这样终端容易掉线,为什么掉线,是终端有可能异常掉线、断网等其他场景,终端出现异常了,系统却认为该终端还是正常态,导致用户发起呼叫、被叫都会出现失败;时间设置很短才发送一次,这样会影响终端的功耗,什么是设置合理范围,什么样去测试,该怎么测试?
首先,我们要找到终端接受的极限值,即压力测试,如何做压力测试,这需要一个完成的测试方案,如何最优最有效的测试,举例,加入系统侧同事告诉你,心跳检测最大值只能设置30秒,这样你的终端测怎么去设置,终端最大设置也是30秒,那就先从最大极限30秒开始测试,插入各种制式的卡,移动联通电信432G等,然后方案制定,在30秒内,随机去发起呼叫,出发它,看是否有出现终端在30秒内实际已经出现断线,1----30区间,这个取值方案确定很重要,你也可以取30----60区间,其实都有一样,细节就不详细描述,该怎么规划看你们方案怎么制定。我这里以[1,30]区间取随机取值去发起呼叫验证(为什么要取随机值,这是因为这里的30秒不是约定的时间,是终端与系统30秒的时间,我们是很难知道而且很难获取这个时间点的)。取随机值的目的是在任一时间去触发,要是出问题,也总是出问题。
这个需要自动化去测试,人工测试统计很累,这里我们设置呼叫100次,为何设置100次,后面后讲到;
我们先编写呼叫端,设置前我们设置一个文件存储和随机参数的公用方法,现在写一个获取随机参数的公用方法,提供其他脚本调用:
util.FileUtil:文件存储,后面会做判断
package util;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class FileUtil {
public static void out (String filepath,String test) throws IOException{
File file = new File(filepath);
if(!file.exists()){
file.createNewFile();
}
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
// bw.write("�����������:"+count1+";");
bw.write(test);
bw.close();
}
}
util.RandomUtil
package util;
import java.io.IOException;
import java.util.Random;
public class RandomUtil {
public static int getOututil (){
int max=30;
int min=1;
int ss;
Random random = new Random();
int radomm = random.nextInt(max)%(max-min+1) + min;
return radomm;
}
}
公用文件写好了,接下来就得写测试用例了;
我们这里要写呼叫端,呼叫100次,只写主叫,被叫接收日志太多,后面讲解原因;
主叫是取随机数的时间[1,30]时间内发起呼叫,呼叫一次保持30秒,然后休眠”随机数“秒,再次发起呼叫,这样循环100次;(为什么要做呼叫,呼叫是取测试终端有没有死,也就是在心跳30秒范围内有没有出现异常)
package uiauto;
import java.util.Random;
import util.FileUtil;
import util.RandomUtil;
import com.android.uiautomator.core.UiDevice;
import com.android.uiautomator.core.UiObject;
import com.android.uiautomator.core.UiSelector;
import com.android.uiautomator.testrunner.UiAutomatorTestCase;
public class callphone extends UiAutomatorTestCase {
private final static int KeyCode_PTT = 284;
public void testcallphone() throws Exception{
int count=1;
int count1=1;
int count2=1;
int count3=1;
int max=60;
int min=1;
UiDevice device = UiDevice.getInstance();
UiObject Kongxian = new UiObject(new UiSelector().resourceId("com.mcptt:id/speaker_name"));
String b = Kongxian.getText();
System.out.print("Kongxian.getText()="+b);
for(int j = 0; j < 10000; j++){
// Random random = new Random();//随机数
// int s = random.nextInt(max)%(max-min+1) + min;//s为随机数,这里我单独写了公用方法
int s=RandomUtil.getOututil();
System.out.println(s);
Runtime.getRuntime().exec("mkdir sdcard/GotaTestPresure");
Runtime.getRuntime().exec("mkdir sdcard/GotaTestPresure/HeattBeatTest");
if(s>=1 && s<=30){//去1-30区间的时间段进行发起呼叫
System.out.print("Log:[1,30]"+"\n");
Runtime.getRuntime().exec("input keyevent --longpress 5 284");//按下PTT键不松,260为PTT键键值
if(Kongxian.getText()!=b){//统计发起成功次数
System.out.print("HuchuSuccess"+"\n");
FileUtil.out("sdcard/GotaTestPresure/HeattBeatTest/30ZhuCallSuccess.txt", "[1,30]主叫呼出成功:"+count);
count=count+1;
}else{
System.out.print("HuchuFile"+"\n");
FileUtil.out("sdcard/GotaTestPresure/HeattBeatTest/30ZhuCallFail.txt", "[1,30]主叫呼出失败:"+count1);
count1=count1+1;
}
sleep(11000);//实际长按10秒
UiDevice.getInstance().pressKeyCode(284);//松开PTT键
int a = s*1000;
System.out.print("Log:Wait"+a+"\n");
sleep(a);
}
/*if( s>90 && s<=120){
System.out.print("Log:(90,120]"+"\n");
Runtime.getRuntime().exec("input keyevent --longpress 5 284");//按下PTT键不松,260为PTT键键值
if(Kongxian.getText()!=b){
System.out.print("HuchuSuccess"+"\n");
FileUtil.out("sdcard/GotaTestPresure/HeattBeatTest/60ZhuCallSuccess.txt", "(90,120]主叫呼出成功:"+count2);
count2=count2+1;
}else{
System.out.print("HuchuFile"+"\n");
FileUtil.out("sdcard/GotaTestPresure/HeattBeatTest/60ZhuCallFail.txt", "(90,120]主叫呼出失败:"+count3);
count3=count3+1;
}
sleep(11000);//实际长按10秒
UiDevice.getInstance().pressKeyCode(284);//松开PTT键
int a = s*1000;
System.out.print("Log:Wait"+a+"\n");
sleep(a);
}*/
}
}
}
写完主叫,肯定要写被叫,但是这里被叫为什么写不了呢,所以这里不用写被叫了,我只是讲解下如何分析接听端成功接听了多少次:
1.uiautomator监听器只是用来监听公网来电和短信的,这里我的主叫属于app通话内部的呼叫,这种监听器监听不了,只能从界面控件判断,接听和空闲两种状态,可是怎么去判断,我写了一下的方法,结果发现这种方法实在不行,因为我是隔断时间去看是否是空闲,不是的话再次记录,而且控件名都是一样的,真做不了,误差太大,得出来的数值偏多和偏少,如主叫呼100次,被叫接听200次或10次,这也存在测试过程受外界打扰,如来电来短信等导致脚本终止,得到的数值没有任何意义;
2.我也考虑过编写apk去监听,可是该呼叫软件没有提供任何的接口,没有办法去写,因为这个通话app是其他部门写的,申请他们提供台麻烦;
3.被叫只能通过日志去去统计,寻找接听成功的关键字,一搜索就出来的,但这里也有个缺点,在MTK平台的日志,长时间连接的日志太大,会冲掉前面的日志,统计次数也失败,所以我设计100次呼叫,进行多轮,这个看下面表格次数5的案例;(现在想到了不只通过日志去统计,我们可以写被较端脚本了)
------不知道大家还有其他什么方法,请在下方评论留言探讨。
失败的接听脚本,这里我就不列了,太丢面子了。(想到了一个简单的被叫端方法,就是一直监听一直for,之前试了for很快,统计数据太多,这里每隔1s监听一次,这样主叫呼十秒,那也就是在10秒中得到10次的统计数据,最后得出的数据除以10就是实际的监听效果,看下面的代码)
/*前面的略,自己添加*/
getUiDevice().wakeUp();//等到端口
UiObject Kongxian1 = new UiObject(new UiSelector().text("空闲"));//判断是否是空闲
for(int j = 1; j < 1000000000; j++){
sleep(1000)//隔1秒就判断,否则for循环速度太快,一下数值就很大;
int n = Kongxian.getText().length();//空闲长度是2位数,非空闲是一串号码
//判断是否是空闲
if(n!=2){//判断非空闲时就记录,最后得出的结果在除以2就行
//接听判断就记录
FileUtil.out("sdcard/GotaTestPresure/HeattBeatTest/BeiListenSuccess1.txt",
"被叫接听 成功次数"+count);
count=count+1;
}
}
把最后统计出的结果除以10,然后在对比日志,看是否一致,暂未有时间验证;
测试结束后把所以log导出来,主叫直接看我脚本的统计,主叫确保是正确的,看主叫呼了多少次,被叫看日志接听了多少次就可以用excel进行统计呼叫成功率如下所示:
次数5一夜长跑1736次统计失败,原因是日志被冲掉,无法统计真实数据,所以测试失败,不计算在内;
运营商(心跳) | 次数2 | 次数3 | 次数4 | 次数5 | 平均值 | |
主叫 | 100 | 98 | 100 | 1736 | ||
1# | 电信3G(30s) | 100 | 98 | 100 | 171 | |
4# | 电信3G(30s) | 100 | 98 | 100 | 279 | |
5# | 电信3G(30s) | 100 | 98 | 99 | 268 | |
3# | 联通4G(30s) | 100 | 98 | 100 | 606 | |
6# | 移动4G(30s) | 100 | 98 | 100 | 290 | |
Z对比机 | 电信3G(2s) | 仅对比 | 不计算 | 对比机 | 的结果 | 参数略 |
统计(%) | 100.00% | 100.00% | 99.80% | 99.93% |
自己根据测试情况设计出来的成功率统计公式:
成功率 = { [ (被叫1#+被叫4#+被叫5#+被叫3#+被叫6#) /5 ] / 主叫 } *100%
举例:
次数4的成功率计算 = { [ (100+100+99+100+100) /5 ] / 100 } *100% = 99.80%
次数3的成功率计算 = { [ (98+98+98+98+98) /5 ] / 98 } *100% = 100.00%
次数2的成功率计算 = { [ (100+100+100+100+100) /5 ] / 100 } *100% = 100.00%
然后测试几次,就全部把所有次数的平均值当做最后结果:(99.80%+100.00%+100.00%)/ 3 = 99.93%;