summaryrefslogtreecommitdiffstats
path: root/init
diff options
context:
space:
mode:
Diffstat (limited to 'init')
-rw-r--r--init/Android.mk33
-rw-r--r--init/NOTICE26
-rw-r--r--init/builtins.cpp117
-rw-r--r--init/devices.cpp140
-rw-r--r--init/init.cpp43
-rw-r--r--init/init_parser.cpp20
-rw-r--r--init/keywords.h1
-rw-r--r--init/property_service.cpp34
-rw-r--r--init/property_service.h1
-rw-r--r--init/ueventd.cpp4
-rw-r--r--init/util.cpp6
-rw-r--r--init/vendor_init.cpp44
-rw-r--r--init/vendor_init.h34
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__ */