type
status
date
slug
summary
tags
category
icon
password
基于Android 10 源码分析
之前已经大致分析了一下Android系统启动的过程,这里回顾一下:
  1. 上电,从Boot ROM中执行一段烧录好的代码加载bootloader
  1. bootloader执行,引导加载并启动linux kernel
  1. linux kernel启动,并创建第一个用户态的进程init
  1. init进程解析init.rc并启动各种服务,包括通过app_process程序创建并启动Zygote进程和system server进程,这个阶段已经启动了虚拟机,进入了Java世界
  1. system server进程会启动各种服务,包括AMS,WMS等
  1. 启动完成之后,发送广播通知
这里来分析一下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,则返回0
basename(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:
    • ActionParser
    • ServiceParser
    • ImportParser
    • 在加载完init.rc文件之后,会加载/{system,vendor,odm}/etc/init/ 下(Android设备中的目录)的所有rc配置文件:
    • /system/etc/init/ : 核心系统,比如SurfaceFlinger,MediaService,logd
      • ITouch.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)
    • 挂载binderfs
      • Android的IPC机制是通过/dev节点从用户空间访问的.一般会分配三个节点:
      • /dev/binder : 框架/应用进程之间的 IPC,使用 AIDL 接口
      • /dev/hwbinder : 框架/供应商进程之间的 IPC,使用 HIDL 接口 供应商进程之间的 IPC,使用 HIDL 接口
      • /dev/vndbinder : 供应商/供应商进程之间的 IPC,使用 AIDL 接口
    • 启动logd,即Android的日志进程
    • 启动servicemanager,hwservicemanager,vndservicemanager
      • Android O之前,Binder服务通过servicemanager注册,Android O开始binder节点分成了三种,因此对应的servicemanager也分成了三种.
    • 判断启动模式,如果是充电模式,在调用charger程序
    • 正常模式下启动,则挂载文件系统,并启动核心系统服务
      • 核心服务,即那些标记 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
    • 启动zygote相关进程
      • 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));
    • second_stage : 在selinux_setp启动完之后执行
    • fisrt_stage : 默认首先执行
  • 第二个阶段,首先加载int.rc配置,然后再依次在Android设备中查找以下三种配置,并加载:
    • /system/etc/init/
    • /vendor/etc/init/
    • /odm/etc/init/
  • init.rc各个过程中会挂载文件系统,包括binderfs,创建各种文件目录,并分配权限
  • 启动servce manager,Android O开始分成三种,对应三种binder节点,给不同的层使用
Android通知的简单用法Android快捷方式的简单使用
姜康
姜康
一个软件工程师
公告
type
status
date
slug
summary
tags
category
icon
password
🎉博客网站重新制作了🎉
👏欢迎更新体验👏