Android app_process 进程创建

原创
03/28 13:51
阅读数 2.9K

一、app_process与Zygote

Android中,创建进程的方式有4种,其中app_process和Zygote有什么不同呢?

Android系统内核初始化完毕后,进入用户空间启动的第一个进程叫init 他是Android系统所有进程的祖先,这个进程启动后会初始化文件系统。Zygote主要负责如下任务

  • 负责启动java虚拟机
  • 加载很多需要预加载的类和系统资源
  • 负责启动systemServer ,systemServer 会启动android中的所有服务,基本上完成了上层框架的所有功能。
  • 负责初始化新进程,其实就是fork app的独立进程,比如启动一个application,那么zygote就负责为新启动的activityThread建立进程,并调用AppRuntime 、activityThread中的main,或进行初始化。

 

对于init来说zygote其实就是一个很普通的服务

service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks
 
service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks

我们从其中的调用逻辑发现,实际上zygote进程是通过app_process工具创建的,可见app_process在Android系统中的作用也很重要。

 

二、app_process

int main(int argc, const char* const argv[])
{
	// These are global variables in ProcessState.cpp
	mArgC = argc;
	mArgV = argv;
 
	mArgLen = 0;
	for (int i=0; i<argc; i++) {
		mArgLen += strlen(argv[i]) + 1;
	}
	mArgLen--;
	AppRuntime runtime;
	const char *arg;
	argv0 = argv[0];
	// Process command line arguments
	// ignore argv[0]
	argc--;
	argv++;
	// Everything up to '--' or first non '-' arg goes to the vm
	int i = runtime.addVmArguments(argc, argv);
	// Next arg is parent directory
	if (i < argc) {
		runtime.mParentDir = argv[i++];
	}
	// Next arg is startup classname or "--zygote"
	if (i < argc) {
		arg = argv[i++];
		if (0 == strcmp("--zygote", arg)) {
			bool startSystemServer = (i < argc) ?
				strcmp(argv[i], "--start-system-server") == 0 : false;
			setArgv0(argv0, "zygote");
			set_process_name("zygote");
			runtime.start("com.android.internal.os.ZygoteInit",
				startSystemServer);
		} else {
			set_process_name(argv0);
			runtime.mClassName = arg;
			// Remainder of args get passed to startup class main()
			runtime.mArgC = argc-i;
			runtime.mArgV = argv+i;
			LOGV("App process is starting with pid=%d, class=%s.\n",
				getpid(), runtime.getClassName());
			runtime.start();
		}
	} else {
		LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
		fprintf(stderr, "Error: no class name or --zygote supplied.\n");
		app_usage();
		return 10;
	}
}

app_process参数格式如下:

app_process [vm-options] [工作目录] [options] 类名 [类的main方法参数] [类的main方法参数] ....

参数解释如下

vm-options – VM 选项
work-dir –工作目录(如/system/bin,/data/app,/data/...) 
options –运行的参数 :
    –-zygote
    –-start-system-server
    –-application (api>=14)
    –-nice-name=nice_proc_name (api>=14) (只有非--zygoate模式下该选项才会生效)
[启动类名] –包含main方法的主类  (如com.android.internal.os.WrapperInit)
main-options –启动时候传递到main方法中的参数

一个完整的例子

app_process -Djava.class.path=/sdcard/classes.dex  /data/local/tmp --application --nice-name=helloservice com.apptest.bash.HelloWorld 1 2 a

一般来说,默认都是--application模式,加上这个参数和不加,都能创建进程,只是IO输入输出的位置不同

此外,我们还可以使用apk

app_process -Djava.class.path=/sdcard/app.apk /data/local com.apptest.bash.HelloWorld

关于几种模式的

  • 传入 –zygote 会启动 com.android.internal.os.ZygoteInit,否则启动 com.android.internal.os.RuntimeInit
  • –start-system-server 只在启动 zygote 时有效。
  • 在非 zygote 模式中,有无 –application 的选项的区别只是是否将 stdout 和 stderr 重定向到 AndroidPrintStream。
  • 只有在非 zygote 的情况下,–nice-name= 选项有效。

从几种模式我们知道,app_process都会走虚拟机相关初始化逻辑,因此,可以确定的是app_process启动的并不是普通的java程序

我们可以证明一下

public class HelloWorld {

    public static void main(String[]args){

        int num = 0;
        while (true) {
            System.out.println("["+android.os.Process.myPid()+" ]Hello, app_process  "+num);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            num++;
        }
    }
}

执行如下命令

app_process -Djava.class.path=/sdcard/app.apk  /data/local --nice-name=hellworld com.apptest.bash.HelloWorld

这个类中调用了android.os.Process.myPid(),运行结果如下,可以发现,Android相关api可以正常运行

[8062 ]Hello, app_process  0
[8062 ]Hello, app_process  1
[8062 ]Hello, app_process  2
[8062 ]Hello, app_process  3
[8062 ]Hello, app_process  4
[8062 ]Hello, app_process  5
[8062 ]Hello, app_process  6
[8062 ]Hello, app_process  7
[8062 ]Hello, app_process  8
[8062 ]Hello, app_process  9

可以明确知道,Android相关服务通过com.android.internal.os.RuntimeInit进行了初始化,这才是app_process真实启动类

三、app_process的父进程

我们知道,Android中app主进程和其他进程都是Zygote的子进程,并且相互隔离,那么app_process启动的进程又是怎么的呢?

对于用户而言,我们一般都是--application模式启动,影响进程父进程的主要因素和用户相关。

总结如下:

  • 在shell进程调用app_process,子进程的父进程为shell,用户id为root或者shell
  • 在用户app中调用app_process,子进程的父进程为init,用户id和app的用户一致。

在Android系统中,用户id一致,意味着进程之间的相关信息可以互相访问,包括杀进程,清理私有目录都会被允许。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部