Android之Monkey源码分析(第一篇:环境与命令)

Monkey源码获取:https://android.googlesource.com/platform/development.git/ 

前言

    monkey,一个Android平台的命令行工具,既熟悉又陌生,很多同学一定熟悉monkey的使用,而陌生的是对它的原理完全不懂,所以才有今天学习Monkey的源码设计,monkey程序是如何实现的呢?

monkey源码下载地址:https://github.com/aosp-mirror/platform_development/tree/master/cmds/monkey

Google:https://android.googlesource.com/platform/development.git/+/refs/heads/master/cmds/monkey/src/com/android/commands/monkey

检查monkey命令

adb shell type monkey
monkey is a tracked alias for /system/bin/monkey

    Android基于Linux内核,所以它也有内置的type命令【type命令是一个可执行文件(程序),它用于查看可执行文件的类型】, 当我们执行

adb shell type monkey

看到标准输出中这么一行:monkey is a tracked alias for /system/bin/monkey

这句话的意思是:monkey是/system/bin/monkey这个可执行文件的别称,当我们输入adb shell monkey的时候,运行的程序为Android系统中的/system/bin/monkey这个可执行文件,接下来学习/system/bin/monkey这个文本文件的内容是什么呢?它是个什么程序呢?

/system/bin/monkey源码分析

# Script to start "monkey" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/monkey.jar
trap "" HUP
for a in "$@"; do
    echo "  bash arg:" $a
done
exec app_process $base/bin com.android.commands.monkey.Monkey "$@"

    /system/bin/monkey是monkey的可执行文件(程序),原来它是位于/system/bin目录下的一个shell脚本文件【可执行权限的文本文件,且遵守bash规范,常称为shell脚本程序,简称shell脚本】,接下来分析这个shell脚本文件都代表啥

0、#开头的是shell脚本编程中的注释

1、创建全局变量base,用于存储目录名称

创建一个称为base的全局变量,变量值是/system,存储的是一个字符串路径(备注:shell脚本只有一种数据类型:字符串)

2、导出环境变量值,用于记录monkey.jar文件的绝对路径

export命令用于导出环境变量CLASSPATH,环境变量值是$base/framework/monkey.jar(备注:$字符是shell编程中的变量替换字符,shell解释器会先执行变量值替换),这里是两个步骤

第一:shell脚本解释器先做变量值替换,

第二:再做字符串拼接(备注:shell脚本的字符串拼接,紧挨着即可,不用+号)

由于$base会被替换为/system,所以最终的CLASSPATH的变量为/system/framework/monkey.jar

monkey.jar是monkey项目的字节码jar包,里面都是.class字节码文件,可见monkey程序是Java写的……(are you sure?难道不是dex?)

3、捕获HUB信号,然后处理

trap命令用于捕获信号,然后处理,HUP:HUP表示中断信号表示用户键入时由终端驱动程序发送的信号,中间""表示捕获信号之后做的事情,这里表示捕获到HUP信号后什么也没有做!【备注:信号是Linux进程间通信的方式之一】

4、循环所有命令行参数,写入标准输出(屏幕)……

一行一个的打印命令行参数(以空格字符隔开),shell中for循环的语法,echo命令用于向屏幕中输出内容,$@可以获取到所有的命令行参数,我们给monkey命令传入的所有命令行参数,echo将接收到的所有命令行参数原样写入到标准输出

5、替换程序,可执行文件(程序)app_process在开始运行

exec命令用于在当前shell进程中替换一个新的程序,这里会替换一个新的程序运行,这个程序就是app_process。此处最初为shell进程,接着shell进程执行的程序替换为app_process(当前的shell程序会被替换,改为执行app_process程序的代码逻辑),$bash/bin和com.android.commands.monkey.Monkey、还有"$@"解析出来的所有命令行参数,会拼接一个一个的命令行函数再传递给app_process程序(可执行文件)

app_process是一个可执行文件,由c++编写,它会创建虚拟机实例,所以可以用来执行Java程序

执行Java程序时,又会将所有命令行参数,传入类Java程序的入口类

app_process是什么

    一个可执行文件(程序),由c++编写,它是zygote进程中实际运行的程序,在app_process程序中会创建虚拟机实例(Android平台中的ART虚拟机),由于app_process涉及内容多,该篇点到为止,后面会专门写一篇app_process程序的分析(这个卷了,c++不熟悉),这里暂时知道monkey程序的主要业务逻辑是在monkey.jar包中的字节码文件中,app_process程序会读取CLASSPATH环境变量值,CLASSPATH环境值指向的是CLASSPATH=$base/framework/monkey.jar,所以app_process程序会从monkey.jar文件中,查找作为命令行参数的com.android.commands.monkey.Monkey类,所以会加载这个Monkey类到ART虚拟机中开始执行Java程序了,也就是Monkey程序主要业务逻辑仍然是Java程序!

举个例子

adb shell monkey -p your.package.name -v 500

    命令行中执行monkey命令(程序),传入4个命令行参数到monkey脚本中(备注:shell编程中的空白字符用于隔开每个单词作为命令行参数)

    以下是shell解释器替换后的monkey脚本程序(备注:shell解释器背后会先做变量值替换,命令行参数替换,最后再执行命令)

# Script to start "monkey" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=/system/framework/monkey.jar
trap "" HUP
for a in -p your.package.name -v 500; do
    echo "  bash arg:" $a
done
exec app_process $base/bin com.android.commands.monkey.Monkey -p your.package.name -v 500

总结

1、com.android.commands.monkey.Monkey,表示Java程序的入口类为Monkey,按照java程序的规范(标准),Monkey类的静态方法main()会执行,而Monkey类后面的所有命令行参数,比如上文中提及的传入的几个参数,会全部传递到Java程序中(app_process程序调用Java程序时执行的)

2、在我的第二篇文章中,我将分析Java程序Monkey类的静态方法main(),静态方法main()是monkey程序的入口,monkey的主线程流程(进程)将在此运行

3、Android平台的monkey程序,涉及到shell脚本程序(monkey)、c++程序(app_process)、java程序,主要的业务逻辑全部在Java程序中,佩服佩服,牛逼牛逼!!!!程序之间相互调用,简直太拽了…………

你可能感兴趣的:(Android,Monkey源码分析,Monkey源码分析)