Android init进程作为用户空间第一个进程,做了很多系统初始化工作,其核心分为两块:一是属性,二是init.rc。此外,在具体的项目过程中,常和init进程打交道,里面有不少技术细节值得我们研究清楚。
bionic/libc/include/sys/System_properties.h
#define PROP_NAME_MAX 32
#define PROP_VALUE_MAX 92
key最大为32个字节,末位\0还要占一个字节,所以真正用于key的最大字串为31。即key = persist.system.donotallow.secsim(32Bytes) 时,会报错。
同理value最大为91Bytes。
if(pi != 0) {
/* ro.* properties may NEVER be modified once set */
if(!strncmp(name, "ro.", 3)) return -1;
persist前缀属性在初始加载属性时须注意,default属性未加载完成时,不能将其写入文件中,以免覆盖文件中的属性值。
对于persist前缀,在设置属性的同时,还会将其写到/data/property/persist.xxx文件中,在系统重启时,将该属性值恢复到上机关机时的状态。那么什么时候加载的这些persist属性?
on property:vold.decrypt=trigger_load_persist_props
load_persist_props
void load_persist_props(void)
{
load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
}
加载时机要控制好,一是在默认属性都加载完成后;二是等data分区挂载好之后,毕竟persist属性存储在data分区中。
tcp的buffer size和接收窗口大小在init中设置,在tcp调优过程中,可以在init.rc中进行修改。
系统中的可执行路径(PATH)在init.environ.rc中设置
on init
export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
# Used to disable USB when switching states
on property:sys.usb.config=none
stop adbd
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/bDeviceClass 0
setprop sys.usb.state ${sys.usb.config}
# adb only USB configuration
# This should only be used during device bringup
# and as a fallback if the USB manager fails to set a standard configuration
on property:sys.usb.config=adb
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/idVendor 18d1
write /sys/class/android_usb/android0/idProduct D002
write /sys/class/android_usb/android0/functions ${sys.usb.config}
write /sys/class/android_usb/android0/enable 1
start adbd
setprop sys.usb.state ${sys.usb.config}
on early-init
start ueventd
ueventd.rc
/dev/null 0666 root root
/dev/zero 0666 root root
/dev/full 0666 root root
/dev/ptmx 0666 root root
/dev/tty 0666 root root
/dev/random 0666 root root
/dev/urandom 0666 root root
# Make HW RNG readable by group system to let EntropyMixer read it.
/dev/hw_random 0440 root system
/dev/ashmem 0666 root root
/dev/binder 0666 root root
service vold /system/bin/vold
class core
socket vold stream 0660 root mount
ioprio be 2
service bootanim /system/bin/bootanimation
class main
user graphics
group graphics
disabled
oneshot
service media /system/bin/mediaserver
class main
user media
group audio camera inet net_bt net_bt_admin net_bw_acct mediadrm
ioprio rt 4
以media服务为例,init进程调用service_start:
pid = fork();
if (pid == 0) { // son
if (properties_inited()) {
get_property_workspace(&fd, &sz);
sprintf(tmp, "%d,%d", dup(fd), sz);
add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
}
for (ei = svc->envvars; ei; ei = ei->next)
add_environment(ei->name, ei->value);
for (si = svc->sockets; si; si = si->next) {
int socket_type = (
!strcmp(si->type, "stream") ? SOCK_STREAM :
(!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
int s = create_socket(si->name, socket_type,
si->perm, si->uid, si->gid, si->socketcon ?: scon);
if (s >= 0) {
publish_socket(si->name, s);
}
}
setsid();
setpgid(0, getpid());
execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
}
_exit(127);
}
init进程启动服务主要包括:
1)把属性内存区域的文件描述符加入到环境变量ANDROID_PROPERTY_WORKSPACE中,因此启动的服务可以与属性进行通信。
2)创建服务配置的unix socket套接字。
3)设置会话id和进程组id
4)执行指定的服务程序
这样一个deamon就正常启动了。