Ejemplo n.º 1
0
int do_powerctl(int nargs, char **args)
{
    char command[PROP_VALUE_MAX];
    int res;
    int len = 0;
    int cmd = 0;
    const char *reboot_target;
    void (*callback_on_ro_remount)(const struct mntent*) = NULL;

    res = expand_props(command, args[1], sizeof(command));
    if (res) {
        ERROR("powerctl: cannot expand '%s'\n", args[1]);
        return -EINVAL;
    }

    if (strncmp(command, "shutdown", 8) == 0) {
        if (property_get_bool("init.shutdown_to_charging", false)) {
            return android_reboot(ANDROID_RB_RESTART2, 0, "charging");
        }
        cmd = ANDROID_RB_POWEROFF;
        len = 8;
        callback_on_ro_remount = unmount_and_fsck;
    } else if (strncmp(command, "reboot", 6) == 0) {
        cmd = ANDROID_RB_RESTART2;
        len = 6;
    } else {
        ERROR("powerctl: unrecognized command '%s'\n", command);
        return -EINVAL;
    }

    if (command[len] == ',') {
        char prop_value[PROP_VALUE_MAX] = {0};
        reboot_target = &command[len + 1];

        if ((property_get("init.svc.recovery", prop_value) == 0) &&
            (strncmp(reboot_target, "keys", 4) == 0)) {
            ERROR("powerctl: permission denied\n");
            return -EINVAL;
        }
    } else if (command[len] == '\0') {
        reboot_target = "";
    } else {
        ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);
        return -EINVAL;
    }

    return android_reboot_with_callback(cmd, 0, reboot_target,
                                        callback_on_ro_remount);
}
Ejemplo n.º 2
0
static int do_powerctl(const std::vector<std::string>& args) {
    const char* command = args[1].c_str();
    int len = 0;
    unsigned int cmd = 0;
    const char *reboot_target = "";
    void (*callback_on_ro_remount)(const struct mntent*) = NULL;

    if (strncmp(command, "shutdown", 8) == 0) {
        cmd = ANDROID_RB_POWEROFF;
        len = 8;
    } else if (strncmp(command, "reboot", 6) == 0) {
        cmd = ANDROID_RB_RESTART2;
        len = 6;
    } else {
        ERROR("powerctl: unrecognized command '%s'\n", command);
        return -EINVAL;
    }

    if (command[len] == ',') {
        if (cmd == ANDROID_RB_POWEROFF &&
            !strcmp(&command[len + 1], "userrequested")) {
            // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
            // Run fsck once the file system is remounted in read-only mode.
            callback_on_ro_remount = unmount_and_fsck;
        } else if (cmd == ANDROID_RB_RESTART2) {
            reboot_target = &command[len + 1];
        }
    } else if (command[len] != '\0') {
        ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);
        return -EINVAL;
    }

    std::string timeout = property_get("ro.build.shutdown_timeout");
    unsigned int delay = 0;

    if (android::base::ParseUint(timeout.c_str(), &delay) && delay > 0) {
        Timer t;
        // Ask all services to terminate.
        ServiceManager::GetInstance().ForEachService(
            [] (Service* s) { s->Terminate(); });

        while (t.duration() < delay) {
            ServiceManager::GetInstance().ReapAnyOutstandingChildren();

            int service_count = 0;
            ServiceManager::GetInstance().ForEachService(
                [&service_count] (Service* s) {
                    // Count the number of services running.
                    // Exclude the console as it will ignore the SIGTERM signal
                    // and not exit.
                    // Note: SVC_CONSOLE actually means "requires console" but
                    // it is only used by the shell.
                    if (s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
                        service_count++;
                    }
                });

            if (service_count == 0) {
                // All terminable services terminated. We can exit early.
                break;
            }

            // Wait a bit before recounting the number or running services.
            usleep(kTerminateServiceDelayMicroSeconds);
        }
        NOTICE("Terminating running services took %.02f seconds", t.duration());
    }

    return android_reboot_with_callback(cmd, 0, reboot_target,
                                        callback_on_ro_remount);
}