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