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中的关键代码如下所示:

.......... 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中加载进程的普遍流程。

你可能感兴趣的:(android)