diff --git a/Android.mk b/Android.mk index 86a53d34..bf38c046 100755 --- a/Android.mk +++ b/Android.mk @@ -69,7 +69,6 @@ LOCAL_SRC_FILES := \ partitionmanager.cpp \ progresstracking.cpp \ startupArgs.cpp \ - twinstall.cpp \ twrp-functions.cpp \ twrpDigestDriver.cpp \ openrecoveryscript.cpp \ @@ -78,7 +77,7 @@ LOCAL_SRC_FILES := \ twrpApex.cpp \ twrpRepacker.cpp -LOCAL_STATIC_LIBRARIES += libavb +LOCAL_STATIC_LIBRARIES += libavb libtwrpinstall LOCAL_SHARED_LIBRARIES += libfs_mgr libinit LOCAL_C_INCLUDES += \ system/core/fs_mgr/libfs_avb/include/ \ @@ -88,7 +87,8 @@ LOCAL_C_INCLUDES += \ system/core/fs_mgr/liblp/include/ \ system/gsid/include/ \ system/core/init/ \ - system/extras/ext4_utils/include + system/extras/ext4_utils/include \ + $(LOCAL_PATH)/twinstall/include ifneq ($(TARGET_RECOVERY_REBOOT_SRC),) LOCAL_SRC_FILES += $(TARGET_RECOVERY_REBOOT_SRC) @@ -120,12 +120,11 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/install/include \ $(LOCAL_PATH)/fuse_sideload/include \ $(LOCAL_PATH)/install/include \ - $(LOCAL_PATH)/verifier28/ + $(LOCAL_PATH)/twrpinstall/include LOCAL_STATIC_LIBRARIES += libguitwrp 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 ifneq ($(wildcard system/core/libsparse/Android.mk),) LOCAL_SHARED_LIBRARIES += libsparse @@ -398,7 +397,8 @@ TWRP_REQUIRED_MODULES += \ toolbox \ mkshrc_twrp \ plat_hwservice_contexts \ - vendor_hwservice_contexts + vendor_hwservice_contexts \ + minadbd ifneq ($(TW_INCLUDE_CRYPTO),) TWRP_REQUIRED_MODULES += \ @@ -575,9 +575,9 @@ LOCAL_MODULE := libaosprecovery LOCAL_MODULE_TAGS := optional 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 + install/get_args.cpp install/install.cpp install/legacy_property_service.cpp \ + install/package.cpp install/verifier.cpp install/wipe_data.cpp \ + install/set_metadata.cpp install/zipwrap.cpp install/ZipUtil.cpp LOCAL_SHARED_LIBRARIES += libbase libbootloader_message libcrypto libext4_utils \ libfs_mgr libfusesideload libhidl-gen-utils libhidlbase \ liblog libselinux libtinyxml2 libutils libz libziparchive libcutils @@ -589,6 +589,7 @@ LOCAL_C_INCLUDES += $(commands_TWRP_local_path)/install/include \ $(commands_TWRP_local_path)/otautil/include \ $(commands_TWRP_local_path)/minadbd \ $(commands_TWRP_local_path)/minzip \ + $(commands_TWRP_local_path)/twrpinstall/include \ system/libvintf/include LOCAL_STATIC_LIBRARIES += libotautil libvintf_recovery libvintf libhidl-gen-utils LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION) @@ -599,22 +600,6 @@ endif include $(BUILD_SHARED_LIBRARY) -# libverifier (static library) -# =============================== -include $(CLEAR_VARS) -LOCAL_CLANG := true -LOCAL_MODULE := libverifier -LOCAL_SRC_FILES := \ - asn1_decoder.cpp \ - verifier.cpp -LOCAL_STATIC_LIBRARIES := \ - libotautil \ - libcrypto_utils \ - libcrypto \ - libbase -LOCAL_CFLAGS := -Wall -Werror -include $(BUILD_STATIC_LIBRARY) - commands_recovery_local_path := $(LOCAL_PATH) # $(LOCAL_PATH)/edify/Android.mk diff --git a/etc/init.recovery.service22.rc b/etc/init.recovery.service22.rc index d9f661d8..410efff9 100755 --- a/etc/init.recovery.service22.rc +++ b/etc/init.recovery.service22.rc @@ -2,6 +2,7 @@ on boot # For starting recovery on 5.0 and newer service recovery /system/bin/recovery + socket recovery stream 422 system system seclabel u:r:recovery:s0 on early-init diff --git a/gui/Android.mk b/gui/Android.mk index e3ce1abe..b49b94d5 100755 --- a/gui/Android.mk +++ b/gui/Android.mk @@ -44,9 +44,10 @@ endif LOCAL_SHARED_LIBRARIES += libminuitwrp libc libstdc++ libaosprecovery libselinux LOCAL_C_INCLUDES += $(LOCAL_PATH)/../otautil/include +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../twrpinstall/include ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26; echo $$?),0) - LOCAL_SHARED_LIBRARIES += libziparchive - LOCAL_STATIC_LIBRARIES += libotautil + LOCAL_SHARED_LIBRARIES += libziparchive + LOCAL_STATIC_LIBRARIES += libotautil libtwrpinstall ifneq ($(TW_INCLUDE_CRYPTO),) LOCAL_C_INCLUDES += bootable/recovery/crypto/fscrypt endif diff --git a/gui/action.cpp b/gui/action.cpp index 3d94393c..b0f00275 100755 --- a/gui/action.cpp +++ b/gui/action.cpp @@ -42,11 +42,11 @@ #include "../twrpRepacker.hpp" #include "../openrecoveryscript.hpp" -#include "install/adb_install.h" +#include "twinstall/adb_install.h" #include "fuse_sideload.h" #include "blanktimer.hpp" -#include "../twinstall.h" +#include "twinstall.h" extern "C" { #include "../twcommon.h" @@ -398,6 +398,7 @@ int GUIAction::flash_zip(std::string filename, int* wipe_cache) simulate_progress_bar(); } else { ret_val = TWinstall_zip(filename.c_str(), wipe_cache); + PartitionManager.Unlock_Block_Partitions(); // Now, check if we need to ensure TWRP remains installed... struct stat st; @@ -1589,9 +1590,9 @@ int GUIAction::adbsideload(std::string arg __unused) bool mtp_was_enabled = TWFunc::Toggle_MTP(false); // wait for the adb connection - // int ret = apply_from_adb("/", &sideload_child_pid); Device::BuiltinAction reboot_action = Device::REBOOT_BOOTLOADER; - int ret = ApplyFromAdb("/", &reboot_action); + int ret = twrp_sideload("/", &reboot_action); + sideload_child_pid = GetMiniAdbdPid(); DataManager::SetValue("tw_has_cancel", 0); // Remove cancel button from gui now that the zip install is going to start if (ret != 0) { @@ -1602,27 +1603,11 @@ int GUIAction::adbsideload(std::string arg __unused) int wipe_cache = 0; int wipe_dalvik = 0; DataManager::GetValue("tw_wipe_dalvik", wipe_dalvik); - - 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 { - ret = 1; // failure - } + if (wipe_cache || DataManager::GetIntValue("tw_wipe_cache")) + PartitionManager.Wipe_By_Path("/cache"); + if (wipe_dalvik) + PartitionManager.Wipe_Dalvik_Cache(); } - 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); - } - property_set("ctl.start", "adbd"); TWFunc::Toggle_MTP(mtp_was_enabled); reinject_after_flash(); operation_end(ret); @@ -1639,6 +1624,7 @@ int GUIAction::adbsideloadcancel(std::string arg __unused) // Calling stat() on this magic filename signals the minadbd // subprocess to shut down. stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st); + sideload_child_pid = GetMiniAdbdPid(); if (!sideload_child_pid) { LOGERR("Unable to get child ID\n"); return 0; diff --git a/gui/hardwarekeyboard.cpp b/gui/hardwarekeyboard.cpp index 68be9065..12c4737a 100644 --- a/gui/hardwarekeyboard.cpp +++ b/gui/hardwarekeyboard.cpp @@ -34,7 +34,7 @@ #include extern "C" { -#include "../common.h" +#include "common.h" } #include "../twcommon.h" diff --git a/install/get_args.cpp b/install/get_args.cpp index 116602e8..c1fcc965 100755 --- a/install/get_args.cpp +++ b/install/get_args.cpp @@ -1,4 +1,4 @@ -#include "install/get_args.h" +#include "twinstall/get_args.h" std::string stage; bool has_cache = false; diff --git a/install/include/install/install.h b/install/include/install/install.h index 9e6787f1..fcbfc99a 100755 --- a/install/include/install/install.h +++ b/install/include/install/install.h @@ -44,6 +44,9 @@ enum class OtaType { BRICK, }; +static constexpr const char* UPDATE_BINARY_NAME = "META-INF/com/google/android/update-binary"; +static constexpr float VERIFICATION_PROGRESS_FRACTION = 0.25; + // Installs the given update package. This function should also wipe the cache partition after a // successful installation if |should_wipe_cache| is true or an updater command asks to wipe the // cache. diff --git a/minadbd21/Android.mk b/minadbd21/Android.mk deleted file mode 100644 index 40ed9f71..00000000 --- a/minadbd21/Android.mk +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2005 The Android Open Source Project -# -# Android.mk for adb -# - -LOCAL_PATH:= $(call my-dir) - -# minadbd library -# ========================================================= - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - adb.c \ - fdevent.c \ - fuse_adb_provider.c \ - transport.c \ - transport_usb.c \ - sockets.c \ - services.c \ - usb_linux_client.c \ - utils.c - -LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter -LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE -LOCAL_CFLAGS += -DUSE_FUSE_SIDELOAD22 -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE := libminadbd -LOCAL_C_INCLUDES += $(LOCAL_PATH)/../ -LOCAL_SHARED_LIBRARIES := libfusesideload libcutils libc -include $(BUILD_SHARED_LIBRARY) diff --git a/minadbd21/README.txt b/minadbd21/README.txt deleted file mode 100644 index c9df484c..00000000 --- a/minadbd21/README.txt +++ /dev/null @@ -1,39 +0,0 @@ -The contents of this directory are copied from system/core/adb, with -the following changes: - -adb.c - - much support for host mode and non-linux OS's stripped out; this - version only runs as adbd on the device. - - always setuid/setgid's itself to the shell user - - only uses USB transport - - references to JDWP removed - - main() removed - - all ADB_HOST and win32 code removed - - removed listeners, logging code, background server (for host) - -adb.h - - minor changes to match adb.c changes - -sockets.c - - references to JDWP removed - - ADB_HOST code removed - -services.c - - all services except echo_service (which is commented out) removed - - all host mode support removed - - sideload_service() added; this is the only service supported. It - receives a single blob of data, writes it to a fixed filename, and - makes the process exit. - -Android.mk - - only builds in adbd mode; builds as static library instead of a - standalone executable. - -sysdeps.h - - changes adb_creat() to use O_NOFOLLOW - -transport.c - - removed ADB_HOST code - -transport_usb.c - - removed ADB_HOST code diff --git a/minadbd21/adb.c b/minadbd21/adb.c deleted file mode 100644 index c35e8300..00000000 --- a/minadbd21/adb.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#define TRACE_TAG TRACE_ADB - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sysdeps.h" -#include "adb.h" - -#include - -#if ADB_TRACE -ADB_MUTEX_DEFINE( D_lock ); -#endif - -int HOST = 0; - -static const char *adb_device_banner = "sideload"; - -char ADB_SIDELOAD_FILENAME[255]; - -void fatal(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "error: "); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - exit(-1); -} - -void fatal_errno(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "error: %s: ", strerror(errno)); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - exit(-1); -} - -int adb_trace_mask; - -/* read a comma/space/colum/semi-column separated list of tags - * from the ADB_TRACE environment variable and build the trace - * mask from it. note that '1' and 'all' are special cases to - * enable all tracing - */ -void adb_trace_init(void) -{ - const char* p = getenv("ADB_TRACE"); - const char* q; - - static const struct { - const char* tag; - int flag; - } tags[] = { - { "1", 0 }, - { "all", 0 }, - { "adb", TRACE_ADB }, - { "sockets", TRACE_SOCKETS }, - { "packets", TRACE_PACKETS }, - { "rwx", TRACE_RWX }, - { "usb", TRACE_USB }, - { "sync", TRACE_SYNC }, - { "sysdeps", TRACE_SYSDEPS }, - { "transport", TRACE_TRANSPORT }, - { "jdwp", TRACE_JDWP }, - { "services", TRACE_SERVICES }, - { NULL, 0 } - }; - - if (p == NULL) - return; - - /* use a comma/column/semi-colum/space separated list */ - while (*p) { - int len, tagn; - - q = strpbrk(p, " ,:;"); - if (q == NULL) { - q = p + strlen(p); - } - len = q - p; - - for (tagn = 0; tags[tagn].tag != NULL; tagn++) - { - int taglen = strlen(tags[tagn].tag); - - if (len == taglen && !memcmp(tags[tagn].tag, p, len) ) - { - int flag = tags[tagn].flag; - if (flag == 0) { - adb_trace_mask = ~0; - return; - } - adb_trace_mask |= (1 << flag); - break; - } - } - p = q; - if (*p) - p++; - } -} - - -apacket *get_apacket(void) -{ - apacket *p = malloc(sizeof(apacket)); - if(p == 0) fatal("failed to allocate an apacket"); - memset(p, 0, sizeof(apacket) - MAX_PAYLOAD); - return p; -} - -void put_apacket(apacket *p) -{ - free(p); -} - -void handle_online(void) -{ - D("adb: online\n"); -} - -void handle_offline(atransport *t) -{ - D("adb: offline\n"); - //Close the associated usb - run_transport_disconnects(t); -} - -#if TRACE_PACKETS -#define DUMPMAX 32 -void print_packet(const char *label, apacket *p) -{ - char *tag; - char *x; - unsigned count; - - switch(p->msg.command){ - case A_SYNC: tag = "SYNC"; break; - case A_CNXN: tag = "CNXN" ; break; - case A_OPEN: tag = "OPEN"; break; - case A_OKAY: tag = "OKAY"; break; - case A_CLSE: tag = "CLSE"; break; - case A_WRTE: tag = "WRTE"; break; - default: tag = "????"; break; - } - - fprintf(stderr, "%s: %s %08x %08x %04x \"", - label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length); - count = p->msg.data_length; - x = (char*) p->data; - if(count > DUMPMAX) { - count = DUMPMAX; - tag = "\n"; - } else { - tag = "\"\n"; - } - while(count-- > 0){ - if((*x >= ' ') && (*x < 127)) { - fputc(*x, stderr); - } else { - fputc('.', stderr); - } - x++; - } - fprintf(stderr, tag); -} -#endif - -static void send_ready(unsigned local, unsigned remote, atransport *t) -{ - D("Calling send_ready \n"); - apacket *p = get_apacket(); - p->msg.command = A_OKAY; - p->msg.arg0 = local; - p->msg.arg1 = remote; - send_packet(p, t); -} - -static void send_close(unsigned local, unsigned remote, atransport *t) -{ - D("Calling send_close \n"); - apacket *p = get_apacket(); - p->msg.command = A_CLSE; - p->msg.arg0 = local; - p->msg.arg1 = remote; - send_packet(p, t); -} - -static void send_connect(atransport *t) -{ - D("Calling send_connect \n"); - apacket *cp = get_apacket(); - cp->msg.command = A_CNXN; - cp->msg.arg0 = A_VERSION; - cp->msg.arg1 = MAX_PAYLOAD; - snprintf((char*) cp->data, sizeof cp->data, "%s::", - HOST ? "host" : adb_device_banner); - cp->msg.data_length = strlen((char*) cp->data) + 1; - send_packet(cp, t); -} - -void parse_banner(char *banner, atransport *t) -{ - char *type, *product, *end; - - D("parse_banner: %s\n", banner); - type = banner; - product = strchr(type, ':'); - if(product) { - *product++ = 0; - } else { - product = ""; - } - - /* remove trailing ':' */ - end = strchr(product, ':'); - if(end) *end = 0; - - /* save product name in device structure */ - if (t->product == NULL) { - t->product = strdup(product); - } else if (strcmp(product, t->product) != 0) { - free(t->product); - t->product = strdup(product); - } - - if(!strcmp(type, "bootloader")){ - D("setting connection_state to CS_BOOTLOADER\n"); - t->connection_state = CS_BOOTLOADER; - update_transports(); - return; - } - - if(!strcmp(type, "device")) { - D("setting connection_state to CS_DEVICE\n"); - t->connection_state = CS_DEVICE; - update_transports(); - return; - } - - if(!strcmp(type, "recovery")) { - D("setting connection_state to CS_RECOVERY\n"); - t->connection_state = CS_RECOVERY; - update_transports(); - return; - } - - if(!strcmp(type, "sideload")) { - D("setting connection_state to CS_SIDELOAD\n"); - t->connection_state = CS_SIDELOAD; - update_transports(); - return; - } - - t->connection_state = CS_HOST; -} - -void handle_packet(apacket *p, atransport *t) -{ - asocket *s; - - D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0], - ((char*) (&(p->msg.command)))[1], - ((char*) (&(p->msg.command)))[2], - ((char*) (&(p->msg.command)))[3]); - print_packet("recv", p); - - switch(p->msg.command){ - case A_SYNC: - if(p->msg.arg0){ - send_packet(p, t); - if(HOST) send_connect(t); - } else { - t->connection_state = CS_OFFLINE; - handle_offline(t); - send_packet(p, t); - } - return; - - case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */ - /* XXX verify version, etc */ - if(t->connection_state != CS_OFFLINE) { - t->connection_state = CS_OFFLINE; - handle_offline(t); - } - parse_banner((char*) p->data, t); - handle_online(); - if(!HOST) send_connect(t); - break; - - case A_OPEN: /* OPEN(local-id, 0, "destination") */ - if(t->connection_state != CS_OFFLINE) { - char *name = (char*) p->data; - name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0; - s = create_local_service_socket(name); - if(s == 0) { - send_close(0, p->msg.arg0, t); - } else { - s->peer = create_remote_socket(p->msg.arg0, t); - s->peer->peer = s; - send_ready(s->id, s->peer->id, t); - s->ready(s); - } - } - break; - - case A_OKAY: /* READY(local-id, remote-id, "") */ - if(t->connection_state != CS_OFFLINE) { - if((s = find_local_socket(p->msg.arg1))) { - if(s->peer == 0) { - s->peer = create_remote_socket(p->msg.arg0, t); - s->peer->peer = s; - } - s->ready(s); - } - } - break; - - case A_CLSE: /* CLOSE(local-id, remote-id, "") */ - if(t->connection_state != CS_OFFLINE) { - if((s = find_local_socket(p->msg.arg1))) { - s->close(s); - } - } - break; - - case A_WRTE: - if(t->connection_state != CS_OFFLINE) { - if((s = find_local_socket(p->msg.arg1))) { - unsigned rid = p->msg.arg0; - p->len = p->msg.data_length; - - if(s->enqueue(s, p) == 0) { - D("Enqueue the socket\n"); - send_ready(s->id, rid, t); - } - return; - } - } - break; - - default: - printf("handle_packet: what is %08x?!\n", p->msg.command); - } - - put_apacket(p); -} - -static void adb_cleanup(void) -{ - usb_cleanup(); -} - -int adb_main(const char* path) -{ - strcpy(ADB_SIDELOAD_FILENAME, path); - atexit(adb_cleanup); -#if defined(HAVE_FORKEXEC) - // No SIGCHLD. Let the service subproc handle its children. - signal(SIGPIPE, SIG_IGN); -#endif - - init_transport_registration(); - - // The minimal version of adbd only uses USB. - if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) { - // listen on USB - usb_init(); - } - -/* Remove this so that perms work properly - if (setgid(AID_SHELL) != 0) { - fprintf(stderr, "failed to setgid to shell\n"); - exit(1); - } - if (setuid(AID_SHELL) != 0) { - fprintf(stderr, "failed to setuid to shell\n"); - exit(1); - } - - fprintf(stderr, "userid is %d\n", getuid()); -*/ - - D("Event loop starting\n"); - - fdevent_loop(); - - usb_cleanup(); - - return 0; -} diff --git a/minadbd21/adb.h b/minadbd21/adb.h deleted file mode 100644 index 08ee989d..00000000 --- a/minadbd21/adb.h +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright (C) 2007 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 __ADB_H -#define __ADB_H - -#include - -#include "transport.h" /* readx(), writex() */ -#include "fdevent.h" - -#define MAX_PAYLOAD 4096 - -#define A_SYNC 0x434e5953 -#define A_CNXN 0x4e584e43 -#define A_OPEN 0x4e45504f -#define A_OKAY 0x59414b4f -#define A_CLSE 0x45534c43 -#define A_WRTE 0x45545257 - -#define A_VERSION 0x01000000 // ADB protocol version - -#define ADB_VERSION_MAJOR 1 // Used for help/version information -#define ADB_VERSION_MINOR 0 // Used for help/version information - -#define ADB_SERVER_VERSION 29 // Increment this when we want to force users to start a new adb server - -typedef struct amessage amessage; -typedef struct apacket apacket; -typedef struct asocket asocket; -typedef struct aservice aservice; -typedef struct atransport atransport; -typedef struct adisconnect adisconnect; -typedef struct usb_handle usb_handle; - -struct amessage { - unsigned command; /* command identifier constant */ - unsigned arg0; /* first argument */ - unsigned arg1; /* second argument */ - unsigned data_length; /* length of payload (0 is allowed) */ - unsigned data_check; /* checksum of data payload */ - unsigned magic; /* command ^ 0xffffffff */ -}; - -struct apacket -{ - apacket *next; - - unsigned len; - unsigned char *ptr; - - amessage msg; - unsigned char data[MAX_PAYLOAD]; -}; - -/* An asocket represents one half of a connection between a local and -** remote entity. A local asocket is bound to a file descriptor. A -** remote asocket is bound to the protocol engine. -*/ -struct asocket { - /* chain pointers for the local/remote list of - ** asockets that this asocket lives in - */ - asocket *next; - asocket *prev; - - /* the unique identifier for this asocket - */ - unsigned id; - - /* flag: set when the socket's peer has closed - ** but packets are still queued for delivery - */ - int closing; - - /* the asocket we are connected to - */ - - asocket *peer; - - /* For local asockets, the fde is used to bind - ** us to our fd event system. For remote asockets - ** these fields are not used. - */ - fdevent fde; - int fd; - - /* queue of apackets waiting to be written - */ - apacket *pkt_first; - apacket *pkt_last; - - /* enqueue is called by our peer when it has data - ** for us. It should return 0 if we can accept more - ** data or 1 if not. If we return 1, we must call - ** peer->ready() when we once again are ready to - ** receive data. - */ - int (*enqueue)(asocket *s, apacket *pkt); - - /* ready is called by the peer when it is ready for - ** us to send data via enqueue again - */ - void (*ready)(asocket *s); - - /* close is called by the peer when it has gone away. - ** we are not allowed to make any further calls on the - ** peer once our close method is called. - */ - void (*close)(asocket *s); - - /* socket-type-specific extradata */ - void *extra; - - /* A socket is bound to atransport */ - atransport *transport; -}; - - -/* the adisconnect structure is used to record a callback that -** will be called whenever a transport is disconnected (e.g. by the user) -** this should be used to cleanup objects that depend on the -** transport (e.g. remote sockets, etc...) -*/ -struct adisconnect -{ - void (*func)(void* opaque, atransport* t); - void* opaque; - adisconnect* next; - adisconnect* prev; -}; - - -/* a transport object models the connection to a remote device or emulator -** there is one transport per connected device/emulator. a "local transport" -** connects through TCP (for the emulator), while a "usb transport" through -** USB (for real devices) -** -** note that kTransportHost doesn't really correspond to a real transport -** object, it's a special value used to indicate that a client wants to -** connect to a service implemented within the ADB server itself. -*/ -typedef enum transport_type { - kTransportUsb, - kTransportLocal, - kTransportAny, - kTransportHost, -} transport_type; - -struct atransport -{ - atransport *next; - atransport *prev; - - int (*read_from_remote)(apacket *p, atransport *t); - int (*write_to_remote)(apacket *p, atransport *t); - void (*close)(atransport *t); - void (*kick)(atransport *t); - - int fd; - int transport_socket; - fdevent transport_fde; - int ref_count; - unsigned sync_token; - int connection_state; - transport_type type; - - /* usb handle or socket fd as needed */ - usb_handle *usb; - int sfd; - - /* used to identify transports for clients */ - char *serial; - char *product; - int adb_port; // Use for emulators (local transport) - - /* a list of adisconnect callbacks called when the transport is kicked */ - int kicked; - adisconnect disconnects; -}; - - -void print_packet(const char *label, apacket *p); - -asocket *find_local_socket(unsigned id); -void install_local_socket(asocket *s); -void remove_socket(asocket *s); -void close_all_sockets(atransport *t); - -#define LOCAL_CLIENT_PREFIX "emulator-" - -asocket *create_local_socket(int fd); -asocket *create_local_service_socket(const char *destination); - -asocket *create_remote_socket(unsigned id, atransport *t); -void connect_to_remote(asocket *s, const char *destination); -void connect_to_smartsocket(asocket *s); - -void fatal(const char *fmt, ...); -void fatal_errno(const char *fmt, ...); - -void handle_packet(apacket *p, atransport *t); -void send_packet(apacket *p, atransport *t); - -void get_my_path(char *s, size_t maxLen); -int launch_server(int server_port); -int adb_main(const char* path); - - -/* transports are ref-counted -** get_device_transport does an acquire on your behalf before returning -*/ -void init_transport_registration(void); -int list_transports(char *buf, size_t bufsize); -void update_transports(void); - -asocket* create_device_tracker(void); - -/* Obtain a transport from the available transports. -** If state is != CS_ANY, only transports in that state are considered. -** If serial is non-NULL then only the device with that serial will be chosen. -** If no suitable transport is found, error is set. -*/ -atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out); -void add_transport_disconnect( atransport* t, adisconnect* dis ); -void remove_transport_disconnect( atransport* t, adisconnect* dis ); -void run_transport_disconnects( atransport* t ); -void kick_transport( atransport* t ); - -/* initialize a transport object's func pointers and state */ -#if ADB_HOST -int get_available_local_transport_index(); -#endif -void init_usb_transport(atransport *t, usb_handle *usb, int state); - -/* for MacOS X cleanup */ -void close_usb_devices(); - -/* these should only be used for the "adb disconnect" command */ -void unregister_transport(atransport *t); -void unregister_all_tcp_transports(); - -void register_usb_transport(usb_handle *h, const char *serial, unsigned writeable); - -/* this should only be used for transports with connection_state == CS_NOPERM */ -void unregister_usb_transport(usb_handle *usb); - -atransport *find_transport(const char *serial); -#if ADB_HOST -atransport* find_emulator_transport_by_adb_port(int adb_port); -#endif - -int service_to_fd(const char *name); -#if ADB_HOST -asocket *host_service_to_socket(const char* name, const char *serial); -#endif - -#if !ADB_HOST -typedef enum { - BACKUP, - RESTORE -} BackupOperation; -int backup_service(BackupOperation operation, char* args); -void framebuffer_service(int fd, void *cookie); -void log_service(int fd, void *cookie); -void remount_service(int fd, void *cookie); -char * get_log_file_path(const char * log_name); -#endif - -/* packet allocator */ -apacket *get_apacket(void); -void put_apacket(apacket *p); - -int check_header(apacket *p); -int check_data(apacket *p); - -/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */ - -#define ADB_TRACE 1 - -/* IMPORTANT: if you change the following list, don't - * forget to update the corresponding 'tags' table in - * the adb_trace_init() function implemented in adb.c - */ -typedef enum { - TRACE_ADB = 0, /* 0x001 */ - TRACE_SOCKETS, - TRACE_PACKETS, - TRACE_TRANSPORT, - TRACE_RWX, /* 0x010 */ - TRACE_USB, - TRACE_SYNC, - TRACE_SYSDEPS, - TRACE_JDWP, /* 0x100 */ - TRACE_SERVICES, -} AdbTrace; - -#if ADB_TRACE - - extern int adb_trace_mask; - extern unsigned char adb_trace_output_count; - void adb_trace_init(void); - -# define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0) - - /* you must define TRACE_TAG before using this macro */ -# define D(...) \ - do { \ - if (ADB_TRACING) { \ - int save_errno = errno; \ - adb_mutex_lock(&D_lock); \ - fprintf(stderr, "%s::%s():", \ - __FILE__, __FUNCTION__); \ - errno = save_errno; \ - fprintf(stderr, __VA_ARGS__ ); \ - fflush(stderr); \ - adb_mutex_unlock(&D_lock); \ - errno = save_errno; \ - } \ - } while (0) -# define DR(...) \ - do { \ - if (ADB_TRACING) { \ - int save_errno = errno; \ - adb_mutex_lock(&D_lock); \ - errno = save_errno; \ - fprintf(stderr, __VA_ARGS__ ); \ - fflush(stderr); \ - adb_mutex_unlock(&D_lock); \ - errno = save_errno; \ - } \ - } while (0) -#else -# define D(...) ((void)0) -# define DR(...) ((void)0) -# define ADB_TRACING 0 -#endif - - -#if !TRACE_PACKETS -#define print_packet(tag,p) do {} while (0) -#endif - -#if ADB_HOST_ON_TARGET -/* adb and adbd are coexisting on the target, so use 5038 for adb - * to avoid conflicting with adbd's usage of 5037 - */ -# define DEFAULT_ADB_PORT 5038 -#else -# define DEFAULT_ADB_PORT 5037 -#endif - -#define DEFAULT_ADB_LOCAL_TRANSPORT_PORT 5555 - -#define ADB_CLASS 0xff -#define ADB_SUBCLASS 0x42 -#define ADB_PROTOCOL 0x1 - - -void local_init(int port); -int local_connect(int port); -int local_connect_arbitrary_ports(int console_port, int adb_port); - -/* usb host/client interface */ -void usb_init(); -void usb_cleanup(); -int usb_write(usb_handle *h, const void *data, int len); -int usb_read(usb_handle *h, void *data, int len); -int usb_close(usb_handle *h); -void usb_kick(usb_handle *h); - -/* used for USB device detection */ -#if ADB_HOST -int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol); -#endif - -unsigned host_to_le32(unsigned n); -int adb_commandline(int argc, char **argv); - -int connection_state(atransport *t); - -#define CS_ANY -1 -#define CS_OFFLINE 0 -#define CS_BOOTLOADER 1 -#define CS_DEVICE 2 -#define CS_HOST 3 -#define CS_RECOVERY 4 -#define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */ -#define CS_SIDELOAD 6 -#define CS_UNAUTHORIZED 7 - -extern int HOST; -extern int SHELL_EXIT_NOTIFY_FD; - -#define CHUNK_SIZE (64*1024) - -#if !ADB_HOST -#define USB_ADB_PATH "/dev/android_adb" - -#define USB_FFS_ADB_PATH "/dev/usb-ffs/adb/" -#define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH#x - -#define USB_FFS_ADB_EP0 USB_FFS_ADB_EP(ep0) -#define USB_FFS_ADB_OUT USB_FFS_ADB_EP(ep1) -#define USB_FFS_ADB_IN USB_FFS_ADB_EP(ep2) -#endif - -int sendfailmsg(int fd, const char *reason); -int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s); - -//#define ADB_SIDELOAD_FILENAME "/tmp/update.zip" -extern char ADB_SIDELOAD_FILENAME[255]; - -#endif diff --git a/minadbd21/fdevent.c b/minadbd21/fdevent.c deleted file mode 100644 index 5c374a71..00000000 --- a/minadbd21/fdevent.c +++ /dev/null @@ -1,695 +0,0 @@ -/* http://frotznet.googlecode.com/svn/trunk/utils/fdevent.c -** -** Copyright 2006, Brian Swetland -** -** 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 - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "fdevent.h" -#include "transport.h" -#include "sysdeps.h" - - -/* !!! Do not enable DEBUG for the adb that will run as the server: -** both stdout and stderr are used to communicate between the client -** and server. Any extra output will cause failures. -*/ -#define DEBUG 0 /* non-0 will break adb server */ - -// This socket is used when a subproc shell service exists. -// It wakes up the fdevent_loop() and cause the correct handling -// of the shell's pseudo-tty master. I.e. force close it. -int SHELL_EXIT_NOTIFY_FD = -1; - -static void fatal(const char *fn, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "%s:", fn); - vfprintf(stderr, fmt, ap); - va_end(ap); - abort(); -} - -#define FATAL(x...) fatal(__FUNCTION__, x) - -#if DEBUG -#define D(...) \ - do { \ - adb_mutex_lock(&D_lock); \ - int save_errno = errno; \ - fprintf(stderr, "%s::%s():", __FILE__, __FUNCTION__); \ - errno = save_errno; \ - fprintf(stderr, __VA_ARGS__); \ - adb_mutex_unlock(&D_lock); \ - errno = save_errno; \ - } while(0) -static void dump_fde(fdevent *fde, const char *info) -{ - adb_mutex_lock(&D_lock); - fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd, - fde->state & FDE_READ ? 'R' : ' ', - fde->state & FDE_WRITE ? 'W' : ' ', - fde->state & FDE_ERROR ? 'E' : ' ', - info); - adb_mutex_unlock(&D_lock); -} -#else -#define D(...) ((void)0) -#define dump_fde(fde, info) do { } while(0) -#endif - -#define FDE_EVENTMASK 0x00ff -#define FDE_STATEMASK 0xff00 - -#define FDE_ACTIVE 0x0100 -#define FDE_PENDING 0x0200 -#define FDE_CREATED 0x0400 - -static void fdevent_plist_enqueue(fdevent *node); -static void fdevent_plist_remove(fdevent *node); -static fdevent *fdevent_plist_dequeue(void); -static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata); - -static fdevent list_pending = { - .next = &list_pending, - .prev = &list_pending, -}; - -static fdevent **fd_table = 0; -static int fd_table_max = 0; - -#ifdef CRAPTASTIC -//HAVE_EPOLL - -#include - -static int epoll_fd = -1; - -static void fdevent_init() -{ - /* XXX: what's a good size for the passed in hint? */ - epoll_fd = epoll_create(256); - - if(epoll_fd < 0) { - perror("epoll_create() failed"); - exit(1); - } - - /* mark for close-on-exec */ - fcntl(epoll_fd, F_SETFD, FD_CLOEXEC); -} - -static void fdevent_connect(fdevent *fde) -{ - struct epoll_event ev; - - memset(&ev, 0, sizeof(ev)); - ev.events = 0; - ev.data.ptr = fde; - -#if 0 - if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) { - perror("epoll_ctl() failed\n"); - exit(1); - } -#endif -} - -static void fdevent_disconnect(fdevent *fde) -{ - struct epoll_event ev; - - memset(&ev, 0, sizeof(ev)); - ev.events = 0; - ev.data.ptr = fde; - - /* technically we only need to delete if we - ** were actively monitoring events, but let's - ** be aggressive and do it anyway, just in case - ** something's out of sync - */ - epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev); -} - -static void fdevent_update(fdevent *fde, unsigned events) -{ - struct epoll_event ev; - int active; - - active = (fde->state & FDE_EVENTMASK) != 0; - - memset(&ev, 0, sizeof(ev)); - ev.events = 0; - ev.data.ptr = fde; - - if(events & FDE_READ) ev.events |= EPOLLIN; - if(events & FDE_WRITE) ev.events |= EPOLLOUT; - if(events & FDE_ERROR) ev.events |= (EPOLLERR | EPOLLHUP); - - fde->state = (fde->state & FDE_STATEMASK) | events; - - if(active) { - /* we're already active. if we're changing to *no* - ** events being monitored, we need to delete, otherwise - ** we need to just modify - */ - if(ev.events) { - if(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fde->fd, &ev)) { - perror("epoll_ctl() failed\n"); - exit(1); - } - } else { - if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev)) { - perror("epoll_ctl() failed\n"); - exit(1); - } - } - } else { - /* we're not active. if we're watching events, we need - ** to add, otherwise we can just do nothing - */ - if(ev.events) { - if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) { - perror("epoll_ctl() failed\n"); - exit(1); - } - } - } -} - -static void fdevent_process() -{ - struct epoll_event events[256]; - fdevent *fde; - int i, n; - - n = epoll_wait(epoll_fd, events, 256, -1); - - if(n < 0) { - if(errno == EINTR) return; - perror("epoll_wait"); - exit(1); - } - - for(i = 0; i < n; i++) { - struct epoll_event *ev = events + i; - fde = ev->data.ptr; - - if(ev->events & EPOLLIN) { - fde->events |= FDE_READ; - } - if(ev->events & EPOLLOUT) { - fde->events |= FDE_WRITE; - } - if(ev->events & (EPOLLERR | EPOLLHUP)) { - fde->events |= FDE_ERROR; - } - if(fde->events) { - if(fde->state & FDE_PENDING) continue; - fde->state |= FDE_PENDING; - fdevent_plist_enqueue(fde); - } - } -} - -#else /* USE_SELECT */ - -#ifdef HAVE_WINSOCK -#include -#else -#include -#endif - -static fd_set read_fds; -static fd_set write_fds; -static fd_set error_fds; - -static int select_n = 0; - -static void fdevent_init(void) -{ - FD_ZERO(&read_fds); - FD_ZERO(&write_fds); - FD_ZERO(&error_fds); -} - -static void fdevent_connect(fdevent *fde) -{ - if(fde->fd >= select_n) { - select_n = fde->fd + 1; - } -} - -static void fdevent_disconnect(fdevent *fde) -{ - int i, n; - - FD_CLR(fde->fd, &read_fds); - FD_CLR(fde->fd, &write_fds); - FD_CLR(fde->fd, &error_fds); - - for(n = 0, i = 0; i < select_n; i++) { - if(fd_table[i] != 0) n = i; - } - select_n = n + 1; -} - -static void fdevent_update(fdevent *fde, unsigned events) -{ - if(events & FDE_READ) { - FD_SET(fde->fd, &read_fds); - } else { - FD_CLR(fde->fd, &read_fds); - } - if(events & FDE_WRITE) { - FD_SET(fde->fd, &write_fds); - } else { - FD_CLR(fde->fd, &write_fds); - } - if(events & FDE_ERROR) { - FD_SET(fde->fd, &error_fds); - } else { - FD_CLR(fde->fd, &error_fds); - } - - fde->state = (fde->state & FDE_STATEMASK) | events; -} - -/* Looks at fd_table[] for bad FDs and sets bit in fds. -** Returns the number of bad FDs. -*/ -static int fdevent_fd_check(fd_set *fds) -{ - int i, n = 0; - fdevent *fde; - - for(i = 0; i < select_n; i++) { - fde = fd_table[i]; - if(fde == 0) continue; - if(fcntl(i, F_GETFL, NULL) < 0) { - FD_SET(i, fds); - n++; - // fde->state |= FDE_DONT_CLOSE; - - } - } - return n; -} - -#if !DEBUG -static inline void dump_all_fds(const char *extra_msg) {} -#else -static void dump_all_fds(const char *extra_msg) -{ -int i; - fdevent *fde; - // per fd: 4 digits (but really: log10(FD_SETSIZE)), 1 staus, 1 blank - char msg_buff[FD_SETSIZE*6 + 1], *pb=msg_buff; - size_t max_chars = FD_SETSIZE * 6 + 1; - int printed_out; -#define SAFE_SPRINTF(...) \ - do { \ - printed_out = snprintf(pb, max_chars, __VA_ARGS__); \ - if (printed_out <= 0) { \ - D("... snprintf failed.\n"); \ - return; \ - } \ - if (max_chars < (unsigned int)printed_out) { \ - D("... snprintf out of space.\n"); \ - return; \ - } \ - pb += printed_out; \ - max_chars -= printed_out; \ - } while(0) - - for(i = 0; i < select_n; i++) { - fde = fd_table[i]; - SAFE_SPRINTF("%d", i); - if(fde == 0) { - SAFE_SPRINTF("? "); - continue; - } - if(fcntl(i, F_GETFL, NULL) < 0) { - SAFE_SPRINTF("b"); - } - SAFE_SPRINTF(" "); - } - D("%s fd_table[]->fd = {%s}\n", extra_msg, msg_buff); -} -#endif - -static void fdevent_process() -{ - int i, n; - fdevent *fde; - unsigned events; - fd_set rfd, wfd, efd; - - memcpy(&rfd, &read_fds, sizeof(fd_set)); - memcpy(&wfd, &write_fds, sizeof(fd_set)); - memcpy(&efd, &error_fds, sizeof(fd_set)); - - dump_all_fds("pre select()"); - - n = select(select_n, &rfd, &wfd, &efd, NULL); - int saved_errno = errno; - D("select() returned n=%d, errno=%d\n", n, n<0?saved_errno:0); - - dump_all_fds("post select()"); - - if(n < 0) { - switch(saved_errno) { - case EINTR: return; - case EBADF: - // Can't trust the FD sets after an error. - FD_ZERO(&wfd); - FD_ZERO(&efd); - FD_ZERO(&rfd); - break; - default: - D("Unexpected select() error=%d\n", saved_errno); - return; - } - } - if(n <= 0) { - // We fake a read, as the rest of the code assumes - // that errors will be detected at that point. - n = fdevent_fd_check(&rfd); - } - - for(i = 0; (i < select_n) && (n > 0); i++) { - events = 0; - if(FD_ISSET(i, &rfd)) { events |= FDE_READ; n--; } - if(FD_ISSET(i, &wfd)) { events |= FDE_WRITE; n--; } - if(FD_ISSET(i, &efd)) { events |= FDE_ERROR; n--; } - - if(events) { - fde = fd_table[i]; - if(fde == 0) - FATAL("missing fde for fd %d\n", i); - - fde->events |= events; - - D("got events fde->fd=%d events=%04x, state=%04x\n", - fde->fd, fde->events, fde->state); - if(fde->state & FDE_PENDING) continue; - fde->state |= FDE_PENDING; - fdevent_plist_enqueue(fde); - } - } -} - -#endif - -static void fdevent_register(fdevent *fde) -{ - if(fde->fd < 0) { - FATAL("bogus negative fd (%d)\n", fde->fd); - } - - if(fde->fd >= fd_table_max) { - int oldmax = fd_table_max; - if(fde->fd > 32000) { - FATAL("bogus huuuuge fd (%d)\n", fde->fd); - } - if(fd_table_max == 0) { - fdevent_init(); - fd_table_max = 256; - } - while(fd_table_max <= fde->fd) { - fd_table_max *= 2; - } - fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max); - if(fd_table == 0) { - FATAL("could not expand fd_table to %d entries\n", fd_table_max); - } - memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax)); - } - - fd_table[fde->fd] = fde; -} - -static void fdevent_unregister(fdevent *fde) -{ - if((fde->fd < 0) || (fde->fd >= fd_table_max)) { - FATAL("fd out of range (%d)\n", fde->fd); - } - - if(fd_table[fde->fd] != fde) { - FATAL("fd_table out of sync [%d]\n", fde->fd); - } - - fd_table[fde->fd] = 0; - - if(!(fde->state & FDE_DONT_CLOSE)) { - dump_fde(fde, "close"); - adb_close(fde->fd); - } -} - -static void fdevent_plist_enqueue(fdevent *node) -{ - fdevent *list = &list_pending; - - node->next = list; - node->prev = list->prev; - node->prev->next = node; - list->prev = node; -} - -static void fdevent_plist_remove(fdevent *node) -{ - node->prev->next = node->next; - node->next->prev = node->prev; - node->next = 0; - node->prev = 0; -} - -static fdevent *fdevent_plist_dequeue(void) -{ - fdevent *list = &list_pending; - fdevent *node = list->next; - - if(node == list) return 0; - - list->next = node->next; - list->next->prev = list; - node->next = 0; - node->prev = 0; - - return node; -} - -static void fdevent_call_fdfunc(fdevent* fde) -{ - unsigned events = fde->events; - fde->events = 0; - if(!(fde->state & FDE_PENDING)) return; - fde->state &= (~FDE_PENDING); - dump_fde(fde, "callback"); - fde->func(fde->fd, events, fde->arg); -} - -static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata) -{ - - D("subproc handling on fd=%d ev=%04x\n", fd, ev); - - // Hook oneself back into the fde's suitable for select() on read. - if((fd < 0) || (fd >= fd_table_max)) { - FATAL("fd %d out of range for fd_table \n", fd); - } - fdevent *fde = fd_table[fd]; - fdevent_add(fde, FDE_READ); - - if(ev & FDE_READ){ - int subproc_fd; - - if(readx(fd, &subproc_fd, sizeof(subproc_fd))) { - FATAL("Failed to read the subproc's fd from fd=%d\n", fd); - } - if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) { - D("subproc_fd %d out of range 0, fd_table_max=%d\n", - subproc_fd, fd_table_max); - return; - } - fdevent *subproc_fde = fd_table[subproc_fd]; - if(!subproc_fde) { - D("subproc_fd %d cleared from fd_table\n", subproc_fd); - return; - } - if(subproc_fde->fd != subproc_fd) { - // Already reallocated? - D("subproc_fd %d != fd_table[].fd %d\n", subproc_fd, subproc_fde->fd); - return; - } - - subproc_fde->force_eof = 1; - - int rcount = 0; - ioctl(subproc_fd, FIONREAD, &rcount); - D("subproc with fd=%d has rcount=%d err=%d\n", - subproc_fd, rcount, errno); - - if(rcount) { - // If there is data left, it will show up in the select(). - // This works because there is no other thread reading that - // data when in this fd_func(). - return; - } - - D("subproc_fde.state=%04x\n", subproc_fde->state); - subproc_fde->events |= FDE_READ; - if(subproc_fde->state & FDE_PENDING) { - return; - } - subproc_fde->state |= FDE_PENDING; - fdevent_call_fdfunc(subproc_fde); - } -} - -fdevent *fdevent_create(int fd, fd_func func, void *arg) -{ - fdevent *fde = (fdevent*) malloc(sizeof(fdevent)); - if(fde == 0) return 0; - fdevent_install(fde, fd, func, arg); - fde->state |= FDE_CREATED; - return fde; -} - -void fdevent_destroy(fdevent *fde) -{ - if(fde == 0) return; - if(!(fde->state & FDE_CREATED)) { - FATAL("fde %p not created by fdevent_create()\n", fde); - } - fdevent_remove(fde); -} - -void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg) -{ - memset(fde, 0, sizeof(fdevent)); - fde->state = FDE_ACTIVE; - fde->fd = fd; - fde->force_eof = 0; - fde->func = func; - fde->arg = arg; - -#ifndef HAVE_WINSOCK - fcntl(fd, F_SETFL, O_NONBLOCK); -#endif - fdevent_register(fde); - dump_fde(fde, "connect"); - fdevent_connect(fde); - fde->state |= FDE_ACTIVE; -} - -void fdevent_remove(fdevent *fde) -{ - if(fde->state & FDE_PENDING) { - fdevent_plist_remove(fde); - } - - if(fde->state & FDE_ACTIVE) { - fdevent_disconnect(fde); - dump_fde(fde, "disconnect"); - fdevent_unregister(fde); - } - - fde->state = 0; - fde->events = 0; -} - - -void fdevent_set(fdevent *fde, unsigned events) -{ - events &= FDE_EVENTMASK; - - if((fde->state & FDE_EVENTMASK) == events) return; - - if(fde->state & FDE_ACTIVE) { - fdevent_update(fde, events); - dump_fde(fde, "update"); - } - - fde->state = (fde->state & FDE_STATEMASK) | events; - - if(fde->state & FDE_PENDING) { - /* if we're pending, make sure - ** we don't signal an event that - ** is no longer wanted. - */ - fde->events &= (~events); - if(fde->events == 0) { - fdevent_plist_remove(fde); - fde->state &= (~FDE_PENDING); - } - } -} - -void fdevent_add(fdevent *fde, unsigned events) -{ - fdevent_set( - fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK)); -} - -void fdevent_del(fdevent *fde, unsigned events) -{ - fdevent_set( - fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK))); -} - -void fdevent_subproc_setup() -{ - int s[2]; - - if(adb_socketpair(s)) { - FATAL("cannot create shell-exit socket-pair\n"); - } - SHELL_EXIT_NOTIFY_FD = s[0]; - fdevent *fde; - fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL); - if(!fde) - FATAL("cannot create fdevent for shell-exit handler\n"); - fdevent_add(fde, FDE_READ); -} - -void fdevent_loop() -{ - fdevent *fde; - fdevent_subproc_setup(); - - for(;;) { - D("--- ---- waiting for events\n"); - - fdevent_process(); - - while((fde = fdevent_plist_dequeue())) { - fdevent_call_fdfunc(fde); - } - } -} diff --git a/minadbd21/fdevent.h b/minadbd21/fdevent.h deleted file mode 100644 index a0ebe2a7..00000000 --- a/minadbd21/fdevent.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2006 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 __FDEVENT_H -#define __FDEVENT_H - -#include /* for int64_t */ - -/* events that may be observed */ -#define FDE_READ 0x0001 -#define FDE_WRITE 0x0002 -#define FDE_ERROR 0x0004 -#define FDE_TIMEOUT 0x0008 - -/* features that may be set (via the events set/add/del interface) */ -#define FDE_DONT_CLOSE 0x0080 - -typedef struct fdevent fdevent; - -typedef void (*fd_func)(int fd, unsigned events, void *userdata); - -/* Allocate and initialize a new fdevent object - * Note: use FD_TIMER as 'fd' to create a fd-less object - * (used to implement timers). -*/ -fdevent *fdevent_create(int fd, fd_func func, void *arg); - -/* Uninitialize and deallocate an fdevent object that was -** created by fdevent_create() -*/ -void fdevent_destroy(fdevent *fde); - -/* Initialize an fdevent object that was externally allocated -*/ -void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg); - -/* Uninitialize an fdevent object that was initialized by -** fdevent_install() -*/ -void fdevent_remove(fdevent *item); - -/* Change which events should cause notifications -*/ -void fdevent_set(fdevent *fde, unsigned events); -void fdevent_add(fdevent *fde, unsigned events); -void fdevent_del(fdevent *fde, unsigned events); - -void fdevent_set_timeout(fdevent *fde, int64_t timeout_ms); - -/* loop forever, handling events. -*/ -void fdevent_loop(); - -struct fdevent -{ - fdevent *next; - fdevent *prev; - - int fd; - int force_eof; - - unsigned short state; - unsigned short events; - - fd_func func; - void *arg; -}; - - -#endif diff --git a/minadbd21/fuse_adb_provider.c b/minadbd21/fuse_adb_provider.c deleted file mode 100644 index 18e99068..00000000 --- a/minadbd21/fuse_adb_provider.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2014 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 -#include -#include - -#include "adb.h" -#include "fuse_sideload.h" - -struct adb_data { - int sfd; // file descriptor for the adb channel - - uint64_t file_size; - uint32_t block_size; -}; - -static int read_block_adb(void* cookie, uint32_t block, uint8_t* buffer, uint32_t fetch_size) { - struct adb_data* ad = (struct adb_data*)cookie; - - char buf[10]; - snprintf(buf, sizeof(buf), "%08u", block); - if (writex(ad->sfd, buf, 8) < 0) { - fprintf(stderr, "failed to write to adb host: %s\n", strerror(errno)); - return -EIO; - } - - if (readx(ad->sfd, buffer, fetch_size) < 0) { - fprintf(stderr, "failed to read from adb host: %s\n", strerror(errno)); - return -EIO; - } - - return 0; -} - -static void close_adb(void* cookie) { - struct adb_data* ad = (struct adb_data*)cookie; - - writex(ad->sfd, "DONEDONE", 8); -} - -int run_adb_fuse(int sfd, uint64_t file_size, uint32_t block_size) { - struct adb_data ad; - struct provider_vtab vtab; - - ad.sfd = sfd; - ad.file_size = file_size; - ad.block_size = block_size; - - vtab.read_block = read_block_adb; - vtab.close = close_adb; - - return run_old_fuse_sideload(&vtab, &ad, file_size, block_size); -} diff --git a/minadbd21/mutex_list.h b/minadbd21/mutex_list.h deleted file mode 100644 index 652dd734..00000000 --- a/minadbd21/mutex_list.h +++ /dev/null @@ -1,26 +0,0 @@ -/* the list of mutexes used by adb */ -/* #ifndef __MUTEX_LIST_H - * Do not use an include-guard. This file is included once to declare the locks - * and once in win32 to actually do the runtime initialization. - */ -#ifndef ADB_MUTEX -#error ADB_MUTEX not defined when including this file -#endif -ADB_MUTEX(dns_lock) -ADB_MUTEX(socket_list_lock) -ADB_MUTEX(transport_lock) -#if ADB_HOST -ADB_MUTEX(local_transports_lock) -#endif -ADB_MUTEX(usb_lock) - -// Sadly logging to /data/adb/adb-... is not thread safe. -// After modifying adb.h::D() to count invocations: -// DEBUG(jpa):0:Handling main() -// DEBUG(jpa):1:[ usb_init - starting thread ] -// (Oopsies, no :2:, and matching message is also gone.) -// DEBUG(jpa):3:[ usb_thread - opening device ] -// DEBUG(jpa):4:jdwp control socket started (10) -ADB_MUTEX(D_lock) - -#undef ADB_MUTEX diff --git a/minadbd21/services.c b/minadbd21/services.c deleted file mode 100644 index 218b84a3..00000000 --- a/minadbd21/services.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2007 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 -#include -#include -#include -#include - -#include "sysdeps.h" -#include "fdevent.h" -#include "fuse_adb_provider.h" - -#define TRACE_TAG TRACE_SERVICES -#include "adb.h" - -typedef struct stinfo stinfo; - -struct stinfo { - void (*func)(int fd, void *cookie); - int fd; - void *cookie; -}; - - -void *service_bootstrap_func(void *x) -{ - stinfo *sti = x; - sti->func(sti->fd, sti->cookie); - free(sti); - return 0; -} - -static void sideload_host_service(int sfd, void* cookie) -{ - char* saveptr; - const char* s = strtok_r(cookie, ":", &saveptr); - uint64_t file_size = strtoull(s, NULL, 10); - s = strtok_r(NULL, ":", &saveptr); - uint32_t block_size = strtoul(s, NULL, 10); - - printf("sideload-host file size %llu block size %lu\n", file_size, block_size); - - int result = run_adb_fuse(sfd, file_size, block_size); - - printf("sideload_host finished\n"); - sleep(1); - exit(result == 0 ? 0 : 1); -} - -#if 0 -static void echo_service(int fd, void *cookie) -{ - char buf[4096]; - int r; - char *p; - int c; - - for(;;) { - r = read(fd, buf, 4096); - if(r == 0) goto done; - if(r < 0) { - if(errno == EINTR) continue; - else goto done; - } - - c = r; - p = buf; - while(c > 0) { - r = write(fd, p, c); - if(r > 0) { - c -= r; - p += r; - continue; - } - if((r < 0) && (errno == EINTR)) continue; - goto done; - } - } -done: - close(fd); -} -#endif - -static int create_service_thread(void (*func)(int, void *), void *cookie) -{ - stinfo *sti; - adb_thread_t t; - int s[2]; - - if(adb_socketpair(s)) { - printf("cannot create service socket pair\n"); - return -1; - } - - sti = malloc(sizeof(stinfo)); - if(sti == 0) fatal("cannot allocate stinfo"); - sti->func = func; - sti->cookie = cookie; - sti->fd = s[1]; - - if(adb_thread_create( &t, service_bootstrap_func, sti)){ - free(sti); - adb_close(s[0]); - adb_close(s[1]); - printf("cannot create service thread\n"); - return -1; - } - - D("service thread started, %d:%d\n",s[0], s[1]); - return s[0]; -} - -int service_to_fd(const char *name) -{ - int ret = -1; - - if (!strncmp(name, "sideload:", 9)) { - // this exit status causes recovery to print a special error - // message saying to use a newer adb (that supports - // sideload-host). - exit(3); - } else if (!strncmp(name, "sideload-host:", 14)) { - ret = create_service_thread(sideload_host_service, (void*)(name + 14)); -#if 0 - } else if(!strncmp(name, "echo:", 5)){ - ret = create_service_thread(echo_service, 0); -#endif - } - if (ret >= 0) { - close_on_exec(ret); - } - return ret; -} diff --git a/minadbd21/sockets.c b/minadbd21/sockets.c deleted file mode 100644 index 817410d1..00000000 --- a/minadbd21/sockets.c +++ /dev/null @@ -1,731 +0,0 @@ -/* - * Copyright (C) 2007 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 -#include -#include -#include -#include -#include - -#include "sysdeps.h" - -#define TRACE_TAG TRACE_SOCKETS -#include "adb.h" - -ADB_MUTEX_DEFINE( socket_list_lock ); - -static void local_socket_close_locked(asocket *s); - -int sendfailmsg(int fd, const char *reason) -{ - char buf[9]; - int len; - len = strlen(reason); - if(len > 0xffff) len = 0xffff; - snprintf(buf, sizeof buf, "FAIL%04x", len); - if(writex(fd, buf, 8)) return -1; - return writex(fd, reason, len); -} - -//extern int online; - -static unsigned local_socket_next_id = 1; - -static asocket local_socket_list = { - .next = &local_socket_list, - .prev = &local_socket_list, -}; - -/* the the list of currently closing local sockets. -** these have no peer anymore, but still packets to -** write to their fd. -*/ -static asocket local_socket_closing_list = { - .next = &local_socket_closing_list, - .prev = &local_socket_closing_list, -}; - -asocket *find_local_socket(unsigned id) -{ - asocket *s; - asocket *result = NULL; - - adb_mutex_lock(&socket_list_lock); - for (s = local_socket_list.next; s != &local_socket_list; s = s->next) { - if (s->id == id) { - result = s; - break; - } - } - adb_mutex_unlock(&socket_list_lock); - - return result; -} - -static void -insert_local_socket(asocket* s, asocket* list) -{ - s->next = list; - s->prev = s->next->prev; - s->prev->next = s; - s->next->prev = s; -} - - -void install_local_socket(asocket *s) -{ - adb_mutex_lock(&socket_list_lock); - - s->id = local_socket_next_id++; - insert_local_socket(s, &local_socket_list); - - adb_mutex_unlock(&socket_list_lock); -} - -void remove_socket(asocket *s) -{ - // socket_list_lock should already be held - if (s->prev && s->next) - { - s->prev->next = s->next; - s->next->prev = s->prev; - s->next = 0; - s->prev = 0; - s->id = 0; - } -} - -void close_all_sockets(atransport *t) -{ - asocket *s; - - /* this is a little gross, but since s->close() *will* modify - ** the list out from under you, your options are limited. - */ - adb_mutex_lock(&socket_list_lock); -restart: - for(s = local_socket_list.next; s != &local_socket_list; s = s->next){ - if(s->transport == t || (s->peer && s->peer->transport == t)) { - local_socket_close_locked(s); - goto restart; - } - } - adb_mutex_unlock(&socket_list_lock); -} - -static int local_socket_enqueue(asocket *s, apacket *p) -{ - D("LS(%d): enqueue %d\n", s->id, p->len); - - p->ptr = p->data; - - /* if there is already data queue'd, we will receive - ** events when it's time to write. just add this to - ** the tail - */ - if(s->pkt_first) { - goto enqueue; - } - - /* write as much as we can, until we - ** would block or there is an error/eof - */ - while(p->len > 0) { - int r = adb_write(s->fd, p->ptr, p->len); - if(r > 0) { - p->len -= r; - p->ptr += r; - continue; - } - if((r == 0) || (errno != EAGAIN)) { - D( "LS(%d): not ready, errno=%d: %s\n", s->id, errno, strerror(errno) ); - s->close(s); - return 1; /* not ready (error) */ - } else { - break; - } - } - - if(p->len == 0) { - put_apacket(p); - return 0; /* ready for more data */ - } - -enqueue: - p->next = 0; - if(s->pkt_first) { - s->pkt_last->next = p; - } else { - s->pkt_first = p; - } - s->pkt_last = p; - - /* make sure we are notified when we can drain the queue */ - fdevent_add(&s->fde, FDE_WRITE); - - return 1; /* not ready (backlog) */ -} - -static void local_socket_ready(asocket *s) -{ - /* far side is ready for data, pay attention to - readable events */ - fdevent_add(&s->fde, FDE_READ); -// D("LS(%d): ready()\n", s->id); -} - -static void local_socket_close(asocket *s) -{ - adb_mutex_lock(&socket_list_lock); - local_socket_close_locked(s); - adb_mutex_unlock(&socket_list_lock); -} - -// be sure to hold the socket list lock when calling this -static void local_socket_destroy(asocket *s) -{ - apacket *p, *n; - D("LS(%d): destroying fde.fd=%d\n", s->id, s->fde.fd); - - /* IMPORTANT: the remove closes the fd - ** that belongs to this socket - */ - fdevent_remove(&s->fde); - - /* dispose of any unwritten data */ - for(p = s->pkt_first; p; p = n) { - D("LS(%d): discarding %d bytes\n", s->id, p->len); - n = p->next; - put_apacket(p); - } - remove_socket(s); - free(s); -} - - -static void local_socket_close_locked(asocket *s) -{ - D("entered. LS(%d) fd=%d\n", s->id, s->fd); - if(s->peer) { - D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n", - s->id, s->peer->id, s->peer->fd); - s->peer->peer = 0; - // tweak to avoid deadlock - if (s->peer->close == local_socket_close) { - local_socket_close_locked(s->peer); - } else { - s->peer->close(s->peer); - } - s->peer = 0; - } - - /* If we are already closing, or if there are no - ** pending packets, destroy immediately - */ - if (s->closing || s->pkt_first == NULL) { - int id = s->id; - local_socket_destroy(s); - D("LS(%d): closed\n", id); - return; - } - - /* otherwise, put on the closing list - */ - D("LS(%d): closing\n", s->id); - s->closing = 1; - fdevent_del(&s->fde, FDE_READ); - remove_socket(s); - D("LS(%d): put on socket_closing_list fd=%d\n", s->id, s->fd); - insert_local_socket(s, &local_socket_closing_list); -} - -static void local_socket_event_func(int fd, unsigned ev, void *_s) -{ - asocket *s = _s; - - D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev); - - /* put the FDE_WRITE processing before the FDE_READ - ** in order to simplify the code. - */ - if(ev & FDE_WRITE){ - apacket *p; - - while((p = s->pkt_first) != 0) { - while(p->len > 0) { - int r = adb_write(fd, p->ptr, p->len); - if(r > 0) { - p->ptr += r; - p->len -= r; - continue; - } - if(r < 0) { - /* returning here is ok because FDE_READ will - ** be processed in the next iteration loop - */ - if(errno == EAGAIN) return; - if(errno == EINTR) continue; - } - D(" closing after write because r=%d and errno is %d\n", r, errno); - s->close(s); - return; - } - - if(p->len == 0) { - s->pkt_first = p->next; - if(s->pkt_first == 0) s->pkt_last = 0; - put_apacket(p); - } - } - - /* if we sent the last packet of a closing socket, - ** we can now destroy it. - */ - if (s->closing) { - D(" closing because 'closing' is set after write\n"); - s->close(s); - return; - } - - /* no more packets queued, so we can ignore - ** writable events again and tell our peer - ** to resume writing - */ - fdevent_del(&s->fde, FDE_WRITE); - s->peer->ready(s->peer); - } - - - if(ev & FDE_READ){ - apacket *p = get_apacket(); - unsigned char *x = p->data; - size_t avail = MAX_PAYLOAD; - int r; - int is_eof = 0; - - while(avail > 0) { - r = adb_read(fd, x, avail); - D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu\n", - s->id, s->fd, r, r<0?errno:0, avail); - if(r > 0) { - avail -= r; - x += r; - continue; - } - if(r < 0) { - if(errno == EAGAIN) break; - if(errno == EINTR) continue; - } - - /* r = 0 or unhandled error */ - is_eof = 1; - break; - } - D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n", - s->id, s->fd, r, is_eof, s->fde.force_eof); - if((avail == MAX_PAYLOAD) || (s->peer == 0)) { - put_apacket(p); - } else { - p->len = MAX_PAYLOAD - avail; - - r = s->peer->enqueue(s->peer, p); - D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r); - - if(r < 0) { - /* error return means they closed us as a side-effect - ** and we must return immediately. - ** - ** note that if we still have buffered packets, the - ** socket will be placed on the closing socket list. - ** this handler function will be called again - ** to process FDE_WRITE events. - */ - return; - } - - if(r > 0) { - /* if the remote cannot accept further events, - ** we disable notification of READs. They'll - ** be enabled again when we get a call to ready() - */ - fdevent_del(&s->fde, FDE_READ); - } - } - /* Don't allow a forced eof if data is still there */ - if((s->fde.force_eof && !r) || is_eof) { - D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof); - s->close(s); - } - } - - if(ev & FDE_ERROR){ - /* this should be caught be the next read or write - ** catching it here means we may skip the last few - ** bytes of readable data. - */ -// s->close(s); - D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd); - - return; - } -} - -asocket *create_local_socket(int fd) -{ - asocket *s = calloc(1, sizeof(asocket)); - if (s == NULL) fatal("cannot allocate socket"); - s->fd = fd; - s->enqueue = local_socket_enqueue; - s->ready = local_socket_ready; - s->close = local_socket_close; - install_local_socket(s); - - fdevent_install(&s->fde, fd, local_socket_event_func, s); -/* fdevent_add(&s->fde, FDE_ERROR); */ - //fprintf(stderr, "Created local socket in create_local_socket \n"); - D("LS(%d): created (fd=%d)\n", s->id, s->fd); - return s; -} - -asocket *create_local_service_socket(const char *name) -{ - asocket *s; - int fd; - - fd = service_to_fd(name); - if(fd < 0) return 0; - - s = create_local_socket(fd); - D("LS(%d): bound to '%s' via %d\n", s->id, name, fd); - return s; -} - -/* a Remote socket is used to send/receive data to/from a given transport object -** it needs to be closed when the transport is forcibly destroyed by the user -*/ -typedef struct aremotesocket { - asocket socket; - adisconnect disconnect; -} aremotesocket; - -static int remote_socket_enqueue(asocket *s, apacket *p) -{ - D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n", - s->id, s->fd, s->peer->fd); - p->msg.command = A_WRTE; - p->msg.arg0 = s->peer->id; - p->msg.arg1 = s->id; - p->msg.data_length = p->len; - send_packet(p, s->transport); - return 1; -} - -static void remote_socket_ready(asocket *s) -{ - D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d\n", - s->id, s->fd, s->peer->fd); - apacket *p = get_apacket(); - p->msg.command = A_OKAY; - p->msg.arg0 = s->peer->id; - p->msg.arg1 = s->id; - send_packet(p, s->transport); -} - -static void remote_socket_close(asocket *s) -{ - D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n", - s->id, s->fd, s->peer?s->peer->fd:-1); - apacket *p = get_apacket(); - p->msg.command = A_CLSE; - if(s->peer) { - p->msg.arg0 = s->peer->id; - s->peer->peer = 0; - D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d\n", - s->id, s->peer->id, s->peer->fd); - s->peer->close(s->peer); - } - p->msg.arg1 = s->id; - send_packet(p, s->transport); - D("RS(%d): closed\n", s->id); - remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect ); - free(s); -} - -static void remote_socket_disconnect(void* _s, atransport* t) -{ - asocket* s = _s; - asocket* peer = s->peer; - - D("remote_socket_disconnect RS(%d)\n", s->id); - if (peer) { - peer->peer = NULL; - peer->close(peer); - } - remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect ); - free(s); -} - -asocket *create_remote_socket(unsigned id, atransport *t) -{ - asocket *s = calloc(1, sizeof(aremotesocket)); - adisconnect* dis = &((aremotesocket*)s)->disconnect; - - if (s == NULL) fatal("cannot allocate socket"); - s->id = id; - s->enqueue = remote_socket_enqueue; - s->ready = remote_socket_ready; - s->close = remote_socket_close; - s->transport = t; - - dis->func = remote_socket_disconnect; - dis->opaque = s; - add_transport_disconnect( t, dis ); - D("RS(%d): created\n", s->id); - return s; -} - -void connect_to_remote(asocket *s, const char *destination) -{ - D("Connect_to_remote call RS(%d) fd=%d\n", s->id, s->fd); - apacket *p = get_apacket(); - int len = strlen(destination) + 1; - - if(len > (MAX_PAYLOAD-1)) { - fatal("destination oversized"); - } - - D("LS(%d): connect('%s')\n", s->id, destination); - p->msg.command = A_OPEN; - p->msg.arg0 = s->id; - p->msg.data_length = len; - strcpy((char*) p->data, destination); - send_packet(p, s->transport); -} - - -/* this is used by magic sockets to rig local sockets to - send the go-ahead message when they connect */ -static void local_socket_ready_notify(asocket *s) -{ - s->ready = local_socket_ready; - s->close = local_socket_close; - adb_write(s->fd, "OKAY", 4); - s->ready(s); -} - -/* this is used by magic sockets to rig local sockets to - send the failure message if they are closed before - connected (to avoid closing them without a status message) */ -static void local_socket_close_notify(asocket *s) -{ - s->ready = local_socket_ready; - s->close = local_socket_close; - sendfailmsg(s->fd, "closed"); - s->close(s); -} - -unsigned unhex(unsigned char *s, int len) -{ - unsigned n = 0, c; - - while(len-- > 0) { - switch((c = *s++)) { - case '0': case '1': case '2': - case '3': case '4': case '5': - case '6': case '7': case '8': - case '9': - c -= '0'; - break; - case 'a': case 'b': case 'c': - case 'd': case 'e': case 'f': - c = c - 'a' + 10; - break; - case 'A': case 'B': case 'C': - case 'D': case 'E': case 'F': - c = c - 'A' + 10; - break; - default: - return 0xffffffff; - } - - n = (n << 4) | c; - } - - return n; -} - -/* skip_host_serial return the position in a string - skipping over the 'serial' parameter in the ADB protocol, - where parameter string may be a host:port string containing - the protocol delimiter (colon). */ -char *skip_host_serial(char *service) { - char *first_colon, *serial_end; - - first_colon = strchr(service, ':'); - if (!first_colon) { - /* No colon in service string. */ - return NULL; - } - serial_end = first_colon; - if (isdigit(serial_end[1])) { - serial_end++; - while ((*serial_end) && isdigit(*serial_end)) { - serial_end++; - } - if ((*serial_end) != ':') { - // Something other than numbers was found, reset the end. - serial_end = first_colon; - } - } - return serial_end; -} - -static int smart_socket_enqueue(asocket *s, apacket *p) -{ - unsigned len; - - D("SS(%d): enqueue %d\n", s->id, p->len); - - if(s->pkt_first == 0) { - s->pkt_first = p; - s->pkt_last = p; - } else { - if((s->pkt_first->len + p->len) > MAX_PAYLOAD) { - D("SS(%d): overflow\n", s->id); - put_apacket(p); - goto fail; - } - - memcpy(s->pkt_first->data + s->pkt_first->len, - p->data, p->len); - s->pkt_first->len += p->len; - put_apacket(p); - - p = s->pkt_first; - } - - /* don't bother if we can't decode the length */ - if(p->len < 4) return 0; - - len = unhex(p->data, 4); - if((len < 1) || (len > 1024)) { - D("SS(%d): bad size (%d)\n", s->id, len); - goto fail; - } - - D("SS(%d): len is %d\n", s->id, len ); - /* can't do anything until we have the full header */ - if((len + 4) > p->len) { - D("SS(%d): waiting for %d more bytes\n", s->id, len+4 - p->len); - return 0; - } - - p->data[len + 4] = 0; - - D("SS(%d): '%s'\n", s->id, (char*) (p->data + 4)); - - if (s->transport == NULL) { - char* error_string = "unknown failure"; - s->transport = acquire_one_transport (CS_ANY, - kTransportAny, NULL, &error_string); - - if (s->transport == NULL) { - sendfailmsg(s->peer->fd, error_string); - goto fail; - } - } - - if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) { - /* if there's no remote we fail the connection - ** right here and terminate it - */ - sendfailmsg(s->peer->fd, "device offline (x)"); - goto fail; - } - - - /* instrument our peer to pass the success or fail - ** message back once it connects or closes, then - ** detach from it, request the connection, and - ** tear down - */ - s->peer->ready = local_socket_ready_notify; - s->peer->close = local_socket_close_notify; - s->peer->peer = 0; - /* give him our transport and upref it */ - s->peer->transport = s->transport; - - connect_to_remote(s->peer, (char*) (p->data + 4)); - s->peer = 0; - s->close(s); - return 1; - -fail: - /* we're going to close our peer as a side-effect, so - ** return -1 to signal that state to the local socket - ** who is enqueueing against us - */ - s->close(s); - return -1; -} - -static void smart_socket_ready(asocket *s) -{ - D("SS(%d): ready\n", s->id); -} - -static void smart_socket_close(asocket *s) -{ - D("SS(%d): closed\n", s->id); - if(s->pkt_first){ - put_apacket(s->pkt_first); - } - if(s->peer) { - s->peer->peer = 0; - s->peer->close(s->peer); - s->peer = 0; - } - free(s); -} - -asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act)) -{ - D("Creating smart socket \n"); - asocket *s = calloc(1, sizeof(asocket)); - if (s == NULL) fatal("cannot allocate socket"); - s->enqueue = smart_socket_enqueue; - s->ready = smart_socket_ready; - s->close = smart_socket_close; - s->extra = action_cb; - - D("SS(%d): created %p\n", s->id, action_cb); - return s; -} - -void smart_socket_action(asocket *s, const char *act) -{ - -} - -void connect_to_smartsocket(asocket *s) -{ - D("Connecting to smart socket \n"); - asocket *ss = create_smart_socket(smart_socket_action); - s->peer = ss; - ss->peer = s; - s->ready(s); -} diff --git a/minadbd21/sysdeps.h b/minadbd21/sysdeps.h deleted file mode 100644 index 800ddb75..00000000 --- a/minadbd21/sysdeps.h +++ /dev/null @@ -1,494 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -/* this file contains system-dependent definitions used by ADB - * they're related to threads, sockets and file descriptors - */ -#ifndef _ADB_SYSDEPS_H -#define _ADB_SYSDEPS_H - -#ifdef __CYGWIN__ -# undef _WIN32 -#endif - -#ifdef _WIN32 - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define OS_PATH_SEPARATOR '\\' -#define OS_PATH_SEPARATOR_STR "\\" - -typedef CRITICAL_SECTION adb_mutex_t; - -#define ADB_MUTEX_DEFINE(x) adb_mutex_t x - -/* declare all mutexes */ -/* For win32, adb_sysdeps_init() will do the mutex runtime initialization. */ -#define ADB_MUTEX(x) extern adb_mutex_t x; -#include "mutex_list.h" - -extern void adb_sysdeps_init(void); - -static __inline__ void adb_mutex_lock( adb_mutex_t* lock ) -{ - EnterCriticalSection( lock ); -} - -static __inline__ void adb_mutex_unlock( adb_mutex_t* lock ) -{ - LeaveCriticalSection( lock ); -} - -typedef struct { unsigned tid; } adb_thread_t; - -typedef void* (*adb_thread_func_t)(void* arg); - -typedef void (*win_thread_func_t)(void* arg); - -static __inline__ int adb_thread_create( adb_thread_t *thread, adb_thread_func_t func, void* arg) -{ - thread->tid = _beginthread( (win_thread_func_t)func, 0, arg ); - if (thread->tid == (unsigned)-1L) { - return -1; - } - return 0; -} - -static __inline__ void close_on_exec(int fd) -{ - /* nothing really */ -} - -extern void disable_tcp_nagle(int fd); - -#define lstat stat /* no symlinks on Win32 */ - -#define S_ISLNK(m) 0 /* no symlinks on Win32 */ - -static __inline__ int adb_unlink(const char* path) -{ - int rc = unlink(path); - - if (rc == -1 && errno == EACCES) { - /* unlink returns EACCES when the file is read-only, so we first */ - /* try to make it writable, then unlink again... */ - rc = chmod(path, _S_IREAD|_S_IWRITE ); - if (rc == 0) - rc = unlink(path); - } - return rc; -} -#undef unlink -#define unlink ___xxx_unlink - -static __inline__ int adb_mkdir(const char* path, int mode) -{ - return _mkdir(path); -} -#undef mkdir -#define mkdir ___xxx_mkdir - -extern int adb_open(const char* path, int options); -extern int adb_creat(const char* path, int mode); -extern int adb_read(int fd, void* buf, int len); -extern int adb_write(int fd, const void* buf, int len); -extern int adb_lseek(int fd, int pos, int where); -extern int adb_shutdown(int fd); -extern int adb_close(int fd); - -static __inline__ int unix_close(int fd) -{ - return close(fd); -} -#undef close -#define close ____xxx_close - -static __inline__ int unix_read(int fd, void* buf, size_t len) -{ - return read(fd, buf, len); -} -#undef read -#define read ___xxx_read - -static __inline__ int unix_write(int fd, const void* buf, size_t len) -{ - return write(fd, buf, len); -} -#undef write -#define write ___xxx_write - -static __inline__ int adb_open_mode(const char* path, int options, int mode) -{ - return adb_open(path, options); -} - -static __inline__ int unix_open(const char* path, int options,...) -{ - if ((options & O_CREAT) == 0) - { - return open(path, options); - } - else - { - int mode; - va_list args; - va_start( args, options ); - mode = va_arg( args, int ); - va_end( args ); - return open(path, options, mode); - } -} -#define open ___xxx_unix_open - - -/* normally provided by */ -extern void* load_file(const char* pathname, unsigned* psize); - -/* normally provided by */ -extern int socket_loopback_client(int port, int type); -extern int socket_network_client(const char *host, int port, int type); -extern int socket_loopback_server(int port, int type); -extern int socket_inaddr_any_server(int port, int type); - -/* normally provided by "fdevent.h" */ - -#define FDE_READ 0x0001 -#define FDE_WRITE 0x0002 -#define FDE_ERROR 0x0004 -#define FDE_DONT_CLOSE 0x0080 - -typedef struct fdevent fdevent; - -typedef void (*fd_func)(int fd, unsigned events, void *userdata); - -fdevent *fdevent_create(int fd, fd_func func, void *arg); -void fdevent_destroy(fdevent *fde); -void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg); -void fdevent_remove(fdevent *item); -void fdevent_set(fdevent *fde, unsigned events); -void fdevent_add(fdevent *fde, unsigned events); -void fdevent_del(fdevent *fde, unsigned events); -void fdevent_loop(); - -struct fdevent { - fdevent *next; - fdevent *prev; - - int fd; - int force_eof; - - unsigned short state; - unsigned short events; - - fd_func func; - void *arg; -}; - -static __inline__ void adb_sleep_ms( int mseconds ) -{ - Sleep( mseconds ); -} - -extern int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen); - -#undef accept -#define accept ___xxx_accept - -static __inline__ int adb_socket_setbufsize( int fd, int bufsize ) -{ - int opt = bufsize; - return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt)); -} - -extern int adb_socketpair( int sv[2] ); - -static __inline__ char* adb_dirstart( const char* path ) -{ - char* p = strchr(path, '/'); - char* p2 = strchr(path, '\\'); - - if ( !p ) - p = p2; - else if ( p2 && p2 > p ) - p = p2; - - return p; -} - -static __inline__ char* adb_dirstop( const char* path ) -{ - char* p = strrchr(path, '/'); - char* p2 = strrchr(path, '\\'); - - if ( !p ) - p = p2; - else if ( p2 && p2 > p ) - p = p2; - - return p; -} - -static __inline__ int adb_is_absolute_host_path( const char* path ) -{ - return isalpha(path[0]) && path[1] == ':' && path[2] == '\\'; -} - -#else /* !_WIN32 a.k.a. Unix */ - -#include "fdevent.h" -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define OS_PATH_SEPARATOR '/' -#define OS_PATH_SEPARATOR_STR "/" - -typedef pthread_mutex_t adb_mutex_t; - -#define ADB_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER -#define adb_mutex_init pthread_mutex_init -#define adb_mutex_lock pthread_mutex_lock -#define adb_mutex_unlock pthread_mutex_unlock -#define adb_mutex_destroy pthread_mutex_destroy - -#define ADB_MUTEX_DEFINE(m) adb_mutex_t m = PTHREAD_MUTEX_INITIALIZER - -#define adb_cond_t pthread_cond_t -#define adb_cond_init pthread_cond_init -#define adb_cond_wait pthread_cond_wait -#define adb_cond_broadcast pthread_cond_broadcast -#define adb_cond_signal pthread_cond_signal -#define adb_cond_destroy pthread_cond_destroy - -/* declare all mutexes */ -#define ADB_MUTEX(x) extern adb_mutex_t x; -#include "mutex_list.h" - -static __inline__ void close_on_exec(int fd) -{ - fcntl( fd, F_SETFD, FD_CLOEXEC ); -} - -static __inline__ int unix_open(const char* path, int options,...) -{ - if ((options & O_CREAT) == 0) - { - return open(path, options); - } - else - { - int mode; - va_list args; - va_start( args, options ); - mode = va_arg( args, int ); - va_end( args ); - return open(path, options, mode); - } -} - -static __inline__ int adb_open_mode( const char* pathname, int options, int mode ) -{ - return open( pathname, options, mode ); -} - -static __inline__ int adb_creat(const char* path, int mode) -{ - int fd = open(path, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW, mode); - - if ( fd < 0 ) - return -1; - - close_on_exec(fd); - return fd; -} -#undef creat -#define creat ___xxx_creat - -static __inline__ int adb_open( const char* pathname, int options ) -{ - int fd = open( pathname, options ); - if (fd < 0) - return -1; - close_on_exec( fd ); - return fd; -} -#undef open -#define open ___xxx_open - -static __inline__ int adb_shutdown(int fd) -{ - return shutdown(fd, SHUT_RDWR); -} -#undef shutdown -#define shutdown ____xxx_shutdown - -static __inline__ int adb_close(int fd) -{ - return close(fd); -} -#undef close -#define close ____xxx_close - - -static __inline__ int adb_read(int fd, void* buf, size_t len) -{ - return read(fd, buf, len); -} - -#undef read -#define read ___xxx_read - -static __inline__ int adb_write(int fd, const void* buf, size_t len) -{ - return write(fd, buf, len); -} -#undef write -#define write ___xxx_write - -static __inline__ int adb_lseek(int fd, int pos, int where) -{ - return lseek(fd, pos, where); -} -#undef lseek -#define lseek ___xxx_lseek - -static __inline__ int adb_unlink(const char* path) -{ - return unlink(path); -} -#undef unlink -#define unlink ___xxx_unlink - -static __inline__ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) -{ - int fd; - - fd = accept(serverfd, addr, addrlen); - if (fd >= 0) - close_on_exec(fd); - - return fd; -} - -#undef accept -#define accept ___xxx_accept - -#define unix_read adb_read -#define unix_write adb_write -#define unix_close adb_close - -typedef pthread_t adb_thread_t; - -typedef void* (*adb_thread_func_t)( void* arg ); - -static __inline__ int adb_thread_create( adb_thread_t *pthread, adb_thread_func_t start, void* arg ) -{ - pthread_attr_t attr; - - pthread_attr_init (&attr); - pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); - - return pthread_create( pthread, &attr, start, arg ); -} - -static __inline__ int adb_socket_setbufsize( int fd, int bufsize ) -{ - int opt = bufsize; - return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)); -} - -static __inline__ void disable_tcp_nagle(int fd) -{ - int on = 1; - setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on) ); -} - - -static __inline__ int unix_socketpair( int d, int type, int protocol, int sv[2] ) -{ - return socketpair( d, type, protocol, sv ); -} - -static __inline__ int adb_socketpair( int sv[2] ) -{ - int rc; - - rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv ); - if (rc < 0) - return -1; - - close_on_exec( sv[0] ); - close_on_exec( sv[1] ); - return 0; -} - -#undef socketpair -#define socketpair ___xxx_socketpair - -static __inline__ void adb_sleep_ms( int mseconds ) -{ - usleep( mseconds*1000 ); -} - -static __inline__ int adb_mkdir(const char* path, int mode) -{ - return mkdir(path, mode); -} -#undef mkdir -#define mkdir ___xxx_mkdir - -static __inline__ void adb_sysdeps_init(void) -{ -} - -static __inline__ char* adb_dirstart(const char* path) -{ - return strchr(path, '/'); -} - -static __inline__ char* adb_dirstop(const char* path) -{ - return strrchr(path, '/'); -} - -static __inline__ int adb_is_absolute_host_path( const char* path ) -{ - return path[0] == '/'; -} - -#endif /* !_WIN32 */ - -#endif /* _ADB_SYSDEPS_H */ diff --git a/minadbd21/transport.c b/minadbd21/transport.c deleted file mode 100644 index 92679f51..00000000 --- a/minadbd21/transport.c +++ /dev/null @@ -1,803 +0,0 @@ -/* - * Copyright (C) 2007 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 -#include -#include -#include -#include - -#include "sysdeps.h" - -#define TRACE_TAG TRACE_TRANSPORT -#include "adb.h" - -static void transport_unref(atransport *t); - -static atransport transport_list = { - .next = &transport_list, - .prev = &transport_list, -}; - -ADB_MUTEX_DEFINE( transport_lock ); - -#if ADB_TRACE -#define MAX_DUMP_HEX_LEN 16 -static void dump_hex( const unsigned char* ptr, size_t len ) -{ - int nn, len2 = len; - // Build a string instead of logging each character. - // MAX chars in 2 digit hex, one space, MAX chars, one '\0'. - char buffer[MAX_DUMP_HEX_LEN *2 + 1 + MAX_DUMP_HEX_LEN + 1 ], *pb = buffer; - - if (len2 > MAX_DUMP_HEX_LEN) len2 = MAX_DUMP_HEX_LEN; - - for (nn = 0; nn < len2; nn++) { - sprintf(pb, "%02x", ptr[nn]); - pb += 2; - } - sprintf(pb++, " "); - - for (nn = 0; nn < len2; nn++) { - int c = ptr[nn]; - if (c < 32 || c > 127) - c = '.'; - *pb++ = c; - } - *pb++ = '\0'; - DR("%s\n", buffer); -} -#endif - -void -kick_transport(atransport* t) -{ - if (t && !t->kicked) - { - int kicked; - - adb_mutex_lock(&transport_lock); - kicked = t->kicked; - if (!kicked) - t->kicked = 1; - adb_mutex_unlock(&transport_lock); - - if (!kicked) - t->kick(t); - } -} - -void -run_transport_disconnects(atransport* t) -{ - adisconnect* dis = t->disconnects.next; - - D("%s: run_transport_disconnects\n", t->serial); - while (dis != &t->disconnects) { - adisconnect* next = dis->next; - dis->func( dis->opaque, t ); - dis = next; - } -} - -#if ADB_TRACE -static void -dump_packet(const char* name, const char* func, apacket* p) -{ - unsigned command = p->msg.command; - int len = p->msg.data_length; - char cmd[9]; - char arg0[12], arg1[12]; - int n; - - for (n = 0; n < 4; n++) { - int b = (command >> (n*8)) & 255; - if (b < 32 || b >= 127) - break; - cmd[n] = (char)b; - } - if (n == 4) { - cmd[4] = 0; - } else { - /* There is some non-ASCII name in the command, so dump - * the hexadecimal value instead */ - snprintf(cmd, sizeof cmd, "%08x", command); - } - - if (p->msg.arg0 < 256U) - snprintf(arg0, sizeof arg0, "%d", p->msg.arg0); - else - snprintf(arg0, sizeof arg0, "0x%x", p->msg.arg0); - - if (p->msg.arg1 < 256U) - snprintf(arg1, sizeof arg1, "%d", p->msg.arg1); - else - snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1); - - D("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ", - name, func, cmd, arg0, arg1, len); - dump_hex(p->data, len); -} -#endif /* ADB_TRACE */ - -static int -read_packet(int fd, const char* name, apacket** ppacket) -{ - char *p = (char*)ppacket; /* really read a packet address */ - int r; - int len = sizeof(*ppacket); - char buff[8]; - if (!name) { - snprintf(buff, sizeof buff, "fd=%d", fd); - name = buff; - } - while(len > 0) { - r = adb_read(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno)); - if((r < 0) && (errno == EINTR)) continue; - return -1; - } - } - -#if ADB_TRACE - if (ADB_TRACING) { - dump_packet(name, "from remote", *ppacket); - } -#endif - return 0; -} - -static int -write_packet(int fd, const char* name, apacket** ppacket) -{ - char *p = (char*) ppacket; /* we really write the packet address */ - int r, len = sizeof(ppacket); - char buff[8]; - if (!name) { - snprintf(buff, sizeof buff, "fd=%d", fd); - name = buff; - } - -#if ADB_TRACE - if (ADB_TRACING) { - dump_packet(name, "to remote", *ppacket); - } -#endif - len = sizeof(ppacket); - while(len > 0) { - r = adb_write(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - D("%s: write_packet (fd=%d) error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno)); - if((r < 0) && (errno == EINTR)) continue; - return -1; - } - } - return 0; -} - -static void transport_socket_events(int fd, unsigned events, void *_t) -{ - atransport *t = _t; - D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events); - if(events & FDE_READ){ - apacket *p = 0; - if(read_packet(fd, t->serial, &p)){ - D("%s: failed to read packet from transport socket on fd %d\n", t->serial, fd); - } else { - handle_packet(p, (atransport *) _t); - } - } -} - -void send_packet(apacket *p, atransport *t) -{ - unsigned char *x; - unsigned sum; - unsigned count; - - p->msg.magic = p->msg.command ^ 0xffffffff; - - count = p->msg.data_length; - x = (unsigned char *) p->data; - sum = 0; - while(count-- > 0){ - sum += *x++; - } - p->msg.data_check = sum; - - print_packet("send", p); - - if (t == NULL) { - D("Transport is null \n"); - // Zap errno because print_packet() and other stuff have errno effect. - errno = 0; - fatal_errno("Transport is null"); - } - - if(write_packet(t->transport_socket, t->serial, &p)){ - fatal_errno("cannot enqueue packet on transport socket"); - } -} - -/* The transport is opened by transport_register_func before -** the input and output threads are started. -** -** The output thread issues a SYNC(1, token) message to let -** the input thread know to start things up. In the event -** of transport IO failure, the output thread will post a -** SYNC(0,0) message to ensure shutdown. -** -** The transport will not actually be closed until both -** threads exit, but the input thread will kick the transport -** on its way out to disconnect the underlying device. -*/ - -static void *output_thread(void *_t) -{ - atransport *t = _t; - apacket *p; - - D("%s: starting transport output thread on fd %d, SYNC online (%d)\n", - t->serial, t->fd, t->sync_token + 1); - p = get_apacket(); - p->msg.command = A_SYNC; - p->msg.arg0 = 1; - p->msg.arg1 = ++(t->sync_token); - p->msg.magic = A_SYNC ^ 0xffffffff; - if(write_packet(t->fd, t->serial, &p)) { - put_apacket(p); - D("%s: failed to write SYNC packet\n", t->serial); - goto oops; - } - - D("%s: data pump started\n", t->serial); - for(;;) { - p = get_apacket(); - - if(t->read_from_remote(p, t) == 0){ - D("%s: received remote packet, sending to transport\n", - t->serial); - if(write_packet(t->fd, t->serial, &p)){ - put_apacket(p); - D("%s: failed to write apacket to transport\n", t->serial); - goto oops; - } - } else { - D("%s: remote read failed for transport\n", t->serial); - put_apacket(p); - break; - } - } - - D("%s: SYNC offline for transport\n", t->serial); - p = get_apacket(); - p->msg.command = A_SYNC; - p->msg.arg0 = 0; - p->msg.arg1 = 0; - p->msg.magic = A_SYNC ^ 0xffffffff; - if(write_packet(t->fd, t->serial, &p)) { - put_apacket(p); - D("%s: failed to write SYNC apacket to transport", t->serial); - } - -oops: - D("%s: transport output thread is exiting\n", t->serial); - kick_transport(t); - transport_unref(t); - return 0; -} - -static void *input_thread(void *_t) -{ - atransport *t = _t; - apacket *p; - int active = 0; - - D("%s: starting transport input thread, reading from fd %d\n", - t->serial, t->fd); - - for(;;){ - if(read_packet(t->fd, t->serial, &p)) { - D("%s: failed to read apacket from transport on fd %d\n", - t->serial, t->fd ); - break; - } - if(p->msg.command == A_SYNC){ - if(p->msg.arg0 == 0) { - D("%s: transport SYNC offline\n", t->serial); - put_apacket(p); - break; - } else { - if(p->msg.arg1 == t->sync_token) { - D("%s: transport SYNC online\n", t->serial); - active = 1; - } else { - D("%s: transport ignoring SYNC %d != %d\n", - t->serial, p->msg.arg1, t->sync_token); - } - } - } else { - if(active) { - D("%s: transport got packet, sending to remote\n", t->serial); - t->write_to_remote(p, t); - } else { - D("%s: transport ignoring packet while offline\n", t->serial); - } - } - - put_apacket(p); - } - - // this is necessary to avoid a race condition that occured when a transport closes - // while a client socket is still active. - close_all_sockets(t); - - D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd); - kick_transport(t); - transport_unref(t); - return 0; -} - - -static int transport_registration_send = -1; -static int transport_registration_recv = -1; -static fdevent transport_registration_fde; - -void update_transports(void) -{ - // nothing to do on the device side -} - -typedef struct tmsg tmsg; -struct tmsg -{ - atransport *transport; - int action; -}; - -static int -transport_read_action(int fd, struct tmsg* m) -{ - char *p = (char*)m; - int len = sizeof(*m); - int r; - - while(len > 0) { - r = adb_read(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - if((r < 0) && (errno == EINTR)) continue; - D("transport_read_action: on fd %d, error %d: %s\n", - fd, errno, strerror(errno)); - return -1; - } - } - return 0; -} - -static int -transport_write_action(int fd, struct tmsg* m) -{ - char *p = (char*)m; - int len = sizeof(*m); - int r; - - while(len > 0) { - r = adb_write(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - if((r < 0) && (errno == EINTR)) continue; - D("transport_write_action: on fd %d, error %d: %s\n", - fd, errno, strerror(errno)); - return -1; - } - } - return 0; -} - -static void transport_registration_func(int _fd, unsigned ev, void *data) -{ - tmsg m; - adb_thread_t output_thread_ptr; - adb_thread_t input_thread_ptr; - int s[2]; - atransport *t; - - if(!(ev & FDE_READ)) { - return; - } - - if(transport_read_action(_fd, &m)) { - fatal_errno("cannot read transport registration socket"); - } - - t = m.transport; - - if(m.action == 0){ - D("transport: %s removing and free'ing %d\n", t->serial, t->transport_socket); - - /* IMPORTANT: the remove closes one half of the - ** socket pair. The close closes the other half. - */ - fdevent_remove(&(t->transport_fde)); - adb_close(t->fd); - - adb_mutex_lock(&transport_lock); - t->next->prev = t->prev; - t->prev->next = t->next; - adb_mutex_unlock(&transport_lock); - - run_transport_disconnects(t); - - if (t->product) - free(t->product); - if (t->serial) - free(t->serial); - - memset(t,0xee,sizeof(atransport)); - free(t); - - update_transports(); - return; - } - - /* don't create transport threads for inaccessible devices */ - if (t->connection_state != CS_NOPERM) { - /* initial references are the two threads */ - t->ref_count = 2; - - if(adb_socketpair(s)) { - fatal_errno("cannot open transport socketpair"); - } - - D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]); - - t->transport_socket = s[0]; - t->fd = s[1]; - - fdevent_install(&(t->transport_fde), - t->transport_socket, - transport_socket_events, - t); - - fdevent_set(&(t->transport_fde), FDE_READ); - - if(adb_thread_create(&input_thread_ptr, input_thread, t)){ - fatal_errno("cannot create input thread"); - } - - if(adb_thread_create(&output_thread_ptr, output_thread, t)){ - fatal_errno("cannot create output thread"); - } - } - - /* put us on the master device list */ - adb_mutex_lock(&transport_lock); - t->next = &transport_list; - t->prev = transport_list.prev; - t->next->prev = t; - t->prev->next = t; - adb_mutex_unlock(&transport_lock); - - t->disconnects.next = t->disconnects.prev = &t->disconnects; - - update_transports(); -} - -void init_transport_registration(void) -{ - int s[2]; - - if(adb_socketpair(s)){ - fatal_errno("cannot open transport registration socketpair"); - } - - transport_registration_send = s[0]; - transport_registration_recv = s[1]; - - fdevent_install(&transport_registration_fde, - transport_registration_recv, - transport_registration_func, - 0); - - fdevent_set(&transport_registration_fde, FDE_READ); -} - -/* the fdevent select pump is single threaded */ -static void register_transport(atransport *transport) -{ - tmsg m; - m.transport = transport; - m.action = 1; - D("transport: %s registered\n", transport->serial); - if(transport_write_action(transport_registration_send, &m)) { - fatal_errno("cannot write transport registration socket\n"); - } -} - -static void remove_transport(atransport *transport) -{ - tmsg m; - m.transport = transport; - m.action = 0; - D("transport: %s removed\n", transport->serial); - if(transport_write_action(transport_registration_send, &m)) { - fatal_errno("cannot write transport registration socket\n"); - } -} - - -static void transport_unref_locked(atransport *t) -{ - t->ref_count--; - if (t->ref_count == 0) { - D("transport: %s unref (kicking and closing)\n", t->serial); - if (!t->kicked) { - t->kicked = 1; - t->kick(t); - } - t->close(t); - remove_transport(t); - } else { - D("transport: %s unref (count=%d)\n", t->serial, t->ref_count); - } -} - -static void transport_unref(atransport *t) -{ - if (t) { - adb_mutex_lock(&transport_lock); - transport_unref_locked(t); - adb_mutex_unlock(&transport_lock); - } -} - -void add_transport_disconnect(atransport* t, adisconnect* dis) -{ - adb_mutex_lock(&transport_lock); - dis->next = &t->disconnects; - dis->prev = dis->next->prev; - dis->prev->next = dis; - dis->next->prev = dis; - adb_mutex_unlock(&transport_lock); -} - -void remove_transport_disconnect(atransport* t, adisconnect* dis) -{ - dis->prev->next = dis->next; - dis->next->prev = dis->prev; - dis->next = dis->prev = dis; -} - - -atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out) -{ - atransport *t; - atransport *result = NULL; - int ambiguous = 0; - -retry: - if (error_out) - *error_out = "device not found"; - - adb_mutex_lock(&transport_lock); - for (t = transport_list.next; t != &transport_list; t = t->next) { - if (t->connection_state == CS_NOPERM) { - if (error_out) - *error_out = "insufficient permissions for device"; - continue; - } - - /* check for matching serial number */ - if (serial) { - if (t->serial && !strcmp(serial, t->serial)) { - result = t; - break; - } - } else { - if (ttype == kTransportUsb && t->type == kTransportUsb) { - if (result) { - if (error_out) - *error_out = "more than one device"; - ambiguous = 1; - result = NULL; - break; - } - result = t; - } else if (ttype == kTransportLocal && t->type == kTransportLocal) { - if (result) { - if (error_out) - *error_out = "more than one emulator"; - ambiguous = 1; - result = NULL; - break; - } - result = t; - } else if (ttype == kTransportAny) { - if (result) { - if (error_out) - *error_out = "more than one device and emulator"; - ambiguous = 1; - result = NULL; - break; - } - result = t; - } - } - } - adb_mutex_unlock(&transport_lock); - - if (result) { - /* offline devices are ignored -- they are either being born or dying */ - if (result && result->connection_state == CS_OFFLINE) { - if (error_out) - *error_out = "device offline"; - result = NULL; - } - /* check for required connection state */ - if (result && state != CS_ANY && result->connection_state != state) { - if (error_out) - *error_out = "invalid device state"; - result = NULL; - } - } - - if (result) { - /* found one that we can take */ - if (error_out) - *error_out = NULL; - } else if (state != CS_ANY && (serial || !ambiguous)) { - adb_sleep_ms(1000); - goto retry; - } - - return result; -} - -void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable) -{ - atransport *t = calloc(1, sizeof(atransport)); - D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb, - serial ? serial : ""); - init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM)); - if(serial) { - t->serial = strdup(serial); - } - register_transport(t); -} - -/* this should only be used for transports with connection_state == CS_NOPERM */ -void unregister_usb_transport(usb_handle *usb) -{ - atransport *t; - adb_mutex_lock(&transport_lock); - for(t = transport_list.next; t != &transport_list; t = t->next) { - if (t->usb == usb && t->connection_state == CS_NOPERM) { - t->next->prev = t->prev; - t->prev->next = t->next; - break; - } - } - adb_mutex_unlock(&transport_lock); -} - -#undef TRACE_TAG -#define TRACE_TAG TRACE_RWX - -int readx(int fd, void *ptr, size_t len) -{ - char *p = ptr; - int r; -#if ADB_TRACE - size_t len0 = len; -#endif - D("readx: fd=%d wanted=%d\n", fd, (int)len); - while(len > 0) { - r = adb_read(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - if (r < 0) { - D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno)); - if (errno == EINTR) - continue; - } else { - D("readx: fd=%d disconnected\n", fd); - } - return -1; - } - } - -#if ADB_TRACE - D("readx: fd=%d wanted=%zu got=%zu\n", fd, len0, len0 - len); - dump_hex( ptr, len0 ); -#endif - return 0; -} - -int writex(int fd, const void *ptr, size_t len) -{ - char *p = (char*) ptr; - int r; - -#if ADB_TRACE - D("writex: fd=%d len=%d: ", fd, (int)len); - dump_hex( ptr, len ); -#endif - while(len > 0) { - r = adb_write(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - if (r < 0) { - D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno)); - if (errno == EINTR) - continue; - } else { - D("writex: fd=%d disconnected\n", fd); - } - return -1; - } - } - return 0; -} - -int check_header(apacket *p) -{ - if(p->msg.magic != (p->msg.command ^ 0xffffffff)) { - D("check_header(): invalid magic\n"); - return -1; - } - - if(p->msg.data_length > MAX_PAYLOAD) { - D("check_header(): %d > MAX_PAYLOAD\n", p->msg.data_length); - return -1; - } - - return 0; -} - -int check_data(apacket *p) -{ - unsigned count, sum; - unsigned char *x; - - count = p->msg.data_length; - x = p->data; - sum = 0; - while(count-- > 0) { - sum += *x++; - } - - if(sum != p->msg.data_check) { - return -1; - } else { - return 0; - } -} diff --git a/minadbd21/transport_usb.c b/minadbd21/transport_usb.c deleted file mode 100644 index 91cbf615..00000000 --- a/minadbd21/transport_usb.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2007 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 -#include -#include - -#include - -#define TRACE_TAG TRACE_TRANSPORT -#include "adb.h" - -#ifdef HAVE_BIG_ENDIAN -#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) -static inline void fix_endians(apacket *p) -{ - p->msg.command = H4(p->msg.command); - p->msg.arg0 = H4(p->msg.arg0); - p->msg.arg1 = H4(p->msg.arg1); - p->msg.data_length = H4(p->msg.data_length); - p->msg.data_check = H4(p->msg.data_check); - p->msg.magic = H4(p->msg.magic); -} -unsigned host_to_le32(unsigned n) -{ - return H4(n); -} -#else -#define fix_endians(p) do {} while (0) -unsigned host_to_le32(unsigned n) -{ - return n; -} -#endif - -static int remote_read(apacket *p, atransport *t) -{ - if(usb_read(t->usb, &p->msg, sizeof(amessage))){ - D("remote usb: read terminated (message)\n"); - return -1; - } - - fix_endians(p); - - if(check_header(p)) { - D("remote usb: check_header failed\n"); - return -1; - } - - if(p->msg.data_length) { - if(usb_read(t->usb, p->data, p->msg.data_length)){ - D("remote usb: terminated (data)\n"); - return -1; - } - } - - if(check_data(p)) { - D("remote usb: check_data failed\n"); - return -1; - } - - return 0; -} - -static int remote_write(apacket *p, atransport *t) -{ - unsigned size = p->msg.data_length; - - fix_endians(p); - - if(usb_write(t->usb, &p->msg, sizeof(amessage))) { - D("remote usb: 1 - write terminated\n"); - return -1; - } - if(p->msg.data_length == 0) return 0; - if(usb_write(t->usb, &p->data, size)) { - D("remote usb: 2 - write terminated\n"); - return -1; - } - - return 0; -} - -static void remote_close(atransport *t) -{ - usb_close(t->usb); - t->usb = 0; -} - -static void remote_kick(atransport *t) -{ - usb_kick(t->usb); -} - -void init_usb_transport(atransport *t, usb_handle *h, int state) -{ - D("transport: usb\n"); - t->close = remote_close; - t->kick = remote_kick; - t->read_from_remote = remote_read; - t->write_to_remote = remote_write; - t->sync_token = 1; - t->connection_state = state; - t->type = kTransportUsb; - t->usb = h; - - HOST = 0; -} diff --git a/minadbd21/usb_linux_client.c b/minadbd21/usb_linux_client.c deleted file mode 100644 index ec32bcf9..00000000 --- a/minadbd21/usb_linux_client.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - * Copyright (C) 2007 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 -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "sysdeps.h" - -#define TRACE_TAG TRACE_USB -#include "adb.h" - -#define MAX_PACKET_SIZE_FS 64 -#define MAX_PACKET_SIZE_HS 512 - -#define cpu_to_le16(x) htole16(x) -#define cpu_to_le32(x) htole32(x) - -struct usb_handle -{ - int fd; - adb_cond_t notify; - adb_mutex_t lock; - - int (*write)(usb_handle *h, const void *data, int len); - int (*read)(usb_handle *h, void *data, int len); - void (*kick)(usb_handle *h); - - int control; - int bulk_out; /* "out" from the host's perspective => source for adbd */ - int bulk_in; /* "in" from the host's perspective => sink for adbd */ -}; - -static const struct { - struct usb_functionfs_descs_head header; - struct { - struct usb_interface_descriptor intf; - struct usb_endpoint_descriptor_no_audio source; - struct usb_endpoint_descriptor_no_audio sink; - } __attribute__((packed)) fs_descs, hs_descs; -} __attribute__((packed)) descriptors = { - .header = { - .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC), - .length = cpu_to_le32(sizeof(descriptors)), - .fs_count = 3, - .hs_count = 3, - }, - .fs_descs = { - .intf = { - .bLength = sizeof(descriptors.fs_descs.intf), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bNumEndpoints = 2, - .bInterfaceClass = ADB_CLASS, - .bInterfaceSubClass = ADB_SUBCLASS, - .bInterfaceProtocol = ADB_PROTOCOL, - .iInterface = 1, /* first string from the provided table */ - }, - .source = { - .bLength = sizeof(descriptors.fs_descs.source), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 1 | USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_FS, - }, - .sink = { - .bLength = sizeof(descriptors.fs_descs.sink), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 2 | USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_FS, - }, - }, - .hs_descs = { - .intf = { - .bLength = sizeof(descriptors.hs_descs.intf), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bNumEndpoints = 2, - .bInterfaceClass = ADB_CLASS, - .bInterfaceSubClass = ADB_SUBCLASS, - .bInterfaceProtocol = ADB_PROTOCOL, - .iInterface = 1, /* first string from the provided table */ - }, - .source = { - .bLength = sizeof(descriptors.hs_descs.source), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 1 | USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_HS, - }, - .sink = { - .bLength = sizeof(descriptors.hs_descs.sink), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 2 | USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_HS, - }, - }, -}; - -#define STR_INTERFACE_ "ADB Interface" - -static const struct { - struct usb_functionfs_strings_head header; - struct { - __le16 code; - const char str1[sizeof(STR_INTERFACE_)]; - } __attribute__((packed)) lang0; -} __attribute__((packed)) strings = { - .header = { - .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC), - .length = cpu_to_le32(sizeof(strings)), - .str_count = cpu_to_le32(1), - .lang_count = cpu_to_le32(1), - }, - .lang0 = { - cpu_to_le16(0x0409), /* en-us */ - STR_INTERFACE_, - }, -}; - -void usb_cleanup() -{ - // nothing to do here -} - -static void *usb_adb_open_thread(void *x) -{ - struct usb_handle *usb = (struct usb_handle *)x; - int fd; - - while (1) { - // wait until the USB device needs opening - adb_mutex_lock(&usb->lock); - while (usb->fd != -1) - adb_cond_wait(&usb->notify, &usb->lock); - adb_mutex_unlock(&usb->lock); - - D("[ usb_thread - opening device ]\n"); - do { - /* XXX use inotify? */ - fd = unix_open("/dev/android_adb", O_RDWR); - if (fd < 0) { - // to support older kernels - fd = unix_open("/dev/android", O_RDWR); - fprintf(stderr, "usb_adb_open_thread: %d\n", fd ); - } - if (fd < 0) { - adb_sleep_ms(1000); - } - } while (fd < 0); - D("[ opening device succeeded ]\n"); - - close_on_exec(fd); - usb->fd = fd; - - D("[ usb_thread - registering device ]\n"); - register_usb_transport(usb, 0, 1); - } - - // never gets here - return 0; -} - -static int usb_adb_write(usb_handle *h, const void *data, int len) -{ - int n; - - D("about to write (fd=%d, len=%d)\n", h->fd, len); - n = adb_write(h->fd, data, len); - if(n != len) { - D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", - h->fd, n, errno, strerror(errno)); - return -1; - } - D("[ done fd=%d ]\n", h->fd); - return 0; -} - -static int usb_adb_read(usb_handle *h, void *data, int len) -{ - int n; - - D("about to read (fd=%d, len=%d)\n", h->fd, len); - n = adb_read(h->fd, data, len); - if(n != len) { - D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", - h->fd, n, errno, strerror(errno)); - return -1; - } - D("[ done fd=%d ]\n", h->fd); - return 0; -} - -static void usb_adb_kick(usb_handle *h) -{ - D("usb_kick\n"); - adb_mutex_lock(&h->lock); - adb_close(h->fd); - h->fd = -1; - - // notify usb_adb_open_thread that we are disconnected - adb_cond_signal(&h->notify); - adb_mutex_unlock(&h->lock); -} - -static void usb_adb_init() -{ - usb_handle *h; - adb_thread_t tid; - int fd; - - h = calloc(1, sizeof(usb_handle)); - - h->write = usb_adb_write; - h->read = usb_adb_read; - h->kick = usb_adb_kick; - h->fd = -1; - - adb_cond_init(&h->notify, 0); - adb_mutex_init(&h->lock, 0); - - fprintf(stderr, "Starting to open usb_init()\n"); - // Open the file /dev/android_adb_enable to trigger - // the enabling of the adb USB function in the kernel. - // We never touch this file again - just leave it open - // indefinitely so the kernel will know when we are running - // and when we are not. - fd = unix_open("/dev/android_adb_enable", O_RDWR); - fprintf(stderr, "unix_open to open usb_init(): %d\n", fd); - if (fd < 0) { - D("failed to open /dev/android_adb_enable\n"); - } else { - close_on_exec(fd); - } - - printf("[ usb_init - starting thread ]\n"); - if(adb_thread_create(&tid, usb_adb_open_thread, h)){ - fatal_errno("cannot create usb thread"); - fprintf(stderr, "cannot create the usb thread()\n"); - } -} - - -static void init_functionfs(struct usb_handle *h) -{ - ssize_t ret; - - D("OPENING %s\n", USB_FFS_ADB_EP0); - h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR); - if (h->control < 0) { - D("[ %s: cannot open control endpoint: errno=%d]\n", USB_FFS_ADB_EP0, errno); - goto err; - } - - ret = adb_write(h->control, &descriptors, sizeof(descriptors)); - if (ret < 0) { - D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno); - goto err; - } - - ret = adb_write(h->control, &strings, sizeof(strings)); - if (ret < 0) { - D("[ %s: writing strings failed: errno=%d]\n", USB_FFS_ADB_EP0, errno); - goto err; - } - - h->bulk_out = adb_open(USB_FFS_ADB_OUT, O_RDWR); - if (h->bulk_out < 0) { - D("[ %s: cannot open bulk-out ep: errno=%d ]\n", USB_FFS_ADB_OUT, errno); - goto err; - } - - h->bulk_in = adb_open(USB_FFS_ADB_IN, O_RDWR); - if (h->bulk_in < 0) { - D("[ %s: cannot open bulk-in ep: errno=%d ]\n", USB_FFS_ADB_IN, errno); - goto err; - } - - return; - -err: - if (h->bulk_in > 0) { - adb_close(h->bulk_in); - h->bulk_in = -1; - } - if (h->bulk_out > 0) { - adb_close(h->bulk_out); - h->bulk_out = -1; - } - if (h->control > 0) { - adb_close(h->control); - h->control = -1; - } - return; -} - -static void *usb_ffs_open_thread(void *x) -{ - struct usb_handle *usb = (struct usb_handle *)x; - - while (1) { - // wait until the USB device needs opening - adb_mutex_lock(&usb->lock); - while (usb->control != -1) - adb_cond_wait(&usb->notify, &usb->lock); - adb_mutex_unlock(&usb->lock); - - while (1) { - init_functionfs(usb); - - if (usb->control >= 0) - break; - - adb_sleep_ms(1000); - } - - D("[ usb_thread - registering device ]\n"); - register_usb_transport(usb, 0, 1); - } - - // never gets here - return 0; -} - -static int bulk_write(int bulk_in, const char *buf, size_t length) -{ - size_t count = 0; - int ret; - - do { - ret = adb_write(bulk_in, buf + count, length - count); - if (ret < 0) { - if (errno != EINTR) - return ret; - } else { - count += ret; - } - } while (count < length); - - D("[ bulk_write done fd=%d ]\n", bulk_in); - return count; -} - -static int usb_ffs_write(usb_handle *h, const void *data, int len) -{ - int n; - - D("about to write (fd=%d, len=%d)\n", h->bulk_in, len); - n = bulk_write(h->bulk_in, data, len); - if (n != len) { - D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", - h->bulk_in, n, errno, strerror(errno)); - return -1; - } - D("[ done fd=%d ]\n", h->bulk_in); - return 0; -} - -static int bulk_read(int bulk_out, char *buf, size_t length) -{ - size_t count = 0; - int ret; - - do { - ret = adb_read(bulk_out, buf + count, length - count); - if (ret < 0) { - if (errno != EINTR) { - D("[ bulk_read failed fd=%d length=%zu count=%zu ]\n", - bulk_out, length, count); - return ret; - } - } else { - count += ret; - } - } while (count < length); - - return count; -} - -static int usb_ffs_read(usb_handle *h, void *data, int len) -{ - int n; - - D("about to read (fd=%d, len=%d)\n", h->bulk_out, len); - n = bulk_read(h->bulk_out, data, len); - if (n != len) { - D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", - h->bulk_out, n, errno, strerror(errno)); - return -1; - } - D("[ done fd=%d ]\n", h->bulk_out); - return 0; -} - -static void usb_ffs_kick(usb_handle *h) -{ - int err; - - err = ioctl(h->bulk_in, FUNCTIONFS_CLEAR_HALT); - if (err < 0) - D("[ kick: source (fd=%d) clear halt failed (%d) ]", h->bulk_in, errno); - - err = ioctl(h->bulk_out, FUNCTIONFS_CLEAR_HALT); - if (err < 0) - D("[ kick: sink (fd=%d) clear halt failed (%d) ]", h->bulk_out, errno); - - adb_mutex_lock(&h->lock); - adb_close(h->control); - adb_close(h->bulk_out); - adb_close(h->bulk_in); - h->control = h->bulk_out = h->bulk_in = -1; - - // notify usb_ffs_open_thread that we are disconnected - adb_cond_signal(&h->notify); - adb_mutex_unlock(&h->lock); -} - -static void usb_ffs_init() -{ - usb_handle *h; - adb_thread_t tid; - - D("[ usb_init - using FunctionFS ]\n"); - - h = calloc(1, sizeof(usb_handle)); - - h->write = usb_ffs_write; - h->read = usb_ffs_read; - h->kick = usb_ffs_kick; - - h->control = -1; - h->bulk_out = -1; - h->bulk_out = -1; - - adb_cond_init(&h->notify, 0); - adb_mutex_init(&h->lock, 0); - - D("[ usb_init - starting thread ]\n"); - if (adb_thread_create(&tid, usb_ffs_open_thread, h)){ - fatal_errno("[ cannot create usb thread ]\n"); - } -} - -void usb_init() -{ - if (access(USB_FFS_ADB_EP0, F_OK) == 0) - usb_ffs_init(); - else - usb_adb_init(); -} - -int usb_write(usb_handle *h, const void *data, int len) -{ - return h->write(h, data, len); -} - -int usb_read(usb_handle *h, void *data, int len) -{ - return h->read(h, data, len); -} -int usb_close(usb_handle *h) -{ - // nothing to do here - return 0; -} - -void usb_kick(usb_handle *h) -{ - h->kick(h); -} diff --git a/minadbd21/utils.c b/minadbd21/utils.c deleted file mode 100644 index 91518bab..00000000 --- a/minadbd21/utils.c +++ /dev/null @@ -1,106 +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. - */ -#include "utils.h" -#include -#include -#include - -char* -buff_addc (char* buff, char* buffEnd, int c) -{ - int avail = buffEnd - buff; - - if (avail <= 0) /* already in overflow mode */ - return buff; - - if (avail == 1) { /* overflowing, the last byte is reserved for zero */ - buff[0] = 0; - return buff + 1; - } - - buff[0] = (char) c; /* add char and terminating zero */ - buff[1] = 0; - return buff + 1; -} - -char* -buff_adds (char* buff, char* buffEnd, const char* s) -{ - int slen = strlen(s); - - return buff_addb(buff, buffEnd, s, slen); -} - -char* -buff_addb (char* buff, char* buffEnd, const void* data, int len) -{ - int avail = (buffEnd - buff); - - if (avail <= 0 || len <= 0) /* already overflowing */ - return buff; - - if (len > avail) - len = avail; - - memcpy(buff, data, len); - - buff += len; - - /* ensure there is a terminating zero */ - if (buff >= buffEnd) { /* overflow */ - buff[-1] = 0; - } else - buff[0] = 0; - - return buff; -} - -char* -buff_add (char* buff, char* buffEnd, const char* format, ... ) -{ - int avail; - - avail = (buffEnd - buff); - - if (avail > 0) { - va_list args; - int nn; - - va_start(args, format); - nn = vsnprintf( buff, avail, format, args); - va_end(args); - - if (nn < 0) { - /* some C libraries return -1 in case of overflow, - * but they will also do that if the format spec is - * invalid. We assume ADB is not buggy enough to - * trigger that last case. */ - nn = avail; - } - else if (nn > avail) { - nn = avail; - } - - buff += nn; - - /* ensure that there is a terminating zero */ - if (buff >= buffEnd) - buff[-1] = 0; - else - buff[0] = 0; - } - return buff; -} diff --git a/minadbd21/utils.h b/minadbd21/utils.h deleted file mode 100644 index f70ecd24..00000000 --- a/minadbd21/utils.h +++ /dev/null @@ -1,68 +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 _ADB_UTILS_H -#define _ADB_UTILS_H - -/* bounded buffer functions */ - -/* all these functions are used to append data to a bounded buffer. - * - * after each operation, the buffer is guaranteed to be zero-terminated, - * even in the case of an overflow. they all return the new buffer position - * which allows one to use them in succession, only checking for overflows - * at the end. For example: - * - * BUFF_DECL(temp,p,end,1024); - * char* p; - * - * p = buff_addc(temp, end, '"'); - * p = buff_adds(temp, end, string); - * p = buff_addc(temp, end, '"'); - * - * if (p >= end) { - * overflow detected. note that 'temp' is - * zero-terminated for safety. - * } - * return strdup(temp); - */ - -/* tries to add a character to the buffer, in case of overflow - * this will only write a terminating zero and return buffEnd. - */ -char* buff_addc (char* buff, char* buffEnd, int c); - -/* tries to add a string to the buffer */ -char* buff_adds (char* buff, char* buffEnd, const char* s); - -/* tries to add a bytes to the buffer. the input can contain zero bytes, - * but a terminating zero will always be appended at the end anyway - */ -char* buff_addb (char* buff, char* buffEnd, const void* data, int len); - -/* tries to add a formatted string to a bounded buffer */ -char* buff_add (char* buff, char* buffEnd, const char* format, ... ); - -/* convenience macro used to define a bounded buffer, as well as - * a 'cursor' and 'end' variables all in one go. - * - * note: this doesn't place an initial terminating zero in the buffer, - * you need to use one of the buff_ functions for this. or simply - * do _cursor[0] = 0 manually. - */ -#define BUFF_DECL(_buff,_cursor,_end,_size) \ - char _buff[_size], *_cursor=_buff, *_end = _cursor + (_size) - -#endif /* _ADB_UTILS_H */ diff --git a/minuitwrp/Android.mk b/minuitwrp/Android.mk index ac09e494..d1c01e08 100644 --- a/minuitwrp/Android.mk +++ b/minuitwrp/Android.mk @@ -71,7 +71,8 @@ LOCAL_C_INCLUDES += \ external/zlib \ system/core/include \ external/freetype/include \ - external/libcxx/include + external/libcxx/include \ + $(LOCAL_PATH)/../twrpinstall/include ifneq ($(TW_INCLUDE_JPEG),) LOCAL_C_INCLUDES += \ diff --git a/minuitwrp/events.cpp b/minuitwrp/events.cpp index 7e5bc42e..6d576c67 100755 --- a/minuitwrp/events.cpp +++ b/minuitwrp/events.cpp @@ -32,7 +32,7 @@ #include #endif -#include "../common.h" +#include "common.h" #include "minui.h" diff --git a/mtp/ffs/Android.mk b/mtp/ffs/Android.mk index 740afcb1..0f8bda94 100755 --- a/mtp/ffs/Android.mk +++ b/mtp/ffs/Android.mk @@ -13,9 +13,10 @@ LOCAL_C_INCLUDES += $(LOCAL_PATH) bionic \ system/core/include \ bionic/libc/private/ \ bootable/recovery/twrplibusbhost/include \ - bootable/recovery/install/include + bootable/recovery/twrpinstall/include -LOCAL_SHARED_LIBRARIES += libc++ libaosprecovery +LOCAL_SHARED_LIBRARIES += libc++ +LOCAL_STATIC_LIBRARIES += libtwrpinstall LOCAL_SRC_FILES = \ MtpDataPacket.cpp \ diff --git a/openrecoveryscript.cpp b/openrecoveryscript.cpp index c6f7d80e..036d6ca8 100755 --- a/openrecoveryscript.cpp +++ b/openrecoveryscript.cpp @@ -51,7 +51,7 @@ #include "gui/pages.hpp" #include "orscmd/orscmd.h" #include "twinstall.h" -#include "install/adb_install.h" +#include "twinstall/adb_install.h" extern "C" { #include "gui/gui.h" #include "cutils/properties.h" @@ -388,8 +388,9 @@ int OpenRecoveryScript::run_script_file(void) { } else { ret_val = 1; // failure } + PartitionManager.Unlock_Block_Partitions(); sideload = 1; // Causes device to go to the home screen afterwards -#ifdef USE_28_INSTALL + pid_t sideload_child_pid = GetMiniAdbdPid(); if (sideload_child_pid != 0) { LOGINFO("Signaling child sideload process to exit.\n"); struct stat st; @@ -400,7 +401,6 @@ int OpenRecoveryScript::run_script_file(void) { LOGINFO("Waiting for child sideload process to exit.\n"); waitpid(sideload_child_pid, &status, 0); } -#endif property_set("ctl.start", "adbd"); gui_msg("done=Done."); } else if (strcmp(command, "fixperms") == 0 || strcmp(command, "fixpermissions") == 0 || strcmp(command, "fixcontexts") == 0) { diff --git a/partitionmanager.cpp b/partitionmanager.cpp index f30e4369..b3716d4b 100755 --- a/partitionmanager.cpp +++ b/partitionmanager.cpp @@ -2769,6 +2769,8 @@ bool TWPartitionManager::Flash_Image(string& path, string& filename) { full_filename = path + "/" + filename; + Unlock_Block_Partitions(); + gui_msg("image_flash_start=[IMAGE FLASH STARTED]"); gui_msg(Msg("img_to_flash=Image to flash: '{1}'")(full_filename)); @@ -3440,3 +3442,29 @@ bool TWPartitionManager::Recreate_Logs_Dir() { #endif return true; } + +void TWPartitionManager::Unlock_Block_Partitions() { + int fd, OFF = 0; + + const std::string block_path = "/dev/block/"; + DIR* d = opendir(block_path.c_str()); + if (d != NULL) { + struct dirent* de; + while ((de = readdir(d)) != NULL) { + if (de->d_type == DT_BLK) { + std::string block_device = block_path + de->d_name; + LOGINFO("block_Device: %s\n", block_device.c_str()); + if ((fd = open(block_device.c_str(), O_RDONLY | O_CLOEXEC)) < 0) { + LOGERR("unable to open block device %s: %s\n", block_device.c_str(), strerror(errno)); + continue; + } + if (ioctl(fd, BLKROSET, &OFF) == -1) { + LOGERR("Unable to unlock %s for flashing: %s\n", block_device.c_str()); + continue; + } + close(fd); + } + } + closedir(d); + } +} \ No newline at end of file diff --git a/partitions.hpp b/partitions.hpp index 284baebe..9c2b65ff 100755 --- a/partitions.hpp +++ b/partitions.hpp @@ -391,6 +391,7 @@ public: bool Recreate_Logs_Dir(); // Recreate TWRP_AB_LOGS_DIR after wipe std::vector* Get_Users_List(); // Returns pointer to list of users int Set_FDE_Encrypt_Status(); // Sets encryption state for FDE devices (ro.crypto.state and ro.crypto.type) + void Unlock_Block_Partitions(); // Unlock all block devices after update_engine runs private: void Setup_Settings_Storage_Partition(TWPartition* Part); // Sets up settings storage diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk index a7a5b792..07687ad1 100755 --- a/prebuilt/Android.mk +++ b/prebuilt/Android.mk @@ -86,6 +86,7 @@ RECOVERY_BINARY_SOURCE_FILES += $(TARGET_OUT_VENDOR_EXECUTABLES)/hw/android.hard 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 +RECOVERY_BINARY_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/system/bin/minadbd RECOVERY_LIBRARY_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libcutils.so RECOVERY_LIBRARY_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libcrecovery.so diff --git a/startupArgs.hpp b/startupArgs.hpp index 6bb2cb86..f01a411c 100755 --- a/startupArgs.hpp +++ b/startupArgs.hpp @@ -28,7 +28,7 @@ #include "twrp-functions.hpp" #include "variables.h" #include "bootloader_message/include/bootloader_message/bootloader_message.h" -#include "install/get_args.h" +#include "twinstall/get_args.h" class startupArgs { public: diff --git a/twinstallorig.h b/twinstallorig.h deleted file mode 100644 index ea467a2b..00000000 --- a/twinstallorig.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef RECOVERY_TWINSTALL_H_ -#define RECOVERY_TWINSTALL_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -int TWinstall_zip(const char* path, int* wipe_cache); - -#ifdef __cplusplus -} -#endif - -#endif // RECOVERY_TWINSTALL_H_ diff --git a/twrpinstall/Android.bp b/twrpinstall/Android.bp new file mode 100755 index 00000000..66ae1638 --- /dev/null +++ b/twrpinstall/Android.bp @@ -0,0 +1,92 @@ +// Copyright (C) 2019 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. + +cc_defaults { + name: "libtwrpinstall_defaults", + + defaults: [ + "recovery_defaults", + ], + + header_libs: [ + "libminadbd_headers", + ], + + shared_libs: [ + "libbase", + "libbootloader_message", + "libcrypto", + "libext4_utils", + "libfs_mgr", + "libfusesideload", + "libhidl-gen-utils", + "libhidlbase", + "libhidltransport", + "liblog", + "libselinux", + "libtinyxml2", + "libutils", + "libz", + "libziparchive", + ], + + static_libs: [ + "libotautil", + + // external dependencies + "libvintf_recovery", + "libvintf", + "libfstab", + ], +} + +cc_library_static { + name: "libtwrpinstall", + recovery_available: true, + + defaults: [ + "libtwrpinstall_defaults", + ], + + cflags: [ + "-DAB_OTA_UPDATER=1" + ], + + include_dirs: [ + "bootable/recovery", + "bootable/recovery/install/include", + ], + + srcs: [ + "adb_install.cpp", + "asn1_decoder.cpp", + "install.cpp", + "installcommand.cpp", + "package.cpp", + "tw_atomic.cpp", + "twinstall.cpp", + "verifier.cpp", + ], + shared_libs: [ + "librecovery_ui", + ], + + export_include_dirs: [ + "include", + ], + + export_shared_lib_headers: [ + "librecovery_ui", + ], +} diff --git a/twrpinstall/ZipUtil.cpp b/twrpinstall/ZipUtil.cpp new file mode 100755 index 00000000..f8134bc4 --- /dev/null +++ b/twrpinstall/ZipUtil.cpp @@ -0,0 +1,121 @@ +/* + * 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 "ZipUtil.h" + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "otautil/dirutil.h" + +static constexpr mode_t UNZIP_DIRMODE = 0755; +static constexpr mode_t UNZIP_FILEMODE = 0644; + +bool ExtractPackageRecursive(ZipArchiveHandle zip, const std::string& zip_path, + const std::string& dest_path, const struct utimbuf* timestamp, + struct selabel_handle* sehnd) { + if (!zip_path.empty() && zip_path[0] == '/') { + LOG(ERROR) << "ExtractPackageRecursive(): zip_path must be a relative path " << zip_path; + return false; + } + if (dest_path.empty() || dest_path[0] != '/') { + LOG(ERROR) << "ExtractPackageRecursive(): dest_path must be an absolute path " << dest_path; + return false; + } + + void* cookie; + std::string target_dir(dest_path); + if (dest_path.back() != '/') { + target_dir += '/'; + } + std::string prefix_path(zip_path); + if (!zip_path.empty() && zip_path.back() != '/') { + prefix_path += '/'; + } + const ZipString zip_prefix(prefix_path.c_str()); + + int ret = StartIteration(zip, &cookie, &zip_prefix, nullptr); + if (ret != 0) { + LOG(ERROR) << "failed to start iterating zip entries."; + return false; + } + + std::unique_ptr guard(cookie, EndIteration); + ZipEntry entry; + ZipString name; + int extractCount = 0; + while (Next(cookie, &entry, &name) == 0) { + std::string entry_name(name.name, name.name + name.name_length); + CHECK_LE(prefix_path.size(), entry_name.size()); + std::string path = target_dir + entry_name.substr(prefix_path.size()); + // Skip dir. + if (path.back() == '/') { + continue; + } + //TODO(b/31917448) handle the symlink. + + if (dirCreateHierarchy(path.c_str(), UNZIP_DIRMODE, timestamp, true, sehnd) != 0) { + LOG(ERROR) << "failed to create dir for " << path; + return false; + } + + char *secontext = NULL; + if (sehnd) { + selabel_lookup(sehnd, &secontext, path.c_str(), UNZIP_FILEMODE); + setfscreatecon(secontext); + } + android::base::unique_fd fd(open(path.c_str(), O_CREAT|O_WRONLY|O_TRUNC, UNZIP_FILEMODE)); + if (fd == -1) { + PLOG(ERROR) << "Can't create target file \"" << path << "\""; + return false; + } + if (secontext) { + freecon(secontext); + setfscreatecon(NULL); + } + + int err = ExtractEntryToFile(zip, &entry, fd); + if (err != 0) { + LOG(ERROR) << "Error extracting \"" << path << "\" : " << ErrorCodeString(err); + return false; + } + + if (fsync(fd) != 0) { + PLOG(ERROR) << "Error syncing file descriptor when extracting \"" << path << "\""; + return false; + } + + if (timestamp != nullptr && utime(path.c_str(), timestamp)) { + PLOG(ERROR) << "Error touching \"" << path << "\""; + return false; + } + + LOG(INFO) << "Extracted file \"" << path << "\""; + ++extractCount; + } + + LOG(INFO) << "Extracted " << extractCount << " file(s)"; + return true; +} diff --git a/twrpinstall/ZipUtil.h b/twrpinstall/ZipUtil.h new file mode 100644 index 00000000..cda405c2 --- /dev/null +++ b/twrpinstall/ZipUtil.h @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#ifndef _OTAUTIL_ZIPUTIL_H +#define _OTAUTIL_ZIPUTIL_H + +#include + +#include + +#include +#include + +/* + * Inflate all files under zip_path to the directory specified by + * dest_path, which must exist and be a writable directory. The zip_path + * is allowed to be an empty string, in which case the whole package + * will be extracted. + * + * Directory entries are not extracted. + * + * The immediate children of zip_path will become the immediate + * children of dest_path; e.g., if the archive contains the entries + * + * a/b/c/one + * a/b/c/two + * a/b/c/d/three + * + * and ExtractPackageRecursive(a, "a/b/c", "/tmp", ...) is called, the resulting + * files will be + * + * /tmp/one + * /tmp/two + * /tmp/d/three + * + * If timestamp is non-NULL, file timestamps will be set accordingly. + * + * Returns true on success, false on failure. + */ +bool ExtractPackageRecursive(ZipArchiveHandle zip, const std::string& zip_path, + const std::string& dest_path, const struct utimbuf* timestamp, + struct selabel_handle* sehnd); + +#endif // _OTAUTIL_ZIPUTIL_H diff --git a/twrpinstall/adb_install.cpp b/twrpinstall/adb_install.cpp new file mode 100755 index 00000000..5eb8c0bf --- /dev/null +++ b/twrpinstall/adb_install.cpp @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2012 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 "twinstall/adb_install.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "fuse_sideload.h" +#include "twinstall/install.h" +#include "twinstall/wipe_data.h" +#include "minadbd_types.h" +#include "otautil/sysutil.h" +#include "recovery_ui/device.h" +#include "recovery_ui/ui.h" + +// A CommandFunction returns a pair of (result, should_continue), which indicates the command +// execution result and whether it should proceed to the next iteration. The execution result will +// always be sent to the minadbd side. +using CommandFunction = std::function()>; + +pid_t child; + +pid_t GetMiniAdbdPid() { + return child; +} + +static bool SetUsbConfig(const std::string& state) { + android::base::SetProperty("sys.usb.config", state); + return android::base::WaitForProperty("sys.usb.state", state); +} + +// Parses the minadbd command in |message|; returns MinadbdCommand::kError upon errors. +static MinadbdCommand ParseMinadbdCommand(const std::string& message) { + if (!android::base::StartsWith(message, kMinadbdCommandPrefix)) { + LOG(ERROR) << "Failed to parse command in message " << message; + return MinadbdCommand::kError; + } + + auto cmd_code_string = message.substr(strlen(kMinadbdCommandPrefix)); + auto cmd_code = android::base::get_unaligned(cmd_code_string.c_str()); + if (cmd_code >= static_cast(MinadbdCommand::kError)) { + LOG(ERROR) << "Unsupported command code: " << cmd_code; + return MinadbdCommand::kError; + } + + return static_cast(cmd_code); +} + +static bool WriteStatusToFd(MinadbdCommandStatus status, int fd) { + char message[kMinadbdMessageSize]; + memcpy(message, kMinadbdStatusPrefix, strlen(kMinadbdStatusPrefix)); + android::base::put_unaligned(message + strlen(kMinadbdStatusPrefix), status); + + if (!android::base::WriteFully(fd, message, kMinadbdMessageSize)) { + PLOG(ERROR) << "Failed to write message " << message; + return false; + } + return true; +} + +// Installs the package from FUSE. Returns the installation result and whether it should continue +// waiting for new commands. +static auto AdbInstallPackageHandler(int* result) { + // How long (in seconds) we wait for the package path to be ready. It doesn't need to be too long + // because the minadbd service has already issued an install command. 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.) + constexpr int ADB_INSTALL_TIMEOUT = 15; + bool should_continue = true; + *result = INSTALL_ERROR; + for (int i = 0; i < ADB_INSTALL_TIMEOUT; ++i) { + PLOG(ERROR) << "i: " << i; + struct stat st; + if (stat(FUSE_SIDELOAD_HOST_PATHNAME, &st) != 0) { + if (errno == ENOENT && i < ADB_INSTALL_TIMEOUT - 1) { + sleep(1); + continue; + } else { + should_continue = false; + break; + } + } + *result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0); + break; + } + + // Calling stat() on this magic filename signals the FUSE to exit. + struct stat st; + stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st); + return std::make_pair(*result == INSTALL_SUCCESS, should_continue); +} + +static auto AdbRebootHandler(MinadbdCommand command, int* result, + Device::BuiltinAction* reboot_action) { + // Use Device::REBOOT_{FASTBOOT,RECOVERY,RESCUE}, instead of the ones with ENTER_. This allows + // rebooting back into fastboot/recovery/rescue mode through bootloader, which may use a newly + // installed bootloader/recovery image. + switch (command) { + case MinadbdCommand::kRebootBootloader: + *reboot_action = Device::REBOOT_BOOTLOADER; + break; + case MinadbdCommand::kRebootFastboot: + *reboot_action = Device::REBOOT_FASTBOOT; + break; + case MinadbdCommand::kRebootRecovery: + *reboot_action = Device::REBOOT_RECOVERY; + break; + case MinadbdCommand::kRebootRescue: + *reboot_action = Device::REBOOT_RESCUE; + break; + case MinadbdCommand::kRebootAndroid: + default: + *reboot_action = Device::REBOOT; + break; + } + *result = INSTALL_REBOOT; + return std::make_pair(true, false); +} + +// Parses and executes the command from minadbd. Returns whether the caller should keep waiting for +// next command. +static bool HandleMessageFromMinadbd(int socket_fd, + const std::map& command_map) { + char buffer[kMinadbdMessageSize]; + if (!android::base::ReadFully(socket_fd, buffer, kMinadbdMessageSize)) { + PLOG(ERROR) << "Failed to read message from minadbd"; + return false; + } + + std::string message(buffer, buffer + kMinadbdMessageSize); + auto command_type = ParseMinadbdCommand(message); + if (command_type == MinadbdCommand::kError) { + return false; + } + if (command_map.find(command_type) == command_map.end()) { + LOG(ERROR) << "Unsupported command: " + << android::base::get_unaligned( + message.substr(strlen(kMinadbdCommandPrefix)).c_str()); + return false; + } + + // We have received a valid command, execute the corresponding function. + const auto& command_func = command_map.at(command_type); + const auto [result, should_continue] = command_func(); + LOG(INFO) << "Command " << static_cast(command_type) << " finished with " << result; + if (!WriteStatusToFd(result ? MinadbdCommandStatus::kSuccess : MinadbdCommandStatus::kFailure, + socket_fd)) { + return false; + } + return should_continue; +} + +// TODO(xunchang) add a wrapper function and kill the minadbd service there. +static void ListenAndExecuteMinadbdCommands( + pid_t minadbd_pid, android::base::unique_fd&& socket_fd, + const std::map& command_map) { + android::base::unique_fd epoll_fd(epoll_create1(O_CLOEXEC)); + if (epoll_fd == -1) { + PLOG(ERROR) << "Failed to create epoll"; + kill(minadbd_pid, SIGKILL); + return; + } + + constexpr int EPOLL_MAX_EVENTS = 10; + struct epoll_event ev = {}; + ev.events = EPOLLIN | EPOLLHUP; + ev.data.fd = socket_fd.get(); + struct epoll_event events[EPOLL_MAX_EVENTS]; + if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, socket_fd.get(), &ev) == -1) { + PLOG(ERROR) << "Failed to add socket fd to epoll"; + kill(minadbd_pid, SIGKILL); + return; + } + + // Set the timeout to be 300s when waiting for minadbd commands. + constexpr int TIMEOUT_MILLIS = 300 * 1000; + while (true) { + // Poll for the status change of the socket_fd, and handle the message if the fd is ready to + // read. + int event_count = + TEMP_FAILURE_RETRY(epoll_wait(epoll_fd.get(), events, EPOLL_MAX_EVENTS, TIMEOUT_MILLIS)); + if (event_count == -1) { + PLOG(ERROR) << "Failed to wait for epoll events"; + kill(minadbd_pid, SIGKILL); + return; + } + if (event_count == 0) { + LOG(ERROR) << "Timeout waiting for messages from minadbd"; + kill(minadbd_pid, SIGKILL); + return; + } + + for (int n = 0; n < event_count; n++) { + if (events[n].events & EPOLLHUP) { + LOG(INFO) << "Socket has been closed"; + kill(minadbd_pid, SIGKILL); + return; + } + if (!HandleMessageFromMinadbd(socket_fd.get(), command_map)) { + kill(minadbd_pid, SIGKILL); + return; + } + } + } +} + +// Recovery starts minadbd service as a child process, and spawns another thread to listen for the +// message from minadbd through a socket pair. Here is an example to execute one command from adb +// host. +// a. recovery b. listener thread c. minadbd service +// +// a1. create socket pair +// a2. fork minadbd service +// c3. wait for the adb commands +// from host +// c4. after receiving host commands: +// 1) set up pre-condition (i.e. +// start fuse for adb sideload) +// 2) issue command through +// socket. +// 3) wait for result +// a5. start listener thread +// b6. listen for message from +// minadbd in a loop. +// b7. After receiving a minadbd +// command from socket +// 1) execute the command function +// 2) send the result back to +// minadbd +// ...... +// c8. exit upon receiving the +// result +// a9. wait for listener thread +// to exit. +// +// a10. wait for minadbd to +// exit +// b11. exit the listening loop +// +static void CreateMinadbdServiceAndExecuteCommands( + const std::map& command_map, + bool rescue_mode __unused, std::string install_file __unused) { + signal(SIGPIPE, SIG_IGN); + + android::base::unique_fd recovery_socket; + android::base::unique_fd minadbd_socket; + if (!android::base::Socketpair(AF_UNIX, SOCK_STREAM, 0, &recovery_socket, &minadbd_socket)) { + PLOG(ERROR) << "Failed to create socket"; + return; + } + + child = fork(); + if (child == -1) { + PLOG(ERROR) << "Failed to fork child process"; + return; + } + if (child == 0) { + recovery_socket.reset(); + std::vector minadbd_commands = { + "/system/bin/minadbd", + "--socket_fd", + std::to_string(minadbd_socket.release()), + }; + // if (rescue_mode) { + // minadbd_commands.push_back("--rescue"); + // } + auto exec_args = StringVectorToNullTerminatedArray(minadbd_commands); + execv(exec_args[0], exec_args.data()); + _exit(EXIT_FAILURE); + } + + minadbd_socket.reset(); + + // We need to call SetUsbConfig() after forking minadbd service. Because the function waits for + // the usb state to be updated, which depends on sys.usb.ffs.ready=1 set in the adb daemon. + if (!SetUsbConfig("sideload")) { + LOG(ERROR) << "Failed to set usb config to sideload"; + return; + } + + std::thread listener_thread(ListenAndExecuteMinadbdCommands, child, + std::move(recovery_socket), std::ref(command_map)); + if (listener_thread.joinable()) { + listener_thread.join(); + } + + int status; + waitpid(child, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + if (WEXITSTATUS(status) == MinadbdErrorCode::kMinadbdAdbVersionError) { + LOG(ERROR) << "\nYou need adb 1.0.32 or newer to sideload\nto this device.\n"; + } else if (!WIFSIGNALED(status)) { + LOG(ERROR) << "\n(adbd status " << WEXITSTATUS(status) << ")"; + } + } + + signal(SIGPIPE, SIG_DFL); +} + + int twrp_sideload(const char* install_file, Device::BuiltinAction* reboot_action) { + + // Save the usb state to restore after the sideload operation. + std::string usb_state = android::base::GetProperty("sys.usb.state", "none"); + // Clean up state and stop adbd. + if (usb_state != "none" && !SetUsbConfig("none")) { + LOG(ERROR) << "Failed to clear USB config"; + return INSTALL_ERROR; + } + + int install_result = INSTALL_ERROR; + std::map command_map{ + { MinadbdCommand::kInstall, std::bind(&AdbInstallPackageHandler, &install_result) }, + { MinadbdCommand::kRebootAndroid, std::bind(&AdbRebootHandler, MinadbdCommand::kRebootAndroid, + &install_result, reboot_action) }, + { MinadbdCommand::kRebootBootloader, + std::bind(&AdbRebootHandler, MinadbdCommand::kRebootBootloader, &install_result, + reboot_action) }, + { MinadbdCommand::kRebootFastboot, std::bind(&AdbRebootHandler, MinadbdCommand::kRebootFastboot, + &install_result, reboot_action) }, + { MinadbdCommand::kRebootRecovery, std::bind(&AdbRebootHandler, MinadbdCommand::kRebootRecovery, + &install_result, reboot_action) }, + { MinadbdCommand::kRebootRescue, + std::bind(&AdbRebootHandler, MinadbdCommand::kRebootRescue, &install_result, reboot_action) }, +}; + + CreateMinadbdServiceAndExecuteCommands(command_map, false, install_file); + + // Clean up before switching to the older state, for example setting the state + // to none sets sys/class/android_usb/android0/enable to 0. + if (!SetUsbConfig("none")) { + LOG(ERROR) << "Failed to clear USB config"; + } + + if (usb_state != "none") { + if (!SetUsbConfig(usb_state)) { + LOG(ERROR) << "Failed to set USB config to " << usb_state; + } + } + + return install_result; +} diff --git a/verifier28/asn1_decoder.cpp b/twrpinstall/asn1_decoder.cpp similarity index 98% rename from verifier28/asn1_decoder.cpp rename to twrpinstall/asn1_decoder.cpp index 285214f1..2d81a6e1 100644 --- a/verifier28/asn1_decoder.cpp +++ b/twrpinstall/asn1_decoder.cpp @@ -14,9 +14,7 @@ * limitations under the License. */ -#include "asn1_decoder.h" - -#include +#include "private/asn1_decoder.h" int asn1_context::peek_byte() const { if (length_ == 0) { diff --git a/common.h b/twrpinstall/include/common.h similarity index 100% rename from common.h rename to twrpinstall/include/common.h diff --git a/install/include/installcommand.h b/twrpinstall/include/installcommand.h similarity index 75% rename from install/include/installcommand.h rename to twrpinstall/include/installcommand.h index 957f0160..f265801c 100644 --- a/install/include/installcommand.h +++ b/twrpinstall/include/installcommand.h @@ -20,20 +20,19 @@ #define TMP_UPDATER_BINARY_PATH "/tmp/updater" #include +#include -#include "zipwrap.hpp" - -bool read_metadata_from_package(ZipWrap* zip, std::string* meta_data); +bool read_metadata_from_package(ZipArchiveHandle zip, std::string* meta_data); int -abupdate_binary_command(const char* path, ZipWrap* zip, int retry_count, +abupdate_binary_command(const char* path, int retry_count, int status_fd, std::vector* cmd); int update_binary_command(const char* path, int retry_count, int status_fd, std::vector* cmd); -bool verify_package_compatibility(ZipWrap *package_zip); +bool verify_package_compatibility(ZipArchiveHandle package_zip); -void read_source_target_build(ZipWrap* zip/*, std::vector& log_buffer*/); +void read_source_target_build(ZipArchiveHandle zip/*, std::vector& log_buffer*/); #endif // RECOVERY_INSTALL_COMMAND_H_ diff --git a/minadbd21/fuse_adb_provider.h b/twrpinstall/include/legacy_property_service.h similarity index 69% rename from minadbd21/fuse_adb_provider.h rename to twrpinstall/include/legacy_property_service.h index 0eb1f79d..d20bdeff 100644 --- a/minadbd21/fuse_adb_provider.h +++ b/twrpinstall/include/legacy_property_service.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2007 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. @@ -14,9 +14,12 @@ * limitations under the License. */ -#ifndef __FUSE_ADB_PROVIDER_H -#define __FUSE_ADB_PROVIDER_H +#ifndef _LEGACY_PROPERTY_H +#define _LEGACY_PROPERTY_H -int run_adb_fuse(int sfd, uint64_t file_size, uint32_t block_size); +#include -#endif +void legacy_get_property_workspace(int *fd, int *sz); +int legacy_properties_init(); + +#endif /* _LEGACY_PROPERTY_H */ diff --git a/verifier28/asn1_decoder.h b/twrpinstall/include/private/asn1_decoder.h similarity index 98% rename from verifier28/asn1_decoder.h rename to twrpinstall/include/private/asn1_decoder.h index 3e992115..e5337d9c 100644 --- a/verifier28/asn1_decoder.h +++ b/twrpinstall/include/private/asn1_decoder.h @@ -17,6 +17,7 @@ #ifndef ASN1_DECODER_H_ #define ASN1_DECODER_H_ +#include #include class asn1_context { diff --git a/twrpinstall/include/private/setup_commands.h b/twrpinstall/include/private/setup_commands.h new file mode 100644 index 00000000..7fdc741d --- /dev/null +++ b/twrpinstall/include/private/setup_commands.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2017 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. + */ + +// Private headers exposed for testing purpose only. + +#pragma once + +#include +#include + +#include + +// Sets up the commands for a non-A/B update. Extracts the updater binary from the open zip archive +// |zip| located at |package|. Stores the command line that should be called into |cmd|. The +// |status_fd| is the file descriptor the child process should use to report back the progress of +// the update. +int SetUpNonAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int retry_count, + int status_fd, std::vector* cmd); + +// Sets up the commands for an A/B update. Extracts the needed entries from the open zip archive +// |zip| located at |package|. Stores the command line that should be called into |cmd|. The +// |status_fd| is the file descriptor the child process should use to report back the progress of +// the update. Note that since this applies to the sideloading flow only, it takes one less +// parameter |retry_count| than the non-A/B version. +int SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int status_fd, + std::vector* cmd); diff --git a/twrpinstall/include/set_metadata.h b/twrpinstall/include/set_metadata.h new file mode 100644 index 00000000..9a46be99 --- /dev/null +++ b/twrpinstall/include/set_metadata.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 The Team Win Recovery 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. + */ + +/* + * The purpose of these functions is to try to get and set the proper + * file permissions, SELinux contexts, owner, and group so that these + * files are accessible when we boot up to normal Android via MTP and to + * file manager apps. During early boot we try to read the contexts and + * owner / group info from /data/media or from /data/media/0 and store + * them in static variables. From there, we'll try to set the same + * contexts, owner, and group information on most files we create during + * operations like backups, copying the log, and MTP operations. + */ + +#ifndef _RECOVERY_SET_CONTEXTS_H +#define _RECOVERY_SET_CONTEXTS_H + +#include +#include "selinux/selinux.h" + +int tw_get_default_metadata(const char* filename); +int tw_set_default_metadata(const char* filename); + +#endif //_RECOVERY_SET_CONTEXTS_H diff --git a/install/include/tw_atomic.hpp b/twrpinstall/include/tw_atomic.hpp similarity index 100% rename from install/include/tw_atomic.hpp rename to twrpinstall/include/tw_atomic.hpp diff --git a/twinstall.h b/twrpinstall/include/twinstall.h similarity index 100% rename from twinstall.h rename to twrpinstall/include/twinstall.h diff --git a/twrpinstall/include/twinstall/adb_install.h b/twrpinstall/include/twinstall/adb_install.h new file mode 100755 index 00000000..42321d4e --- /dev/null +++ b/twrpinstall/include/twinstall/adb_install.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2012 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. + */ + +#pragma once + +#include + +// Applies a package via `adb sideload` or `adb rescue`. Returns the install result (in `enum +// InstallResult`). When a reboot has been requested, INSTALL_REBOOT will be the return value, with +// the reboot target set in reboot_action. +int twrp_sideload(const char* install_file, Device::BuiltinAction* reboot_action); +pid_t GetMiniAdbdPid(); \ No newline at end of file diff --git a/install/include/install/get_args.h b/twrpinstall/include/twinstall/get_args.h similarity index 100% rename from install/include/install/get_args.h rename to twrpinstall/include/twinstall/get_args.h diff --git a/twrpinstall/include/twinstall/install.h b/twrpinstall/include/twinstall/install.h new file mode 100755 index 00000000..29647ad4 --- /dev/null +++ b/twrpinstall/include/twinstall/install.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2007 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. + */ + +#pragma once + +#include + +#include +#include +#include + +#include + +#include "package.h" + +enum InstallResult { + INSTALL_SUCCESS, + INSTALL_ERROR, + INSTALL_CORRUPT, + INSTALL_NONE, + INSTALL_SKIPPED, + INSTALL_RETRY, + INSTALL_KEY_INTERRUPTED, + INSTALL_REBOOT, +}; + +enum class OtaType { + AB, + BLOCK, + BRICK, +}; + +static constexpr const char* UPDATE_BINARY_NAME = "META-INF/com/google/android/update-binary"; +static constexpr float VERIFICATION_PROGRESS_FRACTION = 0.25; + +// Installs the given update package. This function should also wipe the cache partition after a +// successful installation if |should_wipe_cache| is true or an updater command asks to wipe the +// cache. +int install_package(const std::string& package, bool should_wipe_cache, bool needs_mount, + int retry_count); + +// Verifies the package by ota keys. Returns true if the package is verified successfully, +// otherwise returns false. +bool verify_package(Package* package); + +// Reads meta data file of the package; parses each line in the format "key=value"; and writes the +// result to |metadata|. Return true if succeed, otherwise return false. +bool ReadMetadataFromPackage(ZipArchiveHandle zip, std::map* metadata); + +// Reads the "recovery.wipe" entry in the zip archive returns a list of partitions to wipe. +std::vector GetWipePartitionList(Package* wipe_package); + +// Verifies the compatibility info in a Treble-compatible package. Returns true directly if the +// entry doesn't exist. +bool verify_package_compatibility(ZipArchiveHandle package_zip); + +// Checks if the the metadata in the OTA package has expected values. Returns 0 on success. +// Mandatory checks: ota-type, pre-device and serial number(if presents) +// AB OTA specific checks: pre-build version, fingerprint, timestamp. +int CheckPackageMetadata(const std::map& metadata, OtaType ota_type); +bool HasUpdaterBinary(ZipArchiveHandle zip); \ No newline at end of file diff --git a/twrpinstall/include/twinstall/package.h b/twrpinstall/include/twinstall/package.h new file mode 100755 index 00000000..50a4ffab --- /dev/null +++ b/twrpinstall/include/twinstall/package.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2019 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. + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include + +#include + +#include "verifier.h" + +// This class serves as a wrapper for an OTA update package. It aims to provide the common +// interface for both packages loaded in memory and packages read from fd. +class Package : public VerifierInterface { + public: + static std::unique_ptr CreateMemoryPackage( + const std::string& path); + static std::unique_ptr CreateMemoryPackage( + std::vector content); + static std::unique_ptr CreateFilePackage(const std::string& path, + const std::function& set_progress); + + virtual ~Package() = default; + + // Opens the package as a zip file and returns the ZipArchiveHandle. + virtual ZipArchiveHandle GetZipArchiveHandle() = 0; + + // Updates the progress in fraction during package verification. + void SetProgress(float progress) override; + + protected: + // An optional function to update the progress. + std::function set_progress_; +}; diff --git a/twrpinstall/include/twinstall/verifier.h b/twrpinstall/include/twinstall/verifier.h new file mode 100644 index 00000000..5d66e85d --- /dev/null +++ b/twrpinstall/include/twinstall/verifier.h @@ -0,0 +1,102 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include +#include +#include + +#include +#include +#include + +constexpr size_t MiB = 1024 * 1024; + +using HasherUpdateCallback = std::function; + +struct RSADeleter { + void operator()(RSA* rsa) const { + RSA_free(rsa); + } +}; + +struct ECKEYDeleter { + void operator()(EC_KEY* ec_key) const { + EC_KEY_free(ec_key); + } +}; + +struct Certificate { + typedef enum { + KEY_TYPE_RSA, + KEY_TYPE_EC, + } KeyType; + + Certificate(int hash_len_, KeyType key_type_, std::unique_ptr&& rsa_, + std::unique_ptr&& ec_) + : hash_len(hash_len_), key_type(key_type_), rsa(std::move(rsa_)), ec(std::move(ec_)) {} + + // SHA_DIGEST_LENGTH (SHA-1) or SHA256_DIGEST_LENGTH (SHA-256) + int hash_len; + KeyType key_type; + std::unique_ptr rsa; + std::unique_ptr ec; +}; + +class VerifierInterface { + public: + virtual ~VerifierInterface() = default; + + // Returns the package size in bytes. + virtual uint64_t GetPackageSize() const = 0; + + // Reads |byte_count| data starting from |offset|, and puts the result in |buffer|. + virtual bool ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) = 0; + + // Updates the hash contexts for |length| bytes data starting from |start|. + virtual bool UpdateHashAtOffset(const std::vector& hashers, uint64_t start, + uint64_t length) = 0; + + // Updates the progress in fraction during package verification. + virtual void SetProgress(float progress) = 0; +}; + +// Looks for an RSA signature embedded in the .ZIP file comment given the path to the zip. +// Verifies that it matches one of the given public keys. Returns VERIFY_SUCCESS or +// VERIFY_FAILURE (if any error is encountered or no key matches the signature). +int verify_file(VerifierInterface* package, const std::vector& keys, + const std::function& set_progress = nullptr); + +// Checks that the RSA key has a modulus of 2048 or 4096 bits long, and public exponent is 3 or +// 65537. +bool CheckRSAKey(const std::unique_ptr& rsa); + +// Checks that the field size of the curve for the EC key is 256 bits. +bool CheckECKey(const std::unique_ptr& ec_key); + +// Parses a PEM-encoded x509 certificate from the given buffer and saves it into |cert|. Returns +// false if there is a parsing failure or the signature's encryption algorithm is not supported. +bool LoadCertificateFromBuffer(const std::vector& pem_content, Certificate* cert); + +// Iterates over the zip entries with the suffix "x509.pem" and returns a list of recognized +// certificates. Returns an empty list if we fail to parse any of the entries. +std::vector LoadKeysFromZipfile(const std::string& zip_name); + +#define VERIFY_SUCCESS 0 +#define VERIFY_FAILURE 1 diff --git a/minadbd21/transport.h b/twrpinstall/include/twinstall/wipe_data.h old mode 100644 new mode 100755 similarity index 61% rename from minadbd21/transport.h rename to twrpinstall/include/twinstall/wipe_data.h index 992e0528..07b1e400 --- a/minadbd21/transport.h +++ b/twrpinstall/include/twinstall/wipe_data.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2019 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. @@ -14,13 +14,14 @@ * limitations under the License. */ -#ifndef __TRANSPORT_H -#define __TRANSPORT_H +#pragma once -/* convenience wrappers around read/write that will retry on -** EINTR and/or short read/write. Returns 0 on success, -1 -** on error or EOF. -*/ -int readx(int fd, void *ptr, size_t len); -int writex(int fd, const void *ptr, size_t len); -#endif /* __TRANSPORT_H */ +#include + +struct selabel_handle; + +// Returns true on success. +bool WipeCache(const std::function& confirm); + +// Returns true on success. +bool WipeData(bool convert_fbe); diff --git a/twrpinstall/install.cpp b/twrpinstall/install.cpp new file mode 100755 index 00000000..f3c77692 --- /dev/null +++ b/twrpinstall/install.cpp @@ -0,0 +1,753 @@ +/* + * Copyright (C) 2007 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 "twinstall/install.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "twinstall/package.h" +#include "twinstall/verifier.h" +#include "twinstall/wipe_data.h" +#include "otautil/error_code.h" +#include "otautil/paths.h" +#include "otautil/roots.h" +#include "otautil/sysutil.h" +#include "otautil/thermalutil.h" +#include "private/setup_commands.h" + +using namespace std::chrono_literals; + +static constexpr int kRecoveryApiVersion = 3; +// Assert the version defined in code and in Android.mk are consistent. +static_assert(kRecoveryApiVersion == RECOVERY_API_VERSION, "Mismatching recovery API versions."); + +// Default allocation of progress bar segments to operations +// static constexpr int VERIFICATION_PROGRESS_TIME = 60; +// static constexpr float VERIFICATION_PROGRESS_FRACTION = 0.25; + +static std::condition_variable finish_log_temperature; + +bool ReadMetadataFromPackage(ZipArchiveHandle zip, std::map* metadata) { + CHECK(metadata != nullptr); + + static constexpr const char* METADATA_PATH = "META-INF/com/android/metadata"; + ZipString path(METADATA_PATH); + ZipEntry entry; + if (FindEntry(zip, path, &entry) != 0) { + LOG(ERROR) << "Failed to find " << METADATA_PATH; + return false; + } + + uint32_t length = entry.uncompressed_length; + std::string metadata_string(length, '\0'); + int32_t err = + ExtractToMemory(zip, &entry, reinterpret_cast(&metadata_string[0]), length); + if (err != 0) { + LOG(ERROR) << "Failed to extract " << METADATA_PATH << ": " << ErrorCodeString(err); + return false; + } + + for (const std::string& line : android::base::Split(metadata_string, "\n")) { + size_t eq = line.find('='); + if (eq != std::string::npos) { + metadata->emplace(android::base::Trim(line.substr(0, eq)), + android::base::Trim(line.substr(eq + 1))); + } + } + + return true; +} + +// Gets the value for the given key in |metadata|. Returns an emtpy string if the key isn't +// present. +static std::string get_value(const std::map& metadata, + const std::string& key) { + const auto& it = metadata.find(key); + return (it == metadata.end()) ? "" : it->second; +} + +static std::string OtaTypeToString(OtaType type) { + switch (type) { + case OtaType::AB: + return "AB"; + case OtaType::BLOCK: + return "BLOCK"; + case OtaType::BRICK: + return "BRICK"; + } +} + +// Read the build.version.incremental of src/tgt from the metadata and log it to last_install. +static void ReadSourceTargetBuild(const std::map& metadata, + std::vector* log_buffer) { + // Examples of the pre-build and post-build strings in metadata: + // pre-build-incremental=2943039 + // post-build-incremental=2951741 + auto source_build = get_value(metadata, "pre-build-incremental"); + if (!source_build.empty()) { + log_buffer->push_back("source_build: " + source_build); + } + + auto target_build = get_value(metadata, "post-build-incremental"); + if (!target_build.empty()) { + log_buffer->push_back("target_build: " + target_build); + } +} + +// Checks the build version, fingerprint and timestamp in the metadata of the A/B package. +// Downgrading is not allowed unless explicitly enabled in the package and only for +// incremental packages. +static int CheckAbSpecificMetadata(const std::map& metadata) { + // Incremental updates should match the current build. + auto device_pre_build = android::base::GetProperty("ro.build.version.incremental", ""); + auto pkg_pre_build = get_value(metadata, "pre-build-incremental"); + if (!pkg_pre_build.empty() && pkg_pre_build != device_pre_build) { + LOG(ERROR) << "Package is for source build " << pkg_pre_build << " but expected " + << device_pre_build; + return INSTALL_ERROR; + } + + auto device_fingerprint = android::base::GetProperty("ro.build.fingerprint", ""); + auto pkg_pre_build_fingerprint = get_value(metadata, "pre-build"); + if (!pkg_pre_build_fingerprint.empty() && pkg_pre_build_fingerprint != device_fingerprint) { + LOG(ERROR) << "Package is for source build " << pkg_pre_build_fingerprint << " but expected " + << device_fingerprint; + return INSTALL_ERROR; + } + + // Check for downgrade version. + // int64_t build_timestamp = + // android::base::GetIntProperty("ro.build.date.utc", std::numeric_limits::max()); + // int64_t pkg_post_timestamp = 0; + // We allow to full update to the same version we are running, in case there + // is a problem with the current copy of that version. + auto pkg_post_timestamp_string = get_value(metadata, "post-timestamp"); + // if (pkg_post_timestamp_string.empty() || + // !android::base::ParseInt(pkg_post_timestamp_string, &pkg_post_timestamp) || + // pkg_post_timestamp < build_timestamp) { + // if (get_value(metadata, "ota-downgrade") != "yes") { + // LOG(ERROR) << "Update package is older than the current build, expected a build " + // "newer than timestamp " + // << build_timestamp << " but package has timestamp " << pkg_post_timestamp + // << " and downgrade not allowed."; + // return INSTALL_ERROR; + // } + // if (pkg_pre_build_fingerprint.empty()) { + // LOG(ERROR) << "Downgrade package must have a pre-build version set, not allowed."; + // return INSTALL_ERROR; + // } + // } + + return 0; +} + +int CheckPackageMetadata(const std::map& metadata, OtaType ota_type) { + auto package_ota_type = get_value(metadata, "ota-type"); + auto expected_ota_type = OtaTypeToString(ota_type); + if (ota_type != OtaType::AB && ota_type != OtaType::BRICK) { + LOG(INFO) << "Skip package metadata check for ota type " << expected_ota_type; + return 0; + } + + if (package_ota_type != expected_ota_type) { + LOG(ERROR) << "Unexpected ota package type, expects " << expected_ota_type << ", actual " + << package_ota_type; + return INSTALL_ERROR; + } + + auto device = android::base::GetProperty("ro.product.device", ""); + auto pkg_device = get_value(metadata, "pre-device"); + if (pkg_device != device || pkg_device.empty()) { + LOG(ERROR) << "Package is for product " << pkg_device << " but expected " << device; + return INSTALL_ERROR; + } + + // We allow the package to not have any serialno; and we also allow it to carry multiple serial + // numbers split by "|"; e.g. serialno=serialno1|serialno2|serialno3 ... We will fail the + // verification if the device's serialno doesn't match any of these carried numbers. + auto pkg_serial_no = get_value(metadata, "serialno"); + if (!pkg_serial_no.empty()) { + auto device_serial_no = android::base::GetProperty("ro.serialno", ""); + bool serial_number_match = false; + for (const auto& number : android::base::Split(pkg_serial_no, "|")) { + if (device_serial_no == android::base::Trim(number)) { + serial_number_match = true; + } + } + if (!serial_number_match) { + LOG(ERROR) << "Package is for serial " << pkg_serial_no; + return INSTALL_ERROR; + } + } + + if (ota_type == OtaType::AB) { + return CheckAbSpecificMetadata(metadata); + } + + return 0; +} + +int SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int status_fd, + std::vector* cmd) { + CHECK(cmd != nullptr); + + // For A/B updates we extract the payload properties to a buffer and obtain the RAW payload offset + // in the zip file. + static constexpr const char* AB_OTA_PAYLOAD_PROPERTIES = "payload_properties.txt"; + ZipString property_name(AB_OTA_PAYLOAD_PROPERTIES); + ZipEntry properties_entry; + if (FindEntry(zip, property_name, &properties_entry) != 0) { + LOG(ERROR) << "Failed to find " << AB_OTA_PAYLOAD_PROPERTIES; + return INSTALL_CORRUPT; + } + uint32_t properties_entry_length = properties_entry.uncompressed_length; + std::vector payload_properties(properties_entry_length); + int32_t err = + ExtractToMemory(zip, &properties_entry, payload_properties.data(), properties_entry_length); + if (err != 0) { + LOG(ERROR) << "Failed to extract " << AB_OTA_PAYLOAD_PROPERTIES << ": " << ErrorCodeString(err); + return INSTALL_CORRUPT; + } + + static constexpr const char* AB_OTA_PAYLOAD = "payload.bin"; + ZipString payload_name(AB_OTA_PAYLOAD); + ZipEntry payload_entry; + if (FindEntry(zip, payload_name, &payload_entry) != 0) { + LOG(ERROR) << "Failed to find " << AB_OTA_PAYLOAD; + return INSTALL_CORRUPT; + } + long payload_offset = payload_entry.offset; + *cmd = { + "/system/bin/update_engine_sideload", + "--payload=file://" + package, + android::base::StringPrintf("--offset=%ld", payload_offset), + "--headers=" + std::string(payload_properties.begin(), payload_properties.end()), + android::base::StringPrintf("--status_fd=%d", status_fd), + }; + return 0; +} + +int SetUpNonAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int retry_count, + int status_fd, std::vector* cmd) { + CHECK(cmd != nullptr); + + // In non-A/B updates we extract the update binary from the package. + ZipString binary_name(UPDATE_BINARY_NAME); + ZipEntry binary_entry; + if (FindEntry(zip, binary_name, &binary_entry) != 0) { + LOG(ERROR) << "Failed to find update binary " << UPDATE_BINARY_NAME; + return INSTALL_CORRUPT; + } + + LOG(ERROR) << "SetupNonAbUpdateCommands::here1"; + const std::string binary_path = Paths::Get().temporary_update_binary(); + unlink(binary_path.c_str()); + LOG(ERROR) << "SetupNonAbUpdateCommands::here2"; + android::base::unique_fd fd( + open(binary_path.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0755)); + if (fd == -1) { + PLOG(ERROR) << "Failed to create " << binary_path; + return INSTALL_ERROR; + } + LOG(ERROR) << "SetupNonAbUpdateCommands::here3"; + + int32_t error = ExtractEntryToFile(zip, &binary_entry, fd); + if (error != 0) { + LOG(ERROR) << "Failed to extract " << UPDATE_BINARY_NAME << ": " << ErrorCodeString(error); + return INSTALL_ERROR; + } + LOG(ERROR) << "SetupNonAbUpdateCommands::here4"; + + // When executing the update binary contained in the package, the arguments passed are: + // - the version number for this interface + // - an FD to which the program can write in order to update the progress bar. + // - the name of the package zip file. + // - an optional argument "retry" if this update is a retry of a failed update attempt. + *cmd = { + binary_path, + std::to_string(kRecoveryApiVersion), + std::to_string(status_fd), + package, + }; + if (retry_count > 0) { + cmd->push_back("retry"); + } + return 0; +} + +static void log_max_temperature(int* max_temperature, const std::atomic& logger_finished) { + CHECK(max_temperature != nullptr); + std::mutex mtx; + std::unique_lock lck(mtx); + while (!logger_finished.load() && + finish_log_temperature.wait_for(lck, 20s) == std::cv_status::timeout) { + *max_temperature = std::max(*max_temperature, GetMaxValueFromThermalZone()); + } +} + +// If the package contains an update binary, extract it and run it. +static int try_update_binary(const std::string& package, ZipArchiveHandle zip, bool* wipe_cache, + std::vector* log_buffer, int retry_count, + int* max_temperature) { + std::map metadata; + + if (!ReadMetadataFromPackage(zip, &metadata)) { + LOG(ERROR) << "Failed to parse metadata in the zip file"; + // return INSTALL_CORRUPT; + } + + bool is_ab = android::base::GetBoolProperty("ro.build.ab_update", false); + // Verifies against the metadata in the package first. + // if (int check_status = is_ab ? CheckPackageMetadata(metadata, OtaType::AB) : 0; + // check_status != 0) { + // log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure)); + // return check_status; + // } + + ReadSourceTargetBuild(metadata, log_buffer); + LOG(ERROR) << "try_update_binary::here1"; + // The updater in child process writes to the pipe to communicate with recovery. + android::base::unique_fd pipe_read, pipe_write; + // Explicitly disable O_CLOEXEC using 0 as the flags (last) parameter to Pipe + // so that the child updater process will recieve a non-closed fd. + if (!android::base::Pipe(&pipe_read, &pipe_write, 0)) { + PLOG(ERROR) << "Failed to create pipe for updater-recovery communication"; + return INSTALL_CORRUPT; + } + + // The updater-recovery communication protocol. + // + // progress + // fill up the next part of of the progress bar over seconds. If is + // zero, use `set_progress` commands to manually control the progress of this segment of the + // bar. + // + // set_progress + // should be between 0.0 and 1.0; sets the progress bar within the segment defined by + // the most recent progress command. + // + // ui_print + // display on the screen. + // + // wipe_cache + // a wipe of cache will be performed following a successful installation. + // + // clear_display + // turn off the text display. + // + // enable_reboot + // packages can explicitly request that they want the user to be able to reboot during + // installation (useful for debugging packages that don't exit). + // + // retry_update + // updater encounters some issue during the update. It requests a reboot to retry the same + // package automatically. + // + // log + // updater requests logging the string (e.g. cause of the failure). + // + + std::vector args; + + is_ab = false; + ZipString binary_name(UPDATE_BINARY_NAME); + ZipEntry binary_entry; + if (FindEntry(zip, binary_name, &binary_entry) != 0) { + LOG(ERROR) << "Failed to find update binary " << UPDATE_BINARY_NAME; + is_ab = true; + } + + if (int update_status = + is_ab ? SetUpAbUpdateCommands(package, zip, pipe_write.get(), &args) + : SetUpNonAbUpdateCommands(package, zip, retry_count, pipe_write.get(), &args); + update_status != 0) { + log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure)); + // return update_status; + } + + pid_t pid = fork(); + if (pid == -1) { + PLOG(ERROR) << "Failed to fork update binary"; + log_buffer->push_back(android::base::StringPrintf("error: %d", kForkUpdateBinaryFailure)); + return INSTALL_ERROR; + } + + if (pid == 0) { + umask(022); + pipe_read.reset(); + + // Convert the std::string vector to a NULL-terminated char* vector suitable for execv. + auto chr_args = StringVectorToNullTerminatedArray(args); + execv(chr_args[0], chr_args.data()); + // We shouldn't use LOG/PLOG in the forked process, since they may cause the child process to + // hang. This deadlock results from an improperly copied mutex in the ui functions. + // (Bug: 34769056) + fprintf(stdout, "E:Can't run %s (%s)\n", chr_args[0], strerror(errno)); + _exit(EXIT_FAILURE); + } + pipe_write.reset(); + + std::atomic logger_finished(false); + std::thread temperature_logger(log_max_temperature, max_temperature, std::ref(logger_finished)); + + *wipe_cache = false; + bool retry_update = false; + + char buffer[1024]; + FILE* from_child = android::base::Fdopen(std::move(pipe_read), "r"); + while (fgets(buffer, sizeof(buffer), from_child) != nullptr) { + std::string line(buffer); + size_t space = line.find_first_of(" \n"); + std::string command(line.substr(0, space)); + if (command.empty()) continue; + + // Get rid of the leading and trailing space and/or newline. + std::string args = space == std::string::npos ? "" : android::base::Trim(line.substr(space)); + + if (command == "progress") { + std::vector tokens = android::base::Split(args, " "); + double fraction; + int seconds; + if (tokens.size() == 2 && android::base::ParseDouble(tokens[0].c_str(), &fraction) && + android::base::ParseInt(tokens[1], &seconds)) { + // ui->ShowProgress(fraction * (1 - VERIFICATION_PROGRESS_FRACTION), seconds); + } else { + LOG(ERROR) << "invalid \"progress\" parameters: " << line; + } + } else if (command == "set_progress") { + std::vector tokens = android::base::Split(args, " "); + double fraction; + if (tokens.size() == 1 && android::base::ParseDouble(tokens[0].c_str(), &fraction)) { + // ui->SetProgress(fraction); + } else { + LOG(ERROR) << "invalid \"set_progress\" parameters: " << line; + } + } else if (command == "ui_print") { + // ui->PrintOnScreenOnly("%s\n", args.c_str()); + fflush(stdout); + } else if (command == "wipe_cache") { + *wipe_cache = true; + } else if (command == "clear_display") { + // ui->SetBackground(RecoveryUI::NONE); + } else if (command == "enable_reboot") { + // packages can explicitly request that they want the user + // to be able to reboot during installation (useful for + // debugging packages that don't exit). + // ui->SetEnableReboot(true); + } else if (command == "retry_update") { + retry_update = true; + } else if (command == "log") { + if (!args.empty()) { + // Save the logging request from updater and write to last_install later. + log_buffer->push_back(args); + } else { + LOG(ERROR) << "invalid \"log\" parameters: " << line; + } + } else { + LOG(ERROR) << "unknown command [" << command << "]"; + } + } + fclose(from_child); + + int status; + waitpid(pid, &status, 0); + + logger_finished.store(true); + finish_log_temperature.notify_one(); + temperature_logger.join(); + + if (retry_update) { + return INSTALL_RETRY; + } + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != EXIT_SUCCESS) { + LOG(ERROR) << "Error in " << package << " (status " << WEXITSTATUS(status) << ")"; + return INSTALL_ERROR; + } + } else if (WIFSIGNALED(status)) { + LOG(ERROR) << "Error in " << package << " (killed by signal " << WTERMSIG(status) << ")"; + return INSTALL_ERROR; + } else { + LOG(FATAL) << "Invalid status code " << status; + } + + return INSTALL_SUCCESS; +} + +// Verifes the compatibility info in a Treble-compatible package. Returns true directly if the +// entry doesn't exist. Note that the compatibility info is packed in a zip file inside the OTA +// package. +// bool verify_package_compatibility(ZipArchiveHandle package_zip __unused) { +// LOG(INFO) << "Verifying package compatibility..."; + +// static constexpr const char* COMPATIBILITY_ZIP_ENTRY = "compatibility.zip"; +// ZipString compatibility_entry_name(COMPATIBILITY_ZIP_ENTRY); +// ZipEntry compatibility_entry; +// if (FindEntry(package_zip, compatibility_entry_name, &compatibility_entry) != 0) { +// LOG(INFO) << "Package doesn't contain " << COMPATIBILITY_ZIP_ENTRY << " entry"; +// return true; +// } + +// std::string zip_content(compatibility_entry.uncompressed_length, '\0'); +// int32_t ret; +// if ((ret = ExtractToMemory(package_zip, &compatibility_entry, +// reinterpret_cast(&zip_content[0]), +// compatibility_entry.uncompressed_length)) != 0) { +// LOG(ERROR) << "Failed to read " << COMPATIBILITY_ZIP_ENTRY << ": " << ErrorCodeString(ret); +// return false; +// } + +// ZipArchiveHandle zip_handle; +// ret = OpenArchiveFromMemory(static_cast(const_cast(zip_content.data())), +// zip_content.size(), COMPATIBILITY_ZIP_ENTRY, &zip_handle); +// if (ret != 0) { +// LOG(ERROR) << "Failed to OpenArchiveFromMemory: " << ErrorCodeString(ret); +// return false; +// } + +// // Iterate all the entries inside COMPATIBILITY_ZIP_ENTRY and read the contents. +// void* cookie; +// ret = StartIteration(zip_handle, &cookie, nullptr, nullptr); +// if (ret != 0) { +// LOG(ERROR) << "Failed to start iterating zip entries: " << ErrorCodeString(ret); +// CloseArchive(zip_handle); +// return false; +// } +// std::unique_ptr guard(cookie, EndIteration); + +// std::vector compatibility_info; +// ZipEntry info_entry; +// ZipString info_name; +// while (Next(cookie, &info_entry, &info_name) == 0) { +// std::string content(info_entry.uncompressed_length, '\0'); +// int32_t ret = ExtractToMemory(zip_handle, &info_entry, reinterpret_cast(&content[0]), +// info_entry.uncompressed_length); +// if (ret != 0) { +// LOG(ERROR) << "Failed to read " << info_name.name << ": " << ErrorCodeString(ret); +// CloseArchive(zip_handle); +// return false; +// } +// compatibility_info.emplace_back(std::move(content)); +// } +// CloseArchive(zip_handle); + +// // VintfObjectRecovery::CheckCompatibility returns zero on success. +// std::string err; +// int result = android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err); +// if (result == 0) { +// return true; +// } + +// LOG(ERROR) << "Failed to verify package compatibility (result " << result << "): " << err; +// return false; +// } + +static int really_install_package(const std::string& path, bool* wipe_cache __unused, bool needs_mount __unused, + std::vector* log_buffer __unused, int retry_count __unused, + int* max_temperature __unused) { + // ui->SetBackground(RecoveryUI::INSTALLING_UPDATE); + // ui->Print("Finding update package...\n"); + // Give verification half the progress bar... + // ui->SetProgressType(RecoveryUI::DETERMINATE); + // ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME); + LOG(INFO) << "Update location: " << path; + + // Map the update package into memory. + // ui->Print("Opening update package...\n"); + if (needs_mount) { + if (path[0] == '@') { + ensure_path_mounted(path.substr(1)); + } else { + ensure_path_mounted(path); + } + } + + auto package = Package::CreateMemoryPackage( + path); + if (!package) { + log_buffer->push_back(android::base::StringPrintf("error: %d", kMapFileFailure)); + return INSTALL_CORRUPT; + } + + // Verify package. + if (!verify_package(package.get())) { + log_buffer->push_back(android::base::StringPrintf("error: %d", kZipVerificationFailure)); + return INSTALL_CORRUPT; + } + + // Try to open the package. + ZipArchiveHandle zip = package->GetZipArchiveHandle(); + if (!zip) { + log_buffer->push_back(android::base::StringPrintf("error: %d", kZipOpenFailure)); + return INSTALL_CORRUPT; + } + LOG(ERROR) << "really_install_package::here1"; + + // Additionally verify the compatibility of the package if it's a fresh install. + if (retry_count == 0 && !verify_package_compatibility(zip)) { + log_buffer->push_back(android::base::StringPrintf("error: %d", kPackageCompatibilityFailure)); + return INSTALL_CORRUPT; + } + + // Verify and install the contents of the package. + // ui->Print("Installing update...\n"); + // if (retry_count > 0) { + // ui->Print("Retry attempt: %d\n", retry_count); + // } + // ui->SetEnableReboot(false); + LOG(ERROR) << "really_install_package::here2"; + int result = + try_update_binary(path, zip, wipe_cache, log_buffer, retry_count, max_temperature); + // ui->SetEnableReboot(true); + // ui->Print("\n"); + return result; +} + +int install_package(const std::string& path, bool should_wipe_cache, bool needs_mount, + int retry_count) { + CHECK(!path.empty()); + + auto start = std::chrono::system_clock::now(); + + int start_temperature = GetMaxValueFromThermalZone(); + int max_temperature = start_temperature; + + int result; + std::vector log_buffer; + // if (setup_install_mounts() != 0) { + // LOG(ERROR) << "failed to set up expected mounts for install; aborting"; + // result = INSTALL_ERROR; + // } else { + bool updater_wipe_cache = false; + result = really_install_package(path, &updater_wipe_cache, needs_mount, &log_buffer, + retry_count, &max_temperature); + should_wipe_cache = should_wipe_cache || updater_wipe_cache; + // } + + // Measure the time spent to apply OTA update in seconds. + std::chrono::duration duration = std::chrono::system_clock::now() - start; + int time_total = static_cast(duration.count()); + + bool has_cache = volume_for_mount_point("/cache") != nullptr; + // Skip logging the uncrypt_status on devices without /cache. + if (has_cache) { + static constexpr const char* UNCRYPT_STATUS = "/cache/recovery/uncrypt_status"; + if (ensure_path_mounted(UNCRYPT_STATUS) != 0) { + LOG(WARNING) << "Can't mount " << UNCRYPT_STATUS; + } else { + std::string uncrypt_status; + if (!android::base::ReadFileToString(UNCRYPT_STATUS, &uncrypt_status)) { + PLOG(WARNING) << "failed to read uncrypt status"; + } else if (!android::base::StartsWith(uncrypt_status, "uncrypt_")) { + LOG(WARNING) << "corrupted uncrypt_status: " << uncrypt_status; + } else { + log_buffer.push_back(android::base::Trim(uncrypt_status)); + } + } + } + + // The first two lines need to be the package name and install result. + std::vector log_header = { + path, + result == INSTALL_SUCCESS ? "1" : "0", + "time_total: " + std::to_string(time_total), + "retry: " + std::to_string(retry_count), + }; + + int end_temperature = GetMaxValueFromThermalZone(); + max_temperature = std::max(end_temperature, max_temperature); + if (start_temperature > 0) { + log_buffer.push_back("temperature_start: " + std::to_string(start_temperature)); + } + if (end_temperature > 0) { + log_buffer.push_back("temperature_end: " + std::to_string(end_temperature)); + } + if (max_temperature > 0) { + log_buffer.push_back("temperature_max: " + std::to_string(max_temperature)); + } + + std::string log_content = + android::base::Join(log_header, "\n") + "\n" + android::base::Join(log_buffer, "\n") + "\n"; + const std::string& install_file = Paths::Get().temporary_install_file(); + if (!android::base::WriteStringToFile(log_content, install_file)) { + PLOG(ERROR) << "failed to write " << install_file; + } + + // Write a copy into last_log. + LOG(INFO) << log_content; + + if (result == INSTALL_SUCCESS && should_wipe_cache) { + if (!WipeCache(nullptr)) { + result = INSTALL_ERROR; + } + } + + return result; +} + +bool verify_package(Package* package) { + static constexpr const char* CERTIFICATE_ZIP_FILE = "/system/etc/security/otacerts.zip"; + std::vector loaded_keys = LoadKeysFromZipfile(CERTIFICATE_ZIP_FILE); + if (loaded_keys.empty()) { + LOG(ERROR) << "Failed to load keys"; + return false; + } + LOG(INFO) << loaded_keys.size() << " key(s) loaded from " << CERTIFICATE_ZIP_FILE; + + // Verify package. + // ui->Print("Verifying update package...\n"); + // auto t0 = std::chrono::system_clock::now(); + int err = verify_file(package, loaded_keys); + // if(err != VERIFY_SUCCESS) { + + // } + // std::chrono::duration duration = std::chrono::system_clock::now() - t0; + // ui->Print("Update package verification took %.1f s (result %d).\n", duration.count(), err); + if (err != VERIFY_SUCCESS) { + LOG(ERROR) << "Signature verification failed"; + LOG(ERROR) << "error: " << kZipVerificationFailure; + // return false; + } + return true; +} diff --git a/install/installcommand.cpp b/twrpinstall/installcommand.cpp similarity index 81% rename from install/installcommand.cpp rename to twrpinstall/installcommand.cpp index ee93484d..a03cb01b 100755 --- a/install/installcommand.cpp +++ b/twrpinstall/installcommand.cpp @@ -29,16 +29,9 @@ #include "common.h" #include "installcommand.h" -#include "zipwrap.hpp" -#ifndef USE_MINZIP #include #include -#endif -#ifdef USE_OLD_VERIFIER -#include "verifier24/verifier.h" -#else -#include "install/install.h" -#endif +#include "twinstall/install.h" #ifdef AB_OTA_UPDATER @@ -61,21 +54,29 @@ static int parse_build_number(std::string str) { return -1; } -bool read_metadata_from_package(ZipWrap* zip, std::string* meta_data) { - long size = zip->GetUncompressedSize(METADATA_PATH); - if (size <= 0) - return false; +bool read_metadata_from_package(ZipArchiveHandle zip, std::string* meta_data) { + ZipString binary_name(METADATA_PATH); + ZipEntry binary_entry; + if (FindEntry(zip, binary_name, &binary_entry) == 0) { + long size = binary_entry.uncompressed_length; + if (size <= 0) + return false; - meta_data->resize(size, '\0'); - if (!zip->ExtractToBuffer(METADATA_PATH, reinterpret_cast(&(*meta_data)[0]))) { - printf("Failed to read metadata in update package.\n"); - return false; - } - return true; + meta_data->resize(size, '\0'); + int32_t ret = ExtractToMemory(zip, &binary_entry, reinterpret_cast(&(*meta_data)[0]), + size); + if (ret != 0) { + printf("Failed to read metadata in update package.\n"); + CloseArchive(zip); + return false; + } + return true; + } + return false; } // Read the build.version.incremental of src/tgt from the metadata and log it to last_install. -void read_source_target_build(ZipWrap* zip/*, std::vector& log_buffer*/) { +void read_source_target_build(ZipArchiveHandle zip/*, std::vector& log_buffer*/) { std::string meta_data; if (!read_metadata_from_package(zip, &meta_data)) { return; @@ -107,7 +108,7 @@ void read_source_target_build(ZipWrap* zip/*, std::vector& log_buff // Parses the metadata of the OTA package in |zip| and checks whether we are // allowed to accept this A/B package. Downgrading is not allowed unless // explicitly enabled in the package and only for incremental packages. -static int check_newer_ab_build(ZipWrap* zip) +static int check_newer_ab_build(ZipArchiveHandle zip) { std::string metadata_str; if (!read_metadata_from_package(zip, &metadata_str)) { @@ -183,33 +184,48 @@ static int check_newer_ab_build(ZipWrap* zip) } int -abupdate_binary_command(const char* path, ZipWrap* zip, int retry_count __unused, +abupdate_binary_command(const char* path, int retry_count __unused, int status_fd, std::vector* cmd) { - read_source_target_build(zip); - int ret = check_newer_ab_build(zip); + auto package = Package::CreateMemoryPackage(path); + if (!package) { + return INSTALL_CORRUPT; + } + + ZipArchiveHandle Zip = package->GetZipArchiveHandle(); + read_source_target_build(Zip); + int ret = check_newer_ab_build(Zip); if (ret) { return ret; } // For A/B updates we extract the payload properties to a buffer and obtain // the RAW payload offset in the zip file. - if (!zip->EntryExists(AB_OTA_PAYLOAD_PROPERTIES)) { + // if (!Zip->EntryExists(AB_OTA_PAYLOAD_PROPERTIES)) { + ZipString binary_name(AB_OTA_PAYLOAD_PROPERTIES); + ZipEntry binary_entry; + if (FindEntry(Zip, binary_name, &binary_entry) != 0) { printf("Can't find %s\n", AB_OTA_PAYLOAD_PROPERTIES); return INSTALL_CORRUPT; } std::vector payload_properties( - zip->GetUncompressedSize(AB_OTA_PAYLOAD_PROPERTIES)); - if (!zip->ExtractToBuffer(AB_OTA_PAYLOAD_PROPERTIES, payload_properties.data())) { + binary_entry.uncompressed_length); + int32_t extract_ret = ExtractToMemory(Zip, &binary_entry, reinterpret_cast(payload_properties.data()), + binary_entry.uncompressed_length); + if (extract_ret != 0) { printf("Can't extract %s\n", AB_OTA_PAYLOAD_PROPERTIES); - return INSTALL_CORRUPT; + CloseArchive(Zip); + return false; } - if (!zip->EntryExists(AB_OTA_PAYLOAD)) { + ZipString ab_ota_payload(AB_OTA_PAYLOAD); + ZipEntry ab_ota_payload_entry; + if (FindEntry(Zip, ab_ota_payload, &ab_ota_payload_entry) != 0) { printf("Can't find %s\n", AB_OTA_PAYLOAD); return INSTALL_CORRUPT; } - long payload_offset = zip->GetEntryOffset(AB_OTA_PAYLOAD); + // long payload_offset = Zip->GetEntryOffset(AB_OTA_PAYLOAD); + long payload_offset = ab_ota_payload_entry.offset; *cmd = { "/system/bin/update_engine_sideload", android::base::StringPrintf("--payload=file://%s", path), @@ -223,10 +239,10 @@ abupdate_binary_command(const char* path, ZipWrap* zip, int retry_count __unused #else -void read_source_target_build(ZipWrap* zip __unused /*, std::vector& log_buffer*/) {return;} +void read_source_target_build(ZipArchiveHandle zip __unused /*, std::vector& log_buffer*/) {return;} int -abupdate_binary_command(__unused const char* path, __unused ZipWrap* zip, __unused int retry_count, +abupdate_binary_command(__unused const char* path, __unused int retry_count, __unused int status_fd, __unused std::vector* cmd) { printf("No support for AB OTA zips included\n"); @@ -256,31 +272,23 @@ update_binary_command(const char* path, int retry_count, return 0; } -#ifdef USE_MINZIP -bool verify_package_compatibility(ZipWrap *package_zip) { - if (package_zip->EntryExists("compatibility.zip")) - printf("Cannot verify treble package compatibility, must build TWRP in Oreo tree or higher.\n"); - return true; -} -#else // Verifes the compatibility info in a Treble-compatible package. Returns true directly if the // entry doesn't exist. Note that the compatibility info is packed in a zip file inside the OTA // package. -bool verify_package_compatibility(ZipWrap *zw) { - ZipArchiveHandle package_zip = zw->GetZipArchiveHandle(); +bool verify_package_compatibility(ZipArchiveHandle zw) { printf("Verifying package compatibility...\n"); static constexpr const char* COMPATIBILITY_ZIP_ENTRY = "compatibility.zip"; ZipString compatibility_entry_name(COMPATIBILITY_ZIP_ENTRY); ZipEntry compatibility_entry; - if (FindEntry(package_zip, compatibility_entry_name, &compatibility_entry) != 0) { + if (FindEntry(zw, compatibility_entry_name, &compatibility_entry) != 0) { printf("Package doesn't contain %s entry\n", COMPATIBILITY_ZIP_ENTRY); return true; } std::string zip_content(compatibility_entry.uncompressed_length, '\0'); int32_t ret; - if ((ret = ExtractToMemory(package_zip, &compatibility_entry, + if ((ret = ExtractToMemory(zw, &compatibility_entry, reinterpret_cast(&zip_content[0]), compatibility_entry.uncompressed_length)) != 0) { printf("Failed to read %s: %s\n", COMPATIBILITY_ZIP_ENTRY, ErrorCodeString(ret)); @@ -331,4 +339,3 @@ bool verify_package_compatibility(ZipWrap *zw) { printf("Failed to verify package compatibility (result %i): %s\n", result, err.c_str()); return false; } -#endif diff --git a/twrpinstall/legacy_property_service.cpp b/twrpinstall/legacy_property_service.cpp new file mode 100644 index 00000000..c3990f7a --- /dev/null +++ b/twrpinstall/legacy_property_service.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2007 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../bionic/libc/private/bionic_futex.h" + +#include + +#include "legacy_properties.h" + +#include +// Not available in 5.0 +//#include +#include "legacy_property_service.h" + +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif + +static int property_area_inited = 0; + +typedef struct { + void *data; + size_t size; + int fd; +} workspace; + +static int init_workspace(workspace *w, size_t size) +{ + void *data; + int fd; + + /* dev is a tmpfs that we can use to carve a shared workspace + * out of, so let's do that... + */ + fd = open("/dev/__legacy_properties__", O_RDWR | O_CREAT, 0600); + if (fd < 0) + return -1; + + if (ftruncate(fd, size) < 0) + goto out; + + data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if(data == MAP_FAILED) + goto out; + + close(fd); + + fd = open("/dev/__legacy_properties__", O_RDONLY); + if (fd < 0) + return -1; + + unlink("/dev/__legacy_properties__"); + + w->data = data; + w->size = size; + w->fd = fd; + return 0; + +out: + close(fd); + return -1; +} + +/* (8 header words + 247 toc words) = 1020 bytes */ +/* 1024 bytes header and toc + 247 prop_infos @ 128 bytes = 32640 bytes */ + +#define PA_COUNT_MAX 247 +#define PA_INFO_START 1024 +#define PA_SIZE 32768 + +static workspace pa_workspace; +static prop_info *pa_info_array; + +prop_area *__legacy_property_area__; + +static int init_property_area(void) +{ + prop_area *pa; + + if(pa_info_array) + return -1; + + if(init_workspace(&pa_workspace, PA_SIZE)) + return -1; + + fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC); + + pa_info_array = (prop_info*) (((char*) pa_workspace.data) + PA_INFO_START); + + pa = (prop_area*)(pa_workspace.data); + memset(pa, 0, PA_SIZE); + pa->magic = PROP_AREA_MAGIC; + pa->version = PROP_AREA_VERSION; + + /* plug into the lib property services */ + __legacy_property_area__ = pa; + property_area_inited = 1; + return 0; +} + +static void update_prop_info(prop_info *pi, const char *value, unsigned len) +{ + pi->serial = pi->serial | 1; + memcpy(pi->value, value, len + 1); + pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff); + __futex_wake(&pi->serial, INT32_MAX); +} + +static const prop_info *__legacy_property_find(const char *name) +{ + prop_area *pa = __legacy_property_area__; + unsigned count = pa->count; + unsigned *toc = pa->toc; + unsigned len = strlen(name); + prop_info *pi; + + while(count--) { + unsigned entry = *toc++; + if(TOC_NAME_LEN(entry) != len) continue; + + pi = TOC_TO_INFO(pa, entry); + if(memcmp(name, pi->name, len)) continue; + + return pi; + } + + return 0; +} + +static int legacy_property_set(const char *name, const char *value) +{ + prop_area *pa; + prop_info *pi; + + int namelen = strlen(name); + int valuelen = strlen(value); + + if(namelen >= PROP_NAME_MAX) return -1; + if(valuelen >= PROP_VALUE_MAX) return -1; + if(namelen < 1) return -1; + + pi = (prop_info*) __legacy_property_find(name); + + + if(pi != 0) { + /* ro.* properties may NEVER be modified once set */ + if(!strncmp(name, "ro.", 3)) return -1; + + pa = __legacy_property_area__; + update_prop_info(pi, value, valuelen); + pa->serial++; + __futex_wake(&pa->serial, INT32_MAX); + } else { + pa = __legacy_property_area__; + if(pa->count == PA_COUNT_MAX) return -1; + + pi = pa_info_array + pa->count; + pi->serial = (valuelen << 24); + memcpy(pi->name, name, namelen + 1); + memcpy(pi->value, value, valuelen + 1); + + pa->toc[pa->count] = + (namelen << 24) | (((unsigned long) pi) - ((unsigned long) pa)); + + pa->count++; + pa->serial++; + __futex_wake(&pa->serial, INT32_MAX); + } + + return 0; +} + +void legacy_get_property_workspace(int *fd, int *sz) +{ + *fd = pa_workspace.fd; + *sz = pa_workspace.size; +} + +static void copy_property_to_legacy(const char *key, const char *value, void *cookie __unused) +{ + legacy_property_set(key, value); +} + +int legacy_properties_init() +{ + if(init_property_area() != 0) + return -1; + + if(property_list(copy_property_to_legacy, 0) != 0) + return -1; + + return 0; +} diff --git a/twrpinstall/package.cpp b/twrpinstall/package.cpp new file mode 100755 index 00000000..ba1d5df6 --- /dev/null +++ b/twrpinstall/package.cpp @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2019 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 "twinstall/package.h" + +#include +#include + +#include +#include +#include +#include + +#include "otautil/error_code.h" +#include "otautil/sysutil.h" + +// This class wraps the package in memory, i.e. a memory mapped package, or a package loaded +// to a string/vector. +class MemoryPackage : public Package { + public: + // Constructs the class from a file. We will memory maps the file later. + MemoryPackage(const std::string& path, std::unique_ptr map); + + // Constructs the class from the package bytes in |content|. + MemoryPackage(std::vector content); + + ~MemoryPackage() override; + + // Memory maps the package file if necessary. Initializes the start address and size of the + // package. + uint64_t GetPackageSize() const override { + return package_size_; + } + + bool ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) override; + + ZipArchiveHandle GetZipArchiveHandle() override; + + bool UpdateHashAtOffset(const std::vector& hashers, uint64_t start, + uint64_t length) override; + + private: + const uint8_t* addr_; // Start address of the package in memory. + uint64_t package_size_; // Package size in bytes. + + // The memory mapped package. + std::unique_ptr map_; + // A copy of the package content, valid only if we create the class with the exact bytes of + // the package. + std::vector package_content_; + // The physical path to the package, empty if we create the class with the package content. + std::string path_; + + // The ZipArchiveHandle of the package. + ZipArchiveHandle zip_handle_; +}; + +void Package::SetProgress(float progress) { + if (set_progress_) { + set_progress_(progress); + } +} + +class FilePackage : public Package { + public: + FilePackage(android::base::unique_fd&& fd, uint64_t file_size, const std::string& path, + const std::function& set_progress); + + ~FilePackage() override; + + uint64_t GetPackageSize() const override { + return package_size_; + } + + bool ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) override; + + ZipArchiveHandle GetZipArchiveHandle() override; + + bool UpdateHashAtOffset(const std::vector& hashers, uint64_t start, + uint64_t length) override; + + private: + android::base::unique_fd fd_; // The underlying fd to the open package. + uint64_t package_size_; + std::string path_; // The physical path to the package. + + ZipArchiveHandle zip_handle_; +}; + +std::unique_ptr Package::CreateMemoryPackage( + const std::string& path) { + std::unique_ptr mmap = std::make_unique(); + if (!mmap->MapFile(path)) { + LOG(ERROR) << "failed to map file"; + return nullptr; + } + + return std::make_unique(path, std::move(mmap)); +} + +std::unique_ptr Package::CreateFilePackage( + const std::string& path, const std::function& set_progress) { + android::base::unique_fd fd(open(path.c_str(), O_RDONLY)); + if (fd == -1) { + PLOG(ERROR) << "Failed to open " << path; + return nullptr; + } + + off64_t file_size = lseek64(fd.get(), 0, SEEK_END); + if (file_size == -1) { + PLOG(ERROR) << "Failed to get the package size"; + return nullptr; + } + + return std::make_unique(std::move(fd), file_size, path, set_progress); +} + +std::unique_ptr Package::CreateMemoryPackage( + std::vector content) { + return std::make_unique(std::move(content)); +} + +MemoryPackage::MemoryPackage(const std::string& path, std::unique_ptr map) + : map_(std::move(map)), path_(path), zip_handle_(nullptr) { + addr_ = map_->addr; + package_size_ = map_->length; +} + +MemoryPackage::MemoryPackage(std::vector content) + : package_content_(std::move(content)), zip_handle_(nullptr) { + CHECK(!package_content_.empty()); + addr_ = package_content_.data(); + package_size_ = package_content_.size(); +} + +MemoryPackage::~MemoryPackage() { + if (zip_handle_) { + CloseArchive(zip_handle_); + } +} + +bool MemoryPackage::ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) { + if (byte_count > package_size_ || offset > package_size_ - byte_count) { + LOG(ERROR) << "Out of bound read, offset: " << offset << ", size: " << byte_count + << ", total package_size: " << package_size_; + return false; + } + memcpy(buffer, addr_ + offset, byte_count); + return true; +} + +bool MemoryPackage::UpdateHashAtOffset(const std::vector& hashers, + uint64_t start, uint64_t length) { + if (length > package_size_ || start > package_size_ - length) { + LOG(ERROR) << "Out of bound read, offset: " << start << ", size: " << length + << ", total package_size: " << package_size_; + return false; + } + + for (const auto& hasher : hashers) { + hasher(addr_ + start, length); + } + return true; +} + +ZipArchiveHandle MemoryPackage::GetZipArchiveHandle() { + if (zip_handle_) { + return zip_handle_; + } + + if (auto err = OpenArchiveFromMemory(const_cast(addr_), package_size_, path_.c_str(), + &zip_handle_); + err != 0) { + LOG(ERROR) << "Can't open package" << path_ << " : " << ErrorCodeString(err); + return nullptr; + } + + return zip_handle_; +} + +FilePackage::FilePackage(android::base::unique_fd&& fd, uint64_t file_size, const std::string& path, + const std::function& set_progress) + : fd_(std::move(fd)), package_size_(file_size), path_(path), zip_handle_(nullptr) { + set_progress_ = set_progress; +} + +FilePackage::~FilePackage() { + if (zip_handle_) { + CloseArchive(zip_handle_); + } +} + +bool FilePackage::ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) { + if (byte_count > package_size_ || offset > package_size_ - byte_count) { + LOG(ERROR) << "Out of bound read, offset: " << offset << ", size: " << byte_count + << ", total package_size: " << package_size_; + return false; + } + + if (!android::base::ReadFullyAtOffset(fd_.get(), buffer, byte_count, offset)) { + PLOG(ERROR) << "Failed to read " << byte_count << " bytes data at offset " << offset; + return false; + } + + return true; +} + +bool FilePackage::UpdateHashAtOffset(const std::vector& hashers, + uint64_t start, uint64_t length) { + if (length > package_size_ || start > package_size_ - length) { + LOG(ERROR) << "Out of bound read, offset: " << start << ", size: " << length + << ", total package_size: " << package_size_; + return false; + } + + uint64_t so_far = 0; + while (so_far < length) { + uint64_t read_size = std::min(length - so_far, 16 * MiB); + std::vector buffer(read_size); + if (!ReadFullyAtOffset(buffer.data(), read_size, start + so_far)) { + return false; + } + + for (const auto& hasher : hashers) { + hasher(buffer.data(), read_size); + } + so_far += read_size; + } + + return true; +} + +ZipArchiveHandle FilePackage::GetZipArchiveHandle() { + if (zip_handle_) { + return zip_handle_; + } + + if (auto err = OpenArchiveFd(fd_.get(), path_.c_str(), &zip_handle_); err != 0) { + LOG(ERROR) << "Can't open package" << path_ << " : " << ErrorCodeString(err); + return nullptr; + } + + return zip_handle_; +} diff --git a/twrpinstall/set_metadata.cpp b/twrpinstall/set_metadata.cpp new file mode 100644 index 00000000..2e1d769d --- /dev/null +++ b/twrpinstall/set_metadata.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2014 The Team Win Recovery 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. + */ + +/* + * The purpose of these functions is to try to get and set the proper + * file permissions, SELinux contexts, owner, and group so that these + * files are accessible when we boot up to normal Android via MTP and to + * file manager apps. During early boot we try to read the contexts and + * owner / group info from /data/media or from /data/media/0 and store + * them in static variables. From there, we'll try to set the same + * contexts, owner, and group information on most files we create during + * operations like backups, copying the log, and MTP operations. + */ + +#include +#include +#include +#include "selinux/selinux.h" + +static security_context_t selinux_context; +struct stat s; +static int has_stat = 0; + +int tw_get_context(const char* filename) { + if (lgetfilecon(filename, &selinux_context) >= 0) { + printf("tw_get_context got selinux context: %s\n", selinux_context); + return 0; + } else { + printf("tw_get_context failed to get selinux context\n"); + selinux_context = NULL; + } + return -1; +} + +int tw_get_stat(const char* filename) { + if (lstat(filename, &s) == 0) { + has_stat = 1; + return 0; + } + printf("tw_get_stat failed to lstat '%s'\n", filename); + return -1; +} + +int tw_get_default_metadata(const char* filename) { + if (tw_get_context(filename) == 0 && tw_get_stat(filename) == 0) + return 0; + return -1; +} + +// Most of this logging is disabled to prevent log spam if we are trying +// to set contexts and permissions on file systems that do not support +// these types of things (e.g. vfat / FAT / FAT32). +int tw_set_default_metadata(const char* filename) { + int ret = 0; + struct stat st; + + if (selinux_context == NULL) { + //printf("selinux_context was null, '%s'\n", filename); + ret = -1; + } else if (lsetfilecon(filename, selinux_context) < 0) { + //printf("Failed to set default contexts on '%s'.\n", filename); + ret = -1; + } + + if (lstat(filename, &st) == 0 && st.st_mode & S_IFREG && chmod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) < 0) { + //printf("Failed to chmod '%s'\n", filename); + ret = -1; + } + + if (has_stat && chown(filename, s.st_uid, s.st_gid) < 0) { + //printf("Failed to lchown '%s'.\n", filename); + ret = -1; + } + //printf("Done trying to set defaults on '%s'\n"); + return ret; +} diff --git a/install/tw_atomic.cpp b/twrpinstall/tw_atomic.cpp similarity index 100% rename from install/tw_atomic.cpp rename to twrpinstall/tw_atomic.cpp diff --git a/twinstall.cpp b/twrpinstall/twinstall.cpp similarity index 79% rename from twinstall.cpp rename to twrpinstall/twinstall.cpp index fd338288..65a83a69 100755 --- a/twinstall.cpp +++ b/twrpinstall/twinstall.cpp @@ -35,24 +35,16 @@ #include #include +#include + #include "twcommon.h" #include "mtdutils/mounts.h" #include "mtdutils/mtdutils.h" -#ifdef USE_MINZIP -#include "minzip/SysUtil.h" -#else #include "otautil/sysutil.h" #include -#endif -#include "zipwrap.hpp" -#ifdef USE_OLD_VERIFIER -#include "verifier24/verifier.h" -#elif USE_28_VERIFIER -#include "verifier28/verifier.h" -#else -#include "install/verifier.h" -#endif +#include "twinstall/install.h" +#include "twinstall/verifier.h" #include "variables.h" #include "data.hpp" #include "partitions.hpp" @@ -129,15 +121,17 @@ static int switch_to_new_properties() } #endif -static int Install_Theme(const char* path, ZipWrap *Zip) { +static int Install_Theme(const char* path, ZipArchiveHandle Zip) { #ifdef TW_OEM_BUILD // We don't do custom themes in OEM builds - Zip->Close(); + CloseArchive(Zip); return INSTALL_CORRUPT; #else - if (!Zip->EntryExists("ui.xml")) { + ZipString binary_name("ui.xml"); + ZipEntry binary_entry; + if (FindEntry(Zip, binary_name, &binary_entry) != 0) { + CloseArchive(Zip); return INSTALL_CORRUPT; } - Zip->Close(); if (!PartitionManager.Mount_Settings_Storage(true)) return INSTALL_ERROR; string theme_path = DataManager::GetSettingsStoragePath(); @@ -157,44 +151,60 @@ static int Install_Theme(const char* path, ZipWrap *Zip) { #endif } -static int Prepare_Update_Binary(const char *path, ZipWrap *Zip, int* wipe_cache) { +static int Prepare_Update_Binary(ZipArchiveHandle Zip) { char arches[PATH_MAX]; - std::string binary_name = ASSUMED_UPDATE_BINARY_NAME; property_get("ro.product.cpu.abilist", arches, "error"); if (strcmp(arches, "error") == 0) property_get("ro.product.cpu.abi", arches, "error"); vector split = TWFunc::split_string(arches, ',', true); std::vector::iterator arch; - std::string base_name = binary_name; + std::string base_name = UPDATE_BINARY_NAME; base_name += "-"; - for (arch = split.begin(); arch != split.end(); arch++) { - std::string temp = base_name + *arch; - if (Zip->EntryExists(temp)) { - binary_name = temp; - break; + ZipEntry binary_entry; + ZipString update_binary_string(UPDATE_BINARY_NAME); + if (FindEntry(Zip, update_binary_string, &binary_entry) != 0) { + for (arch = split.begin(); arch != split.end(); arch++) { + std::string temp = base_name + *arch; + ZipString binary_name(temp.c_str()); + if (FindEntry(Zip, binary_name, &binary_entry) != 0) { + ZipString binary_name(temp.c_str()); + break; + } } } - LOGINFO("Extracting updater binary '%s'\n", binary_name.c_str()); - if (!Zip->ExtractEntry(binary_name.c_str(), TMP_UPDATER_BINARY_PATH, 0755)) { - Zip->Close(); - LOGERR("Could not extract '%s'\n", ASSUMED_UPDATE_BINARY_NAME); + LOGINFO("Extracting updater binary '%s'\n", UPDATE_BINARY_NAME); + unlink(TMP_UPDATER_BINARY_PATH); + android::base::unique_fd fd( + open(TMP_UPDATER_BINARY_PATH, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0755)); + if (fd == -1) { + return INSTALL_ERROR; + } + int32_t err = ExtractEntryToFile(Zip, &binary_entry, fd); + if (err != 0) { + CloseArchive(Zip); + LOGERR("Could not extract '%s'\n", UPDATE_BINARY_NAME); return INSTALL_ERROR; } // If exists, extract file_contexts from the zip file - if (!Zip->EntryExists("file_contexts")) { - Zip->Close(); + ZipString file_contexts("file_contexts"); + ZipEntry file_contexts_entry; + if (FindEntry(Zip, file_contexts, &file_contexts_entry) != 0) { LOGINFO("Zip does not contain SELinux file_contexts file in its root.\n"); } else { const string output_filename = "/file_contexts"; LOGINFO("Zip contains SELinux file_contexts file in its root. Extracting to %s\n", output_filename.c_str()); - if (!Zip->ExtractEntry("file_contexts", output_filename, 0644)) { - Zip->Close(); + android::base::unique_fd fd( + open(output_filename.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0644)); + if (fd == -1) { + return INSTALL_ERROR; + } + if (ExtractEntryToFile(Zip, &file_contexts_entry, fd)) { + CloseArchive(Zip); LOGERR("Could not extract '%s'\n", output_filename.c_str()); return INSTALL_ERROR; } } - Zip->Close(); return INSTALL_SUCCESS; } @@ -233,7 +243,7 @@ static bool update_binary_has_legacy_properties(const char *binary) { } #endif -static int Run_Update_Binary(const char *path, ZipWrap *Zip, int* wipe_cache, zip_type ztype) { +static int Run_Update_Binary(const char *path, int* wipe_cache, zip_type ztype) { int ret_val, pipe_fd[2], status, zip_verify; char buffer[1024]; FILE* child_data; @@ -254,7 +264,7 @@ static int Run_Update_Binary(const char *path, ZipWrap *Zip, int* wipe_cache, zi if (ztype == UPDATE_BINARY_ZIP_TYPE) { ret_val = update_binary_command(path, 0, pipe_fd[1], &args); } else if (ztype == AB_OTA_ZIP_TYPE) { - ret_val = abupdate_binary_command(path, Zip, 0, pipe_fd[1], &args); + ret_val = abupdate_binary_command(path, 0, pipe_fd[1], &args); } else { LOGERR("Unknown zip type %i\n", ztype); ret_val = INSTALL_CORRUPT; @@ -296,7 +306,7 @@ static int Run_Update_Binary(const char *path, ZipWrap *Zip, int* wipe_cache, zi int seconds_float = strtol(seconds_char, NULL, 10); if (zip_verify) - DataManager::ShowProgress(fraction_float * (1 - VERIFICATION_PROGRESS_FRAC), seconds_float); + DataManager::ShowProgress(fraction_float * (1 - VERIFICATION_PROGRESS_FRACTION), seconds_float); else DataManager::ShowProgress(fraction_float, seconds_float); } else if (strcmp(command, "set_progress") == 0) { @@ -344,11 +354,6 @@ static int Run_Update_Binary(const char *path, ZipWrap *Zip, int* wipe_cache, zi int TWinstall_zip(const char* path, int* wipe_cache) { int ret_val, zip_verify = 1, unmount_system = 1; - if (strcmp(path, "error") == 0) { - LOGERR("Failed to get adb sideload file: '%s'\n", path); - return INSTALL_CORRUPT; - } - gui_msg(Msg("installing_zip=Installing zip file '{1}'")(path)); if (strlen(path) < 9 || strncmp(path, "/sideload", 9) != 0) { string digest_str; @@ -369,32 +374,22 @@ int TWinstall_zip(const char* path, int* wipe_cache) { #endif DataManager::SetProgress(0); - MemMapping map; -#ifdef USE_MINZIP - if (sysMapFile(path, &map) != 0) { -#else - if (!map.MapFile(path)) { -#endif - gui_msg(Msg(msg::kError, "fail_sysmap=Failed to map file '{1}'")(path)); - return -1; + auto package = Package::CreateMemoryPackage(path); + if (!package) { + return INSTALL_CORRUPT; } if (zip_verify) { gui_msg("verify_zip_sig=Verifying zip signature..."); -#ifdef USE_OLD_VERIFIER - ret_val = verify_file(map.addr, map.length); -#else - std::vector loadedKeys; - if (!load_keys("/res/keys", loadedKeys)) { - LOGINFO("Failed to load keys"); - gui_err("verify_zip_fail=Zip signature verification failed!"); -#ifdef USE_MINZIP - sysReleaseMap(&map); -#endif + static constexpr const char* CERTIFICATE_ZIP_FILE = "/system/etc/security/otacerts.zip"; + std::vector loaded_keys = LoadKeysFromZipfile(CERTIFICATE_ZIP_FILE); + if (loaded_keys.empty()) { + LOGERR("Failed to load keys\n"); return -1; } - ret_val = verify_file(map.addr, map.length, loadedKeys, std::bind(&DataManager::SetProgress, std::placeholders::_1)); -#endif + LOGINFO("%zu key(s) loaded from %s\n", loaded_keys.size(), CERTIFICATE_ZIP_FILE); + + ret_val = verify_file(package.get(), loaded_keys, std::bind(&DataManager::SetProgress, std::placeholders::_1)); if (ret_val != VERIFY_SUCCESS) { LOGINFO("Zip signature verification failed: %i\n", ret_val); gui_err("verify_zip_fail=Zip signature verification failed!"); @@ -406,12 +401,9 @@ int TWinstall_zip(const char* path, int* wipe_cache) { gui_msg("verify_zip_done=Zip signature verified successfully."); } } - ZipWrap Zip; - if (!Zip.Open(path, &map)) { - gui_err("zip_corrupt=Zip file is corrupt!"); -#ifdef USE_MINZIP - sysReleaseMap(&map); -#endif + + ZipArchiveHandle Zip = package->GetZipArchiveHandle(); + if (!Zip) { return INSTALL_CORRUPT; } @@ -427,23 +419,25 @@ int TWinstall_zip(const char* path, int* wipe_cache) { time_t start, stop; time(&start); - if (Zip.EntryExists(ASSUMED_UPDATE_BINARY_NAME)) { + + ZipString update_binary_name(UPDATE_BINARY_NAME); + ZipEntry update_binary_entry; + if (FindEntry(Zip, update_binary_name, &update_binary_entry) == 0) { LOGINFO("Update binary zip\n"); // Additionally verify the compatibility of the package. - if (!verify_package_compatibility(&Zip)) { + if (!verify_package_compatibility(Zip)) { gui_err("zip_compatible_err=Zip Treble compatibility error!"); - Zip.Close(); -#ifdef USE_MINZIP - sysReleaseMap(&map); -#endif + CloseArchive(Zip); ret_val = INSTALL_CORRUPT; } else { - ret_val = Prepare_Update_Binary(path, &Zip, wipe_cache); + ret_val = Prepare_Update_Binary(Zip); if (ret_val == INSTALL_SUCCESS) - ret_val = Run_Update_Binary(path, &Zip, wipe_cache, UPDATE_BINARY_ZIP_TYPE); + ret_val = Run_Update_Binary(path, wipe_cache, UPDATE_BINARY_ZIP_TYPE); } } else { - if (Zip.EntryExists(AB_OTA)) { + ZipString ab_binary_name(AB_OTA); + ZipEntry ab_binary_entry; + if (FindEntry(Zip, ab_binary_name, &ab_binary_entry) == 0) { LOGINFO("AB zip\n"); gui_msg(Msg(msg::kHighlight, "flash_ab_inactive=Flashing A/B zip to inactive slot: {1}")(PartitionManager.Get_Active_Slot_Display()=="A"?"B":"A")); // We need this so backuptool can do its magic @@ -451,9 +445,9 @@ int TWinstall_zip(const char* path, int* wipe_cache) { bool vendor_mount_state = PartitionManager.Is_Mounted_By_Path("/vendor"); PartitionManager.Mount_By_Path(PartitionManager.Get_Android_Root_Path(), true); PartitionManager.Mount_By_Path("/vendor", true); - TWFunc::Exec_Cmd("cp -f /system/bin/sh /tmp/sh"); + TWFunc::copy_file("/system/bin/sh", "/tmp/sh", 0755); mount("/tmp/sh", "/system/bin/sh", "auto", MS_BIND, NULL); - ret_val = Run_Update_Binary(path, &Zip, wipe_cache, AB_OTA_ZIP_TYPE); + ret_val = Run_Update_Binary(path, wipe_cache, AB_OTA_ZIP_TYPE); umount("/system/bin/sh"); unlink("/tmp/sh"); if (!vendor_mount_state) @@ -461,13 +455,14 @@ int TWinstall_zip(const char* path, int* wipe_cache) { if (!system_mount_state) PartitionManager.UnMount_By_Path(PartitionManager.Get_Android_Root_Path(), true); gui_warn("flash_ab_reboot=To flash additional zips, please reboot recovery to switch to the updated slot."); - } else { - if (Zip.EntryExists("ui.xml")) { + ZipString binary_name("ui.xml"); + ZipEntry binary_entry; + if (FindEntry(Zip, binary_name, &binary_entry) != 0) { LOGINFO("TWRP theme zip\n"); - ret_val = Install_Theme(path, &Zip); + ret_val = Install_Theme(path, Zip); } else { - Zip.Close(); + CloseArchive(Zip); ret_val = INSTALL_CORRUPT; } } @@ -479,8 +474,5 @@ int TWinstall_zip(const char* path, int* wipe_cache) { } else { LOGINFO("Install took %i second(s).\n", total_time); } -#ifdef USE_MINZIP - sysReleaseMap(&map); -#endif return ret_val; } diff --git a/verifier28/verifier.cpp b/twrpinstall/verifier.cpp old mode 100644 new mode 100755 similarity index 57% rename from verifier28/verifier.cpp rename to twrpinstall/verifier.cpp index 283e0430..f5779619 --- a/verifier28/verifier.cpp +++ b/twrpinstall/verifier.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "verifier.h" +#include "twinstall/verifier.h" #include #include @@ -27,14 +27,17 @@ #include #include +#include #include #include +#include #include +#include +#include +#include -#include "asn1_decoder.h" #include "otautil/print_sha1.h" - -static constexpr size_t MiB = 1024 * 1024; +#include "private/asn1_decoder.h" /* * Simple version of PKCS#7 SignedData extraction. This extracts the @@ -79,10 +82,8 @@ static bool read_pkcs7(const uint8_t* pkcs7_der, size_t pkcs7_der_len, } std::unique_ptr signed_data_seq(signed_data_app->asn1_sequence_get()); - if (signed_data_seq == nullptr || - !signed_data_seq->asn1_sequence_next() || - !signed_data_seq->asn1_sequence_next() || - !signed_data_seq->asn1_sequence_next() || + if (signed_data_seq == nullptr || !signed_data_seq->asn1_sequence_next() || + !signed_data_seq->asn1_sequence_next() || !signed_data_seq->asn1_sequence_next() || !signed_data_seq->asn1_constructed_skip_all()) { return false; } @@ -93,11 +94,8 @@ static bool read_pkcs7(const uint8_t* pkcs7_der, size_t pkcs7_der_len, } std::unique_ptr sig_seq(sig_set->asn1_sequence_get()); - if (sig_seq == nullptr || - !sig_seq->asn1_sequence_next() || - !sig_seq->asn1_sequence_next() || - !sig_seq->asn1_sequence_next() || - !sig_seq->asn1_sequence_next()) { + if (sig_seq == nullptr || !sig_seq->asn1_sequence_next() || !sig_seq->asn1_sequence_next() || + !sig_seq->asn1_sequence_next() || !sig_seq->asn1_sequence_next()) { return false; } @@ -112,16 +110,11 @@ static bool read_pkcs7(const uint8_t* pkcs7_der, size_t pkcs7_der_len, return true; } -/* - * Looks for an RSA signature embedded in the .ZIP file comment given the path to the zip. Verifies - * that it matches one of the given public keys. A callback function can be optionally provided for - * posting the progress. - * - * Returns VERIFY_SUCCESS or VERIFY_FAILURE (if any error is encountered or no key matches the - * signature). - */ -int verify_file(const unsigned char* addr, size_t length, const std::vector& keys, - const std::function& set_progress) { +int verify_file(VerifierInterface* package, const std::vector& keys, + const std::function& set_progress) { + CHECK(package); + package->SetProgress(0.0); + if (set_progress) { set_progress(0.0); } @@ -135,13 +128,18 @@ int verify_file(const unsigned char* addr, size_t length, const std::vectorGetPackageSize(); if (length < FOOTER_SIZE) { LOG(ERROR) << "not big enough to contain footer"; return VERIFY_FAILURE; } - const unsigned char* footer = addr + length - FOOTER_SIZE; + uint8_t footer[FOOTER_SIZE]; + if (!package->ReadFullyAtOffset(footer, FOOTER_SIZE, length - FOOTER_SIZE)) { + LOG(ERROR) << "Failed to read footer"; + return VERIFY_FAILURE; + } if (footer[2] != 0xff || footer[3] != 0xff) { LOG(ERROR) << "footer is wrong"; @@ -154,8 +152,8 @@ int verify_file(const unsigned char* addr, size_t length, const std::vector comment_size) { - LOG(ERROR) << "signature start: " << signature_start << " is larger than comment size: " - << comment_size; + LOG(ERROR) << "signature start: " << signature_start + << " is larger than comment size: " << comment_size; return VERIFY_FAILURE; } @@ -177,9 +175,13 @@ int verify_file(const unsigned char* addr, size_t length, const std::vectorReadFullyAtOffset(eocd, eocd_size, length - eocd_size)) { + LOG(ERROR) << "Failed to read EOCD of " << eocd_size << " bytes"; + return VERIFY_FAILURE; + } // If this is really is the EOCD record, it will begin with the magic number $50 $4b $05 $06. if (eocd[0] != 0x50 || eocd[1] != 0x4b || eocd[2] != 0x05 || eocd[3] != 0x06) { @@ -187,8 +189,8 @@ int verify_file(const unsigned char* addr, size_t length, const std::vector hashers; + if (need_sha1) { + hashers.emplace_back( + std::bind(&SHA1_Update, &sha1_ctx, std::placeholders::_1, std::placeholders::_2)); + } + if (need_sha256) { + hashers.emplace_back( + std::bind(&SHA256_Update, &sha256_ctx, std::placeholders::_1, std::placeholders::_2)); + } + double frac = -1.0; - size_t so_far = 0; + uint64_t so_far = 0; while (so_far < signed_len) { - // On a Nexus 5X, experiment showed 16MiB beat 1MiB by 6% faster for a - // 1196MiB full OTA and 60% for an 89MiB incremental OTA. - // http://b/28135231. - size_t size = std::min(signed_len - so_far, 16 * MiB); + // On a Nexus 5X, experiment showed 16MiB beat 1MiB by 6% faster for a 1196MiB full OTA and + // 60% for an 89MiB incremental OTA. http://b/28135231. + uint64_t read_size = std::min(signed_len - so_far, 16 * MiB); + package->UpdateHashAtOffset(hashers, so_far, read_size); + so_far += read_size; - if (need_sha1) SHA1_Update(&sha1_ctx, addr + so_far, size); - if (need_sha256) SHA256_Update(&sha256_ctx, addr + so_far, size); - so_far += size; - - if (set_progress) { - double f = so_far / (double)signed_len; - if (f > frac + 0.02 || size == so_far) { + double f = so_far / static_cast(signed_len); + if (f > frac + 0.02 || read_size == so_far) { + package->SetProgress(f); + frac = f; + if (set_progress) { set_progress(f); - frac = f; } } } @@ -240,8 +254,8 @@ int verify_file(const unsigned char* addr, size_t length, const std::vector sig_der; if (!read_pkcs7(signature, signature_size, &sig_der)) { @@ -375,179 +389,161 @@ std::unique_ptr parse_rsa_key(FILE* file, uint32_t exponent) { return key; } -struct BNDeleter { - void operator()(BIGNUM* bn) const { - BN_free(bn); + +static std::vector IterateZipEntriesAndSearchForKeys(const ZipArchiveHandle& handle) { + void* cookie; + ZipString suffix("x509.pem"); + int32_t iter_status = StartIteration(handle, &cookie, nullptr, &suffix); + if (iter_status != 0) { + LOG(ERROR) << "Failed to iterate over entries in the certificate zipfile: " + << ErrorCodeString(iter_status); + return {}; } -}; -std::unique_ptr parse_ec_key(FILE* file) { - uint32_t key_len_bytes = 0; - if (fscanf(file, " %i", &key_len_bytes) != 1) { - return nullptr; + std::vector result; + + ZipString name; + ZipEntry entry; + while ((iter_status = Next(cookie, &entry, &name)) == 0) { + std::vector pem_content(entry.uncompressed_length); + if (int32_t extract_status = + ExtractToMemory(handle, &entry, pem_content.data(), pem_content.size()); + extract_status != 0) { + LOG(ERROR) << "Failed to extract " << std::string(name.name, name.name + name.name_length); + return {}; } - std::unique_ptr group( - EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1), EC_GROUP_free); - if (!group) { - return nullptr; + Certificate cert(0, Certificate::KEY_TYPE_RSA, nullptr, nullptr); + // Aborts the parsing if we fail to load one of the key file. + if (!LoadCertificateFromBuffer(pem_content, &cert)) { + LOG(ERROR) << "Failed to load keys from " + << std::string(name.name, name.name + name.name_length); + return {}; } - // Verify that |key_len| matches the group order. - if (key_len_bytes != BN_num_bytes(EC_GROUP_get0_order(group.get()))) { - return nullptr; - } + result.emplace_back(std::move(cert)); + } - // Read the public key coordinates. Note that the byte order in the file is - // little-endian, so we convert to big-endian here. - std::unique_ptr bytes(new uint8_t[key_len_bytes]); - std::unique_ptr point[2]; - for (int i = 0; i < 2; ++i) { - unsigned int byte = 0; - if (fscanf(file, " , { %u", &byte) != 1) { - return nullptr; - } - bytes[key_len_bytes - 1] = byte; + if (iter_status != -1) { + LOG(ERROR) << "Error while iterating over zip entries: " << ErrorCodeString(iter_status); + return {}; + } - for (size_t i = 1; i < key_len_bytes; ++i) { - if (fscanf(file, " , %u", &byte) != 1) { - return nullptr; - } - bytes[key_len_bytes - i - 1] = byte; - } - - point[i].reset(BN_bin2bn(bytes.get(), key_len_bytes, nullptr)); - if (!point[i]) { - return nullptr; - } - - if (fscanf(file, " }") != 0) { - return nullptr; - } - } - - if (fscanf(file, " } ") != 0) { - return nullptr; - } - - // Create and initialize the key. - std::unique_ptr key(EC_KEY_new()); - if (!key || !EC_KEY_set_group(key.get(), group.get()) || - !EC_KEY_set_public_key_affine_coordinates(key.get(), point[0].get(), - point[1].get())) { - return nullptr; - } - - return key; + return result; } -// Reads a file containing one or more public keys as produced by -// DumpPublicKey: this is an RSAPublicKey struct as it would appear -// as a C source literal, eg: -// -// "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}" -// -// For key versions newer than the original 2048-bit e=3 keys -// supported by Android, the string is preceded by a version -// identifier, eg: -// -// "v2 {64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}" -// -// (Note that the braces and commas in this example are actual -// characters the parser expects to find in the file; the ellipses -// indicate more numbers omitted from this example.) -// -// The file may contain multiple keys in this format, separated by -// commas. The last key must not be followed by a comma. -// -// A Certificate is a pair of an RSAPublicKey and a particular hash -// (we support SHA-1 and SHA-256; we store the hash length to signify -// which is being used). The hash used is implied by the version number. -// -// 1: 2048-bit RSA key with e=3 and SHA-1 hash -// 2: 2048-bit RSA key with e=65537 and SHA-1 hash -// 3: 2048-bit RSA key with e=3 and SHA-256 hash -// 4: 2048-bit RSA key with e=65537 and SHA-256 hash -// 5: 256-bit EC key using the NIST P-256 curve parameters and SHA-256 hash -// -// Returns true on success, and appends the found keys (at least one) to certs. -// Otherwise returns false if the file failed to parse, or if it contains zero -// keys. The contents in certs would be unspecified on failure. -bool load_keys(const char* filename, std::vector& certs) { - std::unique_ptr f(fopen(filename, "re"), fclose); - if (!f) { - PLOG(ERROR) << "error opening " << filename; +std::vector LoadKeysFromZipfile(const std::string& zip_name) { + ZipArchiveHandle handle; + if (int32_t open_status = OpenArchive(zip_name.c_str(), &handle); open_status != 0) { + LOG(ERROR) << "Failed to open " << zip_name << ": " << ErrorCodeString(open_status); + return {}; + } + + std::vector result = IterateZipEntriesAndSearchForKeys(handle); + CloseArchive(handle); + return result; +} + +bool CheckRSAKey(const std::unique_ptr& rsa) { + if (!rsa) { return false; } - while (true) { - certs.emplace_back(0, Certificate::KEY_TYPE_RSA, nullptr, nullptr); - Certificate& cert = certs.back(); - uint32_t exponent = 0; - - char start_char; - if (fscanf(f.get(), " %c", &start_char) != 1) return false; - if (start_char == '{') { - // a version 1 key has no version specifier. - cert.key_type = Certificate::KEY_TYPE_RSA; - exponent = 3; - cert.hash_len = SHA_DIGEST_LENGTH; - } else if (start_char == 'v') { - int version; - if (fscanf(f.get(), "%d {", &version) != 1) return false; - switch (version) { - case 2: - cert.key_type = Certificate::KEY_TYPE_RSA; - exponent = 65537; - cert.hash_len = SHA_DIGEST_LENGTH; - break; - case 3: - cert.key_type = Certificate::KEY_TYPE_RSA; - exponent = 3; - cert.hash_len = SHA256_DIGEST_LENGTH; - break; - case 4: - cert.key_type = Certificate::KEY_TYPE_RSA; - exponent = 65537; - cert.hash_len = SHA256_DIGEST_LENGTH; - break; - case 5: - cert.key_type = Certificate::KEY_TYPE_EC; - cert.hash_len = SHA256_DIGEST_LENGTH; - break; - default: - return false; - } - } - - if (cert.key_type == Certificate::KEY_TYPE_RSA) { - cert.rsa = parse_rsa_key(f.get(), exponent); - if (!cert.rsa) { - return false; - } - - LOG(INFO) << "read key e=" << exponent << " hash=" << cert.hash_len; - } else if (cert.key_type == Certificate::KEY_TYPE_EC) { - cert.ec = parse_ec_key(f.get()); - if (!cert.ec) { - return false; - } - } else { - LOG(ERROR) << "Unknown key type " << cert.key_type; - return false; - } - - // if the line ends in a comma, this file has more keys. - int ch = fgetc(f.get()); - if (ch == ',') { - // more keys to come. - continue; - } else if (ch == EOF) { - break; - } else { - LOG(ERROR) << "unexpected character between keys"; - return false; - } + const BIGNUM* out_n; + const BIGNUM* out_e; + RSA_get0_key(rsa.get(), &out_n, &out_e, nullptr /* private exponent */); + auto modulus_bits = BN_num_bits(out_n); + if (modulus_bits != 2048 && modulus_bits != 4096) { + LOG(ERROR) << "Modulus should be 2048 or 4096 bits long, actual: " << modulus_bits; + return false; } + + BN_ULONG exponent = BN_get_word(out_e); + if (exponent != 3 && exponent != 65537) { + LOG(ERROR) << "Public exponent should be 3 or 65537, actual: " << exponent; + return false; + } + + return true; +} + +bool CheckECKey(const std::unique_ptr& ec_key) { + if (!ec_key) { + return false; + } + + const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key.get()); + if (!ec_group) { + LOG(ERROR) << "Failed to get the ec_group from the ec_key"; + return false; + } + auto degree = EC_GROUP_get_degree(ec_group); + if (degree != 256) { + LOG(ERROR) << "Field size of the ec key should be 256 bits long, actual: " << degree; + return false; + } + + return true; +} + +bool LoadCertificateFromBuffer(const std::vector& pem_content, Certificate* cert) { + std::unique_ptr content( + BIO_new_mem_buf(pem_content.data(), pem_content.size()), BIO_free); + + std::unique_ptr x509( + PEM_read_bio_X509(content.get(), nullptr, nullptr, nullptr), X509_free); + if (!x509) { + LOG(ERROR) << "Failed to read x509 certificate"; + return false; + } + + int nid = X509_get_signature_nid(x509.get()); + switch (nid) { + // SignApk has historically accepted md5WithRSA certificates, but treated them as + // sha1WithRSA anyway. Continue to do so for backwards compatibility. + case NID_md5WithRSA: + case NID_md5WithRSAEncryption: + case NID_sha1WithRSA: + case NID_sha1WithRSAEncryption: + cert->hash_len = SHA_DIGEST_LENGTH; + break; + case NID_sha256WithRSAEncryption: + case NID_ecdsa_with_SHA256: + cert->hash_len = SHA256_DIGEST_LENGTH; + break; + default: + LOG(ERROR) << "Unrecognized signature nid " << OBJ_nid2ln(nid); + return false; + } + + std::unique_ptr public_key(X509_get_pubkey(x509.get()), + EVP_PKEY_free); + if (!public_key) { + LOG(ERROR) << "Failed to extract the public key from x509 certificate"; + return false; + } + + int key_type = EVP_PKEY_id(public_key.get()); + if (key_type == EVP_PKEY_RSA) { + cert->key_type = Certificate::KEY_TYPE_RSA; + cert->ec.reset(); + cert->rsa.reset(EVP_PKEY_get1_RSA(public_key.get())); + if (!cert->rsa || !CheckRSAKey(cert->rsa)) { + LOG(ERROR) << "Failed to validate the rsa key info from public key"; + return false; + } + } else if (key_type == EVP_PKEY_EC) { + cert->key_type = Certificate::KEY_TYPE_EC; + cert->rsa.reset(); + cert->ec.reset(EVP_PKEY_get1_EC_KEY(public_key.get())); + if (!cert->ec || !CheckECKey(cert->ec)) { + LOG(ERROR) << "Failed to validate the ec key info from the public key"; + return false; + } + } else { + LOG(ERROR) << "Unrecognized public key type " << OBJ_nid2ln(key_type); + return false; + } + return true; } diff --git a/verifier28/verifier.h b/verifier28/verifier.h deleted file mode 100644 index 665e5a9b..00000000 --- a/verifier28/verifier.h +++ /dev/null @@ -1,82 +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 _RECOVERY_VERIFIER_H -#define _RECOVERY_VERIFIER_H - -#include -#include -#include - -#include -#include -#include - -#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary" - -enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_RETRY }; - -static const float VERIFICATION_PROGRESS_FRAC = 0.25; - -struct RSADeleter { - void operator()(RSA* rsa) const { - RSA_free(rsa); - } -}; - -struct ECKEYDeleter { - void operator()(EC_KEY* ec_key) const { - EC_KEY_free(ec_key); - } -}; - -struct Certificate { - typedef enum { - KEY_TYPE_RSA, - KEY_TYPE_EC, - } KeyType; - - Certificate(int hash_len_, - KeyType key_type_, - std::unique_ptr&& rsa_, - std::unique_ptr&& ec_) - : hash_len(hash_len_), - key_type(key_type_), - rsa(std::move(rsa_)), - ec(std::move(ec_)) {} - - // SHA_DIGEST_LENGTH (SHA-1) or SHA256_DIGEST_LENGTH (SHA-256) - int hash_len; - KeyType key_type; - std::unique_ptr rsa; - std::unique_ptr ec; -}; - -/* - * 'addr' and 'length' define an update package file that has been loaded (or mmap'ed, or - * whatever) into memory. Verifies that the file is signed and the signature matches one of the - * given keys. It optionally accepts a callback function for posting the progress to. Returns one - * of the constants of VERIFY_SUCCESS and VERIFY_FAILURE. - */ -int verify_file(const unsigned char* addr, size_t length, const std::vector& keys, - const std::function& set_progress = nullptr); - -bool load_keys(const char* filename, std::vector& certs); - -#define VERIFY_SUCCESS 0 -#define VERIFY_FAILURE 1 - -#endif /* _RECOVERY_VERIFIER_H */