init.c revision ca7648ddfb46347c60014a849b0150a74df4e1d2
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <stdio.h> 18#include <stdlib.h> 19#include <string.h> 20#include <unistd.h> 21#include <fcntl.h> 22#include <ctype.h> 23#include <signal.h> 24#include <sys/wait.h> 25#include <sys/mount.h> 26#include <sys/stat.h> 27#include <sys/poll.h> 28#include <time.h> 29#include <errno.h> 30#include <stdarg.h> 31#include <mtd/mtd-user.h> 32#include <sys/types.h> 33#include <sys/socket.h> 34#include <sys/un.h> 35#include <sys/reboot.h> 36 37#include <cutils/sockets.h> 38#include <cutils/iosched_policy.h> 39#include <termios.h> 40 41#include <sys/system_properties.h> 42 43#include "devices.h" 44#include "init.h" 45#include "property_service.h" 46#include "bootchart.h" 47#include "keychords.h" 48#include "parser.h" 49 50static int property_triggers_enabled = 0; 51 52#if BOOTCHART 53static int bootchart_count; 54#endif 55 56static char console[32]; 57static char serialno[32]; 58static char bootmode[32]; 59static char baseband[32]; 60static char carrier[32]; 61static char bootloader[32]; 62static char hardware[32]; 63static unsigned revision = 0; 64static char qemu[32]; 65 66static void notify_service_state(const char *name, const char *state) 67{ 68 char pname[PROP_NAME_MAX]; 69 int len = strlen(name); 70 if ((len + 10) > PROP_NAME_MAX) 71 return; 72 snprintf(pname, sizeof(pname), "init.svc.%s", name); 73 property_set(pname, state); 74} 75 76static int have_console; 77static char *console_name = "/dev/console"; 78static time_t process_needs_restart; 79 80static const char *ENV[32]; 81 82/* add_environment - add "key=value" to the current environment */ 83int add_environment(const char *key, const char *val) 84{ 85 int n; 86 87 for (n = 0; n < 31; n++) { 88 if (!ENV[n]) { 89 size_t len = strlen(key) + strlen(val) + 2; 90 char *entry = malloc(len); 91 snprintf(entry, len, "%s=%s", key, val); 92 ENV[n] = entry; 93 return 0; 94 } 95 } 96 97 return 1; 98} 99 100static void zap_stdio(void) 101{ 102 int fd; 103 fd = open("/dev/null", O_RDWR); 104 dup2(fd, 0); 105 dup2(fd, 1); 106 dup2(fd, 2); 107 close(fd); 108} 109 110static void open_console() 111{ 112 int fd; 113 if ((fd = open(console_name, O_RDWR)) < 0) { 114 fd = open("/dev/null", O_RDWR); 115 } 116 dup2(fd, 0); 117 dup2(fd, 1); 118 dup2(fd, 2); 119 close(fd); 120} 121 122/* 123 * gettime() - returns the time in seconds of the system's monotonic clock or 124 * zero on error. 125 */ 126static time_t gettime(void) 127{ 128 struct timespec ts; 129 int ret; 130 131 ret = clock_gettime(CLOCK_MONOTONIC, &ts); 132 if (ret < 0) { 133 ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno)); 134 return 0; 135 } 136 137 return ts.tv_sec; 138} 139 140static void publish_socket(const char *name, int fd) 141{ 142 char key[64] = ANDROID_SOCKET_ENV_PREFIX; 143 char val[64]; 144 145 strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, 146 name, 147 sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); 148 snprintf(val, sizeof(val), "%d", fd); 149 add_environment(key, val); 150 151 /* make sure we don't close-on-exec */ 152 fcntl(fd, F_SETFD, 0); 153} 154 155void service_start(struct service *svc, const char *dynamic_args) 156{ 157 struct stat s; 158 pid_t pid; 159 int needs_console; 160 int n; 161 162 /* starting a service removes it from the disabled 163 * state and immediately takes it out of the restarting 164 * state if it was in there 165 */ 166 svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING)); 167 svc->time_started = 0; 168 169 /* running processes require no additional work -- if 170 * they're in the process of exiting, we've ensured 171 * that they will immediately restart on exit, unless 172 * they are ONESHOT 173 */ 174 if (svc->flags & SVC_RUNNING) { 175 return; 176 } 177 178 needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0; 179 if (needs_console && (!have_console)) { 180 ERROR("service '%s' requires console\n", svc->name); 181 svc->flags |= SVC_DISABLED; 182 return; 183 } 184 185 if (stat(svc->args[0], &s) != 0) { 186 ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name); 187 svc->flags |= SVC_DISABLED; 188 return; 189 } 190 191 if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) { 192 ERROR("service '%s' must be one-shot to use dynamic args, disabling\n", 193 svc->args[0]); 194 svc->flags |= SVC_DISABLED; 195 return; 196 } 197 198 NOTICE("starting '%s'\n", svc->name); 199 200 pid = fork(); 201 202 if (pid == 0) { 203 struct socketinfo *si; 204 struct svcenvinfo *ei; 205 char tmp[32]; 206 int fd, sz; 207 208 get_property_workspace(&fd, &sz); 209 sprintf(tmp, "%d,%d", dup(fd), sz); 210 add_environment("ANDROID_PROPERTY_WORKSPACE", tmp); 211 212 for (ei = svc->envvars; ei; ei = ei->next) 213 add_environment(ei->name, ei->value); 214 215 for (si = svc->sockets; si; si = si->next) { 216 int s = create_socket(si->name, 217 !strcmp(si->type, "dgram") ? 218 SOCK_DGRAM : SOCK_STREAM, 219 si->perm, si->uid, si->gid); 220 if (s >= 0) { 221 publish_socket(si->name, s); 222 } 223 } 224 225 if (svc->ioprio_class != IoSchedClass_NONE) { 226 if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) { 227 ERROR("Failed to set pid %d ioprio = %d,%d: %s\n", 228 getpid(), svc->ioprio_class, svc->ioprio_pri, strerror(errno)); 229 } 230 } 231 232 if (needs_console) { 233 setsid(); 234 open_console(); 235 } else { 236 zap_stdio(); 237 } 238 239#if 0 240 for (n = 0; svc->args[n]; n++) { 241 INFO("args[%d] = '%s'\n", n, svc->args[n]); 242 } 243 for (n = 0; ENV[n]; n++) { 244 INFO("env[%d] = '%s'\n", n, ENV[n]); 245 } 246#endif 247 248 setpgid(0, getpid()); 249 250 /* as requested, set our gid, supplemental gids, and uid */ 251 if (svc->gid) { 252 setgid(svc->gid); 253 } 254 if (svc->nr_supp_gids) { 255 setgroups(svc->nr_supp_gids, svc->supp_gids); 256 } 257 if (svc->uid) { 258 setuid(svc->uid); 259 } 260 261 if (!dynamic_args) { 262 if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) { 263 ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno)); 264 } 265 } else { 266 char *arg_ptrs[SVC_MAXARGS+1]; 267 int arg_idx = svc->nargs; 268 char *tmp = strdup(dynamic_args); 269 char *next = tmp; 270 char *bword; 271 272 /* Copy the static arguments */ 273 memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *))); 274 275 while((bword = strsep(&next, " "))) { 276 arg_ptrs[arg_idx++] = bword; 277 if (arg_idx == SVC_MAXARGS) 278 break; 279 } 280 arg_ptrs[arg_idx] = '\0'; 281 execve(svc->args[0], (char**) arg_ptrs, (char**) ENV); 282 } 283 _exit(127); 284 } 285 286 if (pid < 0) { 287 ERROR("failed to start '%s'\n", svc->name); 288 svc->pid = 0; 289 return; 290 } 291 292 svc->time_started = gettime(); 293 svc->pid = pid; 294 svc->flags |= SVC_RUNNING; 295 296 notify_service_state(svc->name, "running"); 297} 298 299void service_stop(struct service *svc) 300{ 301 /* we are no longer running, nor should we 302 * attempt to restart 303 */ 304 svc->flags &= (~(SVC_RUNNING|SVC_RESTARTING)); 305 306 /* if the service has not yet started, prevent 307 * it from auto-starting with its class 308 */ 309 svc->flags |= SVC_DISABLED; 310 311 if (svc->pid) { 312 NOTICE("service '%s' is being killed\n", svc->name); 313 kill(-svc->pid, SIGTERM); 314 notify_service_state(svc->name, "stopping"); 315 } else { 316 notify_service_state(svc->name, "stopped"); 317 } 318} 319 320void property_changed(const char *name, const char *value) 321{ 322 if (property_triggers_enabled) { 323 queue_property_triggers(name, value); 324 drain_action_queue(); 325 } 326} 327 328#define CRITICAL_CRASH_THRESHOLD 4 /* if we crash >4 times ... */ 329#define CRITICAL_CRASH_WINDOW (4*60) /* ... in 4 minutes, goto recovery*/ 330 331static int wait_for_one_process(int block) 332{ 333 pid_t pid; 334 int status; 335 struct service *svc; 336 struct socketinfo *si; 337 time_t now; 338 struct listnode *node; 339 struct command *cmd; 340 341 while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR ); 342 if (pid <= 0) return -1; 343 INFO("waitpid returned pid %d, status = %08x\n", pid, status); 344 345 svc = service_find_by_pid(pid); 346 if (!svc) { 347 ERROR("untracked pid %d exited\n", pid); 348 return 0; 349 } 350 351 NOTICE("process '%s', pid %d exited\n", svc->name, pid); 352 353 if (!(svc->flags & SVC_ONESHOT)) { 354 kill(-pid, SIGKILL); 355 NOTICE("process '%s' killing any children in process group\n", svc->name); 356 } 357 358 /* remove any sockets we may have created */ 359 for (si = svc->sockets; si; si = si->next) { 360 char tmp[128]; 361 snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name); 362 unlink(tmp); 363 } 364 365 svc->pid = 0; 366 svc->flags &= (~SVC_RUNNING); 367 368 /* oneshot processes go into the disabled state on exit */ 369 if (svc->flags & SVC_ONESHOT) { 370 svc->flags |= SVC_DISABLED; 371 } 372 373 /* disabled processes do not get restarted automatically */ 374 if (svc->flags & SVC_DISABLED) { 375 notify_service_state(svc->name, "stopped"); 376 return 0; 377 } 378 379 now = gettime(); 380 if (svc->flags & SVC_CRITICAL) { 381 if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) { 382 if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) { 383 ERROR("critical process '%s' exited %d times in %d minutes; " 384 "rebooting into recovery mode\n", svc->name, 385 CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60); 386 sync(); 387 __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, 388 LINUX_REBOOT_CMD_RESTART2, "recovery"); 389 return 0; 390 } 391 } else { 392 svc->time_crashed = now; 393 svc->nr_crashed = 1; 394 } 395 } 396 397 svc->flags |= SVC_RESTARTING; 398 399 /* Execute all onrestart commands for this service. */ 400 list_for_each(node, &svc->onrestart.commands) { 401 cmd = node_to_item(node, struct command, clist); 402 cmd->func(cmd->nargs, cmd->args); 403 } 404 notify_service_state(svc->name, "restarting"); 405 return 0; 406} 407 408static void restart_service_if_needed(struct service *svc) 409{ 410 time_t next_start_time = svc->time_started + 5; 411 412 if (next_start_time <= gettime()) { 413 svc->flags &= (~SVC_RESTARTING); 414 service_start(svc, NULL); 415 return; 416 } 417 418 if ((next_start_time < process_needs_restart) || 419 (process_needs_restart == 0)) { 420 process_needs_restart = next_start_time; 421 } 422} 423 424static void restart_processes() 425{ 426 process_needs_restart = 0; 427 service_for_each_flags(SVC_RESTARTING, 428 restart_service_if_needed); 429} 430 431static int signal_fd = -1; 432 433static void sigchld_handler(int s) 434{ 435 write(signal_fd, &s, 1); 436} 437 438static void msg_start(const char *name) 439{ 440 struct service *svc; 441 char *tmp = NULL; 442 char *args = NULL; 443 444 if (!strchr(name, ':')) 445 svc = service_find_by_name(name); 446 else { 447 tmp = strdup(name); 448 args = strchr(tmp, ':'); 449 *args = '\0'; 450 args++; 451 452 svc = service_find_by_name(tmp); 453 } 454 455 if (svc) { 456 service_start(svc, args); 457 } else { 458 ERROR("no such service '%s'\n", name); 459 } 460 if (tmp) 461 free(tmp); 462} 463 464static void msg_stop(const char *name) 465{ 466 struct service *svc = service_find_by_name(name); 467 468 if (svc) { 469 service_stop(svc); 470 } else { 471 ERROR("no such service '%s'\n", name); 472 } 473} 474 475void handle_control_message(const char *msg, const char *arg) 476{ 477 if (!strcmp(msg,"start")) { 478 msg_start(arg); 479 } else if (!strcmp(msg,"stop")) { 480 msg_stop(arg); 481 } else { 482 ERROR("unknown control msg '%s'\n", msg); 483 } 484} 485 486static void import_kernel_nv(char *name, int in_qemu) 487{ 488 char *value = strchr(name, '='); 489 490 if (value == 0) return; 491 *value++ = 0; 492 if (*name == 0) return; 493 494 if (!in_qemu) 495 { 496 /* on a real device, white-list the kernel options */ 497 if (!strcmp(name,"qemu")) { 498 strlcpy(qemu, value, sizeof(qemu)); 499 } else if (!strcmp(name,"androidboot.console")) { 500 strlcpy(console, value, sizeof(console)); 501 } else if (!strcmp(name,"androidboot.mode")) { 502 strlcpy(bootmode, value, sizeof(bootmode)); 503 } else if (!strcmp(name,"androidboot.serialno")) { 504 strlcpy(serialno, value, sizeof(serialno)); 505 } else if (!strcmp(name,"androidboot.baseband")) { 506 strlcpy(baseband, value, sizeof(baseband)); 507 } else if (!strcmp(name,"androidboot.carrier")) { 508 strlcpy(carrier, value, sizeof(carrier)); 509 } else if (!strcmp(name,"androidboot.bootloader")) { 510 strlcpy(bootloader, value, sizeof(bootloader)); 511 } else if (!strcmp(name,"androidboot.hardware")) { 512 strlcpy(hardware, value, sizeof(hardware)); 513 } else { 514 qemu_cmdline(name, value); 515 } 516 } else { 517 /* in the emulator, export any kernel option with the 518 * ro.kernel. prefix */ 519 char buff[32]; 520 int len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name ); 521 if (len < (int)sizeof(buff)) { 522 property_set( buff, value ); 523 } 524 } 525} 526 527static void import_kernel_cmdline(int in_qemu) 528{ 529 char cmdline[1024]; 530 char *ptr; 531 int fd; 532 533 fd = open("/proc/cmdline", O_RDONLY); 534 if (fd >= 0) { 535 int n = read(fd, cmdline, 1023); 536 if (n < 0) n = 0; 537 538 /* get rid of trailing newline, it happens */ 539 if (n > 0 && cmdline[n-1] == '\n') n--; 540 541 cmdline[n] = 0; 542 close(fd); 543 } else { 544 cmdline[0] = 0; 545 } 546 547 ptr = cmdline; 548 while (ptr && *ptr) { 549 char *x = strchr(ptr, ' '); 550 if (x != 0) *x++ = 0; 551 import_kernel_nv(ptr, in_qemu); 552 ptr = x; 553 } 554 555 /* don't expose the raw commandline to nonpriv processes */ 556 chmod("/proc/cmdline", 0440); 557} 558 559static void get_hardware_name(void) 560{ 561 char data[1024]; 562 int fd, n; 563 char *x, *hw, *rev; 564 565 /* Hardware string was provided on kernel command line */ 566 if (hardware[0]) 567 return; 568 569 fd = open("/proc/cpuinfo", O_RDONLY); 570 if (fd < 0) return; 571 572 n = read(fd, data, 1023); 573 close(fd); 574 if (n < 0) return; 575 576 data[n] = 0; 577 hw = strstr(data, "\nHardware"); 578 rev = strstr(data, "\nRevision"); 579 580 if (hw) { 581 x = strstr(hw, ": "); 582 if (x) { 583 x += 2; 584 n = 0; 585 while (*x && !isspace(*x)) { 586 hardware[n++] = tolower(*x); 587 x++; 588 if (n == 31) break; 589 } 590 hardware[n] = 0; 591 } 592 } 593 594 if (rev) { 595 x = strstr(rev, ": "); 596 if (x) { 597 revision = strtoul(x + 2, 0, 16); 598 } 599 } 600} 601 602void drain_action_queue(void) 603{ 604 struct listnode *node; 605 struct command *cmd; 606 struct action *act; 607 int ret; 608 609 while ((act = action_remove_queue_head())) { 610 INFO("processing action %p (%s)\n", act, act->name); 611 list_for_each(node, &act->commands) { 612 cmd = node_to_item(node, struct command, clist); 613 ret = cmd->func(cmd->nargs, cmd->args); 614 INFO("command '%s' r=%d\n", cmd->args[0], ret); 615 } 616 } 617} 618 619void open_devnull_stdio(void) 620{ 621 int fd; 622 static const char *name = "/dev/__null__"; 623 if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) { 624 fd = open(name, O_RDWR); 625 unlink(name); 626 if (fd >= 0) { 627 dup2(fd, 0); 628 dup2(fd, 1); 629 dup2(fd, 2); 630 if (fd > 2) { 631 close(fd); 632 } 633 return; 634 } 635 } 636 637 exit(1); 638} 639 640int main(int argc, char **argv) 641{ 642 int device_fd = -1; 643 int property_set_fd = -1; 644 int signal_recv_fd = -1; 645 int fd_count; 646 int s[2]; 647 int fd; 648 struct sigaction act; 649 char tmp[PROP_VALUE_MAX]; 650 struct pollfd ufds[4]; 651 char *tmpdev; 652 char* debuggable; 653 654 act.sa_handler = sigchld_handler; 655 act.sa_flags = SA_NOCLDSTOP; 656 act.sa_mask = 0; 657 act.sa_restorer = NULL; 658 sigaction(SIGCHLD, &act, 0); 659 660 /* clear the umask */ 661 umask(0); 662 663 /* Get the basic filesystem setup we need put 664 * together in the initramdisk on / and then we'll 665 * let the rc file figure out the rest. 666 */ 667 mkdir("/dev", 0755); 668 mkdir("/proc", 0755); 669 mkdir("/sys", 0755); 670 671 mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755"); 672 mkdir("/dev/pts", 0755); 673 mkdir("/dev/socket", 0755); 674 mount("devpts", "/dev/pts", "devpts", 0, NULL); 675 mount("proc", "/proc", "proc", 0, NULL); 676 mount("sysfs", "/sys", "sysfs", 0, NULL); 677 678 /* We must have some place other than / to create the 679 * device nodes for kmsg and null, otherwise we won't 680 * be able to remount / read-only later on. 681 * Now that tmpfs is mounted on /dev, we can actually 682 * talk to the outside world. 683 */ 684 open_devnull_stdio(); 685 log_init(); 686 687 INFO("reading config file\n"); 688 parse_config_file("/init.rc"); 689 690 /* pull the kernel commandline and ramdisk properties file in */ 691 qemu_init(); 692 import_kernel_cmdline(0); 693 694 get_hardware_name(); 695 snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware); 696 parse_config_file(tmp); 697 698 action_for_each_trigger("early-init", action_add_queue_tail); 699 drain_action_queue(); 700 701 INFO("device init\n"); 702 device_init(); 703 704 property_init(); 705 706 // only listen for keychords if ro.debuggable is true 707 keychord_init(); 708 709 if (console[0]) { 710 snprintf(tmp, sizeof(tmp), "/dev/%s", console); 711 console_name = strdup(tmp); 712 } 713 714 fd = open(console_name, O_RDWR); 715 if (fd >= 0) 716 have_console = 1; 717 close(fd); 718 719 if( load_565rle_image(INIT_IMAGE_FILE) ) { 720 fd = open("/dev/tty0", O_WRONLY); 721 if (fd >= 0) { 722 const char *msg; 723 msg = "\n" 724 "\n" 725 "\n" 726 "\n" 727 "\n" 728 "\n" 729 "\n" // console is 40 cols x 30 lines 730 "\n" 731 "\n" 732 "\n" 733 "\n" 734 "\n" 735 "\n" 736 "\n" 737 " A N D R O I D "; 738 write(fd, msg, strlen(msg)); 739 close(fd); 740 } 741 } 742 743 if (qemu[0]) 744 import_kernel_cmdline(1); 745 746 if (!strcmp(bootmode,"factory")) 747 property_set("ro.factorytest", "1"); 748 else if (!strcmp(bootmode,"factory2")) 749 property_set("ro.factorytest", "2"); 750 else 751 property_set("ro.factorytest", "0"); 752 753 property_set("ro.serialno", serialno[0] ? serialno : ""); 754 property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown"); 755 property_set("ro.baseband", baseband[0] ? baseband : "unknown"); 756 property_set("ro.carrier", carrier[0] ? carrier : "unknown"); 757 property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown"); 758 759 property_set("ro.hardware", hardware); 760 snprintf(tmp, PROP_VALUE_MAX, "%d", revision); 761 property_set("ro.revision", tmp); 762 763 /* execute all the boot actions to get us started */ 764 action_for_each_trigger("init", action_add_queue_tail); 765 action_for_each_trigger("early-fs", action_add_queue_tail); 766 action_for_each_trigger("fs", action_add_queue_tail); 767 action_for_each_trigger("post-fs", action_add_queue_tail); 768 drain_action_queue(); 769 770 /* read any property files on system or data and 771 * fire up the property service. This must happen 772 * after the ro.foo properties are set above so 773 * that /data/local.prop cannot interfere with them. 774 */ 775 property_set_fd = start_property_service(); 776 777 /* create a signalling mechanism for the sigchld handler */ 778 if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) { 779 signal_fd = s[0]; 780 signal_recv_fd = s[1]; 781 fcntl(s[0], F_SETFD, FD_CLOEXEC); 782 fcntl(s[0], F_SETFL, O_NONBLOCK); 783 fcntl(s[1], F_SETFD, FD_CLOEXEC); 784 fcntl(s[1], F_SETFL, O_NONBLOCK); 785 } 786 787 /* make sure we actually have all the pieces we need */ 788 if ((get_device_fd() < 0) || 789 (property_set_fd < 0) || 790 (signal_recv_fd < 0)) { 791 ERROR("init startup failure\n"); 792 return 1; 793 } 794 795 /* execute all the boot actions to get us started */ 796 action_for_each_trigger("early-boot", action_add_queue_tail); 797 action_for_each_trigger("boot", action_add_queue_tail); 798 drain_action_queue(); 799 800 /* run all property triggers based on current state of the properties */ 801 queue_all_property_triggers(); 802 drain_action_queue(); 803 804 /* enable property triggers */ 805 property_triggers_enabled = 1; 806 807 ufds[0].fd = get_device_fd(); 808 ufds[0].events = POLLIN; 809 ufds[1].fd = property_set_fd; 810 ufds[1].events = POLLIN; 811 ufds[2].fd = signal_recv_fd; 812 ufds[2].events = POLLIN; 813 fd_count = 3; 814 815 if (get_keychord_fd() > 0) { 816 ufds[3].fd = get_keychord_fd(); 817 ufds[3].events = POLLIN; 818 fd_count++; 819 } else { 820 ufds[3].events = 0; 821 ufds[3].revents = 0; 822 } 823 824#if BOOTCHART 825 bootchart_count = bootchart_init(); 826 if (bootchart_count < 0) { 827 ERROR("bootcharting init failure\n"); 828 } else if (bootchart_count > 0) { 829 NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS); 830 } else { 831 NOTICE("bootcharting ignored\n"); 832 } 833#endif 834 835 for(;;) { 836 int nr, i, timeout = -1; 837 838 for (i = 0; i < fd_count; i++) 839 ufds[i].revents = 0; 840 841 drain_action_queue(); 842 restart_processes(); 843 844 if (process_needs_restart) { 845 timeout = (process_needs_restart - gettime()) * 1000; 846 if (timeout < 0) 847 timeout = 0; 848 } 849 850#if BOOTCHART 851 if (bootchart_count > 0) { 852 if (timeout < 0 || timeout > BOOTCHART_POLLING_MS) 853 timeout = BOOTCHART_POLLING_MS; 854 if (bootchart_step() < 0 || --bootchart_count == 0) { 855 bootchart_finish(); 856 bootchart_count = 0; 857 } 858 } 859#endif 860 nr = poll(ufds, fd_count, timeout); 861 if (nr <= 0) 862 continue; 863 864 if (ufds[2].revents == POLLIN) { 865 /* we got a SIGCHLD - reap and restart as needed */ 866 read(signal_recv_fd, tmp, sizeof(tmp)); 867 while (!wait_for_one_process(0)) 868 ; 869 continue; 870 } 871 872 if (ufds[0].revents == POLLIN) 873 handle_device_fd(); 874 875 if (ufds[1].revents == POLLIN) 876 handle_property_set_fd(property_set_fd); 877 if (ufds[3].revents == POLLIN) 878 handle_keychord(); 879 } 880 881 return 0; 882} 883