首页 > 移动平台 > 详细

Android之Zygote启动详解

时间:2014-06-22 19:09:38      阅读:476      评论:0      收藏:0      [点我收藏+]

         我们知道Android系统是基于Linux内核的,在Linux系统中所有的进程都是init进程的子进程。Zygote也一样它是在系统启动的过程中由init进程创建的,在系统启动脚本init.rc中:

<span style="font-size:14px;">@init.rc

service zygote /syste/bin/app_process -Xzygote /system/bin -zygote --start-system-server
            class main
            socket zygote stream 666
            onrestart restart surfaceflinger
            ...
</span>

        关键字server告诉init进程创建一个名为zygote的进程,执行的的程序是/syste/bin/app_process,后面都是传递给这个进程的参数。下面的socket表示这个zygote进行需要一个名称为zygote的socket套接字资源,系统启动后在/dev/socket目录下可以看到相关的文件。

 

        zygote 服务进程也叫孵化进程,在Linux的用户空间进程app_process会做一些zygote进程启动的前期工作,如启动runtime运行时的环境等,接着调用runtime.start()来执行zygote服务。runtime.start()这个函数实际是类函数AndroidRuntime::start(),会创建并启动一个虚拟机实例来执行com.android.internal.os.ZygoteInit这个包的main函数。这个main函数会fork一个子进程来启动systemServer,父进程就作为真正的孵化器存在了,每当系统要求执行一个Android应用程序,Zygote就会接收到socket消息fork出一个子进程来执行该应用程序。 而每一个Android应用程序都运行在一个Dalvik虚拟机实例里,每一个虚拟机实例都是一个独立的进程空间。

 

@frameworks/base/cmds/app_process/app_main.cpp

<span style="font-size:14px;">int main(int argc, char* argv[])
{
	AppRuntime runtime;	// 这里AppRuntime是AndroidRuntime的子类,启动runtime运行时环境。
	...	// 获取参数
	/*
		argv[0] = "-Xzygote"
		argv[1] = "/system/bin"
		argv[2] = "--zygote"
		argv[3] = "--start-system-server"	
		startSystemServer = true
	*/
	int i = runtime.addVMArguments(argc. argv);	// 找到参数第一个不是以单个-开始的参数,这里是/system/bin
	runtime.mParentDir = argv[i++]	// 将目录保存到mParentDir变量中
	
	setArgsv0(argv0, "zygote")
	set_process_name("zygote");
	
	runtime.start("com.android.internal.os.zygoteInit", startSystemServer ? "start-system-server" : "");
}</span>

        这里主要就是调用runtime.start() 函数,我们重点看下runtime类型为AppRuntime,它继承于AndroidRuntime类。

@frameworks/base/cmds/app_process/app_main.cpp

<span style="font-size:14px;">class AppRuntime : public AndroidRuntime
{
public:
	AppRuntime() : mParentDir(NULL), mClassName(NULL), mClass(NULL), mArgc(0), mArgv(NULL)
	{}
	...
	const char* getClassName() const {}
	virtual void onVmCreated(JNIEnv* env) {}
	virtual void onStarted() {}
	virtual void onZygoteInit() {}
	virtual void onExit(int code)
	const char* mParentDir;
	const char* mClassName;
	jclass mClas;
	int mArgC;
	const char* const* mArgV;
};</span>


 

<span style="font-size:14px;">@frameworks/base/include/android_runtime/AndroidRuntime.h
@frameworks/base/core/jni/AndroidRuntime.cpp

/* static */ JavaVM* AndroidRuntime::mJavaVM = NULL;
void AndroidRuntime::start(const char* className, const char* options)
{
	...
	JNIEnv *env;

	startVm(&mJavaVM, &env);	// start the virtual machine
	
	onVmCreated(env);	
	
	startReg(env);			// Register android functions 
	
	// call className main
	char *slashClassName = toSlashClassName(className);
	jclass startClass = env->FindClass(slashClassName);
	jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;]V)");
	env->CallStaticVoidMethod(startClass, startMeth, strArray);
	free(slashClassName);
	...
}</span>


         这个start()函数主要做三件事:一是调用startVM()启动虚拟机;二是调用startReg()注册JNI方法;三是调用com.android.internal.os.ZygoteInit类的main函数

 

1) startVM 启动虚拟机

 

2) startReg 注册JNI方法

 

3)启动com.android.internal.os.ZygoteInit的main函数

@frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

<span style="font-size:14px;">public static void main(String argv[]) {
	try {
		SamplingProfilerIntegration.start();
		
		registerZygoteSocket();		// 注册socket
		preloadClasses();			// 加载资源
		preloadResources();
		
		SamplingProfilterIntegration.writeZygoteSnapshot();
		gc();
		if(argv[1].equals("start-system-server"))
			startSystemServer();	// fork一个新的进程system_server
		if(ZYGOTE_FORK_MODE)
			runForkMode();
		else
			runSelectLoopMode();	// Zygote进程进入无限循环,执行孵化工作
		closeServerSocket();
	} catch (MethodAndArgsCaller caller) {
		caller.run();
	}
}</span>

 

       这里也是主要做三件事情:一是调用registerZygoteSocket函数创建了一个socket套接字用来和ActivityManagerService通信;二是调用startSystemServer函数启动SystemServer组件;三是调用runSelectLoopMode函数进程一个无限循环在前面创建的套接字socket上等待ActivityManagerService请求创建新的应用程序进程。
1)registerZygoteSocket

fork()创建子进程,父进程返回true。子进程执行RuntimeInit.zygoteInit。

@frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

<span style="font-size:14px;">public class ZygoteInit {
	...
	private static LocalServerSocket sServerSocket;
	private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";
	
	private static void registerZygoteSocket() {
		if(sServerSocket == NULL) {
			int fileDesc;
			String env = System.getenv(ANDROID_SOCKET_ENV);		// 获取环境变量
			fileDesc = Integer.parseInt(env);
			sServerSocket = new LocalServerSocket(createFileDescriptor(fileDesc));
		}
	}
}</span>

          

         这里通过System.getenv()获取环境变量ANDROID_SOCKET_ENV的值,通过这个文件描述符表示/dev/socket/zygote。那么这个环境变量又是谁设置的呢?在前面分析的解释执行系统启动脚本init.rc的init.c文件里面有个service_start()函数就是用来分析zygote并创建和设置相应socket的。

<span style="font-size:14px;">void service_start(struct service *svc, const char* dynamic_args) 
{
	...
	pid = fork();
	if ( pid == 0) 
	{
		struct socketinfo *si;
		...
		for (si = svc->sockets; si; si = si->next) {
			int socket_type = (!strcmp(si->type, "stream") ? SOCK_STREAM : 
				(!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
			int s = create_socket(si->name, socket_type, si->perm, si->uid, si->gid);
			publish_socket(si->name, s);
		}
	}
	...
}
#define ANDROID_SOCKET_ENV_PREFIX  "ANDROID_SOCKET_"
#define ANDROID_SOCKET_DIR "/dev/socket"
static void publish_socket(const char *name, int fd)
{
	char key[64] = ANDROID_SOCKET_ENV_PREFIX;
	char val[64];
	
	strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) -1, name, sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
	snprintf(val, sizeof(val), "%d", fd);
	add_environment(key, val);	// ANDROID_SOCKET_zygote = val
	fcntl(fd, F_SETFD, 0);
}</span>


       这里每一个service命令都会使init进程调用fork函数创建一个新的进程来分析里面的socket选项,然后调用create_socket()函数在/dev/socket目录下创建一个设备文件,然后获得一个文件描述符并通过publish_socket()写入到环境变量中去。这样就把zygote这个socket的文件描述符写到ANDROID_SOCKET_zygote里面去了,这里创建socket文件描述符的create_socket()函数,最后通过调用execve(svc->args[0], (char**)arg_ptrs, (char**)ENV)去执行zygote的可执行程序,并将环境变量ENV参数传递过去了。所以ZygoteInit.registerZygoteSocket()函数就可以直接从环境变量中取出这个文件描述符来使用。如果其他进程需要打开这个/dev/socket/zygote 文件来和Zygote进程通信就需要通过文件名字连接LocalServerSocket。

2)startSystemServer

 @frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

<span style="font-size:14px;">private static boolean startSystemServer() {
	String args[] = {
		"--setuid=1000", 
		"--setgid=1000", 
		"--setgroups=1001,1002,1003,1004,1005,1006...",
		"--capabilities=13010432,130104352",
		"--runtime-init",
		"--nice-name=system_server",
		"com.android.server.SystemServer",
	};
	ZygoteConnection.Arguments parsedArgs = null;
	parsedArgs = new ZygoteConnection.Arguments(args);
	ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
	ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
	int pid = Zygote.forkSystemServer(
		parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
		parsedArgs.debugFlags, null, parsedArgs.permittedCapabilities,
		parsedArgs.effectiveCapabilities));
	if (pid == 0) {	// 子进程
		handleSystemServerProcess(parsedArgs);
	}
	return true;	// 父进程直接返回true
}
</span>

         这里Zygote进程通过调用Zygote.forkSystemServer()函数创建一个新的进程来启动SystemServer组件。

<span style="font-size:14px;">public class ZygoteInit {
	....
	private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
		closeServerSocket();	// 子进程不需要zygote套接字,直接关闭
	
		FileUtils.setUMask(FileUtils.S_IRWXG | FileUtils.S_IRWXO);
		...
		RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
	}
}</span>
<span style="font-size:14px;">public class RuntimeInit {
	...
	
	public static final void zygoteInit(int targetSdkVersion, String[] argv) {
		redirectLogStreams();
		commonInit();
		zygoteInitNative();			// 是一个native函数,主要完成Binder通信机制的初始化
		applicationInit(targetSdkVersion, argv);
	}
	public static final native void zygoteInitNative();
	
	private static void applicationInit(int targetSdkVersion, String[] argv) {
		VMRuntime.getRuntime().setTargetHeapUtilizatoin(0.75f);
		VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
		final Arguments args;
		args = new Arguments(argv);
		invokeStaticMain(args.startClass, args.startArgs);
	}
	// 这个 className = "com.android.server.SystemServer"
	private static void invokeStaticMain(String className, String[] argv) {
		Class<?> cl;
		cl = Class.forName(className);
		Method m;
		m = cl.getMethod("main", new Class[] {String[].class});
		...
		throw new ZygoteInit.MethodAndArgsCaller(m, argv);
	}
}</span>

 

       这个RuntimeInit.ZygoteInit()函数主要执行两个操作:一是调用zygoteInitNative来执行一个Binder进程间通信机制的初始化工作;二是调用com.android.server.SystemServer类的main函数。

(1) zygoteInitNative: 

<span style="font-size:14px;">@frameworks/base/core/jni/AndroidRuntime.cpp

static JNINativeMethod gMethods[] = { 
     ....
     { "zygoteInitNative", "()V", (void*) com_android_internal_os_RuntimeInit_zygoteInit },
     ....
 };

static void com_android_internal_os_RuntimeInit_zygoteInit(JNIEnv* env, jobject clazz)
{
       gCurRuntime->onZygoteInit();         // 就是启动Binder通信
}

</span>
<span style="font-size:14px;">virtual void onZygoteInit()
{
	sp<ProcessState> proc = ProcessState::self();	// 每个进程一份ProcessState对象,打开Binder驱动
	if(proc->supportsProcess()){
		proc->startThreadPool();	// 启动一个线程用于Binder通信
	}
}</span>


 

(2) SystemServer.main :

@frameworks/base/services/java/com/android/server/SystemServer.java

<span style="font-size:14px;">public class SystemServer {
	native public static void init1(Strig[] args);
	
	public static void main(String[] args) {
		....
		VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
		System.loadLibrary("android_servers");
		init1(args);
	}
	
	public static final void init2() {
		Thread thr = new ServerThread();
		thr.setName("android.server.ServerThread");
		thr.start();
	}
}
<span style="color:#006600;">@frameworks/base/services/jni/com_android_server_SystemServer.cpp</span></span>
<span style="font-size:14px;">static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
{
	system_init();
}
status_t system_init()
{
	sp<ProcessState> proc(ProcessState::self());
	sp<IServiceManager> sm = defaultServiceManager();
	...
	AndroidRuntime* runtime = AndroidRuntime::getRuntime();
	JNIEnv* env = rungime->getJNIEnv();
	jclass clazz = env->FindClass("com/android/server/SystemServer");
	jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V");
	env->CallStaticVoidMethod(clazz, methodId);
	
	ProcessState::self()->startThreadPool();
	IPCThreadState::self()->joinThreadPool();
	return NO_ERROR;
}</span>


       这个SystemServer的main()函数首先会调用JNI方法init1,init1()会调用SystemServer的init2,在init2里面创建一个ServerThread线程执行一些系统关键服务的启动操作。

<span style="font-size:14px;">class ServerThread extends Thread {
	...
	public void run() {
		Looper.prepare();
		// Critical services ...
		ServiceManager.addService(Context.POWER_SERVICE, new PoperManagerService());
		ActivityManagerService.main();
		PackageManagerService.main(context);
		...
	}
}</span>

        到现在为止,zygote已经fork()子进程完成了SystemServer组件的初始化启动操作,回到zygote.main()里面调用runSelectLoopMode()进入一个循环再前面创建的socket接口上等待ActivityManagerService请求创建新的应用程序。

3)runSelectLoopMode

 

<span style="font-size:14px;">public class ZygoteInit {
	....
	private static void runSelectLoopMode() throws MethodAndArgsCaller {
		ArrayList<FileDescriptor> fds = new ArrayList();
		ArrayList<ZygoteConnection> peers = new ArrayList();
		FileDescriptor[] fdArray = new FileDescriptor[4];
		
		fds.add(sServerSocket.getFileDescriptor());
		peers.add(NULL);
		int loopCount = GC_LOOP_COUNT;	// 10
		while(true) {
			fdArray = fds.toArray(fdArray);
			index = selectReadble(fdArray);		// 类似Linux下的select轮询,native 函数
			if(index < 0) {
				...	
			} else if(index == 0) {				// 表示有客户端连接上
				ZygoteConnection newPeer = acceptCommandPeer();
				peers.add(newPeer);
				fds.add(newPeer.getFileDescriptor());
			} else {							// 客户端发送了请求过来,交给ZygoteConnection的runOnce()函数完成
				boolean done = peers.get(index).runOnce();
				if(done) {
					peers.remove(index);
					fds.remove(index);
				}
			}
		}
	}
	
	private static ZygoteConnection acceptCommandPeer() {
		...
		return new ZygoteConnection(sServerSocket.accept());
	}
}</span>

 

        这里while(true)循环里面调用selectReadble(),这是一个native函数,类似select使用多路复用I/O模型。当返回0的时候表示有客户端连接上,ZygoteConnection表示Zygote的一个客户端,每当客户端连接上的时候acceptCommandPeer()返回一个ZygoteConnection对象,ZygoteConnection里面保存着accpet()返回的LocalSocket对象。然后将相应的文件描述符添加到fds里面,下次再对其调用selelct轮询。当返回值大于0的时候表示有客户端发过来的数据请求,交给ZygoteConnection对象的runOnce()函数处理。

        selectReadable()函数对应native函数为:com_android_internal_os_ZygoteInit_SelectReadable()

static jint com_android_internal_os_ZygoteInit_selectReadable (
        JNIEnv *env, jobject clazz, jobjectArray fds)
{
    if (fds == NULL) {
        jniThrowNullPointerException(env, "fds == null");
        return -1;
    }

    jsize length = env->GetArrayLength(fds);
    fd_set fdset;

    if (env->ExceptionOccurred() != NULL) {
        return -1;
    }

    FD_ZERO(&fdset);

    int nfds = 0;
    for (jsize i = 0; i < length; i++) {
        jobject fdObj = env->GetObjectArrayElement(fds, i);
        if  (env->ExceptionOccurred() != NULL) {
            return -1;
        }
        if (fdObj == NULL) {
            continue;
        }
        int fd = jniGetFDFromFileDescriptor(env, fdObj);
        if  (env->ExceptionOccurred() != NULL) {
            return -1;
        }

        FD_SET(fd, &fdset);

        if (fd >= nfds) {
            nfds = fd + 1;
        }
    }

    int err;
    do {
        err = select (nfds, &fdset, NULL, NULL, NULL);
    } while (err < 0 && errno == EINTR);

    if (err < 0) {
        jniThrowIOException(env, errno);
        return -1;
    }

    for (jsize i = 0; i < length; i++) {
        jobject fdObj = env->GetObjectArrayElement(fds, i);
        if  (env->ExceptionOccurred() != NULL) {
            return -1;
        }
        if (fdObj == NULL) {
            continue;
        }
        int fd = jniGetFDFromFileDescriptor(env, fdObj);
        if  (env->ExceptionOccurred() != NULL) {
            return -1;
        }
        if (FD_ISSET(fd, &fdset)) {
            return (jint)i;
        }
    }
    return -1;
}

 

Android之Zygote启动详解,布布扣,bubuko.com

Android之Zygote启动详解

原文:http://blog.csdn.net/llping2011/article/details/9631755

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!