Java程序是跨平台的,由JVM虚拟机执行字节码。Android应用程序开发也是Java,但是都是运行在Context环境下的。独立的Java程序能够在Android上独立运行?
这里不介绍Android启动过程中,app_process从哪个进程fork处理,也不介绍app_process启动App的过程。仅介绍app_process启动纯Java程序的相关知识。
编写一个hellworld 的Java程序,并且编译成.class文件,简单得没啥可说的。
public class Helloworld {
public static void main(String[]args){
System.out.println("Hello, I am started by app_process!");
}
}
Android对Java虚拟机做了修改,即使用自己的dalvik虚拟机(后来的ART)。因此,.class的字节码在Dalvik虚拟机上是不能运行的。Android Platform tool为我们提供了生成Android上可执行jar(Dex)工具:dx。编译命令如下:
//编译,这里主要是Platform tool上用的是Java 7,所以显式指定1.7
javac -source 1.7 -target 1.7 C:\Users\Venscor\Desktop\app_process\dump.java
//生成dex,当然生成jar在Android上也是可执行的
dx --dex --output=C:\Users\Venscor\Desktop\app_process\Hellworld.dex Helloworld.class
app_process参数格式如下:
app_process [vm-options] cmd-dir [options] start-class-name [main-options]
app_process运行参数居然没有help,万恶的开发者。这块要么查资料,要么看源码。从网上找的对参数解释如下:
vm-options – VM 选项
cmd-dir –父目录 (/system/bin)
options –运行的参数 :
–zygote
–start-system-server
–application (api>=14)
–nice-name=nice_proc_name (api>=14)
start-class-name –包含main方法的主类 (com.android.commands.am.Am)
main-options –启动时候传递到main方法中的参数
将我们前面编译得到的dex(jar)文件push到/data/local/tmp文件夹下,构建app_process运行参数:
app_process -Djava.class.path=Helloworld.dex /data/local/tmp Helloworld
切换/data/local/tmp目录下运行,HelloWorld就成功运行啦!
上面展示了使用app_process在Android启动独立的Java进程的Demo。那么,被启动的Java程序作为一个独立的进程,其从何处fork而来,Uid为多少,对应什么级别权限就是下面要解决的问题。
为了能够查看app_process启动的Java程序的进程信息,希望demo程序不立马执行结束,以便能够通过ps查看进程信息。修改上面的demo程序,变成死循环让程序持久存活,并先后启动两个这样的Java程序。
通过上面进程信息可以看到,每次Java程序运行时,系统都会给其分配一个pid,并且进程名都是app_process。(至于为什么要这么命名,不清楚。。。)
通过追踪ppid,还能发现启动的java进程源自何处,即怎么fork出来的,即:/init–>/sbin/adbd–>/system/bin/sh–>app_process(Java进程),也就是说,启动的Java进程是从/system/bin/sh(shell)fork出来的。
知道了相应的pid,就可以通过pid查看进程信息,对应的shell命令为:cat /proc/[pid]/status.
通过上面信息可以看到,app_process启动的Java程序运行的uid是和pid是2000,也就是shell 的Uid,所以app_process启动的Java程序拥有shell级别的权限,下面就此来做个验证。
adb shell中,dumpsys activity命令是查看Activity栈信息的,只有shell权限(可能有shell权限也不行,必须Uid为shell,没有去看)才能调用。所以可以通过这个来验证启动的Java程序是否真的运行于shell的Uid下,测试源代码如下:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class dump {
public static void main(String[]args){
String cmd="dumpsys activity";
System.out.println("Hello, I am started by app_process!");
try {
Process p=Runtime.getRuntime().exec(cmd);
BufferedReader br=new BufferedReader(new InputStreamReader(p.getInputStream()));
String readLine=br.readLine();
while(readLine!=null){
System.out.println(readLine);
readLine=br.readLine();
}
if(br!=null){
br.close();
}
p.destroy();
p=null;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
和前面demo一样编译到Android下运行,查看结果,发现可以正常输出,说明app_process启动的Java程序的确具有shell级别的权限(其实其Uid就是shell)。
总结: 上面说明了app_process启动Java的相关知识,至于有啥重要用途,后续会陆续给出。