diff options
Diffstat (limited to 'init')
-rw-r--r-- | init/Android.mk | 33 | ||||
-rw-r--r-- | init/NOTICE | 26 | ||||
-rw-r--r-- | init/builtins.cpp | 117 | ||||
-rw-r--r-- | init/devices.cpp | 140 | ||||
-rw-r--r-- | init/init.cpp | 43 | ||||
-rw-r--r-- | init/init_parser.cpp | 20 | ||||
-rw-r--r-- | init/keywords.h | 1 | ||||
-rw-r--r-- | init/property_service.cpp | 34 | ||||
-rw-r--r-- | init/property_service.h | 1 | ||||
-rw-r--r-- | init/ueventd.cpp | 4 | ||||
-rw-r--r-- | init/util.cpp | 6 | ||||
-rw-r--r-- | init/vendor_init.cpp | 44 | ||||
-rw-r--r-- | init/vendor_init.h | 34 |
13 files changed, 467 insertions, 36 deletions
diff --git a/init/Android.mk b/init/Android.mk index de065dc..85dfbfc 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -48,9 +48,33 @@ LOCAL_SRC_FILES:= \ ueventd.cpp \ ueventd_parser.cpp \ watchdogd.cpp \ + vendor_init.cpp + +SYSTEM_CORE_INIT_DEFINES := BOARD_CHARGING_MODE_BOOTING_LPM \ + BOARD_CHARGING_CMDLINE_NAME \ + BOARD_CHARGING_CMDLINE_VALUE + +$(foreach system_core_init_define,$(SYSTEM_CORE_INIT_DEFINES), \ + $(if $($(system_core_init_define)), \ + $(eval LOCAL_CFLAGS += -D$(system_core_init_define)=\"$($(system_core_init_define))\") \ + ) \ +) + +ifneq ($(TARGET_IGNORE_RO_BOOT_SERIALNO),) +LOCAL_CFLAGS += -DIGNORE_RO_BOOT_SERIALNO +endif + +ifneq ($(TARGET_IGNORE_RO_BOOT_REVISION),) +LOCAL_CFLAGS += -DIGNORE_RO_BOOT_REVISION +endif + +ifneq ($(TARGET_INIT_UMOUNT_AND_FSCK_IS_UNSAFE),) +LOCAL_CFLAGS += -DUMOUNT_AND_FSCK_IS_UNSAFE +endif LOCAL_MODULE:= init LOCAL_C_INCLUDES += \ + external/zlib \ system/extras/ext4_utils \ system/core/mkbootimg @@ -65,12 +89,14 @@ LOCAL_STATIC_LIBRARIES := \ liblogwrap \ libcutils \ libbase \ - libext4_utils_static \ libutils \ liblog \ libc \ libselinux \ libmincrypt \ + libext4_utils_static \ + libext2_blkid \ + libext2_uuid_static \ libc++_static \ libdl \ libsparse_static \ @@ -82,6 +108,11 @@ LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \ ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd LOCAL_CLANG := $(init_clang) + +ifneq ($(strip $(TARGET_INIT_VENDOR_LIB)),) +LOCAL_WHOLE_STATIC_LIBRARIES += $(TARGET_INIT_VENDOR_LIB) +endif + include $(BUILD_EXECUTABLE) diff --git a/init/NOTICE b/init/NOTICE index c5b1efa..383d0f5 100644 --- a/init/NOTICE +++ b/init/NOTICE @@ -188,3 +188,29 @@ END OF TERMS AND CONDITIONS +Copyright (c) 2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/init/builtins.cpp b/init/builtins.cpp index 8eb5b5b..1681d17 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -16,7 +16,9 @@ #include <errno.h> #include <fcntl.h> +#include <mntent.h> #include <net/if.h> +#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -38,6 +40,7 @@ #include <base/stringprintf.h> #include <cutils/partition_utils.h> #include <cutils/android_reboot.h> +#include <logwrap/logwrap.h> #include <private/android_filesystem_config.h> #include "init.h" @@ -49,6 +52,8 @@ #include "log.h" #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW +#define UNMOUNT_CHECK_MS 5000 +#define UNMOUNT_CHECK_TIMES 10 int add_environment(const char *name, const char *value); @@ -109,25 +114,100 @@ static void service_start_if_not_disabled(struct service *svc) } } +static void unmount_and_fsck(const struct mntent *entry) +{ +#ifndef UMOUNT_AND_FSCK_IS_UNSAFE + if (strcmp(entry->mnt_type, "f2fs") && strcmp(entry->mnt_type, "ext4")) + return; + + /* First, lazily unmount the directory. This unmount request finishes when + * all processes that open a file or directory in |entry->mnt_dir| exit. + */ + TEMP_FAILURE_RETRY(umount2(entry->mnt_dir, MNT_DETACH)); + + /* Next, kill all processes except init, kthreadd, and kthreadd's + * children to finish the lazy unmount. Killing all processes here is okay + * because this callback function is only called right before reboot(). + * It might be cleaner to selectively kill processes that actually use + * |entry->mnt_dir| rather than killing all, probably by reusing a function + * like killProcessesWithOpenFiles() in vold/, but the selinux policy does + * not allow init to scan /proc/<pid> files which the utility function + * heavily relies on. The policy does not allow the process to execute + * killall/pkill binaries either. Note that some processes might + * automatically restart after kill(), but that is not really a problem + * because |entry->mnt_dir| is no longer visible to such new processes. + */ + service_for_each(service_stop); + TEMP_FAILURE_RETRY(kill(-1, SIGKILL)); + + int count = 0; + while (count++ < UNMOUNT_CHECK_TIMES) { + int fd = TEMP_FAILURE_RETRY(open(entry->mnt_fsname, O_RDONLY | O_EXCL)); + if (fd >= 0) { + /* |entry->mnt_dir| has sucessfully been unmounted. */ + close(fd); + break; + } else if (errno == EBUSY) { + /* Some processes using |entry->mnt_dir| are still alive. Wait for a + * while then retry. + */ + TEMP_FAILURE_RETRY( + usleep(UNMOUNT_CHECK_MS * 1000 / UNMOUNT_CHECK_TIMES)); + continue; + } else { + /* Cannot open the device. Give up. */ + return; + } + } + + int st; + if (!strcmp(entry->mnt_type, "f2fs")) { + const char *f2fs_argv[] = { + "/system/bin/fsck.f2fs", "-f", entry->mnt_fsname, + }; + android_fork_execvp_ext(ARRAY_SIZE(f2fs_argv), (char **)f2fs_argv, + &st, true, LOG_KLOG, true, NULL); + } else if (!strcmp(entry->mnt_type, "ext4")) { + const char *ext4_argv[] = { + "/system/bin/e2fsck", "-f", "-y", entry->mnt_fsname, + }; + android_fork_execvp_ext(ARRAY_SIZE(ext4_argv), (char **)ext4_argv, + &st, true, LOG_KLOG, true, NULL); + } +#endif +} + int do_class_start(int nargs, char **args) { - /* Starting a class does not start services - * which are explicitly disabled. They must - * be started individually. - */ + char prop[PROP_NAME_MAX]; + snprintf(prop, PROP_NAME_MAX, "class_start:%s", args[1]); + + /* Starting a class does not start services + * which are explicitly disabled. They must + * be started individually. + */ service_for_each_class(args[1], service_start_if_not_disabled); + action_for_each_trigger(prop, action_add_queue_tail); return 0; } int do_class_stop(int nargs, char **args) { + char prop[PROP_NAME_MAX]; + snprintf(prop, PROP_NAME_MAX, "class_stop:%s", args[1]); + service_for_each_class(args[1], service_stop); + action_for_each_trigger(prop, action_add_queue_tail); return 0; } int do_class_reset(int nargs, char **args) { + char prop[PROP_NAME_MAX]; + snprintf(prop, PROP_NAME_MAX, "class_reset:%s", args[1]); + service_for_each_class(args[1], service_reset); + action_for_each_trigger(prop, action_add_queue_tail); return 0; } @@ -401,6 +481,7 @@ int do_mount_all(int nargs, char **args) int ret = -1; int child_ret = -1; int status; + char boot_mode[PROP_VALUE_MAX] = {0}; struct fstab *fstab; if (nargs != 2) { @@ -450,10 +531,13 @@ int do_mount_all(int nargs, char **args) property_set("vold.decrypt", "trigger_default_encryption"); } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) { property_set("ro.crypto.state", "unencrypted"); - /* If fs_mgr determined this is an unencrypted device, then trigger - * that action. + /* If fs_mgr determined this is an unencrypted device and we are + * not booting into ffbm(fast factory boot mode),then trigger + * that action. */ - action_for_each_trigger("nonencrypted", action_add_queue_tail); + property_get("ro.bootmode", boot_mode); + if (strncmp(boot_mode, "ffbm", 4)) + action_for_each_trigger("nonencrypted", action_add_queue_tail); } else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) { /* Setup a wipe via recovery, and reboot into recovery */ ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n"); @@ -468,7 +552,9 @@ int do_mount_all(int nargs, char **args) // Although encrypted, we have device key, so we do not need to // do anything different from the nonencrypted case. - action_for_each_trigger("nonencrypted", action_add_queue_tail); + property_get("ro.bootmode", boot_mode); + if (strncmp(boot_mode, "ffbm", 4)) + action_for_each_trigger("nonencrypted", action_add_queue_tail); } else if (ret == FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED) { if (e4crypt_install_keyring()) { return -1; @@ -559,6 +645,7 @@ int do_powerctl(int nargs, char **args) 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) { @@ -567,8 +654,12 @@ int do_powerctl(int nargs, char **args) } 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; @@ -578,7 +669,14 @@ int do_powerctl(int nargs, char **args) } 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 { @@ -586,7 +684,8 @@ int do_powerctl(int nargs, char **args) return -EINVAL; } - return android_reboot(cmd, 0, reboot_target); + return android_reboot_with_callback(cmd, 0, reboot_target, + callback_on_ro_remount); } int do_trigger(int nargs, char **args) diff --git a/init/devices.cpp b/init/devices.cpp index 4944cec..bb54cca 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -47,6 +47,8 @@ #include "ueventd_parser.h" #include "util.h" #include "log.h" +#include "property_service.h" +#include <zlib.h> #define SYSFS_PREFIX "/sys" static const char *firmware_dirs[] = { "/etc/firmware", @@ -55,6 +57,8 @@ static const char *firmware_dirs[] = { "/etc/firmware", extern struct selabel_handle *sehandle; +extern char boot_device[PROP_VALUE_MAX]; + static int device_fd = -1; struct uevent { @@ -323,6 +327,35 @@ static void remove_platform_device(const char *path) } } +/* Given a path that may start with an MTD device (/devices/virtual/mtd/mtd8/mtdblock8), + * populate the supplied buffer with the MTD partition number and return 0. + * If it doesn't start with an MTD device, or there is some error, return -1 */ +static int find_mtd_device_prefix(const char *path, char *buf, ssize_t buf_sz) +{ + const char *start, *end; + + if (strncmp(path, "/devices/virtual/mtd", 20)) + return -1; + + /* Beginning of the prefix is the initial "mtdXX" after "/devices/virtual/mtd/" */ + start = path + 21; + + /* End of the prefix is one path '/' later, capturing the partition number + * Example: mtd8 */ + end = strchr(start, '/'); + if (!end) { + return -1; + } + + /* Make sure we have enough room for the string plus null terminator */ + if (end - start + 1 > buf_sz) + return -1; + + strncpy(buf, start, end - start); + buf[end - start] = '\0'; + return 0; +} + /* Given a path that may start with a PCI device, populate the supplied buffer * with the PCI domain/bus number and the peripheral ID and return 0. * If it doesn't start with a PCI device, or there is some error, return -1 */ @@ -472,6 +505,11 @@ static char **get_block_device_symlinks(struct uevent *uevent) char link_path[256]; int link_num = 0; char *p; + int is_bootdevice = -1; + int mtd_fd = -1; + int nr; + char mtd_name_path[256]; + char mtd_name[64]; pdev = find_platform_device(uevent->path); if (pdev) { @@ -480,19 +518,52 @@ static char **get_block_device_symlinks(struct uevent *uevent) } else if (!find_pci_device_prefix(uevent->path, buf, sizeof(buf))) { device = buf; type = "pci"; + } else if (!find_mtd_device_prefix(uevent->path, buf, sizeof(buf))) { + device = buf; + type = "mtd"; } else { return NULL; } - char **links = (char**) malloc(sizeof(char *) * 4); + char **links = (char**) malloc(sizeof(char *) * 6); if (!links) return NULL; - memset(links, 0, sizeof(char *) * 4); + memset(links, 0, sizeof(char *) * 6); INFO("found %s device %s\n", type, device); snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device); + if(!strcmp(type, "mtd")) { + snprintf(mtd_name_path, sizeof(mtd_name_path), + "/sys/devices/virtual/%s/%s/name", type, device); + mtd_fd = open(mtd_name_path, O_RDONLY); + if(mtd_fd < 0) { + ERROR("Unable to open %s for reading", mtd_name_path); + return NULL; + } + nr = read(mtd_fd, mtd_name, sizeof(mtd_name) - 1); + if (nr <= 0) + return NULL; + close(mtd_fd); + mtd_name[nr - 1] = '\0'; + + p = strdup(mtd_name); + sanitize(p); + if (asprintf(&links[link_num], "/dev/block/%s/by-name/%s", type, p) > 0) + link_num++; + else + links[link_num] = NULL; + free(p); + } + + if (pdev && boot_device[0] != '\0' && strstr(device, boot_device)) { + make_link_init(link_path, "/dev/block/bootdevice"); + is_bootdevice = 1; + } else { + is_bootdevice = 0; + } + if (uevent->partition_name) { p = strdup(uevent->partition_name); sanitize(p); @@ -502,6 +573,13 @@ static char **get_block_device_symlinks(struct uevent *uevent) link_num++; else links[link_num] = NULL; + + if (is_bootdevice > 0) { + if (asprintf(&links[link_num], "/dev/block/bootdevice/by-name/%s", p) > 0) + link_num++; + else + links[link_num] = NULL; + } free(p); } @@ -510,6 +588,13 @@ static char **get_block_device_symlinks(struct uevent *uevent) link_num++; else links[link_num] = NULL; + + if (is_bootdevice > 0) { + if (asprintf(&links[link_num], "/dev/block/bootdevice/by-num/p%d", uevent->partition_num) > 0) + link_num++; + else + links[link_num] = NULL; + } } slash = strrchr(uevent->path, '/'); @@ -748,23 +833,20 @@ static void handle_device_event(struct uevent *uevent) } } -static int load_firmware(int fw_fd, int loading_fd, int data_fd) +static int load_firmware(int fw_fd, gzFile gz_fd, int loading_fd, int data_fd) { - struct stat st; - long len_to_copy; int ret = 0; - if(fstat(fw_fd, &st) < 0) - return -1; - len_to_copy = st.st_size; - write(loading_fd, "1", 1); /* start transfer */ - while (len_to_copy > 0) { + while (1) { char buf[PAGE_SIZE]; ssize_t nr; - nr = read(fw_fd, buf, sizeof(buf)); + if (gz_fd) + nr = gzread(gz_fd, buf, sizeof(buf)); + else + nr = read(fw_fd, buf, sizeof(buf)); if(!nr) break; if(nr < 0) { @@ -772,7 +854,6 @@ static int load_firmware(int fw_fd, int loading_fd, int data_fd) break; } - len_to_copy -= nr; while (nr > 0) { ssize_t nw = 0; @@ -788,8 +869,10 @@ static int load_firmware(int fw_fd, int loading_fd, int data_fd) out: if(!ret) write(loading_fd, "0", 1); /* successful end of transfer */ - else + else { + ERROR("%s: aborted transfer\n", __func__); write(loading_fd, "-1", 2); /* abort transfer */ + } return ret; } @@ -799,12 +882,29 @@ static int is_booting(void) return access("/dev/.booting", F_OK) == 0; } +gzFile fw_gzopen(const char *fname, const char *mode) +{ + char *file1 = NULL; + int l; + gzFile gz_fd = NULL; + + l = asprintf(&file1, "%s.gz", fname); + if (l == -1) + goto out; + + gz_fd = gzopen(file1, mode); + free(file1); +out: + return gz_fd; +} + static void process_firmware_event(struct uevent *uevent) { char *root, *loading, *data; int l, loading_fd, data_fd, fw_fd; size_t i; int booting = is_booting(); + gzFile gz_fd = NULL; INFO("firmware: loading '%s' for '%s'\n", uevent->firmware, uevent->path); @@ -837,15 +937,18 @@ try_loading_again: goto data_free_out; fw_fd = open(file, O_RDONLY|O_CLOEXEC); free(file); - if (fw_fd >= 0) { - if(!load_firmware(fw_fd, loading_fd, data_fd)) + if (fw_fd < 0){ + gz_fd = fw_gzopen(file, "rb"); + } + if (fw_fd >= 0 || gz_fd) { + if(!load_firmware(fw_fd, gz_fd, loading_fd, data_fd)) INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware); else INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware); break; } } - if (fw_fd < 0) { + if ((fw_fd < 0) && !gz_fd) { if (booting) { /* If we're not fully booted, we may be missing * filesystems needed for firmware, wait and retry. @@ -859,7 +962,10 @@ try_loading_again: goto data_close_out; } - close(fw_fd); + if (gz_fd) + gzclose(gz_fd); + else + close(fw_fd); data_close_out: close(data_fd); loading_close_out: diff --git a/init/init.cpp b/init/init.cpp index 93fe944..58d7d34 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -63,13 +63,20 @@ #include "util.h" #include "ueventd.h" #include "watchdogd.h" +#include "vendor_init.h" struct selabel_handle *sehandle; struct selabel_handle *sehandle_prop; static int property_triggers_enabled = 0; +#ifndef BOARD_CHARGING_CMDLINE_NAME +#define BOARD_CHARGING_CMDLINE_NAME "androidboot.battchg_pause" +#define BOARD_CHARGING_CMDLINE_VALUE "true" +#endif + static char qemu[32]; +static char battchg_pause[32]; static struct action *cur_action = NULL; static struct command *cur_command = NULL; @@ -529,6 +536,9 @@ static void msg_restart(const char *name) void handle_control_message(const char *msg, const char *arg) { + if (!vendor_handle_control_message(msg, arg)) + return; + if (!strcmp(msg,"start")) { msg_start(arg); } else if (!strcmp(msg,"stop")) { @@ -632,7 +642,7 @@ static int wait_for_coldboot_done_action(int nargs, char **args) { // Any longer than 1s is an unreasonable length of time to delay booting. // If you're hitting this timeout, check that you didn't make your // sepolicy regular expressions too expensive (http://b/19899875). - if (wait_for_file(COLDBOOT_DONE, 1)) { + if (wait_for_file(COLDBOOT_DONE, 5)) { ERROR("Timed out waiting for %s\n", COLDBOOT_DONE); } @@ -782,6 +792,8 @@ static void import_kernel_nv(char *name, bool for_emulator) if (!strcmp(name,"qemu")) { strlcpy(qemu, value, sizeof(qemu)); + } else if (!strcmp(name,BOARD_CHARGING_CMDLINE_NAME)) { + strlcpy(battchg_pause, value, sizeof(battchg_pause)); } else if (!strncmp(name, "androidboot.", 12) && name_len > 12) { const char *boot_prop_name = name + 12; char prop[PROP_NAME_MAX]; @@ -799,12 +811,16 @@ static void export_kernel_boot_props() { const char *dst_prop; const char *default_value; } prop_map[] = { +#ifndef IGNORE_RO_BOOT_SERIALNO { "ro.boot.serialno", "ro.serialno", "", }, +#endif { "ro.boot.mode", "ro.bootmode", "unknown", }, { "ro.boot.baseband", "ro.baseband", "unknown", }, { "ro.boot.bootloader", "ro.bootloader", "unknown", }, { "ro.boot.hardware", "ro.hardware", "unknown", }, +#ifndef IGNORE_RO_BOOT_REVISION { "ro.boot.revision", "ro.revision", "0", }, +#endif }; for (size_t i = 0; i < ARRAY_SIZE(prop_map); i++) { char value[PROP_VALUE_MAX]; @@ -986,6 +1002,24 @@ static void selinux_initialize(bool in_kernel_domain) { } } +static int charging_mode_booting(void) { +#ifndef BOARD_CHARGING_MODE_BOOTING_LPM + return 0; +#else + int f; + char cmb; + f = open(BOARD_CHARGING_MODE_BOOTING_LPM, O_RDONLY); + if (f < 0) + return 0; + + if (1 != read(f, (void *)&cmb,1)) + return 0; + + close(f); + return ('1' == cmb); +#endif +} + int main(int argc, char** argv) { if (!strcmp(basename(argv[0]), "ueventd")) { return ueventd_main(argc, argv); @@ -1097,8 +1131,13 @@ int main(int argc, char** argv) { // Don't mount filesystems or start core system services in charger mode. char bootmode[PROP_VALUE_MAX]; - if (property_get("ro.bootmode", bootmode) > 0 && strcmp(bootmode, "charger") == 0) { + if (((property_get("ro.bootmode", bootmode) > 0 && strcmp(bootmode, "charger") == 0) || + strcmp(battchg_pause, BOARD_CHARGING_CMDLINE_VALUE) == 0) + || charging_mode_booting()) { action_for_each_trigger("charger", action_add_queue_tail); + } else if (strncmp(bootmode, "ffbm", 4) == 0) { + KLOG_ERROR("Booting into ffbm mode\n"); + action_for_each_trigger("ffbm", action_add_queue_tail); } else { action_for_each_trigger("late-init", action_add_queue_tail); } diff --git a/init/init_parser.cpp b/init/init_parser.cpp index 9bab67d..c36d36e 100644 --- a/init/init_parser.cpp +++ b/init/init_parser.cpp @@ -44,7 +44,7 @@ struct import { const char *filename; }; -static void *parse_service(struct parse_state *state, int nargs, char **args); +static void *parse_service(struct parse_state *state, int nargs, char **args, bool redefine); static void parse_line_service(struct parse_state *state, int nargs, char **args); static void *parse_action(struct parse_state *state, int nargs, char **args); @@ -184,6 +184,7 @@ static int lookup_keyword(const char *s) case 's': if (!strcmp(s, "eclabel")) return K_seclabel; if (!strcmp(s, "ervice")) return K_service; + if (!strcmp(s, "ervice_redefine")) return K_service_redefine; if (!strcmp(s, "etenv")) return K_setenv; if (!strcmp(s, "etprop")) return K_setprop; if (!strcmp(s, "etrlimit")) return K_setrlimit; @@ -362,7 +363,8 @@ static void parse_new_section(struct parse_state *state, int kw, nargs > 1 ? args[1] : ""); switch(kw) { case K_service: - state->context = parse_service(state, nargs, args); + case K_service_redefine: + state->context = parse_service(state, nargs, args, (kw == K_service_redefine)); if (state->context) { state->parse_line = parse_line_service; return; @@ -725,7 +727,7 @@ service* make_exec_oneshot_service(int nargs, char** args) { return svc; } -static void *parse_service(struct parse_state *state, int nargs, char **args) +static void *parse_service(struct parse_state *state, int nargs, char **args, bool redefine) { if (nargs < 3) { parse_error(state, "services must have a name and a program\n"); @@ -737,13 +739,18 @@ static void *parse_service(struct parse_state *state, int nargs, char **args) } service* svc = (service*) service_find_by_name(args[1]); - if (svc) { + if (svc && !redefine) { parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]); return 0; } nargs -= 2; - svc = (service*) calloc(1, sizeof(*svc) + sizeof(char*) * nargs); + + if (!svc) { + svc = (service*) calloc(1, sizeof(*svc) + sizeof(char*) * nargs); + redefine = false; + } + if (!svc) { parse_error(state, "out of memory\n"); return 0; @@ -758,7 +765,8 @@ static void *parse_service(struct parse_state *state, int nargs, char **args) cur_trigger->name = "onrestart"; list_add_tail(&svc->onrestart.triggers, &cur_trigger->nlist); list_init(&svc->onrestart.commands); - list_add_tail(&service_list, &svc->slist); + if (!redefine) + list_add_tail(&service_list, &svc->slist); return svc; } diff --git a/init/keywords.h b/init/keywords.h index 0910f60..303685d 100644 --- a/init/keywords.h +++ b/init/keywords.h @@ -84,6 +84,7 @@ enum { KEYWORD(rmdir, COMMAND, 1, do_rmdir) KEYWORD(seclabel, OPTION, 0, 0) KEYWORD(service, SECTION, 0, 0) + KEYWORD(service_redefine, SECTION, 0, 0) KEYWORD(setenv, OPTION, 2, 0) KEYWORD(setprop, COMMAND, 2, do_setprop) KEYWORD(setrlimit, COMMAND, 3, do_setrlimit) diff --git a/init/property_service.cpp b/init/property_service.cpp index 52f6b98..fe82bef 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -54,6 +54,7 @@ #include "init.h" #include "util.h" #include "log.h" +#include "vendor_init.h" #define PERSISTENT_PROPERTY_DIR "/data/property" #define FSTAB_PREFIX "/fstab." @@ -149,6 +150,33 @@ int __property_get(const char *name, char *value) return __system_property_get(name, value); } +bool property_get_bool(const char *key, bool default_value) { + if (!key) { + return default_value; + } + + bool result = default_value; + char buf[PROP_VALUE_MAX] = {'\0',}; + + int len = __property_get(key, buf); + if (len == 1) { + char ch = buf[0]; + if (ch == '0' || ch == 'n') { + result = false; + } else if (ch == '1' || ch == 'y') { + result = true; + } + } else if (len > 1) { + if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) { + result = false; + } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) { + result = true; + } + } + + return result; +} + static void write_persistent_property(const char *name, const char *value) { char tempPath[PATH_MAX]; @@ -518,6 +546,11 @@ void load_persist_props(void) { load_override_properties(); /* Read persistent properties after all default values have been loaded. */ load_persistent_properties(); + + /* update with vendor-specific property runtime + * overrides + */ + vendor_load_properties(); } void load_recovery_id_prop() { @@ -564,6 +597,7 @@ void load_system_props() { load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL); load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL); load_properties_from_file(PROP_PATH_FACTORY, "ro.*"); + load_recovery_id_prop(); } diff --git a/init/property_service.h b/init/property_service.h index 303f251..6b542b5 100644 --- a/init/property_service.h +++ b/init/property_service.h @@ -28,6 +28,7 @@ extern void start_property_service(void); void get_property_workspace(int *fd, int *sz); extern int __property_get(const char *name, char *value); extern int property_set(const char *name, const char *value); +extern bool property_get_bool(const char *name, bool def_value); extern bool properties_initialized(); #ifndef __clang__ diff --git a/init/ueventd.cpp b/init/ueventd.cpp index c63fdaa..2dd8b01 100644 --- a/init/ueventd.cpp +++ b/init/ueventd.cpp @@ -33,6 +33,8 @@ #include "ueventd_parser.h" #include "property_service.h" +char boot_device[PROP_VALUE_MAX]; + int ueventd_main(int argc, char **argv) { /* @@ -65,6 +67,8 @@ int ueventd_main(int argc, char **argv) ueventd_parse_config_file("/ueventd.rc"); ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware).c_str()); + property_get("ro.boot.bootdevice", boot_device); + device_init(); pollfd ufd; diff --git a/init/util.cpp b/init/util.cpp index a5392c6..b006e0b 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -458,9 +458,13 @@ int restorecon(const char* pathname) return selinux_android_restorecon(pathname, 0); } +#define RESTORECON_RECURSIVE_FLAGS \ + (SELINUX_ANDROID_RESTORECON_FORCE | \ + SELINUX_ANDROID_RESTORECON_RECURSE) + int restorecon_recursive(const char* pathname) { - return selinux_android_restorecon(pathname, SELINUX_ANDROID_RESTORECON_RECURSE); + return selinux_android_restorecon(pathname, RESTORECON_RECURSIVE_FLAGS); } /* diff --git a/init/vendor_init.cpp b/init/vendor_init.cpp new file mode 100644 index 0000000..d2964ad --- /dev/null +++ b/init/vendor_init.cpp @@ -0,0 +1,44 @@ +/* +Copyright (c) 2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "vendor_init.h" +#include <errno.h> + +/* init vendor override stubs */ + +__attribute__ ((weak)) +void vendor_load_properties() +{ +} + +__attribute__ ((weak)) +int vendor_handle_control_message(const char *msg, const char *arg) +{ + return -ENOSYS; +} diff --git a/init/vendor_init.h b/init/vendor_init.h new file mode 100644 index 0000000..efa4eea --- /dev/null +++ b/init/vendor_init.h @@ -0,0 +1,34 @@ +/* +Copyright (c) 2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __INIT_VENDOR__H__ +#define __INIT_VENDOR__H__ +extern void vendor_load_properties(void); +extern int vendor_handle_control_message(const char *msg, const char *arg); +#endif /* __INIT_VENDOR__H__ */ |