blob: b45fcc5d165b71a4141ee23c620919219aaa5c64 [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>
San Mehat4e221f02010-02-25 14:19:50 -080038#include <cutils/iosched_policy.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070039#include <termios.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070040
41#include <sys/system_properties.h>
42
43#include "devices.h"
44#include "init.h"
45#include "property_service.h"
The Android Open Source Project35237d12008-12-17 18:08:08 -080046#include "bootchart.h"
Colin Crossa8666952010-04-13 19:20:44 -070047#include "keychords.h"
Colin Crossca7648d2010-04-13 19:29:51 -070048#include "parser.h"
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070049
50static int property_triggers_enabled = 0;
51
52#if BOOTCHART
53static int bootchart_count;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070054#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
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070066static 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
San Mehatf24e2522009-05-19 13:30:46 -0700155void service_start(struct service *svc, const char *dynamic_args)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700156{
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
San Mehatf24e2522009-05-19 13:30:46 -0700191 if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {
San Mehatd4cdd132009-05-20 09:52:16 -0700192 ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
193 svc->args[0]);
San Mehatf24e2522009-05-19 13:30:46 -0700194 svc->flags |= SVC_DISABLED;
195 return;
196 }
197
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700198 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
San Mehat4e221f02010-02-25 14:19:50 -0800225 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
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700232 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
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800250 /* as requested, set our gid, supplemental gids, and uid */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700251 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
San Mehat8ad15682009-05-20 08:50:40 -0700261 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 {
San Mehatf24e2522009-05-19 13:30:46 -0700266 char *arg_ptrs[SVC_MAXARGS+1];
San Mehatd4cdd132009-05-20 09:52:16 -0700267 int arg_idx = svc->nargs;
San Mehatf24e2522009-05-19 13:30:46 -0700268 char *tmp = strdup(dynamic_args);
San Mehatd4cdd132009-05-20 09:52:16 -0700269 char *next = tmp;
270 char *bword;
San Mehatf24e2522009-05-19 13:30:46 -0700271
272 /* Copy the static arguments */
San Mehatd4cdd132009-05-20 09:52:16 -0700273 memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));
San Mehatf24e2522009-05-19 13:30:46 -0700274
San Mehatd4cdd132009-05-20 09:52:16 -0700275 while((bword = strsep(&next, " "))) {
276 arg_ptrs[arg_idx++] = bword;
277 if (arg_idx == SVC_MAXARGS)
San Mehatf24e2522009-05-19 13:30:46 -0700278 break;
San Mehatf24e2522009-05-19 13:30:46 -0700279 }
280 arg_ptrs[arg_idx] = '\0';
281 execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
Ivan Djelic165de922008-11-23 22:26:39 +0100282 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700283 _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
Ben Gruverdc816d52009-01-13 20:43:30 -0600397 svc->flags |= SVC_RESTARTING;
398
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700399 /* 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 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700404 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);
San Mehatf24e2522009-05-19 13:30:46 -0700414 service_start(svc, NULL);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700415 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{
San Mehatf24e2522009-05-19 13:30:46 -0700440 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);
San Mehatf24e2522009-05-19 13:30:46 -0700448 args = strchr(tmp, ':');
449 *args = '\0';
450 args++;
451
452 svc = service_find_by_name(tmp);
453 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700454
455 if (svc) {
San Mehatf24e2522009-05-19 13:30:46 -0700456 service_start(svc, args);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700457 } else {
458 ERROR("no such service '%s'\n", name);
459 }
San Mehatf24e2522009-05-19 13:30:46 -0700460 if (tmp)
461 free(tmp);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700462}
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 {
Dima Zavin770354d2009-05-05 18:33:07 -0700471 ERROR("no such service '%s'\n", name);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700472 }
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
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700486static 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
Jay Freeman (saurik)11e1c422008-11-17 06:35:08 +0000602void drain_action_queue(void)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700603{
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;
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800645 int fd_count;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700646 int s[2];
647 int fd;
648 struct sigaction act;
649 char tmp[PROP_VALUE_MAX];
650 struct pollfd ufds[4];
651 char *tmpdev;
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800652 char* debuggable;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700653
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");
Colin Cross0dd7ca62010-04-13 19:25:51 -0700702 device_init();
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700703
704 property_init();
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800705
706 // only listen for keychords if ro.debuggable is true
Colin Crossa8666952010-04-13 19:20:44 -0700707 keychord_init();
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700708
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) ) {
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800720 fd = open("/dev/tty0", O_WRONLY);
721 if (fd >= 0) {
722 const char *msg;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700723 msg = "\n"
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800724 "\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 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700741 }
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);
Colin Cross31712be2010-04-09 12:26:06 -0700765 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);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700768 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 */
Colin Cross0dd7ca62010-04-13 19:25:51 -0700788 if ((get_device_fd() < 0) ||
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700789 (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
Colin Cross0dd7ca62010-04-13 19:25:51 -0700807 ufds[0].fd = get_device_fd();
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700808 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;
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800813 fd_count = 3;
814
Colin Crossa8666952010-04-13 19:20:44 -0700815 if (get_keychord_fd() > 0) {
816 ufds[3].fd = get_keychord_fd();
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800817 ufds[3].events = POLLIN;
818 fd_count++;
819 } else {
820 ufds[3].events = 0;
821 ufds[3].revents = 0;
822 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700823
824#if BOOTCHART
The Android Open Source Project35237d12008-12-17 18:08:08 -0800825 bootchart_count = bootchart_init();
826 if (bootchart_count < 0) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700827 ERROR("bootcharting init failure\n");
The Android Open Source Project35237d12008-12-17 18:08:08 -0800828 } 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");
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700832 }
833#endif
834
835 for(;;) {
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800836 int nr, i, timeout = -1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700837
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800838 for (i = 0; i < fd_count; i++)
839 ufds[i].revents = 0;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700840
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
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800860 nr = poll(ufds, fd_count, timeout);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700861 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)
Colin Cross0dd7ca62010-04-13 19:25:51 -0700873 handle_device_fd();
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700874
875 if (ufds[1].revents == POLLIN)
876 handle_property_set_fd(property_set_fd);
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800877 if (ufds[3].revents == POLLIN)
Colin Crossa8666952010-04-13 19:20:44 -0700878 handle_keychord();
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700879 }
880
881 return 0;
882}