1 /* 2 * Copyright (C) 2010 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 <errno.h> 19 #include <signal.h> 20 #include <unistd.h> 21 #include <fcntl.h> 22 #include <sys/types.h> 23 #include <sys/socket.h> 24 #include <sys/wait.h> 25 #include <cutils/sockets.h> 26 #include <cutils/android_reboot.h> 27 #include <cutils/list.h> 28 29 #include "init.h" 30 #include "util.h" 31 #include "log.h" 32 33 static int signal_fd = -1; 34 static int signal_recv_fd = -1; 35 36 static void sigchld_handler(int s) 37 { 38 write(signal_fd, &s, 1); 39 } 40 41 #define CRITICAL_CRASH_THRESHOLD 4 /* if we crash >4 times ... */ 42 #define CRITICAL_CRASH_WINDOW (4*60) /* ... in 4 minutes, goto recovery*/ 43 44 static int wait_for_one_process(int block) 45 { 46 pid_t pid; 47 int status; 48 struct service *svc; 49 struct socketinfo *si; 50 time_t now; 51 struct listnode *node; 52 struct command *cmd; 53 54 while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR ); 55 if (pid <= 0) return -1; 56 INFO("waitpid returned pid %d, status = %08x\n", pid, status); 57 58 svc = service_find_by_pid(pid); 59 if (!svc) { 60 if (WIFEXITED(status)) { 61 ERROR("untracked pid %d exited with status %d\n", pid, WEXITSTATUS(status)); 62 } else if (WIFSIGNALED(status)) { 63 ERROR("untracked pid %d killed by signal %d\n", pid, WTERMSIG(status)); 64 } else if (WIFSTOPPED(status)) { 65 ERROR("untracked pid %d stopped by signal %d\n", pid, WSTOPSIG(status)); 66 } else { 67 ERROR("untracked pid %d state changed\n", pid); 68 } 69 return 0; 70 } 71 72 NOTICE("process '%s', pid %d exited\n", svc->name, pid); 73 74 if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) { 75 kill(-pid, SIGKILL); 76 NOTICE("process '%s' killing any children in process group\n", svc->name); 77 } 78 79 /* remove any sockets we may have created */ 80 for (si = svc->sockets; si; si = si->next) { 81 char tmp[128]; 82 snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name); 83 unlink(tmp); 84 } 85 86 svc->pid = 0; 87 svc->flags &= (~SVC_RUNNING); 88 89 /* oneshot processes go into the disabled state on exit, 90 * except when manually restarted. */ 91 if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) { 92 svc->flags |= SVC_DISABLED; 93 } 94 95 /* disabled and reset processes do not get restarted automatically */ 96 if (svc->flags & (SVC_DISABLED | SVC_RESET) ) { 97 notify_service_state(svc->name, "stopped"); 98 return 0; 99 } 100 101 now = gettime(); 102 if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) { 103 if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) { 104 if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) { 105 ERROR("critical process '%s' exited %d times in %d minutes; " 106 "rebooting into recovery mode\n", svc->name, 107 CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60); 108 android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); 109 return 0; 110 } 111 } else { 112 svc->time_crashed = now; 113 svc->nr_crashed = 1; 114 } 115 } 116 117 svc->flags &= (~SVC_RESTART); 118 svc->flags |= SVC_RESTARTING; 119 120 /* Execute all onrestart commands for this service. */ 121 list_for_each(node, &svc->onrestart.commands) { 122 cmd = node_to_item(node, struct command, clist); 123 cmd->func(cmd->nargs, cmd->args); 124 } 125 notify_service_state(svc->name, "restarting"); 126 return 0; 127 } 128 129 void handle_signal(void) 130 { 131 char tmp[32]; 132 133 /* we got a SIGCHLD - reap and restart as needed */ 134 read(signal_recv_fd, tmp, sizeof(tmp)); 135 while (!wait_for_one_process(0)) 136 ; 137 } 138 139 void signal_init(void) 140 { 141 int s[2]; 142 143 struct sigaction act; 144 memset(&act, 0, sizeof(act)); 145 act.sa_handler = sigchld_handler; 146 act.sa_flags = SA_NOCLDSTOP; 147 sigaction(SIGCHLD, &act, 0); 148 149 /* create a signalling mechanism for the sigchld handler */ 150 if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) { 151 signal_fd = s[0]; 152 signal_recv_fd = s[1]; 153 fcntl(s[0], F_SETFD, FD_CLOEXEC); 154 fcntl(s[0], F_SETFL, O_NONBLOCK); 155 fcntl(s[1], F_SETFD, FD_CLOEXEC); 156 fcntl(s[1], F_SETFL, O_NONBLOCK); 157 } 158 159 handle_signal(); 160 } 161 162 int get_signal_fd() 163 { 164 return signal_recv_fd; 165 } 166