栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android 系统启动 <zygote 进程> 笔记【2】

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android 系统启动 <zygote 进程> 笔记【2】

Read The Fucking Source Code. —— Linus

站在’巨人’的肩膀上开始自己的旅途。—— 佚名

愉快的周末,从打开开始,到骑行归来结束。—— 佚名

文章系列

注: 本系列文章源码基于 Android 11-r21 master 分支

  • Android 系统启动 笔记【1】
  • Android 系统启动 笔记【2】
  • Android 系统启动 笔记【3】

相关文件

  • /system/core/init/init.cpp
  • /system/etc/init/hw/init.rc (源码工程没找到,是从手机上获取)
  • /system/etc/init/hw/init.zygote32.rc (手机上获取)
  • /system/etc/init/hw/init.zygote64_32.rc (手机上获取)
  • /system/core/init/action.cpp
  • /system/core/init/service.cpp
  • /system/core/init/service_list.cpp
  • frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
  • frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
  • frameworks/base/core/java/com/android/internal/os/Zygote.java
  • frameworks/base/core/java/com/android/internal/os/WrapperInit.java
解析 hw/init.rc

init.rc 解析

带着上文留下的疑惑继续看源码,之前提到执行到第二阶段时候进入了 loop 循环,似乎不知去向何处?第二阶段创建 init 进程中有一个重要的函数那就是 LoadBootScripts(actionManager,serviceList) 加载启动脚本,相当重要,与 init.rc 文件存在千丝万缕的关系,那么就要看看这里究竟在执行什么。

//init.cpp
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser = CreateParser(action_manager, service_list);
    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    if (bootscript.empty()) {
        //解析 init.rc,启动的关键文件
        parser.ParseConfig("/system/etc/init/hw/init.rc");
        if (!parser.ParseConfig("/system/etc/init")) {
            late_import_paths.emplace_back("/system/etc/init");
        }
        
        parser.ParseConfig("/system_ext/etc/init");
        if (!parser.ParseConfig("/vendor/etc/init")) {
            //vendor 厂商相关的初始化配置
            late_import_paths.emplace_back("/vendor/etc/init");
        }
        if (!parser.ParseConfig("/odm/etc/init")) {
            late_import_paths.emplace_back("/odm/etc/init");
        }
        if (!parser.ParseConfig("/product/etc/init")) {
            late_import_paths.emplace_back("/product/etc/init");
        }
    } else {
        parser.ParseConfig(bootscript);
    }
}
//init.cpp
void SecondStageMain(){

    //数据解析获得,开始构建 action 队列
    ActionManager& am = ActionManager::GetInstance();
    am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
    .... etc

    //触发启动
    am.QueueEventTrigger("init");
    
    //若处于充电模式将延迟初始化
    std::string bootmode = GetProperty("ro.bootmode", "");
    if (bootmode == "charger") {
        am.QueueEventTrigger("charger");
    } else {
        am.QueueEventTrigger("late-init");
    }
    
    //init 进程进入无限轮训
    while(true){
        //开始通过 command 命令执行 inir.rc 脚本各项服务以及初始化
        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
            am.ExecuteOneCommand();
        }
        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {

        // If there's more work to do, wake up again immediately.
        if (am.HasMoreCommands())
            epoll_timeout = 0ms;
        }
    }
}

在 Android 11 上,init.rc 文件在/system/etc/init/hw/init.rc

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FSCwp9hL-1658835973999)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/92ab7d4ccd7a4118a1f705928d97c212~tplv-k3u1fbpfcp-watermark.image?)]

这是在小米手机找的,看看内容,rc 文件被视为 Android 初始化语言,也有一定的语法,可以参考:https://www.cnblogs.com/gufanyuan/p/9350130.html

总结下 Android 初始化语言

  • action on 后携带一组命令
  • trigger 触发器,确定何时执行命令
  • service 当 init 退出时启动或重启
  • options 进一步控制命令执行的方式和时间
  • 命令:on 每一行代表一条命令
  • import 导入额外的 rc 文件需要解析

下面简略看看 rc 文件:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gKFSboqt-1658835973999)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0991aad99b524f9ebc147ce1fe075047~tplv-k3u1fbpfcp-watermark.image?)]

//  /system/etc/init/hw/init.rc

# 小米系统,肯定也是有厂商自己的解析文件需要执行属于自己的进程
# import 指明导入其他配置文件需要解析
# MIUI ADD:
import /init.miui.rc

# 还记得 SecondStageMain actionManage 吗
# am.QueueEventTrigger("early-init");
on early-init
    # 一个守护进程,负责处理 uevent 消息
    start ueventd
    # apex 服务于系统模块安装
    exec_start apexd-bootstrap

# 触发所有 action
# am.QueueEventTrigger("init");
on init
    # 创建 stdio 标准输入输出链接
    symlink /proc/self/fd/0 /dev/stdin
    # 给 sdcard 更改权限
    chmod 0770 /config/sdcardfs
    
    # 启动服务
    # 系统服务,越来越接近应用层了
    start servicemanager
    # hw——hardware,硬件服务
    start hwservicemanager
    #供应商服务
    start vndservicemanager
    # init action 就执行到这,中间省略很多命令,这里只是抽取几个,点到为止
    
# 挂载文件系统以及核心服务
# am.QueueEventTrigger("late-init");
on late-init
    # 触发 fs:Vold 控制和管理外部存储的进程
    trigger early-fs

    # 重点来了⚠️⚠️⚠️
    # import /system/etc/init/hw/init.${ro.zygote}.rc
    # zygote 进来了,常说的 Android 应用层的鼻祖
    trigger zygote-start
    
    trigger early-boot
    trigger boot

on boot
    # 启动 HAL 硬件抽象类服务
    class_start hal
    # 启动核心类服务
    class_start core
解析 zygote.rc

看上面截图,现在该执行init.zygote32.rc、init.zygote64_32.rc,继续往下看。

//  /system/etc/init/hw/init.zygote32.rc
// zygote32 : 只有一个 32,那就是纯纯的为 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 exec_background - system system -- /system/bin/vdc volume abort_fuse
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks

//  /system/etc/init/hw/init.zygote64_32.rc
// zygote64_32 : 前部分 64 指主要模式,后部分 32 指辅助模式;同样的也会有 zygote32_64.rc、zygote32.rc、zygote64.rc  etc.

# service 是 Android 初始化话语言的一部分,指 init 启动或退出时重新启动服务
# 显然,这里的服务名称就是‘家喻户晓’的 zygote 进程
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    priority -20     ### 进程优先级 -20 ,值越小优先级越高,取值范围 [-20,19]
    user root        ### 由 root 用户执行 
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    task_profiles ProcessCapacityHigh MaxPerformance

# zygote_secondary ?????
# 你在看前面提到的‘主模式’和‘辅模式’,恰好 zygote 是 app_process64,zygote_secondary 是 app_process32,
# 刚刚好对应上文件名 init.zygote64_32.rc 【主模式是64,辅模式是32】
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote_secondary stream 660 root system
    socket usap_pool_secondary stream 660 root system
    onrestart restart zygote
    task_profiles ProcessCapacityHigh MaxPerformance
创建 zygote Process

在第二阶段 SecondStageMain 初始化时候解析了 inir.rc,回到 main.cpp 看到 函数映射表 GetBuiltinFunctionMap 作为参数传进入 SubcontextMain 第四部分开始执行,接着看看执行流程。

//main.cpp
return SubcontextMain(argc, argv, &function_map);

//subcontext.cpp
auto subcontext_process = SubcontextProcess(function_map, context, init_fd);

//subcontext.cpp
SubcontextProcess(const BuiltinFunctionMap* function_map, std::string context, int init_fd)
: function_map_(function_map), context_(std::move(context)), init_fd_(init_fd){};
//通过构造函数,直接将函数映射表赋值给成员 function_map_
const BuiltinFunctionMap* function_map_;

//在 SubcontextMain 中开始主循环
subcontext_process.MainLoop();

//主循环中准备执行命令
RunCommand(subcontext_command.execute_command(), &reply);

//映射表 function_map_ 被使用
//根据参数(命令)查找对应的内置函数
auto map_result = function_map_->Find(args);
//找到了命令准备执行
result = RunBuiltinFunction(map_result->function, args, context_);

//构造参数,直接调用
//回想一下,映射表中是否有着一个 item
//{"class_start", {1, 1, {false, do_class_start}}}
//do_class_start:内置函数被声明在 builtins.cpp 中,下面看看其实现
auto builtin_arguments = BuiltinArguments(context);
return function(builtin_arguments);
//builtins.cpp
static Result do_class_start(const BuiltinArguments& args) {
    if (android::base::GetBoolProperty("persist.init.dont_start_class." + args[1], false))
        return {};
    //服务启动
    

    for (const auto& service : ServiceList::GetInstance()) {
        //参数的来源
        
        if (service->classnames().count(args[1])) {
            if (auto result = service->StartIfNotDisabled(); !result.ok()) {
                LOG(ERROR) << "Could not start service '" << service->name()
                           << "' as part of class '" << args[1] << "': " << result.error();
            }
        }
    }
    return {};
}

//service.cpp
Result Service::StartIfNotDisabled() {
    if (!(flags_ & SVC_DISABLED)) {
        return Start();
    } else {
        flags_ |= SVC_DISABLED_START;
    }
    return {};
}

//service.cpp
Result Service::Start() {
    
    pid_t pid = -1;
    if (namespaces_.flags) {
        pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr);
    } else {
        //就这?进程就被 fork 出来了???
        pid = fork();
    }

    // pid 0 是 idle 进程,肯定不能
    if (pid == 0) {
        umask(077);
        RunService(override_mount_namespace, descriptors, std::move(pipefd));
        _exit(127);
    }
    
    //创建进程组
    errno = -createProcessGroup(proc_attr_.uid, pid_, use_memcg);
}

到此,通过查找服务列表创建了一堆进程,现在我们主要关注 zygote进程的创建,这时候间从 cpp 进入 Java

初始化 zygote 预加载
//ZygoteInit.java
public class ZygoteInit {
    
    public static void main(String[] argv) {
        //【1】完成预初始化
        
        preload(bootTimingsTraceLog);
        
        //初始化 GC,并执行一次清理
        ZygoteHooks.gcAndFinalize();
        //到这里 zygote 已经是【初始化完毕】
        Zygote.initNativeState(isPrimaryZygote)
        
        //【2】创建 zygote 服务
        ZygoteServer zygoteServer = null;
        zygoteServer = new ZygoteServer(isPrimaryZygote);
        
        //【3】创建系统服务
        if (startSystemServer) {
            //fork,可见每一个系统服务都是独立的进程;ABI —— Application binary interface【参考链接】
            //在 Android 项目中对应的就是 ndk filter,如 arm64、x86  .etc
            //为支持不同平台,ndk filter 是能够配置多个的,所以是一个列表形式存在
            Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
            if (r != null) {
                //创建之后马上运行
                return;
            }
         }
         
        // zygote 服务进入自己的世界轮训
        caller = zygoteServer.runSelectLoop(abiList);
        if(caller != null){
            caller.run();
        }
    }
}
创建 zygote Server

服务主要还是通过 socket 实现,等待来自 Linux、unix 守护进程 (socket) 的消息,同时也负责子进程的创建。

//ZygoteServer.java
class ZygoteServer {

//列举几个重要的成员
//用于监听 socket 连接
private LocalServerSocket mZygoteSocket;
//为 USAP 非专用应用进程池 服务
private final LocalServerSocket mUsapPoolSocket;

ZygoteServer(boolean isPrimaryZygote) {
        //通过 native 调用获取
        mUsapPoolEventFD = Zygote.getUsapPoolEventFD();
        
        //主 zygote
        if (isPrimaryZygote) {
            //完成的 socket 名称需要和 ANDROID_SOCKET_ + socketname 拼接,
            //然后拿完整的名称去系统环境变量中查找获取文件描述符 fd —— file describe,实际是一个整型数值【参考链接】
            mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
            mUsapPoolSocket =
                    Zygote.createManagedSocketFromInitSocket(
                            Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
        } else { //辅 zygote
            mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);
            mUsapPoolSocket =
                    Zygote.createManagedSocketFromInitSocket(
                            Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
        }

        //获取 非专用应用进程池 配置,还是通过系统配置 SystemPropertice 获取
        
        fetchUsapPoolPolicyProps();
    }
}



//最重要的还是进入 poll 轮训【关于高并发 IO 多路复用,参考链接】
Runnable runSelectLoop(String abiList) {

    while(true){
        //每一次轮训且超过一分钟都更新 USAP 配置
        fetchUsapPoolPolicyPropsWithMinInterval

        //系统调用 poll 处理文件描述符 fd
        //Os.poll 返回值0:表示处理超时或非阻塞状态没有可处理的文件描述符
        pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
        
        ... etc
        
        //还有一个需要关注的就是返回值,类型是 Runnable
        //这是在特殊情况下发生重置 USAP,command 的内容是:
        
        final Runnable command = fillUsapPool(sessionSocketRawFDs, isPriorityRefill);
        if (command != null) {
            return command;
        }
}
创建 System Server
//ZygoteInit.java


private static Runnable forkSystemServer(String abiList, String socketName,
                                             ZygoteServer zygoteServer) {
                                             
    
    //启动参数
    String[] args = {
                "--setuid=1000", //linux 中不同 uid 可以代表拥有不同的权限
                "--setgid=1000",
                "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
                        + "1024,1032,1065,3001,3002,3003,3005,3006,3007,3009,3010,3011,3012",
                "--capabilities=" + capabilities + "," + capabilities,
                "--nice-name=system_server",
                "--runtime-args",
                "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
                "com.android.server.SystemServer",
     };
     

    //省略参数构造过程
    ZygoteArguments parsedArgs;
    
    //创建服务进程,还是调用 native 方法
    
    pid = Zygote.forkSystemServer(
        parsedArgs.mUid, parsedArgs.mGid,
        parsedArgs.mGids,
        parsedArgs.mRuntimeFlags,
        null,
        parsedArgs.mPermittedCapabilities,
        parsedArgs.mEffectiveCapabilities);
     
    
    if (pid == 0) {
        //???还会有第二个 zygote 进程,这是什么操作???
        //看看官方描述:We determine this by comparing the device ABI list with this zygotes list. 
        //            If this zygote supports all ABIs this device supports, there won't be another zygote.
        if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }

        zygoteServer.closeServerSocket();
        //继续把参数分发给系统服务进程,这里做的事情比较多了
        
        return handleSystemServerProcess(parsedArgs);
    }
}
//RuntimeInit.java
protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
        String[] argv, ClassLoader classLoader) {

    //设置运行目标版本
    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
    //通过启动类名找到此类,由类加载器加载并调用其 main 方法
    return findStaticMain(args.startClass, args.startArgs, classLoader);
}
//RuntimeInit.java
protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
  
    //常规方法,只是执行 classloader
    Class cl = Class.forName(className, true, classLoader);
    Method m = cl.getMethod("main", new Class[] { String[].class });
    
        //因为当前是在 zygote 进程创建 SystemServer,在此流程中本次执行我们认为参数 className="com.android.internal.os.SystemServer"
    return new MethodAndArgsCaller(m, argv);
}

到这里 SystemServer 已经创建完成,接下来是通过 MethodAndArgsCaller 方法执行其中的 main 方法,源码路径是/frameworks/base/services/java/com/android/server/SystemServer.java。

那么本节笔记到此,我们下周再见。

附加 参考链接
  • Androi.bp:bp 文件,替换 .mk 的配置文,由 https://github.com/palantir/blueprint 框架解析
  • Android.mk:mk 文件,Android 程序编译
  • lmkd:low memory killer deamon 低内存终止守护进程
  • Apex:Android pony express 解决较低级别系统模块的安装流程 https://source.android.google.cn/devices/tech/ota/apex?hl=zh-cn
  • syspro 文件:系统共享信息的属性配置文件,通常作为系统 API 实现 https://source.android.google.cn/devices/architecture/sysprops-apis?hl=zh-cn#:~:text=一个,Sysprop%20说明文件包含一条属性消息,用来描述一组属性%E3%80%82
  • ABI:与 CPU 指令集相关 https://developer.android.google.cn/ndk/guides/abis?hl=zh-cn
  • fd :文件描述符 https://www.cnblogs.com/cscshi/p/15705033.html
  • Linux IO 多路复用:select、poll、epoll https://cloud.tencent.com/developer/article/1005481
  • MTE:memory tagging extension 内存标签扩展
  • 已加标记指针:https://source.android.google.cn/devices/tech/debug/tagged-pointers?hl=zh-cn
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1028047.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号