Android Framework 基盤 - 初期化プロセス

        Android の init プロセスは、Android システムの最初のユーザー空間プロセスであり、システム全体の起動プロセスでもあります。これは、Linux システムの init プロセス (プロセス ID は 1) のインスタンスであり、システムの初期化と Android システム全体のさまざまなコンポーネントの起動を担当します。

        init プロセスは、システムの起動時にカーネルによってロードされて実行され、Android init スクリプト (/system/etc/init ディレクトリにある) を読み取り、スクリプトの指示に従ってシステムを初期化します。

Android の init プロセスの主な役割には次のようなものがあります。

1) さまざまな主要なサービス (Zygote、SurfaceFlinger、PackageManager など) およびデーモン プロセス (adbd、rild など) を開始して実行します。

2) ファイル システムとデバイス ノードをマウントし、ファイルのアクセス許可を設定します。

3) IO スケジューリングの設定、ハードウェア ドライバーのロードなど、各デバイスのハードウェア初期化を実行します。

4) アプリケーションプロセス、システムサービスプロセスなど、Android システムのさまざまなコンポーネントを作成して起動します。

5) メモリ不足の処理、システムの再起動など、システム動作中にいくつかのイベントと信号を処理します。

        一般に、Android の init プロセスは、システムの起動プロセス全体において重要な役割を果たしており、システムが初期化されて正常に起動できるように、システム内のさまざまなコンポーネントを調整および管理する責任があります。

1. ソースコード分析

        まず、エントリ関数として main() 関数が呼び出されますが、Android のバージョンによって若干の違いがあるため、まずは Android 9.0 バージョンの init 初期化について見てみましょう。

1. Android 9.0の初期化

init.cpp

ソースの場所: /system/core/init/init.cpp

int main(int argc, char** argv) {
    bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
    // 第一次挂载
    if (is_first_stage) {
        ……
        // 挂载和创建一系列文件夹
        // 初始化Kernel日志
        InitKernelLogging(argv);
        LOG(INFO) << "init first stage started!";
        ……
    }

    // 此时,我们处于init的第二阶段。
    InitKernelLogging(argv);
    LOG(INFO) << "init second stage started!";
    ……
    // 创建一块共享的内存空间,用于属性服务
    property_init();
    ……
    // 初始化epoll功能
    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    if (epoll_fd == -1) {
        PLOG(FATAL) << "epoll_create1 failed";
    }
    // 初始化子进程退出的信号处理函数,并调用epoll_ctl设置signal fd可读的回调函数		
    sigchld_handler_init();
    ……
    // 加载default.prop文件
    property_load_boot_defaults();
    export_oem_lock_status();
    // 启动属性服务器,此处会调用epoll_ctl设置property fd可读的回调函数
    start_property_service();
    set_usb_controller();
    ……
    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();
    // 该方法内解析init.rc文件
    LoadBootScripts(am, sm);

    // 执行rc文件中触发器为on early-init的语句
    am.QueueEventTrigger("early-init");
    // 等冷插拔设备初始化完成
    am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
    // ... so that we can start queuing up actions that require stuff from /dev.
    am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
    am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
    am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
    // 设备组合键的初始化操作,此处会调用epoll_ctl设置keychord fd可读的回调函数
    am.QueueBuiltinAction(keychord_init_action, "keychord_init");
    // 屏幕上显示Android静态Logo
    am.QueueBuiltinAction(console_init_action, "console_init");
  
    // 执行rc文件中触发器为on init的语句
    am.QueueEventTrigger("init");

    // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
    // wasn't ready immediately after wait_for_coldboot_done
    am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");

    // 当处于充电模式,则charger加入执行队列;否则late-init加入队列。
    std::string bootmode = GetProperty("ro.bootmode", "");
    if (bootmode == "charger") {
        am.QueueEventTrigger("charger");
    } else {
        am.QueueEventTrigger("late-init");
    }

    // Run all property triggers based on current state of the properties.
    am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");

    while (true) {
        // 默认情况下,休眠直到有事情发生
        int epoll_timeout_ms = -1;

        if (do_shutdown && !shutting_down) {
            do_shutdown = false;
            if (HandlePowerctlMessage(shutdown_command)) {
                shutting_down = true;
            }
        }

        if (!(waiting_for_prop || Service::is_exec_service_running())) {
            am.ExecuteOneCommand();
        }
        if (!(waiting_for_prop || Service::is_exec_service_running())) {
            if (!shutting_down) {
                // 根据需要重启服务
                auto next_process_restart_time = RestartProcesses();

                // 如果有一个进程需要重新启动,及时唤醒
                if (next_process_restart_time) {
                    epoll_timeout_ms = std::chrono::ceil<std::chrono::milliseconds>(*next_process_restart_time - boot_clock::now()).count();
                    if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
                }
            }

            // 如果有更多的工作要做,马上唤醒
            if (am.HasMoreCommands()) epoll_timeout_ms = 0;
        }
        
        epoll_event ev;
        // 循环等待事件发生
        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
        if (nr == -1) {
            PLOG(ERROR) << "epoll_wait failed";
        } else if (nr == 1) {
            ((void (*)()) ev.data.ptr)();
        }
    }

    return 0;
}

        次に、Android 12 の init 初期化プロセスを見てみましょう。

2. Android 12の初期化

        まず第一に、彼の最初の main() 関数は init.cpp ではなく main.cpp にあります。

main.cpp

ソースの場所: /system/core/init/main.cpp

int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif
    // 稍后将恢复Boost prio
    // 设置进程的优先级
    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);
        }

        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }

    return FirstStageMain(argc, argv);
}

        これは Android システム全体のエントリ ポイントです。main()これには、プロセスのエントリ関数である関数が含まれています。このファイルでは、主にいくつかの初期化準備が実行され、その後、さまざまなコマンド ライン パラメーターに従ってさまざまなロジック処理コードに分散されます。

サブコンテキスト.cpp

ソースの場所: /system/core/init/subcontext.cpp

int SubcontextMain(int argc, char** argv, const BuiltinFunctionMap* function_map) {
    if (argc < 4) LOG(FATAL) << "Fewer than 4 args specified to subcontext (" << argc << ")";
    
    auto context = std::string(argv[2]);
    auto init_fd = std::atoi(argv[3]);

    SelabelInitialize();

    trigger_shutdown = [](const std::string& command) { shutdown_command = command; };

    auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
    // 在主循环之前恢复prio
    setpriority(PRIO_PROCESS, 0, 0);
    subcontext_process.MainLoop();
    return 0;
}

        サブコンテキスト(subcontext)の初期化実装についてです。Android システムでは、サブコンテキストは、init プロセスによって作成および管理される独立したサブプロセスです。サブコンテキストは通常​​、いくつかの特別な属性の設定、いくつかの特定のサービスの開始など、システムの初期化中に初期のタスクを実行するために使用されます。

セリナックス.cpp

ソースの場所: /system/core/init/selinux.cpp

int SetupSelinux(char** argv) {
    ……
    // 挂载缺失的系统分区
    MountMissingSystemPartitions();

    // 设置 SELinux 内核日志记录。
    SelinuxSetupKernelLogging();

    // 读取策略文件
    std::string policy;
    ReadPolicy(&policy);

    // 根据需要创建辅助类
    auto snapuserd_helper = SnapuserdSelinuxHelper::CreateIfNeeded();
    ……
    // 加载 SELinux 策略
    LoadSelinuxPolicy(policy);

    ……
    // 设置 SELinux 强制执行
    SelinuxSetEnforcement();

    ……
    const char* path = "/system/bin/init";
    const char* args[] = {path, "second_stage", nullptr};
    // 执行 /system/bin/init
    execv(path, const_cast<char**>(args));
    ……

    return 1;
}

        これには、SELinux (Security-Enhanced Linux) セキュリティ メカニズムに関連する初期化ロジックが含まれています。

        SELinux は、強制アクセス制御 (MAC) メカニズムを実装する Linux カーネルのセキュリティ モジュールです。Androidシステムでは、システムのセキュリティを強化し、各種プロセス間のアクセスや操作を制限するためにSELinuxが広く使われています。このファイルには、SELinux の初期化に関連する関数、変数、ロジックが含まれます。具体的な実装は Android システムのバージョンとデバイスの要件によって異なり、SELinux の関連機能の設定と開始に使用されます。

first_stage_init.cpp

ソースの場所: /system/core/init/first_stage_init.cpp

int FirstStageMain(int argc, char** argv) {
    ……
}

        これは主に Android システムの第 1 フェーズの初期化の実装です。初期化の第 1 段階は、Linux カーネルのブートプロセス (Kernel Init Process) が実行された後、init プロセスが実行を開始する前の段階です。最も基本的なハードウェアの初期化とファイル システムのマウントのみを担当します。コードのこの部分は、実際には上記の Android 9.0 の if (is_first_stage) 部分のコードです。

init.cpp

ソースの場所: /system/core/init/init.cpp

int SecondStageMain(int argc, char** argv) {
    ……
    // 初始化Kernel日志
    InitKernelLogging(argv);
    LOG(INFO) << "init second stage started!";
    ……
    // 初始化系统属性
    PropertyInit();
    ……
    // 安装信号文件描述符处理程序
    InstallSignalFdHandler(&epoll);
    // 启动属性服务
    StartPropertyService(&property_fd);
    // 记录系统启动时间
    RecordStageBoottimes(start_time);
    // 设置 USB 控制器
    SetUsbController();
    // 该方法内解析init.rc文件
    LoadBootScripts(am, sm);

    while (true) {
        // 默认情况下,休眠直到有事情发生
        auto epoll_timeout = std::optional<std::chrono::milliseconds>{};

        auto shutdown_command = shutdown_state.CheckShutdown();
        if (shutdown_command) {
            HandlePowerctlMessage(*shutdown_command);
            shutdown_state.set_do_shutdown(false);
        }

        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
            am.ExecuteOneCommand();
        }
        if (!IsShuttingDown()) {
            auto next_process_action_time = HandleProcessActions();

            // 如果有一个进程需要重新启动,及时唤醒
            if (next_process_action_time) {
                epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(*next_process_action_time - boot_clock::now());
                if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
            }
        }
  
        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;
        }
  
        auto pending_functions = epoll.Wait(epoll_timeout);
        if (!pending_functions.ok()) {
            LOG(ERROR) << pending_functions.error();
        } else if (!pending_functions->empty()) {
            // 我们总是在响应其他挂起函数之前收获子函数。这是为了防止其他守护进程看到服务已经退出并要求init通过ctl重新启动它的竞争。在init获取它之前启动。
            ReapAnyOutstandingChildren();
            for (const auto& function : *pending_functions) {
                (*function)();
             }
        }
        if (!IsShuttingDown()) {
            HandleControlMessages();
            SetUsbController();
        }
    }
    return 0;
}

        ここでは主にAndroidシステムのinitプロセスのメインロジック実装を行います。init プロセスは、Linux カーネルの起動後に最初のユーザー空間プロセスとして実行され、システム サービスの初期化、デバイス構成のロード、init.rc ファイルの解析、およびその他のシステム起動タスクを担当します。

要約する

        Android 12 では主に Android 9.0 の init.cpp 内の main() 関数のさまざまな機能を分割し、初期化作業を個別に完了していることがわかります。

おすすめ

転載: blog.csdn.net/c19344881x/article/details/131920906