【Android 源码学习】 init启动
目录
- Android 源码学习 init启动
- 从main.cpp开始
- init.cpp 部分逻辑
- init启动zygote
- 属性服务
- 总结
Android 源码学习 init启动
Android 11 init 启动流程学习。主要是学习刘望舒腾讯课堂教的AndroidFrameWork部分的笔记。
参考文章:
Android系统启动-Zygote进程
5张图搞懂Android系统启动的核心流程
从main.cpp开始
system/core/init/main.cpp
using namespace android::init;int main(int argc, char** argv) {#if __has_feature(address_sanitizer)__asan_set_error_report_callback(AsanReportCallback);
#endifif (!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);
}
init.cpp 部分逻辑
system/core/init/init.cpp
int SecondStageMain(int argc, char** argv) {...// 系统属性初始化PropertyInit();...// 创建epoll,epoll是Linux内核的可扩展I/O事件通知机制Epoll epoll;if(auto result = epol.Open();!result.ok()){PLOG(FATAL) << result.error();}// 注册信号处理InstallSignalFdHandler(&epoll);//加载默认的系统属性InstallInitNotifier(&epoll);//启动属性服务StartPropertyService(&property_fd);...ActionManager& am = ActionManager::GetInstance();ServiceList& sm = ServiceList::GetInstance();//解析init.rcLoadBootScripts(am,sm);...return 0;
}
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()) {parser.ParseConfig("/system/etc/init/hw/init.rc");if (!parser.ParseConfig("/system/etc/init")) {late_import_paths.emplace_back("/system/etc/init");}parser.ParseConfig("/system_ext/etc/init")if (!parser.ParseConfig("/product/etc/init")) {late_import_paths.emplace_back("/product/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);}
}
init启动zygote
/system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-serverclass mainpriority -20user rootgroup root readproc reserved_disksocket zygote stream 660 root systemsocket usap_pool_primary stream 660 root systemonrestart exec_background - system system -- /system/bin/vdc volume abort_fuseonrestart write /sys/power/state ononrestart restart audioserveronrestart restart cameraserveronrestart restart mediaonrestart restart netdonrestart restart wificondwritepid /dev/cpuset/foreground/tasks
init.rc中还import了其他的rc文件,解析完init.rc后,依次解析其他的rc文件
import /system/etc/init/hw/init.${ro.zygote}.rc
nonencrypted 会触发启动main类别的服务。
main 指zygote
/system/core/rootdir/init.rc 部分代码
on nonencryptedclass_start mainclass_start late_start
class_start 在/system/core/init/builtins.cpp 文件中定义
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 {};
}
/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() {...pid_t pid = -1;if (namespace_flags_) {pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);} else {pid = fork();}if (pid == 0) {...if(!ExpandArgsAndExecv(args_, sigstop_)){PLOG(ERROR) << "cannot execve('" << args_[0]<< "').See the 'Debugging init' section of init's README.md for tips";}_exit(127);}if (pid < 0) {pid_ = 0;return ErrnoError() << "Failed to fork";}...return {};
}
service 就是 zygote
ExpandArgsAndExecv 传递的参数就是“/system/bin/app_process64”
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) {auto expanded_arg = ExpandProps(args[i]);if (!expanded_arg.ok()) {LOG(FATAL) << args[0] << ": cannot expand arguments': " << expanded_arg.error();}expanded_args[i] = *expanded_arg;c_strings.push_back(expanded_args[i].data());}c_strings.push_back(nullptr);if (sigstop) {kill(getpid(), SIGSTOP);}return execv(c_strings[0], c_strings.data()) == 0;
}
其中/system/bin/app_process64的映射的执行文件为:/frameworks/base/cmds/app_process/app_main.cpp,定义在
/frameworks/base/cmds/app_process/Android.bp
低版本是
/frameworks/base/cmds/app_process/Android.mk
cc_binary {name: "app_process",srcs: ["app_main.cpp"],multilib: {lib32: {version_script: ":art_sigchain_version_script32.txt",suffix: "32",},lib64: {version_script: ":art_sigchain_version_script64.txt",suffix: "64",},},ldflags: ["-Wl,--export-dynamic"],shared_libs: ["libandroid_runtime","libbinder","libcutils","libdl","libhidlbase","liblog","libnativeloader","libutils",// This is a list of libraries that need to be included in order to avoid// bad apps. This prevents a library from having a mismatch when resolving// new/delete from an app shared library.// See b/21032018 for more details."libwilhelm",],whole_static_libs: ["libsigchain"],compile_multilib: "both",cflags: ["-Wall","-Werror","-Wunused","-Wunreachable-code",],// If SANITIZE_LITE is revived this will need://product_variables: {// sanitize_lite: {// // In SANITIZE_LITE mode, we create the sanitized binary in a separate location (but reuse// // the same module). Using the same module also works around an issue with make: binaries// // that depend on sanitized libraries will be relinked, even if they set LOCAL_SANITIZE := never.// //// // Also pull in the asanwrapper helper.// relative_install_path: "asan",// required: ["asanwrapper"],// },//},// Create a symlink from app_process to app_process32 or 64// depending on the target configuration.symlink_preferred_arch: true,
}
/frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[]){......if (zygote) {// 启动zygoteruntime.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.");}
}
属性服务
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();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();}// 监听socket 属性服务,最多同时被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();}// 监听property_set_fd,当socket有请求的时候调用handle_property_set_fd 来处理if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd);!result.ok()) {LOG(FATAL) << result.error();}if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) {LOG(FATAL) << result.error();}while (true) {auto pending_functions = epoll.Wait(std::nullopt);if (!pending_functions.ok()) {LOG(ERROR) << pending_functions.error();} else {for (const auto& function : *pending_functions) {(*function)();}}}
}static void handle_property_set_fd() {.....switch (cmd) {case PROP_MSG_SETPROP:{......break;}case PROP_MSG_SETPROP2:{......// 关键代码uint32_t result = HandlePropertySet(name, value, source_context, cr, &socket, &error);if (result != PROP_SUCCESS) {LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid<< " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;}socket.SendUint32(result);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) {.......// 设置属性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 (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.* properties are actually "write-once".// ro开头的是只读,只能设置一次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;}}// 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;
}
总结
init进程在启动过程中主要做了三件事:
- 创建一些文件并挂载设备
- 启动属性服务
- 解析init.rc配置文件并启动zygote进程
【Android 源码学习】 init启动相关推荐
- android源码学习- APP启动流程(android12源码)
前言: 百度一搜能找到很多讲APP启动流程的,但是往往要么就是太老旧(还是基于android6去分析的),要么就是不全(往往只讲了整个流程的一小部分).所以我结合网上现有的文章,以及源码的阅读和调试, ...
- 【Android 源码学习】Zygote启动原理
Android 源码学习 Zygote启动原理 望舒课堂 Zygote进程启动原理学习记录整理. Zygote简介 Zygote是进程在init进程启动时创建的,进程本身是app_process,来源 ...
- 【Android 源码学习】SystemServer启动原理
Android 源码学习 SystemServer启动原理 望舒课堂 SystemServer进程启动原理学习记录整理. 参考文章: Android系统启动流程(三)解析SyetemServer进程启 ...
- 【Android 源码学习】系统架构和启动流程
Android 源码学习 系统架构和启动流程 望舒课堂 学习记录整理.以及以下参考文章的整理汇总.便于我个人的学习记录. 感谢IngresGe,Gityuan的精彩文章.为我们这些初探android系 ...
- Android源码学习之浅析SystemServer脉络
在之前的博文中<Android源码学习之如何创建使用JNI>和<Android源码学习之如何使用eclipse+NDK>中,浅谈了如何创建使用JNI和如何利用NDK工具开发创建 ...
- Android源码阅读---init进程
Android源码阅读-init进程 文章目录 Android源码阅读---init进程 1. 编译命令和进程入口 1. init 进程编译命令 2. main函数流程 2. 主函数处理流程 1. 创 ...
- Android源码编译及启动模拟器
Android源码编译及启动模拟器 源码下载 (1)更改下载源 (2)安装源码下载工具 (3)下载源码 (4)安装环境依赖 源码编译 启动模拟器 源码下载 Ubuntu18.0 (1)更改下载源 源码 ...
- android源码学习-Toast实现原理讲解
前言: 前些日志QQ群有朋友发了一个Toast的崩溃日志.Toast如此简单的用法怎么会崩溃呢?所以顺便就学习了一下Toast在源码中的实现,不算复杂,但内容挺多的,这里就来分享一下,方便读者. 一. ...
- 【Android 源码学习】SharedPreferences 源码学习
第一章:SharedPreferences 源码学习 文章目录 第一章:SharedPreferences 源码学习 Android SharedPreferences的缺陷 MMKV.Jetpack ...
最新文章
- 真正理解线程上下文类加载器(多案例分析)
- sp_MSforeachtable使用方法
- 在fedora21 上的php+mysql+apache环境搭建
- SpringBoot+Shiro学习(一):主要模块介绍
- 页面中文显示问题之终结
- BZOJ 1012: [JSOI2008]最大数maxnumber(线段树)
- 安卓开发.四大组件.activity.1
- 推荐两款 GTD 工具
- java作业 景区门票
- android中的websocket 应用
- STM32 RCC时钟配置
- Datawhale 零基础入门CV赛事-Task2 数据读取与数据扩增
- 中专计算机应用专业简历模板,2016计算机应用专业个人简历模板
- 计算机黑屏的原因及修复,导致笔记本电脑开机黑屏的原因以及对应的修复方法...
- python 读写三菱PLC数据,使用以太网读写Q系列,L系列,Fx系列的PLC数据
- SECRET文件保险柜 V2.7 --统一管理并加密文件
- linux删除某条历史命令,如何从Linux/Unix Bash shell上删除历史记录中的一条命令?...
- linux 下的无线网络配置,详解在LINUX环境下怎样设置无线网络配置
- ie10服务器运行失败,win7系统下无法安装ie10浏览器如何解决?win7系统下无法安装ie10浏览器三种解决方法...
- 公司法人代表变更需要多少钱?