type
status
date
slug
summary
tags
category
icon
password
基于Android 10 源码分析
之前已经大致分析了一下Android系统启动的过程,这里回顾一下:
- 上电,从Boot ROM中执行一段烧录好的代码加载bootloader
- bootloader执行,引导加载并启动linux kernel
- linux kernel启动,并创建第一个用户态的进程
init
init
进程解析init.rc
并启动各种服务,包括通过app_process
程序创建并启动Zygote进程和system server进程,这个阶段已经启动了虚拟机,进入了Java世界
- system server进程会启动各种服务,包括AMS,WMS等
- 启动完成之后,发送广播通知
这里来分析一下
init
进程的一些主要逻辑:强调一点,init就是一个普通的命令行程序,程序位置在/system/core/init
入口:system/core/init/main.cpp
int main(int argc, char** argv) { // system/bin/ueventd入口 if (!strcmp(basename(argv[0]), "ueventd")) { return ueventd_main(argc, argv); } // 带参启动init 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); } } // 不带参,默认启动init入口 return FirstStageMain(argc, argv); }
main(int argc, char** argv) ,其中argc是命令行参数的个数,默认为1,argv是传入的参数,argv[0]是程序的全路径名,arg[1]才是实际意义上的第一个参数.
strcmp(s1,s2)则是用来比较字符串的,如果s1 == s2,则返回0basename(path),返回的是文件名,比如 “/system/bin/ueventd”,返回uevened
ueventd
其实就是init
进程的一个软连接,在system/bin
中也可以看到,通过ls -l
可以看到:lrwxr-xr-x 1 root shell 4 2020-04-04 01:11 ueventd -> init
这个地方根据程序不同的执行方式,有三种入口:
- 默认启动,执行
FirstStageMain(argc, argv)
- 启动
ueventd
程序,执行ueventd_main(argc, argv)
- 带参启动
init
,执行SubcontextMain(argc, argv, &function_map);
SetupSelinux(argv)
SecondStageMain(argc, argv)
中的一个
目前很多文章都说watchdogd进程也是init进程的软连接,但是在新版本的Android中,比如Android 10,watchdogd是一个独立的进程了,并不是init进程.
先来看下
FirstStageMain
第一阶段: 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)); CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC))); // root也只有只读权限 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))); CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=1000")); CHECKCALL(mkdir("/mnt/vendor", 0755)); CHECKCALL(mkdir("/mnt/product", 0755)); CHECKCALL(mount("tmpfs", "/apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0")); CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0")); SetStdioToDevNull(argv); InitKernelLogging(argv); LOG(INFO) << "init first stage started!"; // execv方式执行 /system/bin/init selinux_setup const char* path = "/system/bin/init"; const char* args[] = {path, "selinux_setup", nullptr}; execv(path, const_cast<char**>(args)); return 1; }
setenv():设置环境变量mount():挂载文件系统:// source是一个名字,target是挂载点,filesystemtype是文件系统类型 // 文件系统类型有"btrfs", "ext4", "jfs", "xfs","vfat", "fuse", "tmpfs", "cgroup", "proc", "mqueue", "nfs", //"cifs","iso9660"等 int mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data);
mknod():Linux中创建字符设备文件或者块设备文件tmpfs:一个基于内存的文件系统,断电后数据丢失ABCD A- 0, 表示十进制 B-用户 C-组用户 D-其他用户 --- -> 0 (no excute , no write ,no read) --x -> 1 excute, (no write, no read) -w- -> 2 write -wx -> 3 write, excute r-- -> 4 read r-x -> 5 read, excute rw- -> 6 read, write , rwx -> 7 read, write , excute
0755:用户具有读/写/执行权限,组用户和其它用户具有读写权限
可以看到这个阶段主要是挂载一些文件系统.并启动SELinux.
启动SELinux
这个过程中会执行:
const char* path = "/system/bin/init"; const char* args[] = {path, "second_stage", nullptr}; execv(path, const_cast<char**>(args));
然后进入到init进程的第二个阶段
第二阶段:SecondStageMain
在第一阶段的源码中有一饿SecondStageMain的方法调用,这个时候会进入第二个执行阶段:
int SecondStageMain(int argc, char** argv) { LOG(INFO) << "init second stage started!"; // 会执行 /system/bin/init subcontext .... InitializeSubcontext(); // 为解析init.rc中的action和service做准备 ActionManager& am = ActionManager::GetInstance(); ServiceList& sm = ServiceList::GetInstance(); // 加载init.rc LoadBootScripts(am, sm); // cgroups:用于控制资源,cpuset相关 am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups"); am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict"); am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux"); // 这里会启动ueventd, 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"); Keychords keychords; am.QueueBuiltinAction( [&epoll, &keychords](const BuiltinArguments& args) -> Result<void> { for (const auto& svc : ServiceList::GetInstance()) { keychords.Register(svc->keycodes()); } keychords.Start(&epoll, HandleKeychord); return {}; }, "KeychordInit"); // Trigger all the boot actions to get us started. am.QueueEventTrigger("init"); // 充电模式下不挂载文件系统,也不启动核心系统服务 std::string bootmode = GetProperty("ro.bootmode", ""); if (bootmode == "charger") { am.QueueEventTrigger("charger"); } else { am.QueueEventTrigger("late-init"); } // Run all property triggers based on current state of the properties. am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers"); return 0; }
可以看到第二个阶段依次做了这些事:
- 加载init.rc配置文件
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"); } // 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("/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); } } 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; }
这里会根据init.rc中的item类型创建对应的parser:
在加载完init.rc文件之后,会加载/{system,vendor,odm}/etc/init/ 下(Android设备中的目录)的所有rc配置文件:
/system/etc/init/
: 核心系统,比如SurfaceFlinger,MediaService,logdITouch.rc hwservicemanager.rc runtime_data.rc android.hidl.allocator@1.0-service.rc iGraphics.rc samba.rc atrace.rc incidentd.rc selinux_dmd.rc audioserver.rc init.huawei.iaware.a15.rc servicemanager.rc balonglogcat.rc init.huawei.os.a15.rc shex.rc blank_screen.rc init.huawei.os.common.rc shutanim.rc bootanim.rc init.huawei.recovery.common.rc statsd.rc bootstat.rc init.system.rc storaged.rc cameraserver.rc installd.rc surfaceflinger.rc displayengineserver.rc keystore.rc thermal-daemon.rc drmserver.rc lmkd.rc thermalservice.rc dubaid.rc logcatd_ext.rc tombstoned.rc dumpstate.rc logd.rc uncrypt.rc gatekeeperd.rc mdnsd.rc update_engine.rc gpuassistant.rc mediadrmserver.rc usbd.rc healthd.rc mediaextractor.rc vdc.rc hilogcat.rc mediametrics.rc vold.rc hilogd.rc mediaserver.rc wait_for_keymaster.rc hiview.rc mtpd.rc wificond.rc hivrarserver.rc netd.rc xlogcat.rc hwhfd.rc perfetto.rc hwnffserver.rc racoon.rc
/vendor/etc/init/
: SOC需要的核心功能和守护程序activity_recognition_service.rc android.hardware.bluetooth@1.0-service.rc android.hardware.cas@1.0-service.rc android.hardware.configstore@1.1-service.rc android.hardware.drm@1.0-service.rc android.hardware.drm@1.1-service.clearkey.rc android.hardware.drm@1.1-service.widevine.rc android.hardware.gatekeeper@1.0-service.rc android.hardware.graphics.allocator@2.0-service.rc android.hardware.graphics.composer@2.2-service.rc android.hardware.health@2.0-service.rc android.hardware.ir@1.0-service.rc android.hardware.keymaster@3.0-service.rc android.hardware.media.omx@1.0-service.rc android.hardware.memtrack@1.0-service.rc android.hardware.secure_element@1.0-service.rc android.hardware.thermal@1.0-service.rc android.hardware.usb@1.0-service.rc android.hardware.vr@1.0-service.rc aptouch_daemon.rc charger connectivity hinetmanager.rc hisecd.rc hw init.audio.rc init.balong_modem.rc init.connectivity.rc init.device.rc init.extmodem.rc init.hisi.rc init.ko.rc init.manufacture.rc init.performance.rc init.platform.rc init.post-fs-data.rc init.protocol.rc init.tee.rc init.vowifi.rc isplogcat.rc modemchr_service.rc recovery rild.rc vendor.huawei.graphics.displayeffect@1.0-service.rc vendor.huawei.hardware.audio@4.0-service.rc vendor.huawei.hardware.biometrics.fingerprint@2.1-service.rc vendor.huawei.hardware.biometrics.hwfacerecognize@1.1-service.rc vendor.huawei.hardware.dolby.dms@1.0-service.rc vendor.huawei.hardware.fm@1.0-service.rc vendor.huawei.hardware.gnss@1.2-service.rc vendor.huawei.hardware.graphics.mediacomm@2.0-service.rc vendor.huawei.hardware.hisupl@1.0-service.rc vendor.huawei.hardware.hivrar@1.3-service.rc vendor.huawei.hardware.hwdisplay.displayengine@1.2-service.rc vendor.huawei.hardware.hwdisplay@1.0-service.rc vendor.huawei.hardware.hwfactoryinterface@1.1-service.rc vendor.huawei.hardware.hwfs@1.0-service.rc vendor.huawei.hardware.hwhiview@1.0-service.rc vendor.huawei.hardware.hwsecurity-service.rc vendor.huawei.hardware.hwupdate@1.0-service.rc vendor.huawei.hardware.hwvibrator@1.0-service.rc vendor.huawei.hardware.iawareperf@1.0-service.rc vendor.huawei.hardware.irsl@1.0-service.rc vendor.huawei.hardware.kds@1.0-service.rc vendor.huawei.hardware.libteec@2.0-service.rc vendor.huawei.hardware.light@2.0-service.rc vendor.huawei.hardware.nfc@1.0-service.rc vendor.huawei.hardware.otasimlock@1.0-service.rc vendor.huawei.hardware.otherdevices@1.0-service.rc vendor.huawei.hardware.perfgenius@2.0-service.rc vendor.huawei.hardware.power@1.0-service.rc vendor.huawei.hardware.sensors@1.0-service.rc vendor.huawei.hardware.tp@1.0-service.rc vendor.huawei.hardware.wifi@1.1-service.rc vndservicemanager.rc
/odm/etc/init/
: 设备制造商使用,比如传感器和其他外设功能或者守护程序init.hisi.odm.rc init.odm.rc
- 在触发early_int 之前,配置cgroup,kptr_restrict,perf等限制资源使用的工具
Cgroup 抽象层
- 触发early init,创建一些文件目录,挂载一些文件系统等,并启动ueventd
on early-init start ueventd
- 触发init,修改权限并挂载binderfs,启动logd.lmkd,servicemanager,hwservicemanager,vndservicemanager等
on init # Mount binderfs mkdir /dev/binderfs mount binder binder /dev/binderfs stats=global chmod 0755 /dev/binderfs symlink /dev/binderfs/binder /dev/binder symlink /dev/binderfs/hwbinder /dev/hwbinder symlink /dev/binderfs/vndbinder /dev/vndbinder chmod 0666 /dev/binderfs/hwbinder chmod 0666 /dev/binderfs/binder chmod 0666 /dev/binderfs/vndbinder # Start logd before any other services run to ensure we capture all of their logs. start logd # Start lmkd before any other services run so that it can register them 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 start lmkd # Start essential services. start servicemanager start hwservicemanager start vndservicemanager
低内存终止守护进程 (lmkd)
- /dev/binder : 框架/应用进程之间的 IPC,使用 AIDL 接口
- /dev/hwbinder : 框架/供应商进程之间的 IPC,使用 HIDL 接口 供应商进程之间的 IPC,使用 HIDL 接口
- /dev/vndbinder : 供应商/供应商进程之间的 IPC,使用 AIDL 接口
Android的IPC机制是通过/dev节点从用户空间访问的.一般会分配三个节点:
Android O之前,Binder服务通过servicemanager注册,Android O开始binder节点分成了三种,因此对应的servicemanager也分成了三种.
charger是关机模式下执行的程序,用于显示充电动画,可参考Android运行状况
核心服务,即那些标记
class core
的服务,比如init程序入口的ueventd:service ueventd /system/bin/ueventd class core critical seclabel u:r:ueventd:s0 shutdown critical
还有就是surfaceFlinger等:
service surfaceflinger /system/bin/surfaceflinger class core animation user system group graphics drmrpc readproc onrestart restart zygote onrestart restart gpuassistant writepid /dev/stune/foreground/tasks socket pdx/system/vr/display/client stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0 socket pdx/system/vr/display/manager stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0 socket pdx/system/vr/display/vsync stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s0
late-init中会触发:
trigger zygote-start
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 update verifier that marks a successful boot. exec_start update_verifier_nonencrypted start netd start zygote start zygote_secondary
zygote_secondary是针对同时支持64位,32位架构的配置:
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote 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/power/state on onrestart restart audioserver onrestart restart cameraserver onrestart restart media onrestart restart netd onrestart restart wificond writepid /dev/cpuset/foreground/tasks service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload class main priority -20 user root group root readproc reserved_disk socket zygote_secondary stream 660 root system socket usap_pool_secondary stream 660 root system onrestart restart zygote writepid /dev/cpuset/foreground/tasks
总结
- init入口中包含5个分支:
- ueventd : 实际上就是init程序的软连接,在init.rc的early-init阶段启动
- selinux_setup : FirstStageMain 中通过
/system/bin/init selinux_setup
启动 - subcontext : SecondStageMain 中启动
auto init_path = GetExecutablePath(); auto child_fd_string = std::to_string(child_fd); const char* args[] = {init_path.c_str(), "subcontext", context_.c_str(), child_fd_string.c_str(), nullptr}; execv(init_path.data(), const_cast<char**>(args));
- 第二个阶段,首先加载int.rc配置,然后再依次在Android设备中查找以下三种配置,并加载:
- /system/etc/init/
- /vendor/etc/init/
- /odm/etc/init/
- init.rc各个过程中会挂载文件系统,包括binderfs,创建各种文件目录,并分配权限
- 启动servce manager,Android O开始分成三种,对应三种binder节点,给不同的层使用
- 作者:姜康
- 链接:https://jiangkang.tech/article/4e1c6acc-d881-4f93-8e8b-bbe6c7ed78cf
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章