Android6.0 SystemServer进程

本文详细解析了Android 6.0中SystemServer进程的启动过程,包括从Zygote进程分裂、注册信号处理器、启动核心服务等方面。SystemServer进程在Android系统中的重要性,以及其主要工作内容,如初始化、Binder通信等。此外,还对比了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中加载进程的普遍流程。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值