signal_handler.c revision ed8a7d84428ec945c48b6b53dc5a3a18fabaf683
19c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross/* 29c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross * Copyright (C) 2010 The Android Open Source Project 39c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross * 49c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross * Licensed under the Apache License, Version 2.0 (the "License"); 59c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross * you may not use this file except in compliance with the License. 69c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross * You may obtain a copy of the License at 79c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross * 89c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross * http://www.apache.org/licenses/LICENSE-2.0 99c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross * 109c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross * Unless required by applicable law or agreed to in writing, software 119c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross * distributed under the License is distributed on an "AS IS" BASIS, 129c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross * See the License for the specific language governing permissions and 149c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross * limitations under the License. 159c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross */ 169c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 179c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross#include <stdio.h> 189c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross#include <errno.h> 199c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross#include <signal.h> 209c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross#include <unistd.h> 219c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross#include <fcntl.h> 229c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross#include <sys/types.h> 239c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross#include <sys/socket.h> 249c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross#include <sys/wait.h> 259c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross#include <cutils/sockets.h> 269c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross#include <sys/reboot.h> 279c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 289c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross#include "init.h" 29ed8a7d84428ec945c48b6b53dc5a3a18fabaf683Colin Cross#include "list.h" 303899e9fc01cf608f19f716749c54cc5c4d17e766Colin Cross#include "util.h" 31ed8a7d84428ec945c48b6b53dc5a3a18fabaf683Colin Cross#include "log.h" 329c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 339c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Crossstatic int signal_fd = -1; 349c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Crossstatic int signal_recv_fd = -1; 359c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 369c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Crossstatic void sigchld_handler(int s) 379c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross{ 389c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross write(signal_fd, &s, 1); 399c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross} 409c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 419c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross#define CRITICAL_CRASH_THRESHOLD 4 /* if we crash >4 times ... */ 429c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross#define CRITICAL_CRASH_WINDOW (4*60) /* ... in 4 minutes, goto recovery*/ 439c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 449c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Crossstatic int wait_for_one_process(int block) 459c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross{ 469c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross pid_t pid; 479c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross int status; 489c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross struct service *svc; 499c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross struct socketinfo *si; 509c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross time_t now; 519c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross struct listnode *node; 529c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross struct command *cmd; 539c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 549c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR ); 559c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross if (pid <= 0) return -1; 569c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross INFO("waitpid returned pid %d, status = %08x\n", pid, status); 579c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 589c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross svc = service_find_by_pid(pid); 599c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross if (!svc) { 609c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross ERROR("untracked pid %d exited\n", pid); 619c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross return 0; 629c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross } 639c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 649c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross NOTICE("process '%s', pid %d exited\n", svc->name, pid); 659c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 669c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross if (!(svc->flags & SVC_ONESHOT)) { 679c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross kill(-pid, SIGKILL); 689c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross NOTICE("process '%s' killing any children in process group\n", svc->name); 699c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross } 709c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 719c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross /* remove any sockets we may have created */ 729c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross for (si = svc->sockets; si; si = si->next) { 739c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross char tmp[128]; 749c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name); 759c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross unlink(tmp); 769c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross } 779c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 789c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross svc->pid = 0; 799c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross svc->flags &= (~SVC_RUNNING); 809c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 819c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross /* oneshot processes go into the disabled state on exit */ 829c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross if (svc->flags & SVC_ONESHOT) { 839c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross svc->flags |= SVC_DISABLED; 849c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross } 859c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 869c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross /* disabled processes do not get restarted automatically */ 879c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross if (svc->flags & SVC_DISABLED) { 889c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross notify_service_state(svc->name, "stopped"); 899c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross return 0; 909c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross } 919c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 929c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross now = gettime(); 939c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross if (svc->flags & SVC_CRITICAL) { 949c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) { 959c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) { 969c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross ERROR("critical process '%s' exited %d times in %d minutes; " 979c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross "rebooting into recovery mode\n", svc->name, 989c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60); 999c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross sync(); 1009c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, 1019c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross LINUX_REBOOT_CMD_RESTART2, "recovery"); 1029c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross return 0; 1039c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross } 1049c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross } else { 1059c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross svc->time_crashed = now; 1069c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross svc->nr_crashed = 1; 1079c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross } 1089c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross } 1099c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 1109c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross svc->flags |= SVC_RESTARTING; 1119c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 1129c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross /* Execute all onrestart commands for this service. */ 1139c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross list_for_each(node, &svc->onrestart.commands) { 1149c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross cmd = node_to_item(node, struct command, clist); 1159c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross cmd->func(cmd->nargs, cmd->args); 1169c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross } 1179c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross notify_service_state(svc->name, "restarting"); 1189c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross return 0; 1199c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross} 1209c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 1219c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Crossvoid handle_signal(void) 1229c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross{ 1239c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross char tmp[32]; 1249c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 1259c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross /* we got a SIGCHLD - reap and restart as needed */ 1269c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross read(signal_recv_fd, tmp, sizeof(tmp)); 1279c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross while (!wait_for_one_process(0)) 1289c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross ; 1299c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross} 1309c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross 13112541c61311e0488e9873df754f8328cd12f99b4Colin Crossvoid signal_init(void) 13212541c61311e0488e9873df754f8328cd12f99b4Colin Cross{ 13312541c61311e0488e9873df754f8328cd12f99b4Colin Cross int s[2]; 13412541c61311e0488e9873df754f8328cd12f99b4Colin Cross 13512541c61311e0488e9873df754f8328cd12f99b4Colin Cross struct sigaction act; 13612541c61311e0488e9873df754f8328cd12f99b4Colin Cross 13712541c61311e0488e9873df754f8328cd12f99b4Colin Cross act.sa_handler = sigchld_handler; 13812541c61311e0488e9873df754f8328cd12f99b4Colin Cross act.sa_flags = SA_NOCLDSTOP; 13912541c61311e0488e9873df754f8328cd12f99b4Colin Cross act.sa_mask = 0; 14012541c61311e0488e9873df754f8328cd12f99b4Colin Cross act.sa_restorer = NULL; 14112541c61311e0488e9873df754f8328cd12f99b4Colin Cross sigaction(SIGCHLD, &act, 0); 14212541c61311e0488e9873df754f8328cd12f99b4Colin Cross 14312541c61311e0488e9873df754f8328cd12f99b4Colin Cross /* create a signalling mechanism for the sigchld handler */ 14412541c61311e0488e9873df754f8328cd12f99b4Colin Cross if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) { 14512541c61311e0488e9873df754f8328cd12f99b4Colin Cross signal_fd = s[0]; 14612541c61311e0488e9873df754f8328cd12f99b4Colin Cross signal_recv_fd = s[1]; 14712541c61311e0488e9873df754f8328cd12f99b4Colin Cross fcntl(s[0], F_SETFD, FD_CLOEXEC); 14812541c61311e0488e9873df754f8328cd12f99b4Colin Cross fcntl(s[0], F_SETFL, O_NONBLOCK); 14912541c61311e0488e9873df754f8328cd12f99b4Colin Cross fcntl(s[1], F_SETFD, FD_CLOEXEC); 15012541c61311e0488e9873df754f8328cd12f99b4Colin Cross fcntl(s[1], F_SETFL, O_NONBLOCK); 15112541c61311e0488e9873df754f8328cd12f99b4Colin Cross } 15212541c61311e0488e9873df754f8328cd12f99b4Colin Cross 15312541c61311e0488e9873df754f8328cd12f99b4Colin Cross handle_signal(); 15412541c61311e0488e9873df754f8328cd12f99b4Colin Cross} 15512541c61311e0488e9873df754f8328cd12f99b4Colin Cross 1569c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Crossint get_signal_fd() 1579c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross{ 1589c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross return signal_recv_fd; 1599c5366ba55b1553b2d66f48e3d14fbd274a2944dColin Cross} 160