它的位置在system\core\init\init.c,下面是入口程序:
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;
if (!strcmp(basename(argv[0]), "ueventd"))
return ueventd_main(argc, argv);
/* clear the umask */
umask(0);
/*创建文件夹,并挂载这些设备。这些文件系统放在uramdisk里,通过解析rc文件使之生效
*/
mkdir("/dev", 0755);
mkdir("/proc", 0755);
mkdir("/sys", 0755);
mount("tmpfs", "/dev", "tmpfs", 0, "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);
/* 重定向标准输入/输出到/dev/_null_
*/
open_devnull_stdio();
//初始化日志信息设备
log_init();
INFO("reading config file\n");
//解析init.rc配置文件
init_parse_config_file("/init.rc");
//导入内核命令行
import_kernel_cmdline(0);
//通过读取/proc/cpuinfo得到机器名
get_hardware_name(hardware, &revision);
snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
//解析与机器相关的配置文件
init_parse_config_file(tmp);
//得到一系列的action,注意这是early-init阶段的action,加入action队列尾部
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(property_init_action, "property_init");
//加入keychord(与键盘设置有关)初始化动作
queue_builtin_action(keychord_init_action, "keychord_init");
//加入控制台初始化动作
queue_builtin_action(console_init_action, "console_init");
//加入设置属性初始化动作
queue_builtin_action(set_init_properties_action, "set_init_properties");
//加入init阶段的action
action_for_each_trigger("init", action_add_queue_tail);
//加入early-fs(文件系统相关)阶段的action
action_for_each_trigger("early-fs", action_add_queue_tail);
//加入fs阶段的action
action_for_each_trigger("fs", action_add_queue_tail);
//加入post-fs阶段的action
action_for_each_trigger("post-fs", action_add_queue_tail);
//加入属性服务初始化动作
queue_builtin_action(property_service_init_action, "property_service_init");
//加入信号初始化动作
queue_builtin_action(signal_init_action, "signal_init");
//加入检测启动的动作
queue_builtin_action(check_startup_action, "check_startup");
//加入early-boot阶段的action
action_for_each_trigger("early-boot", action_add_queue_tail);
//加入boot阶段的action
action_for_each_trigger("boot", action_add_queue_tail);
/* 加入当前状态的属性action */
queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");
#if BOOTCHART
//与boot char相关的操作,它是一个工具,对系统性能进行分析
queue_builtin_action(bootchart_init_action, "bootchart_init");
#endif
for(;;) {
//init无限循环
int nr, i, timeout = -1;
//执行动作
execute_one_command();
//重启死去的进程
restart_processes();
//init关注3个方面的事件
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;//置1
}
if (!signal_fd_init && get_signal_fd() > 0) {
/*关于get_signal_fd(signal_recv_fd) ,可以去sigchld_handler.c跟踪它的来由,它由socketpair 创建,事件来自另外的socket(signal_fd)*/
ufds[fd_count].fd = get_signal_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
signal_fd_init = 1;
}
if (!keychord_fd_init && get_keychord_fd() > 0) {
/* keychord初始化成功,也会监听来自keychord(与键盘设置相关)设备的事件 */
ufds[fd_count].fd = get_keychord_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
keychord_fd_init = 1;
}
if (process_needs_restart) {
//死去的进程启动,设置等待时间
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
}
if (!action_queue_empty() || cur_action)
timeout = 0;
#if BOOTCHART
if (bootchart_count > 0) {
if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)
timeout = BOOTCHART_POLLING_MS;
if (bootchart_step() < 0 || --bootchart_count == 0) {
bootchart_finish();
bootchart_count = 0;
}
}
#endif
//poll等待事件的发生
nr = poll(ufds, fd_count, timeout);
if (nr <= 0)
continue;
for (i = 0; i < fd_count; i++) {
if (ufds[i].revents == POLLIN) {
if (ufds[i].fd == get_property_set_fd())
handle_property_set_fd();//处理属性服务的事件
else if (ufds[i].fd == get_keychord_fd())
handle_keychord();//处理keychord事件
else if (ufds[i].fd == get_signal_fd())
handle_signal();//处理socket事件
}
}
}
return 0;
}
由于keychord不常用,下面来讨论signal和property。
关于signal
在sigchld_handler.c中:
int get_signal_fd()
{
return signal_recv_fd;
}
接下来,
void signal_init(void)
{
int s[2];
struct sigaction act;
act.sa_handler = sigchld_handler;
act.sa_flags = SA_NOCLDSTOP;
act.sa_mask = 0;
act.sa_restorer = NULL;
sigaction(SIGCHLD, &act, 0);
/* create a signalling mechanism for the sigchld handler */
//与socketpair有关
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);
}
handle_signal();
}
在socket.c中:
//供系统调用
SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,
int __user *, usockvec)
{
struct socket *sock1, *sock2;
int fd1, fd2, err;
struct file *newfile1, *newfile2;
int flags;
….
err = sock1->ops->socketpair(sock1, sock2);//这里是一个回调函数
if (err < 0)
goto out_release_both;
fd1 = sock_alloc_file(sock1, &newfile1, flags);
if (unlikely(fd1 < 0)) {
err = fd1;
goto out_release_both;
}
fd2 = sock_alloc_file(sock2, &newfile2, flags);
if (unlikely(fd2 < 0)) {
err = fd2;
fput(newfile1);
put_unused_fd(fd1);
sock_release(sock2);
goto out;
}
…
out_release_both:
sock_release(sock2);
out_release_1:
sock_release(sock1);
out:
return err;
}
继续跟踪:
在socketpair.S中有如下定义:
.text
.type socketpair, #function
.globl socketpair
.align 4
.fnstart
socketpair:
.save {r4, r7}
stmfd sp!, {r4, r7}
ldr r7, =__NR_socketpair
swi #0
ldmfd sp!, {r4, r7}
movs r0, r0
bxpl lr
b __set_syscall_errno
.fnend
signal及socketpair分析到此,来看看property吧,在init.rc里我们经常会设置一些属性,在系统层根据这些属性值来执行相关操作。比如双显(LVDS屏和HDMI),如果设置了,假设属性值为1,那么系统层获取该属性值为1,就执行双显功能。否则,跳过执行。
1.先看property_init(),在property_service.c:
void property_init(void)
{
init_property_area();//初始化property存储区
load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);/* #define PROP_PATH_RAMDISK_DEFAULT "/default.prop",即加载default.prop 文件*/
}
2.启动属性服务
void start_property_service(void)
{
int fd;
/*四个属性文件
#define PROP_PATH_RAMDISK_DEFAULT "/default.prop"
#define PROP_PATH_SYSTEM_BUILD "/system/build.prop"
#define PROP_PATH_SYSTEM_DEFAULT "/system/default.prop"
#define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop"
*/
load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
//加载属性文件,这些文件保存到永久介质上
load_persistent_properties();
//创建socket,用于进程间通信
fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);
if(fd < 0) return;
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd, F_SETFL, O_NONBLOCK);
listen(fd, 8);
property_set_fd = fd;
}
3.用handle_property_set_fd()处理事件
void handle_property_set_fd()
{
prop_msg msg;
int s;
int r;
int res;
struct ucred cr;
struct sockaddr_un addr;
socklen_t addr_size = sizeof(addr);
socklen_t cr_size = sizeof(cr);
//socket接收网络连接
if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
return;
}
/* 获取用户端进程的属性 */
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
close(s);
ERROR("Unable to recieve socket options\n");
return;
}
//接受数据请求
r = recv(s, &msg, sizeof(msg), 0);
close(s);
if(r != sizeof(prop_msg)) {
ERROR("sys_prop: mis-match msg size recieved: %d expected: %d\n",
r, sizeof(prop_msg));
return;
}
//客户端消息命令码为PROP_MSG_SETPROP?
switch(msg.cmd) {
case PROP_MSG_SETPROP:
msg.name[PROP_NAME_MAX-1] = 0;
msg.value[PROP_VALUE_MAX-1] = 0;
//接受ctl.开头的控制消息,用一些命令来执行
if(memcmp(msg.name,"ctl.",4) == 0) {
if (check_control_perms(msg.value, cr.uid, cr.gid)) {
handle_control_message((char*) msg.name + 4, (char*) msg.value);
} else {
ERROR("sys_prop: Unable to %s service ctl [%s] uid: %d pid:%d\n",
msg.name + 4, msg.value, cr.uid, cr.pid);
}
} else {
//检查客户端的权限
if (check_perms(msg.name, cr.uid, cr.gid)) {
property_set((char*) msg.name, (char*) msg.value);//调用property_set
} else {
ERROR("sys_prop: permission denied uid:%d name:%s\n",
cr.uid, msg.name);
}
}
break;
default:
break;
}
}
下面分析在property_service.c文件中的property_set和property_get
nt property_set(const char *name, const char *value)
{
prop_area *pa;
prop_info *pi;
int namelen = strlen(name);
int valuelen = strlen(value);
if(namelen >= PROP_NAME_MAX) return -1;
if(valuelen >= PROP_VALUE_MAX) return -1;
if(namelen < 1) return -1;
//查找该属性是否存在
pi = (prop_info*) __system_property_find(name);
if(pi != 0) {
/* ro. 开头的属性表示只读*/
if(!strncmp(name, "ro.", 3)) return -1;
pa = __system_property_area__;
//更新值
update_prop_info(pi, value, valuelen);
pa->serial++;
__futex_wake(&pa->serial, INT32_MAX);
} else {
// PA_COUNT_MAX=247,如果没有找到属性,这里要增加属性,创建新的属性//并分配空间,如果属性总数超过247,直接返回
pa = __system_property_area__;
if(pa->count == PA_COUNT_MAX) return -1;
pi = pa_info_array + pa->count;
pi->serial = (valuelen << 24);
memcpy(pi->name, name, namelen + 1);
memcpy(pi->value, value, valuelen + 1);
pa->toc[pa->count] =
(namelen << 24) | (((unsigned) pi) - ((unsigned) pa));
pa->count++;
pa->serial++;
__futex_wake(&pa->serial, INT32_MAX);
}
/* 如果是以net.开头的属性,当做DNS这类属性*/
if (strncmp("net.", name, strlen("net.")) == 0) {
if (strcmp("net.change", name) == 0) {
return 0;
}
/*
如果有更新,重新设置
*/
property_set("net.change", name);
} else if (persistent_properties_loaded &&
strncmp("persist.", name, strlen("persist.")) == 0) {
/*
如果是以persist.开头的属性,写到/data/property /.temp文件里
*/
write_persistent_property(name, value);
}
//属性设置后,执行操作生效
property_changed(name, value);
return 0;
}
下面:
const char* property_get(const char *name)
{
prop_info *pi;
if(strlen(name) >= PROP_NAME_MAX) return 0;
//查找属性存在与否
pi = (prop_info*) __system_property_find(name);
if(pi != 0) {
return pi->value;//得到值
} else {
return 0;
}
}
之前提到socket,用于进程间通信,上述是属性服务端,那么要看看客户端的情况。
在properties.c中:
Step1:
int property_set(const char *key, const char *value)
{
prop_msg msg;
unsigned resp;
if(key == 0) return -1;
if(value == 0) value = "";
if(strlen(key) >= PROP_NAME_MAX) return -1;
if(strlen(value) >= PROP_VALUE_MAX) return -1;
msg.cmd = PROP_MSG_SETPROP;//设置消息码
strcpy((char*) msg.name, key);
strcpy((char*) msg.value, value);
return send_prop_msg(&msg);//发送请求
}
Step2:
static int send_prop_msg(prop_msg *msg)
{
int s;
int r;
//和服务端的socket连接
s = socket_local_client(PROP_SERVICE_NAME,
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM);
if(s < 0) return -1;
//通过socket发送消息
while((r = send(s, msg, sizeof(prop_msg), 0)) < 0) {
if((errno == EINTR) || (errno == EAGAIN)) continue;
break;
}
if(r == sizeof(prop_msg)) {
r = 0;
} else {
r = -1;
}
close(s);
return r;
}
Step3:
int property_get(const char *key, char *value, const char *default_value)
{
int len;
len = __system_property_get(key, value);//调用system_properties.c里的
//__system_property_get()函数
//如果读到值,返回长度
if(len > 0) {
return len;
}
//如果没读到,将默认值赋给value,并返回长度
if(default_value) {
len = strlen(default_value);
memcpy(value, default_value, len + 1);
}
return len;
}
说明:如果定义HAVE_SYSTEM_PROPERTY_SERVER这个宏,客户端与服务端socket连接如下:
Step1:
static void init(void)
{
assert(gPropFd == -1);
// #define SYSTEM_PROPERTY_PIPE_NAME "/tmp/android-sysprop"
gPropFd = connectToServer(SYSTEM_PROPERTY_PIPE_NAME);//连接服务端
if (gPropFd < 0) {
//LOGW("not connected to system property server\n");
} else {
//LOGV("Connected to system property server\n");
}
}
Step2:
static int connectToServer(const char* fileName)
{
int sock = -1;
int cc;
struct sockaddr_un addr;
//创建客户端的socket
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
LOGW("UNIX domain socket create failed (errno=%d)\n", errno);
return -1;
}
/*连接操作 */
strcpy(addr.sun_path, fileName); // max 108 bytes
addr.sun_family = AF_UNIX;
cc = connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
if (cc < 0) {
// ENOENT means socket file doesn't exist
// ECONNREFUSED means socket exists but nobody is listening
//LOGW("AF_UNIX connect failed for '%s': %s\n",
// fileName, strerror(errno));
close(sock);
return -1;
}
return sock;
}
init这个超级守护进程分析到这里。