百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

字节跳动二面之Zygote进程启动源码分析

bigegpt 2025-02-11 11:01 7 浏览

本文通过在字节面试遇到的问题总结而出,如有不对地方,请及时批评指正。篇幅较长,请耐心阅读

简介

当Android手机从按下开机键时,屏幕点亮,到系统桌面的显示,整个过程系统是怎么启动的?下面我们一起深入源码来看一下。整体流程如下图所示。


源码分析

init进程启动

1.BootROM

当按下电源开关键时,引导芯片程序会从预定义的地方开始执行,加载系统引导程序BootLoader到RAM,启动执行。

2.BootLoader

初始化系统硬件资源,引导操作系统启动。

3.idel进程

初始化进程管理,内存管理,加载Binder驱动,Display,Camera 驱动等相关工作。

4. init进程


Android系统启动时 通过Android.bp启动Main.cpp的main函数。

int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif
    // 设置进程优先级
    setpriority(PRIO_PROCESS, 0, -20);
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }

    if (argc > 1) {
        //根据不同的参数 执行不同的函数。
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();

            return SubcontextMain(argc, argv, &function_map);
        }
         //第二次执行 
        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }
        //最后执行到 SecondStageMain
        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }
    //firstStageMain中再次调用main.cpp,参数传为selinux_setup,后续执行SetupSelinux
    return FirstStageMain(argc, argv);

Main.cpp的main方法被反复执行,最后执行到SecondStageMain方法。

int SecondStageMain(int argc, char** argv) {

    .............
    //初始化属性服务
    PropertyInit();

    // Umount the debug ramdisk after property service has read the .prop files when it means to.
    if (load_debug_prop) {
        UmountDebugRamdisk();
    }

    // Mount extra filesystems required during second stage init
    MountExtraFilesystems();

    // 设置系统安全策略
    SelinuxSetupKernelLogging();
    SelabelInitialize();
    SelinuxRestoreContext();
    //定义epoll机制
    Epoll epoll;
    if (auto result = epoll.Open(); !result.ok()) {
        PLOG(FATAL) << result.error();
    }

    //解析init.rc文件
    LoadBootScripts(am, sm);
   .......................
    while (true) {
        // 循环等待处理
        auto epoll_timeout = std::optional{};

        auto shutdown_command = shutdown_state.CheckShutdown();
       .........................
     
    }

    return 0;
}

}  // namespace init

SecondStageMain方法中,init进程主要处理挂载文件,设置系统安全策略,开启属性服务,注册到epoll中,解析init.rc ,启动Zygote进程。


Zygote进程启动

当安卓系统启动后,会创建一个init进程,所以的进程都是有和这个init进程fork出来的,包括Zygote进程,当系统要求启动一个Android应用程序时,都会通过AMS通知Zygote进程创建一个子进程用来启动该应用程序。

1.App_main.cpp

Zygote进程启动时会执行app_main.cpp的main函数。

int main(int argc, char* const argv[])
{
   .............
   //初始化AppRuntime
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
   
    argc--;
    argv++;
   ...........................

    //是否是zygote进程
    bool zygote = false;
    //是否启动systemServer进程
    bool startSystemServer = false;
    bool application = false;
    //进程名称
    String8 niceName;
    String8 className;

    ++i; 
    while (i < argc) {
        const char* arg = argv[i++];
        //设置zygote启动
        if (strcmp(arg, "--zygote") == 0) {
            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 (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }

    if (zygote) {
        //如果是zygote进程  执行AppRuntime.start
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

2.AndroidRuntime.cpp

AppRuntime继承于AndroidRuntime,执行AppRuntime的start方法就是执行AndroidRuntime中的start方法。className传入的是 "
com.android.internal.os.ZygoteInit
"

void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
{
   
    static const String8 startSystemServer("start-system-server");
    //记录当前zygote是否是fork出SystemServer进程
    bool primary_zygote = false;

    
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    //启动虚拟机
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    //如果没有虚拟机则创建新的虚拟机
    onVmCreated(env);

    /*
     * 注册系统jni方法
     */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
    ..................
    /*
     * 启动虚拟机线程,执行ZygoteInit的main方法
     * className :com.android.internal.os.ZygoteInit
     */
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            //执行jni方法 进入:com.android.internal.os.ZygoteInit的main方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
    }
    ....................
}

3.ZygoteInit.java

AndroidRuntime.start方法中 通过jni调用java代码,执行
com.android.internal.os.ZygoteInit的main方法。

 public static void main(String argv[]) {
        ZygoteServer zygoteServer = null;
        //标记zygote进程启动
        ZygoteHooks.startZygoteNoThreadCreation();
        ...............
        Runnable caller;
        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]);
                }
            }
       
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                //预加载资源
                preload(bootTimingsTraceLog);
            }
            //创建zygote服务
            zygoteServer = new ZygoteServer(isPrimaryZygote);
            //通过zygote进程fork出SystemServer进程
            if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
                if (r != null) {
                    //执行SystemServer的main方法
                    r.run();
                    return;
                } 
            }
            //开启循环
           caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket();
            }
        }
    }

ZygoteInit的main方法主要的作用是:

1).预加载系统资源。

2).创建zygote的socket服务。

3).通过Zygote进程fork出SystemServer进程。

4).执行SystemServer的main方法,启动进程。

5).zygote进入循环等待状态,接收AMS传递的消息。

Zygote作为进程孵化器,当需要启动一个程序时,首先会通过AMS使用Socket发送消息到Zygote进程,Zygote通过fork函数创建需要启动的程序进程。

以上就是字节面试后总结的几个要点,还不会的同学赶紧学起来吧,感谢您的阅读,创造不易,如果您觉得本篇文章对您有帮助,请点击关注小编,您的支持就是小编创作的最大动力!

相关推荐

php-fpm的配置和优化

目录概述php-fpm配置php-fpm进程优化配置慢日志查询配置php7进阶到架构师相关阅读概述这是关于php进阶到架构之php7核心技术与实战学习的系列课程:php-fpm的配置和优化学习目标:理...

成功安装 Magento2.4.3最新版教程「技术干货」

外贸独立站设计公司xingbell.com经过多次的反复实验,最新版的magento2.4.3在oneinstack的环境下的详细安装教程如下:一.vps系统:LinuxCentOS7.7.19...

十分钟让你学会LNMP架构负载均衡

业务架构、应用架构、数据架构和技术架构一、几个基本概念1、pv值pv值(pageviews):页面的浏览量概念:一个网站的所有页面,在一天内,被浏览的总次数。(大型网站通常是上千万的级别)2、u...

php从远程URL获取(mp4 mp3)音视频的流媒体数据

/***从远程URL中获取媒体(如mp4mp3)的内容*@parammixed$file_url*@parammixed$media_type...

Zabbix5.0安装部署

全盘展示运行状态,减轻运维人员的重复性工作量,提高系统排错速度,加速运维知识学习积累。1.png1、环境安装关闭SELinux并重启系统2.png安装httpd、mariadb、php运行yum-...

php 常见配置详解

以下是PHP常见的配置项及其含义:error_reporting:设置错误报告级别,可以控制PHP显示哪些错误。例如,设置为E_ALL将显示所有错误,而设置为0将禁止显示任何错误。displa...

实践分享|基于基石智算 DeepSeek API + WordPress 插件自动生成访客回复

基石智算举办的DeepSeek案例大赛汇集了不少基于CoresHubDeepSeekAPI服务或模型部署服务的精彩实践。本次我们将分享个人实践:通过DeepSeekAPI+Word...

如何在Eclipse中搭建Zabbix源码的调试和开发环境

Zabbix是一款非常优秀的企业级软件,被设计用于对数万台服务器、虚拟机和网络设备的数百万个监控项进行实时监控。Zabbix是开放源码和免费的,这就意味着当出现bug时,我们可以很方便地通过调试源码来...

MySQL自我保护参数

#头条创作挑战赛#之前(MySQL自我保护工具--pt-kill)提到用pt-kill工具来kill相关的会话,来达到保护数据库的目的,本文再通过修改数据库参数的方式达到阻断长时间运行的SQL的目...

Python闭包深度解析:掌握数据封装的高级技巧

闭包作为Python高级编程特性之一,为开发者提供了一种优雅的方式来实现数据封装和状态保持。这一概念源于函数式编程理论,在现代Python开发中发挥着重要作用。理解和掌握闭包的使用不仅能够提升代码的表...

Java服务网格故障注入与熔断实战

在分布式系统的高可用性挑战中,服务网格的故障注入与熔断机制是检验系统韧性的终极试金石。以下是10道逐步升级的"地狱关卡",每个关卡都对应真实生产环境中可能遇到的致命场景,并附具体场景示...

MySQL数据库性能优化全攻略:程序员必知的七大核心策略

作为程序员,我们每天都要与数据库打交道。当系统用户量突破百万级时,数据库往往成为性能瓶颈的首要怀疑对象。本文将深入探讨MySQL优化的七大核心策略,并提供可直接落地的优化方案,助您构建高效稳定的数据库...

如何在 Windows 11 上使用单个命令安装 XAMPP

XAMPP是一种广泛使用的软件,用于在Windows操作系统上快速运行LAMP服务器包,包括Windows11。尽管LAMP通常用于Linux系统,但XAMPP并不使用Li...

uTorrent怎样将bt种子转换为磁力

如何用uTorrent把BT种子转为磁力链接?以下方法希望能帮到你。1、在uTorrent窗口里,点击工具栏的按钮,所示。2、在打开窗口里,选取要转为磁力的种子文件,然后点击打开按钮,参照图示操作...

支持向量机SVM 分类和回归的实例

支持向量机(SupportVectorMachine)是Cortes和Vapnik于1995年首先提出的,它在解决小样本、非线性及高维模式识别中表现出许多特有的优势,并能够推广应用到函数拟合等其他...