背景
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中的关键代码如下所示:
.......... 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中加载进程的普遍流程。