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