引言
ShellUtils是Trinea为了方便开发者使用shell命令而开发的一个封装库,其本意是好的,但是如果对应要运行的脚本不够了解,就可能会引发严重的后果。
1.起因
前两天在团建的时候,系统组的zuxi通信微信告诉我说在Ota14的电视上长按音量+/-键会导致crash,而且android和ios都有这个问题。并且给出log,部分log如下:
|
|
很显然这不是微鲸助手的问题,而是中间件的问题了,但是为了找到问题的根源,对中间件代码进行了一番研究,发现对应的处理逻辑如下:
|
|
就不吐槽这个new Thread这种非常不节约的使用线程的方式了,进入到ShellUtils.execCommand():
|
|
而execCommand()代码如下:
|
|
之后跟踪到Runtime中:
|
|
之后进入到ProcessManager中:
|
|
最终是调用到了一个native方法:
|
|
而这个方法对应的C++方法如下:
|
|
显然,利用fork()创建了一个子进程,并且在父子进程中使用管道传递数据.这样就基本搞清楚了Runtime.getRuntime.exec(“sh”)的本质其实就是管道通信。
但是,即使是创建了进程,又不是Zygote创建的,为何会调用到RuntimeInit呢?
当时在这里卡了一下,后面才想到是命令input可能有问题,打开它的脚本,发现如下:
|
|
原来是先指定input.jar这个jar包的路径,再调用app_process来执行com.android.commands.input.Input的main()方法,这样就知道原因了:
app_process对应的代码在frameworkks/base/cmds/app_process/app_main.cpp这个文件中,代码如下:
|
|
注意最后的判断语句,显然当传入Input类时,会调用runtim.start(“com.android.internal.os.RuntimeInit”),由于runtime是AppRuntime对象,而AppRuntime继承自AndroidRuntime,之后就会调用到AndroidRuntime::start()方法:
|
|
注意在这里面打印了日志而且会创建VM,所以长按音量+/-键相当于频繁创建VM,这样会使system_server挂断,从而导致系统重启。
解决方法很简单:不要使用Runtim.exec()以及input命令的方法来实现,而是使用VolumeManager.
另外,app_process其实是一个非常重要的进程,Zygote进程其实就是由它启动的,详情可以看我的这篇博客:Zygote完全解析(1)