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