让Adb.exe支持Monkey
来源:互联网 发布:2k16库里捏脸数据 编辑:程序博客网 时间:2024/05/10 14:24
最近老研究一些之前的东西,越来越怀旧了真是
下载源码
要改造adb.exe从思路来讲很简单,把android源码里面的adb.exe部分提取出来,改造再进行编译不就可以了?是的。但是这一块的源码在哪个模块呢?由哪些文件构成?我是不是要先下载所有的Android源码才找得到?现在google的网站被封?我还得先…… 技术就是这样,思路很简单的事情操作起来可能并不简单,需要大把的时间,这里给大家介绍一个资源
android源码查找,可以根据文件名,类名,方法名的定义去查找到相应的文件(http://osxr.org/android/ident?)(Ver: 4.1.2_r2)
有了该网站,就可以不用下载整个android源码了,但是我还是把一整套android源码下下来了,整个过程太过艰辛,感叹一下做技术人员不容易,和各种势力进行抗争啊真是。经过一番查找,下面为adb client所在的源码目录
http://osxr.org/android/source/system/core/adb/
到了这里,是不是要去找一些官方文档,该目录下的一些文档说明来进行编译,太纠结了,去github上找找吧,现在是共享时代
https://github.com/t-mat/my_adb
啰嗦了一堆,其实就是下载my_adb去进行改造,不要打我
对源码进行改造
源码结构
//入口 adb.cint main(int argc, char **argv) { #if ADB_HOST adb_sysdeps_init(); adb_trace_init(); D("Handling commandline()\n"); return adb_commandline(argc - 1, argv + 1);#else if((argc > 1) && (!strcmp(argv[1],"recovery"))) { adb_device_banner = "recovery"; recovery_mode = 1; } start_device_log(); return adb_main(0, DEFAULT_ADB_PORT);#endif }
我们执行adb.exe时,会进入到if ture里面的分支,进入到adb_commondline函数
int adb_commandline(int argc, char **argv){...if(!strcmp(argv[0], "devices")) { char *tmp; snprintf(buf, sizeof buf, "host:%s", argv[0]); tmp = adb_query(buf); if(tmp) { printf("List of devices attached \n"); printf("%s\n", tmp); return 0; } else { return 1; } } if(!strcmp(argv[0], "connect")) { char *tmp; if (argc != 2) { fprintf(stderr, "Usage: adb connect <host>[:<port>]\n"); return 1; } snprintf(buf, sizeof buf, "host:connect:%s", argv[1]); tmp = adb_query(buf); if(tmp) { printf("%s\n", tmp); return 0; } else { return 1; } } ...}
该函数里面的功能就是常规的解析命令行参数,然后执行对应的功能,上面的代码展示出来的是常见的两个功能,显示设备列表和连接到某台设备
OK,不往下分析了,先分析一下我们需要加的功能吧
需要改造的功能
通过上一篇文章的分析可以得出有两个功能需要改进:adb.exe中无法传送utf-8格式字符串的问题 和 增加传送monkey指令的功能
adb.exe中无法传送utf-8格式字符串的问题
该问题网上是有现成的解决方案的,思路上只需要在发送buffer的时候,把gbk转成utf-8即可,adb daemon 是识别utf-8格式的,所以原生的adb传送gbk格式,中文就会显示不出来。
cmd默认字符编码是gbk,而且vs2013里面默认的文件编码也是gbk,如果把vs2013里面的源码文件改成utf-8格式的,是否可以不更改adb的源码,就可以用?我没试过,有兴趣的朋友可以测试一下,从原理上来讲是可以的。
增加传送monkey指令的功能
这个功能是需要和本地的adb server进行TCP交互的,还记得上一篇文章的图吗?
执行monkey命令流程流程是这样的,一次连接可能会执行很多次命令
socket层(TCP传输层)
增加传送monkey指令的功能
我们看一下socket层的代码是否需要我们自己添加
char *adb_query(const char *service){ char buf[5]; unsigned n; char *tmp; int fd; //+ D("adb_query: %s\n", service);//- int fd = adb_connect(service); fd = adb_connect(service); if(fd < 0) { fprintf(stderr,"error: %s\n", __adb_error); return 0; } if(readx(fd, buf, 4)) goto oops;...}int adb_connect(const char *service){ // first query the adb server's version int fd = _adb_connect("host:version"); if(fd == -2) { fprintf(stderr, "* daemon not running. *\n"); return -1; fprintf(stdout,"* daemon not running. starting it now on port %d *\n", __adb_server_port); start_server: ...}
adb client的命令有一部分是通过adb_query函数进行发送,里面会用到adb_connect,返回socket实例,再通过该socket读取到返回的内容进行输出
unsigned char* adb_monkey_query(const char *service, int mFd){ char buf[5]; unsigned n; int fd; //+ unsigned char* outRel = NULL; D("adb_query: %s\n", service); //- int fd = adb_connect(service); fd = _adb_monkey_connect(service,mFd,&outRel); if(fd < 0) { fprintf(stderr,"error: %s\n", __adb_error); } return outRel;}int adb_monkey_exec(const char *service, int mFd){ char buf[5]; unsigned n; int fd; //+ unsigned char* outRel = NULL; D("adb_query: %s\n", service); //- int fd = adb_connect(service); fd = _adb_monkey_connect(service,mFd,&outRel); if (outRel!=NULL) { free(outRel); } if(fd < 0) { fprintf(stderr,"error: %s\n", __adb_error); return 0; } return 1;}int _adb_monkey_connect(const char *service, int mFd, unsigned char** outRel){ char tmp[5]; int len; D("_adb_monkey_connect: %s\n", service); len = strlen(service); if((len < 1) || (len > 1024)) { strcpy(__adb_error, "service name too long"); return -1; } if (mFd<=0) { mFd = socket_loopback_client(__adb_monkey_server_port, SOCK_STREAM); } if(mFd < 0) { strcpy(__adb_error, "cannot connect to monkey port"); return -2; } if(writex(mFd, service, len)) { strcpy(__adb_error, "write monkey cmd failure during connection"); adb_close(mFd); return -1; } if(adb_monkey_status(mFd,outRel)) { strcpy(__adb_error, "monkey cmd return err"); //adb_close(mFd); return -1; } return mFd;}
通过上面的代码可以看出,我增加了adb_monkey_query adb_monkey_exec 和 adb_monkey_connect,其实query和exec都是用到了connect函数,只是一个有返回,一个没有返回而已,底层adb_monkey_connect怎么实现的,其实和_adb_connect类似
int _adb_monkey_connect(const char *service, int mFd, unsigned char** outRel){ char tmp[5]; int len; D("_adb_monkey_connect: %s\n", service); len = strlen(service); if((len < 1) || (len > 1024)) { strcpy(__adb_error, "service name too long"); return -1; } if (mFd<=0) { mFd = socket_loopback_client(__adb_monkey_server_port, SOCK_STREAM); } if(mFd < 0) { strcpy(__adb_error, "cannot connect to monkey port"); return -2; } if(writex(mFd, service, len)) { strcpy(__adb_error, "write monkey cmd failure during connection"); adb_close(mFd); return -1; } if(adb_monkey_status(mFd,outRel)) { strcpy(__adb_error, "monkey cmd return err"); //adb_close(mFd); return -1; } return mFd;}int adb_monkey_status(int fd,unsigned char** rel){ unsigned char tbuf[1]; int len,alllen=0; int fail = 0; *rel = NULL; while(fd >= 0) { len = adb_read(fd, tbuf, 1); if (len == 0) {//读取出错 fail = 1; } if(len == 0 || tbuf[0]=='\n') { break; } if(len < 0) { if(errno == EINTR) continue; break; } alllen += len; *rel = (unsigned char*)realloc(*rel,alllen+1); memcpy(*rel+alllen-len,tbuf,len); *(*rel+alllen) = 0; } if(fail) { strcpy(__adb_error, "monkey fault (no status)"); return -1; } if(*rel != NULL && !memcmp(*rel, "OK", 2)) { return 0; } return -1;}
OK,整个monkey功能的socket层就算完了
应用层
adb.exe中无法传送utf-8格式字符串的问题
直接上代码,在执行命令的函数里面把buffer的编码变掉就可以
int shell(char* inSerial, char* inParams, unsigned char** outRelStr){ int fd = 0; char buf[10240]; unsigned char* rel = NULL; char* inParamsUTF8; transport_type ttype = kTransportAny; int server_port = DEFAULT_ADB_PORT; adb_set_transport(ttype, inSerial); adb_set_tcp_specifics(server_port); //这个函数就是关键的编码转换函数 GBK_to_UTF8(inParams,strlen(inParams),&inParamsUTF8); ZeroMemory(buf,10240); snprintf(buf,sizeof buf,"shell:%s",inParamsUTF8); free(inParamsUTF8); fd = adb_connect(buf); //+ if(fd >= 0) { char buf[4096]; int len; int alllen=0; int first = 0; while(fd >= 0) { len = adb_read(fd, buf, 4096); if(len == 0) { break; } if(len < 0) { if(errno == EINTR) continue; break; } alllen+=len; rel = (unsigned char*)realloc(rel,alllen+1); memcpy(rel+alllen-len,buf,len); rel[alllen] = 0; //先做调试用,后期去掉 //fwrite(buf, 1, len, stdout); //fflush(stdout); } * outRelStr = rel; adb_close(fd); return 1; } return 0;}
GBK_to_UTF8函数的代码不贴出来了,网上非常多
增加传送monkey指令的功能
/*初始化monkey的连接,我们采用连接一次成功后,可以无限发送命令的模式连接deviceSocket并查询版本信息连接monkeySocket连接成功就行返回:是否成功 1成功 0失败*/int init(char* inSerial, int inMonkeyPort, int* outMonkeySocket){ transport_type ttype = kTransportAny; int server_port = DEFAULT_ADB_PORT; char *tmp; unsigned char* mrel = NULL; char buf[4096]; int fd = 0; adb_trace_init(); adb_sysdeps_init(); //这里只是设置一个模式,没有起实质性的变化 adb_set_transport(ttype, inSerial); adb_set_tcp_specifics(server_port); //打开Monkey的端口 snprintf(buf, sizeof buf, "host-serial:%s:forward:tcp:%d;tcp:%d",inSerial,inMonkeyPort,inMonkeyPort); fd = adb_connect(buf); if(fd >= 0) { if (adb_status(fd)) { adb_close(fd); return 0; } read_finished(fd); adb_close(fd); } else { fprintf(stderr,"error: %s\n", adb_error()); return 0; } //把手机端的Monkey端口设置为我们的端口 //这是一个bug貌似,非常低端... monkey是阻塞命令,如果连接成功之后直接close这样monkey程序就会退出,所以睡5秒再说,官方的方法就是睡的5秒,如果有更好的办法就太好了 set_monkey_port(inMonkeyPort); snprintf(buf, sizeof buf, "shell:monkey --port %d", inMonkeyPort); fd = adb_connect(buf); printf("monkey --port %d done\r\n",inMonkeyPort); if(fd >= 0) { Sleep(5000); adb_close(fd); } else { return 0; } printf("monkey --port %d ok\r\n",inMonkeyPort); //唤醒屏幕 printf("wake\n",buf); *outMonkeySocket = _adb_monkey_connect( "wake\n",-1,&mrel); if (mrel!=NULL) { free(mrel); } if(*outMonkeySocket < 0) { fprintf(stderr,"error: %s\n", get_adb_error()); return 0; } return 1;}
下面例举几个monkey的应用层命令
int wake(int inMonkeySocket){ return adb_monkey_exec("wake\n",inMonkeySocket);}int press(int inMonkeySocket, char* inKeyName, char* intPressType){ char buf[4096]; if (strncmp("down",intPressType,sizeof("down"))==0) { snprintf(buf, sizeof buf,"key down %s\n",inKeyName); } else if (strncmp("up",intPressType,sizeof("up"))==0) { snprintf(buf, sizeof buf,"key up %s\n",inKeyName); } else if (strncmp("downAndUp",intPressType,sizeof("downAndUp"))==0) { snprintf(buf, sizeof buf,"press %s\n",inKeyName); } return adb_monkey_exec(buf,inMonkeySocket);}
OK,先分析思路,再搭建底层,最后建立应用层,整个adb.exe,或者adb.dll其他的,就可以操控整个android系统了,非常实用。下一讲讲啥呢?操控是可以,我要根据android设备的屏幕输出判断程序结果是否正确怎么办?怎么获取图像?怎么辨别?
目录
- 下载源码
- 对源码进行改造
- 源码结构
- 需要改造的功能
- adbexe中无法传送utf-8格式字符串的问题
- 增加传送monkey指令的功能
- socket层TCP传输层
- 增加传送monkey指令的功能
- 应用层
- adbexe中无法传送utf-8格式字符串的问题
- 增加传送monkey指令的功能
- 目录
- 让Adb.exe支持Monkey
- adb monkey
- adb monkey
- monkey 测试 adb shell monkey
- ADB monkey test
- adb monkey 停止命令
- adb shell monkey
- adb、monkey常用命令
- ADB Shell Monkey Command
- android工具之adb monkey
- adb.exe 命令详解
- adb.exe 找不到
- android 找不到adb.exe
- adb.exe 命令详解
- adb.exe 不能运行
- adb.exe诊断
- adb.exe被占用
- adb.exe 命令详解
- 使用URL读取网页的内容
- WebView(网络视图)
- 类的赋值初始化
- ImageCache——图片三级缓存(内存、文件、网络)
- mybatis的常见问题
- 让Adb.exe支持Monkey
- java SE复习笔记45
- arm-linux-ld命令
- 使用adb将tcpdump的流量导到wireshark
- windows上安装clang教程
- 指向类成员函数的指针
- 最长上升子序列
- mac下卸载android studio
- sql 2005 应用经验技巧与备忘