init 进程启动过程

Android系统启动系列2 init进程 一 概述 init 进程是 Linux 系统中用户空间的第一个进程,进程号为1.当板子上电,bootloader 启动后,加载并启动 kernel,kernel 启动完后,在用户空间启动 init 进程,然后再通过 init 进程,来解析并读取 init.rc 中的相关配置,从而来启动其他相关进程以及其它操作。 init 进程被赋予了很多重要工作,它启动主要分为两个阶段: 第一阶段 ueventd/watchdogd跳转及环境变量设置 挂载文件系统并创建目录 初始化日志输出、挂载分区设备 启用SELinu 阅读详情

Android 系统启动系列文章:

首语

init进程是Android系统中用户空间的第一个进程,进程号为1,是Android系统启动的一个关键步骤,作为第一个进程,它的主要工作是创建Zygote和启动属性服务等。init进程是由多个源文件共同组成的,源码目录在system/core/init中。

源码分析

main(入口函数)

Linux内核加载完成后,在系统文件中寻找init.rc文件,并启动init进程。init进程的入口函数main。

源码路径:system/core/init/main.cpp

main函数根据参数分别执行:

  1. ueventd_main。init进程创建子进程ueventd,并将创建设备节点文件的工作交给veventd。veventd通过两种方式创建设备节点文件(冷启动和热启动)。
  2. FirstStageMain。启动第一阶段。
  3. SubcontextMain。初始化日志系统。
  4. SetupSelinux。加载Selinux规则,并设置Selinux日志,完成Selinux相关工作。
  5. SecondStageMain。启动第二阶段。
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#elif __has_feature(hwaddress_sanitizer)
    __hwasan_set_error_report_callback(AsanReportCallback);
#endif
    // Boost prio which will be restored later
    setpriority(PRIO_PROCESS, 0, -20);
    //当arg[0]的内容是"ueventd",strcmp的值为0,!strcmp的值为1,执行ueventd_main。veventd主要进行设备节点的创建、权限设置工作
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }

    //当传入的参数个数大于1
    if (argc > 1) {
        //参数为"subcontext",初始化日志系统
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();

            return SubcontextMain(argc, argv, &function_map);
        }

        //参数为"selinux_setup",启动Selinux安全策略
        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }

        //参数为"second_stage",启动init进程第二阶段
        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }

    //默认启动init进程第一阶段
    return FirstStageMain(argc, argv);
}
ueventd(节点创建)

ueventd_main 负责节点创建。

源码路径:system/core/init/ueventd.cpp

ueventd进程通过两种方式创建设备节点文件:

  1. 冷启动。统一创建好的文件节点如cpu频率等。
  2. 热启动。动态创建的节点如usb插拔等。
int ueventd_main(int argc, char** argv) {
    //创建的文件没有权限限制
    umask(000);

    android::base::InitLogging(argv, &android::base::KernelLogger);

    LOG(INFO) << "ueventd started!";

    SelinuxSetupKernelLogging();
    SelabelInitialize();

    std::vector<std::unique_ptr<UeventHandler>> uevent_handlers;

    auto ueventd_configuration = GetConfiguration();

    uevent_handlers.emplace_back(std::make_unique<DeviceHandler>(
            std::move(ueventd_configuration.dev_permissions),
            std::move(ueventd_configuration.sysfs_permissions),
            std::move(ueventd_configuration.subsystems), android::fs_mgr::GetBootDevices(), true));
    uevent_handlers.emplace_back(std::make_unique<FirmwareHandler>(
            std::move(ueventd_configuration.firmware_directories),
            std::move(ueventd_configuration.external_firmware_handlers)));
	//enable_modalias_handling=true,创建一个新的ModaliasHandler对象并添加到uevent_handlers中
    if (ueventd_configuration.enable_modalias_handling) {
        std::vector<std::string> base_paths = {"/odm/lib/modules", "/vendor/lib/modules"};
        uevent_handlers.emplace_back(std::make_unique<ModaliasHandler>(base_paths));
    }
    UeventListener uevent_listener(ueventd_configuration.uevent_socket_rcvbuf_size);

    //kColdBootDoneProp=false,冷启动
    if (!android::base::GetBoolProperty(kColdBootDoneProp, false)) {
        ColdBoot cold_boot(uevent_listener, uevent_handlers,
                           ueventd_configuration.enable_parallel_restorecon,
                           ueventd_configuration.parallel_restorecon_dirs);
        cold_boot.Run();
    }

    for (auto& uevent_handler : uevent_handlers) {
        uevent_handler->ColdbootDone();
    }

    // We use waitpid() in ColdBoot, so we can't ignore SIGCHLD until now.
    signal(SIGCHLD, SIG_IGN);
    // Reap and pending children that exited between the last call to waitpid() and setting SIG_IGN
    // for SIGCHLD above.
    while (waitpid(-1, nullptr, WNOHANG) > 0) {
    }

    // Restore prio before main loop
    //监听驱动的热插拔处理
    setpriority(PRIO_PROCESS, 0, 0);
    uevent_listener.Poll([&uevent_handlers](const Uevent& uevent) {
        for (auto& uevent_handler : uevent_handlers) {
            uevent_handler->HandleUevent(uevent);
        }
        return ListenerAction::kContinue;
    });

    return 0;
}

}  // namespace init
}  // namespace android
FirstStageMain(启动第一阶段)

init进程第一阶段主要进行挂载分区、创建设备节点和一些关键目录、初始化日志输出系统、启用Selinux安全策略。

源码路径:system/core/init/first_stage_init.cpp

挂载了tmpsfs、devpts、proc、sysfs和selinuxfs五种文件系统,这些都是系统运行时目录,系统停止时会消失。

挂载mnt和tmpfs,分别创建vendor和product目录。

 CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
 CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
 CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
 CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
 CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));

启动init进程,根据main函数,传入参数selinux_setup,执行SetupSelinux函数。

    const char* path = "/system/bin/init";
    const char* args[] = {path, "selinux_setup", nullptr};
    auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);
    close(fd);
    execv(path, const_cast<char**>(args));

    // execv() only returns if an error happened, in which case we
    // panic and never fall through this conditional.
    PLOG(FATAL) << "execv(\"" << path << "\") failed";

    return 1;
SetupSelinux(加载Selinux)

SetupSelinux主要做了初始化Selinux、加载Selinux并启动。

源码路径:system/core/init/selinux.cpp

    SelinuxSetupKernelLogging();

    LOG(INFO) << "Opening SELinux policy";

    PrepareApexSepolicy();

    // Read the policy before potentially killing snapuserd.
    std::string policy;
    ReadPolicy(&policy);
    CleanupApexSepolicy();

    auto snapuserd_helper = SnapuserdSelinuxHelper::CreateIfNeeded();
    if (snapuserd_helper) {
        // Kill the old snapused to avoid audit messages. After this we cannot
        // read from /system (or other dynamic partitions) until we call
        // FinishTransition().
        snapuserd_helper->StartTransition();
    }

    LoadSelinuxPolicy(policy); 		

传入参数second_stage,执行main函数,匹配参数执行SecondStageMain函数。

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

    // execv() only returns if an error happened, in which case we
    // panic and never return from this function.
    PLOG(FATAL) << "execv(\"" << path << "\") failed";

    return 1;
SecondStageMain(启动第二阶段)

启动第二阶段主要做了初始化属性系统、解析Selinux的匹配路径、处理子进程终止信号、启动系统属性服务、解析init.rc文件等。

代码路径:system/core/init/init.cpp

int SecondStageMain(int argc, char** argv) { 
    //初始化属性服务配置
	PropertyInit();
 	...
    //子进程信号处理函数,如果子进程异常退出,init进程会调用该函数设定的信号处理函数进行处理
    InstallSignalFdHandler(&epoll);
	//启动属性服务
 	StartPropertyService(&property_fd);
    ...
    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();
	//解析各个目录下的init.rc
    LoadBootScripts(am, sm);
    ...
    //重启终止进程
    auto next_process_action_time = HandleProcessActions();
}

static void InstallSignalFdHandler(Epoll* epoll) {
    ...
    auto handler = std::bind(HandleSignalFd, false);
    ...
}
static void HandleSignalFd(bool one_off) {
  	...
    switch (siginfo.ssi_signo) {
        case SIGCHLD:
            //找到终止进程服务并移除。system/core/init/sigchld_handler.cpp
            ReapAnyOutstandingChildren();
            break;
   	...
    }
}

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");
        }
        // late_import is available only in Q and earlier release. As we don't
        // have system_ext in those versions, skip late_import for system_ext.
        parser.ParseConfig("/system_ext/etc/init");
        if (!parser.ParseConfig("/vendor/etc/init")) {
            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);
    }
}

Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser;

    parser.AddSectionParser("service", std::make_unique<ServiceParser>(
                                               &service_list, GetSubcontext(), std::nullopt));
    parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, GetSubcontext()));
    parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));

    return parser;
}
属性服务

Windows有一个注册表管理器,内容采用键值对来记录用户、软件使用信息。即使软件或系统重启,还能根据之前注册表的记录,进行相应的初始化工作,Android提供一个类似的机制,称为属性服务。

init进程启动属性服务并分配内存,存储这些属性,需要直接读取。

源码路径:system/core/init/property_service.cpp

void PropertyInit() {
    ...
    CreateSerializedPropertyInfo();
    //__system_property_area_init() 初始化属性内存区域
    if (__system_property_area_init()) {
        LOG(FATAL) << "Failed to initialize property area";
    }
    if (!property_info_area.LoadDefaultPath()) {
        LOG(FATAL) << "Failed to load serialized property info file";
    }
    ...
}

void StartPropertyService(int* epoll_socket) {
    InitPropertySet("ro.property_service.version", "2");

    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {
        PLOG(FATAL) << "Failed to socketpair() between property_service and init";
    }
    *epoll_socket = from_init_socket = sockets[0];
    init_socket = sockets[1];
    StartSendingMessages();
	//创建非阻塞的socket
    if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                   false, 0666, 0, 0, {});
        result.ok()) {
        property_set_fd = *result;
    } else {
        LOG(FATAL) << "start_property_service socket creation failed: " << result.error();
    }
	//监听property_set_fd,socket变为server,成为属性服务。属性服务最多同时为8个设置属性的用户提供服务。
    listen(property_set_fd, 8);

    auto new_thread = std::thread{PropertyServiceThread};
    property_service_thread.swap(new_thread);
}

static void PropertyServiceThread() {
    Epoll epoll;
    if (auto result = epoll.Open(); !result.ok()) {
        LOG(FATAL) << result.error();
    }
    //Epoll是Linux内核为处理大批量文件描述符而作的改进。它是多路复用IO接口select/poll的增强版本,能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。保存数据类型是红黑树,查找速度快。
	//epoll监听property_set_fd,当property_set_fd有数据时,调用handle_property_set_fd函数处理
    if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd);
        !result.ok()) {
        LOG(FATAL) << result.error();
    }
	...
}

static void handle_property_set_fd() {
    ...
    switch (cmd) {
    case PROP_MSG_SETPROP: {
		...
        //封装处理
        uint32_t result =
                HandlePropertySet(prop_name, prop_value, source_context, cr, nullptr, &error);
		...
        break;
      }

}
uint32_t HandlePropertySet(const std::string& name, const std::string& value,
                           const std::string& source_context, const ucred& cr,
                           SocketConnection* socket, std::string* error) {
    ...
    //属性名称以"ctl."开头,为控制属性
    if (StartsWith(name, "ctl.")) {
        //设置控制属性
        return SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error);
    }
	//特殊属性sys.powerctl,可使设备重新启动。
    // sys.powerctl is a special property that is used to make the device reboot.  We want to log
    // any process that sets this property to be able to accurately blame the cause of a shutdown.
    if (name == "sys.powerctl") {
        ...
    }
    ...
    //普通属性
    return PropertySet(name, value, error);
}

static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
   ...
	//判断属性是否合法,实现规则在sytem/core/init/util.cpp
    if (!IsLegalPropertyName(name)) {
        *error = "Illegal property name";
        return PROP_ERROR_INVALID_NAME;
    }

    if (auto result = IsLegalPropertyValue(name, value); !result.ok()) {
        *error = result.error().message();
        return PROP_ERROR_INVALID_VALUE;
    }
	//从属性存储空间查找该属性
    prop_info* pi = (prop_info*) __system_property_find(name.c_str());
    //如果属性存在
    if (pi != nullptr) {
        //属性名称以"ro."开头,则表示只读,不能修改,直接返回
        // ro.* properties are actually "write-once".
        if (StartsWith(name, "ro.")) {
            *error = "Read-only property was already set";
            return PROP_ERROR_READ_ONLY_PROPERTY;
        }
		//属性存在,更新属性值
        __system_property_update(pi, value.c_str(), valuelen);
    } else {
        int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
        //属性不存在,添加属性
        if (rc < 0) {
            *error = "__system_property_add failed";
            return PROP_ERROR_SET_FAILED;
        }
    }
	//属性名称以"persist."开头,可写。
    // Don't write properties to disk until after we have read all default
    // properties to prevent them from being overwritten by default values.
    if (persistent_properties_loaded && StartsWith(name, "persist.")) {
        WritePersistentProperty(name, value);
    }
    // If init hasn't started its main loop, then it won't be handling property changed messages
    // anyway, so there's no need to try to send them.
    auto lock = std::lock_guard{accept_messages_lock};
    if (accept_messages) {
        PropertyChanged(name, value);
    }
    return PROP_SUCCESS;
}

Android系统属性分为普通属性和控制属性两种。

普通属性是用于描述设备或系统的某些特定信息,例如手机厂商、型号等。这些属性通常以特定的字符串作为前缀,例如"ro"、“persist” 等。

控制属性是用于执行某些命令的属性,例如启动或关闭某个服务。这些属性通常以"ctl.“作为前缀,例如"ctl.start”、"ctl.stop"等。

通过adb setprop/getprop命令,可以在Android系统中查看和设置系统属性。

adb shell setprop [key] [value]
adb shell getprop [prop_name [default]]

Android系统属性配置文件主要是***/default.prop和/system/build.prop***两个文件。

/default.prop文件位于/default.prop,包含了一些默认的系统属性,如ro.sf.cpu_name、ro.product.model等。

/system/build.prop文件位于/system/build.prop,包含了系统的一些详细配置信息,如ro.product.name、ro.product.cpu_abi等。

子进程信号处理

InstallSignalFdHandler函数用于设置子进程信号处理函数。主要防止init进程的子进程成为僵尸进程,为了防止僵尸进程出现,系统会在子进程暂停和终止的时候发出SIGCHLD 信号,InstallSignalFdHandler函数就是用来接收SIGCHLD 信号的(内部只处理进程终止的SIGCHLD 信号)。

假设init进程的某个子进程终止了,InstallSignalFdHandler函数调用HandleSignalFd函数,层层调用处理,找到终止的子进程服务并移除它。再重启子进程服务的启动脚本中带有onrestart的服务。

僵尸进程

在Unix/Linux中,父进程fork创建子进程,在子进程终止后,如果父进程不知道子进程已经终止了,这时子进程虽然退出了,但是系统进程表还保留它的信息,这个子进程就被称为僵尸进程。系统进程表是有限资源,如果系统进程表被僵尸进程耗尽的话,就不能创建新的进程了。

这里着重说明下fork。fork用于创建一个子进程(复制调用fork进程的堆栈等信息),它与原进程(调用fork进程)同时运行,原进程称为父进程。fork不需要参数并返回一个返回值。

  • 负值:创建子进程失败
  • 零:返回到新创建的子进程
  • 正值:返回父进程,该值包含创建子进程的进程ID

源码路径:system/core/init/sigchld_handler.cpp

void ReapAnyOutstandingChildren() {
    while (ReapOneProcess() != 0) {
    }
}

static pid_t ReapOneProcess() {
	...
    //找到服务
    service = ServiceList::GetInstance().FindService(pid, &Service::pid);
    ...
    //移除服务
    ServiceList::GetInstance().RemoveService(*service);
    ...
}
解析init.rc

init.rc是Android初始化语言(Android Init Language)编写的脚本,这种语言主要包含五种类型语句:Action、Command、Service、Option和Import。

以system/core/rootdir/init.rc文件为例。

on init
	sysclktz 0
...
service ueventd /sbin/ueventd
	class core
...

on init 是Action类型的语句,格式如下:

on <trigger> [&& <trigger>]*  //设置触发器
	<command>
	<command>	//动作出发要执行的命令

service ueventd /sbin/ueventd是Service类型的语句,格式如下:

service <name> <pathname> [ <argument> ]*  //<service name><执行程序路径><传递参数>
	<option>  //option是service的修饰词,影响什么时候,如何启动service
	<option>

每个服务对应一个rc文件,基本都被加载到/system/etc/init、/vendor/etc/init、/odm/etc/init、/product/etc/init等目录。

解析Service 类型语句

init.rc中的Action类型语句、Import类型语句和Service类型语句都有相应的文件来解析,如CreateParser函数中的ActionParser、ImportParser、ServiceParser。对应解析文件目录均在sytem/core/init下。

源码路径:system/core/init/service_parser.cpp

Result<void> ServiceParser::ParseSection(std::vector<std::string>&& args,
                                         const std::string& filename, int line) {
    //判断service是否有name和可执行程序
    if (args.size() < 3) {
        return Error() << "services must have a name and a program";
    }

    const std::string& name = args[1];
    //检查service的name是否有效
    if (!IsValidName(name)) {
        return Error() << "invalid service name '" << name << "'";
    }
	...
	//构造service对象,解析完所有数据后,调用EndSection函数
    service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args, from_apex_);
    return {};
}

Result<void> ServiceParser::EndSection() {
    ...
    //构造Service list对象
    service_list_->AddService(std::move(service_));
    ...
}

源码路径:system/core/init/service_list.cpp

void ServiceList::AddService(std::unique_ptr<Service> service) {
    //将services对象添加到Service链表中
    services_.emplace_back(std::move(service));
}
init启动Zygote

init进程会启动Zygote进程。我们分析下Zygote的启动脚本,以64位处理器为例。

脚本路径:system/core/rootdir/init.zygote64.rc

service zygote /system/bin/app_process64 -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 media.tuner
    onrestart restart netd
    onrestart restart wificond
    task_profiles ProcessCapacityHigh
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

上述脚本大致含义是创建名为zygote的进程,这个进程的执行程序路径为/system/bin/app_process64,后面的代码是传给app_process64的参数。class main表示zygote的classname是main。

在解析init.rc时,有以下一段Action类型语句,脚本路径:system/core/rootdir/init.rc

on nonencrypted
    class_start main
    class_start late_start

class_start是一个command,对应的函数为do_class_start, class_start main表示启动classname为main的Service,刚才分析zygote的classname为main,因此它会启动zygote进程。

do_class_start函数在builtins.cpp中。源码路径:system/core/init/builtins.cpp

static Result<void> do_class_start(const BuiltinArguments& args) {
    // Do not start a class if it has a property persist.dont_start_class.CLASS set to 1.
    if (android::base::GetBoolProperty("persist.init.dont_start_class." + args[1], false))
        return {};
    // Starting a class does not start services which are explicitly disabled.
    // They must  be started individually.
    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 {};
}

遍历ServiceList,执行StartIfNotDisabled函数。

如果没有在对应的rc文件中设置disable选项,zygote对应的rc文件没有设置disable选项,则会调用Start函数。

子进程启动,并进入该Service的的main函数中,对于zygote来说,执行程序路径是/system/bin/app_process64,对应的文件为app_main.cpp,进入app_main.cpp的main函数中,也是zygote的main函数。

源码路径:system/core/init/service.cpp

Result<void> Service::StartIfNotDisabled() {
    if (!(flags_ & SVC_DISABLED)) {
        return Start();
    } else {
        flags_ |= SVC_DISABLED_START;
    }
    return {};
}

Result<void> Service::Start() {
    ...
	//service 运行,则不启动
    // Running processes require no additional work --- if they're in the
    // process of exiting, we've ensured that they will immediately restart
    // on exit, unless they are ONESHOT. For ONESHOT service, if it's in
    // stopping status, we just set SVC_RESTART flag so it will get restarted
    // in Reap().
    if (flags_ & SVC_RUNNING) {
        if ((flags_ & SVC_ONESHOT) && disabled) {
            flags_ |= SVC_RESTART;
        }

        LOG(INFO) << "service '" << name_
                  << "' requested start, but it is already running (flags: " << flags_ << ")";

        // It is not an error to try to start a service that is already running.
        reboot_on_failure.Disable();
        return {};
    }
	...
	//判断service对应的执行文件是否存在,不存在则不启动该service
    struct stat sb;
    if (stat(args_[0].c_str(), &sb) == -1) {
        flags_ |= SVC_DISABLED;
        return ErrnoError() << "Cannot find '" << args_[0] << "'";
    }
	...
    pid_t pid = -1;
    if (namespaces_.flags) {
        pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr);
    } else {
        //如果子进程没有启动,则调用fork函数创建子进程
        pid = fork();
    }
	//当前代码逻辑在子进程运行
    if (pid == 0) {
        umask(077);
        //子进程启动
        RunService(override_mount_namespace, descriptors, std::move(pipefd));
        _exit(127);
    }

    if (pid < 0) {
        pid_ = 0;
        return ErrnoError() << "Failed to fork";
    }
	...
}

zygote的main函数源码如下,源码路径:frameworks\base\cmds\app_process\app_main.cpp

int main(int argc, char* const argv[])
{
	...
    if (zygote) {
        //启动zygote,细节会在Zygote进程启动过程中分析
        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.");
    }
}

init启动总结

init进程启动做了很多工作,总的来说有以下三点:

  1. 挂载分区、创建设备结点和一些关键目录、初始化日志输出系统、启用Selinux安全策略。
  2. 初始化属性系统、解析Selinux的匹配规则、启动属性服务。
  3. 解析init.rc配置文件并启动Zygote进程。
Android系统启动(一)— init 进程启动过程 Android和Android系统服务。严格来说,Android系统实际是运行在Linux内核之上的一系列“服务进程”,而这些服务进程的“老祖宗”就是init进程。initAndroidPID1Androidinit.rcAndroidinit.rcinitmkdirmountinit.rcZygoteinitLinuxinit.rcinitAndroid 10对init进程的入口函数进行了调整,不再是之前的的main函数,**而是换成了的main。 阅读详情

相关推荐

Android 系统init进程启动流程

和你一起终身学习,这里是程序员Android经典好文推荐,通过阅读本文,您将收获以下知识点:一、启动流程概述二、Android启动分析三、init 进程启动分析四、init 启动脚本分析五、init 进程分析六、init 脚本执行七、init 进程守护八、init rc 脚本启动Zygote九、启动分析小结一、 启动流程概述Android启动流程跟Linux启动类似,大致分为如下五个阶段。1.开...

程序员Android 1951

【linux】init进程的详解

init进程和init程序(linuxrc程序)是有区别的。init进程一开始就有,它运行于内核态,属于一个内核线程。后来init进程挂载根文件系统,并运行应用程序init程序后,init进程才从内核态转变为用户态。因为转变过程中进程号没有变,还是进程1,所以有人会把init程序(linuxrc程序)当做进程1。但其实init进程除了后来的init程序,还包括内核态下挂载根文件系统等操作。

m0_45406092的博客 6573

init进程【1】——init启动过程

众所周知,Linux中的所有进程都是有init进程创建并运行的。首先Linux内核启动,然后在用户空间中启动init进程,再启动其他系统进程。在系统启动完成完成后,init将变为守护进程监视系统其他进程。Android是基于Linux的操作系统,所以init也是Android系统中用户空间的第一个进程,它的进程号是1。下面先简单的看一下init进程的启动过程。 @/kernel/good

张兴华的技术博客 1万+

init进程

init进程 init的进程号是1(ps -aux | less),从这一点就能看出,init进程是系统所有进程的起点,Linux在完成核内引导以后,就开始运行init程序。 init程序需要读取配置文件/etc/inittab。inittab是一个不可执行的文本文件,它有若干行指令所组成。 理解Runlevel: runlevel用来表示在init进程结束之后的系统状态,在系统的硬件中没...

IT探险者-returningprodigal 1009

Android系统启动流程(一)解析init进程启动过程

作为“Android框架层”这个大系列中的第一个系列,我们首先要了解的是Android系统启动流程,在这个流程中会涉及到很多重要的知识点,这个系列我们就来一一讲解它们,这一篇我们就来学习init进程。

Android进阶三部曲 - 刘望舒 4万+

从源码角度看Android系统init进程启动过程

init进程是Linux系统中用户空间的第一个进程,进程号为1。Kernel启动后,在用户空间启动init进程,并调用/system/core/init.cpp中的main方法执行一些重要的工作。 备注:本文将结合Android8.0的源码看init进程的启动过程以及init进程做了哪些重要工作。 1. init进程启动前系统的启动流程 在引入init进程前,我们需要大致了解系统是如何走到init...

张许平的博客 1042

start_kernel到init进程启动的过程

杨明辉+ 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ” 一、实验过程 1.进入实验楼,打开系统终端,输入命令cd LinuxKernel 和qemu -kernel linux-3.18.6/arch/x86/boot/ bzImage -initrd rootfs

u010521171的博客 2223

JFET放大电路实例设计仿真

参照《晶体管电路设计》中的例子 JFET 2SK184 JFET 2SK184 数据手册如下 电路设计 共源放大 步骤:1、静态工作点 2N4416 1ma 2、RD和RS A=5 5:1 RS 2V /1m=2k RD 5k 3、偏压VG 根据传输特性 VGS-ID vgs=-0.7 vg=2-0.7=1.3 400k^2/50k...

f的博客 7440

Android系统启动流程(一) init进程启动过程解析

init进程是Android系统第一个用户态的进程,init被赋予了很多重要的职责,比如我们熟悉的Zygote孵化器进程就是由init进程启动的。今天我们就来学习init进程的启动过程。 1 init进程启动之前分析 在分析init进程之前,我们先简单说一下init之前的步骤,大概流程如下: 1) 按Power键启动电源及系统启动 当按下电源键,引导芯片代码开始从固化在ROM中预定义的地方开始执行,加载引导程序Bootloader到RAM,然后执行引导程序。 2) 引导程序Bootloader 引导程序.

周将的博客 3498

ZYNQ平台上基于SGMII接口的IEEE1588/PTP协议高效实现方案

本文深入探讨了在Xilinx ZYNQ平台上,利用SGMII接口实现高精度IEEE1588/PTP协议的方案。通过将硬件时间戳单元集成在PL端的AXI以太网子系统IP核中,该方案绕过了软件协议栈和外部PHY的延迟,实现了亚微秒级的时间同步精度。文章详细解析了硬件设计、Vivado IP配置、Linux驱动移植及PTP协议栈部署等关键步骤,为工业控制、通信等领域的高精度网络同步提供了高效、灵活的解决路径。

q5r6s7的博客 604

电源工程师必看:平均电流模式BUCK双环控制详解(从传递函数到Psim仿真)

本文详细解析了平均电流模式BUCK变换器的双环控制策略,从传递函数推导到Psim仿真实现。针对电源工程师关注的环路设计和稳定性问题,深入比较了电压模式、峰值电流模式和平均电流模式的优缺点,并提供了12V/3A BUCK变换器的完整设计案例,帮助工程师掌握平均电流控制这一中高功率应用的首选方案。

weixin_42696271的博客 395

Android 启动过程 - 从上电到init进程的建立

这里需要注意的是,上述调动过程中,pid是在kernel_thread(kernel_init...)时创建的,do_execve使用新进程覆盖当前进程,pid不变。LoadBootScripts中依次解析多个rc文件,其中,/system/etc/init/hw/init.rc是主文件。在/system/etc/init/hw/init.rc中,启动一系列核心进程和服务,包括重要的zygote进程。/system/etc/init/hw/init.rc被执行后,其他rc文件会被执行。

temp7695的博客 1639

Android11 关于三方应用获取su权限

SELinux,全称Security-Enhanced Linux,是一种基于Linux内核的安全机制。它通过强制访问控制(MAC)来增强Linux系统的安全性,如果不禁用SELinux,完成下面的修改可能会导致设备进入Recovery界面!adb shell getenforce 为Permissive(宽容模式),查看报错日志,发现是客户apk想使用su命令提权,但是没有权限!对于保护系统资源和防止未经授权访问非常有帮助!系统这边做修改,让su权限下放到三方应用.客户的apk运行报错。

sinat_37429535的博客 1901

Init进程启动Zygote进程的过程

Android系统启动时在加载完内核之后会启动Init进程,Init进程的启动过程中会读取根目录下的脚本文件Init.rc,以便将Zygote进程启动起来。       //Android系统在加载内核之后会启动init进程,以下为Init进程的main函数 int main(int argc, char **argv) { int fd_count = 0; st

TiuTiu Zone 924

使用sysbench对Oracle做基准测试(-) 安装篇

sysbench是一款开源的多线程性能测试工具, 可以执行CPU/内存/线程/IO/数据库等方面的性能测试。数据库目前支持MySQL/Oracle/PostgreSQL。

道行尚浅(老道)的博客 7810

矩阵奇异值分解算法(SVD)的导数 / 灵敏度分析

设矩阵X∈Rm×nX∈Rm×nXUΣV⊤XUΣV⊤U∈Rm×mU∈Rm×m为左奇异向量矩阵;V∈Rn×nV∈Rn×n为右奇异向量矩阵;Σdiag⁡σ1σ2σrΣdiagσ1​σ2​σr​为奇异值对角阵(rrank⁡XrrankX我们关心:当XXX发生微小扰动dXdX时,UΣVUΣV如何变化?dXdUΣV⊤dX。

qq_36812406的博客 1750

Android启动过程详解(2)——init进程启动逻辑

init进程是Android系统用户空间中的第一个进程,其进程号也是1,足见其重要性。所以它的责任也是重大的,概括地来说init进程主要做了以下几件事: 作为守护进程 解析和执行init.rc文件 属性服务 生成设备驱动节点 接下来文章就着init进程的源码,来一个个分析init进程的工作。

李牙刷儿的专栏 1149

DMDiff(2025):一种基于SAR光学数据融合的双分支多模态条件引导扩散模型-k学长深度学习专栏

DMDiff提出了一种基于扩散模型的多模态遥感图像去云方法,通过双分支网络分别提取SAR的结构信息和光学图像的光谱特征,再利用跨模态注意力机制实现特征融合。创新性地采用IAP策略直接预测无云图像而非噪声,有效解决了传统方法在遥感图像处理中易出现的光谱失真问题。实验表明该方法在PSNR等指标上显著优于现有技术,但存在计算量大、生成速度慢等不足。未来可结合加速采样策略和几何约束进一步优化。

421

Linux启动过程分析之init进程分析

linuxrc是如何启动的 uboot的作用是启动内核,而内核的作用是为了运行应用程序,而应用程序位于文件系统中,因此内核代码运行最终会挂载根文件系统,并启动用户进程。 uboot时通过bootargs传入参数init=/linuxrc,内核启动的最后阶段会根据此命令启动应用程序! 1. init进程完成了从内核态向用户态的转变 (1)一个进程先后两种状态 •init进程刚开始运行的时候是内核态,它属于一个内核线程,然后运行一个用户态下面的程序后,把自己强行转成了用户态(后面的进程需要工作在用户态下)

NUAA1703的博客 1436

GEE:基于MODIS数据计算NDVI时间序列,并使用Savatsky-Golay(SG)滤波器对其进行平滑处理

优快云@_养乐多_本文将介绍如何在 Google Earth Engine (GEE) 平台中,使用 MODIS 数据计算 NDVI 时间序列,并对该数据集应用 Savitzky-Golay 滤波器,得到了一个新的平滑后的数据集。Savitzky-Golay 滤波器可以有效地去除信号中的噪声,并平滑信号的变化。该方法可以扩展到基于 MODIS 数据计算的任何指数或者波段。

养乐多的博客 1423

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

android init进程的运行,Android的init进程启动过程

0. 前言Android中的内核启动后,kernel会启动第一个用户级别的进程:init,它是一个由内核启动的第一个用户级进程。我们可以通过 adb shell ps | grep init 来查看到他的pid 为 1.接下来从源码的角度看看init进程启动的时候做了什么?注:本文分析的andorid版本为 remotes/aosp/nougat-release.init进程的源码在android...

weixin_35863455的博客 1349

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Android系统init进程启动过程

1. init进程启动前系统的启动流程 在引入init进程前,我们需要大致了解系统是如何走到init进程的。大致步骤如下: 启动电源和系统启动 按下电源,让设备开机时引导芯片代码会从预定义的地方开始执行。加载引导程序BootLoader到RAM中。 BootLoader BootLoader只...

cheting4792的博客 513

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Framework学习之旅:init 进程启动过程

init进程是Android系统中用户空间的第一个进程,进程号为1,是Android系统启动流程中一个关键的步骤,它有很多重要的职责,比如创建Zygote(孵化器)和属性服务等。它的生命周期贯穿整个Linux内核运行的始终。Android中所有其它的进程共同的鼻祖均为init进程。创建和挂载启动所需的文件目录初始化和启动属性服务解析init.rc配置文件并启动启动Zygote服务httpshttps。...

xufei5789651的博客 1998

Busybox init进程启动过程分析

<br />上一篇文章只是移植了Busybox不过对中间的启动流程还不是很清楚,经过查看资料,终于搞明白了Busybox启动的基本的流程。现把流程记录如下:一、Busybox    Busybo是一个遵循GPLv2协议的开源项目。Busybox将众多的Linux命令集合进一个很小的可执行程序中,可以用来替换GNU fileutils shellutils等工具集。Busybox中各种命令与相应的GNU工具相比,所能提供的选项较少,但是能够满足一般应用。Busybox为各种小型的或者嵌入式系统提供了一

babyfans的专栏 2506

Android init进程启动过程

init源码在:android/system/core/init/,编译出来的init二进制可执行文件在:android/out/target/product/s900_vr/root/,系统运行起来后,这个root/目录里面的内容都是在根目录下的,也就是说,要想实现从kernel到android的跳转,就需要有地方启动这个完整路径是 "/init"的init进程。

lizekun2010的博客 787

Android 进阶解密:init 进程启动过程

init 进程启动过程一、init 进程二、init 进程启动流程三、启动 init 进程 Android 系统启动与很多内容都有关联,如应用进程启动流程、四大组件原理、AMS、ClassLoader 等 一、init 进程 init 进程是 Android 系统中用户进程的第一个进程,进程号为 1,被赋予很多极其重要的职责,如创建 Zygote 和属性服务等。init 进程由多个源文件组成,文件...

韭菜鲜肉大馄饨的专栏 986
上一篇: Android系统启动
下一篇: Android开机动画启动流程
八归少年
八归少年 新星创作者: 操作系统技术领域 新星创作者: 操作系统技术领域
博客等级 码龄9年 9011粉丝 63原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

八归少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值