我们知道,当手机被root后,就可以通过su来执行具有root权限的代码了,但这基本只局限在了shell里面的命令。
比如我们可以执行 am、pm以及android支持的一些linux命令。
一但我们有些个性化需求,这些命令就显的不是那么人性化了。比如杀死100个程序,难道要循环一百次去执行am force-stop吗?显然不是。
本文主要想法是自己制作一个类似am、pm的工具来满足丰富的需求。
先来简要说一下am、pm等shell里面的命令到底是什么
am、pm其实是一个脚本,位置位于frameworks/base/cmds/am,frameworks/base/cmds/pm
以am举例,打开其脚本可以看到
- # Script to start "am" on the device, which has a very rudimentary
- # shell.
- #
- base=/system //根地址
- export CLASSPATH=$base/framework/am.jar //添加am.jar的java路径
- exec app_process $base/bin com.android.commands.am.Am "$@" //通过app_process 执行java代码
- package com.android.commands.am;
- //import ....;
- public class Am {
- //.....
- /**
- * Command-line entry point.
- *
- * @param args The command-line arguments
- */
- public static void main(String[] args) {//程序的主入口,执行后即调用
- try {
- (new Am()).run(args);//进行参数解析并执行
- } catch (IllegalArgumentException e) {
- showUsage();
- System.err.println("Error: " + e.getMessage());
- } catch (Exception e) {
- e.printStackTrace(System.err);
- System.exit(1);
- }
- }
- private void run(String[] args) throws Exception {
- if (args.length < 1) {
- showUsage();
- return;
- }
- mAm = ActivityManagerNative.getDefault();
- if (mAm == null) {
- System.err.println(NO_SYSTEM_ERROR_CODE);
- throw new AndroidException("Can't connect to activity manager; is the system running?");
- }
- mArgs = args;
- String op = args[0];
- mNextArg = 1;
- //通过匹配参数进行不同操作
- if (op.equals("start")) {
- runStart();
- } else if (op.equals("startservice")) {
- runStartService();
- } else if (op.equals("force-stop")) {
- runForceStop();
- } else if (op.equals("kill")) {
- runKill();
- } else if (op.equals("kill-all")) {
- runKillAll();
- }
- //.........
- else {
- throw new IllegalArgumentException("Unknown command: " + op);
- }
- }
- //.........
- private void runForceStop() throws Exception {
- mAm.forceStopPackage(nextArgRequired());
- }
- //.........
- }
- }
假设我们在shell的环境下执行 am force-stop com.xxx.xxx
实际上是走了如下几步:
1.触发am脚本 就像上面为大家展示的am脚本中的3行代码首先被执行,他起到的作用为首先将am.jar添加到系统的CLASSPATH中,使其jar文件可以被调用。
接下来app_process充当了调用角色,以com.android.commands.am.Am为入口类进行了调用,并传入"$@"参数。这个入口类即上面为大家贴上的Am.java
2.执行am.jar内Am类的对应代码 显然,app_process调用Am类后触发了main函数,并且传入了String[] args参数。am.java中我为大家截取了能说明执行顺序的几个方法
main-->run-->通过匹配参数执行各命令。
这样一来顺序就非常清晰了,原来am通过脚本执行了一个外部的jar文件。由于app_process进程属root组,所以其发起的进程也具有root权限,这也就是为什么类似forcestop之类的特权方法可以被调用。
这样一来,我们的思路也清晰了
1.仿照am.jar制作外部供调用的jar包,这样里面的代码我们就可以完全自定义,想到就心血澎湃啊!
2.通过su执行仿写的am脚本来触发jar包代码
关于制作jar包我们用到了androidSDK下面的DX工具以及aapt,这部分内容不是很难,留在下篇里一起说。