简介
我们从init进程来分析Android系统的启动流程。
init进程代码分析:
init进程是被kernel中的kernel_init函数通过execve系统调用进行的初始化。
init进程的代码位置:
system/core/init/init.c
init的main函数:
(1) 创建并挂载文件系统相关目录,并且赋予root权限(0755); 例如,代码中的:
mkdir("/dev", 0755);
mkdir("/proc", 0755);
mkdir("/sys", 0755);
也就是说,这些目录是在Android系统运行期间由init进程创建的,而不是在编译期间创建。
(2)创建标准输入输出设备节点文件,即
open_devnull_stdio();
这个函数会在/dev目录下创建__null__设备节点文件,然后,标准输入输出,标准错误输出会重定向到这个设备节点中。
(3) 简析init.rc,%hardware%.rc文件。init.rc文件是init进程启动后执行的脚本文件。在rc文件中,启动了很多守护进程,例如,服务管理器servicemanager,rild,installd......等等。init.rc它主要包含五种类型语句:
Action、Commands、Services、Options和Import。
解析init.rc的语句是:
init_parse_config_file("/init.rc");
(4) 初始化设备id;
(5)初始化属性(property)服务;
property_init()
Android系统中的所有进程共享系统属性值,这些属性值被保存在共享内存中,通过调用 property_init()函数,来初始化属性值;
(6) 启动property服务;
(7) 循环处理device/property,进行事件处理。包括重启(restart_processes()函数)或终止子进程,并发送SIGCHLD信号等。
整个流程图如下:
int main(int argc, char **argv)
{
int fd_count = 0;
struct pollfd ufds[4];
char *tmpdev;
char* debuggable;
char tmp[32];
int property_set_fd_init = 0;
int signal_fd_init = 0;
int keychord_fd_init = 0;
bool is_charger = false;
if (!strcmp(basename(argv[0]), "ueventd"))
return ueventd_main(argc, argv);
/* clear the umask */
umask(0);
/* 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.
*/
mkdir("/dev", 0755);
mkdir("/proc", 0755);
mkdir("/sys", 0755);
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
mount("proc", "/proc", "proc", 0, NULL);
mount("sysfs", "/sys", "sysfs", 0, NULL);
/* indicate that booting is in progress to background fw loaders, etc */
close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));
/* We must have some place other than / to create the
* device nodes for kmsg and null, otherwise we won't
* be able to remount / read-only later on.
* Now that tmpfs is mounted on /dev, we can actually
* talk to the outside world.
*/
open_devnull_stdio();
klog_init();
property_init();
get_hardware_name(hardware, &revision);
process_kernel_cmdline();
......
for(;;) {
int nr, i, timeout = -1;
execute_one_command();
restart_processes();
if (!property_set_fd_init && get_property_set_fd() > 0) {
ufds[fd_count].fd = get_property_set_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
property_set_fd_init = 1;
}
if (!signal_fd_init && get_signal_fd() > 0) {
ufds[fd_count].fd = get_signal_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
signal_fd_init = 1;
}
......
return 0;
}
在文件系统创建完成后,就进入了loop循环,在循环中,进行了一系列的fd(文件描述符)的初始化和设置。这些文件fd是struct pollfd结构体类型的,主要有{ device _fd , property_set_fd , signal_recv_fd , keychord_fd }4种。
device _fd:
主要设置包括sdcard在内的socket。
property_set_fd:
property的cs架构:
#define PROP_SERVICE_NAME "property_service"
signal_recv_fd and signal_fd:
//signal_recv_fd and signal_fd:
/* create a signalling mechanism for the sigchld handler */
if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
signal_fd = s[0];
signal_recv_fd = s[1];
fcntl(s[0], F_SETFD, FD_CLOEXEC);
fcntl(s[0], F_SETFL, O_NONBLOCK);
fcntl(s[1], F_SETFD, FD_CLOEXEC);
fcntl(s[1], F_SETFL, O_NONBLOCK);
}
……
//read signal
read(signal_recv_fd, tmp, sizeof(tmp);
while (!wait_for_one_process(0)); //阻塞
这些文件系统,socket等的初始化都ok后,其它进程会和这些资源进行进程间通信。
USER PID PPID VSIZE RSS WCHAN PC NAME
root 1 0 548 196 c00b8c14 0000d5cc S /init
root 2 0 0 0 c006bf70 00000000 S kthreadd
......
root 724 2 0 0 c0216908 00000000 S mmcqd
root 726 1 772 180 c019dbc4 afe0c1dc S /system/bin/sh
system 727 1 840 188 c022d8a0 afe0c47c S /system/bin/servicemanager
root 729 1 1920 336 ffffffff afe0c1dc S /system/bin/mountd
root 730 1 704 176 c0257854 afe0ce0c S /system/bin/debuggerd
root 731 1 4132 628 c027e2f8 afe0ce0c S /opl/bin/tcmd
root 732 1 852 248 c00b92b0 afe0c5a4 S /opl/bin/adapter
radio 733 1 12796 648 ffffffff beaab18c S /system/bin/rild
root 734 1 72000 14172 c00b92b0 afe0c5a4 S zygote
root 735 1 33848 4512 ffffffff afe0c47c S /system/bin/mediaserver
root 736 1 1080 216 c00b8c14 bedc021c S /system/bin/dbus-daemon
root 737 1 832 208 c02b6e80 afe0c1dc S /system/bin/installd
root 740 1 856 260 c00b92b0 afe0c5a4 S /opl/bin/bpd
root 741 1 828 172 c00b8c14 afe0d27c S /opl/bin/battmond
root 768 1 720 272 c02265ec afe0c1dc S /system/bin/logcat
root 769 1 716 264 c02265ec afe0c1dc S /system/bin/logcat
root 816 2 0 0 c0068eec 00000000 S battery.0
system 825 734 574128 28360 ffffffff afe0c47c S system_server
radio 877 734 158260 20040 ffffffff afe0d404 S com.android.phone
app_5 879 734 100888 13616 ffffffff afe0d404 S android.process.acore
system 882 734 144664 24296 ffffffff afe0d404 S android.process.omsservice
app_45 884 734 92304 10932 ffffffff afe0d404 S com.motorola.motohome
app_22 890 734 117068 30228 ffffffff afe0d404 S oms.home
app_3 918 734 98760 12652 ffffffff afe0d404 S oms.widgetmanager
app_5 928 734 100888 13336 ffffffff afe0d404 S com.android.inputmethod.borqs
app_24 930 734 105176 19168 ffffffff afe0d404 S com.db4o.servo.search
app_18 960 734 104180 15208 ffffffff afe0d404 S com.android.mms
app_8 979 734 118860 14044 ffffffff afe0d404 S android.process.media
app_9 991 734 91980 12264 ffffffff afe0d404 S com.android.alarmclock
app_15 998 734 103144 12908 ffffffff afe0d404 S oms.dcd
system 1018 734 94732 13792 ffffffff afe0d404 S oms.dm
app_14 1025 734 95636 13036 ffffffff afe0d404 S com.android.calendar
app_42 1041 734 93292 11316 ffffffff afe0d404 S com.motorola.smsautoreg
app_40 1090 734 97152 15192 ffffffff afe0d404 S com.motorola.mtc
app_38 1102 734 93832 12868 ffffffff afe0d404 S com.streamezzo.browser.android
app_26 1115 734 96596 15084 ffffffff afe0d404 S oms.mediacenter
app_37 1126 734 98208 15212 ffffffff afe0d404 S com.hyfsoft.docviewer
app_20 1146 734 99260 15320 ffffffff afe0d404 S com.android.music
app_47 1157 734 100204 15964 ffffffff afe0d404 S com.motorola.camera
app_11 1183 734 122672 23576 ffffffff afe0d404 S com.android.browser
app_6 1199 734 117032 20388 ffffffff afe0d404 S oms.mobilemusic
system 1244 734 99292 15940 ffffffff afe0d404 S com.android.settings
app_23 1311 734 96932 16004 ffffffff afe0d404 S oms.bru
root 1334 2 0 0 c0216908 00000000 S mmcqd
app_8 1351 734 100308 15876 ffffffff afe0d404 S com.android.camera
app_1 1424 734 111904 17024 ffffffff afe0d404 S oms.messaging
app_4 1436 734 101172 15504 ffffffff afe0d404 S oms.mail
app_2 1484 734 100716 18128 ffffffff afe0d404 S com.ms
app_16 1663 734 101024 16748 ffffffff afe0d404 S oms.android.filemanager
root 1684 1 3364 176 ffffffff 0000e8f4 S /sbin/adbd
root 1692 1684 776 348 c0059cd4 afe0d0ac S /system/bin/sh
root 1724 1692 920 356 00000000 afe0c1dc R ps
init.rc:
init.rc部分代码截取:
import /init.${ro.hardware}.rc
import /init.usb.rc
import /init.trace.rc
on early-init
# Set init and its forked children's oom_adj.
write /proc/1/oom_adj -16
start ueventd
# create mountpoints
mkdir /mnt 0775 root system
on init
sysclktz 0
loglevel 3
# setup the global environment
export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
export LD_LIBRARY_PATH /vendor/lib:/system/lib
export ANDROID_BOOTLOGO 1
export ANDROID_ROOT /system
export ANDROID_ASSETS /system/app
export ANDROID_DATA /data
......
mkdir /system
mkdir /data 0771 system system
mkdir /cache 0770 system cache
mkdir /config 0500 root root
......
## Daemon processes to be run by init.
##
service ueventd /sbin/ueventd
class core
critical
service console /system/bin/sh
class core
console
disabled
user shell
group log
on property:ro.debuggable=1
start console
# adbd is controlled via property triggers in init.<platform>.usb.rc
service adbd /sbin/adbd
class core
disabled
# adbd on at boot in emulator
on property:ro.kernel.qemu=1
start adbd
service servicemanager /system/bin/servicemanager
class core
user system
group system
......
分析:
1. 在init.rc中,创建了系统需要的系统文件夹,例如/system, /data, 并赋予相应的权限。
2. 设置了全局环境变量,例如
export ANDROID_ROOT /system export ANDROID_ASSETS /system/app export ANDROID_DATA /data
3. 用service指令启动了很多守护进程,例如,ueventd,sh,adbd,servicemanager......等。从底层架构的角度来看,正是这些守护进程,对上提供了丰富的功能,对下层,大部分守护进程都是通过系统调用去与kenel进行交互,从而实现在整个系统中,能够进行进程间的通信。
了解底层的运作机制,对于理解上层代码,乃至整个系统,都非常有益。