From cc8ddca9bd78913ed50ef8cbd6a2d2c095823f1a Mon Sep 17 00:00:00 2001 From: that Date: Sat, 3 Jan 2015 01:59:36 +0100 Subject: fix adb sideload - "Cancel" button handling requires another thread - simplify handling of child pid - merge duplicated code for reinjecting TWRP after installation - fix error that showed on host PC after sideload finished - fix problem where adbd sometimes does not stop correctly Change-Id: I536877f024b606756c6a3289c6ddfdba423a60d6 --- adb_install.cpp | 54 +++++++--------- adb_install.h | 2 +- gui/action.cpp | 169 +++++++++++++++++++++++++------------------------ gui/objects.hpp | 2 + openrecoveryscript.cpp | 3 +- twrp.cpp | 3 +- 6 files changed, 117 insertions(+), 116 deletions(-) diff --git a/adb_install.cpp b/adb_install.cpp index 77b9a8c1c..3e53066f5 100644 --- a/adb_install.cpp +++ b/adb_install.cpp @@ -84,7 +84,7 @@ maybe_restart_adbd() { #define ADB_INSTALL_TIMEOUT 300 int -apply_from_adb(const char* install_file) { +apply_from_adb(const char* install_file, pid_t* child_pid) { stop_adbd(); set_usb_driver(true); @@ -98,16 +98,14 @@ apply_from_adb(const char* install_file) { _exit(-1); } - char child_prop[PROPERTY_VALUE_MAX]; - sprintf(child_prop, "%i", child); - property_set("tw_child_pid", child_prop); + *child_pid = child; + // caller can now kill the child thread from another thread // FUSE_SIDELOAD_HOST_PATHNAME will start to exist once the host // connects and starts serving a package. Poll for its // appearance. (Note that inotify doesn't work with FUSE.) int result; int status; - int wipe_cache; bool waited = false; struct stat st; for (int i = 0; i < ADB_INSTALL_TIMEOUT; ++i) { @@ -122,20 +120,21 @@ apply_from_adb(const char* install_file) { sleep(1); continue; } else { - printf("\nTimed out waiting for package.\n\n", strerror(errno)); + printf("\nTimed out waiting for package: %s\n\n", strerror(errno)); result = -1; kill(child, SIGKILL); break; } } - property_set("tw_sideload_file", FUSE_SIDELOAD_HOST_PATHNAME); // Install is handled elsewhere in TWRP - result = 5; //install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache, install_file, false); - break; + //install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache, install_file, false); + return 0; } - // We do this elsewhere in TWRP - /*if (!waited) { + // if we got here, something failed + *child_pid = 0; + + if (!waited) { // Calling stat() on this magic filename signals the minadbd // subprocess to shut down. stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st); @@ -145,26 +144,19 @@ apply_from_adb(const char* install_file) { // you just have to 'adb sideload' a file that's not a valid // package, like "/dev/null". waitpid(child, &status, 0); - }*/ + } - if (result != 5) { - stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st); - waitpid(child, &status, 0); - result = -1; - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - if (WEXITSTATUS(status) == 3) { - printf("\nYou need adb 1.0.32 or newer to sideload\nto this device.\n\n"); - result = -2; - } else if (!WIFSIGNALED(status)) { - printf("status %d\n", WEXITSTATUS(status)); - } + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + if (WEXITSTATUS(status) == 3) { + printf("\nYou need adb 1.0.32 or newer to sideload\nto this device.\n\n"); + result = -2; + } else if (!WIFSIGNALED(status)) { + printf("status %d\n", WEXITSTATUS(status)); } - set_usb_driver(false); - maybe_restart_adbd(); - return result; - } else { - return 0; - } - - return -1; // This should not happen + } + + set_usb_driver(false); + maybe_restart_adbd(); + + return result; } diff --git a/adb_install.h b/adb_install.h index 604c61d27..24e9e21f6 100644 --- a/adb_install.h +++ b/adb_install.h @@ -21,6 +21,6 @@ void set_usb_driver(bool enabled); void maybe_restart_adbd(); -int apply_from_adb(const char* install_file); +int apply_from_adb(const char* install_file, pid_t* child_pid); #endif diff --git a/gui/action.cpp b/gui/action.cpp index 4796ff335..361a676b2 100644 --- a/gui/action.cpp +++ b/gui/action.cpp @@ -41,6 +41,7 @@ #include "../openrecoveryscript.hpp" #include "../adb_install.h" +#include "../fuse_sideload.h" #ifndef TW_NO_SCREEN_TIMEOUT #include "blanktimer.hpp" #endif @@ -68,6 +69,7 @@ GUIAction::mapFunc GUIAction::mf; static string zip_queue[10]; static int zip_queue_index; static pthread_t terminal_command; +pid_t sideload_child_pid; GUIAction::GUIAction(xml_node<>* node) : GUIObject(node) @@ -833,6 +835,26 @@ int GUIAction::fileexists(std::string arg) return 0; } +void GUIAction::reinject_after_flash() +{ + if (DataManager::GetIntValue(TW_HAS_INJECTTWRP) == 1 && DataManager::GetIntValue(TW_INJECT_AFTER_ZIP) == 1) { + operation_start("ReinjectTWRP"); + gui_print("Injecting TWRP into boot image...\n"); + if (simulate) { + simulate_progress_bar(); + } else { + TWPartition* Boot = PartitionManager.Find_Partition_By_Path("/boot"); + if (Boot == NULL || Boot->Current_File_System != "emmc") + TWFunc::Exec_Cmd("injecttwrp --dump /tmp/backup_recovery_ramdisk.img /tmp/injected_boot.img --flash"); + else { + string injectcmd = "injecttwrp --dump /tmp/backup_recovery_ramdisk.img /tmp/injected_boot.img --flash bd=" + Boot->Actual_Block_Device; + TWFunc::Exec_Cmd(injectcmd); + } + gui_print("TWRP injection complete.\n"); + } + } +} + int GUIAction::flash(std::string arg) { int i, ret_val = 0, wipe_cache = 0; @@ -856,22 +878,7 @@ int GUIAction::flash(std::string arg) if (wipe_cache) PartitionManager.Wipe_By_Path("/cache"); - if (DataManager::GetIntValue(TW_HAS_INJECTTWRP) == 1 && DataManager::GetIntValue(TW_INJECT_AFTER_ZIP) == 1) { - operation_start("ReinjectTWRP"); - gui_print("Injecting TWRP into boot image...\n"); - if (simulate) { - simulate_progress_bar(); - } else { - TWPartition* Boot = PartitionManager.Find_Partition_By_Path("/boot"); - if (Boot == NULL || Boot->Current_File_System != "emmc") - TWFunc::Exec_Cmd("injecttwrp --dump /tmp/backup_recovery_ramdisk.img /tmp/injected_boot.img --flash"); - else { - string injectcmd = "injecttwrp --dump /tmp/backup_recovery_ramdisk.img /tmp/injected_boot.img --flash bd=" + Boot->Actual_Block_Device; - TWFunc::Exec_Cmd(injectcmd); - } - gui_print("TWRP injection complete.\n"); - } - } + reinject_after_flash(); PartitionManager.Update_System_Details(); operation_end(ret_val); return 0; @@ -1283,92 +1290,90 @@ int GUIAction::decrypt(std::string arg) return 0; } -int GUIAction::adbsideload(std::string arg) +void* GUIAction::sideload_thread_fn(void *cookie) { - int ret = 0; + gui_print("Starting ADB sideload feature...\n"); + bool mtp_was_enabled = TWFunc::Toggle_MTP(false); + GUIAction* this_ = (GUIAction*) cookie; - operation_start("Sideload"); - if (simulate) { - simulate_progress_bar(); + // wait for the adb connection + int ret = apply_from_adb("/", &sideload_child_pid); + DataManager::SetValue("tw_has_cancel", 0); // Remove cancel button from gui now that the zip install is going to start + + if (ret != 0) { + if (ret == -2) + gui_print("You need adb 1.0.32 or newer to sideload to this device.\n"); + ret = 1; // failure } else { int wipe_cache = 0; int wipe_dalvik = 0; - - gui_print("Starting ADB sideload feature...\n"); - bool mtp_was_enabled = TWFunc::Toggle_MTP(false); DataManager::GetValue("tw_wipe_dalvik", wipe_dalvik); - ret = apply_from_adb("/"); - DataManager::SetValue("tw_has_cancel", 0); // Remove cancel button from gui now that the zip install is going to start - char file_prop[PROPERTY_VALUE_MAX]; - property_get("tw_sideload_file", file_prop, "error"); - if (ret != 0) { - ret = 1; // failure - if (ret == -2) - gui_print("You need adb 1.0.32 or newer to sideload to this device.\n"); + + if (TWinstall_zip(FUSE_SIDELOAD_HOST_PATHNAME, &wipe_cache) == 0) { + if (wipe_cache || DataManager::GetIntValue("tw_wipe_cache")) + PartitionManager.Wipe_By_Path("/cache"); + if (wipe_dalvik) + PartitionManager.Wipe_Dalvik_Cache(); } else { - if (TWinstall_zip(file_prop, &wipe_cache) == 0) { - if (wipe_cache || DataManager::GetIntValue("tw_wipe_cache")) - PartitionManager.Wipe_By_Path("/cache"); - if (wipe_dalvik) - PartitionManager.Wipe_Dalvik_Cache(); - } else { - ret = 1; // failure - } - set_usb_driver(false); - maybe_restart_adbd(); - } - TWFunc::Toggle_MTP(mtp_was_enabled); - if (strcmp(file_prop, "error") != 0) { - struct stat st; - stat("/sideload/exit", &st); - int child_pid, status; - char child_prop[PROPERTY_VALUE_MAX]; - property_get("tw_child_pid", child_prop, "error"); - if (strcmp(child_prop, "error") == 0) { - LOGERR("Unable to get child ID from prop\n"); - } else { - child_pid = atoi(child_prop); - LOGINFO("Waiting for child sideload process to exit.\n"); - waitpid(child_pid, &status, 0); - } + ret = 1; // failure } - if (DataManager::GetIntValue(TW_HAS_INJECTTWRP) == 1 && DataManager::GetIntValue(TW_INJECT_AFTER_ZIP) == 1) { - operation_start("ReinjectTWRP"); - gui_print("Injecting TWRP into boot image...\n"); - if (simulate) { - simulate_progress_bar(); - } else { - TWPartition* Boot = PartitionManager.Find_Partition_By_Path("/boot"); - if (Boot == NULL || Boot->Current_File_System != "emmc") - TWFunc::Exec_Cmd("injecttwrp --dump /tmp/backup_recovery_ramdisk.img /tmp/injected_boot.img --flash"); - else { - string injectcmd = "injecttwrp --dump /tmp/backup_recovery_ramdisk.img /tmp/injected_boot.img --flash bd=" + Boot->Actual_Block_Device; - TWFunc::Exec_Cmd(injectcmd); - } - gui_print("TWRP injection complete.\n"); - } + } + if (sideload_child_pid) { + LOGINFO("Signaling child sideload process to exit.\n"); + struct stat st; + // Calling stat() on this magic filename signals the minadbd + // subprocess to shut down. + stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st); + int status; + LOGINFO("Waiting for child sideload process to exit.\n"); + waitpid(sideload_child_pid, &status, 0); + } + + TWFunc::Toggle_MTP(mtp_was_enabled); + this_->reinject_after_flash(); + this_->operation_end(ret); + return NULL; +} + +int GUIAction::adbsideload(std::string arg) +{ + operation_start("Sideload"); + if (simulate) { + simulate_progress_bar(); + operation_end(0); + } else { + // we need to start a thread to allow the operation to be cancelable + pthread_t sideload_thread; + int rc = pthread_create(&sideload_thread, NULL, sideload_thread_fn, this); + if (rc != 0) { + LOGERR("Error starting sideload thread, rc=%i.\n", rc); + operation_end(1); } } - operation_end(ret); return 0; } int GUIAction::adbsideloadcancel(std::string arg) { - int child_pid; - char child_prop[PROPERTY_VALUE_MAX]; struct stat st; DataManager::SetValue("tw_has_cancel", 0); // Remove cancel button from gui gui_print("Cancelling ADB sideload...\n"); - stat("/sideload/exit", &st); - ::sleep(1); - property_get("tw_child_pid", child_prop, "error"); - if (strcmp(child_prop, "error") == 0) { - LOGERR("Unable to get child ID from prop\n"); + LOGINFO("Signaling child sideload process to exit.\n"); + // Calling stat() on this magic filename signals the minadbd + // subprocess to shut down. + stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st); + if (!sideload_child_pid) { + LOGERR("Unable to get child ID\n"); return 0; } - child_pid = atoi(child_prop); - kill(child_pid, SIGTERM); + ::sleep(1); + LOGINFO("Killing child sideload process.\n"); + kill(sideload_child_pid, SIGTERM); + int status; + LOGINFO("Waiting for child sideload process to exit.\n"); + waitpid(sideload_child_pid, &status, 0); + sideload_child_pid = 0; + operation_end(1); DataManager::SetValue("tw_page_done", "1"); // For OpenRecoveryScript support return 0; } diff --git a/gui/objects.hpp b/gui/objects.hpp index 3f12ea7f7..bf07c86bc 100644 --- a/gui/objects.hpp +++ b/gui/objects.hpp @@ -283,9 +283,11 @@ protected: int doAction(Action action); void simulate_progress_bar(void); int flash_zip(std::string filename, std::string pageName, int* wipe_cache); + void reinject_after_flash(); void operation_start(const string operation_name); void operation_end(const int operation_status); static void* command_thread(void *cookie); + static void* sideload_thread_fn(void *cookie); time_t Start; // map action name to function pointer diff --git a/openrecoveryscript.cpp b/openrecoveryscript.cpp index 0b71a42eb..0db55cd44 100644 --- a/openrecoveryscript.cpp +++ b/openrecoveryscript.cpp @@ -356,7 +356,8 @@ int OpenRecoveryScript::run_script_file(void) { gui_print("Starting ADB sideload feature...\n"); DataManager::SetValue("tw_has_cancel", 1); DataManager::SetValue("tw_cancel_action", "adbsideloadcancel"); - ret_val = apply_from_adb(Sideload_File.c_str()); + pid_t child_pid; + ret_val = apply_from_adb(Sideload_File.c_str(), &child_pid); DataManager::SetValue("tw_has_cancel", 0); if (ret_val != 0) ret_val = 1; // failure diff --git a/twrp.cpp b/twrp.cpp index e0b335975..35404c34d 100644 --- a/twrp.cpp +++ b/twrp.cpp @@ -77,6 +77,7 @@ int main(int argc, char **argv) { // Handle ADB sideload if (argc == 3 && strcmp(argv[1], "--adbd") == 0) { + property_set("ctl.stop", "adbd"); adb_main(argv[2]); return 0; } @@ -95,7 +96,7 @@ int main(int argc, char **argv) { property_set("ro.twrp.version", TW_VERSION_STR); time_t StartupTime = time(NULL); - printf("Starting TWRP %s on %s (pid %d)", TW_VERSION_STR, ctime(&StartupTime), getpid()); + printf("Starting TWRP %s on %s (pid %d)\n", TW_VERSION_STR, ctime(&StartupTime), getpid()); // Load default values to set DataManager constants and handle ifdefs DataManager::SetDefaultValues(); -- cgit v1.2.3