【Android FrameWork(一)】- 启动程序 init

news2024/9/17 8:24:44

文章目录

  • 背景
  • 源码分析(第一个启动程序 init)
    • 1.main.cpp
    • 2.init.cpp
    • 3.property_service.cpp
    • 4,LoadBootScripts
  • 拓展知识
    • Android的架构图
    • I/O多路复用
  • 总结

离职找工作间隙,停下脚步整理下自己的知识体系,把之前忙于开发未曾整理的知识都记录成文档,分享出来,希望可以帮助到大家。另外也打算把写了几年的 简书 整理到CSDN这边来。


背景

阅读源码是提高技术能力最好的学习材料。长久的业务开发经常所面对常用Api的调用,UI搭建,架构。随着深入,仅仅只会Api的调用是无法满足需求的,如果想成为高级开发工程师,那么阅读系统源码是必须要经历的过程。例如我们在开发的过程中遇到的问题,有很多是需要通过分析源码解决,还有性能优化,卡顿优化,ANR等。我们也可以从阅读源码的过程中学到很多知识,能够做一些看似无法实现的功能,例如一些数据结构的最优解、插件化、保活等。

源码分析(第一个启动程序 init)

1.main.cpp

main.cpp入口
—>first_stage_init.cpp 挂载文件系统 创建目录 启动selinux_setup安全权限相关

int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif
    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;
            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);//在这里创建和挂载了启动所需要的目录信息包含tmpfs、devpts、proc、sysfs、selinuxfs文件系统。。
}

2.init.cpp

init.cpp 首先初始化内存空间— 创建Epoll—InstallSignalFdHandler(Epoll)注册Epoll监听—startPropertyService 调用函数把服务拉起来


int SecondStageMain(int argc, char** argv) {
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
    }
    SetStdioToDevNull(argv);
    InitKernelLogging(argv);
    LOG(INFO) << "init second stage started!";
    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();
    }
    GlobalSeccomp();
    keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);
    close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
    property_init();//初始化属性服务
    process_kernel_dt();
    process_kernel_cmdline();
    export_kernel_boot_props();
    property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
    property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
    const char* avb_version = getenv("INIT_AVB_VERSION");
    if (avb_version) property_set("ro.boot.avb_version", avb_version);
    const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
    if (force_debuggable_env && AvbHandle::IsDeviceUnlocked()) {
        load_debug_prop = "true"s == force_debuggable_env;
    }
    unsetenv("INIT_STARTED_AT");
    unsetenv("INIT_SELINUX_TOOK");
    unsetenv("INIT_AVB_VERSION");
    unsetenv("INIT_FORCE_DEBUGGABLE");
    SelinuxSetupKernelLogging();
    SelabelInitialize();
    SelinuxRestoreContext();
    //创建Epoll
    Epoll epoll;
    if (auto result = epoll.Open(); !result) {
        PLOG(FATAL) << result.error();
    }
    //创建Handler,监听子进程的信号,如果子进程异常退出,init会调用对应的处理函数来进行处理。
    InstallSignalFdHandler(&epoll);
    property_load_boot_defaults(load_debug_prop);
    UmountDebugRamdisk();
    fs_mgr_vendor_overlay_mount_all();
    export_oem_lock_status();
    //开启属性服务
    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& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();
    //加载配置脚本文件 init.rc
    LoadBootScripts(am, sm);
    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");
    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");
    // Trigger all the boot actions to get us started.
    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");
    // Initialize binder before bringing up other system services
    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") {
        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) {
        // 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;
}


3.property_service.cpp

创建Android的注册表,将一些用户、应用的信息存储下来 系统会根据这些属性进行初始化工作。创建了property的socket 并且将socket注册到Epoll中,在handle_property_set_fd中将属性添加到内存空间中去。

void StartPropertyService(Epoll* epoll) {
    selinux_callback cb;
    cb.func_audit = SelinuxAuditCallback;
    //设置selinux的callback
    selinux_set_callback(SELINUX_CB_AUDIT, cb);

    property_set("ro.property_service.version", "2");
     //创建属性的非阻塞式socket
    property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                   false, 0666, 0, 0, nullptr);
    if (property_set_fd == -1) {
        PLOG(FATAL) << "start_property_service socket creation failed";
    }
    //listen对property_set_fd进行监听,最多可以同时为8个链接提供服务。
    listen(property_set_fd, 8);
     //epoll 注册Handler,监听property_set_fd,当有更新的时候会调用handle_property_set_fd来进行处理。
    if (auto result = epoll->RegisterHandler(property_set_fd, handle_property_set_fd); !result) {
        PLOG(FATAL) << result.error();
    }
}


//属性事件处理器
static void handle_property_set_fd() {
    static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */ //设置超时时长

    int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC);
    if (s == -1) {
        return;
    }

    ucred cr;
    socklen_t cr_size = sizeof(cr);
    if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
        close(s);
        PLOG(ERROR) << "sys_prop: unable to get SO_PEERCRED";
        return;
    }

    SocketConnection socket(s, cr);
    uint32_t timeout_ms = kDefaultSocketTimeout;

    uint32_t cmd = 0;
    if (!socket.RecvUint32(&cmd, &timeout_ms)) {//接收数据
        PLOG(ERROR) << "sys_prop: error while reading command from the socket";
        socket.SendUint32(PROP_ERROR_READ_CMD);
        return;
    }

    switch (cmd) {
    case PROP_MSG_SETPROP: {//设置属性事件
        char prop_name[PROP_NAME_MAX];
        char prop_value[PROP_VALUE_MAX];
        //从socket中读取name 和 value
        if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
            !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
          return;
        }

        prop_name[PROP_NAME_MAX-1] = 0;
        prop_value[PROP_VALUE_MAX-1] = 0;

        const auto& cr = socket.cred();
        std::string error;
        uint32_t result =
            HandlePropertySet(prop_name, prop_value, socket.source_context(), cr, &error);//设置属性
        if (result != PROP_SUCCESS) {
            LOG(ERROR) << "Unable to set property '" << prop_name << "' to '" << prop_value
                       << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": "
                       << error;
        }

        break;
      }

    case PROP_MSG_SETPROP2: {//同上
        std::string name;
        std::string value;
        if (!socket.RecvString(&name, &timeout_ms) ||
            !socket.RecvString(&value, &timeout_ms)) {
          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
          socket.SendUint32(PROP_ERROR_READ_DATA);
          return;
        }

        const auto& cr = socket.cred();
        std::string error;
        uint32_t result = HandlePropertySet(name, value, socket.source_context(), cr, &error);
        if (result != PROP_SUCCESS) {
            LOG(ERROR) << "Unable to set property '" << name << "' to '" << value
                       << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": "
                       << error;
        }
        socket.SendUint32(result);
        break;
      }

    default:
        LOG(ERROR) << "sys_prop: invalid command " << cmd;
        socket.SendUint32(PROP_ERROR_INVALID_CMD);
        break;
    }
}

//设置属性
uint32_t HandlePropertySet(const std::string& name, const std::string& value,
                           const std::string& source_context, const ucred& cr, std::string* error) {
    if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) {
        return ret;
    }

    if (StartsWith(name, "ctl.")) {//控制属性的处理
        HandleControlMessage(name.c_str() + 4, value, cr.pid);
        return PROP_SUCCESS;
    }

    // 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") {//记录重启设备原因的属性
        std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
        std::string process_cmdline;
        std::string process_log_string;
        if (ReadFileToString(cmdline_path, &process_cmdline)) {
            // Since cmdline is null deliminated, .c_str() conveniently gives us just the process
            // path.
            process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
        }
        LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
                  << process_log_string;
    }

    if (name == "selinux.restorecon_recursive") {
        return PropertySetAsync(name, value, RestoreconRecursiveAsync, error);
    }
    //设置普通属性
    return PropertySet(name, value, error);
}
我们只看普通属性,因为控制属性需要客户端的权限。


static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
    size_t valuelen = value.size();

    if (!IsLegalPropertyName(name)) {
        *error = "Illegal property name";
        return PROP_ERROR_INVALID_NAME;
    }

    if (valuelen >= PROP_VALUE_MAX && !StartsWith(name, "ro.")) {
        *error = "Property value too long";
        return PROP_ERROR_INVALID_VALUE;
    }

    if (mbstowcs(nullptr, value.data(), 0) == static_cast<std::size_t>(-1)) {
        *error = "Value is not a UTF8 encoded string";
        return PROP_ERROR_INVALID_VALUE;
    }
    //从属性内存空间查找,属性存在就更新属性值,否则创建并且添加进去。
    prop_info* pi = (prop_info*) __system_property_find(name.c_str());
    if (pi != nullptr) {
        // 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;
        }
    }

    if (persistent_properties_loaded && StartsWith(name, "persist.")) {
        WritePersistentProperty(name, value);
    }
    property_changed(name, value);
    return PROP_SUCCESS;
}


4,LoadBootScripts

加载并解析init.rc 根据rc文件创建Service对象,最终将service添加到service_List中,然后解析执行 class_start的时候会开启服务调用Service::Start函数,fork子进程,并且执行app_process文件 开启了zygote,也就到了zygote的main函数中了。

static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser = CreateParser(action_manager, service_list);//创建解析器

    std::string bootscript = GetProperty("ro.boot.init_rc", "");//根据ro.boot.init_rc的属性值来获取需要执行的脚本
    if (bootscript.empty()) {
        parser.ParseConfig("/init.rc");
        if (!parser.ParseConfig("/system/etc/init")) {
            late_import_paths.emplace_back("/system/etc/init");
        }
        if (!parser.ParseConfig("/product/etc/init")) {
            late_import_paths.emplace_back("/product/etc/init");
        }
        if (!parser.ParseConfig("/product_services/etc/init")) {
            late_import_paths.emplace_back("/product_services/etc/init");
        }
        if (!parser.ParseConfig("/odm/etc/init")) {
            late_import_paths.emplace_back("/odm/etc/init");
        }
        if (!parser.ParseConfig("/vendor/etc/init")) {
            late_import_paths.emplace_back("/vendor/etc/init");
        }
    } else {
        parser.ParseConfig(bootscript);
    }
}

//1.根据action on  和import类型的不同创建不同的解析器
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;
}

/*2.读取init.rc文件 在init.rc中根据系统导入对应的zygote.rc  在init进程中创建Zygote进程,该进程的可执行文件在/system/bin/app_process  并且传入参数 -Xzygote /system/bin --zygote --start-system-server 指定classname=main */


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 write /sys/android_power/request_state wake
    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
    
    
3.解析器根据文件的格式来执行对应的动作。
文件目录:system/core/init/service.cpp
在线地址:https://cs.android.com/android/platform/superproject/+/android10-release:system/core/init/service.cpp

//开始解析
Result<Success> ServiceParser::ParseSection(std::vector<std::string>&& args,
                                            const std::string& filename, int line) {
    if (args.size() < 3) {//判断可执行参数 我们传递的参数大于3个的 所以不会到这里来。
        return Error() << "services must have a name and a program";
    }

    const std::string& name = args[1];
    if (!IsValidName(name)) {//校验Name
        return Error() << "invalid service name '" << name << "'";
    }

    filename_ = filename;

    Subcontext* restart_action_subcontext = nullptr;
    if (subcontexts_) {
        for (auto& subcontext : *subcontexts_) {
            if (StartsWith(filename, subcontext.path_prefix())) {
                restart_action_subcontext = &subcontext;
                break;
            }
        }
    }

    std::vector<std::string> str_args(args.begin() + 2, args.end());

    if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_P__) {
        if (str_args[0] == "/sbin/watchdogd") {
            str_args[0] = "/system/bin/watchdogd";
        }
    }
    //创建service对象
    service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args);
    return Success();
}

//解析完成
Result<Success> ServiceParser::EndSection() {
    if (service_) {//如果service存在就将原来的service删除 再添加新的
        Service* old_service = service_list_->FindService(service_->name());
        if (old_service) {
            if (!service_->is_override()) {
                return Error() << "ignored duplicate definition of service '" << service_->name()
                               << "'";
            }

            if (StartsWith(filename_, "/apex/") && !old_service->is_updatable()) {
                return Error() << "cannot update a non-updatable service '" << service_->name()
                               << "' with a config in APEX";
            }

            service_list_->RemoveService(*old_service);
            old_service = nullptr;
        }
        //调用service_list->addService函数进行添加
        service_list_->AddService(std::move(service_));
    }

    return Success();
}

解析完成后需要启动 在init.rc中我们找到对应的启动 之前说到的class = main  而class_start是一个command
on nonencrypted
    class_start main
    class_start late_start
    
 文件目录: /android/system/core/init   
 
static Result<Success> 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 Success();
    // Starting a class does not start services which are explicitly disabled.
    // They must  be started individually.
    for (const auto& service : ServiceList::GetInstance()) {//遍历serviceList 
        if (service->classnames().count(args[1])) {
            if (auto result = service->StartIfNotDisabled(); !result) {//执行startIfNotDisable函数
                LOG(ERROR) << "Could not start service '" << service->name()
                           << "' as part of class '" << args[1] << "': " << result.error();
            }
        }
    }
    return Success();
}

文件目录:/system/core/init/service.cpp
Result<Success> Service::StartIfNotDisabled() {
    if (!(flags_ & SVC_DISABLED)) { //判断有没有在init.rc中配置disabled
        return Start();//开启Zygote
    } else {
        flags_ |= SVC_DISABLED_START;
    }
    return Success();
}


//调用start 开启zygote服务
Result<Success> Service::Start() {
    if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) {
        ServiceList::GetInstance().DelayService(*this);
        return Error() << "Cannot start an updatable service '" << name_
                       << "' before configs from APEXes are all loaded. "
                       << "Queued for execution.";
    }

    bool disabled = (flags_ & (SVC_DISABLED | SVC_RESET));
    flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));

    if (flags_ & SVC_RUNNING) {//如果服务已经开启 就return Success
        if ((flags_ & SVC_ONESHOT) && disabled) {
            flags_ |= SVC_RESTART;
        }
        // It is not an error to try to start a service that is already running.
        return Success();
    }

    bool needs_console = (flags_ & SVC_CONSOLE);
    if (needs_console) {
        if (console_.empty()) {
            console_ = default_console;
        }

        int console_fd = open(console_.c_str(), O_RDWR | O_CLOEXEC);
        if (console_fd < 0) {
            flags_ |= SVC_DISABLED;
            return ErrnoError() << "Couldn't open console '" << console_ << "'";
        }
        close(console_fd);
    }

    struct stat sb;
    //判断对应的执行文件是否存在也就算zygote.rc中的/system/bin/app_process。手机中的/system/bin/app_process文件。
    if (stat(args_[0].c_str(), &sb) == -1) {
        flags_ |= SVC_DISABLED;
        return ErrnoError() << "Cannot find '" << args_[0] << "'";
    }

    std::string scon;
    if (!seclabel_.empty()) {
        scon = seclabel_;
    } else {
        auto result = ComputeContextFromExecutable(args_[0]);
        if (!result) {
            return result.error();
        }
        scon = *result;
    }

    if (!IsRuntimeApexReady() && !pre_apexd_) {
        pre_apexd_ = true;
    }

    post_data_ = ServiceList::GetInstance().IsPostData();

    LOG(INFO) << "starting service '" << name_ << "'...";
    //判断进程是否启动,没有启动就fork子进程。所以zygote是init的子进程。
    pid_t pid = -1;
    if (namespace_flags_) {
        pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
    } else {
        pid = fork();
    }

    if (pid == 0) {//子进程(zygote)中执行的函数
        umask(077);

        if (auto result = EnterNamespaces(); !result) {
            LOG(FATAL) << "Service '" << name_ << "' could not enter namespaces: " << result.error();
        }

        if (namespace_flags_ & CLONE_NEWNS) {
            if (auto result = SetUpMountNamespace(); !result) {
                LOG(FATAL) << "Service '" << name_
                           << "' could not set up mount namespace: " << result.error();
            }
        }

        if (namespace_flags_ & CLONE_NEWPID) {
            if (auto result = SetUpPidNamespace(); !result) {
                LOG(FATAL) << "Service '" << name_
                           << "' could not set up PID namespace: " << result.error();
            }
        }

        for (const auto& [key, value] : environment_vars_) {
            setenv(key.c_str(), value.c_str(), 1);
        }

        std::for_each(descriptors_.begin(), descriptors_.end(),
                      std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon));

        std::string cpuset_path;
        if (CgroupGetControllerPath("cpuset", &cpuset_path)) {
            auto cpuset_predicate = [&cpuset_path](const std::string& path) {
                return StartsWith(path, cpuset_path + "/");
            };
            auto iter =
                    std::find_if(writepid_files_.begin(), writepid_files_.end(), cpuset_predicate);
            if (iter == writepid_files_.end()) {
                std::string default_cpuset = GetProperty("ro.cpuset.default", "");
                if (!default_cpuset.empty()) {
                    if (default_cpuset.front() != '/') {
                        default_cpuset.insert(0, 1, '/');
                    }
                    if (default_cpuset.back() != '/') {
                        default_cpuset.push_back('/');
                    }
                    writepid_files_.push_back(
                            StringPrintf("%s%stasks", cpuset_path.c_str(), default_cpuset.c_str()));
                }
            }
        } else {
            LOG(ERROR) << "cpuset cgroup controller is not mounted!";
        }
        std::string pid_str = std::to_string(getpid());
        for (const auto& file : writepid_files_) {
            if (!WriteStringToFile(pid_str, file)) {
                PLOG(ERROR) << "couldn't write " << pid_str << " to " << file;
            }
        }

        if (ioprio_class_ != IoSchedClass_NONE) {
            if (android_set_ioprio(getpid(), ioprio_class_, ioprio_pri_)) {
                PLOG(ERROR) << "failed to set pid " << getpid()
                            << " ioprio=" << ioprio_class_ << "," << ioprio_pri_;
            }
        }

        if (needs_console) {
            setsid();
            OpenConsole();
        } else {
            ZapStdio();
        }

        SetProcessAttributes();
        //调用execv函数,启动service子进程
        if (!ExpandArgsAndExecv(args_, sigstop_)) {
            PLOG(ERROR) << "cannot execve('" << args_[0] << "')";
        }

        _exit(127);
    }

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

    if (oom_score_adjust_ != -1000) {
        std::string oom_str = std::to_string(oom_score_adjust_);
        std::string oom_file = StringPrintf("/proc/%d/oom_score_adj", pid);
        if (!WriteStringToFile(oom_str, oom_file)) {
            PLOG(ERROR) << "couldn't write oom_score_adj";
        }
    }

    time_started_ = boot_clock::now();
    pid_ = pid;
    flags_ |= SVC_RUNNING;
    start_order_ = next_start_order_++;
    process_cgroup_empty_ = false;

    bool use_memcg = swappiness_ != -1 || soft_limit_in_bytes_ != -1 || limit_in_bytes_ != -1 ||
                      limit_percent_ != -1 || !limit_property_.empty();
    errno = -createProcessGroup(uid_, pid_, use_memcg);
    if (errno != 0) {
        PLOG(ERROR) << "createProcessGroup(" << uid_ << ", " << pid_ << ") failed for service '"
                    << name_ << "'";
    } else if (use_memcg) {
        if (swappiness_ != -1) {
            if (!setProcessGroupSwappiness(uid_, pid_, swappiness_)) {
                PLOG(ERROR) << "setProcessGroupSwappiness failed";
            }
        }

        if (soft_limit_in_bytes_ != -1) {
            if (!setProcessGroupSoftLimit(uid_, pid_, soft_limit_in_bytes_)) {
                PLOG(ERROR) << "setProcessGroupSoftLimit failed";
            }
        }

        size_t computed_limit_in_bytes = limit_in_bytes_;
        if (limit_percent_ != -1) {
            long page_size = sysconf(_SC_PAGESIZE);
            long num_pages = sysconf(_SC_PHYS_PAGES);
            if (page_size > 0 && num_pages > 0) {
                size_t max_mem = SIZE_MAX;
                if (size_t(num_pages) < SIZE_MAX / size_t(page_size)) {
                    max_mem = size_t(num_pages) * size_t(page_size);
                }
                computed_limit_in_bytes =
                        std::min(computed_limit_in_bytes, max_mem / 100 * limit_percent_);
            }
        }

        if (!limit_property_.empty()) {
            computed_limit_in_bytes = android::base::GetUintProperty(
                    limit_property_, computed_limit_in_bytes, SIZE_MAX);
        }

        if (computed_limit_in_bytes != size_t(-1)) {
            if (!setProcessGroupLimit(uid_, pid_, computed_limit_in_bytes)) {
                PLOG(ERROR) << "setProcessGroupLimit failed";
            }
        }
    }

    NotifyStateChange("running");
    return Success();
}

static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigstop) {
    std::vector<std::string> expanded_args;
    std::vector<char*> c_strings;

    expanded_args.resize(args.size());
    c_strings.push_back(const_cast<char*>(args[0].data()));
    for (std::size_t i = 1; i < args.size(); ++i) {
        if (!expand_props(args[i], &expanded_args[i])) {
            LOG(FATAL) << args[0] << ": cannot expand '" << args[i] << "'";
        }
        c_strings.push_back(expanded_args[i].data());
    }
    c_strings.push_back(nullptr);

    if (sigstop) {
        kill(getpid(), SIGSTOP);
    }
    //执行app_process 也就是调用app_main.cpp的main函数 这样就进入到zygote了。
    return execv(c_strings[0], c_strings.data()) == 0;
}

拓展知识

Android的架构图

// 从上到下依次(这是知识体系建立的第一步)
Applications //应用层开发
Application Framework //Framework开发
Libraries / Android Runtime
HAL
Linux

在这里插入图片描述

I/O多路复用

Select–>poll—>epoll 区别
Select -->数组 大小限制1024. 性能
Poll -->链表 没有大小限制 性能 系统上下文切换
Epoll–>红黑树 O(1)基于事件 fd 写操作唤起对应读操作端

总结

Framework 的第一个启动程序init主要流程如下:
1,FirstStageMain() 挂载文件系统以及创建目录 调用selinux_setup安全权限相关
2,上下文审查
3,初始化内存空间 property_init 初始化属性服务 创建Epoll 注册监听Epoll 子进程的一些情况 (重启异常操作等,对子进程进行线程守护)
4,startPropertyServic 开启属性服务 进行监听
5,LoadBootScripts 加载init.rc文件 进行解析 调用do_class_start 文件开启service
6,init.rc文件(多种子进程) . Service::Start函数->fork子进程->并且执行app_process文件
开启了zygote zygote是init的子进程
流程图:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/458896.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SOLIDWORKS Electrical无缝集成电气和机械设计

集成电气系统设计SOLIDWORKS⑧Electrical 解决方案借助专为工程专业设计的特定工具简化了电气铲品设计&#xff0c;并借助直观的用户界面更快地设计嵌入式电气系统。 与SOLIDWORKS 3DCAD的原生集成能提供更好的协作与生产效率&#xff0c;同时减少产品延迟、提高设计的一致性与…

微信小程序nodejs+python+php+springboot+vue 法律知识分享科普系统平台

要想实现法律知识分享平台的各项功能&#xff0c;需要后台数据库的大力支持。管理员验证注册信息&#xff0c;收集的信息&#xff0c;并由此分析得出的关联信息等大量的数据都由数据库管理。本文中数据库服务器端采用了Mysql作为后台数据库 紧密联系起来。在设计过程中&#xf…

从零开始,轻松入门React - 构建现代Web应用的利器!

文章目录 前言渲染 React 组件使用 JSX传递属性&#xff08;Props&#xff09;处理组件状态&#xff08;State&#xff09;处理用户输入&#xff08;事件处理&#xff09;组合和嵌套组件写在最后 前言 React 是一种由 Facebook 开发的流行的 JavaScript 库&#xff0c;用于构建…

通用人工智能+智能车舱,商汤绝影带来怎样一番景象?

本文来源&#xff1a;智车科技 / 导读 / 进入4月&#xff0c;中国科技圈迎来最卷的时刻&#xff0c;这可能中国AI史上一个重要节点。ChatGPT、GPT-4的出圈掀起了通用人工智能&#xff08;AGI&#xff09;的技术狂潮&#xff0c;引爆了一场以大模型为代表的生成式AI狂飙&#x…

【基础】Kafka -- 日志存储

Kafka -- 日志存储 日志文件目录日志索引偏移量索引时间戳索引 日志清理日志删除基于时间基于日志大小基于日志起始偏移量 日志压缩 日志文件目录 Kafka 中的消息以主题为单位进行基本归类&#xff0c;而每个主题又可以划分为一个或者多个分区。在不考虑多副本的情况下&#x…

Adobe Photoshop 软件下载

Adobe Photoshop&#xff0c;简称“PS”&#xff0c;是由Adobe Systems开发和发行的图像处理软件。Photoshop主要处理以像素所构成的数字图像。 时至今日&#xff0c;Adobe Photoshop 已经成为当今世界上最流行、应用最广泛的图像处理软件。不但设计专业的学生要系统的学习这个…

【算法】最容易懂得的红黑树

红黑树是一个平衡的二叉树&#xff0c;但不是一个完美的平衡二叉树。虽然我们希望一个所有查找都能在~lgN次比较内结束&#xff0c;但是这样在动态插入中保持树的完美平衡代价太高&#xff0c;所以&#xff0c;我们稍微放松逛一下限制&#xff0c;希望找到一个能在对数时间内完…

【iOS】AVPlayer 视频播放

视频播放器的类别 iOS开发中不可避免地会遇到音视频播放方面的需求。 常用的音频播放器有 AVAudioPlayer、AVPlayer 等。不同的是&#xff0c;AVAudioPlayer 只支持本地音频的播放&#xff0c;而 AVPlayer 既支持本地音频播放&#xff0c;也支持网络音频播放。 常用的视频播放…

python学习——【第八弹】

前言 上篇文章 python学习——【第七弹】学习了python中的可变序列集合&#xff0c;自此python中的序列的学习就完成啦&#xff0c;这篇文章开始学习python中的函数。 函数 在学习其他编程语言的时候我们就了解过函数&#xff1a;函数就是执行特定任何以完成特定功能的一段代…

【JWT】token jwt-跨域认证的问题、JWT 的原理、java JWT实用案例

本文是向大家介绍token JWT的相关学习&#xff0c;它能够实现登录认证功能的实现,了解它能够让我们对系统有更加全面系统的理解 JSON Web Token&#xff08;缩写 JWT&#xff09;是目前最流行的跨域认证解决方案&#xff0c;本文介绍它的原理和用法。 一、跨域认证的问题 互联…

动态组件、keep-alive的使用及自定义指令

目录 1. 动态组件 2.如何实现动态组件渲染 3. 使用keep-alive保持状态 4. keep-alive对应的生命周期函数 5. keep-alive的include属性 自定义指令 1.什么是自定义指令 2. 自定义指令的分类 3. 私有自定义指令 4. update函数 5. 函数简写 全局自定义指令&#xff1a; …

媒体沟通会 | 云擎未来 智信天下:移动云大会终极预告

4月24日&#xff0c;“云擎未来 智信天下”2023移动云大会媒体沟通会在苏州举办&#xff0c;百余家主流新闻媒体参会。在媒体沟通会现场&#xff0c;中国移动云能力中心副总经理吴世俊致欢迎词&#xff0c;市场部副总经理吴炯详细介绍了移动云大会盛况&#xff0c;并透露在本届…

三问 ThreadLocal —— 有什么用 ? 使用时有什么潜在风险?原理 ?

最近想实现一些功能&#xff0c;求诸于网络之后&#xff0c;得到了使用 ThreadLocal 实现的方式&#xff0c;那么 ThreadLocal 到底是什么呢 &#xff1f; 遂写此文&#xff0c;抽丝剥茧的来看一下这个 Java 并发类 。 最近&#xff0c;me 的 gpt 账号没了&#xff0c;所以不能…

【模板】Hexo Docker Nginx 个人博客服务器部署

上文&#xff1a;基于 Hexo 的 Github 博客搭建 注意&#xff1a;通过验证部署&#xff0c;确定无误。AI生成的部分有&#x1f916;图标。 &#x1f916; TLDR By ChatGPT 本指南提供了在服务器上设置Git仓库、将本地Hexo页面推送到服务器仓库、在服务器上创建Nginx配置文件以…

数字信封例程不支持的bug,以及卸载安装配置Node.js

文章目录 前言一、运行错误:0308010C:数字信封例程:不支持二、卸载Node.js三、重新安装Node.js总结 前言 下载了若依项目&#xff0c;但是在前端项目运行打包都出现了bug。最后&#xff0c;卸载了Node.js&#xff0c;并重新安装了低版本的Node.js。 一、运行错误:0308010C:数字…

[算法前沿]--003-AGI通用人工智能模型对安全的影响和开源的大模型

文章目录 0.ChatGPT大模型带来的影响0.1 ChatGPT带来信息化革命性创新&#xff0c;目前尚不能处理专业知识但成长很快0.2 Chat GPT为网安行业带来新的创新方向&#xff0c;也将引领新一轮投融资热潮0.2.1 攻击方发起网络攻击的门槛降低0.2.2 防守方合理使用ChatGPT可大幅减少安…

组态王与PLC之间1主多从自组网无线通信

本方案是基于三菱专用协议下实现的1主多从自组网无线通信形式&#xff0c;主站为组态王&#xff0c;从站为三菱FX3U PLC和485BD扩展。采用日系PLC专用无线通讯终端DTD435MC-V96&#xff0c;作为实现无线通讯的硬件设备&#xff0c;来解决组态王与PLC之间的通讯问题。 一、方案…

百度AI模型“文心一言”新鲜体验

今天收到通知可以体验百度的AI模型“文心一言”&#xff0c;等了一个多月迫不及待的去体验了一把&#xff0c;以下是体验的相关记录。 1、简单介绍 通过文心一言官网链接https://yiyan.baidu.com/进入&#xff0c;看到如下界面&#xff1a; 在文心一言的自我介绍中&#xff0c…

seetaface6 GPU版本windows编译

目录 1. seetaface6概述2. 编译说明2.1 编译工具2.2 编译顺序 3. 编译OpenRoleZoo4. 编译SeetaAuthorize5. 编译TenniS6. 编译FaceTracker6 1. seetaface6概述 seetaface6源码以及模型文件github下载路径&#xff1a;https://github.com/SeetaFace6Open/index 由于项目性能需求…

华为为何要搞相对冷门的ERP?

大家都知道华为的研发实力很强&#xff0c;但几天前他们宣布研发出超大规模云原生的ERP时&#xff0c;还是有些吃惊。 20日&#xff0c;在东莞的一场“英雄强渡大渡河”表彰会上&#xff0c;华为抛出一个大多数公司都难以做到的成果&#xff1a;三年时间&#xff0c;数千人&am…