Android init 进程的启动(Android 10)

文章详细阐述了Android系统从按下电源键开始的启动流程,包括Bootloader加载Linux内核,内核启动Init进程,接着Init进程执行如servicemanager、Zygote和SystemServer的启动。Init进程在Linux用户空间中是第一个进程,负责挂载目录,初始化SELinux,并根据init.rc文件执行各种服务和设置。文章还介绍了init.rc文件的内容和作用,以及rc文件的语法解析,展示了init进程如何响应系统事件并管理其他进程和服务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android init 进程的启动(Android 10)

1 系统启动流程简析

在分析 Init 进程的启动流程前,我们先来看一下Android系统开机启动流程,经历了哪些关键的步骤,Init 进程时从哪里开始被启动的。

1.1 启动电源

当电源按下时引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序Bootloader到RAM,然后执行。

1.2 引导程序Bootloader

引导程序是在Android操作系统开始运行前的一个小程序,它的主要作用是把系统OS拉起来并运行。

1.3 Linux Kernel启动

内核kernel启动时,设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第一个进程。

1.4 Init进程启动

Init 进程作为 Android 系统中用户空间的第一个进程,它在整个Android系统中扮演了重要的角色,比如负责启动servicemanager(binder 服务管家)、创建 Zygote 进程(Java 进程的鼻祖)、启动属性服务、初始化 Selinux等。

1.5.1 servicemanager 启动(binder 管家)

1.5.2 Zygote 进程启动

1.6 SystemServer 进程启动

1.7 应用进程启动

2 Init 进程

Init 进程时Linux系统中用户空间的第一个进程,pid为1,在kernel启动后,会调用 /system/core/init/main.cpp的main()方法,由此启动 init 进程。

2.1 main.cpp#main()

首次进入main()函数会先调用FirstStageMain函数, 在FirstStageMain函数中,完成相关文件目录、分区的挂载后,会再通过 execv(path, const_cast<char**>(args)); 的方式,携带指定参数再次执行到这个main函数,进入selinux_setup、second_stage、subcontext等阶段。

//system/core/init/main.cpp
int main(int argc, char** argv) {
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }
	// 参数长度大于1, 在FirstStageMain函数中通过,会通过 execv(path, const_cast<char**>(args)); 的方式,携带置顶参数再次执行到这个main函数
    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
        		// 初始化 kernel log
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap function_map;
            // 4 
            return SubcontextMain(argc, argv, &function_map);
        }
		// 2.初始化 selinux
        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }
		// 3.进入 SecondStageMain
        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }
	// 进入 1.FirstStageMain
    return FirstStageMain(argc, argv);
}

2.2 first_stage_init.cpp#FirstStageMain()

//system/core/init/first_stage_init.cpp
int FirstStageMain(int argc, char** argv) {
    // 。。。
	// 创建、挂载系统相关目录并赋予权限
    CHECKCALL(clearenv());
    CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));
    // Get the basic filesystem setup we need put together in the initramdisk
    // on / and then we'll let the rc file figure out the rest.
    CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
    CHECKCALL(mkdir("/dev/pts", 0755));
    CHECKCALL(mkdir("/dev/socket", 0755));
    CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
#define MAKE_STR(x) __STRING(x)
    CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
#undef MAKE_STR
    // Don't expose the raw commandline to unprivileged processes.
    CHECKCALL(chmod("/proc/cmdline", 0440));
    gid_t groups[] = {AID_READPROC};
    CHECKCALL(setgroups(arraysize(groups), groups));
    CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
    CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));

    CHECKCALL(mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11)));

    if constexpr (WORLD_WRITABLE_KMSG) {
        CHECKCALL(mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11)));
    }

    CHECKCALL(mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8)));
    CHECKCALL(mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9)));

    // This is needed for log wrapper, which gets called before ueventd runs.
    CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2)));
    CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3)));

		// 以下挂载操作在 first stage init 完成,以便可以挂载 /mnt/{vendor,product}/ 的子目录,
		// 其他挂载则可以放在rc文件中完成
		// 下面的这些挂载是在第一阶段初始化中完成的,以便first stage 可以挂载 /mnt/{vendor,product}/ 的子目录。 
		// first stage 不需要的其他挂载,应该在 RC 文件中完成
    // 挂载的设备的暂存区域由 vold 管理
    CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                    "mode=0755,uid=0,gid=1000"));
    // /mnt/vendor is used to mount vendor-specific partitions that can not be
    // part of the vendor partition, e.g. because they are mounted read-write.
    CHECKCALL(mkdir("/mnt/vendor", 0755));
    // /mnt/product is used to mount product-specific partitions that can not be
    // part of the product partition, e.g. because they are mounted read-write.
    CHECKCALL(mkdir("/mnt/product", 0755));
    // /apex is used to mount APEXes
    CHECKCALL(mount("tmpfs", "/apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                    "mode=0755,uid=0,gid=0"));
    // /debug_ramdisk is used to preserve additional files from the debug ramdisk
    CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                    "mode=0755,uid=0,gid=0"));
#undef CHECKCALL

    SetStdioToDevNull(argv);
    // 现在 tmpfs 挂载在 /dev 上,系统中存在 /dev/kmsg,我们现在可以与外界交流了...
    // 初始化内核日志
    InitKernelLogging(argv);

    if (!errors.empty()) {
        for (const auto& [error_string, error_errno] : errors) {
            LOG(ERROR) << error_string << " " << strerror(error_errno);
        }
        LOG(FATAL) << "Init encountered errors starting first stage, aborting";
    }
    
    LOG(INFO) << "init first stage started!";
		// 完成分区挂载工作
    if (!DoFirstStageMount()) {
        LOG(FATAL) << "Failed to mount required partitions early ...";
    }
    //
    SetInitAvbVersionInRecovery();

    static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
    uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
    setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);

	// 一旦第一阶段 init 完成,它就会使用 “selinux_setup” 参数执行 /system/bin/init
	// 这个步骤是选择性地编译 SELinux 并将其加载到系统上的地方。
    const char* path = "/system/bin/init";
    const char* args[] = {path, "selinux_setup", nullptr};
    execv(path, const_cast<char**>(args));

    return 1;
}
DoFirstStageMount()

完成分区挂载工作

// system/core/init/first_stage_mount.cpp
bool FirstStageMount::DoFirstStageMount() {
    if (!IsDmLinearEnabled() && fstab_.empty()) {
        // Nothing to mount.
        LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)";
        return true;
    }

    if (!InitDevices()) return false;

    if (!CreateLogicalPartitions()) return false;

    if (!MountPartitions()) return false;

    return true;
}

2.3 selinux.cpp#SetupSelinux()

执行 /system/bin/init 脚本,传递 selinux_setup作为参数

// system/core/init/selinux.cpp
int SetupSelinux(char** argv) {
    InitKernelLogging(argv);
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
    }
    // 设置 SELinux,加载 SELinux 策略
    SelinuxSetupKernelLogging();
    SelinuxInitialize();
    
	//使用 “second_stage” 参数执行 /system/bin/init,此时进入 second_stage
    const char* path = "/system/bin/init";
    const char* args[] = {path, "second_stage", nullptr};
    execv(path, const_cast<char**>(args));
    return 1;
}

2.4 init.cpp#SecondStageMain()

// system/core/init/init.cpp
int SecondStageMain(int argc, char** argv) {

    SetStdioToDevNull(argv);
    InitKernelLogging(argv);
    LOG(INFO) << "init second stage started!";

    // 设置init进程和它fork出来的子进程的oom_adj, init 进程的pid为1,/proc/{pid}/oom_score_adj
    if (auto result = WriteFile("/proc/1/oom_score_adj", "-1000"); !result) {
        LOG(ERROR) << "Unable to write -1000 to /proc/1/oom_score_adj: " << result.error();
    }

    // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
    GlobalSeccomp();

    // Set up a session keyring that all processes will have access to. It
    // will hold things like FBE encryption keys. No process should override
    // its session keyring.
    keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);

    // Indicate that booting is in progress to background fw loaders, etc.
    close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
		
		// 属性服务初始化
    property_init();

    // If arguments are passed both on the command line and in DT,
    // properties set in DT always have priority over the command-line ones.
    process_kernel_dt();
    process_kernel_cmdline();

    // Propagate the kernel variables to internal variables
    // used by init as well as the current required properties.
    export_kernel_boot_props();

    // Make the time that init started available for bootstat to log.
    property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
    property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));

    // Set libavb version for Framework-only OTA match in Treble build.
    const char* avb_version = getenv("INIT_AVB_VERSION");
    if (avb_version) property_set("ro.boot.avb_version", avb_version);

    // See if need to load debug props to allow adb root, when the device is unlocked.
    const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
    if (force_debuggable_env && AvbHandle::IsDeviceUnlocked()) {
        load_debug_prop = "true"s == force_debuggable_env;
    }

    // Clean up our environment.
    unsetenv("INIT_STARTED_AT");
    unsetenv("INIT_SELINUX_TOOK");
    unsetenv("INIT_AVB_VERSION");
    unsetenv("INIT_FORCE_DEBUGGABLE");

    // Now set up SELinux for second stage.
    SelinuxSetupKernelLogging();
    SelabelInitialize();
    SelinuxRestoreContext();

    Epoll epoll;
    if (auto result = epoll.Open(); !result) {
        PLOG(FATAL) << result.error();
    }

    InstallSignalFdHandler(&epoll);

    property_load_boot_defaults(load_debug_prop);
    UmountDebugRamdisk();
    fs_mgr_vendor_overlay_mount_all();
    export_oem_lock_status();
    // 启动属性服务 PropertyService
    StartPropertyService(&epoll);
    MountHandler mount_handler(&epoll);
    set_usb_controller();

    const BuiltinFunctionMap function_map;
    Action::set_function_map(&function_map);
    if (!SetupMountNamespaces()) {
        PLOG(FATAL) << "SetupMountNamespaces failed";
    }

    subcontexts = InitializeSubcontexts();

	// 开始实例化 ActionManager、ServiceList,用于处理 rc文件中的关键字操作
    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();
	// 加载rc启动脚本
    LoadBootScripts(am, sm);

    // Turning this on and letting the INFO logging be discarded adds 0.2s to
    // Nexus 9 boot time, so it's disabled by default.
    if (false) DumpState();

    // Make the GSI status available before scripts start running.
    if (android::gsi::IsGsiRunning()) {
        property_set("ro.gsid.image_running", "1");
    } else {
        property_set("ro.gsid.image_running", "0");
    }

    am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
	// 执行 rc 文件中触发器为 on early-init 的语句
    am.QueueEventTrigger("early-init");

    // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
    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");
    Keychords keychords;
    am.QueueBuiltinAction(
        [&epoll, &keychords](const BuiltinArguments& args) -> Result<Success> {
            for (const auto& svc : ServiceList::GetInstance()) {
                keychords.Register(svc->keycodes());
            }
            keychords.Start(&epoll, HandleKeychord);
            return Success();
        },
        "KeychordInit");
    am.QueueBuiltinAction(console_init_action, "console_init");

    // 执行 rc 文件中触发器为 on init 的语句
    am.QueueEventTrigger("init");

    // Starting the BoringSSL self test, for NIAP certification compliance.
    am.QueueBuiltinAction(StartBoringSslSelfTest, "StartBoringSslSelfTest");

    // 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");

    // 在启动其他系统服务之前初始化binder程序
    am.QueueBuiltinAction(InitBinder, "InitBinder");

    // Don't mount filesystems or start core system services in charger mode.
    std::string bootmode = GetProperty("ro.bootmode", "");
    if (bootmode == "charger") {
    // 执行 rc 文件中触发器为 on charger 的语句
        am.QueueEventTrigger("charger");
    } else {
    // 执行 rc 文件中触发器为 on late-init 的语句
        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) {
        // By default, sleep until something happens.
        auto epoll_timeout = std::optional<std::chrono::milliseconds>{};

        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_action_time = HandleProcessActions();

                // If there's a process that needs restarting, wake up in time for that.
                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 there's more work to do, wake up again immediately.
            if (am.HasMoreCommands()) epoll_timeout = 0ms;
        }
			// 等待事件发生
        if (auto result = epoll.Wait(epoll_timeout); !result) {
            LOG(ERROR) << result.error();
        }
    }

    return 0;
}
SelabelInitialize()
StartPropertyService()
LoadBootScripts()
QueueEventTrigger
epoll.Wait

通过上面的流程,我们可以得知 init 进程的主要工作可以分为4个阶段,主要完成了以下几件事:

  1. 创建一些文件夹并挂载设备、分区
  2. 设置 SElinux 机制
  3. 初始化和启动属性服务
  4. 解析init.rc配置文件(触发脚本,如启动zygote进程)
  5. 响应rc文件中配置的相关事件

3 init .rc 文件

# system/core/rootdir/init.rc
# inport 引入其他rc文件
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc

# Cgroups are mounted right before early-init using list from /etc/cgroups.json
on early-init
    # Disable sysrq from keyboard
    write /proc/sys/kernel/sysrq 0
    # Set the security context of /adb_keys if present.
    restorecon /adb_keys
    # Set the security context of /postinstall if present.
    restorecon /postinstall
    mkdir /acct/uid

    # 省略。。。

    start ueventd
    exec_start apexd-bootstrap

on init
    sysclktz 0
    # Mix device-specific information into the entropy pool
    copy /proc/cmdline /dev/urandom
    copy /system/etc/prop.default /dev/urandom

    # Start logd before any other services run to ensure we capture all of their logs.
    start logd

    # Start essential services.
    # 启动 servicemanager、hwservicemanager、vndservicemanager
    start servicemanager
    start hwservicemanager
    start vndservicemanager

# Healthd can trigger a full boot from charger mode by signaling this
# property when the power button is held.
on property:sys.boot_from_charger_mode=1
    class_stop charger
    trigger late-init

on load_persist_props_action
    load_persist_props
    start logd
    start logd-reinit

# Indicate to fw loaders that the relevant mounts are up.
on firmware_mounts_complete
    rm /dev/.booting

# 挂载文件系统和启动核心服务
on late-init
    trigger early-fs
    trigger fs
    trigger post-fs
    trigger late-fs
    trigger post-fs-data
    trigger load_persist_props_action
    trigger zygote-start
    trigger firmware_mounts_complete
    trigger early-boot
    trigger boot

on early-fs
    start vold

on post-fs
   # 省略

# 建议从后 fs 数据中放置不必要的数据/初始化
# 在设备的 init.rc 中启动zygote以解锁zygote启动。
on zygote-start && property:ro.crypto.state=unencrypted
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

on zygote-start && property:ro.crypto.state=unsupported
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
    # A/B 升级验证,标记是否成功开机
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

on boot
    # basic network init
    ifup lo
    hostname localhost
    domainname localdomain

    # IPsec SA default expiration length
    write /proc/sys/net/core/xfrm_acq_expires 3600

    # Memory management.  
    write /proc/sys/vm/overcommit_memory 1
    write /proc/sys/vm/min_free_order_shift 4
    chown root system /sys/module/lowmemorykiller/parameters/adj
    chmod 0664 /sys/module/lowmemorykiller/parameters/adj
    chown root system /sys/module/lowmemorykiller/parameters/minfree
    chmod 0664 /sys/module/lowmemorykiller/parameters/minfree

    # System server manages zram writeback
    chown root system /sys/block/zram0/idle
    chmod 0664 /sys/block/zram0/idle
    chown root system /sys/block/zram0/writeback
    chmod 0664 /sys/block/zram0/writeback

    # Tweak background writeout
    write /proc/sys/vm/dirty_expire_centisecs 200
    write /proc/sys/vm/dirty_background_ratio  5


    chown system system /sys/class/leds/vibrator/trigger
    chown system system /sys/class/leds/vibrator/activate
    chown system system /sys/class/leds/vibrator/brightness
    chown system system /sys/class/leds/vibrator/duration
    chown system system /sys/class/leds/vibrator/state
    chown system system /sys/class/timed_output/vibrator/enable
    chown system system /sys/class/leds/keyboard-backlight/brightness
    chown system system /sys/class/leds/lcd-backlight/brightness
    chown system system /sys/class/leds/button-backlight/brightness
    chown system system /sys/class/leds/jogball-backlight/brightness
    chown system system /sys/class/leds/red/brightness
    chown system system /sys/class/leds/green/brightness
    chown system system /sys/class/leds/blue/brightness
    chown system system /sys/class/leds/red/device/grpfreq
    chown system system /sys/class/leds/red/device/grppwm
    chown system system /sys/class/leds/red/device/blink
    chown system system /sys/module/sco/parameters/disable_esco
    chown system system /sys/kernel/ipv4/tcp_wmem_min
    chown system system /sys/kernel/ipv4/tcp_wmem_def
    chown system system /sys/kernel/ipv4/tcp_wmem_max
    chown system system /sys/kernel/ipv4/tcp_rmem_min
    chown system system /sys/kernel/ipv4/tcp_rmem_def
    chown system system /sys/kernel/ipv4/tcp_rmem_max
    chown root radio /proc/cmdline

    # Define default initial receive window size in segments.
    setprop net.tcp.default_init_rwnd 60

    # Start standard binderized HAL daemons
    class_start hal

    class_start core

on nonencrypted
    class_start main
    class_start late_start

on property:sys.init_log_level=*
    loglevel ${sys.init_log_level}

on charger
    class_start charger

on property:vold.decrypt=trigger_load_persist_props
    load_persist_props
    start logd
    start logd-reinit

on property:vold.decrypt=trigger_post_fs_data
    trigger post-fs-data
    trigger zygote-start

on property:vold.decrypt=trigger_restart_min_framework
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier
    class_start main

on property:vold.decrypt=trigger_restart_framework
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier
    class_start_post_data hal
    class_start_post_data core
    class_start main
    class_start late_start
    setprop service.bootanim.exit 0
    start bootanim

on property:vold.decrypt=trigger_shutdown_framework
    class_reset late_start
    class_reset main
    class_reset_post_data core
    class_reset_post_data hal

on property:sys.boot_completed=1
    bootchart stop
    # Setup per_boot directory so other .rc could start to use it on boot_completed
    exec - system system -- /bin/rm -rf /data/per_boot
    mkdir /data/per_boot 0700 system system

# system server cannot write to /proc/sys files,
# and chown/chmod does not work for /proc/sys/ entries.
# So proxy writes through init.
on property:sys.sysctl.extra_free_kbytes=*
    write /proc/sys/vm/extra_free_kbytes ${sys.sysctl.extra_free_kbytes}

# "tcp_default_init_rwnd" Is too long!
on property:sys.sysctl.tcp_def_init_rwnd=*
    write /proc/sys/net/ipv4/tcp_default_init_rwnd ${sys.sysctl.tcp_def_init_rwnd}

on property:security.perf_harden=0
    write /proc/sys/kernel/perf_event_paranoid 1
    write /proc/sys/kernel/perf_event_max_sample_rate ${debug.perf_event_max_sample_rate:-100000}
    write /proc/sys/kernel/perf_cpu_time_max_percent ${debug.perf_cpu_time_max_percent:-25}
    write /proc/sys/kernel/perf_event_mlock_kb ${debug.perf_event_mlock_kb:-516}

on property:security.perf_harden=1
    write /proc/sys/kernel/perf_event_paranoid 3

# on shutdown
service ueventd /system/bin/ueventd
    class core
    critical
    seclabel u:r:ueventd:s0
    shutdown critical

service console /system/bin/sh
    class core
    console
    disabled
    user shell
    group shell log readproc
    seclabel u:r:shell:s0
    setenv HOSTNAME console

on property:ro.debuggable=1
    # Give writes to anyone for the trace folder on debug builds.
    # The folder is used to store method traces.
    chmod 0773 /data/misc/trace
    # Give reads to anyone for the window trace folder on debug builds.
    chmod 0775 /data/misc/wmtrace
    start console

service flash_recovery /system/bin/install-recovery.sh
    class main
    oneshot

4 rc文件语法解析

Android init.rc 文件分析

总结

init 进程(pid=1)是 Linux 系统中用户空间的第一个进程,主要工作如下:

  • 创建一块共享的内存空间,用于属性服务器;
  • 解析各个 rc 文件,并启动相应属性服务进程;
  • 初始化 epoll,依次设置 signal、property、keychord 这 3 个 fd 可读时相对应的回调函数;
  • 进入无限循环状态,执行如下流程:
    • 检查 action_queue 列表是否为空,若不为空则执行相应的 action;
    • 检查是否需要重启的进程,若有则将其重新启动;
    • 进入 epoll_wait 等待状态,直到系统属性变化事件(property_set 改变属性值),或者收到子进程的信号 SIGCHLD,再或者 keychord 键盘输入事件,则会退出等待状态,执行相应的回调函数。

可见 init 进程在开机之后的核心工作就是响应 property 变化事件和回收僵尸进程。当某个进程调用 property_set 来改变一个系统属性值时,系统会通过 socket 向 init 进程发送一个 property 变化的事件通知,那么 property fd 会变成可读,init 进程采用 epoll 机制监听该 fd 则会触发回调 handle_property_set_fd()方法。
回收僵尸进程,在 Linux 内核中,如父进程不等待子进程的结束直接退出,会导致 子进程在结束后变成僵尸进程,占用系统资源。为此,init 进程专门安装了 SIGCHLD 信号接收器,当某些子进程退出时发现其父进程已经退出,则会向 init 进程发送 SIGCHLD 信号,init 进程调用回调方法 handle_signal()来回收僵尸子 进程。

6 参考链接

Android 开机解析
Android 系统启动流程
init.rc 文件语法解析
Android framework 精编内核解析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值