安卓使用Root权限实现后台模拟全局按键、触屏事件方法(相似按键精灵)android
有 时咱们须要使用安卓实如今后台模拟系统按键,好比对音量进行调节(模拟音量键),关闭前台正在运行的App(模拟返回键),或者模拟触屏事件。可是对于原 生安卓系统而言,后台进程关闭前台进程,甚至模拟用户事件,进而操控整个系统,是不符合系统安全原则的,若是有这样的漏洞被病毒或恶意软件所利用,会很是 危险。
因为一些特殊缘由,我恰巧须要实现这样的功能,而又没有条件自行编译安卓系统(可是能够利用Root权限,由于Root权限的获取相对简单不少,而且不少用户的安卓设备都有Root过)。网上也看到不少人在提相似的问题,不少人讨论了半天,结果都是无解。因而我花了很大精力,最后终于找到了解决方案。
在网上查找了不少资料,主要找到两种方法:Instrumentation和IWindowManager。编程
使用Instrumentation接口:对于非自行编译的安卓系统,没法获取系统签名,只能在前台模拟按键,不能后台模拟。安全
一种是使用Instrumentation接口,这个接口本来是用来对软件进行测试而留出来的。通过尝试,发现这个接口能够模拟按键,可是前提是在应用处于前台时。而应用处于前台时,模拟按键基本上也没有太大的做用(模拟按键操做应用自身彷佛没有很大意义)。
当应用处于后台时,这个Instrumentation接口就失效了。网上找到的解释是,在后台使用这个接口,须要有系统权限,也就是在Manifest中添加android:sharedUserId=”android.uid.system”。而这会致使什么问题呢?声明了系统权限的APK,只有具备系统签名的状况下,才能被安装到安卓设备上,好比系统自带的电话、短信,本质上也就是APK程序,可是这些应用具备系统权限。
安 卓系统有一套签名机制,APK只有有了数字签名,才能被安装。一般调试时默认Eclipse自动对其进行签名,使用的是Debug签名。当发布应用时,开 发者则使用本身独有的数字签名文件对APK进行签名(这个文件能够用Eclipse生成,签名也可让Eclipse完成)。APK有新版本的安装时,如 果检测到签名不一致,系统会提示签名不一致,只有卸载旧版本才能安装。这一机制从必定程度上避免了第三方对官方发布的APK进行修改甚至非法植入病毒等行 为(固然若是用户主动卸载旧版本的官方应用、安装新版本的非官方APK也是能够的)。而具备同一签名的不一样App,它们之间能够共享一些数据。
而 系统签名怎么获取呢?在编译安卓系统的时候,会将一个系统签名的数字签名文件放到一块儿编译。对于一个已经编译完成的系统,或者为了适配不一样系统,必然没法 获取到这个数字签名文件,因而也没法对APK进行系统签名。最后就致使具备uid.system属性的APK没法被安装,因而 Instrumentation接口后台模拟按键的方法,只能在自行编译系统的状况下才可使用。学习
使用反射方法调用系统IWindowManager隐藏API:兼容性较差,稳定性很差,容易出错。另外实际编译时发生错误,缘由暂时不明。
网 上还有一种方法。安卓系统中有一些隐藏API,一般是利用Java的权限限制,使得这些API没法被调用。但经过反射的方式,能够突破Java的权限限 制。在IWindowManager中就隐藏了能够模拟按键和触屏事件的API。尝试网上的方法,下载到一个由安卓源码编译好的jar文件,添加到工程 中,而后使用发射编写了一些代码,尝试调用隐藏API。结果编译的时候Eclipse直接不响应了,多是由于电脑配置不够,jar文件太大。尝试了几回 没有成功,又考虑到这种方法有不少弊端,而且极可能最后仍是须要系统权限(网上很多文章说得不是很清楚),因而就放弃了这个方法。
android模拟按键问题总结[使用IWindowManager.injectKeyEvent方法]测试
Android中使用隐藏API(大量图解)ui
JNI调用C程序模拟按键:仍然是权限问题。
参 考了网上一些资料所提出的可能的思路,发现剩下能想到的方法就是用JNI实现,经过调用C/C++程序来模拟按键。对Linux底层编程不熟悉,网上参考 了一些代码,在Ubuntu下编写了一个按键模拟程序,很顺利的编译运行经过。而后又开始学习JNI的编译方法,先在C程序层写了个简单的加法运算,编译 运行测试经过,而后就把模拟按键的代码贴了进去。满怀期待的写好安卓Java层代码,编译、下载、执行程序,却发现彻底没有效果。
想看一下究竟是哪一步出错了,就在C程序里面改了改,用LogCat打印出C程序的返回值,发如今打开按键设备的时候出错,看来确定又是权限的问题了。
尽管系统已经Root,APK也容许使用Root权限,可是Root权限无法传递给C程序,权限不够,程序没法执行。在网上找了一通有关Linux、安卓权限的资料,也没找出来什么思路。其实当时很疑惑,在Linux系统中,Root权限是最高的权限,安卓也不例外,有文章指出,Root权限>系统权限>用户权限。尽管能获取到Root权限,却不能完成系统权限所能完成的任务,总感受不该该。调试
安卓按键精灵:使用Root权限而不需系统签名,实现后台模拟按键和触屏等事件是可行的。
当时很绝望,感受估计只有自行编译系统才能解决问题了。就在那时候,忽然想起了按键精灵软件。之前用过电脑版,在安卓市场一找,果真也有安卓版。下载使用发现,按键精灵就能够实如今后台模拟按键操做,须要Root权限,可是是什么原理却不得而知。本想尝试反编译源码查看,可是当时出了一些问题,反编译没有成功。在网上搜索安卓按键精灵的原理,除了以前的那两种依赖源码环境才能使用的API,也没有找到结果。不过至少说明了,使用Root权限而不须要系统签名,实现模拟按键、而且兼容大量安卓设备是可行的。对象
最终解决问题:使用Shell调用ADB指令实现。
继 续在网上搜索安卓按键模拟(其实那时都不知道用什么关键字好了,能想到的关键字都用遍了,可是搜索出来的结果,都是以前提到的那几个依赖源码环境和系统权 限的方案)。发现有不少介绍ADB调试,向手机发送按键事件的文章。恰好以前作过在Root权限下,用Java调用安卓底层的Linux Shell,而后执行pm指令进行APK的安装卸载。这时我突发奇想,可否用Shell调用ADB指令呢?
因而就进行了尝试,使用Java执行 Runtime.getRuntime().exec(“su”).getOutputStream(),获取了一个具备Root权限的Process的 输出流对象,向其中写入字符串便可以Root权限被Shell执行,ADB模拟按键的指令为 “input keyevent keyCode”,keyCode为按键的键值,例如KeyEvent.KEYCODE_VOLUME_UP表示音量加。
编译完程序安装执行,终于实现了预期的效果接口