Android系统关键服务的启动流程简述

前言

  每个Android开发者都知道Android系统从kernel、hal、native c\c++ Library、framwork、application五层经典框架,但是要从头到尾说清楚AMS、WMS这些服务是怎么启动的?怎么能让application层使用还是需要一定基础的,下面我们来共同学习下Android系统这座参天大厦是如何架构其关键服务的。

一、Android系统的第一个进程-----init进程

  Android设备的启动必会经过三个过程:BootLoader、kernel、Android系统服务,本质上来说Android系统就是在Linux系统这个kernel内核层运行了各种各样的系统进程服务,而init进程就是所有这些进程的第一代老祖宗。

init进程的pid=0,由init.rc引导脚本来构建系统的初始体系,Android的重要服务进程多数是由这个init.rc引导脚本设置并启动的(如需自定义一个开机自启动的应用进程,就可以在这个脚本中仿照来设置),init.rc脚本语法可以跳转查看小例子

  对于Android系统来说关键的系统服务进程莫过于:Zygote、ServiceManager、SysteMserver,很显然这些系统服务都会在init进程中被启动,zygote进程是首先被加载的进程,从(system/core/rootdir/init.rc)可以看到,import /init.${ro.zygote}.rc,由于现在的设备有32位和64位因此需要根据不同的芯片架构来加载zygote。这里拿了32位的例子,不影响逻辑

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart vendor.hwcomposer-2-3
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart accanim
    onrestart restart wificond
    onrestart restart vendor.servicetracker-1-1
    writepid /dev/cpuset/foreground/tasks

二、孵化其他进程的进程-----zygote进程

  对于zygote进程,第一印象就是其他的应用和系统进程是由zygote进程来fork,那么它是怎么启动的?从init脚本看得出来,其源码在/system/bin/app_process,来看main函数

//framworks/base/cmds/app_process/App_main.cpp
int main(int argc, char* const argv[])
{...
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    ....
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i;  // Skip unused "parent dir" argument.
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {//set1、当前进程是否用于承载zygote
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } 

这个函数用于解析init脚本启动service时传递的参数,具体如下:

1、–zygote:表示当前进程用于承载zygote;
2、–start-system-server:是否需要启动SystemServer;
3、–application:启动进入独立的程序模式;
4、–nice-name:进程 “别名”

这里需要注意一点:对于非zygote的情况:上述参数的末尾会跟上main class名称,而后的其他参数则属于这个class的主函数参数;而对于zygote的情况,所有参数都作为它的主函数入参使用!
对于init脚本来说,参数中zygote和start-system-server都有,这时会由runtime先启动VM(Java虚拟机)来执行(framworks/base/core/jni/androidruntime.cpp)start()函数,最后会启动framworks/base/core/java/com/java/android/internal/os/zygoteInit.java,执行main函数

    @UnsupportedAppUsage
    public static void main(String argv[]) {
    ...
     try {
     boolean startSystemServer = false;
            String zygoteSocketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }
            final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
            Zygote.initNativeState(isPrimaryZygote);//新版本修改了实现,我理解这就是老版本中的registerZygoteSocket(zygoteSocketName );
        zygoteServer = new ZygoteServer(isPrimaryZygote);
            if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);//fork新进程用来承载系统服务的运行
                // child (system_server) process.
                if (r != null) {
                    r.run();
                    return;
                }
            }
            // The select loop returns early in the child process after a fork and
            // loops forever in the zygote.
            caller = zygoteServer.runSelectLoop(abiList);//set 1
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket();
            }
        }
   }       

这个函数主要作用是:

1、注册一个socket,需要创建用户进程时与zygote实现进程间通信
2、fork一个SystemServer进程,用来承载系统服务,当启动SystemServer进程后,app_process服务就专注的去做zygote这个进程孵化器的角色。

1、 这里分成了两步,我们先来看看1中的socket是怎么实现的?

caller = zygoteServer.runSelectLoop(abiList);
/** framworks/base/core/java//com/android/internal/os/ZygoteServer.java*/
//构造函数就创建了要使用的socket
ZygoteServer(boolean isPrimaryZygote) {
        mUsapPoolEventFD = Zygote.getUsapPoolEventFD();

        if (isPrimaryZygote) {
            mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
            mUsapPoolSocket =
                    Zygote.createManagedSocketFromInitSocket(
                            Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
        } else {
            mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);
            mUsapPoolSocket =
                    Zygote.createManagedSocketFromInitSocket(
                            Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
        }

        fetchUsapPoolPolicyProps();

        mUsapPoolSupported = true;
    }

Runnable runSelectLoop(String abiList) {
...
/**这里有个死循环去取socket数据,源码太长限于篇幅只截取片段,socket就是在这里处理,pollIndex = 0,
说明有了新的连接请求,此时需要 acceptCommandPeer接受来自客户端的连接,
产生一个新的zygoteConnection,然后分别更新peers和fd,*/
    while (--pollIndex >= 0) {
                if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
                    continue;
                }

                if (pollIndex == 0) {
                    // Zygote server socket

                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    socketFDs.add(newPeer.getFileDescriptor());

                } else if (pollIndex < usapPoolEventFDIndex) {
                    // Session socket accepted from the Zygote server socket
                    //当大于0,说明已经建立连接的socket中有来自客户端的数据需要处理,processOneCommand
                    try {
                        ZygoteConnection connection = peers.get(pollIndex);
                        final Runnable command = connection.processOneCommand(this);
    }
}

socket连接部分分析完成,转到ZygoteConnection.processOneCommand中,查看zygote如何处理socket客户端发来的新消息(例如AMS需要新启动一个APP应用)

/** framworks/base/core/java//com/android/internal/os/ZygoteConnection.java*/
Runnable processOneCommand(ZygoteServer zygoteServer) {
  ...
  pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
                parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
                parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
                parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion);

        try {
            if (pid == 0) {
                // in child
                zygoteServer.setForkChild();

                zygoteServer.closeServerSocket();
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;

                return handleChildProc(parsedArgs, descriptors, childPipeFd,
                        parsedArgs.mStartChildZygote);
            } else {
                // In the parent. A pid < 0 indicates a failure and will be handled in
                // handleParentProc.
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                handleParentProc(pid, descriptors, serverPipeFd);
                return null;
            }
  
}

这函数很长,我们主要关注两个方面:
1、创建承载应用程序的新进程,这个可以理解,Android系统上的进程都是沙盒进程,彼此隔离,zygote需要为每个新启动的应用生成独立的进程,但这里并没有直接用fork,而是使用了forkAndSpecialize,新进程中一定是运行应用程序自身代码,这部分逻辑是在(pid = 0;是child进程,handleChildProc函数中运行child进程本身的代码)这里处理的;
2、pid !=0;是parent进程,handleParentProc函数执行父进程的一些扫尾工作、child进程加入进程组、关闭文件等
Specialize字母意思是“专门化”,可以理解为zygote在“孵化”的过程中也要把它转变为Android的应用程序目标,进入forkAndSpecialize来看fork新进程的详细步骤:

/** framworks/base/core/java//com/android/internal/os/Zygote.java*/
    public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
            int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
            int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
            int targetSdkVersion) {
        ZygoteHooks.preFork();//set.1
         int pid = nativeForkAndSpecialize(
                uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                fdsToIgnore, startChildZygote, instructionSet, appDataDir);//set.2
        ...
        ZygoteHooks.postForkCommon(); //set.3
    }

这个函数我们能看到主要是三个阶段:
1、preFork(),限于篇幅不做深入研究,这里直接给出结论,感兴趣的读者可以自行追踪代码,在(art/runtime/native/dalvik_system_ZygoteHooks.cc)中ZygoteHooks_nativePreFork()函数会调用runtime->PreZygoteFork(),而它又会调用Heap::PreZygoteFork(),从而完成堆空间的初始化
2、nativeForkAndSpecialize是一个native函数,具体在(com_android_internal_os_Zygote_nativeForkAndSpecialize,后者又调用ForkAndSpecializeCommon函数),在这里真正的fork()了一个进程,
3、postForkCommon(),一些进程孵化后的处理,到目前为止,还是没有执行到应用程序相关的业务,这部分工作实际是由(framworks/base/core/java//com/android/internal/os/ZygoteConnection.java)handleChildProc函数来执行的,来看看详细代码:

/** framworks/base/core/java//com/android/internal/os/ZygoteConnection.java*/
private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors,
            FileDescriptor pipeFd, boolean isZygote) {
            if (parsedArgs.mNiceName != null) {
            Process.setArgV0(parsedArgs.mNiceName);//set.1 class类名,重要!!!
            }
            if (parsedArgs.mInvokeWith != null) {
            //invoke-with会抛异常 IllegalStateException("WrapperInit.execApplication 
            unexpectedly returned")
        } else {
            if (!isZygote) {
                return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                        parsedArgs.mRemainingArgs, null /* classLoader */);
            } else {
                return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
                        parsedArgs.mRemainingArgs, null /* 正常会走到这里来 */);
            }
        }
        }
static final Runnable childZygoteInit(
            int targetSdkVersion, String[] argv, ClassLoader classLoader) {
        RuntimeInit.Arguments args = new RuntimeInit.Arguments(argv);
        return RuntimeInit.findStaticMain(args.startClass, args.startArgs, classLoader);//会执行到这里
    }

     这个函数追踪起来代码不少,本质上它的作用就是:找到并执行应用程序的入口函数(根据经验入口函数都是main(),)我们联想一下,APP的入口函数是什么?
    我们能看到最后执行的地方是findStaticMain,确实是执行main函数,那么是哪个类的main函数,重点就来了,set.1中的ClassName至关重要,它是什么,就会启动谁的main(),这里其实要对应用程序的启动有全面认知,穿插AMS服务的业务逻辑才能理清,我们先直接给出结论,
    当一个新的应用程序需要启动的时候,会使用AMS来新建任务,而AMS在启动一个应用时就是调用了Zygote来孵化应用进程,在AMS中有个函数(startProcessLocked)会调用Process.start(第一个参数entryPoint),而这第一个参数:就是我们在handleChildProc中看到的ClassName,问题转变成AMS中entryPoint是什么?

entryPoint = “android.app.ActivityThread”;

至此真相大白,绕了一大圈子,zygote体系中handleChildProc函数会调用ActivityThread类的main();,此时应用程序将被真正启动,这就是zygote进程孵化新应用进程的逻辑。

2、现在来看zygote如何拉起系统关键服务进程的

还记得framworks/base/core/java/com/java/android/internal/os/zygoteInit.java的main函数吗?它的一个作业是使用socket来响应socket客户端的消息任务,另一个就是forkSystemServer函数,它会孵化出一个子进程,在pid = 0的时候调用handleSystemServerProcess函数,后者继续转进handleSystemServerProcess,最后进入ZygoteInit.zygoteInit()函数:

/**framworks/base/core/java/com/java/android/internal/os/zygoteInit.java*/
    public static final Runnable zygoteInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
        RuntimeInit.commonInit();
        ZygoteInit.nativeZygoteInit();
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

这里分为三部分:
1、commonInit(),通用部分的初始化,包括设置默认的uncaught exception handler(对应RuntimeInit中的UncaughtHandler类),为HttpURLConnection准备默认的配置等待
2、nativeZygoteInit(),本地初始化函数
3、applicationInit这个函数实际上就是去调用com.android.server.SystemServer类的main函数,
至此,程序出现两个分支,一个是在本地native层初始化SystemServer系统服务,一个是Java层的服务的启动,

native层本地初始化函数
当我们调用nativeZygoteInit,实际上执行了com_android_internal_os_RuntimeInit_nativeZygoteInit@AndroidRuntime.cpp,而AndroidRuntime我 们应该能猜测到是个父类,,真正的实现是在app_main.cpp中的AppRuntime,当我们新建AppRuntime时,父类AndroidRuntime的构造函数就会调用,且前者会开启Binder线程池以保证其他进程可以争取访问到Zygote提供的服务。这样Java层、SystemServer、app process就关联起来了

Java层系统服务的启动
applicationInit这个函数实际上就是去调用com.android.server.SystemServer类的main函数,而真正起作用的是SystemServer().run(),这里才是真实实现服务的地方,这里开启的一系列的系统核心服务:install、AMS、PMS、DMS等等,有一个点需要注意,SystemServer分为三类:
1、bootstrap service代表系统最核心的那部分服务,因为它们相互纠缠调用,因此必须一起来管理启动
2、core services 优先级略低,LED和背光管理器、电池电量管理器、应用程序使用管理器等
3、other services 优先级最低,数量最多,USBService、AudioServices等等

最后SystemServer,通过Looper.loop()进入死循环,并依托onZygoteInit中启动的Binder服务接受和处理外界请求,Android系统终于启动起来了

最后我们思考一个问题:Android中跨进程通信基本上都用到了Binder来处理,为什么在zygote孵化新的应用程序进程时,使用了socket来处理?

原因:
1、在zygote进程启动的时候,ServiceManager还未加载启动,因此无法使用Binder,即便将ServiceManager调整到第一个去启动,也无法保证zygote进程使用时,Binder一定就初始化完成,还得额外去做进程间同步;
2、zygote进程去孵化新应用进程时,需要在单线程的环境下使用,否则有死锁的可能性,而Binder是多线程环境,要使用也会造成额外的同步操作,因此干脆就是要socket来通信,彻底杜绝这些问题。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值