fastboot: implement fastbootd in twrp

fastbootd is a userspace daemon that runs in the recovery
ramdisk. It allows writing single partitions to the super
partition via fastboot CLI. When TWRP sees the fastboot option
in the misc partition during startup, it will start with
the fastbootd page and fastbootd running. Otherwise it will
run recovery normally.

Change-Id: Id7b12d29ef21dbd5950dc884dd1cd788f25357f0
diff --git a/Android.mk b/Android.mk
index f536f1a..56f4926 100755
--- a/Android.mk
+++ b/Android.mk
@@ -68,6 +68,7 @@
     partition.cpp \
     partitionmanager.cpp \
     progresstracking.cpp \
+    startupArgs.cpp \
     twinstall.cpp \
     twrp-functions.cpp \
     twrpDigestDriver.cpp \
@@ -119,7 +120,6 @@
     external/boringssl/include \
     external/libcxx/include \
     external/libselinux/include \
-    $(LOCAL_PATH)/bootloader_message_twrp/include \
     $(LOCAL_PATH)/recovery_ui/include \
     $(LOCAL_PATH)/otautil/include \
     $(LOCAL_PATH)/install/include \
@@ -128,7 +128,7 @@
     $(LOCAL_PATH)/verifier28/
 
 LOCAL_STATIC_LIBRARIES += libguitwrp
-LOCAL_SHARED_LIBRARIES += libz libc libcutils libstdc++ libtar libblkid libminuitwrp libminadbd libmtdutils libtwadbbu libbootloader_message_twrp
+LOCAL_SHARED_LIBRARIES += libz libc libcutils libstdc++ libtar libblkid libminuitwrp libminadbd libmtdutils libtwadbbu libbootloader_message
 LOCAL_SHARED_LIBRARIES += libcrecovery libtwadbbu libtwrpdigest libc++ libaosprecovery libinit libcrypto libbase libziparchive libselinux
 LOCAL_CFLAGS += -DUSE_28_VERIFIER
 
@@ -377,7 +377,7 @@
     mkfs.fat \
     permissive.sh \
     simg2img_twrp \
-    libbootloader_message_twrp \
+    libbootloader_message \
     init.recovery.hlthchrg.rc \
     init.recovery.service.rc \
     init.recovery.ldconfig.rc \
@@ -386,7 +386,8 @@
     awk \
     toybox \
     toolbox \
-    mkshrc_twrp
+    mkshrc_twrp \
+    android.hardware.health@2.0-service
 
 ifneq ($(TW_INCLUDE_CRYPTO),)
 TWRP_REQUIRED_MODULES += \
@@ -558,8 +559,8 @@
 LOCAL_MODULE := libaosprecovery
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := install/adb_install.cpp install/asn1_decoder.cpp install/fuse_sdcard_install.cpp\
-    install/install.cpp install/installcommand.cpp install/legacy_property_service.cpp \
+LOCAL_SRC_FILES := install/adb_install.cpp install/asn1_decoder.cpp install/fuse_sdcard_install.cpp \
+    install/get_args.cpp install/install.cpp install/installcommand.cpp install/legacy_property_service.cpp \
     install/package.cpp install/verifier.cpp install/wipe_data.cpp install/tw_atomic.cpp \
     install/set_metadata.cpp verifier28/verifier.cpp install/zipwrap.cpp install/ZipUtil.cpp
 LOCAL_SHARED_LIBRARIES += libbase libbootloader_message libcrypto libext4_utils \
@@ -607,8 +608,7 @@
     # $(commands_TWRP_local_path)/boot_control/Android.bp 
     # $(commands_TWRP_local_path)/update_verifier/Android.mk
 include \
-    $(commands_TWRP_local_path)/updater/Android.mk \
-    $(commands_TWRP_local_path)/bootloader_message_twrp/Android.mk
+    $(commands_TWRP_local_path)/updater/Android.mk
 
 include $(commands_TWRP_local_path)/mtp/ffs/Android.mk
 
diff --git a/bootloader_message/bootloader_message.cpp b/bootloader_message/bootloader_message.cpp
old mode 100644
new mode 100755
index c1ebeaa..3328233
--- a/bootloader_message/bootloader_message.cpp
+++ b/bootloader_message/bootloader_message.cpp
@@ -46,6 +46,7 @@
   }
   Fstab fstab;
   if (!ReadDefaultFstab(&fstab)) {
+    printf("failed to read default fstab\n");
     *err = "failed to read default fstab";
     return "";
   }
@@ -56,6 +57,7 @@
   }
 
   *err = "failed to find /misc partition";
+  printf("failed to find misc partition\n");
   return "";
 }
 
diff --git a/bootloader_message_twrp/Android.mk b/bootloader_message_twrp/Android.mk
deleted file mode 100644
index 932cd04..0000000
--- a/bootloader_message_twrp/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_CLANG := true
-LOCAL_SRC_FILES := bootloader_message.cpp
-LOCAL_MODULE := libbootloader_message_twrp
-LOCAL_C_INCLUDES += bionic $(LOCAL_PATH)/include
-ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 21; echo $$?),0)
-    LOCAL_C_INCLUDES += external/stlport/stlport
-    LOCAL_SHARED_LIBRARIES += libstlport
-else
-    LOCAL_C_INCLUDES += external/libcxx/include
-    LOCAL_SHARED_LIBRARIES += libc++
-endif
-LOCAL_CFLAGS := -Werror -std=c++11
-# 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
-ifeq ($(BOOTLOADER_MESSAGE_OFFSET),)
-    LOCAL_CFLAGS += -DBOARD_RECOVERY_BLDRMSG_OFFSET=0
-else
-    LOCAL_CFLAGS += -DBOARD_RECOVERY_BLDRMSG_OFFSET=$(BOOTLOADER_MESSAGE_OFFSET)
-endif
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-include $(BUILD_SHARED_LIBRARY)
diff --git a/bootloader_message_twrp/bootloader_message.cpp b/bootloader_message_twrp/bootloader_message.cpp
deleted file mode 100644
index db8c5ce..0000000
--- a/bootloader_message_twrp/bootloader_message.cpp
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * Copyright (C) 2016 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 <bootloader_message_twrp/bootloader_message.h>
-
-#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>
-
-// Spaces used by misc partition are as below:
-// 0   - 2K     For bootloader_message
-// 2K  - 16K    Used by Vendor's bootloader (the 2K - 4K range may be optionally used
-//              as bootloader_message_ab struct)
-// 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.
-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;
-
-static std::string misc_blkdev;
-
-void set_misc_device(const char* name) {
-    misc_blkdev = name;
-}
-
-static std::string get_misc_blk_device(std::string* err) {
-  *err = "";
-  return misc_blkdev;
-}
-
-// 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) {
-  int tries = 0;
-  int ret;
-  err->clear();
-  do {
-    ++tries;
-    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;
-}
-
-static bool read_misc_partition(void* p, size_t size, const std::string& misc_blk_device,
-                                size_t offset, std::string* err) {
-  if (!wait_for_device(misc_blk_device, err)) {
-    return false;
-  }
-
-  int fd(open(misc_blk_device.c_str(), O_RDONLY));
-  if (fd < 0) {
-    *err = "failed to open " + misc_blk_device + ": ";
-    *err += strerror(errno);
-    /*
-  android::base::unique_fd fd(open(misc_blk_device.c_str(), O_RDONLY));
-  if (fd == -1) {
-    *err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
-                                       strerror(errno));
-    */
-    return false;
-  }
-  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 ((size_t)read(fd, p, size) != size) {
-    *err = "failed to read " + misc_blk_device + ": ";
-    *err += strerror(errno);
-    close(fd);
-    /*
-  if (!android::base::ReadFully(fd, p, size)) {
-    *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;
-  }
-  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);
-    /*
-static bool write_misc_partition(const void* p, size_t size, const std::string& misc_blk_device,
-                                 size_t offset, std::string* err) {
-  android::base::unique_fd fd(open(misc_blk_device.c_str(), O_WRONLY));
-  if (fd == -1) {
-    *err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
-                                       strerror(errno));
-    */
-    return false;
-  }
-  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 ((size_t)write(fd, p, size) != size) {
-    *err = "failed to write " + misc_blk_device + ": ";
-    *err += strerror(errno);
-    close(fd);
-    /*
-  if (!android::base::WriteFully(fd, p, size)) {
-    *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) == -1) {
-    *err = "failed to fsync " + misc_blk_device + ": ";
-    *err += strerror(errno);
-    close(fd);
-    /*
-  if (fsync(fd) == -1) {
-    *err = android::base::StringPrintf("failed to fsync %s: %s", misc_blk_device.c_str(),
-                                       strerror(errno));
-    */
-    return false;
-  }
-  close(fd);
-  return true;
-}
-
-bool read_bootloader_message_from(bootloader_message* boot, const std::string& misc_blk_device,
-                                  std::string* err) {
-  return read_misc_partition(boot, sizeof(*boot), misc_blk_device,
-                             BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
-}
-
-bool read_bootloader_message(bootloader_message* boot, std::string* err) {
-  std::string misc_blk_device = get_misc_blk_device(err);
-  if (misc_blk_device.empty()) {
-    return false;
-  }
-  return read_bootloader_message_from(boot, misc_blk_device, err);
-}
-
-bool write_bootloader_message_to(const bootloader_message& boot, __unused const std::string& misc_blk_device,
-                                 std::string* err) {
-  return write_misc_partition(&boot, sizeof(boot),
-                              BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
-}
-
-bool write_bootloader_message(const bootloader_message& boot, std::string* err) {
-  std::string misc_blk_device = get_misc_blk_device(err);
-  if (misc_blk_device.empty()) {
-    return false;
-  }
-  return write_bootloader_message_to(boot, misc_blk_device, err);
-}
-
-// libc++ in 5.1 does not know how to handle a std::string* so this craziness is needed
-bool clear_bootloader_message(void* err) {
-  std::string &s = *(static_cast<std::string*>(err));
-  return clear_bootloader_message(&s);
-}
-
-bool clear_bootloader_message(std::string* err) {
-  bootloader_message boot = {};
-  if (BOOTLOADER_MESSAGE_OFFSET_IN_MISC < sizeof(bootloader_message)) {
-      return write_misc_partition(&boot, sizeof(boot), 0 /* offset */, err);
-  }
-  return write_bootloader_message(boot, err);
-}
-
-bool write_bootloader_message(const std::vector<std::string>& options, std::string* err) {
-  bootloader_message boot = {};
-  strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
-  strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
-  for (const auto& s : options) {
-    strlcat(boot.recovery, s.c_str(), sizeof(boot.recovery));
-    if (s.substr(s.size() - 1) != "\n") {
-      strlcat(boot.recovery, "\n", sizeof(boot.recovery));
-    }
-  }
-  return write_bootloader_message(boot, err);
-}
-
-bool update_bootloader_message(const std::vector<std::string>& options, std::string* err) {
-  bootloader_message boot;
-  if (!read_bootloader_message(&boot, err)) {
-    return false;
-  }
-
-  // Zero out the entire fields.
-  memset(boot.command, 0, sizeof(boot.command));
-  memset(boot.recovery, 0, sizeof(boot.recovery));
-
-  strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
-  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') {
-      strlcat(boot.recovery, "\n", sizeof(boot.recovery));
-    }
-  }
-  return write_bootloader_message(boot, err);
-}
-
-bool write_reboot_bootloader(std::string* err) {
-  bootloader_message boot;
-  if (!read_bootloader_message(&boot, err)) {
-    return false;
-  }
-  if (boot.command[0] != '\0') {
-    *err = "Bootloader command pending.";
-    return false;
-  }
-  strlcpy(boot.command, "bootonce-bootloader", sizeof(boot.command));
-  return write_bootloader_message(boot, err);
-}
-
-bool read_wipe_package(std::string* package_data, size_t size, std::string* err) {
-  std::string misc_blk_device = get_misc_blk_device(err);
-  if (misc_blk_device.empty()) {
-    return false;
-  }
-  package_data->resize(size);
-  return read_misc_partition(&(*package_data)[0], size, misc_blk_device,
-                             WIPE_PACKAGE_OFFSET_IN_MISC, err);
-}
-
-bool write_wipe_package(const std::string& package_data, std::string* err) {
-  std::string misc_blk_device = get_misc_blk_device(err);
-  if (misc_blk_device.empty()) {
-    return false;
-  }
-  return write_misc_partition(package_data.data(), package_data.size(),
-                              WIPE_PACKAGE_OFFSET_IN_MISC, err);
-}
-
-extern "C" bool write_reboot_bootloader(void) {
-  std::string err;
-  return write_reboot_bootloader(&err);
-}
-
-extern "C" bool write_bootloader_message(const char* options) {
-  std::string 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] != (char)255) {
-        printf("Boot command: %.*s\n", (int)sizeof(boot.command), boot.command);
-    }
-
-    if (boot.status[0] != 0 && boot.status[0] != (char)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] = NULL;
-                    *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] != (char)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_twrp/include/bootloader_message_twrp/bootloader_message.h b/bootloader_message_twrp/include/bootloader_message_twrp/bootloader_message.h
deleted file mode 100644
index d8d955e..0000000
--- a/bootloader_message_twrp/include/bootloader_message_twrp/bootloader_message.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _BOOTLOADER_MESSAGE_TWRP_H
-#define _BOOTLOADER_MESSAGE_TWRP_H
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdint.h>
-
-/* Bootloader Message (2-KiB)
- *
- * This structure describes the content of a block in flash
- * that is used for recovery and the bootloader to talk to
- * each other.
- *
- * The command field is updated by linux when it wants to
- * reboot into recovery or to update radio or bootloader firmware.
- * It is also updated by the bootloader when firmware update
- * is complete (to boot into recovery for any final cleanup)
- *
- * The status field was used by the bootloader after the completion
- * of an "update-radio" or "update-hboot" command, which has been
- * deprecated since Froyo.
- *
- * The recovery field is only written by linux and used
- * for the system to send a message to recovery or the
- * other way around.
- *
- * The stage field is written by packages which restart themselves
- * multiple times, so that the UI can reflect which invocation of the
- * package it is.  If the value is of the format "#/#" (eg, "1/3"),
- * the UI will add a simple indicator of that status.
- *
- * We used to have slot_suffix field for A/B boot control metadata in
- * this struct, which gets unintentionally cleared by recovery or
- * uncrypt. Move it into struct bootloader_message_ab to avoid the
- * issue.
- */
-struct bootloader_message {
-    char command[32];
-    char status[32];
-    char recovery[768];
-
-    // The 'recovery' field used to be 1024 bytes.  It has only ever
-    // been used to store the recovery command line, so 768 bytes
-    // should be plenty.  We carve off the last 256 bytes to store the
-    // stage string (for multistage packages) and possible future
-    // expansion.
-    char stage[32];
-
-    // The 'reserved' field used to be 224 bytes when it was initially
-    // carved off from the 1024-byte recovery field. Bump it up to
-    // 1184-byte so that the entire bootloader_message struct rounds up
-    // to 2048-byte.
-    char reserved[1184];
-};
-
-/**
- * We must be cautious when changing the bootloader_message struct size,
- * because A/B-specific fields may end up with different offsets.
- */
-/*#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
-static_assert(sizeof(struct bootloader_message) == 2048,
-              "struct bootloader_message size changes, which may break A/B devices");
-#endif*/
-
-/**
- * The A/B-specific bootloader message structure (4-KiB).
- *
- * We separate A/B boot control metadata from the regular bootloader
- * message struct and keep it here. Everything that's A/B-specific
- * stays after struct bootloader_message, which should be managed by
- * the A/B-bootloader or boot control HAL.
- *
- * The slot_suffix field is used for A/B implementations where the
- * bootloader does not set the androidboot.ro.boot.slot_suffix kernel
- * commandline parameter. This is used by fs_mgr to mount /system and
- * other partitions with the slotselect flag set in fstab. A/B
- * implementations are free to use all 32 bytes and may store private
- * data past the first NUL-byte in this field. It is encouraged, but
- * not mandatory, to use 'struct bootloader_control' described below.
- */
-struct bootloader_message_ab {
-    struct bootloader_message message;
-    char slot_suffix[32];
-
-    // Round up the entire struct to 4096-byte.
-    char reserved[2016];
-};
-
-/**
- * Be cautious about the struct size change, in case we put anything post
- * bootloader_message_ab struct (b/29159185).
- */
-/*#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
-static_assert(sizeof(struct bootloader_message_ab) == 4096,
-              "struct bootloader_message_ab size changes");
-#endif*/
-
-#define BOOT_CTRL_MAGIC   0x42414342 /* Bootloader Control AB */
-#define BOOT_CTRL_VERSION 1
-
-struct slot_metadata {
-    // Slot priority with 15 meaning highest priority, 1 lowest
-    // priority and 0 the slot is unbootable.
-    uint8_t priority : 4;
-    // Number of times left attempting to boot this slot.
-    uint8_t tries_remaining : 3;
-    // 1 if this slot has booted successfully, 0 otherwise.
-    uint8_t successful_boot : 1;
-    // 1 if this slot is corrupted from a dm-verity corruption, 0
-    // otherwise.
-    uint8_t verity_corrupted : 1;
-    // Reserved for further use.
-    uint8_t reserved : 7;
-} __attribute__((packed));
-
-/* Bootloader Control AB
- *
- * This struct can be used to manage A/B metadata. It is designed to
- * be put in the 'slot_suffix' field of the 'bootloader_message'
- * structure described above. It is encouraged to use the
- * 'bootloader_control' structure to store the A/B metadata, but not
- * mandatory.
- */
-struct bootloader_control {
-    // NUL terminated active slot suffix.
-    char slot_suffix[4];
-    // Bootloader Control AB magic number (see BOOT_CTRL_MAGIC).
-    uint32_t magic;
-    // Version of struct being used (see BOOT_CTRL_VERSION).
-    uint8_t version;
-    // Number of slots being managed.
-    uint8_t nb_slot : 3;
-    // Number of times left attempting to boot recovery.
-    uint8_t recovery_tries_remaining : 3;
-    // Ensure 4-bytes alignment for slot_info field.
-    uint8_t reserved0[2];
-    // Per-slot information.  Up to 4 slots.
-    struct slot_metadata slot_info[4];
-    // Reserved for further use.
-    uint8_t reserved1[8];
-    // CRC32 of all 28 bytes preceding this field (little endian
-    // format).
-    uint32_t crc32_le;
-} __attribute__((packed));
-
-/*#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
-static_assert(sizeof(struct bootloader_control) ==
-              sizeof(((struct bootloader_message_ab *)0)->slot_suffix),
-              "struct bootloader_control has wrong size");
-#endif*/
-
-#ifdef __cplusplus
-
-#include <string.h>
-#include <vector>
-
-// Read bootloader message into boot. Error message will be set in err.
-bool read_bootloader_message(bootloader_message* boot, std::string* err);
-
-// Read bootloader message from the specified misc device into boot.
-bool read_bootloader_message_from(bootloader_message* boot, const std::string& misc_blk_device,
-                                  std::string* err);
-
-// Write bootloader message to BCB.
-bool write_bootloader_message(const bootloader_message& boot, std::string* err);
-
-// Write bootloader message to the specified BCB device.
-bool write_bootloader_message_to(const bootloader_message& boot,
-                                 const std::string& misc_blk_device, std::string* err);
-
-// Write bootloader message (boots into recovery with the options) to BCB. Will
-// set the command and recovery fields, and reset the rest.
-bool write_bootloader_message(const std::vector<std::string>& options, std::string* err);
-
-// Update bootloader message (boots into recovery with the options) to BCB. Will
-// only update the command and recovery fields.
-bool update_bootloader_message(const std::vector<std::string>& options, std::string* err);
-
-// Clear BCB.
-bool clear_bootloader_message(void* err);
-bool clear_bootloader_message(std::string* err);
-
-// Writes the reboot-bootloader reboot reason to the bootloader_message.
-bool write_reboot_bootloader(std::string* err);
-
-// Read the wipe package from BCB (from offset WIPE_PACKAGE_OFFSET_IN_MISC).
-bool read_wipe_package(std::string* package_data, size_t size, std::string* err);
-
-void set_misc_device(const char* name);
-void get_args(int *argc, char ***argv);
-
-// Write the wipe package into BCB (to offset WIPE_PACKAGE_OFFSET_IN_MISC).
-bool write_wipe_package(const std::string& package_data, std::string* err);
-
-#else
-
-#include <stdbool.h>
-
-// C Interface.
-bool write_bootloader_message(const char* options);
-bool write_reboot_bootloader(void);
-
-#endif  // ifdef __cplusplus
-
-#endif  // _BOOTLOADER_MESSAGE_TWRP_H
diff --git a/data.cpp b/data.cpp
index a13fbe7..571def6 100755
--- a/data.cpp
+++ b/data.cpp
@@ -717,6 +717,10 @@
 	printf("TW_HAS_EDL_MODE := true\n");
 	mConst.SetValue(TW_EDL_MODE, "1");
 #endif
+#ifdef PRODUCT_USE_DYNAMIC_PARTITIONS
+	printf("PRODUCT_USE_DYNAMIC_PARTITIONS := true\n");
+	mConst.SetValue(TW_FASTBOOT_MODE, "1");
+#endif
 #ifdef TW_INCLUDE_CRYPTO
 	mConst.SetValue(TW_HAS_CRYPTO, "1");
 	printf("TW_INCLUDE_CRYPTO := true\n");
@@ -792,6 +796,7 @@
 	mData.SetValue("tw_encrypt_backup", "0");
 	mData.SetValue("tw_sleep_total", "5");
 	mData.SetValue("tw_sleep", "5");
+	mData.SetValue("tw_enable_fastboot", "0");
 
 	// Brightness handling
 	string findbright;
diff --git a/gui/action.cpp b/gui/action.cpp
index 5e842d5..19c3d09 100755
--- a/gui/action.cpp
+++ b/gui/action.cpp
@@ -33,6 +33,7 @@
 #include <sys/wait.h>
 #include <dirent.h>
 #include <private/android_filesystem_config.h>
+#include <android-base/properties.h>
 
 #include <string>
 #include <sstream>
@@ -201,6 +202,8 @@
 		ADD_ACTION(setlanguage);
 		ADD_ACTION(checkforapp);
 		ADD_ACTION(togglebacklight);
+		ADD_ACTION(enableadb);
+		ADD_ACTION(enablefastboot);
 
 		// remember actions that run in the caller thread
 		for (mapFunc::const_iterator it = mf.begin(); it != mf.end(); ++it)
@@ -2242,3 +2245,16 @@
 	operation_end(op_status);
 	return 0;
 }
+
+
+int GUIAction::enableadb(std::string arg __unused) {
+	android::base::SetProperty("sys.usb.config", "none");
+	android::base::SetProperty("sys.usb.config", "adb");
+	return 0;
+}
+
+int GUIAction::enablefastboot(std::string arg __unused) {
+	android::base::SetProperty("sys.usb.config", "none");
+	android::base::SetProperty("sys.usb.config", "fastboot");
+	return 0;
+}
diff --git a/gui/console.cpp b/gui/console.cpp
old mode 100644
new mode 100755
index 03628ec..77fdd96
--- a/gui/console.cpp
+++ b/gui/console.cpp
@@ -1,5 +1,5 @@
 /*
-	Copyright 2015 bigbiff/Dees_Troy TeamWin
+	Copyright 2012 - 2020 TeamWin
 	This file is part of TWRP/TeamWin Recovery Project.
 
 	TWRP is free software: you can redistribute it and/or modify
diff --git a/gui/gui.cpp b/gui/gui.cpp
index 4628650..2a36fec 100755
--- a/gui/gui.cpp
+++ b/gui/gui.cpp
@@ -650,8 +650,9 @@
 			gui_changePage("main");
 			break;
 		}
-		if (DataManager::GetIntValue("tw_gui_done") != 0)
+		if (DataManager::GetIntValue("tw_gui_done") != 0) {
 			break;
+		}
 	}
 	if (ors_read_fd > 0)
 		close(ors_read_fd);
diff --git a/gui/objects.hpp b/gui/objects.hpp
old mode 100644
new mode 100755
index 24e9d24..ccfc522
--- a/gui/objects.hpp
+++ b/gui/objects.hpp
@@ -371,7 +371,8 @@
 	int uninstalltwrpsystemapp(std::string arg);
 	int repackimage(std::string arg);
 	int fixabrecoverybootloop(std::string arg);
-
+	int enableadb(std::string arg);
+	int enablefastboot(std::string arg);
 	int simulate;
 };
 
diff --git a/gui/theme/common/landscape.xml b/gui/theme/common/landscape.xml
index 67c8f91..3fbac9e 100755
--- a/gui/theme/common/landscape.xml
+++ b/gui/theme/common/landscape.xml
@@ -2639,6 +2639,133 @@
 			</action>
 		</page>
 
+		<page name="fastbootreboot">
+			<template name="page"/>
+
+			<text style="text_l">
+				<placement x="%col1_x_header%" y="%row3_header_y%"/>
+				<text>{@reboot_hdr=Reboot}</text>
+			</text>
+
+			<listbox style="advanced_listbox">
+				<placement x="%col1_x_left%" y="%row2_y%" w="%content_width%" h="%listbox_advanced_height%"/>
+
+				<listitem name="{@rb_system_btn=System}">
+					<condition var1="tw_reboot_system" var2="1"/>
+					<actions>
+						<action function="set">tw_back=fastbootreboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=system</action>
+						<action function="set">tw_reboot_param=system</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">confirm_action</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@rb_poweroff_btn=Power Off}">
+					<condition var1="tw_reboot_poweroff" var2="1"/>
+					<actions>
+						<action function="set">tw_back=fastbootreboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=poweroff</action>
+						<action function="set">tw_reboot_param=poweroff</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_action_text1={@turning_off=Turning Off...}</action>
+						<action function="set">tw_complete_text1={@turning_off=Turning Off...}</action>
+						<action function="set">tw_slider_text={@swipe_power_off=Swipe to Power Off}</action>
+						<action function="page">confirm_action</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@rb_recovery_btn=Recovery}">
+					<condition var1="tw_reboot_recovery" var2="1"/>
+					<actions>
+						<action function="set">tw_back=fastbootreboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=recovery</action>
+						<action function="set">tw_reboot_param=recovery</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">confirm_action</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@rb_bootloader_btn=Bootloader}">
+					<condition var1="tw_reboot_bootloader" var2="1"/>
+					<actions>
+						<action function="set">tw_back=fastbootreboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=bootloader</action>
+						<action function="set">tw_reboot_param=bootloader</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">confirm_action</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@rb_download_btn=Download}">
+					<condition var1="tw_download_mode" var2="1"/>
+					<actions>
+						<action function="set">tw_back=fastbootreboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=download</action>
+						<action function="set">tw_reboot_param=download</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">confirm_action</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@fastboot_button=Fastboot}">
+					<condition var1="tw_fastboot_mode" var2="1"/>
+					<actions>
+						<action function="set">tw_back=fastbootreboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=fastboot</action>
+						<action function="set">tw_reboot_param=fastboot</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">confirm_action</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@rb_edl_btn=Edl}">
+					<condition var1="tw_edl_mode" var2="1"/>
+					<actions>
+						<action function="set">tw_back=fastbootreboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=edl</action>
+						<action function="set">tw_reboot_param=edl</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">confirm_action</action>
+					</actions>
+				</listitem>
+			</listbox>
+			<action>
+				<touch key="home"/>
+				<action function="page">fastboot</action>
+			</action>
+
+			<action>
+				<touch key="back"/>
+				<action function="page">fastboot</action>
+			</action>
+		</page>
+
 		<page name="reboot">
 			<template name="page"/>
 
@@ -2647,108 +2774,156 @@
 				<text>{@reboot_hdr=Reboot}</text>
 			</text>
 
+			<listbox style="advanced_listbox">
+				<placement x="%col1_x_left%" y="%row2_y%" w="%content_width%" h="%listbox_advanced_height%"/>
+
+				<listitem name="{@rb_system_btn=System}">
+					<condition var1="tw_reboot_system" var2="1"/>
+					<actions>
+						<action function="set">tw_back=reboot</action>
+						<action function="page">reboot_system_routine</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@rb_poweroff_btn=Power Off}">
+					<condition var1="tw_reboot_poweroff" var2="1"/>
+					<actions>
+						<action function="set">tw_back=reboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=poweroff</action>
+						<action function="set">tw_reboot_param=poweroff</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
+						<action function="set">tw_text2={@no_ospo=sure you wish to power off?}</action>
+						<action function="set">tw_action_text1={@turning_off=Turning Off...}</action>
+						<action function="set">tw_complete_text1={@turning_off=Turning Off...}</action>
+						<action function="set">tw_slider_text={@swipe_power_off=Swipe to Power Off}</action>
+						<action function="page">rebootcheck</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@rb_recovery_btn=Recovery}">
+					<condition var1="tw_reboot_recovery" var2="1"/>
+					<actions>
+						<action function="set">tw_back=reboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=recovery</action>
+						<action function="set">tw_reboot_param=recovery</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
+						<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">rebootcheck</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@rb_bootloader_btn=Bootloader}">
+					<condition var1="tw_reboot_bootloader" var2="1"/>
+					<actions>
+						<action function="set">tw_back=reboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=bootloader</action>
+						<action function="set">tw_reboot_param=bootloader</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
+						<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">rebootcheck</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@rb_download_btn=Download}">
+					<condition var1="tw_download_mode" var2="1"/>
+					<actions>
+						<action function="set">tw_back=reboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=download</action>
+						<action function="set">tw_reboot_param=download</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
+						<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">rebootcheck</action>
+					</actions>
+				</listitem>
+
+
+				<listitem name="{@fastboot_button=Fastboot}">
+					<condition var1="tw_fastboot_mode" var2="1"/>
+					<actions>
+						<action function="set">tw_back=reboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=fastboot</action>
+						<action function="set">tw_reboot_param=fastboot</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
+						<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">rebootcheck</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@rb_edl_btn=Edl}">
+					<condition var1="tw_edl_mode" var2="1"/>
+					<actions>
+						<action function="set">tw_back=reboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=edl</action>
+						<action function="set">tw_reboot_param=edl</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
+						<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">rebootcheck</action>
+					</actions>
+				</button>
+			</listbox>
+
+			<text style="text_m">
+				<condition var1="tw_has_boot_slots" var2="1"/>
+				<placement x="%center_x%" y="%row14_y%" placement="5"/>
+				<text>{@current_boot_slot=Current Slot: %tw_active_slot%}</text>
+			</text>
+
 			<button style="main_button">
-				<condition var1="tw_reboot_system" var2="1"/>
-				<placement x="%col1_x_left%" y="%row2_y%"/>
-				<text>{@rb_system_btn=System}</text>
+				<condition var1="tw_has_boot_slots" var2="1"/>
+				<placement x="%indent%" y="%row16_y%"/>
+				<text>{@boot_slot_a=Slot A}</text>
 				<actions>
 					<action function="set">tw_back=reboot</action>
-					<action function="page">reboot_system_routine</action>
+					<action function="set">tw_action=setbootslot</action>
+					<action function="set">tw_action_param=A</action>
+					<action function="set">tw_has_action2=0</action>
+					<action function="set">tw_action_text1={@changing_boot_slot=Changing Boot Slot}</action>
+					<action function="set">tw_action_text2=</action>
+					<action function="set">tw_complete_text1={@changing_boot_slot_complete=Change Boot Slot Complete}</action>
+					<action function="page">action_page</action>
 				</actions>
 			</button>
 
 			<button style="main_button">
-				<condition var1="tw_reboot_poweroff" var2="1"/>
-				<placement x="%center_x%" y="%row2_y%"/>
-				<text>{@rb_poweroff_btn=Power Off}</text>
+				<condition var1="tw_has_boot_slots" var2="1"/>
+				<placement x="%center_x%" y="%row16_y%"/>
+				<text>{@boot_slot_b=Slot B}</text>
 				<actions>
 					<action function="set">tw_back=reboot</action>
-					<action function="set">tw_action=reboot</action>
-					<action function="set">tw_action_param=poweroff</action>
-					<action function="set">tw_reboot_param=poweroff</action>
+					<action function="set">tw_action=setbootslot</action>
+					<action function="set">tw_action_param=B</action>
 					<action function="set">tw_has_action2=0</action>
-					<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
-					<action function="set">tw_text2={@no_ospo=sure you wish to power off?}</action>
-					<action function="set">tw_action_text1={@turning_off=Turning Off...}</action>
-					<action function="set">tw_complete_text1={@turning_off=Turning Off...}</action>
-					<action function="set">tw_slider_text={@swipe_power_off=Swipe to Power Off}</action>
-					<action function="page">rebootcheck</action>
-				</actions>
-			</button>
-
-			<button style="main_button">
-				<condition var1="tw_reboot_recovery" var2="1"/>
-				<placement x="%col1_x_left%" y="%row6a_y%"/>
-				<text>{@rb_recovery_btn=Recovery}</text>
-				<actions>
-					<action function="set">tw_back=reboot</action>
-					<action function="set">tw_action=reboot</action>
-					<action function="set">tw_action_param=recovery</action>
-					<action function="set">tw_reboot_param=recovery</action>
-					<action function="set">tw_has_action2=0</action>
-					<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
-					<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
-					<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
-					<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
-					<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
-					<action function="page">rebootcheck</action>
-				</actions>
-			</button>
-
-			<button style="main_button">
-				<condition var1="tw_reboot_bootloader" var2="1"/>
-				<placement x="%center_x%" y="%row6a_y%"/>
-				<text>{@rb_bootloader_btn=Bootloader}</text>
-				<actions>
-					<action function="set">tw_back=reboot</action>
-					<action function="set">tw_action=reboot</action>
-					<action function="set">tw_action_param=bootloader</action>
-					<action function="set">tw_reboot_param=bootloader</action>
-					<action function="set">tw_has_action2=0</action>
-					<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
-					<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
-					<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
-					<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
-					<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
-					<action function="page">rebootcheck</action>
-				</actions>
-			</button>
-
-			<button style="main_button">
-				<condition var1="tw_download_mode" var2="1"/>
-				<placement x="%col1_x_left%" y="%row11_y%"/>
-				<text>{@rb_download_btn=Download}</text>
-				<actions>
-					<action function="set">tw_back=reboot</action>
-					<action function="set">tw_action=reboot</action>
-					<action function="set">tw_action_param=download</action>
-					<action function="set">tw_reboot_param=download</action>
-					<action function="set">tw_has_action2=0</action>
-					<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
-					<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
-					<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
-					<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
-					<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
-					<action function="page">rebootcheck</action>
-				</actions>
-			</button>
-
-			<button style="main_button">
-				<condition var1="tw_edl_mode" var2="1"/>
-				<placement x="%center_x%" y="%row11_y%"/>
-				<text>{@rb_edl_btn=Edl}</text>
-				<actions>
-					<action function="set">tw_back=reboot</action>
-					<action function="set">tw_action=reboot</action>
-					<action function="set">tw_action_param=edl</action>
-					<action function="set">tw_reboot_param=edl</action>
-					<action function="set">tw_has_action2=0</action>
-					<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
-					<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
-					<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
-					<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
-					<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
-					<action function="page">rebootcheck</action>
+					<action function="set">tw_action_text1={@changing_boot_slot=Changing Boot Slot}</action>
+					<action function="set">tw_action_text2=</action>
+					<action function="set">tw_complete_text1={@changing_boot_slot_complete=Change Boot Slot Complete}</action>
+					<action function="page">action_page</action>
 				</actions>
 			</button>
 
@@ -4868,6 +5043,47 @@
 				<action function="screenshot" />
 			</object>
 		</page>
+	
+		<page name="fastboot">
+			<template name="page"/>
+
+			<text style="text_l">
+				<placement x="%col1_x_header%" y="%row3_header_y%"/>
+				<text>{@fastboot_button=Fastboot}</text>
+			</text>
+
+			<template name="console"/>
+
+			<template name="progress_bar"/>
+
+			<button style="main_button_half_width">
+				<condition var1="tw_enable_fastboot" op="=" var2="1" />
+				<placement x="%col2_x_right%" y="%row15a_y%"/>
+				<text>{@enable_adb=Enable ADB}</text>
+				<actions>
+					<action function="enableadb"/>
+					<action function="set">tw_enable_adb=1</action>
+					<action function="set">tw_enable_fastboot=0</action>
+				</actions>
+			</button>
+
+			<button style="main_button_half_width">
+				<condition var1="tw_enable_adb" op="=" var2="1" />
+				<placement x="%col2_x_right%" y="%row15a_y%"/>
+				<text>{@enable_fastboot=Enable Fastboot}</text>
+				<actions>
+					<action function="enablefastboot"/>
+					<action function="set">tw_enable_fastboot=1</action>
+					<action function="set">tw_enable_adb=0</action>
+				</actions>
+			</button>
+
+			<button style="main_button_half_width">
+				<placement x="%col3_x_right%" y="%row15a_y%"/>
+				<text>{@reboot_btn=Reboot}</text>
+				<action function="page">fastbootreboot</action>
+			</button>
+		</page>
 
 		<page name="sideload">
 			<template name="page"/>
diff --git a/gui/theme/common/languages/en.xml b/gui/theme/common/languages/en.xml
index 7982a3b..fa8058a 100755
--- a/gui/theme/common/languages/en.xml
+++ b/gui/theme/common/languages/en.xml
@@ -727,5 +727,9 @@
 		<string name="ozip_decrypt_decryption">Starting Ozip Decryption...</string>
 		<string name="ozip_decrypt_finish">Ozip Decryption Finished!</string>
 		<string name="fbe_wipe_msg">WARNING: {1} wiped. FBE device should be booted into Android and not Recovery to set initial FBE policy after wipe.</string>
+		<string name="fastboot_button">Fastboot</string>
+		<string name="enable_adb">Enable ADB</string>
+		<string name="enable_fastboot">Enable Fastboot</string>
+		<string name="fastboot_console_msg">Entered Fastboot mode...</string>
 	</resources>
 </language>
diff --git a/gui/theme/common/portrait.xml b/gui/theme/common/portrait.xml
index 31aef46..3960faf 100755
--- a/gui/theme/common/portrait.xml
+++ b/gui/theme/common/portrait.xml
@@ -2795,6 +2795,134 @@
 			</action>
 		</page>
 
+		<page name="fastbootreboot">
+			<template name="page"/>
+
+			<text style="text_l">
+				<placement x="%col1_x_header%" y="%row3_header_y%"/>
+				<text>{@reboot_hdr=Reboot}</text>
+			</text>
+
+			<listbox style="advanced_listbox">
+				<placement x="%indent%" y="%row2a_y%" w="%content_width%" h="%listbox_advanced_height%"/>
+
+				<listitem name="{@rb_system_btn=System}">
+					<condition var1="tw_reboot_system" var2="1"/>
+					<actions>
+						<action function="set">tw_back=fastbootreboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=system</action>
+						<action function="set">tw_reboot_param=system</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">confirm_action</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@rb_poweroff_btn=Power Off}">
+					<condition var1="tw_reboot_poweroff" var2="1"/>
+					<actions>
+						<action function="set">tw_back=fastbootreboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=poweroff</action>
+						<action function="set">tw_reboot_param=poweroff</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_action_text1={@turning_off=Turning Off...}</action>
+						<action function="set">tw_complete_text1={@turning_off=Turning Off...}</action>
+						<action function="set">tw_slider_text={@swipe_power_off=Swipe to Power Off}</action>
+						<action function="page">confirm_action</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@rb_recovery_btn=Recovery}">
+					<condition var1="tw_reboot_recovery" var2="1"/>
+					<actions>
+						<action function="set">tw_back=fastbootreboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=recovery</action>
+						<action function="set">tw_reboot_param=recovery</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">confirm_action</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@rb_bootloader_btn=Bootloader}">
+					<condition var1="tw_reboot_bootloader" var2="1"/>
+					<actions>
+						<action function="set">tw_back=fastbootreboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=bootloader</action>
+						<action function="set">tw_reboot_param=bootloader</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">confirm_action</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@rb_download_btn=Download}">
+					<condition var1="tw_download_mode" var2="1"/>
+					<actions>
+						<action function="set">tw_back=fastbootreboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=download</action>
+						<action function="set">tw_reboot_param=download</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">confirm_action</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@fastboot_button=Fastboot}">
+					<condition var1="tw_fastboot_mode" var2="1"/>
+					<actions>
+						<action function="set">tw_back=fastbootreboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=fastboot</action>
+						<action function="set">tw_reboot_param=fastboot</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">confirm_action</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@rb_edl_btn=Edl}">
+					<condition var1="tw_edl_mode" var2="1"/>
+					<actions>
+						<action function="set">tw_back=fastbootreboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=edl</action>
+						<action function="set">tw_reboot_param=edl</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">confirm_action</action>
+					</actions>
+				</listitem>
+			</listbox>
+
+			<action>
+				<touch key="home"/>
+				<action function="page">fastboot</action>
+			</action>
+
+			<action>
+				<touch key="back"/>
+				<action function="page">fastboot</action>
+			</action>
+		</page>
+
 		<page name="reboot">
 			<template name="page"/>
 
@@ -2803,118 +2931,127 @@
 				<text>{@reboot_hdr=Reboot}</text>
 			</text>
 
-			<button style="main_button">
-				<condition var1="tw_reboot_system" var2="1"/>
-				<placement x="%indent%" y="%row2a_y%"/>
-				<text>{@rb_system_btn=System}</text>
-				<actions>
-					<action function="set">tw_back=reboot</action>
-					<action function="page">reboot_system_routine</action>
-				</actions>
-			</button>
+			<listbox style="advanced_listbox">
+				<placement x="%indent%" y="%row2a_y%" w="%content_width%" h="%listbox_advanced_height%"/>
 
-			<button style="main_button">
-				<condition var1="tw_reboot_poweroff" var2="1"/>
-				<placement x="%center_x%" y="%row2a_y%"/>
-				<text>{@rb_poweroff_btn=Power Off}</text>
-				<actions>
-					<action function="set">tw_back=reboot</action>
-					<action function="set">tw_action=reboot</action>
-					<action function="set">tw_action_param=poweroff</action>
-					<action function="set">tw_reboot_param=poweroff</action>
-					<action function="set">tw_has_action2=0</action>
-					<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
-					<action function="set">tw_text2={@no_ospo=sure you wish to power off?}</action>
-					<action function="set">tw_action_text1={@turning_off=Turning Off...}</action>
-					<action function="set">tw_complete_text1={@turning_off=Turning Off...}</action>
-					<action function="set">tw_slider_text={@swipe_power_off=Swipe to Power Off}</action>
-					<action function="page">rebootcheck</action>
-				</actions>
-			</button>
+				<listitem name="{@rb_system_btn=System}">
+					<condition var1="tw_reboot_system" var2="1"/>
+					<actions>
+						<action function="set">tw_back=reboot</action>
+						<action function="page">reboot_system_routine</action>
+					</actions>
+				</listitem>
 
-			<button style="main_button">
-				<condition var1="tw_reboot_recovery" var2="1"/>
-				<placement x="%indent%" y="%row8_y%"/>
-				<text>{@rb_recovery_btn=Recovery}</text>
-				<actions>
-					<action function="set">tw_back=reboot</action>
-					<action function="set">tw_action=reboot</action>
-					<action function="set">tw_action_param=recovery</action>
-					<action function="set">tw_reboot_param=recovery</action>
-					<action function="set">tw_has_action2=0</action>
-					<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
-					<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
-					<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
-					<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
-					<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
-					<action function="page">rebootcheck</action>
-				</actions>
-			</button>
+				<listitem name="{@rb_poweroff_btn=Power Off}">
+					<condition var1="tw_reboot_poweroff" var2="1"/>
+					<actions>
+						<action function="set">tw_back=reboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=poweroff</action>
+						<action function="set">tw_reboot_param=poweroff</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
+						<action function="set">tw_text2={@no_ospo=sure you wish to power off?}</action>
+						<action function="set">tw_action_text1={@turning_off=Turning Off...}</action>
+						<action function="set">tw_complete_text1={@turning_off=Turning Off...}</action>
+						<action function="set">tw_slider_text={@swipe_power_off=Swipe to Power Off}</action>
+						<action function="page">rebootcheck</action>
+					</actions>
+				</listitem>
 
-			<button style="main_button">
-				<condition var1="tw_reboot_bootloader" var2="1"/>
-				<placement x="%center_x%" y="%row8_y%"/>
-				<text>{@rb_bootloader_btn=Bootloader}</text>
-				<actions>
-					<action function="set">tw_back=reboot</action>
-					<action function="set">tw_action=reboot</action>
-					<action function="set">tw_action_param=bootloader</action>
-					<action function="set">tw_reboot_param=bootloader</action>
-					<action function="set">tw_has_action2=0</action>
-					<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
-					<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
-					<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
-					<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
-					<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
-					<action function="page">rebootcheck</action>
-				</actions>
-			</button>
+				<listitem name="{@rb_recovery_btn=Recovery}">
+					<condition var1="tw_reboot_recovery" var2="1"/>
+					<actions>
+						<action function="set">tw_back=reboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=recovery</action>
+						<action function="set">tw_reboot_param=recovery</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
+						<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">rebootcheck</action>
+					</actions>
+				</listitem>
 
-			<button style="main_button">
-				<condition var1="tw_download_mode" var2="1"/>
-				<placement x="%indent%" y="%row13a_y%"/>
-				<text>{@rb_download_btn=Download}</text>
-				<actions>
-					<action function="set">tw_back=reboot</action>
-					<action function="set">tw_action=reboot</action>
-					<action function="set">tw_action_param=download</action>
-					<action function="set">tw_reboot_param=download</action>
-					<action function="set">tw_has_action2=0</action>
-					<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
-					<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
-					<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
-					<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
-					<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
-					<action function="page">rebootcheck</action>
-				</actions>
-			</button>
+				<listitem name="{@rb_bootloader_btn=Bootloader}">
+					<condition var1="tw_reboot_bootloader" var2="1"/>
+					<actions>
+						<action function="set">tw_back=reboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=bootloader</action>
+						<action function="set">tw_reboot_param=bootloader</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
+						<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">rebootcheck</action>
+					</actions>
+				</listitem>
 
-			<button style="main_button">
-				<condition var1="tw_edl_mode" var2="1"/>
-				<placement x="%center_x%" y="%row13a_y%"/>
-				<text>{@rb_edl_btn=Edl}</text>
-				<actions>
-					<action function="set">tw_back=reboot</action>
-					<action function="set">tw_action=reboot</action>
-					<action function="set">tw_action_param=edl</action>
-					<action function="set">tw_reboot_param=edl</action>
-					<action function="set">tw_has_action2=0</action>
-					<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
-					<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
-					<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
-					<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
-					<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
-					<action function="page">rebootcheck</action>
-				</actions>
-			</button>
+				<listitem name="{@rb_download_btn=Download}">
+					<condition var1="tw_download_mode" var2="1"/>
+					<actions>
+						<action function="set">tw_back=reboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=download</action>
+						<action function="set">tw_reboot_param=download</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
+						<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">rebootcheck</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@fastboot_button=Fastboot}">
+					<condition var1="tw_fastboot_mode" var2="1"/>
+					<actions>
+						<action function="set">tw_back=reboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=fastboot</action>
+						<action function="set">tw_reboot_param=fastboot</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
+						<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">rebootcheck</action>
+					</actions>
+				</listitem>
+
+				<listitem name="{@rb_edl_btn=Edl}">
+					<condition var1="tw_edl_mode" var2="1"/>
+					<actions>
+						<action function="set">tw_back=reboot</action>
+						<action function="set">tw_action=reboot</action>
+						<action function="set">tw_action_param=edl</action>
+						<action function="set">tw_reboot_param=edl</action>
+						<action function="set">tw_has_action2=0</action>
+						<action function="set">tw_text1={@no_os1=No OS Installed! Are you}</action>
+						<action function="set">tw_text2={@no_osrb=sure you wish to reboot?}</action>
+						<action function="set">tw_action_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_complete_text1={@rebooting=Rebooting...}</action>
+						<action function="set">tw_slider_text={@swipe_reboot=Swipe to Reboot}</action>
+						<action function="page">rebootcheck</action>
+					</actions>
+				</button>
+			</listbox>
 
 			<text style="text_m">
 				<condition var1="tw_has_boot_slots" var2="1"/>
-				<placement x="%center_x%" y="%row18_y%" placement="5"/>
+				<placement x="%center_x%" y="%row15_y%" placement="5"/>
 				<text>{@current_boot_slot=Current Slot: %tw_active_slot%}</text>
 			</text>
 
-			<button style="main_button">
+			<button style="main_button_half_height">
 				<condition var1="tw_has_boot_slots" var2="1"/>
 				<placement x="%indent%" y="%row19_y%"/>
 				<text>{@boot_slot_a=Slot A}</text>
@@ -2930,7 +3067,7 @@
 				</actions>
 			</button>
 
-			<button style="main_button">
+			<button style="main_button_half_height">
 				<condition var1="tw_has_boot_slots" var2="1"/>
 				<placement x="%center_x%" y="%row19_y%"/>
 				<text>{@boot_slot_b=Slot B}</text>
@@ -4851,6 +4988,47 @@
 			</action>
 		</page>
 
+		<page name="fastboot">
+			<template name="page"/>
+
+			<text style="text_l">
+				<placement x="%col1_x_header%" y="%row3_header_y%"/>
+				<text>{@fastboot_button=Fastboot}</text>
+			</text>
+
+			<template name="console"/>
+
+			<template name="progress_bar"/>
+
+			<button style="main_button_half_height">
+				<condition var1="tw_enable_fastboot" op="=" var2="1" />
+				<placement x="%indent%" y="%row21a_y%"/>
+				<text>{@enable_adb=Enable ADB}</text>
+				<actions>
+					<action function="enableadb"/>
+					<action function="set">tw_enable_adb=1</action>
+					<action function="set">tw_enable_fastboot=0</action>
+				</actions>
+			</button>
+
+			<button style="main_button_half_height">
+				<condition var1="tw_enable_adb" op="=" var2="1" />
+				<placement x="%indent%" y="%row21a_y%"/>
+				<text>{@enable_fastboot=Enable Fastboot}</text>
+				<actions>
+					<action function="enablefastboot"/>
+					<action function="set">tw_enable_fastboot=1</action>
+					<action function="set">tw_enable_adb=0</action>
+				</actions>
+			</button>
+
+			<button style="main_button_half_height">
+				<placement x="%center_x%" y="%row21a_y%"/>
+				<text>{@reboot_btn=Reboot}</text>
+				<action function="page">fastbootreboot</action>
+			</button>
+		</page>
+
 		<page name="sideload">
 			<template name="page"/>
 
diff --git a/gui/theme/landscape_hdpi/ui.xml b/gui/theme/landscape_hdpi/ui.xml
index 6e746a0..45aa82b 100755
--- a/gui/theme/landscape_hdpi/ui.xml
+++ b/gui/theme/landscape_hdpi/ui.xml
@@ -6,7 +6,7 @@
 		<title>Backup Naowz</title>
 		<description>Default basic theme</description>
 		<preview>preview.png</preview>
-		<themeversion>3</themeversion>
+		<themeversion>4</themeversion>
 	</details>
 
 	<include>
@@ -198,6 +198,7 @@
 		<variable name="partitionlist_backup_height" value="528"/>
 		<variable name="listbox_timezone_height" value="768"/>
 		<variable name="listbox_settings_height" value="648"/>
+		<variable name="listbox_advanced_height" value="700"/>
 		<variable name="fastscroll_w" value="18"/>
 		<variable name="fastscroll_linew" value="2"/>
 		<variable name="fastscroll_rectw" value="18"/>
diff --git a/gui/theme/landscape_mdpi/ui.xml b/gui/theme/landscape_mdpi/ui.xml
index 24458ec..8b7b6d3 100755
--- a/gui/theme/landscape_mdpi/ui.xml
+++ b/gui/theme/landscape_mdpi/ui.xml
@@ -6,7 +6,7 @@
 		<title>Backup Naowz</title>
 		<description>Default basic theme</description>
 		<preview>preview.png</preview>
-		<themeversion>3</themeversion>
+		<themeversion>4</themeversion>
 	</details>
 
 	<include>
@@ -198,6 +198,7 @@
 		<variable name="partitionlist_backup_height" value="198"/>
 		<variable name="listbox_timezone_height" value="306"/>
 		<variable name="listbox_settings_height" value="243"/>
+		<variable name="listbox_advanced_height" value="300"/>
 		<variable name="fastscroll_w" value="7"/>
 		<variable name="fastscroll_linew" value="1"/>
 		<variable name="fastscroll_rectw" value="7"/>
diff --git a/gui/theme/portrait_hdpi/ui.xml b/gui/theme/portrait_hdpi/ui.xml
old mode 100644
new mode 100755
index f9ce5b0..abb1960
--- a/gui/theme/portrait_hdpi/ui.xml
+++ b/gui/theme/portrait_hdpi/ui.xml
@@ -6,7 +6,7 @@
 		<title>Backup Naowz</title>
 		<description>Default basic theme</description>
 		<preview>preview.png</preview>
-		<themeversion>3</themeversion>
+		<themeversion>4</themeversion>
 	</details>
 
 	<include>
diff --git a/gui/theme/portrait_mdpi/ui.xml b/gui/theme/portrait_mdpi/ui.xml
index 8b91641..3de99ce 100755
--- a/gui/theme/portrait_mdpi/ui.xml
+++ b/gui/theme/portrait_mdpi/ui.xml
@@ -6,7 +6,7 @@
 		<title>Backup Naowz</title>
 		<description>Default basic theme</description>
 		<preview>preview.png</preview>
-		<themeversion>3</themeversion>
+		<themeversion>4</themeversion>
 	</details>
 
 	<include>
diff --git a/install/get_args.cpp b/install/get_args.cpp
new file mode 100755
index 0000000..116602e
--- /dev/null
+++ b/install/get_args.cpp
@@ -0,0 +1,91 @@
+#include "install/get_args.h"
+
+std::string stage;
+bool has_cache = false;
+static constexpr const char* COMMAND_FILE = "/cache/recovery/command";
+
+// 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)
+std::vector<std::string> args::get_args(const int *argc, char*** const argv) {
+  CHECK_GT(*argc, 0);
+
+  bootloader_message boot = {};
+  std::string err;
+  if (!read_bootloader_message(&boot, &err)) {
+    LOG(ERROR) << err;
+    // If fails, leave a zeroed bootloader_message.
+    boot = {};
+  }
+  stage = std::string(boot.stage);
+
+  std::string boot_command;
+  if (boot.command[0] != 0) {
+    if (memchr(boot.command, '\0', sizeof(boot.command))) {
+      boot_command = std::string(boot.command);
+    } else {
+      boot_command = std::string(boot.command, sizeof(boot.command));
+    }
+    LOG(INFO) << "Boot command: " << boot_command;
+    printf("boot command: %s\n", boot_command.c_str());
+  }
+
+  if (boot.status[0] != 0) {
+    std::string boot_status = std::string(boot.status, sizeof(boot.status));
+    LOG(INFO) << "Boot status: " << boot_status;
+  }
+
+  std::vector<std::string> args(*argv, *argv + *argc);
+
+  // --- if arguments weren't supplied, look in the bootloader control block
+  if (args.size() == 1) {
+    boot.recovery[sizeof(boot.recovery) - 1] = '\0';  // Ensure termination
+    std::string boot_recovery(boot.recovery);
+    std::vector<std::string> tokens = android::base::Split(boot_recovery, "\n");
+    if (!tokens.empty() && tokens[0] == "recovery") {
+      for (auto it = tokens.begin() + 1; it != tokens.end(); it++) {
+        // Skip empty and '\0'-filled tokens.
+        if (!it->empty() && (*it)[0] != '\0') args.push_back(std::move(*it));
+      }
+      LOG(INFO) << "Got " << args.size() << " arguments from boot message";
+    } else if (boot.recovery[0] != 0) {
+      LOG(ERROR) << "Bad boot message: \"" << boot_recovery << "\"";
+    }
+  }
+
+  // --- if that doesn't work, try the command file (if we have /cache).
+  if (args.size() == 1 && has_cache) {
+    std::string content;
+    if (ensure_path_mounted(COMMAND_FILE) == 0 &&
+        android::base::ReadFileToString(COMMAND_FILE, &content)) {
+      std::vector<std::string> tokens = android::base::Split(content, "\n");
+      // All the arguments in COMMAND_FILE are needed (unlike the BCB message,
+      // COMMAND_FILE doesn't use filename as the first argument).
+      for (auto it = tokens.begin(); it != tokens.end(); it++) {
+        // Skip empty and '\0'-filled tokens.
+        if (!it->empty() && (*it)[0] != '\0') args.push_back(std::move(*it));
+      }
+      LOG(INFO) << "Got " << args.size() << " arguments from " << COMMAND_FILE;
+    }
+  }
+
+  // Write the arguments (excluding the filename in args[0]) back into the
+  // bootloader control block. So the device will always boot into recovery to
+  // finish the pending work, until finish_recovery() is called.
+  std::vector<std::string> options(args.cbegin() + 1, args.cend());
+  if (!update_bootloader_message(options, &err)) {
+    LOG(ERROR) << "Failed to set BCB message: " << err;
+  }
+
+  // Finally, if no arguments were specified, check whether we should boot
+  // into fastboot or rescue mode.
+  if (args.size() == 1 && boot_command == "boot-fastboot") {
+    printf("fastbootd needed\n");
+    args.emplace_back("--fastboot");
+  } else if (args.size() == 1 && boot_command == "boot-rescue") {
+    args.emplace_back("--rescue");
+  }
+
+  return args;
+}
diff --git a/install/include/install/get_args.h b/install/include/install/get_args.h
new file mode 100755
index 0000000..edad642
--- /dev/null
+++ b/install/include/install/get_args.h
@@ -0,0 +1,17 @@
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+#include "otautil/roots.h"
+
+#include "bootloader_message/include/bootloader_message/bootloader_message.h"
+
+extern std::string stage;
+
+class args {
+    public:
+        static std::vector<std::string> get_args(const int *argc, char*** const argv);
+};
\ No newline at end of file
diff --git a/openrecoveryscript.cpp b/openrecoveryscript.cpp
index 5e7091b..86eec4d 100755
--- a/openrecoveryscript.cpp
+++ b/openrecoveryscript.cpp
@@ -373,11 +373,9 @@
 
 				int wipe_cache = 0;
 				string result;
-				// pid_t sideload_child_pid;
 
 				gui_msg("start_sideload=Starting ADB sideload feature...");
 
-				// ret_val = apply_from_adb("/", &sideload_child_pid);
 				Device::BuiltinAction reboot_action = Device::REBOOT_BOOTLOADER;
 				ret_val = ApplyFromAdb("/", &reboot_action);
 				if (ret_val != 0) {
@@ -452,8 +450,6 @@
 int OpenRecoveryScript::Insert_ORS_Command(string Command) {
 	ofstream ORSfile(SCRIPT_FILE_TMP, ios_base::app | ios_base::out);
 	if (ORSfile.is_open()) {
-		//if (Command.substr(Command.size() - 1, 1) != "\n")
-		//	Command += "\n";
 		LOGINFO("Inserting '%s'\n", Command.c_str());
 		ORSfile << Command.c_str() << endl;
 		ORSfile.close();
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index bdc4f9e..75fdb5d 100755
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -271,6 +271,7 @@
 			andsec_partition = (*iter);
 		else
 			(*iter)->Has_Android_Secure = false;
+
 		if (Is_Super_Partition(TWFunc::Remove_Beginning_Slash((*iter)->Get_Mount_Point()).c_str()))
 			Prepare_Super_Volume((*iter));
 	}
@@ -3240,7 +3241,12 @@
 }
 
 bool TWPartitionManager::Get_Super_Status() {
-	return access(Get_Super_Partition().c_str(), F_OK) == 0;
+	std::string fastboot_mode = android::base::GetProperty("sys.usb.config", "");
+	if (fastboot_mode == "fastboot") {
+		return false;
+	}
+	else
+		return access(Get_Super_Partition().c_str(), F_OK) == 0;
 }
 
 bool TWPartitionManager::Recreate_Logs_Dir() {
diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk
index e3feb41..e81f49b 100755
--- a/prebuilt/Android.mk
+++ b/prebuilt/Android.mk
@@ -81,6 +81,7 @@
 RECOVERY_BINARY_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/vold_prepare_subdirs
 RECOVERY_BINARY_SOURCE_FILES += $(TARGET_OUT_VENDOR_EXECUTABLES)/vndservicemanager
 RECOVERY_BINARY_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/toybox
+RECOVERY_BINARY_SOURCE_FILES += $(TARGET_OUT_VENDOR_EXECUTABLES)/hw/android.hardware.health@2.0-service
 RECOVERY_BINARY_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/system/bin/charger
 RECOVERY_BINARY_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/system/bin/ueventd
 RECOVERY_BINARY_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/system/bin/watchdogd
@@ -120,11 +121,11 @@
 RECOVERY_LIBRARY_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libbmlutils.so
 RECOVERY_LIBRARY_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libflashutils.so
 RECOVERY_LIBRARY_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libfusesideload.so
-RECOVERY_LIBRARY_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libbootloader_message_twrp.so
+RECOVERY_LIBRARY_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libbootloader_message.so
 
 RECOVERY_LIBRARY_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libcrypto.so \
 $(if $(WITH_CRYPTO_UTILS),$(TARGET_OUT_SHARED_LIBRARIES)/libcrypto_utils.so)
-  
+
 RECOVERY_LIBRARY_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/system/lib64/libbacktrace.so
 RECOVERY_LIBRARY_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libunwind.so
 RECOVERY_LIBRARY_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libbase.so
diff --git a/startupArgs.cpp b/startupArgs.cpp
new file mode 100755
index 0000000..01b1955
--- /dev/null
+++ b/startupArgs.cpp
@@ -0,0 +1,81 @@
+/*
+	Copyright 2012-2020 TeamWin
+	This file is part of TWRP/TeamWin Recovery Project.
+
+	TWRP is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	TWRP is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with TWRP.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "startupArgs.hpp"
+
+void startupArgs::parse(int *argc, char ***argv) {
+	std::vector<std::string> args = args::get_args(argc, argv);
+	int index;
+
+	LOGINFO("Startup Commands: ");
+	for (index = 1; index < args.size(); index++) {
+		printf("'%s'", args[index].c_str());
+		if (args[index] == FASTBOOT) {
+			fastboot_mode = true;
+			android::base::SetProperty("sys.usb.config", "none");
+			android::base::SetProperty("sys.usb.configfs", "0");
+			sleep(1);
+			android::base::SetProperty("sys.usb.configfs", "1");
+			android::base::SetProperty("sys.usb.config", "fastboot");
+			DataManager::SetValue("tw_enable_adb", 0);
+			DataManager::SetValue("tw_enable_fastboot", 1);
+		} else if (args[index] == UPDATE_PACKAGE) {
+			std::string::size_type eq_pos = args[index].find("=");
+			std::string arg = args[index].substr(eq_pos + 1, args[index].size());
+			if (arg.size() == 0) {
+				LOGERR("argument error specifying zip file\n");
+			} else {
+				std::string ORSCommand = "install " + arg;
+				SkipDecryption = arg.find("@") == 1;
+				if (!OpenRecoveryScript::Insert_ORS_Command(ORSCommand))
+					break;
+			}
+		} else if (args[index].find(SEND_INTENT) != std::string::npos) {
+			std::string::size_type eq_pos = args[index].find("=");
+			std::string arg = args[index].substr(eq_pos + 1, args[index].size());
+			if (arg.size() == 0) {
+				LOGERR("argument error specifying intent file\n");
+			} else {
+				Send_Intent = arg;
+			}
+		} else if (args[index].find(WIPE_DATA) != std::string::npos) {
+			if (!OpenRecoveryScript::Insert_ORS_Command("wipe data\n"))
+				break;
+		} else if (args[index].find(WIPE_CACHE) != std::string::npos) {
+			if (!OpenRecoveryScript::Insert_ORS_Command("wipe cache\n"))
+				break;
+		} else if (args[index].find(NANDROID) != std::string::npos) {
+			DataManager::SetValue(TW_BACKUP_NAME, gui_parse_text("{@auto_generate}"));
+			if (!OpenRecoveryScript::Insert_ORS_Command("backup BSDCAE\n"))
+				break;
+		}
+	}
+	printf("\n");
+}
+
+bool startupArgs::Should_Skip_Decryption() {
+	return SkipDecryption;
+}
+
+std::string startupArgs::Get_Intent() {
+	return Send_Intent;
+}
+
+bool startupArgs::Get_Fastboot_Mode() {
+	return fastboot_mode;
+}
\ No newline at end of file
diff --git a/startupArgs.hpp b/startupArgs.hpp
new file mode 100755
index 0000000..53a47c4
--- /dev/null
+++ b/startupArgs.hpp
@@ -0,0 +1,53 @@
+/*
+	Copyright 2012-2020 TeamWin
+	This file is part of TWRP/TeamWin Recovery Project.
+
+	TWRP is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	TWRP is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with TWRP.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef STARTUPARGS_HPP
+#define STARTUPARGS_HPP
+#include <android-base/properties.h>
+
+#include "data.hpp"
+#include "gui/gui.hpp"
+#include "openrecoveryscript.hpp"
+#include "partitions.hpp"
+#include "twcommon.h"
+#include "twrp-functions.hpp"
+#include "variables.h"
+#include "bootloader_message/include/bootloader_message/bootloader_message.h"
+#include "install/get_args.h"
+
+class startupArgs {
+public:
+	static inline std::string const UPDATE_PACKAGE = "--update_package";
+	static inline std::string const WIPE_CACHE = "--wipe_cache";
+	static inline std::string const WIPE_DATA = "--wipe_data";
+	static inline std::string const SEND_INTENT = "--send_intent";
+	static inline std::string const SIDELOAD = "--sideload";
+	static inline std::string const REASON = "--reason";
+	static inline std::string const FASTBOOT = "--fastboot";
+	static inline std::string const NANDROID = "--nandroid";
+	void parse(int *argc, char ***argv);
+	bool Should_Skip_Decryption();
+	std::string Get_Intent();
+	bool Get_Fastboot_Mode();
+
+private:
+	bool SkipDecryption = false;
+	bool fastboot_mode = false;
+	std::string Send_Intent;
+};
+#endif
\ No newline at end of file
diff --git a/twrp-functions.cpp b/twrp-functions.cpp
index aeb2f7e..694c9bb 100755
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -1,5 +1,5 @@
 /*
-	Copyright 2012 bigbiff/Dees_Troy TeamWin
+	Copyright 2012-2020 TeamWin
 	This file is part of TWRP/TeamWin Recovery Project.
 
 	TWRP is free software: you can redistribute it and/or modify
@@ -45,7 +45,7 @@
 #include "data.hpp"
 #include "partitions.hpp"
 #include "variables.h"
-#include "bootloader_message_twrp/include/bootloader_message_twrp/bootloader_message.h"
+#include "bootloader_message/include/bootloader_message/bootloader_message.h"
 #include "cutils/properties.h"
 #include "cutils/android_reboot.h"
 #include <sys/reboot.h>
@@ -619,19 +619,6 @@
 	chmod(logCopy.c_str(), 0600);
 	chmod(lastLogCopy.c_str(), 0640);
 
-	// Reset bootloader message
-	TWPartition* Part = PartitionManager.Find_Partition_By_Path("/misc");
-	if (Part != NULL) {
-		std::string err;
-		if (!clear_bootloader_message((void*)&err)) {
-			if (err == "no misc device set") {
-				LOGINFO("%s\n", err.c_str());
-			} else {
-				LOGERR("%s\n", err.c_str());
-			}
-		}
-	}
-
 	if (get_log_dir() == CACHE_LOGS_DIR) {
 		if (PartitionManager.Mount_By_Path("/cache", false)) {
 			if (unlink("/cache/recovery/command") && errno != ENOENT) {
@@ -642,6 +629,17 @@
 	sync();
 }
 
+void TWFunc::Clear_Bootloader_Message() {
+	std::string err;
+	if (!clear_bootloader_message(&err)) {
+		if (err == "no misc device set") {
+			LOGINFO("%s\n", err.c_str());
+		} else {
+			LOGERR("%s\n", err.c_str());
+		}
+	}
+}
+
 void TWFunc::Update_Intent_File(string Intent) {
 	if (PartitionManager.Mount_By_Path("/cache", false) && !Intent.empty()) {
 		TWFunc::write_to_file("/cache/recovery/intent", Intent);
@@ -672,18 +670,10 @@
 #endif
 		case rb_recovery:
 			check_and_run_script("/system/bin/rebootrecovery.sh", "reboot recovery");
-#ifdef ANDROID_RB_PROPERTY
 			return property_set(ANDROID_RB_PROPERTY, "reboot,recovery");
-#else
-			return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "recovery");
-#endif
 		case rb_bootloader:
 			check_and_run_script("/system/bin/rebootbootloader.sh", "reboot bootloader");
-#ifdef ANDROID_RB_PROPERTY
 			return property_set(ANDROID_RB_PROPERTY, "reboot,bootloader");
-#else
-			return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "bootloader");
-#endif
 		case rb_poweroff:
 			check_and_run_script("/system/bin/poweroff.sh", "power off");
 #ifdef ANDROID_RB_PROPERTY
@@ -695,18 +685,12 @@
 #endif
 		case rb_download:
 			check_and_run_script("/system/bin/rebootdownload.sh", "reboot download");
-#ifdef ANDROID_RB_PROPERTY
 			return property_set(ANDROID_RB_PROPERTY, "reboot,download");
-#else
-			return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "download");
-#endif
 		case rb_edl:
 			check_and_run_script("/system/bin/rebootedl.sh", "reboot edl");
-#ifdef ANDROID_RB_PROPERTY
 			return property_set(ANDROID_RB_PROPERTY, "reboot,edl");
-#else
-			return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "edl");
-#endif
+		case rb_fastboot:
+			return property_set(ANDROID_RB_PROPERTY, "reboot,fastboot");
 		default:
 			return -1;
 	}
diff --git a/twrp-functions.hpp b/twrp-functions.hpp
index 2686734..611397e 100755
--- a/twrp-functions.hpp
+++ b/twrp-functions.hpp
@@ -39,9 +39,10 @@
 	rb_system,
 	rb_recovery,
 	rb_poweroff,
-	rb_bootloader,     // May also be fastboot
+	rb_bootloader,
 	rb_download,
 	rb_edl,
+	rb_fastboot
 } RebootCommand;
 
 enum Archive_Type {
@@ -116,6 +117,7 @@
 	static bool Get_Encryption_Policy(fscrypt_encryption_policy &policy, std::string path); // return encryption policy for path
 	static bool Set_Encryption_Policy(std::string path, const fscrypt_encryption_policy &policy); // set encryption policy for path
 	static void List_Mounts();
+	static void Clear_Bootloader_Message();
 
 private:
 	static void Copy_Log(string Source, string Destination);
diff --git a/twrp.cpp b/twrp.cpp
index 584245b..7ec428c 100755
--- a/twrp.cpp
+++ b/twrp.cpp
@@ -1,16 +1,19 @@
 /*
-		TWRP is free software: you can redistribute it and/or modify
-		it under the terms of the GNU General Public License as published by
-		the Free Software Foundation, either version 3 of the License, or
-		(at your option) any later version.
+	Copyright 2012-2020 TeamWin
+	This file is part of TWRP/TeamWin Recovery Project.
 
-		TWRP is distributed in the hope that it will be useful,
-		but WITHOUT ANY WARRANTY; without even the implied warranty of
-		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-		GNU General Public License for more details.
+	TWRP is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
 
-		You should have received a copy of the GNU General Public License
-		along with TWRP.  If not, see <http://www.gnu.org/licenses/>.
+	TWRP is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with TWRP.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include <stdio.h>
@@ -24,7 +27,6 @@
 #include "gui/twmsg.h"
 
 #include "cutils/properties.h"
-#include "bootloader_message_twrp/include/bootloader_message_twrp/bootloader_message.h"
 
 #ifdef ANDROID_RB_RESTART
 #include "cutils/android_reboot.h"
@@ -50,6 +52,7 @@
 #endif
 #include "openrecoveryscript.hpp"
 #include "variables.h"
+#include "startupArgs.hpp"
 #include "twrpAdbBuFifo.hpp"
 #ifdef TW_USE_NEW_MINADBD
 // #include "minadbd/minadbd.h"
@@ -96,53 +99,21 @@
 	}
 }
 
-int main(int argc, char **argv) {
-	// Recovery needs to install world-readable files, so clear umask
-	// set by init
-	umask(0);
-
-	Log_Offset = 0;
-
-	// Set up temporary log file (/tmp/recovery.log)
-	freopen(TMP_LOG_FILE, "a", stdout);
-	setbuf(stdout, NULL);
-	freopen(TMP_LOG_FILE, "a", stderr);
-	setbuf(stderr, NULL);
-
-	signal(SIGPIPE, SIG_IGN);
-
-	// Handle ADB sideload
-	if (argc == 3 && strcmp(argv[1], "--adbd") == 0) {
-		property_set("ctl.stop", "adbd");
-#ifdef TW_USE_NEW_MINADBD
-		//adb_server_main(0, DEFAULT_ADB_PORT, -1); TODO fix this for android8
-		// minadbd_main();
-#else
-		adb_main(argv[2]);
-#endif
-		return 0;
-	}
-
-#ifdef RECOVERY_SDCARD_ON_DATA
-	datamedia = true;
-#endif
-
+static void process_recovery_mode(twrpAdbBuFifo* adb_bu_fifo, bool skip_decryption) {
 	char crash_prop_val[PROPERTY_VALUE_MAX];
 	int crash_counter;
 	property_get("twrp.crash_counter", crash_prop_val, "-1");
 	crash_counter = atoi(crash_prop_val) + 1;
 	snprintf(crash_prop_val, sizeof(crash_prop_val), "%d", crash_counter);
 	property_set("twrp.crash_counter", crash_prop_val);
-	property_set("ro.twrp.boot", "1");
-	property_set("ro.twrp.version", TW_VERSION_STR);
 
-	time_t StartupTime = time(NULL);
-	printf("Starting TWRP %s-%s on %s (pid %d)\n", TW_VERSION_STR, TW_GIT_REVISION, ctime(&StartupTime), getpid());
+	if (crash_counter == 0) {
+		property_list(Print_Prop, NULL);
+		printf("\n");
+	} else {
+		printf("twrp.crash_counter=%d\n", crash_counter);
+	}
 
-	// Load default values to set DataManager constants and handle ifdefs
-	DataManager::SetDefaultValues();
-	printf("Starting the UI...\n");
-	gui_init();
 	printf("=> Linking mtab\n");
 	symlink("/proc/mounts", "/etc/mtab");
 	std::string fstab_filename = "/etc/twrp.fstab";
@@ -152,7 +123,7 @@
 	printf("=> Processing %s\n", fstab_filename.c_str());
 	if (!PartitionManager.Process_Fstab(fstab_filename, 1)) {
 		LOGERR("Failing out of recovery due to problem with fstab.\n");
-		return -1;
+		return;
 	}
 	PartitionManager.Output_Partition_Logging();
 
@@ -188,96 +159,6 @@
 	}
 #endif
 
-	// Load up all the resources
-	gui_loadResources();
-
-	bool Shutdown = false;
-	bool SkipDecryption = false;
-	string Send_Intent = "";
-	{
-		TWPartition* misc = PartitionManager.Find_Partition_By_Path("/misc");
-		if (misc != NULL) {
-			if (misc->Current_File_System == "emmc") {
-				set_misc_device(misc->Actual_Block_Device.c_str());
-			} else {
-				LOGERR("Only emmc /misc is supported\n");
-			}
-		}
-		get_args(&argc, &argv);
-
-		int index, index2, len;
-		char* argptr;
-		char* ptr;
-		printf("Startup Commands: ");
-		for (index = 1; index < argc; index++) {
-			argptr = argv[index];
-			printf(" '%s'", argv[index]);
-			len = strlen(argv[index]);
-			if (*argptr == '-') {argptr++; len--;}
-			if (*argptr == '-') {argptr++; len--;}
-			if (*argptr == 'u') {
-				ptr = argptr;
-				index2 = 0;
-				while (*ptr != '=' && *ptr != '\n')
-					ptr++;
-				// skip the = before grabbing Zip_File
-				while (*ptr == '=')
-					ptr++;
-				if (*ptr) {
-					string ORSCommand = "install ";
-					ORSCommand.append(ptr);
-
-					// If we have a map of blocks we don't need to mount data.
-					SkipDecryption = *ptr == '@';
-
-					if (!OpenRecoveryScript::Insert_ORS_Command(ORSCommand))
-						break;
-				} else
-					LOGERR("argument error specifying zip file\n");
-			} else if (*argptr == 'w') {
-				if (len == 9) {
-					if (!OpenRecoveryScript::Insert_ORS_Command("wipe data\n"))
-						break;
-				} else if (len == 10) {
-					if (!OpenRecoveryScript::Insert_ORS_Command("wipe cache\n"))
-						break;
-				}
-				// Other 'w' items are wipe_ab and wipe_package_size which are related to bricking the device remotely. We will not bother to suppor these as having TWRP probably makes "bricking" the device in this manner useless
-			} else if (*argptr == 'n') {
-				DataManager::SetValue(TW_BACKUP_NAME, gui_parse_text("{@auto_generate}"));
-				if (!OpenRecoveryScript::Insert_ORS_Command("backup BSDCAE\n"))
-					break;
-			} else if (*argptr == 'p') {
-				Shutdown = true;
-			} else if (*argptr == 's') {
-				if (strncmp(argptr, "send_intent", strlen("send_intent")) == 0) {
-					ptr = argptr + strlen("send_intent") + 1;
-					Send_Intent = *ptr;
-				} else if (strncmp(argptr, "security", strlen("security")) == 0) {
-					LOGINFO("Security update\n");
-				} else if (strncmp(argptr, "sideload", strlen("sideload")) == 0) {
-					if (!OpenRecoveryScript::Insert_ORS_Command("sideload\n"))
-						break;
-				} else if (strncmp(argptr, "stages", strlen("stages")) == 0) {
-					LOGINFO("ignoring stages command\n");
-				}
-			} else if (*argptr == 'r') {
-				if (strncmp(argptr, "reason", strlen("reason")) == 0) {
-					ptr = argptr + strlen("reason") + 1;
-					gui_print("%s\n", ptr);
-				}
-			}
-		}
-		printf("\n");
-	}
-
-	if (crash_counter == 0) {
-		property_list(Print_Prop, NULL);
-		printf("\n");
-	} else {
-		printf("twrp.crash_counter=%d\n", crash_counter);
-	}
-
 	// Check for and run startup script if script exists
 	TWFunc::check_and_run_script("/system/bin/runatboot.sh", "boot");
 	TWFunc::check_and_run_script("/system/bin/postrecoveryboot.sh", "boot");
@@ -295,22 +176,20 @@
 	LOGINFO("Backup of TWRP ramdisk done.\n");
 #endif
 
-	Decrypt_Page(SkipDecryption, datamedia);
+	Decrypt_Page(skip_decryption, datamedia);
 
 	// Fixup the RTC clock on devices which require it
 	if (crash_counter == 0)
 		TWFunc::Fixup_Time_On_Boot();
 
 	DataManager::ReadSettingsFile();
-	PageManager::LoadLanguage(DataManager::GetStrValue("tw_language"));
-	GUIConsole::Translate_Now();
 
 	// Run any outstanding OpenRecoveryScript
 	std::string cacheDir = TWFunc::get_log_dir();
 	if (cacheDir == DATA_LOGS_DIR)
 		cacheDir = "/data/cache";
 	std::string orsFile = cacheDir + "/recovery/openrecoveryscript";
-	if ((DataManager::GetIntValue(TW_IS_ENCRYPTED) == 0 || SkipDecryption) && (TWFunc::Path_Exists(SCRIPT_FILE_TMP) || TWFunc::Path_Exists(orsFile))) {
+	if ((DataManager::GetIntValue(TW_IS_ENCRYPTED) == 0 || skip_decryption) && (TWFunc::Path_Exists(SCRIPT_FILE_TMP) || TWFunc::Path_Exists(orsFile))) {
 		OpenRecoveryScript::Run_OpenRecoveryScript();
 	}
 
@@ -378,23 +257,19 @@
 
 	TWFunc::Update_Log_File();
 
-	twrpAdbBuFifo *adb_bu_fifo = new twrpAdbBuFifo();
 	adb_bu_fifo->threadAdbBuFifo();
 
-	// Launch the main GUI
-	gui_start();
-
 #ifndef TW_OEM_BUILD
 	// Disable flashing of stock recovery
 	TWFunc::Disable_Stock_Recovery_Replace();
 #endif
+}
 
-	// Reboot
-	TWFunc::Update_Intent_File(Send_Intent);
-	delete adb_bu_fifo;
-	TWFunc::Update_Log_File();
+static void reboot() {
 	gui_msg(Msg("rebooting=Rebooting..."));
+	TWFunc::Update_Log_File();
 	string Reboot_Arg;
+
 	DataManager::GetValue("tw_reboot_arg", Reboot_Arg);
 	if (Reboot_Arg == "recovery")
 		TWFunc::tw_reboot(rb_recovery);
@@ -406,9 +281,86 @@
 		TWFunc::tw_reboot(rb_download);
 	else if (Reboot_Arg == "edl")
 		TWFunc::tw_reboot(rb_edl);
+	else if (Reboot_Arg == "fastboot")
+		TWFunc::tw_reboot(rb_fastboot);
 	else
 		TWFunc::tw_reboot(rb_system);
+}
+
+int main(int argc, char **argv) {
+	// Recovery needs to install world-readable files, so clear umask
+	// set by init
+	umask(0);
+
+	Log_Offset = 0;
+
+	// Set up temporary log file (/tmp/recovery.log)
+	freopen(TMP_LOG_FILE, "a", stdout);
+	setbuf(stdout, NULL);
+	freopen(TMP_LOG_FILE, "a", stderr);
+	setbuf(stderr, NULL);
+
+	signal(SIGPIPE, SIG_IGN);
+
+	// Handle ADB sideload
+	if (argc == 3 && strcmp(argv[1], "--adbd") == 0) {
+		property_set("ctl.stop", "adbd");
+#ifdef TW_USE_NEW_MINADBD
+		//adb_server_main(0, DEFAULT_ADB_PORT, -1); TODO fix this for android8
+		// minadbd_main();
+#else
+		adb_main(argv[2]);
+#endif
+		return 0;
+	}
+
+#ifdef RECOVERY_SDCARD_ON_DATA
+	datamedia = true;
+#endif
+
+	property_set("ro.twrp.boot", "1");
+	property_set("ro.twrp.version", TW_VERSION_STR);
+
+	time_t StartupTime = time(NULL);
+	printf("Starting TWRP %s-%s on %s (pid %d)\n", TW_VERSION_STR, TW_GIT_REVISION, ctime(&StartupTime), getpid());
+
+	// Load default values to set DataManager constants and handle ifdefs
+	DataManager::SetDefaultValues();
+	printf("Starting the UI...\n");
+	gui_init();
+
+	// Load up all the resources
+	gui_loadResources();
+
+	PageManager::LoadLanguage(DataManager::GetStrValue("tw_language"));
+	GUIConsole::Translate_Now();
+
+	startupArgs startup;
+	startup.parse(&argc, &argv);
+	twrpAdbBuFifo *adb_bu_fifo = new twrpAdbBuFifo();
+	TWFunc::Clear_Bootloader_Message();
+
+	if (startup.Get_Fastboot_Mode()) {
+		LOGINFO("starting fastboot\n");
+		gui_msg(Msg("fastboot_console_msg=Entered Fastboot mode..."));
+		if (gui_startPage("fastboot", 1, 1) != 0) {
+			LOGERR("Failed to start fastbootd page.\n");
+		}
+		delete adb_bu_fifo;
+		TWFunc::Update_Intent_File(startup.Get_Intent());
+
+		reboot();
+		return 0;
+	} else {
+		process_recovery_mode(adb_bu_fifo, startup.Should_Skip_Decryption());
+	}
+
+	// Launch the main GUI
+	gui_start();
+	delete adb_bu_fifo;
+	TWFunc::Update_Intent_File(startup.Get_Intent());
+
+	reboot();
 
 	return 0;
 }
-
diff --git a/variables.h b/variables.h
index 51ee09f..95946b7 100755
--- a/variables.h
+++ b/variables.h
@@ -130,6 +130,7 @@
 #define TW_MIN_SYSTEM_VAR           "tw_min_system"
 #define TW_DOWNLOAD_MODE            "tw_download_mode"
 #define TW_EDL_MODE                 "tw_edl_mode"
+#define TW_FASTBOOT_MODE            "tw_fastboot_mode"
 #define TW_IS_ENCRYPTED             "tw_is_encrypted"
 #define TW_IS_DECRYPTED             "tw_is_decrypted"
 #define TW_CRYPTO_PWTYPE            "tw_crypto_pwtype"