diff options
Diffstat (limited to 'bootloader_message')
-rw-r--r-- | bootloader_message/Android.mk | 27 | ||||
-rw-r--r-- | bootloader_message/bootloader_message.cpp | 184 | ||||
-rw-r--r-- | bootloader_message/include/bootloader_message/bootloader_message.h | 7 |
3 files changed, 204 insertions, 14 deletions
diff --git a/bootloader_message/Android.mk b/bootloader_message/Android.mk index 815ac67d7..1d5c85fe3 100644 --- a/bootloader_message/Android.mk +++ b/bootloader_message/Android.mk @@ -14,11 +14,32 @@ LOCAL_PATH := $(call my-dir) +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 25; echo $$?),0) + include $(CLEAR_VARS) + LOCAL_CLANG := true + LOCAL_SRC_FILES := bootloader_message.cpp + LOCAL_MODULE := libbootloader_message + LOCAL_STATIC_LIBRARIES := libfs_mgr + LOCAL_C_INCLUDES := $(LOCAL_PATH)/include + LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include + include $(BUILD_STATIC_LIBRARY) +endif + include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_SRC_FILES := bootloader_message.cpp LOCAL_MODULE := libbootloader_message -LOCAL_STATIC_LIBRARIES := libbase libfs_mgr -LOCAL_C_INCLUDES := $(LOCAL_PATH)/include +LOCAL_C_INCLUDES += bionic $(LOCAL_PATH)/include +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0) + LOCAL_C_INCLUDES += external/stlport/stlport + LOCAL_SHARED_LIBRARIES += libstlport +else + LOCAL_SHARED_LIBRARIES += libc++ +endif +LOCAL_CFLAGS := -DEXCLUDE_FS_MGR +# ignore bootloader's factory reset command even when written to /misc +ifeq ($(TW_IGNORE_MISC_WIPE_DATA), true) + LOCAL_CFLAGS += -DIGNORE_MISC_WIPE_DATA +endif LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include -include $(BUILD_STATIC_LIBRARY) +include $(BUILD_SHARED_LIBRARY) diff --git a/bootloader_message/bootloader_message.cpp b/bootloader_message/bootloader_message.cpp index 9de7dff40..4d1ce5bb4 100644 --- a/bootloader_message/bootloader_message.cpp +++ b/bootloader_message/bootloader_message.cpp @@ -19,16 +19,31 @@ #include <errno.h> #include <fcntl.h> #include <string.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/types.h> #include <sys/system_properties.h> #include <string> #include <vector> +/* #include <android-base/file.h> #include <android-base/stringprintf.h> #include <android-base/unique_fd.h> +*/ +#ifndef EXCLUDE_FS_MGR #include <fs_mgr.h> +#endif + +static std::string misc_blkdev; + +void set_misc_device(std::string name) { + misc_blkdev = name; +} +#ifndef EXCLUDE_FS_MGR static struct fstab* read_fstab(std::string* err) { // The fstab path is always "/fstab.${ro.hardware}". std::string fstab_path = "/fstab."; @@ -44,8 +59,12 @@ static struct fstab* read_fstab(std::string* err) { } return fstab; } +#endif static std::string get_misc_blk_device(std::string* err) { +#ifdef EXCLUDE_FS_MGR + return misc_blkdev; +#else struct fstab* fstab = read_fstab(err); if (fstab == nullptr) { return ""; @@ -56,8 +75,10 @@ static std::string get_misc_blk_device(std::string* err) { return ""; } return record->blk_device; +#endif } + // In recovery mode, recovery can get started and try to access the misc // device before the kernel has actually created it. static bool wait_for_device(const std::string& blk_device, std::string* err) { @@ -69,14 +90,23 @@ static bool wait_for_device(const std::string& blk_device, std::string* err) { struct stat buf; ret = stat(blk_device.c_str(), &buf); if (ret == -1) { + char buffer[2048]; + sprintf(buffer, "failed to stat %s try %d: %s\n", + blk_device.c_str(), tries, strerror(errno)); + *err += buffer; + /* *err += android::base::StringPrintf("failed to stat %s try %d: %s\n", blk_device.c_str(), tries, strerror(errno)); + */ sleep(1); } } while (ret && tries < 10); if (ret) { + *err += "failed to stat " + blk_device + "\n"; + /* *err += android::base::StringPrintf("failed to stat %s\n", blk_device.c_str()); + */ } return ret == 0; } @@ -89,53 +119,89 @@ static bool read_misc_partition(void* p, size_t size, size_t offset, std::string if (!wait_for_device(misc_blk_device, err)) { return false; } - android::base::unique_fd fd(open(misc_blk_device.c_str(), O_RDONLY)); - if (fd.get() == -1) { + int fd(open(misc_blk_device.c_str(), O_RDONLY)); + if (fd < 0) { + *err = "failed to open " + misc_blk_device + ": "; + *err += strerror(errno); + /* *err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(), strerror(errno)); + */ return false; } - if (lseek(fd.get(), static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) { + if (lseek(fd, static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) { + *err = "failed to lseek " + misc_blk_device + ": "; + *err += strerror(errno); + close(fd); + /* *err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(), strerror(errno)); + */ return false; } - if (!android::base::ReadFully(fd.get(), p, size)) { + if (read(fd, p, size) != size) { + *err = "failed to read " + misc_blk_device + ": "; + *err += strerror(errno); + close(fd); + /* *err = android::base::StringPrintf("failed to read %s: %s", misc_blk_device.c_str(), strerror(errno)); + */ return false; } + close(fd); return true; } static bool write_misc_partition(const void* p, size_t size, size_t offset, std::string* err) { std::string misc_blk_device = get_misc_blk_device(err); if (misc_blk_device.empty()) { + *err = "no misc device set"; return false; } - android::base::unique_fd fd(open(misc_blk_device.c_str(), O_WRONLY | O_SYNC)); - if (fd.get() == -1) { + int fd = (open(misc_blk_device.c_str(), O_WRONLY | O_SYNC)); + if (fd == -1) { + *err = "failed to open " + misc_blk_device + ": "; + *err += strerror(errno); + /* *err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(), strerror(errno)); + */ return false; } - if (lseek(fd.get(), static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) { + if (lseek(fd, static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) { + *err = "failed to lseek " + misc_blk_device + ": "; + *err += strerror(errno); + close(fd); + /* *err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(), strerror(errno)); + */ return false; } - if (!android::base::WriteFully(fd.get(), p, size)) { + if (write(fd, p, size) != size) { + *err = "failed to write " + misc_blk_device + ": "; + *err += strerror(errno); + close(fd); + /* *err = android::base::StringPrintf("failed to write %s: %s", misc_blk_device.c_str(), strerror(errno)); + */ return false; } // TODO: O_SYNC and fsync duplicates each other? - if (fsync(fd.get()) == -1) { + if (fsync(fd) == -1) { + *err = "failed to fsync " + misc_blk_device + ": "; + *err += strerror(errno); + close(fd); + /* *err = android::base::StringPrintf("failed to fsync %s: %s", misc_blk_device.c_str(), strerror(errno)); + */ return false; } + close(fd); return true; } @@ -158,7 +224,7 @@ bool write_bootloader_message(const std::vector<std::string>& options, std::stri strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery)); for (const auto& s : options) { strlcat(boot.recovery, s.c_str(), sizeof(boot.recovery)); - if (s.back() != '\n') { + if (s.substr(s.size() - 1) != "\n") { strlcat(boot.recovery, "\n", sizeof(boot.recovery)); } } @@ -177,5 +243,101 @@ bool write_wipe_package(const std::string& package_data, std::string* err) { extern "C" bool write_bootloader_message(const char* options) { std::string err; - return write_bootloader_message({options}, &err); + bootloader_message boot = {}; + memcpy(&boot, options, sizeof(boot)); + return write_bootloader_message(boot, &err); +} + +static const char *COMMAND_FILE = "/cache/recovery/command"; +static const int MAX_ARG_LENGTH = 4096; +static const int MAX_ARGS = 100; + +// command line args come from, in decreasing precedence: +// - the actual command line +// - the bootloader control block (one per line, after "recovery") +// - the contents of COMMAND_FILE (one per line) +void +get_args(int *argc, char ***argv) { + bootloader_message boot = {}; + std::string err; + if (!read_bootloader_message(&boot, &err)) { + printf("%s\n", err.c_str()); + // If fails, leave a zeroed bootloader_message. + memset(&boot, 0, sizeof(boot)); + } + //stage = strndup(boot.stage, sizeof(boot.stage)); + + if (boot.command[0] != 0 && boot.command[0] != 255) { + printf("Boot command: %.*s\n", (int)sizeof(boot.command), boot.command); + } + + if (boot.status[0] != 0 && boot.status[0] != 255) { + printf("Boot status: %.*s\n", (int)sizeof(boot.status), boot.status); + } + + // --- if arguments weren't supplied, look in the bootloader control block + if (*argc <= 1) { + boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination + const char *arg = strtok(boot.recovery, "\n"); + if (arg != NULL && !strcmp(arg, "recovery")) { + *argv = (char **) malloc(sizeof(char *) * MAX_ARGS); + (*argv)[0] = strdup(arg); + for (*argc = 1; *argc < MAX_ARGS; ++*argc) { + if ((arg = strtok(NULL, "\n")) == NULL) break; + +// if the device does not have an own recovery key combo we just want to open TWRP after +// walking through the factory reset screen - without actually doing a factory reset +#ifdef IGNORE_MISC_WIPE_DATA + if (!strcmp(arg, "--wipe_data")) { + (*argv)[*argc] = ""; + *argc = *argc -1; + printf("Bootloader arg \"%s\" ignored because TWRP was compiled with TW_IGNORE_MISC_WIPE_DATA\n", arg); + continue; + } +#endif + (*argv)[*argc] = strdup(arg); + } + printf("Got arguments from boot message\n"); + } else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) { + printf("Bad boot message\n\"%.20s\"\n", boot.recovery); + } + } + + // --- if that doesn't work, try the command file (if we have /cache). + if (*argc <= 1/* && has_cache*/) { + FILE *fp = fopen(COMMAND_FILE, "r"); + if (fp != NULL) { + char *token; + char *argv0 = (*argv)[0]; + *argv = (char **) malloc(sizeof(char *) * MAX_ARGS); + (*argv)[0] = argv0; // use the same program name + + char buf[MAX_ARG_LENGTH]; + for (*argc = 1; *argc < MAX_ARGS; ++*argc) { + if (!fgets(buf, sizeof(buf), fp)) break; + token = strtok(buf, "\r\n"); + if (token != NULL) { + (*argv)[*argc] = strdup(token); // Strip newline. + } else { + --*argc; + } + } + + fclose(fp); + printf("Got arguments from %s\n", COMMAND_FILE); + } + } + + // --> write the arguments we have back into the bootloader control block + // always boot into recovery after this (until finish_recovery() is called) + strlcpy(boot.command, "boot-recovery", sizeof(boot.command)); + strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery)); + int i; + for (i = 1; i < *argc; ++i) { + strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery)); + strlcat(boot.recovery, "\n", sizeof(boot.recovery)); + } + if (!write_bootloader_message(boot, &err)) { + printf("%s\n", err.c_str()); + } } diff --git a/bootloader_message/include/bootloader_message/bootloader_message.h b/bootloader_message/include/bootloader_message/bootloader_message.h index c63aeca6f..e0fc2cd8a 100644 --- a/bootloader_message/include/bootloader_message/bootloader_message.h +++ b/bootloader_message/include/bootloader_message/bootloader_message.h @@ -25,8 +25,13 @@ // 16K - 64K Used by uncrypt and recovery to store wipe_package for A/B devices // Note that these offsets are admitted by bootloader,recovery and uncrypt, so they // are not configurable without changing all of them. +#ifdef BOARD_RECOVERY_BLDRMSG_OFFSET +static const size_t BOOTLOADER_MESSAGE_OFFSET_IN_MISC = BOARD_RECOVERY_BLDRMSG_OFFSET; +static const size_t WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024 + BOOTLOADER_MESSAGE_OFFSET_IN_MISC; +#else static const size_t BOOTLOADER_MESSAGE_OFFSET_IN_MISC = 0; static const size_t WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024; +#endif /* Bootloader Message * @@ -86,6 +91,8 @@ bool clear_bootloader_message(std::string* err); bool read_wipe_package(std::string* package_data, size_t size, std::string* err); bool write_wipe_package(const std::string& package_data, std::string* err); +void set_misc_device(std::string name); +void get_args(int *argc, char ***argv); #else |