Android6.0 SystemServer进程

Posted ZhangJianIsAStark

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android6.0 SystemServer进程相关的知识,希望对你有一定的参考价值。

背景
SystemServer进程是zygote进程启动后,主动“分裂”的第一个进程。
它负责启动大量的android系统核心服务,其重要性不言而喻。一旦该进程崩溃,整个Android系统将重新启动。

版本
Android 6.0

一、启动SystemServer进程
在分析zygote进程时,我们知道当zygote进程进入到java世界后,在ZygoteInit.java中,将调用startSystemServer函数启动SystemServer进程,其关键代码是:

pid = Zygote.forkSystemServer(
	parsedArgs.uid, parsedArgs.gid,
	parsedArgs.gids,
	parsedArgs.debugFlags,
	null,
	parsedArgs.permittedCapabilities,
	parsedArgs.effectiveCapabilities);

其中,函数forkSystemServer函数定义于Zygote.java中。

public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) 
	..................
	int pid = nativeForkSystemServer(uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
	..................

容易看出,该函数通过调用native方法,完成实际的创建操作。
该Native方法定义于frameworks/base/core/jni/com_android_internal_os_Zygote.cpp中。
我们来看看对应的native函数。

static jint com_android_internal_os_Zygote_nativeForkSystemServer(
        JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
        jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,
        jlong effectiveCapabilities) 

  //进行实际的“分裂”工作
  pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                                      debug_flags, rlimits,
                                      permittedCapabilities, effectiveCapabilities,
                                      MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
                                      NULL, NULL);

  if (pid > 0) 
      //这里SystemServer进程已经创建出来,pid > 0 说明在父进程中
      //将子进程SystemServer的pid存在zygote进程的全局变量中
      gSystemServerPid = pid;

      int status;
      //小概率,SystemServer进程刚创建,就crash;此时需要重启zygote
      if (waitpid(pid, &status, WNOHANG) == pid) 
          ALOGE("System server process %d has died. Restarting Zygote!", pid);
          RuntimeAbort(env);
      
  
  return pid;

上述代码中,实际的“分裂”工作,由函数ForAndSpecializeCommon完成。

static pid_t ForkAndSpecializeCommon(......) 
  //注册信号监听器
  SetSigChldHandler();
  ..........
  pid_t pid = fork();
  if (pid == 0) 
	  //根据传入参数进行对应的处理,例如设置进程名,设置各种id(用户id,组id)等
	  ........
	  //反注册掉信号监听器
	  UnsetSigChldHandler();
	  ......
   else if () 
	  .......
  

  return pid;

从上面的代码可以看出,ForkAndSpecializeCommon最终是通过fork的方式,分裂出子进程。
这里需要关注一下的是,在zygote进程fork之前,调用SetSigChldHandler函数注册了一个子进程信号监听器。由于子进程共享父进程中的堆及栈信息,因此在子进程中也会有相应的信号处理器。
为了避免该信号监听器对子进程的影响,可以看到在子进程中进行了UnsetSigChldHandler的操作。

接下来,我们看看SetSigChldHandler进行了哪些操作。

static void SetSigChldHandler() 
  struct sigaction sa;
  memset(&sa, 0, sizeof(sa));
  sa.sa_handler = SigChldHandler;
  //该信号监听器关注子进程结束,对应的处理函数为SigChldHandler
  int err = sigaction(SIGCHLD, &sa, NULL);
  if (err < 0) 
    ALOGW("Error setting SIGCHLD handler: %s", strerror(errno));
  

从上面的代码可以看出,SetSigChldHandler函数将注册一个信号处理器,来监听子进程的死亡。当子进程死亡后,利用SigChldHandler进行操作。需要注意的是,zygote的信号监听器,关注的是zygote所有的子进程,而不只是SystemServer进程(每次创建一个新的进程时,zygote都会注册对应的监听器)。

SigChldHandler中的重要代码如下所示:

static void SigChldHandler(int /*signal_number*/) 
	.......
	//监听的pid为-1,表示监听任何子进程结束
	while ((pid = waitpid(-1, &status, WNOHANG)) > 0) 
		//通过status判断子进程结束的原因,并打印相应的log
		........
		//上文已经介绍过,gSystemServerPid中记录了SystemServer的pid
		if (pid == gSystemServerPid) 
		    ALOGE("Exit zygote because system server (%d) has terminated", pid);
		    //如果结束的子进程为SystemServer, zygote也将结束自己
		    kill(getpid(), SIGKILL);
	    
	
	.........

这里的问题是,所有zygote的子进程中,zygote只关心了SystemServer的死活。当其它子进程crash时,zygote只打印了log信息。

最后看看UnsetSigChldHandler函数:

// Sets the SIGCHLD handler back to default behavior in zygote children.
static void UnsetSigChldHandler() 
	struct sigaction sa;
	memset(&sa, 0, sizeof(sa));
	sa.sa_handler = SIG_DFL;

    int err = sigaction(SIGCHLD, &sa, NULL);
    if (err < 0) 
	    ALOGW("Error unsetting SIGCHLD handler: %s", strerror(errno));
    

zygote子进程的子进程crash后,应该还是zygote来处理,当然只是打印log信息。

二、SystemServer的主要工作
在分析zygote进程时,我们知道当ZygoteInit.java的startSystemServer函数,通过fork创建出SystemServer进程后,SystemServer进程调用handleSystemServerProcess函数,开始执行自己的工作。

........
if (pid == 0) 
	........
    handleSystemServerProcess(parsedArgs);

........

接下来,我们来看看handleSystemServerProcess函数的主要内容。

private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) 
throws ZygoteInit.MethodAndArgsCaller 
	//关闭从zygote进程那里继承下来server socket
	closeServerSocket();
	//设置SystemServer进程的一些属性
	........
	//加载SystemServer对应的文件
	final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
	if (systemServerClasspath != null) 
		performSystemServerDexOpt(systemServerClasspath);
	

	if (parsedArgs.invokeWith != null) 
		........
	 else 
		//利用systemServerClass对应的路径构建对应的ClassLoader
		ClassLoader cl = null;
		if (systemServerClasspath != null) 
			cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
			Thread.currentThread().setContextClassLoader(cl);
        

		//将剩余参数及classLoader递交给RuntimeInit的zygoteInit函数
		RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
	

从上面的代码可以看出,接下来的流程进入到RuntimeInit中的zygoteInit函数。zygoteInit函数将根据classLoader和参数,完成不同进程所需要的初始化工作(SystemServer进程与zygote的其它子进程均将使用zygoteInit函数)。

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller 
	..........
	commonInit();
	nativeZygoteInit();
	applicationInit(targetSdkVersion, argv, classLoader);

2.1 commonInit
commonInit主要进行一些常规初始化。由于自己是做通信的,所以比较关注的是创建UA(user agent):

private static final void commonInit() 
	.......
	/* Sets the default HTTP User-Agent used by HttpURLConnection.*/
	String userAgent = getDefaultUserAgent();
    System.setProperty("http.agent", userAgent);
    .........

User-Agent是Http协议中的一部分,属于头域的组成部分,是一种向访问网站提供你所使用的浏览器类型、操作系统、浏览器内核等信息的标识。通过这个标识,用户所访问的网站可以显示不同的排版,从而为用户提供更好的体验或者进行信息统计。

2.2 nativeZygoteInit
函数nativeZyoteInit实现在frameworks/base/core/jni/AndroidRuntime.cpp中,主要用于为Binder通信打下基础。

static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)

    gCurRuntime->onZygoteInit();

这里需要关注的是,SystemServer进程中的gCurRuntime指的是什么呢?

实际上在zygote进程启动时,在app_main.cpp的main函数中,创建出了AppRuntime:

int main(int argc, char* const argv[])

	........
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    ........

AppRuntime定义如下:

class AppRuntime : public AndroidRuntime

public:
    AppRuntime(char* argBlockStart, const size_t argBlockLength)
        : AndroidRuntime(argBlockStart, argBlockLength)
        , mClass(NULL)
    
    
    ...........

看看AppRuntime的父类AndroidRuntime:

AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
        mExitWithoutCleanup(false),
        mArgBlockStart(argBlockStart),
        mArgBlockLength(argBlockLength)

	.................
    assert(gCurRuntime == NULL);        // one per process
    gCurRuntime = this;

从代码可以看出,AndroidRuntime初始化时定义了gCurRuntime。gCurRuntime指向对象自身,也就是说gCurRuntime指向的是AppRuntime对象。

由于SystemServer进程由zygote进程fork出来,于是system server进程中也存在gCurRuntime对象,类型为AppRuntime。至此我们知道,Native函数中gCurRuntime->onZygoteInit将调用AppRuntime中的onZygoteInit。

virtual void onZygoteInit()

	sp<ProcessState> proc = ProcessState::self();
	ALOGV("App process: starting thread pool.\\n");
	proc->startThreadPool();

onZygoteInit的用途是启动一个线程,用于binder通信。这由将是一个沉重的话题,我们今后再分析。

2.3 applicationInit

private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller 
	//设置一些进程退出的处理策略,可用堆栈上限等
	.............
	invokeStaticMain(args.startClass, args.startArgs, classLoader);

我们来进一步看看invokeStaticMain函数的内容。

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller 
	//className为进行初始化工作的进程类名
	//在SystemServer初始化时,为com.android.server.SystemServer
	Class<?> cl;

	//下面就是通过反射得到对应类的main方法
	try 
		cl = Class.forName(className, true, classLoader);
     catch (ClassNotFoundException ex) 
		.......
	

	Method m;
	try 
		m = cl.getMethod("main", new Class[]  String[].class );
	 catch (NoSuchMethodException ex) 
		.....
	 catch (SecurityException ex) 
		.......
	

	int modifiers = m.getModifiers();
	if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) 
		......
	
	
	/*
	 * 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);

上述代码的最后抛出了一个异常。那么这个异常是在哪里捕获的呢?
实际上注释中已经给出了提示,在ZygoteInit.java的main函数中:

public static void main(String argv[]) 
	try 
		........
		if (startSystemServer) 
			startSystemServer(abiList, socketName);
		

		Log.i(TAG, "Accepting command socket connections");
		runSelectLoop(abiList);

		closeServerSocket();
	 catch (MethodAndArgsCaller caller) 
		//不论是startSystemServer拉起SystemServer进程
		//还是runSelectLoop收到请求,建立起进程
		//都会抛出MethodAndArgsCaller
		caller.run();
	 catch (RuntimeException ex) 
		Log.e(TAG, "Zygote died with exception", ex);
		closeServerSocket();
		throw ex;
	

从上述代码,可以看出捕获MethodAndArgsCaller异常后,调用了MethodAndArgsCaller的run方法:

public void run() 
	try 
		mMethod.invoke(null, new Object[]  mArgs );
	 catch (IllegalAccessException ex) 
		throw new RuntimeException(ex);
	 catch (InvocationTargetException ex) 
		......
    

从上面的代码可以看到,run方法单纯地利用反射调用对应类的main方法(此处是SystemServer.java的main方法)。

这里的问题是,为什么不在RuntimeInit.java的invokeStaticMain中,直接利用反射调用每个类的main方法?

参考invokeStaticMain中抛出异常的注释,我们可以推测出,这与linux的exec函数族的意图相似。
注意到,我们此时运行在SystemServer进程中。由于zygote进程fork的原因,SystemServer调用到invokeStaticMain时,整个堆栈实际上包含了大量zygote进程复制过来的调用信息。此时,我们通过抛异常捕获的方式,让位于栈底的ZygoteInit.main函数来进行处理,可起到刷新整个调用栈的作用(旧的无用调用出栈)。

exec 函数族就提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新的进程替换了。

2.4 SystemServer.java main

接下来就进入了SystemServer.java的main函数:

public static void main(String[] args) 
	//创建并运行,简单粗暴!
	new SystemServer().run();

我们来看看run方法中,进行了哪些重要操作。

private void run() 
	//设置一些属性
	........
	//确保主线程的优先级,并初始化SystemServer的looper。
	android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_FOREGROUND);
	android.os.Process.setCanSelfBackground(false);
	Looper.prepareMainLooper();

	//加载native层的库文件
	System.loadLibrary("android_servers");
	.........
	//创建出SystemServiceManager, 将用于创建和管理系统服务
	mSystemServiceManager = new SystemServiceManager(mSystemContext);
	LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);

	try 
		// 分种类启动不同的system service
		startBootstrapServices();
		startCoreServices();
		startOtherServices();
	 catch (Throwable ex) 
		........
	
	..........
	//启动looper,以处理到来的消息
	Looper.loop();
	throw new RuntimeException("Main thread loop unexpectedly exited");

三、其它进程的启动
最后这一部分,我们举例分析一下,其它的进程如何被zygote进程启动,与SystemServer进程做一个对比。

我们已经知道,zygote进程分裂出SystemServer进程后,就调用runSelectLoop函数等待并处理来自客户端的消息。
为了进一步理解这个过程,我们以启动Activity对应进程的过程举例。
在ActivityManagerService.java中,函数startProcessLocked中的关键代码如下所示:

..........
// Start the process.  It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
boolean isActivityProcess = (entryPoint == null);
//指定了className
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
..........................
Process.ProcessStartResult startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                    app.info.dataDir, entryPointArgs);
.........

接下来我们看看Process.java中的start函数:

public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int debugFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String[] zygoteArgs) 
	try 
		//processClass的值是“android.app.ActivityThread”
		//函数名很清楚,via zygote
		return startViaZygote(processClass, niceName, uid, gid, gids,
					debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, zygoteArgs);
     catch (ZygoteStartFailedEx ex) 
		.........
    
 

startViaZygote的主要工作如下面代码所示。

private static ProcessStartResult startViaZygote(....) 
	//准备参数,写入到argsForZygote
	........
	return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);

其中,openZygoteSocketIfNeeded的代码如下:

private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx 
	if (primaryZygoteState == null || primaryZygoteState.isClosed()) 
		try 
			//当前还没有可用的与zygote通信的socket,则创建一个
			primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
		 catch (IOException ioe) 
			throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
		
	

	if (primaryZygoteState.matches(abi)) 
		//如果已经有可用的socket,就使用该socket
		return primaryZygoteState;
	
	.................

我们稍微来看一下ZygoteState的connect函数定义,这个socket通信写的非常标准:

 public static ZygoteState connect(String socketAddress) throws IOException 
	DataInputStream zygoteInputStream = null;
	BufferedWriter zygoteWriter = null;
	//创建本地进程的socket
	final LocalSocket zygoteSocket = new LocalSocket();

	try 
		//连接zygote进程中的server socket
		zygoteSocket.connect(new LocalSocketAddress(socketAddress, LocalSocketAddress.Namespace.RESERVED));

		zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());

		//利用zygoteWriter包装socket的outputStream
		zygoteWriter = new BufferedWriter(new OutputStreamWriter( zygoteSocket.getOutputStream()), 256);
	 catch (IOException ex) 
		try 
			zygoteSocket.close();
		 catch (IOException ignore) 
		

		throw ex;
	
	.........

	return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter, Arrays.asList(abiListString.split(",")));

socket连接建立成功后,我们回头再看看函数zygoteSendArgsAndGetResult:

private static ProcessStartResult zygoteSendArgsAndGetResult(ZygoteState zygoteState, ArrayList<String> args) throws ZygoteStartFailedEx 
	try 
		//其实就是获取的socket的outputStream和inputStream
		final BufferedWriter writer = zygoteState.writer;
		final DataInputStream inputStream = zygoteState.inputStream;

		writer.write(Integer.toString(args.size()));
		writer.newLine();

		int sz = args.size();
		for (int i = 0; i < sz; i++) 
			String arg = args.get(i);
			if (arg.indexOf('\\n') >= 0) 
				 throw new ZygoteStartFailedEx("embedded newlines not allowed");
			
			writer.write(arg);
			writer.newLine();
		

		//利用socket将消息发往zygote
		writer.flush();

		ProcessStartResult result = new ProcessStartResult();
		//阻塞直到收到结果,pid大于0则说明进程启动成功
		result.pid = inputStream.readInt();
		if (result.pid < 0) 
			throw new ZygoteStartFailedEx("fork() failed");
        
		result.usingWrapper = inputStream.readBoolean();
		return result;
	 catch (IOException ex) 
		.......
	 

ActivityManagerService将请求发送给zygote进程后, 就轮到zygote进程处理消息了。通过分析zygote进程的启动流程,我们已经知道zygote进程收到请求后,将执行ZygoteConnection的runOnce函数。

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller 
	ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
	ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
	......
	for (int i = pollFds.length - 1; i >= 0; --i) 
		.........
		if (i == 0) 
			ZygoteConnection newPeer = acceptCommandPeer(abiList);
			peers.add(newPeer);
			fds.add(newPeer.getFileDesciptor());
		 else 
			//处理请求
			boolean done = peers.get(i).runOnce();
			if (done) 
				peers.remove(i);
				fds.remove(i);
			
		
	
    ............

接下来,我们看看函数runOnce的实际操作:

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller 
	//解析传入的参数
	........
	try 
		.......
		//与启动SystemServer进程一样,最终也会通过native函数fork,并配置进程的参数
		pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet, parsedArgs.appDataDir);
	  catch (ErrnoException ex) 
		.......   
	 catch (IllegalArgumentException ex) 
		....... 
	 catch (ZygoteSecurityException ex) 
		....... 
	

	try 
		if (pid == 0) 
			// in child
			IoUtils.closeQuietly(serverPipeFd);
			serverPipeFd = null;
			//子进程根据参数利用handleChildProc作进一步处理
			handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

			// should never get here, the child is expected to either
			// throw ZygoteInit.MethodAndArgsCaller or exec().
			return true;
		 else 
			// in parent...pid of < 0 means failure
			IoUtils.closeQuietly(childPipeFd);
			childPipeFd = null;
			//父进程进行一些后续操作,例如清理工作等
			return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
		
     finally 
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    

最后,我们看看handlehandleChildProc:

private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller 
    //关闭fork过来的zygote server socket
	closeSocket();
	ZygoteInit.closeServerSocket();
	//处理参数
	........
	if (parsedArgs.invokeWith != null) 
		.......
	 else 
		//完成进程的初始化,然后抛异常
		RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /* classLoader */);
    

从上面的代码可以看出,函数handleChildProc最终还是会调用Runtime的zygoteInit。
如同SystemServer进程一样,普通进程也会进行一些初始化,建立binder通信后,抛出异常,最终由ZygoteInit.java捕获异常,然后反射启动对应类的main函数(实际上是android.app.ActivityThread类的main函数)。

结束语
以上就是对SystemServer进程的初步分析,通过对比普通进程,我们可以找到Android中加载进程的普遍流程。

以上是关于Android6.0 SystemServer进程的主要内容,如果未能解决你的问题,请参考以下文章

Android系统启动-SystemServer上篇

Android6.0系统启动流程分析一:init进程

android6.0源码分析之Zygote进程分析

SystemServer进程

Android SystemServer启动流程源码解析

从源码角度看Android系统SystemServer进程启动过程