⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 init.c

📁 Android 一些工具
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <ctype.h>#include <signal.h>#include <sys/wait.h>#include <sys/mount.h>#include <sys/stat.h>#include <sys/poll.h>#include <time.h>#include <errno.h>#include <stdarg.h>#include <mtd/mtd-user.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/un.h>#include <sys/reboot.h>#include <cutils/sockets.h>#include <termios.h>#include <linux/kd.h>#include <sys/system_properties.h>#include "devices.h"#include "init.h"#include "property_service.h"#ifndef BOOTCHART# define  BOOTCHART  0#endifstatic int property_triggers_enabled = 0;#if BOOTCHARTstatic int   bootchart_count;extern int   bootchart_init(void);extern int   bootchart_step(void);extern void  bootchart_finish(void);# define BOOTCHART_POLLING_MS   200 /* polling period in ms */# define BOOTCHART_MAX_TIME_MS  (2*60*1000) /* max polling time from boot */# define BOOTCHART_MAX_COUNT    (BOOTCHART_MAX_TIME_MS/BOOTCHART_POLLING_MS)#endifstatic char console[32];static char serialno[32];static char bootmode[32];static char baseband[32];static char carrier[32];static char bootloader[32];static char hardware[32];static unsigned revision = 0;static char qemu[32];static void drain_action_queue(void);static void notify_service_state(const char *name, const char *state){    char pname[PROP_NAME_MAX];    int len = strlen(name);    if ((len + 10) > PROP_NAME_MAX)        return;    snprintf(pname, sizeof(pname), "init.svc.%s", name);    property_set(pname, state);}static int have_console;static char *console_name = "/dev/console";static time_t process_needs_restart;static const char *ENV[32];/* add_environment - add "key=value" to the current environment */int add_environment(const char *key, const char *val){    int n;     for (n = 0; n < 31; n++) {        if (!ENV[n]) {            size_t len = strlen(key) + strlen(val) + 2;            char *entry = malloc(len);            snprintf(entry, len, "%s=%s", key, val);            ENV[n] = entry;            return 0;        }    }    return 1;}static void zap_stdio(void){    int fd;    fd = open("/dev/null", O_RDWR);    dup2(fd, 0);    dup2(fd, 1);    dup2(fd, 2);    close(fd);}static void open_console(){    int fd;    if ((fd = open(console_name, O_RDWR)) < 0) {        fd = open("/dev/null", O_RDWR);    }    dup2(fd, 0);    dup2(fd, 1);    dup2(fd, 2);    close(fd);}/* * gettime() - returns the time in seconds of the system's monotonic clock or * zero on error. */static time_t gettime(void){    struct timespec ts;    int ret;    ret = clock_gettime(CLOCK_MONOTONIC, &ts);    if (ret < 0) {        ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));        return 0;    }    return ts.tv_sec;}static void publish_socket(const char *name, int fd){    char key[64] = ANDROID_SOCKET_ENV_PREFIX;    char val[64];    strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,            name,            sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));    snprintf(val, sizeof(val), "%d", fd);    add_environment(key, val);    /* make sure we don't close-on-exec */    fcntl(fd, F_SETFD, 0);}void service_start(struct service *svc){    struct stat s;    pid_t pid;    int needs_console;    int n;        /* starting a service removes it from the disabled         * state and immediately takes it out of the restarting         * state if it was in there         */    svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING));    svc->time_started = 0;            /* running processes require no additional work -- if         * they're in the process of exiting, we've ensured         * that they will immediately restart on exit, unless         * they are ONESHOT         */    if (svc->flags & SVC_RUNNING) {        return;    }    needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;    if (needs_console && (!have_console)) {        ERROR("service '%s' requires console\n", svc->name);        svc->flags |= SVC_DISABLED;        return;    }    if (stat(svc->args[0], &s) != 0) {        ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);        svc->flags |= SVC_DISABLED;        return;    }    NOTICE("starting '%s'\n", svc->name);    pid = fork();    if (pid == 0) {        struct socketinfo *si;        struct svcenvinfo *ei;        char tmp[32];        int fd, sz;        get_property_workspace(&fd, &sz);        sprintf(tmp, "%d,%d", dup(fd), sz);        add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);        for (ei = svc->envvars; ei; ei = ei->next)            add_environment(ei->name, ei->value);        for (si = svc->sockets; si; si = si->next) {            int s = create_socket(si->name,                                  !strcmp(si->type, "dgram") ?                                   SOCK_DGRAM : SOCK_STREAM,                                  si->perm, si->uid, si->gid);            if (s >= 0) {                publish_socket(si->name, s);            }        }        if (needs_console) {            setsid();            open_console();        } else {            zap_stdio();        }#if 0        for (n = 0; svc->args[n]; n++) {            INFO("args[%d] = '%s'\n", n, svc->args[n]);        }        for (n = 0; ENV[n]; n++) {            INFO("env[%d] = '%s'\n", n, ENV[n]);        }#endif        setpgid(0, getpid());	/* as requested, set our gid, supplemental gids, and uid */        if (svc->gid) {            setgid(svc->gid);        }        if (svc->nr_supp_gids) {            setgroups(svc->nr_supp_gids, svc->supp_gids);        }        if (svc->uid) {            setuid(svc->uid);        }        execve(svc->args[0], (char**) svc->args, (char**) ENV);        _exit(127);    }    if (pid < 0) {        ERROR("failed to start '%s'\n", svc->name);        svc->pid = 0;        return;    }    svc->time_started = gettime();    svc->pid = pid;    svc->flags |= SVC_RUNNING;    notify_service_state(svc->name, "running");}void service_stop(struct service *svc){        /* we are no longer running, nor should we         * attempt to restart         */    svc->flags &= (~(SVC_RUNNING|SVC_RESTARTING));        /* if the service has not yet started, prevent         * it from auto-starting with its class         */    svc->flags |= SVC_DISABLED;    if (svc->pid) {        NOTICE("service '%s' is being killed\n", svc->name);        kill(-svc->pid, SIGTERM);        notify_service_state(svc->name, "stopping");    } else {        notify_service_state(svc->name, "stopped");    }}void property_changed(const char *name, const char *value){    if (property_triggers_enabled) {        queue_property_triggers(name, value);        drain_action_queue();    }}#define CRITICAL_CRASH_THRESHOLD    4       /* if we crash >4 times ... */#define CRITICAL_CRASH_WINDOW       (4*60)  /* ... in 4 minutes, goto recovery*/static int wait_for_one_process(int block){    pid_t pid;    int status;    struct service *svc;    struct socketinfo *si;    time_t now;    struct listnode *node;    struct command *cmd;    while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );    if (pid <= 0) return -1;    INFO("waitpid returned pid %d, status = %08x\n", pid, status);    svc = service_find_by_pid(pid);    if (!svc) {        ERROR("untracked pid %d exited\n", pid);        return 0;    }    NOTICE("process '%s', pid %d exited\n", svc->name, pid);    if (!(svc->flags & SVC_ONESHOT)) {        kill(-pid, SIGKILL);        NOTICE("process '%s' killing any children in process group\n", svc->name);    }    /* remove any sockets we may have created */    for (si = svc->sockets; si; si = si->next) {        char tmp[128];        snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);        unlink(tmp);    }    svc->pid = 0;    svc->flags &= (~SVC_RUNNING);        /* oneshot processes go into the disabled state on exit */    if (svc->flags & SVC_ONESHOT) {        svc->flags |= SVC_DISABLED;    }        /* disabled processes do not get restarted automatically */    if (svc->flags & SVC_DISABLED) {        notify_service_state(svc->name, "stopped");        return 0;    }    now = gettime();    if (svc->flags & SVC_CRITICAL) {        if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {            if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {                ERROR("critical process '%s' exited %d times in %d minutes; "                      "rebooting into recovery mode\n", svc->name,                      CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);                sync();                __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,                         LINUX_REBOOT_CMD_RESTART2, "recovery");                return 0;            }        } else {            svc->time_crashed = now;            svc->nr_crashed = 1;        }    }    /* Execute all onrestart commands for this service. */    list_for_each(node, &svc->onrestart.commands) {        cmd = node_to_item(node, struct command, clist);        cmd->func(cmd->nargs, cmd->args);    }    svc->flags |= SVC_RESTARTING;    notify_service_state(svc->name, "restarting");    return 0;}static void restart_service_if_needed(struct service *svc){    time_t next_start_time = svc->time_started + 5;    if (next_start_time <= gettime()) {        svc->flags &= (~SVC_RESTARTING);        service_start(svc);        return;    }    if ((next_start_time < process_needs_restart) ||        (process_needs_restart == 0)) {        process_needs_restart = next_start_time;    }}static void restart_processes(){    process_needs_restart = 0;    service_for_each_flags(SVC_RESTARTING,                           restart_service_if_needed);}static int signal_fd = -1;static void sigchld_handler(int s){    write(signal_fd, &s, 1);}static void msg_start(const char *name){    struct service *svc = service_find_by_name(name);        if (svc) {        service_start(svc);    } else {        ERROR("no such service '%s'\n", name);    }}static void msg_stop(const char *name){    struct service *svc = service_find_by_name(name);    if (svc) {        service_stop(svc);    } else {        ERROR("no such service '%s'\n");    }}void handle_control_message(const char *msg, const char *arg){    if (!strcmp(msg,"start")) {        msg_start(arg);    } else if (!strcmp(msg,"stop")) {        msg_stop(arg);    } else {        ERROR("unknown control msg '%s'\n", msg);    }}#define MAX_MTD_PARTITIONS 16static struct {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -