android体系课-系统启动流程-之zygote进程启动过程源码分析

简介: 笔者刚开始学习Android的时候也和大部分同学一样,只会使用一些应用层面的知识,对于一些比较常见的开源框架如<mark>RxJava</mark>,<mark>OkHttp</mark>,<mark>Retrofit</mark>,以及后来谷歌推出的<mark>协程</mark>等,都只在使用层面,对于他们<mark>内部原理</mark>,基本没有去了解觉得够用就可以了,又比如Activity,Service等四大组件的使用原理,系统开机过程,Launcher启动过程等知之甚少,知其然而不知其所以然,结果就是出现某些问题,不知道从哪里找原因,只能依赖万能的百度,但是百度看多了,你会发现自己

前言

本文主要记录笔者对Android系统启动流程的一个的一个过程了解

笔者刚开始学习Android的时候也和大部分同学一样,只会使用一些应用层面的知识,对于一些比较常见的开源框架如RxJava,OkHttp,Retrofit,以及后来谷歌推出的协程等,都只在使用层面,对于他们内部原理,基本没有去了解觉得够用就可以了,又比如Activity,Service等四大组件的使用原理,系统开机过程,Launcher启动过程等知之甚少,知其然而不知其所以然,结果就是出现某些问题,不知道从哪里找原因,只能依赖万能的百度,但是百度看多了,你会发现自己还是什么都不会,过一段时间可能就忘记了

  • 为了能更加深刻的理解这些机制,笔者决定自己深入Framework层面去考察下这些代码的机制:

讲解时间线如下:

对于源码解析部分,可能大家会有部分疑惑,我们列出部分:

  • 1.zygoye是什么?有什么作用

    答:zygote英文翻译是“孵化”。

在了解zygote之前首先我们需要知道我们进程是如何创建的?

我们安卓设备内核使用的是linux内核,
开机先是启动一个init进程,在init进程中会创建一个zygote进程,
zygote进程会启动java虚拟机并注册java-native 的jni方法,通过jni调用到java层的ZygoteInit,在这个类里面会注册一个ServerSocket用于设备创建应用进程的需要。
当启动一个应用需要创建一个进程时,会调用到这个ServerSocket的创建进程流程,主要是通过fork的方式创建进程,这样子进程就拥有了父进程所有的资源,
fork会返回两次,当返回的pid=0时说明现在是处于子进程,继续处理子进程流程就可以了。如果是SystemServer进程,则会启动各类服务,包括AMS,WMS等系统服务。

按上面所讲,zygote就是作为创建子进程的一个孵化器。‘

  • 2.SystemServer是什么?有什么作用?它与zygote的关系是什么?

答:SystemServer是一个由zygotefork出来的子进程,该进程主要作用是创建创建binder线程池和启动android运行需要的诸多系统服务,比如:AMS,PMS,WMS等并启动系统Launcher

  • 3.ActivityManagerService是什么?什么时候初始化的?有什么作用?

答:ActivityManagerService,简称AMS,服务端对象,负责统一调度系统中四大组件的生命周期。ActivityManagerService进行初始化的时机很明确,就是在SystemServer进程开启的时候,就会初始化ActivityManagerService

**APP和AMS其实是通过binder进行通讯的。**

binder机制简述。
    binder其实是进程间通信的一种方式,在linux进程中有socket,管道,共享内存,消息队列等方式,
    而由于binder对性能消耗低和安全性方面的考虑,android大量的使用了binder通讯 ,可以说binder是android的基石。
binder模型简述:
    首先我们binder是通过CS架构进行设计的:Client和Service
    先搞懂三个概念:client,server和serverManger
    server通过binder通讯将自己注册到serverManager中,client通过binder获取serverManager中注册的server,
    其实是获取一个handle,通过这个handle就可以在bidner驱动中找找到server进程和需要处理的方法地址等信息。
    从而间接实现了进程间通讯,这个是binder的一个简要概述,详细的需要去了解binder驱动实现原理。
  • 4.Launcher是什么?什么时候启动的?

    答:Launcher也是一个应用app,是在SystemServer启动的时候,启动的一个应用
    
    

5.Instrumentation是什么?和ActivityThread是什么关系?

答:Instrumentation是一个沟通Activity和AMS以及ActivityThread和Activity中间桥梁工具类
例如:Activity.startActivity
        ->mInstrumentation.execStartActivity
        ->ActivityManagerService.startActivity->ActivityThread.thread.scheduleLaunchActivity
        ->ActivityThread.handleLaunchActivity
        ->mInstrumentation.callActivityOnCreate

针对以上问题:笔者会以源码的方式呈现

我们先来看下Android设备启动过程

  • init进程 0号进程

作用:

1.创建和挂载启动所需的文件系统:tmpfs,devpts,proc,sysfs,selinuxfs等

2.初始化和启动属性服务

3.设置子进程(zygote进程)异常退出处理函数。

在UNIX/linux中,父进程调用fork函数创建子进程,在子进程在异常退出后,如果父进程不知道子进程已经退出,其会在系统进程表中保留进程信息(进程号,退出状态和运行时间等),
这个子进程就变成僵尸进程,系统进程表是一项有限资源,如果系统进程被僵尸进程耗尽就会无法创建新的进程

4.解析init.rc文件,并启动孵化zygote进程(Android初始化语言)

5.启动孵化zygote进程,这个是本篇文章的分析重点,从源码角度分析了Android zygote进程启动过程

app_main.cpp

    int main(){
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
            AndroidRuntime.cpp:start:
            //启动java虚拟机
            startVm(&mJavaVM, &env, zygote) != 0;
            //注册android启动需要的jni方法
            startReg(env) < 0;
            //startClass="com.android.internal.os.ZygoteInit" startMeth=main方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray); 
            //即调用ZygoteInit的main方法
            ZygoteInit.java:main{    
                //创建一个Server端的socket,socketName=“zygote” 用于接收应用的请求创建应用进程fork方式
                zygoteServer.registerServerSocket(socketName);
                    ZygoteServer.java:registerServerSocket
                //预加载系统类和系统资源
                preload(bootTimingsTraceLog){
                    preloadClasses();
                    preloadResources();
                    preloadOpenGL();
                    preloadSharedLibraries();
                    preloadTextResources();
                    WebViewFactory.prepareWebViewInZygote();
                }
                //启动SystemServer进程
                startSystemServer(abiList, socketName, zygoteServer){
                    //fork system server进程
                    pid = Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid...);
                    //pid=0,说明运行在子进程中:SystemServer进程中
                    if (pid == 0) {
                        //关闭SystemServer进程中的socket,因为是通过fork创建,子进程也会有socket服务,需要关闭子进程的socket通道
                        zygoteServer.closeServerSocket();
                        //处理SystemServer进程
                        handleSystemServerProcess(parsedArgs){
                            //创建PathClassLoader
                            cl = createPathClassLoader(...);
                            //注释2
                            ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl){
                                //RuntimeInit初始化操作
                                RuntimeInit.commonInit();
                                    RuntimeInit.java:commonInit
                                    //设置主线程未捕获异常时回调的Handler,可以在app中替换
                                    Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler());
                                //对应AndroidRunTime:com_android_internal_os_ZygoteInit_nativeZygoteInit:
                                ZygoteInit.nativeZygoteInit(){
                                    //gCurRuntime = AppRuntime在app_main.cpp中初始化
                                    gCurRuntime->onZygoteInit(); 
                                        sp<ProcessState> proc = ProcessState::self();
                                        //启动线程池,内部会循环获取其他应用发过来的数据,根据binder机制
                                        proc->startThreadPool();
                                }
                                RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader){
                                
                                    invokeStaticMain(args.startClass, args.startArgs, classLoader){
                                        //前面传入的是"com.android.server.SystemServer",加载类SystemServer
                                        cl = Class.forName(className, true, classLoader); 
                                        //反射获取SystemServer的main方法
                                        m = cl.getMethod("main", new Class[] { String[].class });
                                        //可以再注释1出捕获,最终进入SystemServer的main方法
                                        throw new Zygote.MethodAndArgsCaller(m, argv);
                                    }
                                }
                            }
                        }            
                    }
                }
                //这个还是在app_main进程中等待AMS创建新的应用程序进程 注释3
                zygoteServer.runSelectLoop(abiList){
                    while (true) {
                        StructPollfd[] pollFds = new StructPollfd[fds.size()];
                        for (int i = 0; i < pollFds.length; ++i) {
                            pollFds[i] = new StructPollfd();
                            pollFds[i].fd = fds.get(i);
                            pollFds[i].events = (short) POLLIN;
                        }
                        try {
                            //poll函数使用pollfd类型的结构来监控一组文件句柄
                            //https://blog.csdn.net/sijinxiaotongxue/article/details/81988411
                            Os.poll(pollFds, -1);
                        } catch (ErrnoException ex) {
                            throw new RuntimeException("poll failed", ex);
                        }
                        for (int i = pollFds.length - 1; i >= 0; --i) {
                            if ((pollFds[i].revents & POLLIN) == 0) {
                                continue;
                            }
                            if (i == 0) {i=0为connect阶段
                                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                                peers.add(newPeer);
                                fds.add(newPeer.getFileDesciptor());
                            } else {
                                //不为0则说明AMS向孵化进程发出一个创建进程的请求,调用fork方式创建进程
                                boolean done = peers.get(i).runOnce(this){
                                    acceptCommandPeer.runOnce(this){
                                        //读客户端发来的数据
                                        args = readArgumentList();
                                        调用fork创建新的进程        
                                        pid = Zygote.forkAndSpecialize(...) 
                                    }
                                }        
                                //创建成功,移除ZygoteConnection
                                if (done) {
                                    peers.remove(i);
                                    fds.remove(i);
                                }
                            }
                        }
                    }
                    //0为子进程
                    if (pid == 0) { 
                        //关闭子进程的socket连接,子进程不需要创建socket
                        zygoteServer.closeServerSocket();
                        //处理子进程
                        handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
                            //和注释2一样内部为初始化和创建子进程的线程池和启动子进程
                            ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,parsedArgs.remainingArgs, null /* classLoader */);
                                
                    }
                }
                catch (Zygote.MethodAndArgsCaller caller) {
                    //子进程入口 注释1,zygote进程还是在注释3处等待
                    caller.run();
                } 
                
            }
    }

zygote进程总结:

  • 1.启动java虚拟机
  • 2.注册android启动需要的jni方法
  • 3.调用com.android.internal.os.ZygoteInit的main方法

    • 3.1:创建一个Server端的socket,socketName=“zygote” 用于接收应用的请求创建应用进程:使用的fork方式
    • 3.2:预加载系统类和系统资源,如果进程是使用fork方式创建的,则这个预加载的类和资源也可以被子进程所用
    • 3.2:使用fork方式创建SystemServer进程,最终会在3.3处接收到socket请求并创建SystemServer进程。并在异常后调用caller.run()运行SystemServer的main方法;
      SystemServer进程中:

      • 3.2.1:创建PathClassLoader
      • 3.2.2:设置主线程未捕获异常时回调的Handler,可以在app中替换
      • 3.2.3:启动binder线程池
      • 3.2.4:使用抛出异常加反射的方式,启动SystemServer的main方法
    • 3.3:在app_main进程中等待AMS创建新的应用程序进程

下一篇我们会讲解关于SystemServer启动过程源码分析

相关文章
|
ARouter IDE 开发工具
Android面试题之App的启动流程和启动速度优化
App启动流程概括: 当用户点击App图标,Launcher通过Binder IPC请求system_server启动Activity。system_server指示Zygote fork新进程,接着App进程向system_server申请启动Activity。经过Binder通信,Activity创建并回调生命周期方法。启动状态分为冷启动、温启动和热启动,其中冷启动耗时最长。优化技巧包括异步初始化、避免主线程I/O、类加载优化和简化布局。
681 3
Android面试题之App的启动流程和启动速度优化
|
Java Android开发 数据安全/隐私保护
Android中多进程通信有几种方式?需要注意哪些问题?
本文介绍了Android中的多进程通信(IPC),探讨了IPC的重要性及其实现方式,如Intent、Binder、AIDL等,并通过一个使用Binder机制的示例详细说明了其实现过程。
1319 4
|
Android开发 开发者 Kotlin
Android 多进程情况下判断应用是否处于前台或者后台
本文介绍在多进程环境下判断Android应用前后台状态的方法。通过`ActivityManager`和服务信息`RunningAppProcessInfo`可有效检测应用状态,优化资源使用。提供Kotlin代码示例,帮助开发者轻松集成。
1712 8
|
API Android开发
Android P 性能优化:创建APP进程白名单,杀死白名单之外的进程
本文介绍了在Android P系统中通过创建应用进程白名单并杀死白名单之外的进程来优化性能的方法,包括设置权限、获取运行中的APP列表、配置白名单以及在应用启动时杀死非白名单进程的代码实现。
695 1
|
Java Linux Android开发
Android面试题之说说系统的启动流程(总结)
这篇文章概述了Android系统的启动流程,从Boot Rom到Zygote进程和SystemServer的启动。init进程作为用户级别的第一个进程,负责创建文件目录、初始化服务并启动Zygote。Zygote通过预加载资源和创建Socket服务,使用fork函数生成SystemServer进程。fork过程中,子进程继承父进程大部分信息但具有独立的进程ID。Zygote预加载资源以减少后续进程的启动时间,而SystemServer启动众多服务并最终开启Launcher应用。文中还讨论了为何从Zygote而非init或SystemServer fork新进程的原因。
511 2
|
Android开发
Android面试题之activity启动流程
该文探讨了Android应用启动和Activity管理服务(AMS)的工作原理。从Launcher启动应用开始,涉及Binder机制、AMS回调、进程创建、Application和Activity的生命周期。文中详细阐述了AMS处理流程,包括创建ClassLoader、加载APK、启动Activity的步骤,以及权限校验和启动模式判断。此外,还补充了activity启动流程中AMS的部分细节。欲了解更多内容,可关注公众号“AntDream”。
464 1
|
大数据 Linux Android开发
Android ParcelFileDescriptor实现进程间通信
Android ParcelFileDescriptor实现进程间通信
987 0
|
vr&ar 数据库 Android开发
Android面试题之ActivityManagerService的启动流程
本文探讨了Android系统的SystemServer启动过程,包括创建SystemContext、引导服务、启动各类核心服务以及AMS的启动和初始化。AMS负责管理activity、广播队列、provider等,并设置SystemProcess,安装系统Provider。当AMS调用SystemReady时,系统UI准备启动,启动Launcher。文中还对比了init、zygote和system_server进程的角色。最后推荐了两本关于Android内核剖析的书籍:柯元旦教授的《Android内核剖析》和罗升阳的《Android系统源代码情景分析》。关注公众号AntDream获取更多内容。
307 0
|
XML 前端开发 Android开发
Android架构设计——MVC(1),Android多进程从头讲到尾
Android架构设计——MVC(1),Android多进程从头讲到尾
|
Linux 数据库 Perl
【YashanDB 知识库】如何避免 yasdb 进程被 Linux OOM Killer 杀掉
本文来自YashanDB官网,探讨Linux系统中OOM Killer对数据库服务器的影响及解决方法。当内存接近耗尽时,OOM Killer会杀死占用最多内存的进程,这可能导致数据库主进程被误杀。为避免此问题,可采取两种方法:一是在OS层面关闭OOM Killer,通过修改`/etc/sysctl.conf`文件并重启生效;二是豁免数据库进程,由数据库实例用户借助`sudo`权限调整`oom_score_adj`值。这些措施有助于保护数据库进程免受系统内存管理机制的影响。

热门文章

最新文章