• 安卓启动相关以及架构设计相关


    安卓启动相关以及架构设计相关

           我们知道安卓大多数是服务等的启动是伴随着init进程启动一起启动,这个init进程类似于linux的init,进程pid为1。

           读过安卓源代码的人都应该非常熟悉init会读取init.rc和init.xxx.rc等,想必也读取过关于rc的相关readme。文档中介绍了Actions、Service、Command、Options。当中我仅仅摘取Service的一段原文介绍(此service非framework层的service,安卓把每一个由init执行的程序或者进程叫做服务,):

    Services

    ----------------------------------------------------------------------------------------------------------------

     Services are programs which init launches and(optionally) restarts when they exit. Services take the form of:

    service<name> <pathname> [ <argument> ]* <option>

       <option>

       ...

    Options

    ----------------------------------------------------------------------------------------------------------------

           介绍的非常明了,服务是init执行起来的程序或者可选地重新启动当它们退出的时候。服务格式例如以下:

           service <name> <pathname> [<argument> ]*

       <option>

       <option>

       ...

           Options当中option是选项

    在init中service结构体(仅仅显示重要部分):

    struct service {

            /* list of all services */

        struct listnode slist;服务链表,内核结构应该是双向链表  

        const char *name;服务名称

        const char *classname;服务相应的class类

        unsigned flags;

        pid_t pid;进程id

        uid_t uid;用户uid

        gid_t gid;组id

        char *seclabel;

        struct socketinfo *sockets;

        struct svcenvinfo *envvars;

        struct action onrestart;  /* Actions to execute on restart. */

    };

    好我们如今理解了服务,那在看看init.rc中包括的一个我们比較关注的服务(也算一个样例):

    service zygote/system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

     socket zygote 666

    启动一个名字为zygote的服务,它的路径名为/system/bin/app_process,參数为

    -Xzygote /system/bin--zygote --start-system-server,选项为socket zygote 666(打开socket)

    // Everything upto '--' or first non '-' arg goes to the vm这句摘自app_main.cpp

    这句是对參数-Xzygote /system/bin --zygote的一个非常好的诠释,-Xzygote是传递给vm的參数,而--zygote --start-system-server是传递给/system/bin的參数,意思是启动system_server,其父进程是zygote。

           zygote作为一个service底层通过对应的alloc和fork实现。

    用adb连接我自己的htc设备,然后ps显示zygote和system_server进程例如以下:






    从上图看到system_server的ppid为1527,zygote的pid为1527而ppid为1,得出zygote是由init进程fork出来的,而system_server由zygote进程fork出来的。

    Service启动的四种模式

             Zygote、SystemServer、Application、Tool

    全部这一切构成了安卓系统的服务,在init启动时会都被启动起来。

    从Zygote開始

    zygote代码集合

             查看过源代码的人能够了解到,zygote重要的相关代码包括例如以下:

    framework/base/cmds/app_main.cpp

    fremework/base/core/java/com/android/internal/os/ZygoteInit.java

    fremework/base/core/java/com/android/internal/os/ZygoteConnection.java

    libcore/dalvik/java/dalvik/system/Zygote.java

    dalvik/vm/native/ dalvik_system_Zygote.cpp

    frameworks/base/core/jni/com_android_internal_os_ZygoteInit.cpp

    当然zygote相关代码比显示的要多,可是上面这些已经足够你了解zygote了。

             如今我们来解说一下zygote究竟做了什么,当然这些解说的根据是上面讲到的相关zygote源代码。可是我不会详细列出流程出自哪个文件,由于这样讲起来比較费力气,所以我这里仅仅是解说流程逻辑。

    app_process创造了zygote

           能够从上面的init.rc和相关Readme介绍得到,zygote是由/system/app_process这个bin加一些參数创造出来的,所以你不用在纠结什么zygote和app_process关系。

           另外一方面init进程fork出来了zygote进程,而zygote进程又相继孵化出来了system_server进程等其它进程。

           那是不是能够理解app_process就是init进程呢?这个问题我用一个样例回答你。我们从7岁開始上学到20多岁毕业,这段时间中我们经历了小学九年义务教育,经历了高中三年教育,经历了大学四年教育。然后我问你,你读高一,那么这个高一能代表你的全部学习经历吗?学习就好比init进程,我们学习经历的小学中学高中大学,就好比init一点一点一步一步做的事情,那么通过一个可运行bin app_process启动zygote也是当中之中的一个的工作,当然init的工作可远不止如此。相同app_process也不仅仅创造了zygote,还做了其它事情。

           看一段代码(摘自app_main.cpp):

    classAppRuntime:publicAndroidRuntime{……}

    AppRuntimeruntime;

    if (zygote) {

            runtime.start("com.android.internal.os.ZygoteInit",

                    startSystemServer ? "start-system-server":"");

       } elseif(className) {

            // Remainder of args get passed to startup class main()

            runtime.mClassName = className;

            runtime.mArgC = argc - i;

            runtime.mArgV = argv + i;

            runtime.start("com.android.internal.os.RuntimeInit",

                    application ? "application":"tool");

        }

       上面代码(app_process)说明了AppRuntime继承自AndroidRuntime,同一时候获得AndroidRuntime实例。假设是zygote启动它,怎么启动runtime.start("com.android.internal.os.ZygoteInit",

                    startSystemServer ? "start-system-server":"");

    假设不是通过传递过来的类的參数启动它runtime.start("com.android.internal.os.RuntimeInit",

                    application ? "application":"tool");

    做完这些事情app_process就寿终正寝了。

    Zygote做了些什么,ZygoteInit

             init进程启动的时候zygote被作为一种服务启动起来,而且赋予了进程名字为zygote。

    所做之事:

    n  SamplingProfilerIntegration.start();开启性能监控,这个对解说没什么意义

    n  registerZygoteSocket();注冊socket

    n  preloadClasses();在preloaded-classes文件里,这里面包名了全部安卓环境须要的服务和工具和全部类,有兴趣的能够去看看这个文件。

    n  preloadResources();准备preloadClasses()须要的资源。

    n  startSystemServer();启动system_server

    n  假设是zygote 模式,runForkMode();

    n  否则runSelectLoopMode();

    n  closeServerSocket();关闭socket

    n  Exception运行caller.run();

    上面proloadclasses实际上并没有真正的实例化类,而是只载入类的vm中。

    runForkMode

             while (true) {

                ZygoteConnection peer = acceptCommandPeer();

                int pid;

                pid = Zygote.fork();

                if (pid == 0) {

                    ……

                    peer.run();

                    break;

               }

       runForkMode 方法首先fork新的进程,而且对fork出来的进程运行run方法,那么Zygote.fork做了什么呢?

           首先它运行nativeFork然后调用dalvik native代码forkAndSpecializeCommon这里我仅仅选择了最重要的大家能看懂的一行代码,其它代码有兴趣的能够去源代码中研究:

        pid = fork();Linux中的经典fork。

    从上面代码能够看出Zygote确实是fork出来了进程,当中包括system_server,并且zygote作为后台进程无限的从socket接收到fork请求,来fork出新的进程。

           fork出来的进程运行run方法,run方法运行runOnce,runOnce做了什么,请看下一节。实际这里调用这种方法它什么都没做。

    runSelectLoopMode

             这里最基本的是它调用了runOnce,而runOnce最核心的一行代码是:

    pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName);

    这种方法调用nativeForkAndSpecialize在调用Dalvik_dalvik_system_Zygote_fork,这里仅仅是常规的fork。

    SystemServer为一切安卓环境做准备

             zygote启动完毕之后,它启动了system_server,然后自己进入了fork模式等待fork新的进程。

    启动system_server

    n  Zygote.forkSystemServer//终于调用forkAndSpecializeCommon fork出system_server

    n  handleSystemServerProcess//由于invokeWith为空所以它运行了RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,parsedArgs.remainingArgs)-------------------->

    redirectLogStreams();//重置输入错误流

    commonInit();//设置时区,http代理,安装NetworkManagementSocketTagger

    nativeZygoteInit();//终于调用onZygoteInit

    ||sp<ProcessState>proc = ProcessState::self();

    ||proc->startThreadPool();//创建线程,启动

    applicationInit(targetSdkVersion,argv);//运行SystemServer的main函数,看到了没才刚刚開始哦。

           进入SystemServer类的main函数,当中主要运行了下面方法:

    n  System.loadLibrary("android_servers");//载入libandroid_servers.so

    n  init1(args);//掉用system_init();

    调用system_init

       sp<ProcessState> proc(ProcessState::self());

       sp<IServiceManager> sm = defaultServiceManager();

    获得processstate实例,获得servicemanager实例。

      ……

       AndroidRuntime* runtime = AndroidRuntime::getRuntime();

       获得启动安卓的vm

       JNIEnv* env = runtime->getJNIEnv();

       jclass clazz = env->FindClass("com/android/server/SystemServer");

       jmethodID methodId = env->GetStaticMethodID(clazz, "init2","()V");

       env->CallStaticVoidMethod(clazz, methodId);

    载入SystemServer类并运行init2方法

       ProcessState::self()->startThreadPool();

    创建一个线程,不知道为什么google的project师把它命名为startThreadPool

    ,pool非常easy影响人的思维,可是当你查看代码的时候发现它终于就调用了一个pthread_create无非就是创建一个线程。

       IPCThreadState::self()->joinThreadPool();

    joinThreadPool实现有点复杂,我摘几行最重要的代码:

    do {

           ……

            int32_t cmd;

            result = talkWithDriver();

           if (result >= NO_ERROR) {

                result = executeCommand(cmd);

            }

           ……

            if(result == TIMED_OUT &&!isMain) {

                break;

            }

          ……

       } while (result != -ECONNREFUSED && result != -EBADF);

       talkWithDriver(false);

     这个函数在循环中反复运行下列动作:
      1.talkWithDriver 通过ioctl(mProcess->mDriverFD,BINDER_WRITE_READ, &bwr)读取请求和写回结果。
     2.executeCommand 运行对应的请求,反正也是和binder相关的

    凡是程序中包括有joinThreadPool这段代码,它就具备和binder通讯的能力了。

       有些人总是看到pool就喜欢和什么池联系起来,可是我看了几遍源代码都没看见对于池的操作,至于google为什么这么设计我不知道。

    init2

    代码来源于SystemServer

    Thread thr = new ServerThread();

    thr.start();

       首先ServerThread是继承自Thread的,那么上面这两行我们已经非常清楚了就是启动一个线程。

       在线程里做了什么呢,记得之前zygote启动的时候proload中的proclasses吗,当时仅仅是载入了全部的class到vm中,可是并没有实例化并投入到工作中,并且zygote启动之后进入了loop模式等待socket请求来fock新的进程,其它的事情它就撒手无论了,就交给了system_server。到如今为止,安卓的环境还没有准备充足,什么我们平时经常听到了ActivityManagerService呀,什么PackageManagerService呀,各种服务各种应用吧,凡是为安卓大多数安卓的环境这里差点儿都准备了。

    run方法

             以下让我们看一些重要的源代码吧(感兴趣的能够自己细致研习代码):

    ……

    Looper.prepareMainLooper();

    准备loop,进入loop

    android.os.Process.setThreadPriority(

                    android.os.Process.THREAD_PRIORITY_FOREGROUND);

    BinderInternal.disableBackgroundScheduling(true);

    设置进程优先权,设置binder禁止内部后台调度

    ……

    HandlerThread uiHandlerThread = newHandlerThread("UI");

            uiHandlerThread.start();

    Handler uiHandler = new Handler(uiHandlerThread.getLooper());

    uiHandler.post();

    HandlerThread wmHandlerThread = newHandlerThread("WindowManager");

    wmHandlerThread.start();

    Handler wmHandler = newHandler(wmHandlerThread.getLooper());

    wmHandler.post();

    UI和WindowManager进入handle状态

    以下就是实例化各种服务了,当中包括实例化,向ServiceManager中注冊服务,调用各种服务类的核心方法等。代码太一目了然了,顺着代码你能够去相关类去看详细方法,从而能得知全部启动过程和调用方法运行了什么。

    installer = new Installer();

    installer.ping();

    ServiceManager.addService("entropy",newEntropyMixer());

    power = new PowerManagerService();

    //电源管理

    ServiceManager.addService(Context.POWER_SERVICE,power);

    context =ActivityManagerService.main(factoryTest);

    display = newDisplayManagerService(context, wmHandler, uiHandler);

    ServiceManager.addService(Context.DISPLAY_SERVICE,display, true);

    telephonyRegistry = newTelephonyRegistry(context);

    ServiceManager.addService("telephony.registry",telephonyRegistry);

    ServiceManager.addService(Context.SCHEDULING_POLICY_SERVICE,

                        new SchedulingPolicyService());

    ……

    pm =PackageManagerService.main(context, installer,

                        factoryTest !=SystemServer.FACTORY_TEST_OFF,

                        onlyCore);

    //包管理

    ActivityManagerService.setSystemProcess();

    ServiceManager.addService(Context.USER_SERVICE,

                       UserManagerService.getInstance());

    mContentResolver= context.getContentResolver();

    accountManager = newAccountManagerService(context);

    ServiceManager.addService(Context.ACCOUNT_SERVICE,accountManager);

    ……实在是太多ManagerService和太多的Service了,不写了自己去看吧

    power.systemReady(twilight, dreamy);

    pm.systemReady();

    ……各种ready各种初始化各种调用主要函数不写了

    startSystemUi(contextF);

    context.startServiceAsUser(intent,UserHandle.OWNER);

    启动系统UI

    Looper.loop();

    进入loop模式,handleMessage去了。后面略。

    至此SystemServer就算讲完了,通过上面你应该知道它是什么时候被启动的已经启动后它做了些什么。

    ServiceManager

             ServiceManager是做什么的呢,事实上它就是一个管理framework层各种服务的。它内部有一个结构体,是一个链表结构,每一个节点相应一个服务,当运行SystemServer时它的run方法里面的全部服务都会向ServiceManager进行注冊。

             一个服务本身并不全然由纯java编写,也许有一些是这样,由于我并没有看过全部代码不敢妄断,可是通常一个服务是由java和jni和native代码一起编写。并且通常状态下假设一个service会为上层应用提供服务那么这个service一般会有一个binder的stub,这个stub叫做桩,类似于代理可是又不能说是代理,这是rpc协议和机理所致。假设做过java rpc的人也许会对此并不陌生。

             通用规则:

             全部的XXXManager都是作为XXX的管理者。

             全部的XXXManagerService或者XXXService差点儿都是作为XXX类型对上层通过binder通讯而为其服务的独立进程。

    svcinfo结构体

    struct svcinfo

    {

       structsvcinfo *next;下一个服务

       void*ptr;服务指向的地址

       structbinder_deathdeath;

       intallow_isolated;

       unsignedlen;

       uint16_t name[0];服务名称

    };

    structsvcinfo *svclist = 0;

     

       这个结构体就是一个相应service list的结构体,它里面包括全部服务。初始时这个链表为0也就是NULL。

    servicemanager提供的方法

             查找服务、加入服务、释放svc结构、处理svc当中包括(查找服务、加入服务、检查服务、列出全部服务、获得服务)。

             通过读取servicemanager的main函数我们得知它首先打开了binder,而且把自己变成了BINDER_SERVICE_MANAGER,然后进入了无限循环状态,等待其它service的binder通讯,它负责各个service之间的通讯通过binder,它作为了一个桥梁。

    binder相关

             首先binder作为一种驱动设计,用于进程间通讯,使用rpc协议。遵循linux驱动设计。在类unix世界一切皆文件,全部你能在binder相关源文件看到,訪问binder和訪问文件一样通过一个open就能够了,用户层和binder的通讯命令借助底层实现的ioctl函数。

       由于安卓世界里,差点儿每个service都是作为独立进程执行的,都是由zygote进程fork出来的,全部各个进程是独立的,他们有自己的进程空间,所以为了彼此通讯,安卓设计了有别的binder机制。

     

  • 相关阅读:
    全链路压测(1):认识全链路压测
    碎片式的技术笔记
    聊聊传统压测和全链路压测的区别
    生产全链路压测常态化方案
    C++选择文件打开方式的函数
    常用的一些 git 命令
    MyBatis 批量插入数据的 3 种方法!
    MyBatis Plus 批量数据插入功能,yyds!
    什么是可中断锁?有什么用?怎么实现?
    1.3w字,一文详解死锁!
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4059163.html
Copyright © 2020-2023  润新知