System进程的启动流程第一部分

     承接上篇文章Zygote进程的启动流程,我们继续分析System进程的启动流程。

     Zygote进程在启动的过程中,除了会创建一个Dalvik虚拟机实例之外,还会将Java运行时库加载到进程中来,以及注册一些Android核心类的JNI方法来前面创建的Dalvik虚拟机实例中去。注意,一个应用程序进程被Zygote进程孵化出来的时候,不仅会获得Zygote进程中的Dalvik虚拟机实例拷贝,还会与Zygote一起共享Java运行时库,这完全得益于Linux内核的进程创建机制(fork)。这种Zygote孵化机制的优点是不仅可以快速地启动一个应用程序进程,还可以节省整体的内存消耗,缺点是会影响开机速度,毕竟Zygote是在开机过程中启动的。不过,总体来说,是利大于弊的,毕竟整个系统只有一个Zygote进程,而可能有无数个应用程序进程,而且我们不会经常去关闭手机,大多数情况下只是让它进入休眠状态。

     在ZygoteInit类的静态方法startSystemServer,代码如下:

public class ZygoteInit {
	......

	private static boolean startSystemServer()
			throws MethodAndArgsCaller, RuntimeException {
		/* Hardcoded command line to start the system server */
		String args[] = {
			"--setuid=1000",
			"--setgid=1000",
			"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003",
			"--capabilities=130104352,130104352",
			"--runtime-init",
			"--nice-name=system_server",
			"com.android.server.SystemServer",
		};
		ZygoteConnection.Arguments parsedArgs = null;

		int pid;

		try {
			parsedArgs = new ZygoteConnection.Arguments(args);

			......

			/* Request to fork the system server process */
			pid = Zygote.forkSystemServer(
				parsedArgs.uid, parsedArgs.gid,
				parsedArgs.gids, debugFlags, null,
				parsedArgs.permittedCapabilities,
				parsedArgs.effectiveCapabilities);//System进程uid为1000
		} catch (IllegalArgumentException ex) {
			......
		}

		/* For child process */
		if (pid == 0) {//子进程,System进程
			handleSystemServerProcess(parsedArgs);//System进程,后续再分析
		}

		return true;
	}
	
	......
}

     我们继续分析handleSystemServerProcess,代码如下:

private static void handleSystemServerProcess(
            ZygoteConnection.Arguments parsedArgs)
            throws ZygoteInit.MethodAndArgsCaller {

        closeServerSocket();

        /*
         * Pass the remaining arguments to SystemServer.
         * "--nice-name=system_server com.android.server.SystemServer"
         */
        RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
        /* should never reach here */
    }
    由于System进程复制了Zygote进程的地址空间,因此,它就会获得Zygote进程在启动过程中所创建的一个Socket。System进程不需要使用这个Socket,因此调用closeServerSocket来关闭它。接下来调用RuntimeInit类的静态成员函数zygoteInit来进一步启动System进程。

public class RuntimeInit {  
	......  

	public static final void zygoteInit(String[] argv)  
			throws ZygoteInit.MethodAndArgsCaller {  
		......  
  
		zygoteInitNative();  

		......  


		// Remaining arguments are passed to the start class's static main  

		String startClass = argv[curArg++];  
		String[] startArgs = new String[argv.length - curArg];  

		System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);  
		invokeStaticMain(startClass, startArgs);  
	}  

	......  
}
     首先调用RuntimeInit类的静态成员函数zygoteInitNative来启动一个Binder线程池,会调用一个JNI方法。

public static final native void zygoteInitNative();
     Runtime类的静态成员函数zygoteInitNative是一个JNI方法,它是由C++层的函数com_android_internal_os_RuntimeInit_zygoteInit来实现的,如下:

static AndroidRuntime* gCurRuntime = NULL;
......
static void com_android_internal_os_RuntimeInit_zygoteInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onZygoteInit();
}  
     gCurRuntime是一个全局变量,它是在AndroidRuntime类的构造函数中被初始化的,如下所示:

AndroidRuntime::AndroidRuntime()
{
    ......

    assert(gCurRuntime == NULL);        // one per process
    gCurRuntime = this;
}
     Zygote进程在启动时,会在进程中创建一个AppRuntime对象。由于AppRuntime类继承了AndroidRuntime类,因此,在创建一个AppRuntime对象时,会导致AndroidRuntime类的构造函数被调用。在调用的过程中,全局变量gCurRuntime就会被初始化,它指向的就是正在创建的AppRuntime对象。又由于每一个新创建的应用进程都复制了Zygote进程的地址空间,因此,在每个应用程序进程中,都会存在一个全局变量gCurRuntime。

     回到函数com_android_internal_os_RuntimeInit_zygoteInit,调用了全局变量gCurRuntime的成员函数onZygoteInit来启动一个Binder线程池。全局变量gCurRuntime指向的是一个AppRuntime对象,并且AppRuntime类重写了父类AndroidRuntime的成员函数onZygoteInit,因此,接下来实际上调用的是AppRuntime类的成员函数onZygoteInit。

virtual void onZygoteInit()
    {
        sp<ProcessState> proc = ProcessState::self();
        if (proc->supportsProcesses()) {
            LOGV("App process: starting thread pool.\n");
            proc->startThreadPool();
        }       
    }
    首先判断是否支持Binder进程间通信机制,如果支持,那么就调用当前应用程序进程中的ProcessState对象的成员函数startThreadPool来启动一个Binder线程池,以便使得当前应用程序可以通过Binder进程间通信机制和其他进程通信。

void ProcessState::startThreadPool()
{
    AutoMutex _l(mLock);
    if (!mThreadPoolStarted) {
        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }
}
     ProcessState类有一个成员变量mThreadPoolStarted,它的初始值等于false。在Android系统中,每一个支持Binder进程间通信机制的进程内部都有一个唯一的ProcessState对象。当这个ProcessState对象的成员函数startThreadPoll第一次被调用时,它就会在当前进程中启动一个Binder线程池,并且将它的成员变量mThreadPoolStarted的值设置为true,避免以后重复执行启动Binder线程池的操作。

void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) {
        int32_t s = android_atomic_add(1, &mThreadPoolSeq);
        char buf[32];
        sprintf(buf, "Binder Thread #%d", s);
        LOGV("Spawning new pooled thread, name=%s\n", buf);
        sp<Thread> t = new PoolThread(isMain);
        t->run(buf);
    }
}
    这里它会创建一个PoolThread线程类,然后执行它的run函数,最终就会执行PoolThread类的threadLoop函数了。

class PoolThread : public Thread
{
public:
    PoolThread(bool isMain)
        : mIsMain(isMain)
    {
    }

protected:
    virtual bool threadLoop()
    {
        IPCThreadState::self()->joinThreadPool(mIsMain);
        return false;
    }

    const bool mIsMain;
};
    有关 Native线程的创建过程,请参考Dalvik虚拟机进程和线程的创建过程分析

    

     返回到RuntimeInit类的静态方法zygoteInit,继续执行invokeStaticMain,代码如下:

private static void invokeStaticMain(String className, String[] argv)//className为com.android.server.SystemServer
            throws ZygoteInit.MethodAndArgsCaller {

        // We want to be fairly aggressive about heap utilization, to avoid
        // holding on to a lot of memory that isn't needed.
        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);

        Class<?> cl;

        try {
            cl = Class.forName(className);//首先将com.android.server.SystemServer类加载到当前进程中
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(
                    "Missing class when invoking static main " + className,
                    ex);
        }

        Method m;
        try {
            m = cl.getMethod("main", new Class[] { String[].class });//获取了它的静态函数main
        } catch (NoSuchMethodException ex) {
            throw new RuntimeException(
                    "Missing static main on " + className, ex);
        } catch (SecurityException ex) {
            throw new RuntimeException(
                    "Problem getting static main on " + className, ex);
        }

        int modifiers = m.getModifiers();
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
            throw new RuntimeException(
                    "Main method is not public and static on " + className);
        }

        /*
         * This throw gets caught in ZygoteInit.main(), which responds
         * by invoking the exception's run() method. This arrangement
         * clears up all the stack frames that were required in setting
         * up the process.
         */
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);//把这个Method对象封装在一个MethodAndArgsCaller对象中,并且将这个MethodAndArgsCaller对象作为一个异常对象抛出来给当前进程处理
    }
     我们知道System进程复制了Zygote进程的地址空间,因此,System进程的调用堆栈和Zygote进程的调用堆栈是一致的,从前面知道,Zygote进程最开始执行的是应用程序app_process的入口函数main,如下:

public class ZygoteInit {
	......

	public static void main(String argv[]) {
		try {
			......

			registerZygoteSocket();//创建一个Server端Socket,这个Server端Socket是用来等待Activity管理服务ActivityManagerService请求Zygote进程创建新的应用程序进程的<span style="white-space:pre">	</span>
			
			......

			......

			if (argv[1].equals("true")) {
				startSystemServer();//启动System进程,以便它可以将系统的关键服务启动起来
			} else if (!argv[1].equals("false")) {
				......
			}

			......

			if (ZYGOTE_FORK_MODE) {//false
				......
			} else {
				runSelectLoopMode();
			}

			......
		} catch (MethodAndArgsCaller caller) {
			caller.run();
		} catch (RuntimeException ex) {
			......
		}
	}

	......
}
    这个异常最后会被main函数里面的catch捕获,ZygoteInit类的静态成员函数main捕获了一个类型为MethodAndArgsCaller的异常之后,就会调用MethodAndArgsCaller类的成员run来进一步处理。

public class ZygoteInit {
	......

	public static class MethodAndArgsCaller extends Exception
			implements Runnable {
		/** method to call */
		private final Method mMethod;

		/** argument array */
		private final String[] mArgs;

		public MethodAndArgsCaller(Method method, String[] args) {
			mMethod = method;
			mArgs = args;
		}

		public void run() {
			try {
				mMethod.invoke(null, new Object[] { mArgs });//调用了com.android.server.SystemServer的main函数
			} catch (IllegalAccessException ex) {
				......
			} catch (InvocationTargetException ex) {
				......
			}
		}
	}

	......
}
     为什么要这么折腾呢?直接调用不行么,由于新创建的System进程一开始就需要在内部初始化运行时库,以及启动Binder线程池,因此com.android.server.SystemServer的main函数被调用时,System进程其实已经执行了相当多代码。为了使得新创建的System进程觉得它的入口函数就是com.android.server.SystemServer的main函数,系统不直接调用它,而是抛出一个异常回到ZygoteInit类的静态成员函数main中,然后再间接地调用它,这样就可以巧妙地利用Java语言的异常处理机制来清理它前面的调用堆栈了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值