Android系统启动流程

  • 启动流程
    • Loader
    • Kernel
    • Native
    • Framework
    • Application
  • init进程
    • 启动
    • rc文件规则
      • Actions
      • Commands
      • Service
      • Options
    • init.rc文件
    • init进程的功能
  • Zygote进程
    • main
    • AndroidRuntime::start
    • AndroidRuntime::startVm
    • AndroidRuntime::startReg
    • ZygoteInit.main
    • ZygoteInit.registerZygoteSocket
    • ZygoteInit.preload
    • ZygoteInit.runSelectLoop
    • ZygoteInit.acceptCommandPeer
    • ZygoteConnection.runOnce
    • Zygote总结:
  • System Server进程
    • ZygoteInit.main
    • ZygoteInit.startSystemServer
    • Zygote.forkSystemServer
    • com_android_internal_os_Zygote.nativeForkSystemServer
    • com_android_internal_os_Zygote.ForkAndSpecializeCommon
    • fork
    • ZygoteInit.handleSystemServerProcess
    • RuntimeInit.zygoteInit
    • ZygoteInit.main
    • ZygoteInit.MethodAndArgsCaller.run
    • SystemServer.main
    • system server进程总结:

启动流程

Android系统启动过程往细了说可以分为5步:
Loader --》Kernel --》Native --》Framework --》Application

Loader

  • Boot ROM: 当手机处于关机状态时,长按Power键开机,引导芯片开始从固化在ROM里的预设出代码开始执行,然后加载引导程序到RAM
  • Boot Loader:这是启动Android系统之前的引导程序,主要是检查RAM,初始化硬件参数等功能

Kernel

Kernel层是指Android内核层,到这里才刚刚开始进入Android系统

  • 启动Kernel的swapper进程(pid=0):该进程又称为idle进程, 系统初始化过程Kernel由无到有开创的第一个进程, 用于初始化进程管理、内存管理,加载Display,Camera Driver,Binder Driver等相关工作
  • 启动kthreadd进程(pid=2):是Linux系统的内核进程,会创建内核工作线程kworkder,软中断线程ksoftirqd,thermal等内核守护进程。kthreadd进程是所有内核进程的鼻祖

Native

这里的Native层主要包括init孵化来的用户空间的守护进程、HAL层以及开机动画等。启动init进程(pid=1),是Linux系统的用户进程,init进程是所有用户进程的鼻祖

  • init进程会孵化出ueventd、logd、healthd、installd、adbd、lmkd等用户守护进程
  • init进程还启动servicemanager(binder服务管家)、bootanim(开机动画)等重要服务
  • init进程孵化出Zygote进程,Zygote进程是Android系统的第一个Java进程(即虚拟机进程),Zygote是所有Java进程的父进程

Framework

  • Zygote进程启动后,加载ZygoteInit类,注册Zygote Socket服务端套接字;加载虚拟机;加载类,加载系统资源
  • System Server进程,是由Zygote进程fork而来,System Server是Zygote孵化的第一个进程,System Server负责启动和管理整个Java framework,包含ActivityManager,PowerManager等服务
  • Media Server进程,是由init进程fork而来,负责启动和管理整个C++ framework,包含AudioFlinger,Camera Service等服务

Application

  • Zygote进程孵化出的第一个App进程是Launcher,即手机桌面APP,没错,手机桌面就是跟我们平时使用的APP一样,它也是一个应用
  • 所有APP进程都是由zygote进程fork出来的

这些层之间,有的并不能直接交流,比如Native与Kernel之间要经过系统调用才能访问,Java层和Native层需要通过JNI进行调用

严格来说,Android系统实际上是运行于Linux内核上的一系列服务进程,这些进程是维持设备正常运行的关键,而这些进程的老祖宗就是init进程


init进程

上面也介绍到了,当内核启动完成后,就会创建用户空间的第一个进程,即init进程;后面所有的进程,比如Binder机制中的ServiceManager,Zygote都是由init进程孵化出来的

启动

当init进程启动后会调用/system/core/init/Init.cpp的main()方法

int main(int argc, char** argv) {...klog_init();  //初始化kernel log,位于设备节点/dev/kmsgklog_set_level(KLOG_NOTICE_LEVEL); //设置输出的log级别// 输出init启动阶段的logNOTICE("init%s started!\n", is_first_stage ? "" : " second stage");property_init(); //创建一块共享的内存空间,用于属性服务signal_handler_init();  //初始化子进程退出的信号处理过程property_load_boot_defaults(); //加载default.prop文件start_property_service();   //启动属性服务器(通过socket通信)init_parse_config_file("/init.rc"); //解析init.rc文件//执行rc文件中触发器为 on early-init的语句action_for_each_trigger("early-init", action_add_queue_tail);//等冷插拔设备初始化完成queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");//设备组合键的初始化操作queue_builtin_action(keychord_init_action, "keychord_init");// 屏幕上显示Android静态Logo queue_builtin_action(console_init_action, "console_init");//执行rc文件中触发器为 on init的语句action_for_each_trigger("init", action_add_queue_tail);queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");char bootmode[PROP_VALUE_MAX];//当处于充电模式,则charger加入执行队列;否则late-init加入队列。if (property_get("ro.bootmode", bootmode) > 0 && strcmp(bootmode, "charger") == 0) {action_for_each_trigger("charger", action_add_queue_tail);} else {action_for_each_trigger("late-init", action_add_queue_tail);}//触发器为属性是否设置queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");while (true) {if (!waiting_for_exec) {execute_one_command();restart_processes(); }int timeout = -1;if (process_needs_restart) {timeout = (process_needs_restart - gettime()) * 1000;if (timeout < 0)timeout = 0;}if (!action_queue_empty() || cur_action) {timeout = 0;}epoll_event ev;//循环 等待事件发生int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));if (nr == -1) {ERROR("epoll_wait failed: %s\n", strerror(errno));} else if (nr == 1) {((void (*)()) ev.data.ptr)();}}return 0;
}

这里很重要的一句话就是init_parse_config_file,然后去解析init.rc文件,init.rc位于/bootable/recovery/etc/init.rc;需要注意的是这就是一个脚本文件,就像Android打包用到的gradle脚本一样

rc文件规则

这个文件解析具体实现在init_parser.cpp文件中,一个完整的init.rc脚本由四种类型的声明组成

  • Action(动作)
  • Commands(命令)
  • Service(服务)
  • Options(选项)

rc文件有一些通用的语法规则

  • 注释以 # 开头
  • 关键字和参数以空格分割,每个语句以行为单位
  • C语言风格的反斜杠转义字符("")可以用来为参数添加空格
  • 为了防止字符串中的空格把其切割成多个部分,我们需要对其使用双引号
  • 行尾的反斜杠用来表示下面一行是同一行
  • Actions和Service暗示着下一个新语句的开始,这两个关键字后面跟着的commands或者options都属于这个新语句
  • ActionsService有唯一的名字,如果出现和已有Actions和Service重名的会被当做错误而忽略

Actions

Actions代表一些Action,Action代表一组命令(Commands),每个Action都有一个trigger(触发器),这个触发器决定了在什么情况下执行该Action中定义的命令;当一些条件满足触发器的条件时,该Action中定义的命令会被添加到“命令执行队列”的尾部,如果命令已经存在了就不会再添加了

Action的格式如下

on <trgger> ## on后面接触发条件<command1> ## 命令1<command2> ## 命令2<command3> ## 命令3...

不同的脚本用【on】来区分,on后面跟一个触发器,当被触发时,下面的命令就会以此执行

常用的有以下几种事件触发器

类型                      说明
-------------------------------------------------
boot                    init.rc被装载后触发
device-added-<path>     当设备节点添加时触发
device-removed-<path>   当设备节点移除时触发
service-exited-<name>   在指定的服务(service)退出时触发
early-init              init程序初始化之前触发
late-init               init程序初始化之后触发
init                    初始化时触发(在 /init.conf (启动配置文件)被装载之后)

Commands

  • exec< path>[< argument>]* :fork并执行一个程序,其路径为< path>,这条命令将阻塞直到该程序启动完成
  • ifup< interface>:使网络接口< interface>成功连接
  • chdir< directory>:更改工作目录< directory>
  • chmod< octal-mode>< path>:更改文件访问权限
  • chroot< directory>:更改根目录位置
  • class_start< serviceclass>:启动由< serviceclass>类名指定的所有相关服务,如果它们不在运行状态的话
  • class_stop< serviceclass>:停止所有由< serviceclass>类名指定的服务,如果它们还在运行的话
  • domainname< name>:设置域名
  • start< service>:启动一个服务,如果没有运行
  • stop< service>:停止一个服务,如果还在运行
  • sysclktz< mins_west_of_gmt>:设置基准时间
  • write< path>< String>[< String>]*:打开一个文件,写入一个或者多个String

Service

Service其实是一个可执行程序,以service开头的脚本,在特定选项的约束下会被init程序启动或者重启(Service可以在配置中指定是否需要在退出时重启,这样当Service出现crash时就可以有机会复原)

脚本格式如下

service <name> <pathname> [ <argument> ]*<option><option>...
  • service开头表明这是一个可执行程序
  • < name> 表示服务名
  • < pathname> 此服务所在路径,因为是可执行文件,所以肯定有存储路径
  • < argument> 启动Service所带的参数
  • < option> 对service的设置的选项

Options

可用选项如下,也就是上面Service所用到的< option>

  • critical:表明这是对设备至关重要的一个服务,如果它在四分钟内退出超过四次,则设备进入恢复模式
  • disabled:此服务不会自动启动,而是需要显示调用服务名来启动
  • socket< name>< type>< perm>[< user>[< group>] ]:创建一个名为/dev/socket/< name>的unix domain socket,然后将它的fd值传给启动它的进程;有效的< type>值包括dgram,stream,seqpacket,而user和group默认值是0
  • user< username>:在启动服务前将用户切换至< username>,默认情况下用户都是root
  • group< groupname>[< groupname>]*:在启动服务前将用户组切换至< groupname>]
  • oneshot:当该服务退出时,不要主动去重启它
  • class< name>:为该服务指定一个class名,同一个class的所有服务必须同时启动或者停止,默认情况下< name>值是default
  • onrestart:当此服务重启时执行某些命令

init.rc文件

# Copyright (C) 2012 The Android Open Source Project
#
# IMPORTANT: Do not create world writable files or directories.
# This is a common source of Android security bugs.
#"【import <filename>一个init配置文件,扩展当前配置。】"
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.${ro.zygote}.rc
import /init.trace.rc"【触发条件early-init,在early-init阶段调用以下行】"
on early-init# Set init and its forked children's oom_adj.write /proc/1/oom_score_adj -1000"【打开路径为<path>的一个文件,并写入一个或多个字符串】"# Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.write /sys/fs/selinux/checkreqprot 0# Set the security context for the init process.# This should occur before anything else (e.g. ueventd) is started."【这段脚本的意思是init进程启动之后就马上调用函数setcon将自己的安全上下文设置为“u:r:init:s0”,即将init进程的domain指定为init。】"setcon u:r:init:s0# Set the security context of /adb_keys if present."【恢复指定文件到file_contexts配置中指定的安全上线文环境】"restorecon /adb_keys"【执行start ueventd的命令。ueventd是一个service后面有定义】 "start ueventd"【mkdir <path> [mode] [owner] [group]   //创建一个目录<path>,可以选择性地指定mode、owner以及group。如果没有指定,默认的权限为755,并属于root用户和root组。】"# create mountpointsmkdir /mnt 0775 root systemon init"【设置系统时钟的基准,比如0代表GMT,即以格林尼治时间为准】"sysclktz 0"【设置kernel日志等级】"
loglevel 6 ####write /proc/bootprof "INIT: on init start" ####"【symlink <target> <path>    //创建一个指向<path>的软连接<target>。】"# Backward compatibilitysymlink /system/etc /etcsymlink /sys/kernel/debug /d# Right now vendor lives on the same filesystem as system,# but someday that may change.symlink /system/vendor /vendor"【创建一个目录<path>,可以选择性地指定mode、owner以及group。】"# Create cgroup mount point for cpu accountingmkdir /acctmount cgroup none /acct cpuacctmkdir /acct/uid"【mount <type> <device> <dir> [ <mountoption> ]   //在目录<dir>挂载指定的设备。<device> 可以是以 mtd@name 的形式指定一个mtd块设备。<mountoption>包括 ro、rw、remount、noatime、 ...】"# Create cgroup mount point for memorymount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000mkdir /sys/fs/cgroup/memory 0750 root systemmount cgroup none /sys/fs/cgroup/memory memorywrite /sys/fs/cgroup/memory/memory.move_charge_at_immigrate 1"【chown <owner> <group> <path>   //改变文件的所有者和组。】""【后面的一些行因为类似,就省略了】".....# Healthd can trigger a full boot from charger mode by signaling this
# property when the power button is held.
on property:sys.boot_from_charger_mode=1"【停止指定类别服务类下的所有已运行的服务】"class_stop charger"【触发一个事件,将该action排在某个action之后(用于Action排队)】"trigger late-init# Load properties from /system/ + /factory after fs mount.
on load_all_props_action"【从/system,/vendor加载属性。默认包含在init.rc】"load_all_props# Indicate to fw loaders that the relevant mounts are up.
on firmware_mounts_complete"【删除指定路径下的文件】"rm /dev/.booting# Mount filesystems and start core system services.
on late-init"【触发一个事件。用于将一个action与另一个 action排列。】"trigger early-fstrigger fstrigger post-fstrigger post-fs-data# Load properties from /system/ + /factory after fs mount. Place# this in another action so that the load will be scheduled after the prior# issued fs triggers have completed.trigger load_all_props_action# Remove a file to wake up anything waiting for firmware.trigger firmware_mounts_completetrigger early-boottrigger booton post-fs..."【一些创造目录,建立链接,更改权限的操作,这里省略】"on post-fs-data..."【一些创造目录,建立链接,更改权限的操作,这里省略】""【恢复指定文件到file_contexts配置中指定的安全上线文环境】"restorecon /data/mediaserver"【将系统属性<name>的值设置为<value>,即以键值对的方式设置系统属性】"# Reload policy from /data/security if present.setprop selinux.reload_policy 1"【以递归的方式恢复指定目录到file_contexts配置中指定的安全上下文中】"# Set SELinux security contexts on upgrade or policy update.restorecon_recursive /data# If there is no fs-post-data action in the init.<device>.rc file, you# must uncomment this line, otherwise encrypted filesystems# won't work.# Set indication (checked by vold) that we have finished this action#setprop vold.post_fs_data_done 1on boot"【初始化网络】"# basic network initifup lo"【设置主机名为localhost】"hostname localhost"【设置域名localdomain】"domainname localdomain"【设置资源限制】"# set RLIMIT_NICE to allow priorities from 19 to -20setrlimit 13 40 40"【这里省略了一些chmod,chown,等操作,不多解释】"...# Define default initial receive window size in segments.setprop net.tcp.default_init_rwnd 60"【重启core服务】"class_start coreon nonencryptedclass_start mainclass_start late_starton property:vold.decrypt=trigger_default_encryptionstart defaultcryptoon property:vold.decrypt=trigger_encryptionstart surfaceflingerstart encrypton property:sys.init_log_level=*loglevel ${sys.init_log_level}on chargerclass_start chargeron property:vold.decrypt=trigger_reset_mainclass_reset mainon property:vold.decrypt=trigger_load_persist_propsload_persist_propson property:vold.decrypt=trigger_post_fs_datatrigger post-fs-dataon property:vold.decrypt=trigger_restart_min_frameworkclass_start mainon property:vold.decrypt=trigger_restart_frameworkclass_start mainclass_start late_starton property:vold.decrypt=trigger_shutdown_frameworkclass_reset late_startclass_reset mainon property:sys.powerctl=*powerctl ${sys.powerctl}# system server cannot write to /proc/sys files,
# and chown/chmod does not work for /proc/sys/ entries.
# So proxy writes through init.
on property:sys.sysctl.extra_free_kbytes=*write /proc/sys/vm/extra_free_kbytes ${sys.sysctl.extra_free_kbytes}# "tcp_default_init_rwnd" Is too long!
on property:sys.sysctl.tcp_def_init_rwnd=*write /proc/sys/net/ipv4/tcp_default_init_rwnd ${sys.sysctl.tcp_def_init_rwnd}"【守护进程】"
## Daemon processes to be run by init.
##
service ueventd /sbin/ueventdclass corecriticalseclabel u:r:ueventd:s0"【日志服务进程】"
service logd /system/bin/logdclass coresocket logd stream 0666 logd logdsocket logdr seqpacket 0666 logd logdsocket logdw dgram 0222 logd logdseclabel u:r:logd:s0"【Healthd是android4.4之后提出来的一种中介模型,该模型向下监听来自底层的电池事件,向上传递电池数据信息给Framework层的BatteryService用以计算电池电量相关状态信息】"
service healthd /sbin/healthdclass corecriticalseclabel u:r:healthd:s0"【控制台进程】"
service console /system/bin/sh"【为当前service设定一个类别.相同类别的服务将会同时启动或者停止,默认类名是default】"class core"【服务需要一个控制台】"console"【服务不会自动启动,必须通过服务名显式启动】"disabled"【在执行此服务之前切换用户名,当前默认的是root.自Android M开始,即使它要求linux capabilities,也应该使用该选项.很明显,为了获得该功能,进程需要以root用户运行】"user shellseclabel u:r:shell:s0on property:ro.debuggable=1start console# 启动adbd服务进程
service adbd /sbin/adbd --root_seclabel=u:r:su:s0class core"【创建一个unix域下的socket,其被命名/dev/socket/<name>. 并将其文件描述符fd返回给服务进程.其中,type必须为dgram,stream或者seqpacke,user和group默认是0.seclabel是该socket的SELLinux的安全上下文环境,默认是当前service的上下文环境,通过seclabel指定】"socket adbd stream 660 system systemdisabledseclabel u:r:adbd:s0# adbd on at boot in emulator
on property:ro.kernel.qemu=1start adbd"【内存管理服务,内存不够释放内存】"
service lmkd /system/bin/lmkdclass corecriticalsocket lmkd seqpacket 0660 system system"【ServiceManager是一个守护进程,它维护着系统服务和客户端的binder通信。
在Android系统中用到最多的通信机制就是Binder,Binder主要由Client、Server、ServiceManager和Binder驱动程序组成。其中Client、Service和ServiceManager运行在用户空间,而Binder驱动程序运行在内核空间。核心组件就是Binder驱动程序了,而ServiceManager提供辅助管理的功能,无论是Client还是Service进行通信前首先要和ServiceManager取得联系。而ServiceManager是一个守护进程,负责管理Server并向Client提供查询Server的功能。】"
service servicemanager /system/bin/servicemanagerclass coreuser systemgroup systemcriticalonrestart restart healthd"【servicemanager 服务启动时会重启zygote服务】"onrestart restart zygoteonrestart restart mediaonrestart restart surfaceflingeronrestart restart drm"【Vold是Volume Daemon的缩写,它是Android平台中外部存储系统的管控中心,是管理和控制Android平台外部存储设备的后台进程】"
service vold /system/bin/voldclass coresocket vold stream 0660 root mountioprio be 2"【Netd是Android系统中专门负责网络管理和控制的后台daemon程序】"
service netd /system/bin/netdclass mainsocket netd stream 0660 root systemsocket dnsproxyd stream 0660 root inetsocket mdns stream 0660 root systemsocket fwmarkd stream 0660 root inet"【debuggerd是一个daemon进程,在系统启动时随着init进程启动。主要负责将进程运行时的信息dump到文件或者控制台中】"
service debuggerd /system/bin/debuggerdclass mainservice debuggerd64 /system/bin/debuggerd64class main"【Android RIL (Radio Interface Layer)提供了Telephony服务和Radio硬件之间的抽象层】"
# for using TK init.modem.rc rild-daemon setting
#service ril-daemon /system/bin/rild
#    class main
#    socket rild stream 660 root radio
#    socket rild-debug stream 660 radio system
#    user root
#    group radio cache inet misc audio log"【提供系统 范围内的surface composer功能,它能够将各种应用 程序的2D、3D surface进行组合。】"
service surfaceflinger /system/bin/surfaceflingerclass coreuser systemgroup graphics drmrpconrestart restart zygote"【DRM可以直接访问DRM clients的硬件。DRM驱动用来处理DMA,内存管理,资源锁以及安全硬件访问。为了同时支持多个3D应用,3D图形卡硬件必须作为一个共享资源,因此需要锁来提供互斥访问。DMA传输和AGP接口用来发送图形操作的buffers到显卡硬件,因此要防止客户端越权访问显卡硬件。】"
#make sure drm server has rights to read and write sdcard ####
service drm /system/bin/drmserverclass mainuser drm# group drm system inet drmrpc ####group drm system inet drmrpc sdcard_r ####"【媒体服务,无需多说】"
service media /system/bin/mediaserverclass mainuser root ####
#   google default ####
#   user media    ####group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm media sdcard_r system net_bt_stack ####
#   google default ####
#   group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm ####ioprio rt 4"【设备加密相关服务】"
# One shot invocation to deal with encrypted volume.
service defaultcrypto /system/bin/vdc --wait cryptfs mountdefaultencrypteddisabled"【当服务退出时,不重启该服务】"oneshot# vold will set vold.decrypt to trigger_restart_framework (default# encryption) or trigger_restart_min_framework (other encryption)# One shot invocation to encrypt unencrypted volumes
service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace defaultdisabledoneshot# vold will set vold.decrypt to trigger_restart_framework (default# encryption)"【开机动画服务】"
service bootanim /system/bin/bootanimationclass coreuser graphics
#    group graphics audio ####group graphics media audio ####disabledoneshot"【在Android系统中,PackageManagerService用于管理系统中的所有安装包信息及应用程序的安装卸载,但是应用程序的安装与卸载并非PackageManagerService来完成,而是通过PackageManagerService来访问installd服务来执行程序包的安装与卸载的。】"
service installd /system/bin/installdclass mainsocket installd stream 600 system systemservice flash_recovery /system/bin/install-recovery.shclass mainseclabel u:r:install_recovery:s0oneshot"【vpn相关的服务】"
service racoon /system/bin/racoonclass mainsocket racoon stream 600 system system# IKE uses UDP port 500. Racoon will setuid to vpn after binding the port.group vpn net_admin inetdisabledoneshot"【android中有mtpd命令可以连接vpn】"
service mtpd /system/bin/mtpdclass mainsocket mtpd stream 600 system systemuser vpngroup vpn net_admin inet net_rawdisabledoneshotservice keystore /system/bin/keystore /data/misc/keystoreclass mainuser keystoregroup keystore drmrpc"【可以用dumpstate 获取设备的各种信息】"
service dumpstate /system/bin/dumpstate -sclass mainsocket dumpstate stream 0660 shell logdisabledoneshot"【mdnsd 是多播 DNS 和 DNS 服务发现的守护程序。】"
service mdnsd /system/bin/mdnsdclass mainuser mdnsrgroup inet net_rawsocket mdnsd stream 0660 mdnsr inetdisabledoneshot"【触发关机流程继续往下走】"
service pre-recovery /system/bin/uncryptclass maindisabled"【当服务退出时,不重启该服务】"oneshot

启动顺序是on early-init -> init -> late-init -> boot,接下来就是各种服务的启动

init进程的功能

  • 分析和运行所有的init.rc文件
  • 生成设备驱动节点(通过rc文件创建)
  • 处理子进程的终止(signal方式)
  • 提供属性服务

Zygote进程

在Android中,zygote是整个系统创建新进程的核心进程。在init进程启动后就会创建zygote进程;zygote进程在内部会先启动Dalvik虚拟机,继而加载一些必要的系统资源和系统类,最后进入一种监听状态。在之后的运作中,当其他系统模块(比如AMS)希望创建新进程时,只需向zygote进程发出请求,zygote进程监听到该请求后,会相应地fork出新的进程,于是这个新进程在初生之时,就先天具有了自己的Dalvik虚拟机以及系统资源

其实在早期的Android版本中,Zygote的启动命令直接是写在init.rc中的,但是随着硬件的不断升级换代,Android系统也要面对32位和64位机器同时存在的情况,所以对Zygote启动也需要根据不同情况对待

在init.rc顶部可以看到有这么一句话

import /init.${ro.zygote}.rc

这里会根据系统属性ro.zygote的值去加载不同的描述Zygote的rc脚本,比如

  • init.zygote32.rc
  • init.zygote64.rc
  • init.zygote32_64.rc
  • init.zygote64_32.rc

以init.zygote64_32.rc为例

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygoteclass mainsocket zygote stream 660 root systemonrestart write /sys/android_power/request_state wakeonrestart write /sys/power/state ononrestart restart audioserveronrestart restart cameraserveronrestart restart mediaonrestart restart netdwritepid /dev/cpuset/foreground/tasksservice zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondaryclass mainsocket zygote_secondary stream 660 root systemonrestart restart zygotewritepid /dev/cpuset/foreground/tasks

如上,可以看到服务名(进程名)是zygote,对应的可执行程序是app_processXX,而且还创建了一个名为zygote的unix domain socket,类型是stream,这个socket是为了后面IPC所用;上面可以看到还有一个zygote_secondary的进程,其实这是为了适配不同的abi型号

其中Zygote进程能够重启的地方有

  • servicemanager进程被杀
  • surfaceflinger进程被杀
  • Zygote进程自己被杀
  • system_server进程被杀

接下来看看zygote启动过程,zygote对应的可执行文件就是/system/bin/app_processXX,也就是说系统启动时会执行到这个可执行文件的main()函数里

main

int main(int argc, char* const argv[])
{//Android运行时环境,传到的参数argv为“-Xzygote /system/bin --zygote --start-system-server”AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));argc--; argv++; //忽略第一个参数int i;for (i = 0; i < argc; i++) {if (argv[i][0] != '-') {break;}if (argv[i][1] == '-' && argv[i][2] == 0) {++i;break;}runtime.addOption(strdup(argv[i]));}//参数解析bool zygote = false;bool startSystemServer = false;bool application = false;String8 niceName;String8 className;++i;while (i < argc) {const char* arg = argv[i++];if (strcmp(arg, "--zygote") == 0) {zygote = true;//--zygote表示当前进程用于承载zygote//对于64位系统nice_name为zygote64; 32位系统为zygoteniceName = ZYGOTE_NICE_NAME;} else if (strcmp(arg, "--start-system-server") == 0) {//是否需要启动system serverstartSystemServer = true;} else if (strcmp(arg, "--application") == 0) {//启动进入独立的程序模式application = true;} else if (strncmp(arg, "--nice-name=", 12) == 0) {//niceName 为当前进程别名,区别abi型号niceName.setTo(arg + 12);} else if (strncmp(arg, "--", 2) != 0) {className.setTo(arg);break;} else {--i;break;}}Vector<String8> args;if (!className.isEmpty()) {// 运行application或tool程序args.add(application ? String8("application") : String8("tool"));runtime.setClassNameAndArgs(className, argc - i, argv + i);} else {//进入zygote模式,创建 /data/dalvik-cache路径maybeCreateDalvikCache();if (startSystemServer) {args.add(String8("start-system-server"));}char prop[PROP_VALUE_MAX];if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {return 11;}String8 abiFlag("--abi-list=");abiFlag.append(prop);args.add(abiFlag);for (; i < argc; ++i) {args.add(String8(argv[i]));}}//设置进程名if (!niceName.isEmpty()) {runtime.setArgv0(niceName.string());set_process_name(niceName.string());}if (zygote) {runtime.start("com.android.internal.os.ZygoteInit", args, zygote);} else if (className) {runtime.start("com.android.internal.os.RuntimeInit", args, zygote);} else {//没有指定类名或zygote,参数错误return 10;}
}

根据传入参数的不同可以有两种启动方式,一个是 “com.android.internal.os.RuntimeInit”, 另一个是 ”com.android.internal.os.ZygoteInit", 对应RuntimeInit 和 ZygoteInit 两个类, 这两个类的主要区别在于Java端,可以明显看出,ZygoteInit 相比 RuntimeInit 多做了很多事情,比如说 “preload", “gc” 等等。但是在Native端,他们都做了相同的事, startVM() 和 startReg()

在当前场景中,init.rc指定了–zygote选项,并且args有添加start-system-server值,所以接下来执行

AndroidRuntime::start

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{static const String8 startSystemServer("start-system-server");for (size_t i = 0; i < options.size(); ++i) {if (options[i] == startSystemServer) {const int LOG_BOOT_PROGRESS_START = 3000;}}const char* rootDir = getenv("ANDROID_ROOT");if (rootDir == NULL) {rootDir = "/system";if (!hasDir("/system")) {return;}setenv("ANDROID_ROOT", rootDir, 1);}JniInvocation jni_invocation;jni_invocation.Init(NULL);JNIEnv* env;// 虚拟机创建,主要篇幅是关于虚拟机参数的设置if (startVm(&mJavaVM, &env, zygote) != 0) {return;}onVmCreated(env);// JNI方法注册if (startReg(env) < 0) {return;}jclass stringClass;jobjectArray strArray;jstring classNameStr;//等价 strArray= new String[options.size() + 1];stringClass = env->FindClass("java/lang/String");strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);//等价 strArray[0] = "com.android.internal.os.ZygoteInit"classNameStr = env->NewStringUTF(className);env->SetObjectArrayElement(strArray, 0, classNameStr);//等价 strArray[1] = "start-system-server";//    strArray[2] = "--abi-list=xxx";//其中xxx为系统响应的cpu架构类型,比如arm64-v8a.for (size_t i = 0; i < options.size(); ++i) {jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());env->SetObjectArrayElement(strArray, i + 1, optionsStr);}//将"com.android.internal.os.ZygoteInit"转换为"com/android/internal/os/ZygoteInit"char* slashClassName = toSlashClassName(className);//找到Zygoteinit类jclass startClass = env->FindClass(slashClassName);if (startClass == NULL) {...} else {//找到这个类后就继续找成员函数main方法的Mehtod IDjmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");// 通过反射调用ZygoteInit.main()方法env->CallStaticVoidMethod(startClass, startMeth, strArray);}//释放相应对象的内存空间free(slashClassName);mJavaVM->DetachCurrentThread();mJavaVM->DestroyJavaVM();
}

AndroidRuntime::startVm

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{// JNI检测功能,用于native层调用jni函数时进行常规检测,比较弱字符串格式是否符合要求,资源是否正确释放。该功能一般用于早期系统调试或手机Eng版,对于User版往往不会开启,引用该功能比较消耗系统CPU资源,降低系统性能。bool checkJni = false;property_get("dalvik.vm.checkjni", propBuf, "");if (strcmp(propBuf, "true") == 0) {checkJni = true;} else if (strcmp(propBuf, "false") != 0) {property_get("ro.kernel.android.checkjni", propBuf, "");if (propBuf[0] == '1') {checkJni = true;}}if (checkJni) {addOption("-Xcheck:jni");}//虚拟机产生的trace文件,主要用于分析系统问题,路径默认为/data/anr/traces.txtparseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");//对于不同的软硬件环境,这些参数往往需要调整、优化,从而使系统达到最佳性能parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");parseRuntimeOption("dalvik.vm.heaptargetutilization",heaptargetutilizationOptsBuf, "-XX:HeapTargetUtilization=");...//preloaded-classes文件内容是由WritePreloadedClassFile.java生成的,//在ZygoteInit类中会预加载工作将其中的classes提前加载到内存,以提高系统性能if (!hasFile("/system/etc/preloaded-classes")) {return -1;}//初始化虚拟机if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {ALOGE("JNI_CreateJavaVM failed\n");return -1;}
}

AndroidRuntime::startReg

int AndroidRuntime::startReg(JNIEnv* env)
{//设置线程创建方法为javaCreateThreadEtc androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);env->PushLocalFrame(200);//进程JNI方法的注册if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {env->PopLocalFrame(NULL);return -1;}env->PopLocalFrame(NULL);return 0;
}

总结一下Zygote native 进程做了哪些主要工作:

  • 创建虚拟机–startVM
  • 注册JNI函数–startReg
  • 通过JNI知道Java层的com.android.internal.os.ZygoteInit 类,调用main 函数,进入java 世界

这就开始进入java层了

/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

ZygoteInit.main

public static void main(String argv[]) {try {RuntimeInit.enableDdms(); //开启DDMS功能SamplingProfilerIntegration.start();boolean startSystemServer = false;String socketName = "zygote";String abiList = null;for (int i = 1; i < argv.length; i++) {if ("start-system-server".equals(argv[i])) {startSystemServer = true;} else if (argv[i].startsWith(ABI_LIST_ARG)) {abiList = argv[i].substring(ABI_LIST_ARG.length());} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {socketName = argv[i].substring(SOCKET_NAME_ARG.length());} else {throw new RuntimeException("Unknown command line argument: " + argv[i]);}}...registerZygoteSocket(socketName); //为Zygote注册socketpreload(); // 预加载类和资源SamplingProfilerIntegration.writeZygoteSnapshot();gcAndFinalize(); //GC操作if (startSystemServer) {startSystemServer(abiList, socketName);//启动system_server}runSelectLoop(abiList); //进入循环模式closeServerSocket();} catch (MethodAndArgsCaller caller) {caller.run(); //启动system_server中会讲到。} catch (RuntimeException ex) {closeServerSocket();throw ex;}
}

ZygoteInit.registerZygoteSocket

private static void registerZygoteSocket(String socketName) {if (sServerSocket == null) {int fileDesc;final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;try {String env = System.getenv(fullSocketName);fileDesc = Integer.parseInt(env);} catch (RuntimeException ex) {...}try {FileDescriptor fd = new FileDescriptor();fd.setInt$(fileDesc); //设置文件描述符sServerSocket = new LocalServerSocket(fd); //创建Socket的本地服务端} catch (IOException ex) {...}}
}

在这里就是实例化一个LocalServerSocket,这样zygote就可以作为服务端,不断的获取其它进程发送过来的请求

ZygoteInit.preload

static void preload() {//预加载位于/system/etc/preloaded-classes文件中的类preloadClasses();//预加载资源,包含drawable和color资源preloadResources();//预加载OpenGLpreloadOpenGL();//通过System.loadLibrary()方法,//预加载"android","compiler_rt","jnigraphics"这3个共享库preloadSharedLibraries();//预加载  文本连接符资源preloadTextResources();//仅用于zygote进程,用于内存共享的进程WebViewFactory.prepareWebViewInZygote();
}

执行Zygote进程的初始化,对于类加载,采用反射机制Class.forName()方法来加载。对于资源加载,主要是 com.android.internal.R.array.preloaded_drawables和com.android.internal.R.array.preloaded_color_state_lists,在应用程序中以com.android.internal.R.xxx开头的资源,便是此时由Zygote加载到内存的

ZygoteInit.runSelectLoop

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();//sServerSocket是socket通信中的服务端,即zygote进程。保存到fds[0]fds.add(sServerSocket.getFileDescriptor());peers.add(null);while (true) {StructPollfd[] pollFds = new StructPollfd[fds.size()];for (int i = 0; i < pollFds.length; ++i) {pollFds[i] = new StructPollfd();pollFds[i].fd = fds.get(i);pollFds[i].events = (short) POLLIN;}try {//处理轮询状态,当pollFds有事件到来则往下执行,否则阻塞在这里Os.poll(pollFds, -1);} catch (ErrnoException ex) {...}for (int i = pollFds.length - 1; i >= 0; --i) {//采用I/O多路复用机制,当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行;// 否则进入continue,跳出本次循环。if ((pollFds[i].revents & POLLIN) == 0) {continue;}if (i == 0) {//即fds[0],代表的是sServerSocket,则意味着有客户端连接请求;// 则创建ZygoteConnection对象,并添加到fds。ZygoteConnection newPeer = acceptCommandPeer(abiList);peers.add(newPeer);fds.add(newPeer.getFileDesciptor()); //添加到fds.} else {//i>0,则代表通过socket接收来自对端的数据,并执行相应操作boolean done = peers.get(i).runOnce();if (done) {peers.remove(i);fds.remove(i); //处理完则从fds中移除该文件描述符}}}}
}

ZygoteInit.acceptCommandPeer

private static ZygoteConnection acceptCommandPeer(String abiList) {try {return new ZygoteConnection(sServerSocket.accept(), abiList);} catch (IOException ex) {...}
}

ZygoteConnection.runOnce

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {String args[];Arguments parsedArgs = null;FileDescriptor[] descriptors;try {//读取socket客户端发送过来的参数列表args = readArgumentList();descriptors = mSocket.getAncillaryFileDescriptors();} catch (IOException ex) {...return true;}...try {//将binder客户端传递过来的参数,解析成Arguments对象格式parsedArgs = new Arguments(args);...pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,parsedArgs.appDataDir);} catch (Exception e) {...}try {if (pid == 0) {//子进程执行IoUtils.closeQuietly(serverPipeFd);serverPipeFd = null;//进入子进程流程handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);return true;} else {//父进程执行IoUtils.closeQuietly(childPipeFd);childPipeFd = null;return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);}} finally {IoUtils.closeQuietly(childPipeFd);IoUtils.closeQuietly(serverPipeFd);}
}

接收客户端发送过来的connect()操作,Zygote作为服务端执行accept()操作。 再后面客户端调用write()写数据,Zygote进程调用read()读数据。

没有连接请求时会进入休眠状态,当有创建新进程的连接请求时,唤醒Zygote进程,创建Socket通道ZygoteConnection,然后执行ZygoteConnection的runOnce()方法。

Zygote总结:

  • 解析init.zygote.rc中的参数,创建AppRuntime并调用AppRuntime.start()方法
  • 调用AndroidRuntime的startVM()方法创建虚拟机,再调用startReg()注册JNI函数
  • 通过JNI方式调用ZygoteInit.main(),第一次进入Java世界
  • registerZygoteSocket()建立socket通道,zygote作为通信的服务端,用于响应客户端请求
  • preload()预加载通用类、drawable和color资源、openGL以及共享库以及WebView,用于提高app启动效率
  • 通过startSystemServer(),fork得力帮手system_server进程,也是Java Framework的运行载体(下面讲到system server再详细讲解)
  • 调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作

System Server进程

system server进程和zygote进程可以说是Android世界中的两大最重要的进程,离开其中之一基本上系统就玩完了;基本上在Java Framework中的大多数服务都是在system server进程中一个线程的方式存在的,如下:

  • EntropyService 提供伪随机数
  • PowerManagerService 电源管理服务
  • ActivityManagerService 最核心的服务之一,管理 四大组件
  • TelephonyRegistry 通过该服务注册电话模块的事件响应,比如重启、关闭、启动等
  • PackageManagerService 程序包管理服务
  • AccountManagerService 账户管理服务,是指联系人账户,而不是 Linux 系统的账户
  • ContentService ContentProvider 服务,提供跨进程数据交换
  • BatteryService 电池管理服务
  • LightsService 自然光强度感应传感器服务
  • VibratorService 震动器服务
  • AlarmManagerService 定时器管理服务,提供定时提醒服务
  • WindowManagerService Framework 最核心的服务之一,负责窗口管理
  • BluetoothService 蓝牙服务
  • DevicePolicyManagerService 提供一些系统级别的设置及属性
  • StatusBarManagerService 状态栏管理服务
  • ClipboardService 系统剪切板服务
  • InputMethodManagerService 输入法管理服务
  • NetStatService 网络状态服务
  • NetworkManagementService 网络管理服务
  • ConnectivityService 网络连接管理服务
  • ThrottleService 暂不清楚其作用
  • AccessibilityManagerService 辅助管理程序截获所有的用户输入,并根据这些输入给用户一些额外的反馈,起到辅助的效果
  • MountService 挂载服务,可通过该服务调用 Linux 层面的 mount 程序
  • NotificationManagerService 通知栏管理服务, Android 中的通知栏和状态栏在一起,只是界面上前者在左边,后者在右边
  • DeviceStorageMonitorService 磁盘空间状态检测服务
  • LocationManagerService 地理位置服务
  • SearchManagerService 搜索管理服务
  • DropBoxManagerService 通过该服务访问 Linux 层面的 Dropbox 程序
  • WallpaperManagerService 墙纸管理服务,墙纸不等同于桌面背景,在 View 系统内部,墙纸可以作为任何窗口的背景
  • AudioService 音频管理服务
  • BackupManagerService 系统备份服务
  • AppWidgetService Widget 服务
  • RecognitionManagerService 身份识别服务
  • DiskStatsService 磁盘统计服务

system server进程也是由zygote进程fork出来的,在上面的ZygoteInit.main方法中有如下代码

ZygoteInit.main

public static void main(String argv[]) {try {if (startSystemServer) {startSystemServer(abiList, socketName);//启动system_server}} catch (MethodAndArgsCaller caller) {caller.run(); //这一步很重要,接下来会讲到} catch (RuntimeException ex) {closeServerSocket();throw ex;}
}

ZygoteInit.startSystemServer

private static boolean startSystemServer(String abiList, String socketName)throws MethodAndArgsCaller, RuntimeException {...//参数准备String args[] = {"--setuid=1000","--setgid=1000","--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007","--capabilities=" + capabilities + "," + capabilities,"--nice-name=system_server","--runtime-args","com.android.server.SystemServer",};ZygoteConnection.Arguments parsedArgs = null;int pid;try {//用于解析参数,生成目标格式parsedArgs = new ZygoteConnection.Arguments(args);ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);// fork子进程,该进程是system_server进程pid = Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids,parsedArgs.debugFlags,null,parsedArgs.permittedCapabilities,parsedArgs.effectiveCapabilities);} catch (IllegalArgumentException ex) {throw new RuntimeException(ex);}//进入子进程system_serverif (pid == 0) {//第二个zygote进程if (hasSecondZygote(abiList)) {waitForSecondaryZygote(socketName);}// 完成system_server进程剩余的工作 handleSystemServerProcess(parsedArgs);}return true;
}

这个方法先准备参数,然后fork新进程,对于有两个zygote进程情况,需等待第2个zygote创建完成

Zygote.forkSystemServer

public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {VM_HOOKS.preFork();// 调用native方法fork system_server进程int pid = nativeForkSystemServer(uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);if (pid == 0) {Trace.setTracingEnabled(true);}VM_HOOKS.postForkCommon();return pid;
}

nativeForkSystemServer()方法在AndroidRuntime.cpp中注册的,调用com_android_internal_os_Zygote.cpp中的register_com_android_internal_os_Zygote()方法建立native方法的映射关系,所以接下来进入如下方法

com_android_internal_os_Zygote.nativeForkSystemServer

static jint com_android_internal_os_Zygote_nativeForkSystemServer(JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,jlong effectiveCapabilities) {//fork子进程pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,debug_flags, rlimits,permittedCapabilities, effectiveCapabilities,MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,NULL, NULL);if (pid > 0) {// zygote进程,检测system_server进程是否创建gSystemServerPid = pid;int status;if (waitpid(pid, &status, WNOHANG) == pid) {//当system_server进程死亡后,重启zygote进程RuntimeAbort(env);}}return pid;
}

当system_server进程创建失败时,将会重启zygote进程。这里需要注意,对于Android 5.0以上系统,有两个zygote进程,分别是zygote、zygote64两个进程,system_server的父进程,一般来说64位系统其父进程是zygote64进程

  • 当kill system_server进程后,只重启zygote64和system_server,不重启zygote;
  • 当kill zygote64进程后,只重启zygote64和system_server,也不重启zygote;
  • 当kill zygote进程,则重启zygote、zygote64以及system_server。

com_android_internal_os_Zygote.ForkAndSpecializeCommon

static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,jint debug_flags, jobjectArray javaRlimits,jlong permittedCapabilities, jlong effectiveCapabilities,jint mount_external,jstring java_se_info, jstring java_se_name,bool is_system_server, jintArray fdsToClose,jstring instructionSet, jstring dataDir) {SetSigChldHandler(); //设置子进程的signal信号处理函数pid_t pid = fork(); //fork子进程if (pid == 0) {//进入子进程DetachDescriptors(env, fdsToClose); //关闭并清除文件描述符if (!is_system_server) {//对于非system_server子进程,则创建进程组int rc = createProcessGroup(uid, getpid());}SetGids(env, javaGids); //设置设置groupSetRLimits(env, javaRlimits); //设置资源limitint rc = setresgid(gid, gid, gid);rc = setresuid(uid, uid, uid);SetCapabilities(env, permittedCapabilities, effectiveCapabilities);SetSchedulerPolicy(env); //设置调度策略//selinux上下文rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);if (se_info_c_str == NULL && is_system_server) {se_name_c_str = "system_server";}if (se_info_c_str != NULL) {SetThreadName(se_name_c_str); //设置线程名为system_server,方便调试}UnsetSigChldHandler(); //设置子进程的signal信号处理函数为默认函数//等价于调用zygote.callPostForkChildHooks()env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,is_system_server ? NULL : instructionSet);...} else if (pid > 0) {//进入父进程,即zygote进程}return pid;
}int fork() {__bionic_atfork_run_prepare(); pthread_internal_t* self = __get_thread();//fork期间,获取父进程pid,并使其缓存值无效pid_t parent_pid = self->invalidate_cached_pid();//系统调用int result = syscall(__NR_clone, FORK_FLAGS, NULL, NULL, NULL, &(self->tid));if (result == 0) {self->set_cached_pid(gettid());__bionic_atfork_run_child(); //fork完成执行子进程回调方法} else {self->set_cached_pid(parent_pid);__bionic_atfork_run_parent(); //fork完成执行父进程回调方法}return result;
}

fork

fork()采用copy on write技术,这是linux创建进程的标准方法,调用一次,返回两次,返回值有3种类型

  • 父进程中,fork返回新创建的子进程的pid;
  • 子进程中,fork返回0;
  • 当出现错误时,fork返回负数。(当进程数超过上限或者系统内存不足时会出错)

fork()的主要工作是寻找空闲的进程号pid,然后从父进程拷贝进程信息,例如数据段和代码段,fork()后子进程要执行的代码等。 Zygote进程是所有Android进程的母体,包括system_server和各个App进程。zygote利用fork()方法生成新进程,对于新进程A复用Zygote进程本身的资源,再加上新进程A相关的资源,构成新的应用进程A

fork之后,操作系统会复制一个与父进程完全相同的子进程,虽说是父子关系,但是在操作系统看来,他们更像兄弟关系,这2个进程共享代码空间,但是数据空间是互相独立的,子进程数据空间中的内容是父进程的完整拷贝,指令指针也完全相同,子进程拥有父进程当前运行到的位置(两进程的程序计数器pc值相同,也就是说,子进程是从fork返回处开始执行的),但有一点不同,如果fork成功,子进程中fork的返回值是0,父进程中fork的返回值是子进程的进程号,如果fork不成功,父进程会返回错误。
可以这样想象,2个进程一直同时运行,而且步调一致,在fork之后,他们就开始分别作不同的工作,正如fork原意【分支】一样

到此system_server进程已完成了创建的所有工作,接下来开始了system_server进程的真正工作。在前面startSystemServer()方法中,zygote进程执行完forkSystemServer()后,新创建出来的system_server进程便进入handleSystemServerProcess()方法

ZygoteInit.handleSystemServerProcess

private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs)throws ZygoteInit.MethodAndArgsCaller {closeServerSocket(); //关闭父进程zygote复制而来的SocketOs.umask(S_IRWXG | S_IRWXO);if (parsedArgs.niceName != null) {Process.setArgV0(parsedArgs.niceName); //设置当前进程名为"system_server"}final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");if (systemServerClasspath != null) {//执行dex优化操作performSystemServerDexOpt(systemServerClasspath);}if (parsedArgs.invokeWith != null) {String[] args = parsedArgs.remainingArgs;if (systemServerClasspath != null) {String[] amendedArgs = new String[args.length + 2];amendedArgs[0] = "-cp";amendedArgs[1] = systemServerClasspath;System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length);}//启动应用进程WrapperInit.execApplication(parsedArgs.invokeWith,parsedArgs.niceName, parsedArgs.targetSdkVersion,VMRuntime.getCurrentInstructionSet(), null, args);} else {ClassLoader cl = null;if (systemServerClasspath != null) {创建类加载器,并赋予当前线程cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());Thread.currentThread().setContextClassLoader(cl);}//system_server故进入此分支RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);}
}

RuntimeInit.zygoteInit

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)throws ZygoteInit.MethodAndArgsCaller {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");redirectLogStreams(); //重定向log输出commonInit(); // 通用的一些初始化nativeZygoteInit(); // zygote初始化 applicationInit(targetSdkVersion, argv, classLoader); // 应用初始化
}private static final void commonInit() {// 设置默认的未捕捉异常处理方法Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());// 设置市区,中国时区为"Asia/Shanghai"TimezoneGetter.setInstance(new TimezoneGetter() {@Overridepublic String getId() {return SystemProperties.get("persist.sys.timezone");}});TimeZone.setDefault(null);//重置log配置LogManager.getLogManager().reset();new AndroidConfig();// 设置默认的HTTP User-agent格式( "Dalvik/1.1.0 (Linux; U; Android 6.0.1;LenovoX3c70 Build/LMY47V)"),用于 HttpURLConnectionString userAgent = getDefaultUserAgent();System.setProperty("http.agent", userAgent);// 设置socket的tag,用于网络流量统计NetworkManagementSocketTagger.install();
}private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)throws ZygoteInit.MethodAndArgsCaller {//true代表应用程序退出时不调用AppRuntime.onExit(),否则会在退出前调用nativeSetExitWithoutCleanup(true);//设置虚拟机的内存利用率参数值为0.75VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);final Arguments args;try {args = new Arguments(argv); //解析参数} catch (IllegalArgumentException ex) {return;}Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);//调用startClass的static方法 main() 此处args.startClass为”com.android.server.SystemServer”invokeStaticMain(args.startClass, args.startArgs, classLoader);
}private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)throws ZygoteInit.MethodAndArgsCaller {Class<?> cl = Class.forName(className, true, classLoader);...Method m;try {m = cl.getMethod("main", new Class[] { String[].class });} catch (NoSuchMethodException ex) {...} catch (SecurityException ex) {...}//通过抛出异常,回到ZygoteInit.main()。这样做好处是能清空栈帧,提高栈帧利用率throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

重点看最后一个方法,通过反射获取SystemServer类的main方法参数,然后抛出MethodAndArgsCaller异常;但是抛出异常后怎么弄呢,我们知道一个方法抛异常,会一直走到调用方法,直到一个方法捕获了异常,这里就是开头讲的,在ZygoteInit.main方法捕获了异常然后去执行

ZygoteInit.main

public static void main(String argv[]) {try {if (startSystemServer) {startSystemServer(abiList, socketName);//启动system_server}} catch (MethodAndArgsCaller caller) {caller.run(); //这一步很重要,接下来会讲到} catch (RuntimeException ex) {closeServerSocket();throw ex;}
}

但是为啥没有直接在startSystemServer()或者上面的方法中直接调用SystemServer类的main方法,而是通过抛异常的方式处理呢?

我们知道,当一个函数抛出异常后,这个异常会依次传递给调用它的函数,直到这个异常被捕获,如果这个异常一直没有被处理,最终就会引起程序的崩溃。

程序都是由一个个函数组成的(除了汇编程序),c/c++/java/…等高级语言编写的应用程序,在执行的时候,他们都拥有自己的栈空间(是一种先进后出的内存区域),用于存放函数的返回地址和函数的临时数据,每调用一个函数时,就会把函数的返回地址和相关数据压入栈中,当一个函数执行完后,就会从栈中弹出,cpu会根据函数的返回地址,执行上一个调用函数的下一条指令。

所以,在抛出异常后,如果异常没有在当前的函数中捕获,那么当前的函数执行就会异常的退出,从应用程序的栈弹出,并将这个异常传递给上一个函数,直到异常被捕获处理,否则,就会引起程序的崩溃。

因此,这里通过抛异常的方式启动主要是清理应用程序栈中ZygoteInit.main以上的函数栈帧,以实现当相应的main函数退出时,能直接退出整个应用程序

ZygoteInit.MethodAndArgsCaller.run

public static class MethodAndArgsCaller extends Exceptionimplements Runnable {/** 调用的方法 在上面的方法可知是main方法 */private final Method mMethod;/** 参数列表 */private final String[] mArgs;public MethodAndArgsCaller(Method method, String[] args) {mMethod = method;mArgs = args;}public void run() {try {mMethod.invoke(null, new Object[] { mArgs });} catch (IllegalAccessException ex) {throw new RuntimeException(ex);} catch (InvocationTargetException ex) {Throwable cause = ex.getCause();if (cause instanceof RuntimeException) {throw (RuntimeException) cause;} else if (cause instanceof Error) {throw (Error) cause;}throw new RuntimeException(ex);}}}

可以看到这里根据传递过来的参数,可知此处通过反射机制调用的是SystemServer.main()方法;到此,总算是进入到了SystemServer类的main()方法

SystemServer.main

public static void main(String[] args) {new SystemServer().run();
}private void run() {try {//如果系统时间比1970年早,那就设置为1970if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);}//变更虚拟机的库文件,对于Android 6.0默认采用的是libart.soSystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());//清除vm内存增长上限,由于启动过程需要较多的虚拟机内存空间VMRuntime.getRuntime().clearGrowthLimit();//设置内存的可能有效使用率为0.8VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);// 针对部分设备依赖于运行时就产生指纹信息,因此需要在开机完成前已经定义Build.ensureFingerprintProperty();//访问环境变量前,需要明确地指定用户Environment.setUserRequired(true);// Within the system server, any incoming Bundles should be defused// to avoid throwing BadParcelableException.BaseBundle.setShouldDefuse(true);//确保当前系统进程的binder调用,总是运行在前台优先级(foreground priority)BinderInternal.disableBackgroundScheduling(true);// 增加system_server中的binder线程数BinderInternal.setMaxThreads(sMaxBinderThreads);// 创建主线程looper 在当前线程运行android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_FOREGROUND);android.os.Process.setCanSelfBackground(false);Looper.prepareMainLooper();//初始化android_servers库System.loadLibrary("android_servers");//检测上次关机过程是否失败performPendingShutdown();//初始化系统上下文//初始化系统上下文对象mSystemContext,并设置默认的主题,mSystemContext实际上是一个ContextImpl对象。//调用ActivityThread.systemMain()的时候,会调用ActivityThread.attach(true),而在attach()里面,则创建了Application对象,并调用了Application.onCreate()。createSystemContext();//创建系统服务管理mSystemServiceManager = new SystemServiceManager(mSystemContext);LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);} finally {Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);}//启动各种系统服务try {//引导服务startBootstrapServices();//核心服务startCoreServices();//其它服务startOtherServices();} catch (Throwable ex) {throw ex;} finally {Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);}//开启消息循环Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}

system server进程总结:

  • zygote进程通过Zygote.forkSystemServer —> fork.fork()创建system server进程
  • 调用ZygoteInit.handleSystemServerProcess方法设置当前进程名为"system_server",执行dex优化操作,一些属性的初始化,设置binder线程
  • 通过抛出MethodAndArgsCaller异常,回到ZygoteInit.main(),在try catch中执行MethodAndArgsCaller.run;在这里通过反射执行SystemServer.main()方法
  • 在SystemServer.run方法中做一些设置,比如初始化系统上下文 ,创建SystemServiceManager,启动引导服务,启动核心服务,启动其他服务
  • 最后调用Looper.loop(),不断的从消息队列取出消息处理

从源码解析-Android系统启动流程概述 init进程zygote进程SystemServer进程启动流程相关推荐

  1. 从源码解析-Android中Zygote进程是如何fork一个APP进程的

    zygote进程fork子进程 前言 强烈推荐 进程创建流程 APP启动第三方应用 startActivity startService sendBroadcast ContentResolver.q ...

  2. 从源码解析-Android中View的绘制流程及performTraversals方法

    谈谈Activity的setContentView是怎么加载XML视图的 谈谈Activity的View怎么与View绘制工具ViewRootImpl关联的 在前面两篇文章中分析了View是如何跟绘制 ...

  3. (连载)Android系统源码分析--Android系统启动流程之Linux内核

    > **这是一个连载的博文系列,我将持续为大家提供尽可能透彻的Android源码分析 [github连载地址](https://github.com/foxleezh/AOSP/issues/3 ...

  4. android 日历源码解析,Android 4.0日历(calendar)源码分析之概览

    Calendar 从4.0开始,谷歌android系统有了脱碳换骨的改变,相应的日历应用的代码架构也跟2.*完全不同.代码更规范,当然也更复杂,且涉及到了android开发的方方面面. 如果你熟悉了i ...

  5. SpringSession的源码解析(从Cookie中读取Sessionid,根据sessionid查询信息全流程分析)

    前言 上一篇我们介绍了SpringSession中Session的保存过程,今天我们接着来看看Session的读取过程.相对保存过程,读取过程相对比较简单. 本文想从源码的角度,详细介绍一下Sessi ...

  6. okhttp的应用详解与源码解析--android网络请求框架发展史

    乘5G之势,借物联网之风,Android未来亦可期,Android优势在于开放,手机.平板.车载设备.智能家居等都是Android的舞台,Google不倒,Android不灭,本专栏的同步视频教程已经 ...

  7. [Dubbo3.0.8源码解析系列]-12-全局视野来看Dubbo3.0.8的服务启动生命周期

    目录 12 全局视野来看Dubbo3的服务启动生命周期 12.1 启动方法简介 12.2 启动器启动方法的调用逻辑start() 12.3 应用程序发布器DefaultApplicationDeplo ...

  8. Android多线程之IntentService源码解析

    想要了解 IntentService 的工作原理需要先对 Android 系统中以 Handler.Looper.MessageQueue 组成的异步消息处理机制以及 HandlerThread 有所 ...

  9. Android 源码解析之Adapter和AdapterView与适配器模式

    概述 在Android中大量存在着适配器模式,其中的设计思路就是Adapter(提供数据)设在到AdapterView(展示数据集合的视图),其中Adapter体系结构如下 而AdapterView有 ...

最新文章

  1. OVS端口镜像(十四)
  2. 【Demo 0116】堆的使用
  3. 如何基于Restful ABAP Programming模型开发并部署一个支持增删改查的Fiori应用
  4. 【Pytorch】tensorboardX==》数据可视化
  5. 太阳能工程联箱知识_超导热管集热器为何在太阳能热水工程中咨询量那么高
  6. 2016年工作中遇到的问题41-50:Dubbo注册中心奇葩问题,wifi热点坑了
  7. bootdo框架首页解析
  8. Android消息处理机制之二:消息中obtain源代码剖析
  9. Scary Movie 4
  10. 《阿特拉斯耸耸肩》节选:互害与甩锅的反敏捷组织
  11. 企业信息与网络通信安全 团队成员简历-叶俊
  12. 4. 多重建模-不同视角
  13. JAVA入门学习资料
  14. QQ邮箱测试域用户密码过期邮件提示
  15. 电脑-U盘插入电脑(笔记本电脑)没反应
  16. 云小蜜人工智能训练师
  17. 天津达内:大数据自学可以学会吗
  18. dive into openstack ovn (by quqi99)
  19. 南加州大学计算机科学案例,南加州大学计算机科学硕士录取
  20. ThingsBoard 开发环境搭建

热门文章

  1. 使用VB合并word文档内容
  2. 【贪玩巴斯】数字信号处理Digital Signal Processing(DSP)——第四节「离散时间系统分类、线性和非线性、因果和非因果、稳定和不稳定以及互联」2021-10-20
  3. 印象笔记android,Android
  4. 【北邮国院大三上】电子商务法(e-commerce law)知识点整理——Banking Lawe-Payment
  5. ARM Cortex-M处理器详解
  6. Elasticsearch 和 MongoDB 对比
  7. 64位ubantu 16.04.2系统安装谷歌浏览器过程
  8. 转载自科技猿人:联想5G投票这事,我们就来彻底讲清楚
  9. 论文阅读(7)水母游动的流体动力学 - 海洋科学年刊(2021)
  10. 锐捷认证客户端——多网卡限制破解