Merge AOSP android-9.0.0_r3
Fix conflicts and make it build in 5.1, 6.0, 7.1, 8.1, and 9.0
Change-Id: Ida0a64c29ff27d339b7f42a18d820930964ac6e4
diff --git a/.clang-format b/.clang-format
index 5322788..0e0f4d1 100644
--- a/.clang-format
+++ b/.clang-format
@@ -10,6 +10,5 @@
PointerAlignment: Left
TabWidth: 2
UseTab: Never
-PenaltyExcessCharacter: 32
Cpp11BracedListStyle: false
diff --git a/Android.bp b/Android.bp
index 07fc27d..8837b20 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,8 @@
subdirs = [
-// "bootloader_message",
+// "applypatch",
+ "bootloader_message",
+// "edify",
+// "otafault",
// "otautil",
+// "uncrypt",
]
diff --git a/Android.mk b/Android.mk
index 6880ed2..cacd783 100644
--- a/Android.mk
+++ b/Android.mk
@@ -13,6 +13,7 @@
# limitations under the License.
LOCAL_PATH := $(call my-dir)
+commands_TWRP_local_path := $(LOCAL_PATH)
ifdef project-path-for
ifeq ($(LOCAL_PATH),$(call project-path-for,recovery))
@@ -114,6 +115,7 @@
LOCAL_C_INCLUDES += bionic
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
LOCAL_C_INCLUDES += external/stlport/stlport external/openssl/include
+ LOCAL_CFLAGS += -DUSE_FUSE_SIDELOAD22
else
LOCAL_C_INCLUDES += external/boringssl/include external/libcxx/include
endif
@@ -143,6 +145,7 @@
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26; echo $$?),0)
LOCAL_SHARED_LIBRARIES += libziparchive
+ LOCAL_C_INCLUDES += $(LOCAL_PATH)/otautil/include
else
LOCAL_SHARED_LIBRARIES += libminzip
LOCAL_CFLAGS += -DUSE_MINZIP
@@ -160,11 +163,13 @@
endif
ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
- LOCAL_CFLAGS += -DUSE_EXT4
- LOCAL_C_INCLUDES += system/extras/ext4_utils
- LOCAL_SHARED_LIBRARIES += libext4_utils
- ifneq ($(wildcard external/lz4/Android.mk),)
- #LOCAL_STATIC_LIBRARIES += liblz4
+ ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 28; echo $$?),0)
+ LOCAL_CFLAGS += -DUSE_EXT4
+ LOCAL_C_INCLUDES += system/extras/ext4_utils
+ LOCAL_SHARED_LIBRARIES += libext4_utils
+ ifneq ($(wildcard external/lz4/Android.mk),)
+ #LOCAL_STATIC_LIBRARIES += liblz4
+ endif
endif
endif
LOCAL_C_INCLUDES += external/libselinux/include
@@ -181,7 +186,7 @@
ifeq ($(AB_OTA_UPDATER),true)
LOCAL_CFLAGS += -DAB_OTA_UPDATER=1
LOCAL_SHARED_LIBRARIES += libhardware
- LOCAL_ADDITIONAL_DEPENDENCIES += libhardware
+ LOCAL_REQUIRED_MODULES += libhardware
endif
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
@@ -362,7 +367,7 @@
ifneq ($(TW_CLOCK_OFFSET),)
LOCAL_CFLAGS += -DTW_CLOCK_OFFSET=$(TW_CLOCK_OFFSET)
endif
-LOCAL_ADDITIONAL_DEPENDENCIES += \
+LOCAL_REQUIRED_MODULES += \
dump_image \
erase_image \
flash_image \
@@ -390,7 +395,6 @@
LOCAL_LDFLAGS += -Wl,-dynamic-linker,/sbin/linker64
endif
ifneq ($(TW_USE_TOOLBOX), true)
- LOCAL_ADDITIONAL_DEPENDENCIES += busybox_symlinks
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 24; echo $$?),0)
LOCAL_POST_INSTALL_CMD := \
$(hide) mkdir -p $(TARGET_RECOVERY_ROOT_OUT)/sbin && \
@@ -398,72 +402,72 @@
endif
else
ifneq ($(wildcard external/toybox/Android.mk),)
- LOCAL_ADDITIONAL_DEPENDENCIES += toybox_symlinks
+ LOCAL_REQUIRED_MODULES += toybox_symlinks
endif
ifneq ($(wildcard external/zip/Android.mk),)
- LOCAL_ADDITIONAL_DEPENDENCIES += zip
+ LOCAL_REQUIRED_MODULES += zip
endif
ifneq ($(wildcard external/unzip/Android.mk),)
- LOCAL_ADDITIONAL_DEPENDENCIES += unzip
+ LOCAL_REQUIRED_MODULES += unzip
endif
endif
ifneq ($(TW_NO_EXFAT), true)
- LOCAL_ADDITIONAL_DEPENDENCIES += mkexfatfs fsckexfat
+ LOCAL_REQUIRED_MODULES += mkexfatfs fsckexfat
ifneq ($(TW_NO_EXFAT_FUSE), true)
- LOCAL_ADDITIONAL_DEPENDENCIES += exfat-fuse
+ LOCAL_REQUIRED_MODULES += exfat-fuse
endif
endif
ifeq ($(BOARD_HAS_NO_REAL_SDCARD),)
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 22; echo $$?),0)
- LOCAL_ADDITIONAL_DEPENDENCIES += sgdisk
+ LOCAL_REQUIRED_MODULES += sgdisk
else
- LOCAL_ADDITIONAL_DEPENDENCIES += sgdisk_static
+ LOCAL_REQUIRED_MODULES += sgdisk_static
endif
endif
ifneq ($(TW_EXCLUDE_ENCRYPTED_BACKUPS), true)
- LOCAL_ADDITIONAL_DEPENDENCIES += openaes openaes_license
+ LOCAL_REQUIRED_MODULES += openaes openaes_license
endif
ifeq ($(TW_INCLUDE_DUMLOCK), true)
- LOCAL_ADDITIONAL_DEPENDENCIES += \
+ LOCAL_REQUIRED_MODULES += \
htcdumlock htcdumlocksys flash_imagesys dump_imagesys libbmlutils.so \
libflashutils.so libmmcutils.so libmtdutils.so HTCDumlock.apk
endif
ifeq ($(TW_INCLUDE_FB2PNG), true)
- LOCAL_ADDITIONAL_DEPENDENCIES += fb2png
+ LOCAL_REQUIRED_MODULES += fb2png
endif
ifneq ($(TW_OEM_BUILD),true)
- LOCAL_ADDITIONAL_DEPENDENCIES += orscmd
+ LOCAL_REQUIRED_MODULES += orscmd
endif
ifeq ($(BOARD_USES_BML_OVER_MTD),true)
- LOCAL_ADDITIONAL_DEPENDENCIES += bml_over_mtd
+ LOCAL_REQUIRED_MODULES += bml_over_mtd
endif
ifeq ($(TW_INCLUDE_INJECTTWRP), true)
- LOCAL_ADDITIONAL_DEPENDENCIES += injecttwrp
+ LOCAL_REQUIRED_MODULES += injecttwrp
endif
ifneq ($(TW_EXCLUDE_DEFAULT_USB_INIT), true)
- LOCAL_ADDITIONAL_DEPENDENCIES += init.recovery.usb.rc
+ LOCAL_REQUIRED_MODULES += init.recovery.usb.rc
endif
ifeq ($(TWRP_INCLUDE_LOGCAT), true)
- LOCAL_ADDITIONAL_DEPENDENCIES += logcat
+ LOCAL_REQUIRED_MODULES += logcat
ifeq ($(TARGET_USES_LOGD), true)
- LOCAL_ADDITIONAL_DEPENDENCIES += logd libsysutils libnl init.recovery.logd.rc
+ LOCAL_REQUIRED_MODULES += logd libsysutils libnl init.recovery.logd.rc
endif
endif
# Allow devices to specify device-specific recovery dependencies
ifneq ($(TARGET_RECOVERY_DEVICE_MODULES),)
- LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_RECOVERY_DEVICE_MODULES)
+ LOCAL_REQUIRED_MODULES += $(TARGET_RECOVERY_DEVICE_MODULES)
endif
LOCAL_CFLAGS += -DTWRES=\"$(TWRES_PATH)\"
LOCAL_CFLAGS += -DTWHTCD_PATH=\"$(TWHTCD_PATH)\"
ifeq ($(TW_INCLUDE_NTFS_3G),true)
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 22; echo $$?),0)
- LOCAL_ADDITIONAL_DEPENDENCIES += \
+ LOCAL_REQUIRED_MODULES += \
mount.ntfs \
fsck.ntfs \
mkfs.ntfs
else
- LOCAL_ADDITIONAL_DEPENDENCIES += \
+ LOCAL_REQUIRED_MODULES += \
ntfs-3g \
ntfsfix \
mkntfs
@@ -471,14 +475,14 @@
endif
ifeq ($(TARGET_USERIMAGES_USE_F2FS), true)
ifeq ($(shell test $(CM_PLATFORM_SDK_VERSION) -ge 3; echo $$?),0)
- LOCAL_ADDITIONAL_DEPENDENCIES += \
+ LOCAL_REQUIRED_MODULES += \
fsck.f2fs \
mkfs.f2fs
endif
endif
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 25; echo $$?),0)
- LOCAL_ADDITIONAL_DEPENDENCIES += file_contexts_text
+ LOCAL_REQUIRED_MODULES += file_contexts_text
endif
ifeq ($(BOARD_CACHEIMAGE_PARTITION_SIZE),)
@@ -494,7 +498,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_REQUIRED_MODULES := file_contexts.bin
LOCAL_POST_INSTALL_CMD := \
- $(hide) cp -f $(OUT)/obj/ETC/file_contexts.bin_intermediates/file_contexts.concat.tmp $(TARGET_RECOVERY_ROOT_OUT)/file_contexts
+ $(hide) cp -f $(PRODUCT_OUT)/obj/ETC/file_contexts.bin_intermediates/file_contexts.concat.tmp $(TARGET_RECOVERY_ROOT_OUT)/file_contexts
include $(BUILD_PHONY_PACKAGE)
@@ -571,9 +575,8 @@
# shared libfusesideload
# ===============================
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := fuse_sideload.cpp
LOCAL_CLANG := true
-LOCAL_CFLAGS := -Wall -Werror
+LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
LOCAL_MODULE_TAGS := optional
@@ -586,14 +589,19 @@
else
LOCAL_SHARED_LIBRARIES += libcrypto
endif
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
+ LOCAL_SRC_FILES := fuse_sideload22.cpp
+ LOCAL_CFLAGS += -DUSE_FUSE_SIDELOAD22
+else
+ LOCAL_SRC_FILES := fuse_sideload.cpp
+endif
include $(BUILD_SHARED_LIBRARY)
# static libfusesideload
# =============================== (required to fix build errors in 8.1 due to use by tests)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := fuse_sideload.cpp
LOCAL_CLANG := true
-LOCAL_CFLAGS := -Wall -Werror
+LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
LOCAL_MODULE_TAGS := optional
@@ -606,6 +614,12 @@
else
LOCAL_STATIC_LIBRARIES += libcrypto_static
endif
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
+ LOCAL_SRC_FILES := fuse_sideload22.cpp
+ LOCAL_CFLAGS += -DUSE_FUSE_SIDELOAD22
+else
+ LOCAL_SRC_FILES := fuse_sideload.cpp
+endif
include $(BUILD_STATIC_LIBRARY)
# libmounts (static library)
@@ -634,6 +648,7 @@
LOCAL_MODULE := librecovery
LOCAL_STATIC_LIBRARIES := \
libminui \
+ libotautil \
libvintf_recovery \
libcrypto_utils \
libcrypto \
@@ -646,6 +661,7 @@
# ===============================
include $(CLEAR_VARS)
+
LOCAL_MODULE := libaosprecovery
LOCAL_MODULE_TAGS := eng optional
LOCAL_CFLAGS := -std=gnu++0x
@@ -655,6 +671,7 @@
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
LOCAL_SHARED_LIBRARIES += libstdc++ libstlport
LOCAL_C_INCLUDES += bionic external/stlport/stlport
+ LOCAL_CFLAGS += -DUSE_FUSE_SIDELOAD22
else
LOCAL_SHARED_LIBRARIES += libc++
endif
@@ -666,37 +683,49 @@
else
LOCAL_SHARED_LIBRARIES += libcrypto libbase
LOCAL_SRC_FILES += verifier.cpp asn1_decoder.cpp
+ LOCAL_C_INCLUDES += $(LOCAL_PATH)/otautil/include
endif
ifeq ($(AB_OTA_UPDATER),true)
LOCAL_CFLAGS += -DAB_OTA_UPDATER=1
endif
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26; echo $$?),0)
- LOCAL_SRC_FILES += otautil/ZipUtil.cpp otautil/SysUtil.cpp
+ LOCAL_SRC_FILES += otautil/ZipUtil.cpp otautil/SysUtil.cpp otautil/DirUtil.cpp
LOCAL_SHARED_LIBRARIES += libziparchive libext4_utils libcrypto libcrypto_utils
LOCAL_STATIC_LIBRARIES += libvintf_recovery libfs_mgr liblogwrap libavb libvintf libtinyxml2 libz
- LOCAL_WHOLE_STATIC_LIBRARIES +=
+ LOCAL_C_INCLUDES += $(LOCAL_PATH)/otautil/include
+ ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 27; echo $$?),0)
+ # Android 9.0 needs c++17 for libvintf
+ LOCAL_CPPFLAGS += -std=c++17
+ # Android 9.0's libvintf also needs this library
+ LOCAL_STATIC_LIBRARIES += libhidl-gen-utils
+ endif
else
LOCAL_CFLAGS += -DUSE_MINZIP
endif
include $(BUILD_SHARED_LIBRARY)
-
-# All the APIs for testing
+# libverifier (static library)
+# ===============================
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_MODULE := libverifier
LOCAL_SRC_FILES := \
asn1_decoder.cpp \
- verifier.cpp \
- ui.cpp
-LOCAL_STATIC_LIBRARIES := libcrypto_static
+ verifier.cpp
+LOCAL_STATIC_LIBRARIES := \
+ libotautil \
+ libcrypto_utils \
+ libcrypto \
+ libbase
+LOCAL_CFLAGS := -Wall -Werror
include $(BUILD_STATIC_LIBRARY)
# Wear default device
# ===============================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := wear_device.cpp
+LOCAL_CFLAGS := -Wall -Werror
# Should match TARGET_RECOVERY_UI_LIB in BoardConfig.mk.
LOCAL_MODULE := librecovery_ui_wear
@@ -708,6 +737,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := vr_device.cpp
+LOCAL_CFLAGS := -Wall -Werror
# should match TARGET_RECOVERY_UI_LIB set in BoardConfig.mk
LOCAL_MODULE := librecovery_ui_vr
@@ -716,20 +746,23 @@
commands_recovery_local_path := $(LOCAL_PATH)
+# $(LOCAL_PATH)/edify/Android.mk
+# $(LOCAL_PATH)/otafault/Android.mk
+# $(LOCAL_PATH)/bootloader_message/Android.mk
include \
- $(LOCAL_PATH)/applypatch/Android.mk \
- $(LOCAL_PATH)/boot_control/Android.mk \
- $(LOCAL_PATH)/edify/Android.mk \
- $(LOCAL_PATH)/otafault/Android.mk \
- $(LOCAL_PATH)/tests/Android.mk \
- $(LOCAL_PATH)/tools/Android.mk \
- $(LOCAL_PATH)/updater/Android.mk \
- $(LOCAL_PATH)/update_verifier/Android.mk \
- $(LOCAL_PATH)/bootloader_message/Android.mk \
- $(LOCAL_PATH)/bootloader_message_twrp/Android.mk
+ $(commands_TWRP_local_path)/boot_control/Android.mk \
+ $(commands_TWRP_local_path)/tests/Android.mk \
+ $(commands_TWRP_local_path)/tools/Android.mk \
+ $(commands_TWRP_local_path)/updater/Android.mk \
+ $(commands_TWRP_local_path)/update_verifier/Android.mk \
+ $(commands_TWRP_local_path)/bootloader_message_twrp/Android.mk
+
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -le 25; echo $$?),0)
+include $(commands_TWRP_local_path)/bootloader_message/Android.mk
+endif
ifeq ($(wildcard system/core/uncrypt/Android.mk),)
- include $(commands_recovery_local_path)/uncrypt/Android.mk
+ #include $(commands_TWRP_local_path)/uncrypt/Android.mk
endif
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 22; echo $$?),0)
@@ -737,81 +770,81 @@
TARGET_GLOBAL_CFLAGS += -DTW_USE_MINUI_WITH_DATA
CLANG_TARGET_GLOBAL_CFLAGS += -DTW_USE_MINUI_WITH_DATA
endif
- include $(commands_recovery_local_path)/minadbd/Android.mk \
- $(commands_recovery_local_path)/minui/Android.mk
+ include $(commands_TWRP_local_path)/minadbd/Android.mk \
+ $(commands_TWRP_local_path)/minui/Android.mk
else
TARGET_GLOBAL_CFLAGS += -DTW_USE_MINUI_21
- include $(commands_recovery_local_path)/minadbd21/Android.mk \
- $(commands_recovery_local_path)/minui21/Android.mk
+ include $(commands_TWRP_local_path)/minadbd21/Android.mk \
+ $(commands_TWRP_local_path)/minui21/Android.mk
endif
+#$(commands_TWRP_local_path)/otautil/Android.mk
#includes for TWRP
-include $(commands_recovery_local_path)/injecttwrp/Android.mk \
- $(commands_recovery_local_path)/htcdumlock/Android.mk \
- $(commands_recovery_local_path)/gui/Android.mk \
- $(commands_recovery_local_path)/mmcutils/Android.mk \
- $(commands_recovery_local_path)/bmlutils/Android.mk \
- $(commands_recovery_local_path)/prebuilt/Android.mk \
- $(commands_recovery_local_path)/mtdutils/Android.mk \
- $(commands_recovery_local_path)/flashutils/Android.mk \
- $(commands_recovery_local_path)/pigz/Android.mk \
- $(commands_recovery_local_path)/libtar/Android.mk \
- $(commands_recovery_local_path)/libcrecovery/Android.mk \
- $(commands_recovery_local_path)/libblkid/Android.mk \
- $(commands_recovery_local_path)/minuitwrp/Android.mk \
- $(commands_recovery_local_path)/otautil/Android.mk \
- $(commands_recovery_local_path)/openaes/Android.mk \
- $(commands_recovery_local_path)/toolbox/Android.mk \
- $(commands_recovery_local_path)/twrpTarMain/Android.mk \
- $(commands_recovery_local_path)/mtp/Android.mk \
- $(commands_recovery_local_path)/minzip/Android.mk \
- $(commands_recovery_local_path)/dosfstools/Android.mk \
- $(commands_recovery_local_path)/etc/Android.mk \
- $(commands_recovery_local_path)/toybox/Android.mk \
- $(commands_recovery_local_path)/simg2img/Android.mk \
- $(commands_recovery_local_path)/adbbu/Android.mk \
- $(commands_recovery_local_path)/libpixelflinger/Android.mk \
- $(commands_recovery_local_path)/twrpDigest/Android.mk \
- $(commands_recovery_local_path)/attr/Android.mk
+include $(commands_TWRP_local_path)/injecttwrp/Android.mk \
+ $(commands_TWRP_local_path)/htcdumlock/Android.mk \
+ $(commands_TWRP_local_path)/gui/Android.mk \
+ $(commands_TWRP_local_path)/mmcutils/Android.mk \
+ $(commands_TWRP_local_path)/bmlutils/Android.mk \
+ $(commands_TWRP_local_path)/prebuilt/Android.mk \
+ $(commands_TWRP_local_path)/mtdutils/Android.mk \
+ $(commands_TWRP_local_path)/flashutils/Android.mk \
+ $(commands_TWRP_local_path)/pigz/Android.mk \
+ $(commands_TWRP_local_path)/libtar/Android.mk \
+ $(commands_TWRP_local_path)/libcrecovery/Android.mk \
+ $(commands_TWRP_local_path)/libblkid/Android.mk \
+ $(commands_TWRP_local_path)/minuitwrp/Android.mk \
+ $(commands_TWRP_local_path)/openaes/Android.mk \
+ $(commands_TWRP_local_path)/toolbox/Android.mk \
+ $(commands_TWRP_local_path)/twrpTarMain/Android.mk \
+ $(commands_TWRP_local_path)/mtp/Android.mk \
+ $(commands_TWRP_local_path)/minzip/Android.mk \
+ $(commands_TWRP_local_path)/dosfstools/Android.mk \
+ $(commands_TWRP_local_path)/etc/Android.mk \
+ $(commands_TWRP_local_path)/toybox/Android.mk \
+ $(commands_TWRP_local_path)/simg2img/Android.mk \
+ $(commands_TWRP_local_path)/adbbu/Android.mk \
+ $(commands_TWRP_local_path)/libpixelflinger/Android.mk \
+ $(commands_TWRP_local_path)/twrpDigest/Android.mk \
+ $(commands_TWRP_local_path)/attr/Android.mk
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 24; echo $$?),0)
- include $(commands_recovery_local_path)/libmincrypt/Android.mk
+ include $(commands_TWRP_local_path)/libmincrypt/Android.mk
endif
ifeq ($(TW_INCLUDE_CRYPTO), true)
- include $(commands_recovery_local_path)/crypto/lollipop/Android.mk
- include $(commands_recovery_local_path)/crypto/scrypt/Android.mk
+ include $(commands_TWRP_local_path)/crypto/lollipop/Android.mk
+ include $(commands_TWRP_local_path)/crypto/scrypt/Android.mk
ifeq ($(TW_INCLUDE_CRYPTO_FBE), true)
- include $(commands_recovery_local_path)/crypto/ext4crypt/Android.mk
+ include $(commands_TWRP_local_path)/crypto/ext4crypt/Android.mk
endif
ifneq ($(TW_CRYPTO_USE_SYSTEM_VOLD),)
ifneq ($(TW_CRYPTO_USE_SYSTEM_VOLD),false)
- include $(commands_recovery_local_path)/crypto/vold_decrypt/Android.mk
+ include $(commands_TWRP_local_path)/crypto/vold_decrypt/Android.mk
endif
endif
- include $(commands_recovery_local_path)/gpt/Android.mk
+ include $(commands_TWRP_local_path)/gpt/Android.mk
endif
ifeq ($(BUILD_ID), GINGERBREAD)
TW_NO_EXFAT := true
endif
ifneq ($(TW_NO_EXFAT), true)
- include $(commands_recovery_local_path)/exfat/mkfs/Android.mk \
- $(commands_recovery_local_path)/exfat/fsck/Android.mk \
- $(commands_recovery_local_path)/fuse/Android.mk \
- $(commands_recovery_local_path)/exfat/libexfat/Android.mk
+ include $(commands_TWRP_local_path)/exfat/mkfs/Android.mk \
+ $(commands_TWRP_local_path)/exfat/fsck/Android.mk \
+ $(commands_TWRP_local_path)/fuse/Android.mk \
+ $(commands_TWRP_local_path)/exfat/libexfat/Android.mk
ifneq ($(TW_NO_EXFAT_FUSE), true)
- include $(commands_recovery_local_path)/exfat/fuse/Android.mk
+ include $(commands_TWRP_local_path)/exfat/fuse/Android.mk
endif
endif
ifneq ($(TW_OEM_BUILD),true)
- include $(commands_recovery_local_path)/orscmd/Android.mk
+ include $(commands_TWRP_local_path)/orscmd/Android.mk
endif
# FB2PNG
ifeq ($(TW_INCLUDE_FB2PNG), true)
- include $(commands_recovery_local_path)/fb2png/Android.mk
+ include $(commands_TWRP_local_path)/fb2png/Android.mk
endif
-commands_recovery_local_path :=
-
endif
+
+commands_TWRP_local_path :=
diff --git a/OWNERS b/OWNERS
index 09754c6..b3f11dc 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,3 @@
-enh+aosp-gerrit@google.com
+enh@google.com
tbao@google.com
xunchang@google.com
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..b5f5f03
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,6 @@
+[Builtin Hooks]
+clang_format = true
+
+[Builtin Hooks Options]
+# Handle native codes only.
+clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
diff --git a/adb_install.h b/adb_install.h
index 121ae3c..97dc83d 100644
--- a/adb_install.h
+++ b/adb_install.h
@@ -21,8 +21,8 @@
//class RecoveryUI;
-static void set_usb_driver(bool enabled);
-static void maybe_restart_adbd();
+//static void set_usb_driver(bool enabled);
+//static void maybe_restart_adbd();
int apply_from_adb(const char* install_file, pid_t* child_pid);
#endif
diff --git a/adbbu/adbbumain.cpp b/adbbu/adbbumain.cpp
index 2e66bce..bd96b20 100644
--- a/adbbu/adbbumain.cpp
+++ b/adbbu/adbbumain.cpp
@@ -32,9 +32,9 @@
int main(int argc, char **argv) {
int index;
- int pos = 0;
+ size_t pos = 0;
bool ret = false;
- int maxpos = sizeof(TWRPARG + 2);
+ size_t maxpos = strlen(TWRPARG) + 2;
std::string command;
twrpback tw;
@@ -45,10 +45,10 @@
}
pos = command.find(TWRP_BACKUP_ARG);
- if (pos < 0 || pos > (maxpos + sizeof(TWRP_BACKUP_ARG) + 1)) {
+ if (pos == std::string::npos || pos > (maxpos + strlen(TWRP_BACKUP_ARG) + 1)) {
pos = command.find(TWRP_RESTORE_ARG);
}
- if (pos < 0 || pos > maxpos + sizeof(TWRP_STREAM_ARG + 1)) {
+ if (pos == std::string::npos || pos > maxpos + strlen(TWRP_STREAM_ARG) + 1) {
pos = command.find(TWRP_STREAM_ARG);
}
diff --git a/adbbu/twrpback.cpp b/adbbu/twrpback.cpp
index 56bc13d..b3de76d 100644
--- a/adbbu/twrpback.cpp
+++ b/adbbu/twrpback.cpp
@@ -144,7 +144,7 @@
uint64_t md5fnsize = 0;
struct AdbBackupControlType endadb;
- ADBSTRUCT_STATIC_ASSERT(sizeof(endadb) == MAX_ADB_READ);
+ //ADBSTRUCT_STATIC_ASSERT(sizeof(endadb) == MAX_ADB_READ);
bool writedata = true;
bool compressed = false;
@@ -177,7 +177,7 @@
}
memset(operation, 0, sizeof(operation));
- if (snprintf(operation, sizeof(operation), "adbbackup %s", command.c_str()) >= sizeof(operation)) {
+ if (snprintf(operation, sizeof(operation), "adbbackup %s", command.c_str()) >= (int)sizeof(operation)) {
adblogwrite("Operation too big to write to ORS_INPUT_FILE\n");
close_backup_fds();
return false;
@@ -278,7 +278,7 @@
adblogwrite("writing TWFN\n");
digest.init();
- ADBSTRUCT_STATIC_ASSERT(sizeof(twfilehdr) == MAX_ADB_READ);
+ //ADBSTRUCT_STATIC_ASSERT(sizeof(twfilehdr) == MAX_ADB_READ);
memset(&twfilehdr, 0, sizeof(twfilehdr));
memcpy(&twfilehdr, cmd, sizeof(cmd));
@@ -420,7 +420,7 @@
fileBytes += bytes;
dataChunkBytes += bytes;
- if (fwrite(writeAdbReadStream, 1, bytes, adbd_fp) != bytes) {
+ if (fwrite(writeAdbReadStream, 1, bytes, adbd_fp) != (unsigned long long)bytes) {
adblogwrite("Error writing backup data to adbd\n");
close_backup_fds();
return false;
@@ -508,8 +508,8 @@
int errctr = 0;
uint64_t totalbytes = 0, dataChunkBytes = 0;
uint64_t md5fnsize = 0, fileBytes = 0;
- bool writedata, read_from_adb;
- bool eofsent, md5trsent, md5sumdata;
+ bool read_from_adb;
+ bool md5sumdata;
bool compressed, tweofrcvd, extraData;
read_from_adb = true;
@@ -649,7 +649,7 @@
struct AdbBackupStreamHeader cnthdr;
uint32_t crc, cnthdrcrc;
- ADBSTRUCT_STATIC_ASSERT(sizeof(cnthdr) == MAX_ADB_READ);
+ //ADBSTRUCT_STATIC_ASSERT(sizeof(cnthdr) == MAX_ADB_READ);
md5sumdata = false;
memset(&cnthdr, 0, sizeof(cnthdr));
@@ -884,7 +884,7 @@
struct AdbBackupFileTrailer md5tr;
uint32_t crc, md5trcrc, md5ident, md5identmatch;
- ADBSTRUCT_STATIC_ASSERT(sizeof(md5tr) == MAX_ADB_READ);
+ //ADBSTRUCT_STATIC_ASSERT(sizeof(md5tr) == MAX_ADB_READ);
memcpy(&md5tr, readAdbStream, MAX_ADB_READ);
md5ident = md5tr.ident;
diff --git a/applypatch/Android.bp b/applypatch/Android.bp
new file mode 100644
index 0000000..cb0b367
--- /dev/null
+++ b/applypatch/Android.bp
@@ -0,0 +1,206 @@
+// 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.
+
+cc_defaults {
+ name: "applypatch_defaults",
+
+ cflags: [
+ "-D_FILE_OFFSET_BITS=64",
+ "-DZLIB_CONST",
+ "-Wall",
+ "-Werror",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+}
+
+cc_library_static {
+ name: "libapplypatch",
+
+ host_supported: true,
+
+ defaults: [
+ "applypatch_defaults",
+ ],
+
+ srcs: [
+ "applypatch.cpp",
+ "bspatch.cpp",
+ "freecache.cpp",
+ "imgpatch.cpp",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ static_libs: [
+ "libbase",
+ "libbspatch",
+ "libbz",
+ "libcrypto",
+ "libedify",
+ "libotafault",
+ "libotautil",
+ "libz",
+ ],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+cc_library_static {
+ name: "libapplypatch_modes",
+
+ defaults: [
+ "applypatch_defaults",
+ ],
+
+ srcs: [
+ "applypatch_modes.cpp",
+ ],
+
+ static_libs: [
+ "libapplypatch",
+ "libbase",
+ "libcrypto",
+ "libedify",
+ "libotautil",
+ ],
+}
+
+cc_binary {
+ name: "applypatch",
+
+ defaults: [
+ "applypatch_defaults",
+ ],
+
+ srcs: [
+ "applypatch_main.cpp",
+ ],
+
+ static_libs: [
+ "libapplypatch_modes",
+ "libapplypatch",
+ "libedify",
+ "libotafault",
+ "libotautil",
+ "libbspatch",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libbrotli",
+ "libbz",
+ "libcrypto",
+ "liblog",
+ "libz",
+ "libziparchive",
+ ],
+}
+
+cc_library_static {
+ name: "libimgdiff",
+
+ host_supported: true,
+
+ defaults: [
+ "applypatch_defaults",
+ ],
+
+ srcs: [
+ "imgdiff.cpp",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ static_libs: [
+ "libbase",
+ "libbsdiff",
+ "libdivsufsort",
+ "libdivsufsort64",
+ "liblog",
+ "libotautil",
+ "libutils",
+ "libz",
+ "libziparchive",
+ ],
+}
+
+cc_binary_host {
+ name: "imgdiff",
+
+ srcs: [
+ "imgdiff_main.cpp",
+ ],
+
+ defaults: [
+ "applypatch_defaults",
+ ],
+
+ static_libs: [
+ "libimgdiff",
+ "libotautil",
+ "libbsdiff",
+ "libdivsufsort",
+ "libdivsufsort64",
+ "libziparchive",
+ "libbase",
+ "libutils",
+ "liblog",
+ "libbrotli",
+ "libbz",
+ "libz",
+ ],
+}
+
+cc_library_static {
+ name: "libimgpatch",
+
+ // The host module is for recovery_host_test (Linux only).
+ host_supported: true,
+
+ defaults: [
+ "applypatch_defaults",
+ ],
+
+ srcs: [
+ "bspatch.cpp",
+ "imgpatch.cpp",
+ ],
+
+ static_libs: [
+ "libbase",
+ "libbspatch",
+ "libbz",
+ "libcrypto",
+ "libedify",
+ "libotautil",
+ "libz",
+ ],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
diff --git a/applypatch/Makefile b/applypatch/Makefile
deleted file mode 100644
index fb49843..0000000
--- a/applypatch/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# This file is for building imgdiff in Chrome OS.
-
-CPPFLAGS += -iquote.. -Iinclude
-CXXFLAGS += -std=c++11 -O3 -Wall -Werror
-LDLIBS += -lbz2 -lz
-
-.PHONY: all clean
-
-all: imgdiff libimgpatch.a
-
-clean:
- rm -f *.o imgdiff libimgpatch.a
-
-imgdiff: imgdiff.o bsdiff.o utils.o
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDLIBS) -o $@ $^
-
-libimgpatch.a utils.o: CXXFLAGS += -fPIC
-libimgpatch.a: imgpatch.o bspatch.o utils.o
- ${AR} rcs $@ $^
diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp
index 43e9b80..5c6c83f 100644
--- a/applypatch/applypatch.cpp
+++ b/applypatch/applypatch.cpp
@@ -42,8 +42,9 @@
#include "mtdutils/mtdutils.h"
#include "edify/expr.h"
-#include "ota_io.h"
-#include "print_sha1.h"
+#include "otafault/ota_io.h"
+#include "otautil/cache_location.h"
+#include "otautil/print_sha1.h"
static int LoadPartitionContents(const std::string& filename, FileContents* file);
static size_t FileSink(const unsigned char* data, size_t len, int fd);
@@ -64,12 +65,13 @@
return LoadPartitionContents(filename, file);
}
- if (stat(filename, &file->st) == -1) {
+ struct stat sb;
+ if (stat(filename, &sb) == -1) {
printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
return -1;
}
- std::vector<unsigned char> data(file->st.st_size);
+ std::vector<unsigned char> data(sb.st_size);
unique_file f(ota_fopen(filename, "rb"));
if (!f) {
printf("failed to open \"%s\": %s\n", filename, strerror(errno));
@@ -208,10 +210,6 @@
buffer.resize(buffer_size);
file->data = std::move(buffer);
- // Fake some stat() info.
- file->st.st_mode = 0644;
- file->st.st_uid = 0;
- file->st.st_gid = 0;
return 0;
}
@@ -240,15 +238,6 @@
return -1;
}
- if (chmod(filename, file->st.st_mode) != 0) {
- printf("chmod of \"%s\" failed: %s\n", filename, strerror(errno));
- return -1;
- }
- if (chown(filename, file->st.st_uid, file->st.st_gid) != 0) {
- printf("chown of \"%s\" failed: %s\n", filename, strerror(errno));
- return -1;
- }
-
return 0;
}
@@ -509,12 +498,10 @@
(!patch_sha1_str.empty() && FindMatchingPatch(file.sha1, patch_sha1_str) < 0)) {
printf("file \"%s\" doesn't have any of expected sha1 sums; checking cache\n", filename);
- // If the source file is missing or corrupted, it might be because
- // we were killed in the middle of patching it. A copy of it
- // should have been made in CACHE_TEMP_SOURCE. If that file
- // exists and matches the sha1 we're looking for, the check still
- // passes.
- if (LoadFileContents(CACHE_TEMP_SOURCE, &file) != 0) {
+ // If the source file is missing or corrupted, it might be because we were killed in the middle
+ // of patching it. A copy of it should have been made in cache_temp_source. If that file
+ // exists and matches the sha1 we're looking for, the check still passes.
+ if (LoadFileContents(CacheLocation::location().cache_temp_source().c_str(), &file) != 0) {
printf("failed to load cache file\n");
return 1;
}
@@ -560,9 +547,8 @@
if (MakeFreeSpaceOnCache(bytes) < 0) {
printf("unable to make %zu bytes available on /cache\n", bytes);
return 1;
- } else {
- return 0;
}
+ return 0;
}
// This function applies binary patches to EMMC target files in a way that is safe (the original
@@ -587,7 +573,7 @@
// become obsolete since we have dropped the support for patching non-EMMC targets (EMMC targets
// have the size embedded in the filename).
int applypatch(const char* source_filename, const char* target_filename,
- const char* target_sha1_str, size_t target_size __unused,
+ const char* target_sha1_str, size_t /* target_size */,
const std::vector<std::string>& patch_sha1_str,
const std::vector<std::unique_ptr<Value>>& patch_data, const Value* bonus_data) {
printf("patch %s: ", source_filename);
@@ -637,7 +623,7 @@
printf("source file is bad; trying copy\n");
FileContents copy_file;
- if (LoadFileContents(CACHE_TEMP_SOURCE, ©_file) < 0) {
+ if (LoadFileContents(CacheLocation::location().cache_temp_source().c_str(), ©_file) < 0) {
printf("failed to read copy file\n");
return 1;
}
@@ -732,7 +718,7 @@
printf("not enough free space on /cache\n");
return 1;
}
- if (SaveFileContents(CACHE_TEMP_SOURCE, &source_file) < 0) {
+ if (SaveFileContents(CacheLocation::location().cache_temp_source().c_str(), &source_file) < 0) {
printf("failed to back up source file\n");
return 1;
}
@@ -749,11 +735,11 @@
int result;
if (use_bsdiff) {
- result = ApplyBSDiffPatch(source_file.data.data(), source_file.data.size(), patch.get(), 0,
- sink, &ctx);
+ result =
+ ApplyBSDiffPatch(source_file.data.data(), source_file.data.size(), *patch, 0, sink, &ctx);
} else {
- result = ApplyImagePatch(source_file.data.data(), source_file.data.size(), patch.get(), sink,
- &ctx, bonus_data);
+ result = ApplyImagePatch(source_file.data.data(), source_file.data.size(), *patch, sink, &ctx,
+ bonus_data);
}
if (result != 0) {
@@ -778,7 +764,7 @@
}
// Delete the backup copy of the source.
- unlink(CACHE_TEMP_SOURCE);
+ unlink(CacheLocation::location().cache_temp_source().c_str());
// Success!
return 0;
diff --git a/applypatch/bspatch.cpp b/applypatch/bspatch.cpp
index 65ee614..912dbbd 100644
--- a/applypatch/bspatch.cpp
+++ b/applypatch/bspatch.cpp
@@ -26,11 +26,12 @@
#include <string>
#include <android-base/logging.h>
-#include <bspatch.h>
+#include <bsdiff/bspatch.h>
#include <openssl/sha.h>
#include "applypatch/applypatch.h"
-#include "print_sha1.h"
+#include "edify/expr.h"
+#include "otautil/print_sha1.h"
void ShowBSDiffLicense() {
puts("The bsdiff library used herein is:\n"
@@ -64,7 +65,7 @@
);
}
-int ApplyBSDiffPatch(const unsigned char* old_data, size_t old_size, const Value* patch,
+int ApplyBSDiffPatch(const unsigned char* old_data, size_t old_size, const Value& patch,
size_t patch_offset, SinkFn sink, SHA_CTX* ctx) {
auto sha_sink = [&sink, &ctx](const uint8_t* data, size_t len) {
len = sink(data, len);
@@ -72,23 +73,21 @@
return len;
};
- CHECK(patch != nullptr);
- CHECK_LE(patch_offset, patch->data.size());
+ CHECK_LE(patch_offset, patch.data.size());
int result = bsdiff::bspatch(old_data, old_size,
- reinterpret_cast<const uint8_t*>(&patch->data[patch_offset]),
- patch->data.size() - patch_offset, sha_sink);
+ reinterpret_cast<const uint8_t*>(&patch.data[patch_offset]),
+ patch.data.size() - patch_offset, sha_sink);
if (result != 0) {
LOG(ERROR) << "bspatch failed, result: " << result;
// print SHA1 of the patch in the case of a data error.
if (result == 2) {
uint8_t digest[SHA_DIGEST_LENGTH];
- SHA1(reinterpret_cast<const uint8_t*>(patch->data.data() + patch_offset),
- patch->data.size() - patch_offset, digest);
+ SHA1(reinterpret_cast<const uint8_t*>(patch.data.data() + patch_offset),
+ patch.data.size() - patch_offset, digest);
std::string patch_sha1 = print_sha1(digest);
- LOG(ERROR) << "Patch may be corrupted, offset: " << patch_offset << ", SHA1: "
- << patch_sha1;
+ LOG(ERROR) << "Patch may be corrupted, offset: " << patch_offset << ", SHA1: " << patch_sha1;
}
}
return result;
-}
\ No newline at end of file
+}
diff --git a/applypatch/freecache.cpp b/applypatch/freecache.cpp
index 331cae2..ea364d8 100644
--- a/applypatch/freecache.cpp
+++ b/applypatch/freecache.cpp
@@ -33,6 +33,7 @@
#include <android-base/stringprintf.h>
#include "applypatch/applypatch.h"
+#include "otautil/cache_location.h"
static int EliminateOpenFiles(std::set<std::string>* files) {
std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/proc"), closedir);
@@ -90,10 +91,9 @@
while ((de = readdir(d.get())) != 0) {
std::string path = std::string(dirs[i]) + "/" + de->d_name;
- // We can't delete CACHE_TEMP_SOURCE; if it's there we might have
- // restarted during installation and could be depending on it to
- // be there.
- if (path == CACHE_TEMP_SOURCE) {
+ // We can't delete cache_temp_source; if it's there we might have restarted during
+ // installation and could be depending on it to be there.
+ if (path == CacheLocation::location().cache_temp_source()) {
continue;
}
@@ -112,6 +112,12 @@
}
int MakeFreeSpaceOnCache(size_t bytes_needed) {
+#ifndef __ANDROID__
+ // TODO (xunchang) implement a heuristic cache size check during host simulation.
+ printf("Skip making (%zu) bytes free space on cache; program is running on host\n", bytes_needed);
+ return 0;
+#endif
+
size_t free_now = FreeSpaceForFile("/cache");
printf("%zu bytes free on /cache (%zu needed)\n", free_now, bytes_needed);
diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp
index fc24064..674cc2b 100644
--- a/applypatch/imgdiff.cpp
+++ b/applypatch/imgdiff.cpp
@@ -15,53 +15,44 @@
*/
/*
- * This program constructs binary patches for images -- such as boot.img
- * and recovery.img -- that consist primarily of large chunks of gzipped
- * data interspersed with uncompressed data. Doing a naive bsdiff of
- * these files is not useful because small changes in the data lead to
- * large changes in the compressed bitstream; bsdiff patches of gzipped
- * data are typically as large as the data itself.
+ * This program constructs binary patches for images -- such as boot.img and recovery.img -- that
+ * consist primarily of large chunks of gzipped data interspersed with uncompressed data. Doing a
+ * naive bsdiff of these files is not useful because small changes in the data lead to large
+ * changes in the compressed bitstream; bsdiff patches of gzipped data are typically as large as
+ * the data itself.
*
- * To patch these usefully, we break the source and target images up into
- * chunks of two types: "normal" and "gzip". Normal chunks are simply
- * patched using a plain bsdiff. Gzip chunks are first expanded, then a
- * bsdiff is applied to the uncompressed data, then the patched data is
- * gzipped using the same encoder parameters. Patched chunks are
- * concatenated together to create the output file; the output image
- * should be *exactly* the same series of bytes as the target image used
- * originally to generate the patch.
+ * To patch these usefully, we break the source and target images up into chunks of two types:
+ * "normal" and "gzip". Normal chunks are simply patched using a plain bsdiff. Gzip chunks are
+ * first expanded, then a bsdiff is applied to the uncompressed data, then the patched data is
+ * gzipped using the same encoder parameters. Patched chunks are concatenated together to create
+ * the output file; the output image should be *exactly* the same series of bytes as the target
+ * image used originally to generate the patch.
*
- * To work well with this tool, the gzipped sections of the target
- * image must have been generated using the same deflate encoder that
- * is available in applypatch, namely, the one in the zlib library.
- * In practice this means that images should be compressed using the
- * "minigzip" tool included in the zlib distribution, not the GNU gzip
- * program.
+ * To work well with this tool, the gzipped sections of the target image must have been generated
+ * using the same deflate encoder that is available in applypatch, namely, the one in the zlib
+ * library. In practice this means that images should be compressed using the "minigzip" tool
+ * included in the zlib distribution, not the GNU gzip program.
*
- * An "imgdiff" patch consists of a header describing the chunk structure
- * of the file and any encoding parameters needed for the gzipped
- * chunks, followed by N bsdiff patches, one per chunk.
+ * An "imgdiff" patch consists of a header describing the chunk structure of the file and any
+ * encoding parameters needed for the gzipped chunks, followed by N bsdiff patches, one per chunk.
*
- * For a diff to be generated, the source and target images must have the
- * same "chunk" structure: that is, the same number of gzipped and normal
- * chunks in the same order. Android boot and recovery images currently
- * consist of five chunks: a small normal header, a gzipped kernel, a
- * small normal section, a gzipped ramdisk, and finally a small normal
- * footer.
+ * For a diff to be generated, the source and target must be in well-formed zip archive format;
+ * or they are image files with the same "chunk" structure: that is, the same number of gzipped and
+ * normal chunks in the same order. Android boot and recovery images currently consist of five
+ * chunks: a small normal header, a gzipped kernel, a small normal section, a gzipped ramdisk, and
+ * finally a small normal footer.
*
- * Caveats: we locate gzipped sections within the source and target
- * images by searching for the byte sequence 1f8b0800: 1f8b is the gzip
- * magic number; 08 specifies the "deflate" encoding [the only encoding
- * supported by the gzip standard]; and 00 is the flags byte. We do not
- * currently support any extra header fields (which would be indicated by
- * a nonzero flags byte). We also don't handle the case when that byte
- * sequence appears spuriously in the file. (Note that it would have to
- * occur spuriously within a normal chunk to be a problem.)
+ * Caveats: we locate gzipped sections within the source and target images by searching for the
+ * byte sequence 1f8b0800: 1f8b is the gzip magic number; 08 specifies the "deflate" encoding
+ * [the only encoding supported by the gzip standard]; and 00 is the flags byte. We do not
+ * currently support any extra header fields (which would be indicated by a nonzero flags byte).
+ * We also don't handle the case when that byte sequence appears spuriously in the file. (Note
+ * that it would have to occur spuriously within a normal chunk to be a problem.)
*
*
* The imgdiff patch header looks like this:
*
- * "IMGDIFF1" (8) [magic number and version]
+ * "IMGDIFF2" (8) [magic number and version]
* chunk count (4)
* for each chunk:
* chunk type (4) [CHUNK_{NORMAL, GZIP, DEFLATE, RAW}]
@@ -98,33 +89,62 @@
* target len (4)
* data (target len)
*
- * All integers are little-endian. "source start" and "source len"
- * specify the section of the input image that comprises this chunk,
- * including the gzip header and footer for gzip chunks. "source
- * expanded len" is the size of the uncompressed source data. "target
- * expected len" is the size of the uncompressed data after applying
- * the bsdiff patch. The next five parameters specify the zlib
- * parameters to be used when compressing the patched data, and the
- * next three specify the header and footer to be wrapped around the
- * compressed data to create the output chunk (so that header contents
- * like the timestamp are recreated exactly).
+ * All integers are little-endian. "source start" and "source len" specify the section of the
+ * input image that comprises this chunk, including the gzip header and footer for gzip chunks.
+ * "source expanded len" is the size of the uncompressed source data. "target expected len" is the
+ * size of the uncompressed data after applying the bsdiff patch. The next five parameters
+ * specify the zlib parameters to be used when compressing the patched data, and the next three
+ * specify the header and footer to be wrapped around the compressed data to create the output
+ * chunk (so that header contents like the timestamp are recreated exactly).
*
- * After the header there are 'chunk count' bsdiff patches; the offset
- * of each from the beginning of the file is specified in the header.
+ * After the header there are 'chunk count' bsdiff patches; the offset of each from the beginning
+ * of the file is specified in the header.
*
- * This tool can take an optional file of "bonus data". This is an
- * extra file of data that is appended to chunk #1 after it is
- * compressed (it must be a CHUNK_DEFLATE chunk). The same file must
- * be available (and passed to applypatch with -b) when applying the
- * patch. This is used to reduce the size of recovery-from-boot
- * patches by combining the boot image with recovery ramdisk
+ * This tool can take an optional file of "bonus data". This is an extra file of data that is
+ * appended to chunk #1 after it is compressed (it must be a CHUNK_DEFLATE chunk). The same file
+ * must be available (and passed to applypatch with -b) when applying the patch. This is used to
+ * reduce the size of recovery-from-boot patches by combining the boot image with recovery ramdisk
* information that is stored on the system partition.
+ *
+ * When generating the patch between two zip files, this tool has an option "--block-limit" to
+ * split the large source/target files into several pair of pieces, with each piece has at most
+ * *limit* blocks. When this option is used, we also need to output the split info into the file
+ * path specified by "--split-info".
+ *
+ * Format of split info file:
+ * 2 [version of imgdiff]
+ * n [count of split pieces]
+ * <patch_size>, <tgt_size>, <src_range> [size and ranges for split piece#1]
+ * ...
+ * <patch_size>, <tgt_size>, <src_range> [size and ranges for split piece#n]
+ *
+ * To split a pair of large zip files, we walk through the chunks in target zip and search by its
+ * entry_name in the source zip. If the entry_name is non-empty and a matching entry in source
+ * is found, we'll add the source entry to the current split source image; otherwise we'll skip
+ * this chunk and later do bsdiff between all the skipped trunks and the whole split source image.
+ * We move on to the next pair of pieces if the size of the split source image reaches the block
+ * limit.
+ *
+ * After the split, the target pieces are continuous and block aligned, while the source pieces
+ * are mutually exclusive. Some of the source blocks may not be used if there's no matching
+ * entry_name in the target; as a result, they won't be included in any of these split source
+ * images. Then we will generate patches accordingly between each split image pairs; in particular,
+ * the unmatched trunks in the split target will diff against the entire split source image.
+ *
+ * For example:
+ * Input: [src_image, tgt_image]
+ * Split: [src-0, tgt-0; src-1, tgt-1, src-2, tgt-2]
+ * Diff: [ patch-0; patch-1; patch-2]
+ *
+ * Patch: [(src-0, patch-0) = tgt-0; (src-1, patch-1) = tgt-1; (src-2, patch-2) = tgt-2]
+ * Concatenate: [tgt-0 + tgt-1 + tgt-2 = tgt_image]
*/
#include "applypatch/imgdiff.h"
#include <errno.h>
#include <fcntl.h>
+#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -139,15 +159,26 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/memory.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
+#include <bsdiff/bsdiff.h>
#include <ziparchive/zip_archive.h>
-
-#include <bsdiff.h>
#include <zlib.h>
+#include "applypatch/imgdiff_image.h"
+#include "otautil/rangeset.h"
+
using android::base::get_unaligned;
-static constexpr auto BUFFER_SIZE = 0x8000;
+static constexpr size_t VERSION = 2;
+
+// We assume the header "IMGDIFF#" is 8 bytes.
+static_assert(VERSION <= 9, "VERSION occupies more than one byte");
+
+static constexpr size_t BLOCK_SIZE = 4096;
+static constexpr size_t BUFFER_SIZE = 0x8000;
// If we use this function to write the offset and length (type size_t), their values should not
// exceed 2^63; because the signed bit will be casted away.
@@ -161,99 +192,80 @@
return android::base::WriteFully(fd, &value, sizeof(int32_t));
}
-class ImageChunk {
- public:
- static constexpr auto WINDOWBITS = -15; // 32kb window; negative to indicate a raw stream.
- static constexpr auto MEMLEVEL = 8; // the default value.
- static constexpr auto METHOD = Z_DEFLATED;
- static constexpr auto STRATEGY = Z_DEFAULT_STRATEGY;
+// Trim the head or tail to align with the block size. Return false if the chunk has nothing left
+// after alignment.
+static bool AlignHead(size_t* start, size_t* length) {
+ size_t residual = (*start % BLOCK_SIZE == 0) ? 0 : BLOCK_SIZE - *start % BLOCK_SIZE;
- ImageChunk(int type, size_t start, const std::vector<uint8_t>* file_content, size_t raw_data_len)
- : type_(type),
- start_(start),
- input_file_ptr_(file_content),
- raw_data_len_(raw_data_len),
- compress_level_(6),
- source_start_(0),
- source_len_(0),
- source_uncompressed_len_(0) {
- CHECK(file_content != nullptr) << "input file container can't be nullptr";
+ if (*length <= residual) {
+ *length = 0;
+ return false;
}
- int GetType() const {
- return type_;
- }
- size_t GetRawDataLength() const {
- return raw_data_len_;
- }
- const std::string& GetEntryName() const {
- return entry_name_;
+ // Trim the data in the beginning.
+ *start += residual;
+ *length -= residual;
+ return true;
+}
+
+static bool AlignTail(size_t* start, size_t* length) {
+ size_t residual = (*start + *length) % BLOCK_SIZE;
+ if (*length <= residual) {
+ *length = 0;
+ return false;
}
- // CHUNK_DEFLATE will return the uncompressed data for diff, while other types will simply return
- // the raw data.
- const uint8_t * DataForPatch() const;
- size_t DataLengthForPatch() const;
+ // Trim the data in the end.
+ *length -= residual;
+ return true;
+}
- void Dump() const {
- printf("type %d start %zu len %zu\n", type_, start_, DataLengthForPatch());
+// Remove the used blocks from the source chunk to make sure the source ranges are mutually
+// exclusive after split. Return false if we fail to get the non-overlapped ranges. In such
+// a case, we'll skip the entire source chunk.
+static bool RemoveUsedBlocks(size_t* start, size_t* length, const SortedRangeSet& used_ranges) {
+ if (!used_ranges.Overlaps(*start, *length)) {
+ return true;
}
- void SetSourceInfo(const ImageChunk& other);
- void SetEntryName(std::string entryname);
- void SetUncompressedData(std::vector<uint8_t> data);
- bool SetBonusData(const std::vector<uint8_t>& bonus_data);
+ // TODO find the largest non-overlap chunk.
+ LOG(INFO) << "Removing block " << used_ranges.ToString() << " from " << *start << " - "
+ << *start + *length - 1;
- bool operator==(const ImageChunk& other) const;
- bool operator!=(const ImageChunk& other) const {
- return !(*this == other);
+ // If there's no duplicate entry name, we should only overlap in the head or tail block. Try to
+ // trim both blocks. Skip this source chunk in case it still overlaps with the used ranges.
+ if (AlignHead(start, length) && !used_ranges.Overlaps(*start, *length)) {
+ return true;
+ }
+ if (AlignTail(start, length) && !used_ranges.Overlaps(*start, *length)) {
+ return true;
}
- size_t GetHeaderSize(size_t patch_size) const;
- // Return the offset of the next patch into the patch data.
- size_t WriteHeaderToFd(int fd, const std::vector<uint8_t>& patch, size_t offset);
+ LOG(WARNING) << "Failed to remove the overlapped block ranges; skip the source";
+ return false;
+}
- /*
- * Cause a gzip chunk to be treated as a normal chunk (ie, as a blob
- * of uninterpreted data). The resulting patch will likely be about
- * as big as the target file, but it lets us handle the case of images
- * where some gzip chunks are reconstructible but others aren't (by
- * treating the ones that aren't as normal chunks).
- */
- void ChangeDeflateChunkToNormal();
- bool ChangeChunkToRaw(size_t patch_size);
-
- /*
- * Verify that we can reproduce exactly the same compressed data that
- * we started with. Sets the level, method, windowBits, memLevel, and
- * strategy fields in the chunk to the encoding parameters needed to
- * produce the right output.
- */
- bool ReconstructDeflateChunk();
- bool IsAdjacentNormal(const ImageChunk& other) const;
- void MergeAdjacentNormal(const ImageChunk& other);
-
- private:
- int type_; // CHUNK_NORMAL, CHUNK_DEFLATE, CHUNK_RAW
- size_t start_; // offset of chunk in the original input file
- const std::vector<uint8_t>* input_file_ptr_; // ptr to the full content of original input file
- size_t raw_data_len_;
-
- // --- for CHUNK_DEFLATE chunks only: ---
- std::vector<uint8_t> uncompressed_data_;
- std::string entry_name_; // used for zip entries
-
- // deflate encoder parameters
- int compress_level_;
-
- size_t source_start_;
- size_t source_len_;
- size_t source_uncompressed_len_;
-
- const uint8_t* GetRawData() const;
- bool TryReconstruction(int level);
+static const struct option OPTIONS[] = {
+ { "zip-mode", no_argument, nullptr, 'z' },
+ { "bonus-file", required_argument, nullptr, 'b' },
+ { "block-limit", required_argument, nullptr, 0 },
+ { "debug-dir", required_argument, nullptr, 0 },
+ { "split-info", required_argument, nullptr, 0 },
+ { "verbose", no_argument, nullptr, 'v' },
+ { nullptr, 0, nullptr, 0 },
};
+ImageChunk::ImageChunk(int type, size_t start, const std::vector<uint8_t>* file_content,
+ size_t raw_data_len, std::string entry_name)
+ : type_(type),
+ start_(start),
+ input_file_ptr_(file_content),
+ raw_data_len_(raw_data_len),
+ compress_level_(6),
+ entry_name_(std::move(entry_name)) {
+ CHECK(file_content != nullptr) << "input file container can't be nullptr";
+}
+
const uint8_t* ImageChunk::GetRawData() const {
CHECK_LE(start_ + raw_data_len_, input_file_ptr_->size());
return input_file_ptr_->data() + start_;
@@ -273,6 +285,11 @@
return raw_data_len_;
}
+void ImageChunk::Dump(size_t index) const {
+ LOG(INFO) << "chunk: " << index << ", type: " << type_ << ", start: " << start_
+ << ", len: " << DataLengthForPatch() << ", name: " << entry_name_;
+}
+
bool ImageChunk::operator==(const ImageChunk& other) const {
if (type_ != other.type_) {
return false;
@@ -281,20 +298,6 @@
memcmp(GetRawData(), other.GetRawData(), raw_data_len_) == 0);
}
-void ImageChunk::SetSourceInfo(const ImageChunk& src) {
- source_start_ = src.start_;
- if (type_ == CHUNK_NORMAL) {
- source_len_ = src.raw_data_len_;
- } else if (type_ == CHUNK_DEFLATE) {
- source_len_ = src.raw_data_len_;
- source_uncompressed_len_ = src.uncompressed_data_.size();
- }
-}
-
-void ImageChunk::SetEntryName(std::string entryname) {
- entry_name_ = std::move(entryname);
-}
-
void ImageChunk::SetUncompressedData(std::vector<uint8_t> data) {
uncompressed_data_ = std::move(data);
}
@@ -307,80 +310,13 @@
return true;
}
-// Convert CHUNK_NORMAL & CHUNK_DEFLATE to CHUNK_RAW if the target size is
-// smaller. Also take the header size into account during size comparison.
-bool ImageChunk::ChangeChunkToRaw(size_t patch_size) {
- if (type_ == CHUNK_RAW) {
- return true;
- } else if (type_ == CHUNK_NORMAL && (raw_data_len_ <= 160 || raw_data_len_ < patch_size)) {
- type_ = CHUNK_RAW;
- return true;
- }
- return false;
-}
-
void ImageChunk::ChangeDeflateChunkToNormal() {
if (type_ != CHUNK_DEFLATE) return;
type_ = CHUNK_NORMAL;
- entry_name_.clear();
+ // No need to clear the entry name.
uncompressed_data_.clear();
}
-// Header size:
-// header_type 4 bytes
-// CHUNK_NORMAL 8*3 = 24 bytes
-// CHUNK_DEFLATE 8*5 + 4*5 = 60 bytes
-// CHUNK_RAW 4 bytes + patch_size
-size_t ImageChunk::GetHeaderSize(size_t patch_size) const {
- switch (type_) {
- case CHUNK_NORMAL:
- return 4 + 8 * 3;
- case CHUNK_DEFLATE:
- return 4 + 8 * 5 + 4 * 5;
- case CHUNK_RAW:
- return 4 + 4 + patch_size;
- default:
- CHECK(false) << "unexpected chunk type: " << type_; // Should not reach here.
- return 0;
- }
-}
-
-size_t ImageChunk::WriteHeaderToFd(int fd, const std::vector<uint8_t>& patch, size_t offset) {
- Write4(fd, type_);
- switch (type_) {
- case CHUNK_NORMAL:
- printf("normal (%10zu, %10zu) %10zu\n", start_, raw_data_len_, patch.size());
- Write8(fd, static_cast<int64_t>(source_start_));
- Write8(fd, static_cast<int64_t>(source_len_));
- Write8(fd, static_cast<int64_t>(offset));
- return offset + patch.size();
- case CHUNK_DEFLATE:
- printf("deflate (%10zu, %10zu) %10zu %s\n", start_, raw_data_len_, patch.size(),
- entry_name_.c_str());
- Write8(fd, static_cast<int64_t>(source_start_));
- Write8(fd, static_cast<int64_t>(source_len_));
- Write8(fd, static_cast<int64_t>(offset));
- Write8(fd, static_cast<int64_t>(source_uncompressed_len_));
- Write8(fd, static_cast<int64_t>(uncompressed_data_.size()));
- Write4(fd, compress_level_);
- Write4(fd, METHOD);
- Write4(fd, WINDOWBITS);
- Write4(fd, MEMLEVEL);
- Write4(fd, STRATEGY);
- return offset + patch.size();
- case CHUNK_RAW:
- printf("raw (%10zu, %10zu)\n", start_, raw_data_len_);
- Write4(fd, static_cast<int32_t>(patch.size()));
- if (!android::base::WriteFully(fd, patch.data(), patch.size())) {
- CHECK(false) << "failed to write " << patch.size() <<" bytes patch";
- }
- return offset;
- default:
- CHECK(false) << "unexpected chunk type: " << type_;
- return offset;
- }
-}
-
bool ImageChunk::IsAdjacentNormal(const ImageChunk& other) const {
if (type_ != CHUNK_NORMAL || other.type_ != CHUNK_NORMAL) {
return false;
@@ -393,14 +329,62 @@
raw_data_len_ = raw_data_len_ + other.raw_data_len_;
}
-bool ImageChunk::ReconstructDeflateChunk() {
- if (type_ != CHUNK_DEFLATE) {
- printf("attempt to reconstruct non-deflate chunk\n");
+bool ImageChunk::MakePatch(const ImageChunk& tgt, const ImageChunk& src,
+ std::vector<uint8_t>* patch_data,
+ bsdiff::SuffixArrayIndexInterface** bsdiff_cache) {
+#if defined(__ANDROID__)
+ char ptemp[] = "/data/local/tmp/imgdiff-patch-XXXXXX";
+#else
+ char ptemp[] = "/tmp/imgdiff-patch-XXXXXX";
+#endif
+
+ int fd = mkstemp(ptemp);
+ if (fd == -1) {
+ PLOG(ERROR) << "MakePatch failed to create a temporary file";
+ return false;
+ }
+ close(fd);
+
+ int r = bsdiff::bsdiff(src.DataForPatch(), src.DataLengthForPatch(), tgt.DataForPatch(),
+ tgt.DataLengthForPatch(), ptemp, bsdiff_cache);
+ if (r != 0) {
+ LOG(ERROR) << "bsdiff() failed: " << r;
return false;
}
- // We only check two combinations of encoder parameters: level 6
- // (the default) and level 9 (the maximum).
+ android::base::unique_fd patch_fd(open(ptemp, O_RDONLY));
+ if (patch_fd == -1) {
+ PLOG(ERROR) << "Failed to open " << ptemp;
+ return false;
+ }
+ struct stat st;
+ if (fstat(patch_fd, &st) != 0) {
+ PLOG(ERROR) << "Failed to stat patch file " << ptemp;
+ return false;
+ }
+
+ size_t sz = static_cast<size_t>(st.st_size);
+
+ patch_data->resize(sz);
+ if (!android::base::ReadFully(patch_fd, patch_data->data(), sz)) {
+ PLOG(ERROR) << "Failed to read " << ptemp;
+ unlink(ptemp);
+ return false;
+ }
+
+ unlink(ptemp);
+
+ return true;
+}
+
+bool ImageChunk::ReconstructDeflateChunk() {
+ if (type_ != CHUNK_DEFLATE) {
+ LOG(ERROR) << "Attempted to reconstruct non-deflate chunk";
+ return false;
+ }
+
+ // We only check two combinations of encoder parameters: level 6 (the default) and level 9
+ // (the maximum).
for (int level = 6; level <= 9; level += 3) {
if (TryReconstruction(level)) {
compress_level_ = level;
@@ -412,10 +396,9 @@
}
/*
- * Takes the uncompressed data stored in the chunk, compresses it
- * using the zlib parameters stored in the chunk, and checks that it
- * matches exactly the compressed data we started with (also stored in
- * the chunk).
+ * Takes the uncompressed data stored in the chunk, compresses it using the zlib parameters stored
+ * in the chunk, and checks that it matches exactly the compressed data we started with (also
+ * stored in the chunk).
*/
bool ImageChunk::TryReconstruction(int level) {
z_stream strm;
@@ -426,7 +409,7 @@
strm.next_in = uncompressed_data_.data();
int ret = deflateInit2(&strm, level, METHOD, WINDOWBITS, MEMLEVEL, STRATEGY);
if (ret < 0) {
- printf("failed to initialize deflate: %d\n", ret);
+ LOG(ERROR) << "Failed to initialize deflate: " << ret;
return false;
}
@@ -437,7 +420,7 @@
strm.next_out = buffer.data();
ret = deflate(&strm, Z_FINISH);
if (ret < 0) {
- printf("failed to deflate: %d\n", ret);
+ LOG(ERROR) << "Failed to deflate: " << ret;
return false;
}
@@ -458,29 +441,381 @@
return true;
}
+PatchChunk::PatchChunk(const ImageChunk& tgt, const ImageChunk& src, std::vector<uint8_t> data)
+ : type_(tgt.GetType()),
+ source_start_(src.GetStartOffset()),
+ source_len_(src.GetRawDataLength()),
+ source_uncompressed_len_(src.DataLengthForPatch()),
+ target_start_(tgt.GetStartOffset()),
+ target_len_(tgt.GetRawDataLength()),
+ target_uncompressed_len_(tgt.DataLengthForPatch()),
+ target_compress_level_(tgt.GetCompressLevel()),
+ data_(std::move(data)) {}
+
+// Construct a CHUNK_RAW patch from the target data directly.
+PatchChunk::PatchChunk(const ImageChunk& tgt)
+ : type_(CHUNK_RAW),
+ source_start_(0),
+ source_len_(0),
+ source_uncompressed_len_(0),
+ target_start_(tgt.GetStartOffset()),
+ target_len_(tgt.GetRawDataLength()),
+ target_uncompressed_len_(tgt.DataLengthForPatch()),
+ target_compress_level_(tgt.GetCompressLevel()),
+ data_(tgt.DataForPatch(), tgt.DataForPatch() + tgt.DataLengthForPatch()) {}
+
+// Return true if raw data is smaller than the patch size.
+bool PatchChunk::RawDataIsSmaller(const ImageChunk& tgt, size_t patch_size) {
+ size_t target_len = tgt.GetRawDataLength();
+ return (tgt.GetType() == CHUNK_NORMAL && (target_len <= 160 || target_len < patch_size));
+}
+
+void PatchChunk::UpdateSourceOffset(const SortedRangeSet& src_range) {
+ if (type_ == CHUNK_DEFLATE) {
+ source_start_ = src_range.GetOffsetInRangeSet(source_start_);
+ }
+}
+
+// Header size:
+// header_type 4 bytes
+// CHUNK_NORMAL 8*3 = 24 bytes
+// CHUNK_DEFLATE 8*5 + 4*5 = 60 bytes
+// CHUNK_RAW 4 bytes + patch_size
+size_t PatchChunk::GetHeaderSize() const {
+ switch (type_) {
+ case CHUNK_NORMAL:
+ return 4 + 8 * 3;
+ case CHUNK_DEFLATE:
+ return 4 + 8 * 5 + 4 * 5;
+ case CHUNK_RAW:
+ return 4 + 4 + data_.size();
+ default:
+ CHECK(false) << "unexpected chunk type: " << type_; // Should not reach here.
+ return 0;
+ }
+}
+
+// Return the offset of the next patch into the patch data.
+size_t PatchChunk::WriteHeaderToFd(int fd, size_t offset, size_t index) const {
+ Write4(fd, type_);
+ switch (type_) {
+ case CHUNK_NORMAL:
+ LOG(INFO) << android::base::StringPrintf("chunk %zu: normal (%10zu, %10zu) %10zu", index,
+ target_start_, target_len_, data_.size());
+ Write8(fd, static_cast<int64_t>(source_start_));
+ Write8(fd, static_cast<int64_t>(source_len_));
+ Write8(fd, static_cast<int64_t>(offset));
+ return offset + data_.size();
+ case CHUNK_DEFLATE:
+ LOG(INFO) << android::base::StringPrintf("chunk %zu: deflate (%10zu, %10zu) %10zu", index,
+ target_start_, target_len_, data_.size());
+ Write8(fd, static_cast<int64_t>(source_start_));
+ Write8(fd, static_cast<int64_t>(source_len_));
+ Write8(fd, static_cast<int64_t>(offset));
+ Write8(fd, static_cast<int64_t>(source_uncompressed_len_));
+ Write8(fd, static_cast<int64_t>(target_uncompressed_len_));
+ Write4(fd, target_compress_level_);
+ Write4(fd, ImageChunk::METHOD);
+ Write4(fd, ImageChunk::WINDOWBITS);
+ Write4(fd, ImageChunk::MEMLEVEL);
+ Write4(fd, ImageChunk::STRATEGY);
+ return offset + data_.size();
+ case CHUNK_RAW:
+ LOG(INFO) << android::base::StringPrintf("chunk %zu: raw (%10zu, %10zu)", index,
+ target_start_, target_len_);
+ Write4(fd, static_cast<int32_t>(data_.size()));
+ if (!android::base::WriteFully(fd, data_.data(), data_.size())) {
+ CHECK(false) << "Failed to write " << data_.size() << " bytes patch";
+ }
+ return offset;
+ default:
+ CHECK(false) << "unexpected chunk type: " << type_;
+ return offset;
+ }
+}
+
+size_t PatchChunk::PatchSize() const {
+ if (type_ == CHUNK_RAW) {
+ return GetHeaderSize();
+ }
+ return GetHeaderSize() + data_.size();
+}
+
+// Write the contents of |patch_chunks| to |patch_fd|.
+bool PatchChunk::WritePatchDataToFd(const std::vector<PatchChunk>& patch_chunks, int patch_fd) {
+ // Figure out how big the imgdiff file header is going to be, so that we can correctly compute
+ // the offset of each bsdiff patch within the file.
+ size_t total_header_size = 12;
+ for (const auto& patch : patch_chunks) {
+ total_header_size += patch.GetHeaderSize();
+ }
+
+ size_t offset = total_header_size;
+
+ // Write out the headers.
+ if (!android::base::WriteStringToFd("IMGDIFF" + std::to_string(VERSION), patch_fd)) {
+ PLOG(ERROR) << "Failed to write \"IMGDIFF" << VERSION << "\"";
+ return false;
+ }
+
+ Write4(patch_fd, static_cast<int32_t>(patch_chunks.size()));
+ LOG(INFO) << "Writing " << patch_chunks.size() << " patch headers...";
+ for (size_t i = 0; i < patch_chunks.size(); ++i) {
+ offset = patch_chunks[i].WriteHeaderToFd(patch_fd, offset, i);
+ }
+
+ // Append each chunk's bsdiff patch, in order.
+ for (const auto& patch : patch_chunks) {
+ if (patch.type_ == CHUNK_RAW) {
+ continue;
+ }
+ if (!android::base::WriteFully(patch_fd, patch.data_.data(), patch.data_.size())) {
+ PLOG(ERROR) << "Failed to write " << patch.data_.size() << " bytes patch to patch_fd";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+ImageChunk& Image::operator[](size_t i) {
+ CHECK_LT(i, chunks_.size());
+ return chunks_[i];
+}
+
+const ImageChunk& Image::operator[](size_t i) const {
+ CHECK_LT(i, chunks_.size());
+ return chunks_[i];
+}
+
+void Image::MergeAdjacentNormalChunks() {
+ size_t merged_last = 0, cur = 0;
+ while (cur < chunks_.size()) {
+ // Look for normal chunks adjacent to the current one. If such chunk exists, extend the
+ // length of the current normal chunk.
+ size_t to_check = cur + 1;
+ while (to_check < chunks_.size() && chunks_[cur].IsAdjacentNormal(chunks_[to_check])) {
+ chunks_[cur].MergeAdjacentNormal(chunks_[to_check]);
+ to_check++;
+ }
+
+ if (merged_last != cur) {
+ chunks_[merged_last] = std::move(chunks_[cur]);
+ }
+ merged_last++;
+ cur = to_check;
+ }
+ if (merged_last < chunks_.size()) {
+ chunks_.erase(chunks_.begin() + merged_last, chunks_.end());
+ }
+}
+
+void Image::DumpChunks() const {
+ std::string type = is_source_ ? "source" : "target";
+ LOG(INFO) << "Dumping chunks for " << type;
+ for (size_t i = 0; i < chunks_.size(); ++i) {
+ chunks_[i].Dump(i);
+ }
+}
+
+bool Image::ReadFile(const std::string& filename, std::vector<uint8_t>* file_content) {
+ CHECK(file_content != nullptr);
+
+ android::base::unique_fd fd(open(filename.c_str(), O_RDONLY));
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open " << filename;
+ return false;
+ }
+ struct stat st;
+ if (fstat(fd, &st) != 0) {
+ PLOG(ERROR) << "Failed to stat " << filename;
+ return false;
+ }
+
+ size_t sz = static_cast<size_t>(st.st_size);
+ file_content->resize(sz);
+ if (!android::base::ReadFully(fd, file_content->data(), sz)) {
+ PLOG(ERROR) << "Failed to read " << filename;
+ return false;
+ }
+ fd.reset();
+
+ return true;
+}
+
+bool ZipModeImage::Initialize(const std::string& filename) {
+ if (!ReadFile(filename, &file_content_)) {
+ return false;
+ }
+
+ // Omit the trailing zeros before we pass the file to ziparchive handler.
+ size_t zipfile_size;
+ if (!GetZipFileSize(&zipfile_size)) {
+ LOG(ERROR) << "Failed to parse the actual size of " << filename;
+ return false;
+ }
+ ZipArchiveHandle handle;
+ int err = OpenArchiveFromMemory(const_cast<uint8_t*>(file_content_.data()), zipfile_size,
+ filename.c_str(), &handle);
+ if (err != 0) {
+ LOG(ERROR) << "Failed to open zip file " << filename << ": " << ErrorCodeString(err);
+ CloseArchive(handle);
+ return false;
+ }
+
+ if (!InitializeChunks(filename, handle)) {
+ CloseArchive(handle);
+ return false;
+ }
+
+ CloseArchive(handle);
+ return true;
+}
+
+// Iterate the zip entries and compose the image chunks accordingly.
+bool ZipModeImage::InitializeChunks(const std::string& filename, ZipArchiveHandle handle) {
+ void* cookie;
+ int ret = StartIteration(handle, &cookie, nullptr, nullptr);
+ if (ret != 0) {
+ LOG(ERROR) << "Failed to iterate over entries in " << filename << ": " << ErrorCodeString(ret);
+ return false;
+ }
+
+ // Create a list of deflated zip entries, sorted by offset.
+ std::vector<std::pair<std::string, ZipEntry>> temp_entries;
+ ZipString name;
+ ZipEntry entry;
+ while ((ret = Next(cookie, &entry, &name)) == 0) {
+ if (entry.method == kCompressDeflated || limit_ > 0) {
+ std::string entry_name(name.name, name.name + name.name_length);
+ temp_entries.emplace_back(entry_name, entry);
+ }
+ }
+
+ if (ret != -1) {
+ LOG(ERROR) << "Error while iterating over zip entries: " << ErrorCodeString(ret);
+ return false;
+ }
+ std::sort(temp_entries.begin(), temp_entries.end(),
+ [](auto& entry1, auto& entry2) { return entry1.second.offset < entry2.second.offset; });
+
+ EndIteration(cookie);
+
+ // For source chunks, we don't need to compose chunks for the metadata.
+ if (is_source_) {
+ for (auto& entry : temp_entries) {
+ if (!AddZipEntryToChunks(handle, entry.first, &entry.second)) {
+ LOG(ERROR) << "Failed to add " << entry.first << " to source chunks";
+ return false;
+ }
+ }
+
+ // Add the end of zip file (mainly central directory) as a normal chunk.
+ size_t entries_end = 0;
+ if (!temp_entries.empty()) {
+ entries_end = static_cast<size_t>(temp_entries.back().second.offset +
+ temp_entries.back().second.compressed_length);
+ }
+ CHECK_LT(entries_end, file_content_.size());
+ chunks_.emplace_back(CHUNK_NORMAL, entries_end, &file_content_,
+ file_content_.size() - entries_end);
+
+ return true;
+ }
+
+ // For target chunks, add the deflate entries as CHUNK_DEFLATE and the contents between two
+ // deflate entries as CHUNK_NORMAL.
+ size_t pos = 0;
+ size_t nextentry = 0;
+ while (pos < file_content_.size()) {
+ if (nextentry < temp_entries.size() &&
+ static_cast<off64_t>(pos) == temp_entries[nextentry].second.offset) {
+ // Add the next zip entry.
+ std::string entry_name = temp_entries[nextentry].first;
+ if (!AddZipEntryToChunks(handle, entry_name, &temp_entries[nextentry].second)) {
+ LOG(ERROR) << "Failed to add " << entry_name << " to target chunks";
+ return false;
+ }
+
+ pos += temp_entries[nextentry].second.compressed_length;
+ ++nextentry;
+ continue;
+ }
+
+ // Use a normal chunk to take all the data up to the start of the next entry.
+ size_t raw_data_len;
+ if (nextentry < temp_entries.size()) {
+ raw_data_len = temp_entries[nextentry].second.offset - pos;
+ } else {
+ raw_data_len = file_content_.size() - pos;
+ }
+ chunks_.emplace_back(CHUNK_NORMAL, pos, &file_content_, raw_data_len);
+
+ pos += raw_data_len;
+ }
+
+ return true;
+}
+
+bool ZipModeImage::AddZipEntryToChunks(ZipArchiveHandle handle, const std::string& entry_name,
+ ZipEntry* entry) {
+ size_t compressed_len = entry->compressed_length;
+ if (compressed_len == 0) return true;
+
+ // Split the entry into several normal chunks if it's too large.
+ if (limit_ > 0 && compressed_len > limit_) {
+ int count = 0;
+ while (compressed_len > 0) {
+ size_t length = std::min(limit_, compressed_len);
+ std::string name = entry_name + "-" + std::to_string(count);
+ chunks_.emplace_back(CHUNK_NORMAL, entry->offset + limit_ * count, &file_content_, length,
+ name);
+
+ count++;
+ compressed_len -= length;
+ }
+ } else if (entry->method == kCompressDeflated) {
+ size_t uncompressed_len = entry->uncompressed_length;
+ std::vector<uint8_t> uncompressed_data(uncompressed_len);
+ int ret = ExtractToMemory(handle, entry, uncompressed_data.data(), uncompressed_len);
+ if (ret != 0) {
+ LOG(ERROR) << "Failed to extract " << entry_name << " with size " << uncompressed_len << ": "
+ << ErrorCodeString(ret);
+ return false;
+ }
+ ImageChunk curr(CHUNK_DEFLATE, entry->offset, &file_content_, compressed_len, entry_name);
+ curr.SetUncompressedData(std::move(uncompressed_data));
+ chunks_.push_back(std::move(curr));
+ } else {
+ chunks_.emplace_back(CHUNK_NORMAL, entry->offset, &file_content_, compressed_len, entry_name);
+ }
+
+ return true;
+}
+
// EOCD record
// offset 0: signature 0x06054b50, 4 bytes
// offset 4: number of this disk, 2 bytes
// ...
// offset 20: comment length, 2 bytes
// offset 22: comment, n bytes
-static bool GetZipFileSize(const std::vector<uint8_t>& zip_file, size_t* input_file_size) {
- if (zip_file.size() < 22) {
- printf("file is too small to be a zip file\n");
+bool ZipModeImage::GetZipFileSize(size_t* input_file_size) {
+ if (file_content_.size() < 22) {
+ LOG(ERROR) << "File is too small to be a zip file";
return false;
}
// Look for End of central directory record of the zip file, and calculate the actual
// zip_file size.
- for (int i = zip_file.size() - 22; i >= 0; i--) {
- if (zip_file[i] == 0x50) {
- if (get_unaligned<uint32_t>(&zip_file[i]) == 0x06054b50) {
+ for (int i = file_content_.size() - 22; i >= 0; i--) {
+ if (file_content_[i] == 0x50) {
+ if (get_unaligned<uint32_t>(&file_content_[i]) == 0x06054b50) {
// double-check: this archive consists of a single "disk".
- CHECK_EQ(get_unaligned<uint16_t>(&zip_file[i + 4]), 0);
+ CHECK_EQ(get_unaligned<uint16_t>(&file_content_[i + 4]), 0);
- uint16_t comment_length = get_unaligned<uint16_t>(&zip_file[i + 20]);
+ uint16_t comment_length = get_unaligned<uint16_t>(&file_content_[i + 20]);
size_t file_size = i + 22 + comment_length;
- CHECK_LE(file_size, zip_file.size());
+ CHECK_LE(file_size, file_content_.size());
*input_file_size = file_size;
return true;
}
@@ -491,162 +826,445 @@
return false;
}
-static bool ReadZip(const char* filename, std::vector<ImageChunk>* chunks,
- std::vector<uint8_t>* zip_file, bool include_pseudo_chunk) {
- CHECK(chunks != nullptr && zip_file != nullptr);
+ImageChunk ZipModeImage::PseudoSource() const {
+ CHECK(is_source_);
+ return ImageChunk(CHUNK_NORMAL, 0, &file_content_, file_content_.size());
+}
- android::base::unique_fd fd(open(filename, O_RDONLY));
- if (fd == -1) {
- printf("failed to open \"%s\" %s\n", filename, strerror(errno));
- return false;
+const ImageChunk* ZipModeImage::FindChunkByName(const std::string& name, bool find_normal) const {
+ if (name.empty()) {
+ return nullptr;
}
- struct stat st;
- if (fstat(fd, &st) != 0) {
- printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
- return false;
- }
-
- size_t sz = static_cast<size_t>(st.st_size);
- zip_file->resize(sz);
- if (!android::base::ReadFully(fd, zip_file->data(), sz)) {
- printf("failed to read \"%s\" %s\n", filename, strerror(errno));
- return false;
- }
- fd.reset();
-
- // Trim the trailing zeros before we pass the file to ziparchive handler.
- size_t zipfile_size;
- if (!GetZipFileSize(*zip_file, &zipfile_size)) {
- printf("failed to parse the actual size of %s\n", filename);
- return false;
- }
- ZipArchiveHandle handle;
- int err = OpenArchiveFromMemory(zip_file->data(), zipfile_size, filename, &handle);
- if (err != 0) {
- printf("failed to open zip file %s: %s\n", filename, ErrorCodeString(err));
- CloseArchive(handle);
- return false;
- }
-
- // Create a list of deflated zip entries, sorted by offset.
- std::vector<std::pair<std::string, ZipEntry>> temp_entries;
- void* cookie;
- int ret = StartIteration(handle, &cookie, nullptr, nullptr);
- if (ret != 0) {
- printf("failed to iterate over entries in %s: %s\n", filename, ErrorCodeString(ret));
- CloseArchive(handle);
- return false;
- }
-
- ZipString name;
- ZipEntry entry;
- while ((ret = Next(cookie, &entry, &name)) == 0) {
- if (entry.method == kCompressDeflated) {
- std::string entryname(name.name, name.name + name.name_length);
- temp_entries.push_back(std::make_pair(entryname, entry));
- }
- }
-
- if (ret != -1) {
- printf("Error while iterating over zip entries: %s\n", ErrorCodeString(ret));
- CloseArchive(handle);
- return false;
- }
- std::sort(temp_entries.begin(), temp_entries.end(),
- [](auto& entry1, auto& entry2) {
- return entry1.second.offset < entry2.second.offset;
- });
-
- EndIteration(cookie);
-
- if (include_pseudo_chunk) {
- chunks->emplace_back(CHUNK_NORMAL, 0, zip_file, zip_file->size());
- }
-
- size_t pos = 0;
- size_t nextentry = 0;
- while (pos < zip_file->size()) {
- if (nextentry < temp_entries.size() &&
- static_cast<off64_t>(pos) == temp_entries[nextentry].second.offset) {
- // compose the next deflate chunk.
- std::string entryname = temp_entries[nextentry].first;
- size_t uncompressed_len = temp_entries[nextentry].second.uncompressed_length;
- std::vector<uint8_t> uncompressed_data(uncompressed_len);
- if ((ret = ExtractToMemory(handle, &temp_entries[nextentry].second, uncompressed_data.data(),
- uncompressed_len)) != 0) {
- printf("failed to extract %s with size %zu: %s\n", entryname.c_str(), uncompressed_len,
- ErrorCodeString(ret));
- CloseArchive(handle);
- return false;
- }
-
- size_t compressed_len = temp_entries[nextentry].second.compressed_length;
- ImageChunk curr(CHUNK_DEFLATE, pos, zip_file, compressed_len);
- curr.SetEntryName(std::move(entryname));
- curr.SetUncompressedData(std::move(uncompressed_data));
- chunks->push_back(curr);
-
- pos += compressed_len;
- ++nextentry;
+ for (auto& chunk : chunks_) {
+ if (chunk.GetType() != CHUNK_DEFLATE && !find_normal) {
continue;
}
- // Use a normal chunk to take all the data up to the start of the next deflate section.
- size_t raw_data_len;
- if (nextentry < temp_entries.size()) {
- raw_data_len = temp_entries[nextentry].second.offset - pos;
- } else {
- raw_data_len = zip_file->size() - pos;
+ if (chunk.GetEntryName() == name) {
+ return &chunk;
}
- chunks->emplace_back(CHUNK_NORMAL, pos, zip_file, raw_data_len);
- pos += raw_data_len;
+ // Edge case when target chunk is split due to size limit but source chunk isn't.
+ if (name == (chunk.GetEntryName() + "-0") || chunk.GetEntryName() == (name + "-0")) {
+ return &chunk;
+ }
+
+ // TODO handle the .so files with incremental version number.
+ // (e.g. lib/arm64-v8a/libcronet.59.0.3050.4.so)
}
- CloseArchive(handle);
+ return nullptr;
+}
+
+ImageChunk* ZipModeImage::FindChunkByName(const std::string& name, bool find_normal) {
+ return const_cast<ImageChunk*>(
+ static_cast<const ZipModeImage*>(this)->FindChunkByName(name, find_normal));
+}
+
+bool ZipModeImage::CheckAndProcessChunks(ZipModeImage* tgt_image, ZipModeImage* src_image) {
+ for (auto& tgt_chunk : *tgt_image) {
+ if (tgt_chunk.GetType() != CHUNK_DEFLATE) {
+ continue;
+ }
+
+ ImageChunk* src_chunk = src_image->FindChunkByName(tgt_chunk.GetEntryName());
+ if (src_chunk == nullptr) {
+ tgt_chunk.ChangeDeflateChunkToNormal();
+ } else if (tgt_chunk == *src_chunk) {
+ // If two deflate chunks are identical (eg, the kernel has not changed between two builds),
+ // treat them as normal chunks. This makes applypatch much faster -- it can apply a trivial
+ // patch to the compressed data, rather than uncompressing and recompressing to apply the
+ // trivial patch to the uncompressed data.
+ tgt_chunk.ChangeDeflateChunkToNormal();
+ src_chunk->ChangeDeflateChunkToNormal();
+ } else if (!tgt_chunk.ReconstructDeflateChunk()) {
+ // We cannot recompress the data and get exactly the same bits as are in the input target
+ // image. Treat the chunk as a normal non-deflated chunk.
+ LOG(WARNING) << "Failed to reconstruct target deflate chunk [" << tgt_chunk.GetEntryName()
+ << "]; treating as normal";
+
+ tgt_chunk.ChangeDeflateChunkToNormal();
+ src_chunk->ChangeDeflateChunkToNormal();
+ }
+ }
+
+ // For zips, we only need merge normal chunks for the target: deflated chunks are matched via
+ // filename, and normal chunks are patched using the entire source file as the source.
+ if (tgt_image->limit_ == 0) {
+ tgt_image->MergeAdjacentNormalChunks();
+ tgt_image->DumpChunks();
+ }
+
return true;
}
-// Read the given file and break it up into chunks, and putting the data in to a vector.
-static bool ReadImage(const char* filename, std::vector<ImageChunk>* chunks,
- std::vector<uint8_t>* img) {
- CHECK(chunks != nullptr && img != nullptr);
+// For each target chunk, look for the corresponding source chunk by the zip_entry name. If
+// found, add the range of this chunk in the original source file to the block aligned source
+// ranges. Construct the split src & tgt image once the size of source range reaches limit.
+bool ZipModeImage::SplitZipModeImageWithLimit(const ZipModeImage& tgt_image,
+ const ZipModeImage& src_image,
+ std::vector<ZipModeImage>* split_tgt_images,
+ std::vector<ZipModeImage>* split_src_images,
+ std::vector<SortedRangeSet>* split_src_ranges) {
+ CHECK_EQ(tgt_image.limit_, src_image.limit_);
+ size_t limit = tgt_image.limit_;
- android::base::unique_fd fd(open(filename, O_RDONLY));
- if (fd == -1) {
- printf("failed to open \"%s\" %s\n", filename, strerror(errno));
- return false;
+ src_image.DumpChunks();
+ LOG(INFO) << "Splitting " << tgt_image.NumOfChunks() << " tgt chunks...";
+
+ SortedRangeSet used_src_ranges; // ranges used for previous split source images.
+
+ // Reserve the central directory in advance for the last split image.
+ const auto& central_directory = src_image.cend() - 1;
+ CHECK_EQ(CHUNK_NORMAL, central_directory->GetType());
+ used_src_ranges.Insert(central_directory->GetStartOffset(),
+ central_directory->DataLengthForPatch());
+
+ SortedRangeSet src_ranges;
+ std::vector<ImageChunk> split_src_chunks;
+ std::vector<ImageChunk> split_tgt_chunks;
+ for (auto tgt = tgt_image.cbegin(); tgt != tgt_image.cend(); tgt++) {
+ const ImageChunk* src = src_image.FindChunkByName(tgt->GetEntryName(), true);
+ if (src == nullptr) {
+ split_tgt_chunks.emplace_back(CHUNK_NORMAL, tgt->GetStartOffset(), &tgt_image.file_content_,
+ tgt->GetRawDataLength());
+ continue;
+ }
+
+ size_t src_offset = src->GetStartOffset();
+ size_t src_length = src->GetRawDataLength();
+
+ CHECK(src_length > 0);
+ CHECK_LE(src_length, limit);
+
+ // Make sure this source range hasn't been used before so that the src_range pieces don't
+ // overlap with each other.
+ if (!RemoveUsedBlocks(&src_offset, &src_length, used_src_ranges)) {
+ split_tgt_chunks.emplace_back(CHUNK_NORMAL, tgt->GetStartOffset(), &tgt_image.file_content_,
+ tgt->GetRawDataLength());
+ } else if (src_ranges.blocks() * BLOCK_SIZE + src_length <= limit) {
+ src_ranges.Insert(src_offset, src_length);
+
+ // Add the deflate source chunk if it hasn't been aligned.
+ if (src->GetType() == CHUNK_DEFLATE && src_length == src->GetRawDataLength()) {
+ split_src_chunks.push_back(*src);
+ split_tgt_chunks.push_back(*tgt);
+ } else {
+ // TODO split smarter to avoid alignment of large deflate chunks
+ split_tgt_chunks.emplace_back(CHUNK_NORMAL, tgt->GetStartOffset(), &tgt_image.file_content_,
+ tgt->GetRawDataLength());
+ }
+ } else {
+ bool added_image = ZipModeImage::AddSplitImageFromChunkList(
+ tgt_image, src_image, src_ranges, split_tgt_chunks, split_src_chunks, split_tgt_images,
+ split_src_images);
+
+ split_tgt_chunks.clear();
+ split_src_chunks.clear();
+ // No need to update the split_src_ranges if we don't update the split source images.
+ if (added_image) {
+ used_src_ranges.Insert(src_ranges);
+ split_src_ranges->push_back(std::move(src_ranges));
+ }
+ src_ranges.Clear();
+
+ // We don't have enough space for the current chunk; start a new split image and handle
+ // this chunk there.
+ tgt--;
+ }
}
- struct stat st;
- if (fstat(fd, &st) != 0) {
- printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
+
+ // TODO Trim it in case the CD exceeds limit too much.
+ src_ranges.Insert(central_directory->GetStartOffset(), central_directory->DataLengthForPatch());
+ bool added_image = ZipModeImage::AddSplitImageFromChunkList(tgt_image, src_image, src_ranges,
+ split_tgt_chunks, split_src_chunks,
+ split_tgt_images, split_src_images);
+ if (added_image) {
+ split_src_ranges->push_back(std::move(src_ranges));
+ }
+
+ ValidateSplitImages(*split_tgt_images, *split_src_images, *split_src_ranges,
+ tgt_image.file_content_.size());
+
+ return true;
+}
+
+bool ZipModeImage::AddSplitImageFromChunkList(const ZipModeImage& tgt_image,
+ const ZipModeImage& src_image,
+ const SortedRangeSet& split_src_ranges,
+ const std::vector<ImageChunk>& split_tgt_chunks,
+ const std::vector<ImageChunk>& split_src_chunks,
+ std::vector<ZipModeImage>* split_tgt_images,
+ std::vector<ZipModeImage>* split_src_images) {
+ CHECK(!split_tgt_chunks.empty());
+
+ std::vector<ImageChunk> aligned_tgt_chunks;
+
+ // Align the target chunks in the beginning with BLOCK_SIZE.
+ size_t i = 0;
+ while (i < split_tgt_chunks.size()) {
+ size_t tgt_start = split_tgt_chunks[i].GetStartOffset();
+ size_t tgt_length = split_tgt_chunks[i].GetRawDataLength();
+
+ // Current ImageChunk is long enough to align.
+ if (AlignHead(&tgt_start, &tgt_length)) {
+ aligned_tgt_chunks.emplace_back(CHUNK_NORMAL, tgt_start, &tgt_image.file_content_,
+ tgt_length);
+ break;
+ }
+
+ i++;
+ }
+
+ // Nothing left after alignment in the current split tgt chunks; skip adding the split_tgt_image.
+ if (i == split_tgt_chunks.size()) {
return false;
}
- size_t sz = static_cast<size_t>(st.st_size);
- img->resize(sz);
- if (!android::base::ReadFully(fd, img->data(), sz)) {
- printf("failed to read \"%s\" %s\n", filename, strerror(errno));
+ aligned_tgt_chunks.insert(aligned_tgt_chunks.end(), split_tgt_chunks.begin() + i + 1,
+ split_tgt_chunks.end());
+ CHECK(!aligned_tgt_chunks.empty());
+
+ // Add a normal chunk to align the contents in the end.
+ size_t end_offset =
+ aligned_tgt_chunks.back().GetStartOffset() + aligned_tgt_chunks.back().GetRawDataLength();
+ if (end_offset % BLOCK_SIZE != 0 && end_offset < tgt_image.file_content_.size()) {
+ size_t tail_block_length = std::min<size_t>(tgt_image.file_content_.size() - end_offset,
+ BLOCK_SIZE - (end_offset % BLOCK_SIZE));
+ aligned_tgt_chunks.emplace_back(CHUNK_NORMAL, end_offset, &tgt_image.file_content_,
+ tail_block_length);
+ }
+
+ ZipModeImage split_tgt_image(false);
+ split_tgt_image.Initialize(std::move(aligned_tgt_chunks), {});
+ split_tgt_image.MergeAdjacentNormalChunks();
+
+ // Construct the dummy source file based on the src_ranges.
+ std::vector<uint8_t> src_content;
+ for (const auto& r : split_src_ranges) {
+ size_t end = std::min(src_image.file_content_.size(), r.second * BLOCK_SIZE);
+ src_content.insert(src_content.end(), src_image.file_content_.begin() + r.first * BLOCK_SIZE,
+ src_image.file_content_.begin() + end);
+ }
+
+ // We should not have an empty src in our design; otherwise we will encounter an error in
+ // bsdiff since src_content.data() == nullptr.
+ CHECK(!src_content.empty());
+
+ ZipModeImage split_src_image(true);
+ split_src_image.Initialize(split_src_chunks, std::move(src_content));
+
+ split_tgt_images->push_back(std::move(split_tgt_image));
+ split_src_images->push_back(std::move(split_src_image));
+
+ return true;
+}
+
+void ZipModeImage::ValidateSplitImages(const std::vector<ZipModeImage>& split_tgt_images,
+ const std::vector<ZipModeImage>& split_src_images,
+ std::vector<SortedRangeSet>& split_src_ranges,
+ size_t total_tgt_size) {
+ CHECK_EQ(split_tgt_images.size(), split_src_images.size());
+
+ LOG(INFO) << "Validating " << split_tgt_images.size() << " images";
+
+ // Verify that the target image pieces is continuous and can add up to the total size.
+ size_t last_offset = 0;
+ for (const auto& tgt_image : split_tgt_images) {
+ CHECK(!tgt_image.chunks_.empty());
+
+ CHECK_EQ(last_offset, tgt_image.chunks_.front().GetStartOffset());
+ CHECK(last_offset % BLOCK_SIZE == 0);
+
+ // Check the target chunks within the split image are continuous.
+ for (const auto& chunk : tgt_image.chunks_) {
+ CHECK_EQ(last_offset, chunk.GetStartOffset());
+ last_offset += chunk.GetRawDataLength();
+ }
+ }
+ CHECK_EQ(total_tgt_size, last_offset);
+
+ // Verify that the source ranges are mutually exclusive.
+ CHECK_EQ(split_src_images.size(), split_src_ranges.size());
+ SortedRangeSet used_src_ranges;
+ for (size_t i = 0; i < split_src_ranges.size(); i++) {
+ CHECK(!used_src_ranges.Overlaps(split_src_ranges[i]))
+ << "src range " << split_src_ranges[i].ToString() << " overlaps "
+ << used_src_ranges.ToString();
+ used_src_ranges.Insert(split_src_ranges[i]);
+ }
+}
+
+bool ZipModeImage::GeneratePatchesInternal(const ZipModeImage& tgt_image,
+ const ZipModeImage& src_image,
+ std::vector<PatchChunk>* patch_chunks) {
+ LOG(INFO) << "Constructing patches for " << tgt_image.NumOfChunks() << " chunks...";
+ patch_chunks->clear();
+
+ bsdiff::SuffixArrayIndexInterface* bsdiff_cache = nullptr;
+ for (size_t i = 0; i < tgt_image.NumOfChunks(); i++) {
+ const auto& tgt_chunk = tgt_image[i];
+
+ if (PatchChunk::RawDataIsSmaller(tgt_chunk, 0)) {
+ patch_chunks->emplace_back(tgt_chunk);
+ continue;
+ }
+
+ const ImageChunk* src_chunk = (tgt_chunk.GetType() != CHUNK_DEFLATE)
+ ? nullptr
+ : src_image.FindChunkByName(tgt_chunk.GetEntryName());
+
+ const auto& src_ref = (src_chunk == nullptr) ? src_image.PseudoSource() : *src_chunk;
+ bsdiff::SuffixArrayIndexInterface** bsdiff_cache_ptr =
+ (src_chunk == nullptr) ? &bsdiff_cache : nullptr;
+
+ std::vector<uint8_t> patch_data;
+ if (!ImageChunk::MakePatch(tgt_chunk, src_ref, &patch_data, bsdiff_cache_ptr)) {
+ LOG(ERROR) << "Failed to generate patch, name: " << tgt_chunk.GetEntryName();
+ return false;
+ }
+
+ LOG(INFO) << "patch " << i << " is " << patch_data.size() << " bytes (of "
+ << tgt_chunk.GetRawDataLength() << ")";
+
+ if (PatchChunk::RawDataIsSmaller(tgt_chunk, patch_data.size())) {
+ patch_chunks->emplace_back(tgt_chunk);
+ } else {
+ patch_chunks->emplace_back(tgt_chunk, src_ref, std::move(patch_data));
+ }
+ }
+ delete bsdiff_cache;
+
+ CHECK_EQ(patch_chunks->size(), tgt_image.NumOfChunks());
+ return true;
+}
+
+bool ZipModeImage::GeneratePatches(const ZipModeImage& tgt_image, const ZipModeImage& src_image,
+ const std::string& patch_name) {
+ std::vector<PatchChunk> patch_chunks;
+
+ ZipModeImage::GeneratePatchesInternal(tgt_image, src_image, &patch_chunks);
+
+ CHECK_EQ(tgt_image.NumOfChunks(), patch_chunks.size());
+
+ android::base::unique_fd patch_fd(
+ open(patch_name.c_str(), O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR));
+ if (patch_fd == -1) {
+ PLOG(ERROR) << "Failed to open " << patch_name;
return false;
}
+ return PatchChunk::WritePatchDataToFd(patch_chunks, patch_fd);
+}
+
+bool ZipModeImage::GeneratePatches(const std::vector<ZipModeImage>& split_tgt_images,
+ const std::vector<ZipModeImage>& split_src_images,
+ const std::vector<SortedRangeSet>& split_src_ranges,
+ const std::string& patch_name,
+ const std::string& split_info_file,
+ const std::string& debug_dir) {
+ LOG(INFO) << "Constructing patches for " << split_tgt_images.size() << " split images...";
+
+ android::base::unique_fd patch_fd(
+ open(patch_name.c_str(), O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR));
+ if (patch_fd == -1) {
+ PLOG(ERROR) << "Failed to open " << patch_name;
+ return false;
+ }
+
+ std::vector<std::string> split_info_list;
+ for (size_t i = 0; i < split_tgt_images.size(); i++) {
+ std::vector<PatchChunk> patch_chunks;
+ if (!ZipModeImage::GeneratePatchesInternal(split_tgt_images[i], split_src_images[i],
+ &patch_chunks)) {
+ LOG(ERROR) << "Failed to generate split patch";
+ return false;
+ }
+
+ size_t total_patch_size = 12;
+ for (auto& p : patch_chunks) {
+ p.UpdateSourceOffset(split_src_ranges[i]);
+ total_patch_size += p.PatchSize();
+ }
+
+ if (!PatchChunk::WritePatchDataToFd(patch_chunks, patch_fd)) {
+ return false;
+ }
+
+ size_t split_tgt_size = split_tgt_images[i].chunks_.back().GetStartOffset() +
+ split_tgt_images[i].chunks_.back().GetRawDataLength() -
+ split_tgt_images[i].chunks_.front().GetStartOffset();
+ std::string split_info = android::base::StringPrintf(
+ "%zu %zu %s", total_patch_size, split_tgt_size, split_src_ranges[i].ToString().c_str());
+ split_info_list.push_back(split_info);
+
+ // Write the split source & patch into the debug directory.
+ if (!debug_dir.empty()) {
+ std::string src_name = android::base::StringPrintf("%s/src-%zu", debug_dir.c_str(), i);
+ android::base::unique_fd fd(
+ open(src_name.c_str(), O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR));
+
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open " << src_name;
+ return false;
+ }
+ if (!android::base::WriteFully(fd, split_src_images[i].PseudoSource().DataForPatch(),
+ split_src_images[i].PseudoSource().DataLengthForPatch())) {
+ PLOG(ERROR) << "Failed to write split source data into " << src_name;
+ return false;
+ }
+
+ std::string patch_name = android::base::StringPrintf("%s/patch-%zu", debug_dir.c_str(), i);
+ fd.reset(open(patch_name.c_str(), O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR));
+
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open " << patch_name;
+ return false;
+ }
+ if (!PatchChunk::WritePatchDataToFd(patch_chunks, fd)) {
+ return false;
+ }
+ }
+ }
+
+ // Store the split in the following format:
+ // Line 0: imgdiff version#
+ // Line 1: number of pieces
+ // Line 2: patch_size_1 tgt_size_1 src_range_1
+ // ...
+ // Line n+1: patch_size_n tgt_size_n src_range_n
+ std::string split_info_string = android::base::StringPrintf(
+ "%zu\n%zu\n", VERSION, split_info_list.size()) + android::base::Join(split_info_list, '\n');
+ if (!android::base::WriteStringToFile(split_info_string, split_info_file)) {
+ PLOG(ERROR) << "Failed to write split info to " << split_info_file;
+ return false;
+ }
+
+ return true;
+}
+
+bool ImageModeImage::Initialize(const std::string& filename) {
+ if (!ReadFile(filename, &file_content_)) {
+ return false;
+ }
+
+ size_t sz = file_content_.size();
size_t pos = 0;
-
while (pos < sz) {
// 0x00 no header flags, 0x08 deflate compression, 0x1f8b gzip magic number
- if (sz - pos >= 4 && get_unaligned<uint32_t>(img->data() + pos) == 0x00088b1f) {
+ if (sz - pos >= 4 && get_unaligned<uint32_t>(file_content_.data() + pos) == 0x00088b1f) {
// 'pos' is the offset of the start of a gzip chunk.
size_t chunk_offset = pos;
// The remaining data is too small to be a gzip chunk; treat them as a normal chunk.
if (sz - pos < GZIP_HEADER_LEN + GZIP_FOOTER_LEN) {
- chunks->emplace_back(CHUNK_NORMAL, pos, img, sz - pos);
+ chunks_.emplace_back(CHUNK_NORMAL, pos, &file_content_, sz - pos);
break;
}
// We need three chunks for the deflated image in total, one normal chunk for the header,
// one deflated chunk for the body, and another normal chunk for the footer.
- chunks->emplace_back(CHUNK_NORMAL, pos, img, GZIP_HEADER_LEN);
+ chunks_.emplace_back(CHUNK_NORMAL, pos, &file_content_, GZIP_HEADER_LEN);
pos += GZIP_HEADER_LEN;
// We must decompress this chunk in order to discover where it ends, and so we can update
@@ -657,13 +1275,13 @@
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = sz - pos;
- strm.next_in = img->data() + pos;
+ strm.next_in = file_content_.data() + pos;
// -15 means we are decoding a 'raw' deflate stream; zlib will
// not expect zlib headers.
int ret = inflateInit2(&strm, -15);
if (ret < 0) {
- printf("failed to initialize inflate: %d\n", ret);
+ LOG(ERROR) << "Failed to initialize inflate: " << ret;
return false;
}
@@ -675,8 +1293,8 @@
strm.next_out = uncompressed_data.data() + uncompressed_len;
ret = inflate(&strm, Z_NO_FLUSH);
if (ret < 0) {
- printf("Warning: inflate failed [%s] at offset [%zu], treating as a normal chunk\n",
- strm.msg, chunk_offset);
+ LOG(WARNING) << "Inflate failed [" << strm.msg << "] at offset [" << chunk_offset
+ << "]; treating as a normal chunk";
break;
}
uncompressed_len = allocated - strm.avail_out;
@@ -697,25 +1315,25 @@
// matches the size of the data we got when we actually did the decompression.
size_t footer_index = pos + raw_data_len + GZIP_FOOTER_LEN - 4;
if (sz - footer_index < 4) {
- printf("Warning: invalid footer position; treating as a nomal chunk\n");
+ LOG(WARNING) << "invalid footer position; treating as a normal chunk";
continue;
}
- size_t footer_size = get_unaligned<uint32_t>(img->data() + footer_index);
+ size_t footer_size = get_unaligned<uint32_t>(file_content_.data() + footer_index);
if (footer_size != uncompressed_len) {
- printf("Warning: footer size %zu != decompressed size %zu; treating as a nomal chunk\n",
- footer_size, uncompressed_len);
+ LOG(WARNING) << "footer size " << footer_size << " != " << uncompressed_len
+ << "; treating as a normal chunk";
continue;
}
- ImageChunk body(CHUNK_DEFLATE, pos, img, raw_data_len);
+ ImageChunk body(CHUNK_DEFLATE, pos, &file_content_, raw_data_len);
uncompressed_data.resize(uncompressed_len);
body.SetUncompressedData(std::move(uncompressed_data));
- chunks->push_back(body);
+ chunks_.push_back(std::move(body));
pos += raw_data_len;
// create a normal chunk for the footer
- chunks->emplace_back(CHUNK_NORMAL, pos, img, GZIP_FOOTER_LEN);
+ chunks_.emplace_back(CHUNK_NORMAL, pos, &file_content_, GZIP_FOOTER_LEN);
pos += GZIP_FOOTER_LEN;
} else {
@@ -726,12 +1344,12 @@
size_t data_len = 0;
while (data_len + pos < sz) {
if (data_len + pos + 4 <= sz &&
- get_unaligned<uint32_t>(img->data() + pos + data_len) == 0x00088b1f) {
+ get_unaligned<uint32_t>(file_content_.data() + pos + data_len) == 0x00088b1f) {
break;
}
data_len++;
}
- chunks->emplace_back(CHUNK_NORMAL, pos, img, data_len);
+ chunks_.emplace_back(CHUNK_NORMAL, pos, &file_content_, data_len);
pos += data_len;
}
@@ -740,346 +1358,256 @@
return true;
}
-/*
- * Given source and target chunks, compute a bsdiff patch between them.
- * Store the result in the patch_data.
- * |bsdiff_cache| can be used to cache the suffix array if the same |src| chunk
- * is used repeatedly, pass nullptr if not needed.
- */
-static bool MakePatch(const ImageChunk* src, ImageChunk* tgt, std::vector<uint8_t>* patch_data,
- saidx_t** bsdiff_cache) {
- if (tgt->ChangeChunkToRaw(0)) {
- size_t patch_size = tgt->DataLengthForPatch();
- patch_data->resize(patch_size);
- std::copy(tgt->DataForPatch(), tgt->DataForPatch() + patch_size, patch_data->begin());
- return true;
- }
-
-#if defined(__ANDROID__)
- char ptemp[] = "/data/local/tmp/imgdiff-patch-XXXXXX";
-#else
- char ptemp[] = "/tmp/imgdiff-patch-XXXXXX";
-#endif
-
- int fd = mkstemp(ptemp);
- if (fd == -1) {
- printf("MakePatch failed to create a temporary file: %s\n", strerror(errno));
- return false;
- }
- close(fd);
-
- int r = bsdiff::bsdiff(src->DataForPatch(), src->DataLengthForPatch(), tgt->DataForPatch(),
- tgt->DataLengthForPatch(), ptemp, bsdiff_cache);
- if (r != 0) {
- printf("bsdiff() failed: %d\n", r);
+bool ImageModeImage::SetBonusData(const std::vector<uint8_t>& bonus_data) {
+ CHECK(is_source_);
+ if (chunks_.size() < 2 || !chunks_[1].SetBonusData(bonus_data)) {
+ LOG(ERROR) << "Failed to set bonus data";
+ DumpChunks();
return false;
}
- android::base::unique_fd patch_fd(open(ptemp, O_RDONLY));
- if (patch_fd == -1) {
- printf("failed to open %s: %s\n", ptemp, strerror(errno));
+ LOG(INFO) << " using " << bonus_data.size() << " bytes of bonus data";
+ return true;
+}
+
+// In Image Mode, verify that the source and target images have the same chunk structure (ie, the
+// same sequence of deflate and normal chunks).
+bool ImageModeImage::CheckAndProcessChunks(ImageModeImage* tgt_image, ImageModeImage* src_image) {
+ // In image mode, merge the gzip header and footer in with any adjacent normal chunks.
+ tgt_image->MergeAdjacentNormalChunks();
+ src_image->MergeAdjacentNormalChunks();
+
+ if (tgt_image->NumOfChunks() != src_image->NumOfChunks()) {
+ LOG(ERROR) << "Source and target don't have same number of chunks!";
+ tgt_image->DumpChunks();
+ src_image->DumpChunks();
return false;
}
- struct stat st;
- if (fstat(patch_fd, &st) != 0) {
- printf("failed to stat patch file %s: %s\n", ptemp, strerror(errno));
- return false;
+ for (size_t i = 0; i < tgt_image->NumOfChunks(); ++i) {
+ if ((*tgt_image)[i].GetType() != (*src_image)[i].GetType()) {
+ LOG(ERROR) << "Source and target don't have same chunk structure! (chunk " << i << ")";
+ tgt_image->DumpChunks();
+ src_image->DumpChunks();
+ return false;
+ }
}
- size_t sz = static_cast<size_t>(st.st_size);
- // Change the chunk type to raw if the patch takes less space that way.
- if (tgt->ChangeChunkToRaw(sz)) {
- unlink(ptemp);
- size_t patch_size = tgt->DataLengthForPatch();
- patch_data->resize(patch_size);
- std::copy(tgt->DataForPatch(), tgt->DataForPatch() + patch_size, patch_data->begin());
- return true;
- }
- patch_data->resize(sz);
- if (!android::base::ReadFully(patch_fd, patch_data->data(), sz)) {
- printf("failed to read \"%s\" %s\n", ptemp, strerror(errno));
- return false;
+ for (size_t i = 0; i < tgt_image->NumOfChunks(); ++i) {
+ auto& tgt_chunk = (*tgt_image)[i];
+ auto& src_chunk = (*src_image)[i];
+ if (tgt_chunk.GetType() != CHUNK_DEFLATE) {
+ continue;
+ }
+
+ // If two deflate chunks are identical treat them as normal chunks.
+ if (tgt_chunk == src_chunk) {
+ tgt_chunk.ChangeDeflateChunkToNormal();
+ src_chunk.ChangeDeflateChunkToNormal();
+ } else if (!tgt_chunk.ReconstructDeflateChunk()) {
+ // We cannot recompress the data and get exactly the same bits as are in the input target
+ // image, fall back to normal
+ LOG(WARNING) << "Failed to reconstruct target deflate chunk " << i << " ["
+ << tgt_chunk.GetEntryName() << "]; treating as normal";
+ tgt_chunk.ChangeDeflateChunkToNormal();
+ src_chunk.ChangeDeflateChunkToNormal();
+ }
}
- unlink(ptemp);
- tgt->SetSourceInfo(*src);
+ // For images, we need to maintain the parallel structure of the chunk lists, so do the merging
+ // in both the source and target lists.
+ tgt_image->MergeAdjacentNormalChunks();
+ src_image->MergeAdjacentNormalChunks();
+ if (tgt_image->NumOfChunks() != src_image->NumOfChunks()) {
+ // This shouldn't happen.
+ LOG(ERROR) << "Merging normal chunks went awry";
+ return false;
+ }
return true;
}
-/*
- * Look for runs of adjacent normal chunks and compress them down into
- * a single chunk. (Such runs can be produced when deflate chunks are
- * changed to normal chunks.)
- */
-static void MergeAdjacentNormalChunks(std::vector<ImageChunk>* chunks) {
- size_t merged_last = 0, cur = 0;
- while (cur < chunks->size()) {
- // Look for normal chunks adjacent to the current one. If such chunk exists, extend the
- // length of the current normal chunk.
- size_t to_check = cur + 1;
- while (to_check < chunks->size() && chunks->at(cur).IsAdjacentNormal(chunks->at(to_check))) {
- chunks->at(cur).MergeAdjacentNormal(chunks->at(to_check));
- to_check++;
+// In image mode, generate patches against the given source chunks and bonus_data; write the
+// result to |patch_name|.
+bool ImageModeImage::GeneratePatches(const ImageModeImage& tgt_image,
+ const ImageModeImage& src_image,
+ const std::string& patch_name) {
+ LOG(INFO) << "Constructing patches for " << tgt_image.NumOfChunks() << " chunks...";
+ std::vector<PatchChunk> patch_chunks;
+ patch_chunks.reserve(tgt_image.NumOfChunks());
+
+ for (size_t i = 0; i < tgt_image.NumOfChunks(); i++) {
+ const auto& tgt_chunk = tgt_image[i];
+ const auto& src_chunk = src_image[i];
+
+ if (PatchChunk::RawDataIsSmaller(tgt_chunk, 0)) {
+ patch_chunks.emplace_back(tgt_chunk);
+ continue;
}
- if (merged_last != cur) {
- chunks->at(merged_last) = std::move(chunks->at(cur));
+ std::vector<uint8_t> patch_data;
+ if (!ImageChunk::MakePatch(tgt_chunk, src_chunk, &patch_data, nullptr)) {
+ LOG(ERROR) << "Failed to generate patch for target chunk " << i;
+ return false;
}
- merged_last++;
- cur = to_check;
- }
- if (merged_last < chunks->size()) {
- chunks->erase(chunks->begin() + merged_last, chunks->end());
- }
-}
+ LOG(INFO) << "patch " << i << " is " << patch_data.size() << " bytes (of "
+ << tgt_chunk.GetRawDataLength() << ")";
-static ImageChunk* FindChunkByName(const std::string& name, std::vector<ImageChunk>& chunks) {
- for (size_t i = 0; i < chunks.size(); ++i) {
- if (chunks[i].GetType() == CHUNK_DEFLATE && chunks[i].GetEntryName() == name) {
- return &chunks[i];
+ if (PatchChunk::RawDataIsSmaller(tgt_chunk, patch_data.size())) {
+ patch_chunks.emplace_back(tgt_chunk);
+ } else {
+ patch_chunks.emplace_back(tgt_chunk, src_chunk, std::move(patch_data));
}
}
- return nullptr;
-}
-static void DumpChunks(const std::vector<ImageChunk>& chunks) {
- for (size_t i = 0; i < chunks.size(); ++i) {
- printf("chunk %zu: ", i);
- chunks[i].Dump();
+ CHECK_EQ(tgt_image.NumOfChunks(), patch_chunks.size());
+
+ android::base::unique_fd patch_fd(
+ open(patch_name.c_str(), O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR));
+ if (patch_fd == -1) {
+ PLOG(ERROR) << "Failed to open " << patch_name;
+ return false;
}
+
+ return PatchChunk::WritePatchDataToFd(patch_chunks, patch_fd);
}
int imgdiff(int argc, const char** argv) {
+ bool verbose = false;
bool zip_mode = false;
-
- if (argc >= 2 && strcmp(argv[1], "-z") == 0) {
- zip_mode = true;
- --argc;
- ++argv;
- }
-
std::vector<uint8_t> bonus_data;
- if (argc >= 3 && strcmp(argv[1], "-b") == 0) {
- android::base::unique_fd fd(open(argv[2], O_RDONLY));
- if (fd == -1) {
- printf("failed to open bonus file %s: %s\n", argv[2], strerror(errno));
- return 1;
- }
- struct stat st;
- if (fstat(fd, &st) != 0) {
- printf("failed to stat bonus file %s: %s\n", argv[2], strerror(errno));
- return 1;
- }
+ size_t blocks_limit = 0;
+ std::string split_info_file;
+ std::string debug_dir;
- size_t bonus_size = st.st_size;
- bonus_data.resize(bonus_size);
- if (!android::base::ReadFully(fd, bonus_data.data(), bonus_size)) {
- printf("failed to read bonus file %s: %s\n", argv[2], strerror(errno));
- return 1;
- }
+ int opt;
+ int option_index;
+ optind = 0; // Reset the getopt state so that we can call it multiple times for test.
- argc -= 2;
- argv += 2;
+ while ((opt = getopt_long(argc, const_cast<char**>(argv), "zb:v", OPTIONS, &option_index)) !=
+ -1) {
+ switch (opt) {
+ case 'z':
+ zip_mode = true;
+ break;
+ case 'b': {
+ android::base::unique_fd fd(open(optarg, O_RDONLY));
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open bonus file " << optarg;
+ return 1;
+ }
+ struct stat st;
+ if (fstat(fd, &st) != 0) {
+ PLOG(ERROR) << "Failed to stat bonus file " << optarg;
+ return 1;
+ }
+
+ size_t bonus_size = st.st_size;
+ bonus_data.resize(bonus_size);
+ if (!android::base::ReadFully(fd, bonus_data.data(), bonus_size)) {
+ PLOG(ERROR) << "Failed to read bonus file " << optarg;
+ return 1;
+ }
+ break;
+ }
+ case 'v':
+ verbose = true;
+ break;
+ case 0: {
+ std::string name = OPTIONS[option_index].name;
+ if (name == "block-limit" && !android::base::ParseUint(optarg, &blocks_limit)) {
+ LOG(ERROR) << "Failed to parse size blocks_limit: " << optarg;
+ return 1;
+ } else if (name == "split-info") {
+ split_info_file = optarg;
+ } else if (name == "debug-dir") {
+ debug_dir = optarg;
+ }
+ break;
+ }
+ default:
+ LOG(ERROR) << "unexpected opt: " << static_cast<char>(opt);
+ return 2;
+ }
}
- if (argc != 4) {
- printf("usage: %s [-z] [-b <bonus-file>] <src-img> <tgt-img> <patch-file>\n",
- argv[0]);
+ if (!verbose) {
+ android::base::SetMinimumLogSeverity(android::base::WARNING);
+ }
+
+ if (argc - optind != 3) {
+ LOG(ERROR) << "usage: " << argv[0] << " [options] <src-img> <tgt-img> <patch-file>";
+ LOG(ERROR)
+ << " -z <zip-mode>, Generate patches in zip mode, src and tgt should be zip files.\n"
+ " -b <bonus-file>, Bonus file in addition to src, image mode only.\n"
+ " --block-limit, For large zips, split the src and tgt based on the block limit;\n"
+ " and generate patches between each pair of pieces. Concatenate "
+ "these\n"
+ " patches together and output them into <patch-file>.\n"
+ " --split-info, Output the split information (patch_size, tgt_size, src_ranges);\n"
+ " zip mode with block-limit only.\n"
+ " --debug-dir, Debug directory to put the split srcs and patches, zip mode only.\n"
+ " -v, --verbose, Enable verbose logging.";
return 2;
}
- std::vector<ImageChunk> src_chunks;
- std::vector<ImageChunk> tgt_chunks;
- std::vector<uint8_t> src_file;
- std::vector<uint8_t> tgt_file;
-
if (zip_mode) {
- if (!ReadZip(argv[1], &src_chunks, &src_file, true)) {
- printf("failed to break apart source zip file\n");
+ ZipModeImage src_image(true, blocks_limit * BLOCK_SIZE);
+ ZipModeImage tgt_image(false, blocks_limit * BLOCK_SIZE);
+
+ if (!src_image.Initialize(argv[optind])) {
return 1;
}
- if (!ReadZip(argv[2], &tgt_chunks, &tgt_file, false)) {
- printf("failed to break apart target zip file\n");
+ if (!tgt_image.Initialize(argv[optind + 1])) {
+ return 1;
+ }
+
+ if (!ZipModeImage::CheckAndProcessChunks(&tgt_image, &src_image)) {
+ return 1;
+ }
+
+ // Compute bsdiff patches for each chunk's data (the uncompressed data, in the case of
+ // deflate chunks).
+ if (blocks_limit > 0) {
+ if (split_info_file.empty()) {
+ LOG(ERROR) << "split-info path cannot be empty when generating patches with a block-limit";
+ return 1;
+ }
+
+ std::vector<ZipModeImage> split_tgt_images;
+ std::vector<ZipModeImage> split_src_images;
+ std::vector<SortedRangeSet> split_src_ranges;
+ ZipModeImage::SplitZipModeImageWithLimit(tgt_image, src_image, &split_tgt_images,
+ &split_src_images, &split_src_ranges);
+
+ if (!ZipModeImage::GeneratePatches(split_tgt_images, split_src_images, split_src_ranges,
+ argv[optind + 2], split_info_file, debug_dir)) {
+ return 1;
+ }
+
+ } else if (!ZipModeImage::GeneratePatches(tgt_image, src_image, argv[optind + 2])) {
return 1;
}
} else {
- if (!ReadImage(argv[1], &src_chunks, &src_file)) {
- printf("failed to break apart source image\n");
+ ImageModeImage src_image(true);
+ ImageModeImage tgt_image(false);
+
+ if (!src_image.Initialize(argv[optind])) {
return 1;
}
- if (!ReadImage(argv[2], &tgt_chunks, &tgt_file)) {
- printf("failed to break apart target image\n");
+ if (!tgt_image.Initialize(argv[optind + 1])) {
return 1;
}
- // Verify that the source and target images have the same chunk
- // structure (ie, the same sequence of deflate and normal chunks).
-
- // Merge the gzip header and footer in with any adjacent normal chunks.
- MergeAdjacentNormalChunks(&tgt_chunks);
- MergeAdjacentNormalChunks(&src_chunks);
-
- if (src_chunks.size() != tgt_chunks.size()) {
- printf("source and target don't have same number of chunks!\n");
- printf("source chunks:\n");
- DumpChunks(src_chunks);
- printf("target chunks:\n");
- DumpChunks(tgt_chunks);
+ if (!ImageModeImage::CheckAndProcessChunks(&tgt_image, &src_image)) {
return 1;
}
- for (size_t i = 0; i < src_chunks.size(); ++i) {
- if (src_chunks[i].GetType() != tgt_chunks[i].GetType()) {
- printf("source and target don't have same chunk structure! (chunk %zu)\n", i);
- printf("source chunks:\n");
- DumpChunks(src_chunks);
- printf("target chunks:\n");
- DumpChunks(tgt_chunks);
- return 1;
- }
- }
- }
- for (size_t i = 0; i < tgt_chunks.size(); ++i) {
- if (tgt_chunks[i].GetType() == CHUNK_DEFLATE) {
- // Confirm that given the uncompressed chunk data in the target, we
- // can recompress it and get exactly the same bits as are in the
- // input target image. If this fails, treat the chunk as a normal
- // non-deflated chunk.
- if (!tgt_chunks[i].ReconstructDeflateChunk()) {
- printf("failed to reconstruct target deflate chunk %zu [%s]; treating as normal\n", i,
- tgt_chunks[i].GetEntryName().c_str());
- tgt_chunks[i].ChangeDeflateChunkToNormal();
- if (zip_mode) {
- ImageChunk* src = FindChunkByName(tgt_chunks[i].GetEntryName(), src_chunks);
- if (src != nullptr) {
- src->ChangeDeflateChunkToNormal();
- }
- } else {
- src_chunks[i].ChangeDeflateChunkToNormal();
- }
- continue;
- }
-
- // If two deflate chunks are identical (eg, the kernel has not
- // changed between two builds), treat them as normal chunks.
- // This makes applypatch much faster -- it can apply a trivial
- // patch to the compressed data, rather than uncompressing and
- // recompressing to apply the trivial patch to the uncompressed
- // data.
- ImageChunk* src;
- if (zip_mode) {
- src = FindChunkByName(tgt_chunks[i].GetEntryName(), src_chunks);
- } else {
- src = &src_chunks[i];
- }
-
- if (src == nullptr) {
- tgt_chunks[i].ChangeDeflateChunkToNormal();
- } else if (tgt_chunks[i] == *src) {
- tgt_chunks[i].ChangeDeflateChunkToNormal();
- src->ChangeDeflateChunkToNormal();
- }
- }
- }
-
- // Merging neighboring normal chunks.
- if (zip_mode) {
- // For zips, we only need to do this to the target: deflated
- // chunks are matched via filename, and normal chunks are patched
- // using the entire source file as the source.
- MergeAdjacentNormalChunks(&tgt_chunks);
-
- } else {
- // For images, we need to maintain the parallel structure of the
- // chunk lists, so do the merging in both the source and target
- // lists.
- MergeAdjacentNormalChunks(&tgt_chunks);
- MergeAdjacentNormalChunks(&src_chunks);
- if (src_chunks.size() != tgt_chunks.size()) {
- // This shouldn't happen.
- printf("merging normal chunks went awry\n");
+ if (!bonus_data.empty() && !src_image.SetBonusData(bonus_data)) {
return 1;
}
- }
- // Compute bsdiff patches for each chunk's data (the uncompressed
- // data, in the case of deflate chunks).
-
- DumpChunks(src_chunks);
-
- printf("Construct patches for %zu chunks...\n", tgt_chunks.size());
- std::vector<std::vector<uint8_t>> patch_data(tgt_chunks.size());
- saidx_t* bsdiff_cache = nullptr;
- for (size_t i = 0; i < tgt_chunks.size(); ++i) {
- if (zip_mode) {
- ImageChunk* src;
- if (tgt_chunks[i].GetType() == CHUNK_DEFLATE &&
- (src = FindChunkByName(tgt_chunks[i].GetEntryName(), src_chunks))) {
- if (!MakePatch(src, &tgt_chunks[i], &patch_data[i], nullptr)) {
- printf("Failed to generate patch for target chunk %zu: ", i);
- return 1;
- }
- } else {
- if (!MakePatch(&src_chunks[0], &tgt_chunks[i], &patch_data[i], &bsdiff_cache)) {
- printf("Failed to generate patch for target chunk %zu: ", i);
- return 1;
- }
- }
- } else {
- if (i == 1 && !bonus_data.empty()) {
- printf(" using %zu bytes of bonus data for chunk %zu\n", bonus_data.size(), i);
- src_chunks[i].SetBonusData(bonus_data);
- }
-
- if (!MakePatch(&src_chunks[i], &tgt_chunks[i], &patch_data[i], nullptr)) {
- printf("Failed to generate patch for target chunk %zu: ", i);
- return 1;
- }
- }
- printf("patch %3zu is %zu bytes (of %zu)\n", i, patch_data[i].size(),
- src_chunks[i].GetRawDataLength());
- }
-
- if (bsdiff_cache != nullptr) {
- free(bsdiff_cache);
- }
-
- // Figure out how big the imgdiff file header is going to be, so
- // that we can correctly compute the offset of each bsdiff patch
- // within the file.
-
- size_t total_header_size = 12;
- for (size_t i = 0; i < tgt_chunks.size(); ++i) {
- total_header_size += tgt_chunks[i].GetHeaderSize(patch_data[i].size());
- }
-
- size_t offset = total_header_size;
-
- android::base::unique_fd patch_fd(open(argv[3], O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR));
- if (patch_fd == -1) {
- printf("failed to open \"%s\": %s\n", argv[3], strerror(errno));
- return 1;
- }
-
- // Write out the headers.
- if (!android::base::WriteStringToFd("IMGDIFF2", patch_fd)) {
- printf("failed to write \"IMGDIFF2\" to \"%s\": %s\n", argv[3], strerror(errno));
- return 1;
- }
- Write4(patch_fd, static_cast<int32_t>(tgt_chunks.size()));
- for (size_t i = 0; i < tgt_chunks.size(); ++i) {
- printf("chunk %zu: ", i);
- offset = tgt_chunks[i].WriteHeaderToFd(patch_fd, patch_data[i], offset);
- }
-
- // Append each chunk's bsdiff patch, in order.
- for (size_t i = 0; i < tgt_chunks.size(); ++i) {
- if (tgt_chunks[i].GetType() != CHUNK_RAW) {
- if (!android::base::WriteFully(patch_fd, patch_data[i].data(), patch_data[i].size())) {
- CHECK(false) << "failed to write " << patch_data[i].size() << " bytes patch for chunk "
- << i;
- }
+ if (!ImageModeImage::GeneratePatches(tgt_image, src_image, argv[optind + 2])) {
+ return 1;
}
}
diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp
index df75f98..3682d61 100644
--- a/applypatch/imgpatch.cpp
+++ b/applypatch/imgpatch.cpp
@@ -37,6 +37,8 @@
#include <openssl/sha.h>
#include <zlib.h>
+#include "edify/expr.h"
+
static inline int64_t Read8(const void *address) {
return android::base::get_unaligned<int64_t>(address);
}
@@ -48,7 +50,7 @@
// This function is a wrapper of ApplyBSDiffPatch(). It has a custom sink function to deflate the
// patched data and stream the deflated data to output.
static bool ApplyBSDiffPatchAndStreamOutput(const uint8_t* src_data, size_t src_len,
- const Value* patch, size_t patch_offset,
+ const Value& patch, size_t patch_offset,
const char* deflate_header, SinkFn sink, SHA_CTX* ctx) {
size_t expected_target_length = static_cast<size_t>(Read8(deflate_header + 32));
int level = Read4(deflate_header + 40);
@@ -57,13 +59,13 @@
int mem_level = Read4(deflate_header + 52);
int strategy = Read4(deflate_header + 56);
- std::unique_ptr<z_stream, decltype(&deflateEnd)> strm(new z_stream(), deflateEnd);
- strm->zalloc = Z_NULL;
- strm->zfree = Z_NULL;
- strm->opaque = Z_NULL;
- strm->avail_in = 0;
- strm->next_in = nullptr;
- int ret = deflateInit2(strm.get(), level, method, window_bits, mem_level, strategy);
+ z_stream strm;
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = 0;
+ strm.next_in = nullptr;
+ int ret = deflateInit2(&strm, level, method, window_bits, mem_level, strategy);
if (ret != Z_OK) {
LOG(ERROR) << "Failed to init uncompressed data deflation: " << ret;
return false;
@@ -74,18 +76,19 @@
size_t actual_target_length = 0;
size_t total_written = 0;
static constexpr size_t buffer_size = 32768;
- auto compression_sink = [&](const uint8_t* data, size_t len) -> size_t {
+ auto compression_sink = [&strm, &actual_target_length, &expected_target_length, &total_written,
+ &ret, &ctx, &sink](const uint8_t* data, size_t len) -> size_t {
// The input patch length for an update never exceeds INT_MAX.
- strm->avail_in = len;
- strm->next_in = data;
+ strm.avail_in = len;
+ strm.next_in = data;
do {
std::vector<uint8_t> buffer(buffer_size);
- strm->avail_out = buffer_size;
- strm->next_out = buffer.data();
+ strm.avail_out = buffer_size;
+ strm.next_out = buffer.data();
if (actual_target_length + len < expected_target_length) {
- ret = deflate(strm.get(), Z_NO_FLUSH);
+ ret = deflate(&strm, Z_NO_FLUSH);
} else {
- ret = deflate(strm.get(), Z_FINISH);
+ ret = deflate(&strm, Z_FINISH);
}
if (ret != Z_OK && ret != Z_STREAM_END) {
LOG(ERROR) << "Failed to deflate stream: " << ret;
@@ -93,20 +96,24 @@
return 0;
}
- size_t have = buffer_size - strm->avail_out;
+ size_t have = buffer_size - strm.avail_out;
total_written += have;
if (sink(buffer.data(), have) != have) {
LOG(ERROR) << "Failed to write " << have << " compressed bytes to output.";
return 0;
}
if (ctx) SHA1_Update(ctx, buffer.data(), have);
- } while ((strm->avail_in != 0 || strm->avail_out == 0) && ret != Z_STREAM_END);
+ } while ((strm.avail_in != 0 || strm.avail_out == 0) && ret != Z_STREAM_END);
actual_target_length += len;
return len;
};
- if (ApplyBSDiffPatch(src_data, src_len, patch, patch_offset, compression_sink, nullptr) != 0) {
+ int bspatch_result =
+ ApplyBSDiffPatch(src_data, src_len, patch, patch_offset, compression_sink, nullptr);
+ deflateEnd(&strm);
+
+ if (bspatch_result != 0) {
return false;
}
@@ -128,48 +135,39 @@
int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const unsigned char* patch_data,
size_t patch_size, SinkFn sink) {
Value patch(VAL_BLOB, std::string(reinterpret_cast<const char*>(patch_data), patch_size));
-
- return ApplyImagePatch(old_data, old_size, &patch, sink, nullptr, nullptr);
+ return ApplyImagePatch(old_data, old_size, patch, sink, nullptr, nullptr);
}
-/*
- * Apply the patch given in 'patch_filename' to the source data given
- * by (old_data, old_size). Write the patched output to the 'output'
- * file, and update the SHA context with the output data as well.
- * Return 0 on success.
- */
-int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const Value* patch, SinkFn sink,
+int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const Value& patch, SinkFn sink,
SHA_CTX* ctx, const Value* bonus_data) {
- if (patch->data.size() < 12) {
+ if (patch.data.size() < 12) {
printf("patch too short to contain header\n");
return -1;
}
- // IMGDIFF2 uses CHUNK_NORMAL, CHUNK_DEFLATE, and CHUNK_RAW.
- // (IMGDIFF1, which is no longer supported, used CHUNK_NORMAL and
- // CHUNK_GZIP.)
- size_t pos = 12;
- const char* header = &patch->data[0];
- if (memcmp(header, "IMGDIFF2", 8) != 0) {
+ // IMGDIFF2 uses CHUNK_NORMAL, CHUNK_DEFLATE, and CHUNK_RAW. (IMGDIFF1, which is no longer
+ // supported, used CHUNK_NORMAL and CHUNK_GZIP.)
+ const char* const patch_header = patch.data.data();
+ if (memcmp(patch_header, "IMGDIFF2", 8) != 0) {
printf("corrupt patch file header (magic number)\n");
return -1;
}
- int num_chunks = Read4(header + 8);
-
+ int num_chunks = Read4(patch_header + 8);
+ size_t pos = 12;
for (int i = 0; i < num_chunks; ++i) {
// each chunk's header record starts with 4 bytes.
- if (pos + 4 > patch->data.size()) {
+ if (pos + 4 > patch.data.size()) {
printf("failed to read chunk %d record\n", i);
return -1;
}
- int type = Read4(&patch->data[pos]);
+ int type = Read4(patch_header + pos);
pos += 4;
if (type == CHUNK_NORMAL) {
- const char* normal_header = &patch->data[pos];
+ const char* normal_header = patch_header + pos;
pos += 24;
- if (pos > patch->data.size()) {
+ if (pos > patch.data.size()) {
printf("failed to read chunk %d normal header data\n", i);
return -1;
}
@@ -187,30 +185,32 @@
return -1;
}
} else if (type == CHUNK_RAW) {
- const char* raw_header = &patch->data[pos];
+ const char* raw_header = patch_header + pos;
pos += 4;
- if (pos > patch->data.size()) {
+ if (pos > patch.data.size()) {
printf("failed to read chunk %d raw header data\n", i);
return -1;
}
size_t data_len = static_cast<size_t>(Read4(raw_header));
- if (pos + data_len > patch->data.size()) {
+ if (pos + data_len > patch.data.size()) {
printf("failed to read chunk %d raw data\n", i);
return -1;
}
- if (ctx) SHA1_Update(ctx, &patch->data[pos], data_len);
- if (sink(reinterpret_cast<const unsigned char*>(&patch->data[pos]), data_len) != data_len) {
+ if (ctx) {
+ SHA1_Update(ctx, patch_header + pos, data_len);
+ }
+ if (sink(reinterpret_cast<const unsigned char*>(patch_header + pos), data_len) != data_len) {
printf("failed to write chunk %d raw data\n", i);
return -1;
}
pos += data_len;
} else if (type == CHUNK_DEFLATE) {
// deflate chunks have an additional 60 bytes in their chunk header.
- const char* deflate_header = &patch->data[pos];
+ const char* deflate_header = patch_header + pos;
pos += 60;
- if (pos > patch->data.size()) {
+ if (pos > patch.data.size()) {
printf("failed to read chunk %d deflate header data\n", i);
return -1;
}
diff --git a/applypatch/include/applypatch/applypatch.h b/applypatch/include/applypatch/applypatch.h
index 581360e..912ead1 100644
--- a/applypatch/include/applypatch/applypatch.h
+++ b/applypatch/include/applypatch/applypatch.h
@@ -18,7 +18,6 @@
#define _APPLYPATCH_H
#include <stdint.h>
-#include <sys/stat.h>
#include <functional>
#include <memory>
@@ -27,24 +26,18 @@
#include <openssl/sha.h>
-#include "edify/expr.h"
+// Forward declaration to avoid including "edify/expr.h" in the header.
+struct Value;
struct FileContents {
uint8_t sha1[SHA_DIGEST_LENGTH];
std::vector<unsigned char> data;
- struct stat st;
};
-// When there isn't enough room on the target filesystem to hold the
-// patched version of the file, we copy the original here and delete
-// it to free up space. If the expected source file doesn't exist, or
-// is corrupted, we look to see if this file contains the bits we want
-// and use it as the source instead.
-#define CACHE_TEMP_SOURCE "/cache/saved.file"
-
using SinkFn = std::function<size_t(const unsigned char*, size_t)>;
// applypatch.cpp
+
int ShowLicenses();
size_t FreeSpaceForFile(const char* filename);
int CacheSizeCheck(size_t bytes);
@@ -66,15 +59,25 @@
int SaveFileContents(const char* filename, const FileContents* file);
// bspatch.cpp
+
void ShowBSDiffLicense();
-int ApplyBSDiffPatch(const unsigned char* old_data, size_t old_size, const Value* patch,
+
+// Applies the bsdiff-patch given in 'patch' (from offset 'patch_offset' to the end) to the source
+// data given by (old_data, old_size). Writes the patched output through the given 'sink', and
+// updates the SHA-1 context with the output data. Returns 0 on success.
+int ApplyBSDiffPatch(const unsigned char* old_data, size_t old_size, const Value& patch,
size_t patch_offset, SinkFn sink, SHA_CTX* ctx);
// imgpatch.cpp
-int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const Value* patch, SinkFn sink,
+
+// Applies the imgdiff-patch given in 'patch' to the source data given by (old_data, old_size), with
+// the optional bonus data. Writes the patched output through the given 'sink', and updates the
+// SHA-1 context with the output data. Returns 0 on success.
+int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const Value& patch, SinkFn sink,
SHA_CTX* ctx, const Value* bonus_data);
// freecache.cpp
+
int MakeFreeSpaceOnCache(size_t bytes_needed);
#endif
diff --git a/applypatch/include/applypatch/imgdiff_image.h b/applypatch/include/applypatch/imgdiff_image.h
new file mode 100644
index 0000000..0848072
--- /dev/null
+++ b/applypatch/include/applypatch/imgdiff_image.h
@@ -0,0 +1,306 @@
+/*
+ * 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.
+ */
+
+#ifndef _APPLYPATCH_IMGDIFF_IMAGE_H
+#define _APPLYPATCH_IMGDIFF_IMAGE_H
+
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <string>
+#include <vector>
+
+#include <bsdiff/bsdiff.h>
+#include <ziparchive/zip_archive.h>
+#include <zlib.h>
+
+#include "imgdiff.h"
+#include "otautil/rangeset.h"
+
+class ImageChunk {
+ public:
+ static constexpr auto WINDOWBITS = -15; // 32kb window; negative to indicate a raw stream.
+ static constexpr auto MEMLEVEL = 8; // the default value.
+ static constexpr auto METHOD = Z_DEFLATED;
+ static constexpr auto STRATEGY = Z_DEFAULT_STRATEGY;
+
+ ImageChunk(int type, size_t start, const std::vector<uint8_t>* file_content, size_t raw_data_len,
+ std::string entry_name = {});
+
+ int GetType() const {
+ return type_;
+ }
+ size_t GetRawDataLength() const {
+ return raw_data_len_;
+ }
+ const std::string& GetEntryName() const {
+ return entry_name_;
+ }
+ size_t GetStartOffset() const {
+ return start_;
+ }
+ int GetCompressLevel() const {
+ return compress_level_;
+ }
+
+ // CHUNK_DEFLATE will return the uncompressed data for diff, while other types will simply return
+ // the raw data.
+ const uint8_t* DataForPatch() const;
+ size_t DataLengthForPatch() const;
+
+ void Dump(size_t index) const;
+
+ void SetUncompressedData(std::vector<uint8_t> data);
+ bool SetBonusData(const std::vector<uint8_t>& bonus_data);
+
+ bool operator==(const ImageChunk& other) const;
+ bool operator!=(const ImageChunk& other) const {
+ return !(*this == other);
+ }
+
+ /*
+ * Cause a gzip chunk to be treated as a normal chunk (ie, as a blob of uninterpreted data).
+ * The resulting patch will likely be about as big as the target file, but it lets us handle
+ * the case of images where some gzip chunks are reconstructible but others aren't (by treating
+ * the ones that aren't as normal chunks).
+ */
+ void ChangeDeflateChunkToNormal();
+
+ /*
+ * Verify that we can reproduce exactly the same compressed data that we started with. Sets the
+ * level, method, windowBits, memLevel, and strategy fields in the chunk to the encoding
+ * parameters needed to produce the right output.
+ */
+ bool ReconstructDeflateChunk();
+ bool IsAdjacentNormal(const ImageChunk& other) const;
+ void MergeAdjacentNormal(const ImageChunk& other);
+
+ /*
+ * Compute a bsdiff patch between |src| and |tgt|; Store the result in the patch_data.
+ * |bsdiff_cache| can be used to cache the suffix array if the same |src| chunk is used
+ * repeatedly, pass nullptr if not needed.
+ */
+ static bool MakePatch(const ImageChunk& tgt, const ImageChunk& src,
+ std::vector<uint8_t>* patch_data,
+ bsdiff::SuffixArrayIndexInterface** bsdiff_cache);
+
+ private:
+ const uint8_t* GetRawData() const;
+ bool TryReconstruction(int level);
+
+ int type_; // CHUNK_NORMAL, CHUNK_DEFLATE, CHUNK_RAW
+ size_t start_; // offset of chunk in the original input file
+ const std::vector<uint8_t>* input_file_ptr_; // ptr to the full content of original input file
+ size_t raw_data_len_;
+
+ // deflate encoder parameters
+ int compress_level_;
+
+ // --- for CHUNK_DEFLATE chunks only: ---
+ std::vector<uint8_t> uncompressed_data_;
+ std::string entry_name_; // used for zip entries
+};
+
+// PatchChunk stores the patch data between a source chunk and a target chunk. It also keeps track
+// of the metadata of src&tgt chunks (e.g. offset, raw data length, uncompressed data length).
+class PatchChunk {
+ public:
+ PatchChunk(const ImageChunk& tgt, const ImageChunk& src, std::vector<uint8_t> data);
+
+ // Construct a CHUNK_RAW patch from the target data directly.
+ explicit PatchChunk(const ImageChunk& tgt);
+
+ // Return true if raw data size is smaller than the patch size.
+ static bool RawDataIsSmaller(const ImageChunk& tgt, size_t patch_size);
+
+ // Update the source start with the new offset within the source range.
+ void UpdateSourceOffset(const SortedRangeSet& src_range);
+
+ // Return the total size (header + data) of the patch.
+ size_t PatchSize() const;
+
+ static bool WritePatchDataToFd(const std::vector<PatchChunk>& patch_chunks, int patch_fd);
+
+ private:
+ size_t GetHeaderSize() const;
+ size_t WriteHeaderToFd(int fd, size_t offset, size_t index) const;
+
+ // The patch chunk type is the same as the target chunk type. The only exception is we change
+ // the |type_| to CHUNK_RAW if target length is smaller than the patch size.
+ int type_;
+
+ size_t source_start_;
+ size_t source_len_;
+ size_t source_uncompressed_len_;
+
+ size_t target_start_; // offset of the target chunk within the target file
+ size_t target_len_;
+ size_t target_uncompressed_len_;
+ size_t target_compress_level_; // the deflate compression level of the target chunk.
+
+ std::vector<uint8_t> data_; // storage for the patch data
+};
+
+// Interface for zip_mode and image_mode images. We initialize the image from an input file and
+// split the file content into a list of image chunks.
+class Image {
+ public:
+ explicit Image(bool is_source) : is_source_(is_source) {}
+
+ virtual ~Image() {}
+
+ // Create a list of image chunks from input file.
+ virtual bool Initialize(const std::string& filename) = 0;
+
+ // Look for runs of adjacent normal chunks and compress them down into a single chunk. (Such
+ // runs can be produced when deflate chunks are changed to normal chunks.)
+ void MergeAdjacentNormalChunks();
+
+ void DumpChunks() const;
+
+ // Non const iterators to access the stored ImageChunks.
+ std::vector<ImageChunk>::iterator begin() {
+ return chunks_.begin();
+ }
+
+ std::vector<ImageChunk>::iterator end() {
+ return chunks_.end();
+ }
+
+ std::vector<ImageChunk>::const_iterator cbegin() const {
+ return chunks_.cbegin();
+ }
+
+ std::vector<ImageChunk>::const_iterator cend() const {
+ return chunks_.cend();
+ }
+
+ ImageChunk& operator[](size_t i);
+ const ImageChunk& operator[](size_t i) const;
+
+ size_t NumOfChunks() const {
+ return chunks_.size();
+ }
+
+ protected:
+ bool ReadFile(const std::string& filename, std::vector<uint8_t>* file_content);
+
+ bool is_source_; // True if it's for source chunks.
+ std::vector<ImageChunk> chunks_; // Internal storage of ImageChunk.
+ std::vector<uint8_t> file_content_; // Store the whole input file in memory.
+};
+
+class ZipModeImage : public Image {
+ public:
+ explicit ZipModeImage(bool is_source, size_t limit = 0) : Image(is_source), limit_(limit) {}
+
+ bool Initialize(const std::string& filename) override;
+
+ // Initialize a dummy ZipModeImage from an existing ImageChunk vector. For src img pieces, we
+ // reconstruct a new file_content based on the source ranges; but it's not needed for the tgt img
+ // pieces; because for each chunk both the data and their offset within the file are unchanged.
+ void Initialize(const std::vector<ImageChunk>& chunks, const std::vector<uint8_t>& file_content) {
+ chunks_ = chunks;
+ file_content_ = file_content;
+ }
+
+ // The pesudo source chunk for bsdiff if there's no match for the given target chunk. It's in
+ // fact the whole source file.
+ ImageChunk PseudoSource() const;
+
+ // Find the matching deflate source chunk by entry name. Search for normal chunks also if
+ // |find_normal| is true.
+ ImageChunk* FindChunkByName(const std::string& name, bool find_normal = false);
+
+ const ImageChunk* FindChunkByName(const std::string& name, bool find_normal = false) const;
+
+ // Verify that we can reconstruct the deflate chunks; also change the type to CHUNK_NORMAL if
+ // src and tgt are identical.
+ static bool CheckAndProcessChunks(ZipModeImage* tgt_image, ZipModeImage* src_image);
+
+ // Compute the patch between tgt & src images, and write the data into |patch_name|.
+ static bool GeneratePatches(const ZipModeImage& tgt_image, const ZipModeImage& src_image,
+ const std::string& patch_name);
+
+ // Compute the patch based on the lists of split src and tgt images. Generate patches for each
+ // pair of split pieces and write the data to |patch_name|. If |debug_dir| is specified, write
+ // each split src data and patch data into that directory.
+ static bool GeneratePatches(const std::vector<ZipModeImage>& split_tgt_images,
+ const std::vector<ZipModeImage>& split_src_images,
+ const std::vector<SortedRangeSet>& split_src_ranges,
+ const std::string& patch_name, const std::string& split_info_file,
+ const std::string& debug_dir);
+
+ // Split the tgt chunks and src chunks based on the size limit.
+ static bool SplitZipModeImageWithLimit(const ZipModeImage& tgt_image,
+ const ZipModeImage& src_image,
+ std::vector<ZipModeImage>* split_tgt_images,
+ std::vector<ZipModeImage>* split_src_images,
+ std::vector<SortedRangeSet>* split_src_ranges);
+
+ private:
+ // Initialize image chunks based on the zip entries.
+ bool InitializeChunks(const std::string& filename, ZipArchiveHandle handle);
+ // Add the a zip entry to the list.
+ bool AddZipEntryToChunks(ZipArchiveHandle handle, const std::string& entry_name, ZipEntry* entry);
+ // Return the real size of the zip file. (omit the trailing zeros that used for alignment)
+ bool GetZipFileSize(size_t* input_file_size);
+
+ static void ValidateSplitImages(const std::vector<ZipModeImage>& split_tgt_images,
+ const std::vector<ZipModeImage>& split_src_images,
+ std::vector<SortedRangeSet>& split_src_ranges,
+ size_t total_tgt_size);
+ // Construct the dummy split images based on the chunks info and source ranges; and move them into
+ // the given vectors. Return true if we add a new split image into |split_tgt_images|, and
+ // false otherwise.
+ static bool AddSplitImageFromChunkList(const ZipModeImage& tgt_image,
+ const ZipModeImage& src_image,
+ const SortedRangeSet& split_src_ranges,
+ const std::vector<ImageChunk>& split_tgt_chunks,
+ const std::vector<ImageChunk>& split_src_chunks,
+ std::vector<ZipModeImage>* split_tgt_images,
+ std::vector<ZipModeImage>* split_src_images);
+
+ // Function that actually iterates the tgt_chunks and makes patches.
+ static bool GeneratePatchesInternal(const ZipModeImage& tgt_image, const ZipModeImage& src_image,
+ std::vector<PatchChunk>* patch_chunks);
+
+ // size limit in bytes of each chunk. Also, if the length of one zip_entry exceeds the limit,
+ // we'll split that entry into several smaller chunks in advance.
+ size_t limit_;
+};
+
+class ImageModeImage : public Image {
+ public:
+ explicit ImageModeImage(bool is_source) : Image(is_source) {}
+
+ // Initialize the image chunks list by searching the magic numbers in an image file.
+ bool Initialize(const std::string& filename) override;
+
+ bool SetBonusData(const std::vector<uint8_t>& bonus_data);
+
+ // In Image Mode, verify that the source and target images have the same chunk structure (ie, the
+ // same sequence of deflate and normal chunks).
+ static bool CheckAndProcessChunks(ImageModeImage* tgt_image, ImageModeImage* src_image);
+
+ // In image mode, generate patches against the given source chunks and bonus_data; write the
+ // result to |patch_name|.
+ static bool GeneratePatches(const ImageModeImage& tgt_image, const ImageModeImage& src_image,
+ const std::string& patch_name);
+};
+
+#endif // _APPLYPATCH_IMGDIFF_IMAGE_H
diff --git a/applypatch/libimgpatch.pc b/applypatch/libimgpatch.pc
deleted file mode 100644
index e500293..0000000
--- a/applypatch/libimgpatch.pc
+++ /dev/null
@@ -1,6 +0,0 @@
-# This file is for libimgpatch in Chrome OS.
-
-Name: libimgpatch
-Description: Apply imgdiff patch
-Version: 0.0.1
-Libs: -limgpatch -lbz2 -lz
diff --git a/bmlutils/bmlutils.c b/bmlutils/bmlutils.c
index 7875f6f..b5da078 100644
--- a/bmlutils/bmlutils.c
+++ b/bmlutils/bmlutils.c
@@ -27,7 +27,7 @@
static int restore_internal(const char* bml, const char* filename)
{
char buf[4096];
- int dstfd, srcfd, bytes_read, bytes_written, total_read = 0;
+ int dstfd, srcfd, bytes_read, total_read = 0;
if (filename == NULL)
srcfd = 0;
else {
@@ -82,7 +82,7 @@
int cmd_bml_backup_raw_partition(const char *partition, const char *out_file)
{
- char* bml;
+ const char* bml;
if (strcmp("boot", partition) == 0)
bml = BOARD_BML_BOOT;
else if (strcmp("recovery", partition) == 0)
@@ -99,12 +99,11 @@
int ch;
FILE *in;
FILE *out;
- int val = 0;
char buf[512];
unsigned sz = 0;
unsigned i;
int ret = -1;
- char *in_file = bml;
+ const char *in_file = bml;
in = fopen ( in_file, "r" );
if (in == NULL)
@@ -144,23 +143,23 @@
return ret;
}
-int cmd_bml_erase_raw_partition(const char *partition)
+int cmd_bml_erase_raw_partition(const char *partition __unused)
{
// TODO: implement raw wipe
return 0;
}
-int cmd_bml_erase_partition(const char *partition, const char *filesystem)
+int cmd_bml_erase_partition(const char *partition __unused, const char *filesystem __unused)
{
return -1;
}
-int cmd_bml_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only)
+int cmd_bml_mount_partition(const char *partition __unused, const char *mount_point __unused, const char *filesystem __unused, int read_only __unused)
{
return -1;
}
-int cmd_bml_get_partition_device(const char *partition, char *device)
+int cmd_bml_get_partition_device(const char *partition __unused, char *device __unused)
{
return -1;
}
diff --git a/boot_control/Android.mk b/boot_control/Android.mk
index 27e3d97..9814d71 100644
--- a/boot_control/Android.mk
+++ b/boot_control/Android.mk
@@ -24,8 +24,7 @@
-D_FILE_OFFSET_BITS=64 \
-Werror \
-Wall \
- -Wextra \
- -Wno-unused-parameter
+ -Wextra
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_STATIC_LIBRARIES := libbootloader_message libfs_mgr libbase
LOCAL_POST_INSTALL_CMD := \
diff --git a/bootloader_message/Android.NObp b/bootloader_message/Android.bp
similarity index 93%
rename from bootloader_message/Android.NObp
rename to bootloader_message/Android.bp
index f0d76e7..c81c67b 100644
--- a/bootloader_message/Android.NObp
+++ b/bootloader_message/Android.bp
@@ -17,7 +17,10 @@
cc_library_static {
name: "libbootloader_message",
srcs: ["bootloader_message.cpp"],
- cppflags: ["-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
static_libs: [
"libbase",
"libfs_mgr",
diff --git a/bootloader_message/bootloader_message.cpp b/bootloader_message/bootloader_message.cpp
index 6c237e6..72ec8bc 100644
--- a/bootloader_message/bootloader_message.cpp
+++ b/bootloader_message/bootloader_message.cpp
@@ -186,14 +186,8 @@
bool write_bootloader_message(const std::vector<std::string>& options, std::string* err) {
bootloader_message boot = {};
- strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
- strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
- for (const auto& s : options) {
- strlcat(boot.recovery, s.c_str(), sizeof(boot.recovery));
- if (s.back() != '\n') {
- strlcat(boot.recovery, "\n", sizeof(boot.recovery));
- }
- }
+ update_bootloader_message_in_struct(&boot, options);
+
return write_bootloader_message(boot, err);
}
@@ -202,20 +196,27 @@
if (!read_bootloader_message(&boot, err)) {
return false;
}
+ update_bootloader_message_in_struct(&boot, options);
- // Zero out the entire fields.
- memset(boot.command, 0, sizeof(boot.command));
- memset(boot.recovery, 0, sizeof(boot.recovery));
+ return write_bootloader_message(boot, err);
+}
- strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
- strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
+bool update_bootloader_message_in_struct(bootloader_message* boot,
+ const std::vector<std::string>& options) {
+ if (!boot) return false;
+ // Replace the command & recovery fields.
+ memset(boot->command, 0, sizeof(boot->command));
+ memset(boot->recovery, 0, sizeof(boot->recovery));
+
+ strlcpy(boot->command, "boot-recovery", sizeof(boot->command));
+ strlcpy(boot->recovery, "recovery\n", sizeof(boot->recovery));
for (const auto& s : options) {
- strlcat(boot.recovery, s.c_str(), sizeof(boot.recovery));
+ strlcat(boot->recovery, s.c_str(), sizeof(boot->recovery));
if (s.back() != '\n') {
- strlcat(boot.recovery, "\n", sizeof(boot.recovery));
+ strlcat(boot->recovery, "\n", sizeof(boot->recovery));
}
}
- return write_bootloader_message(boot, err);
+ return true;
}
bool write_reboot_bootloader(std::string* err) {
diff --git a/bootloader_message/include/bootloader_message/bootloader_message.h b/bootloader_message/include/bootloader_message/bootloader_message.h
index 4da1171..29f5601 100644
--- a/bootloader_message/include/bootloader_message/bootloader_message.h
+++ b/bootloader_message/include/bootloader_message/bootloader_message.h
@@ -114,13 +114,17 @@
* implementations are free to use all 32 bytes and may store private
* data past the first NUL-byte in this field. It is encouraged, but
* not mandatory, to use 'struct bootloader_control' described below.
+ *
+ * The update_channel field is used to store the Omaha update channel
+ * if update_engine is compiled with Omaha support.
*/
struct bootloader_message_ab {
struct bootloader_message message;
char slot_suffix[32];
+ char update_channel[128];
// Round up the entire struct to 4096-byte.
- char reserved[2016];
+ char reserved[1888];
};
/**
@@ -218,6 +222,11 @@
// only update the command and recovery fields.
bool update_bootloader_message(const std::vector<std::string>& options, std::string* err);
+// Update bootloader message (boots into recovery with the |options|) in |boot|. Will only update
+// the command and recovery fields.
+bool update_bootloader_message_in_struct(bootloader_message* boot,
+ const std::vector<std::string>& options);
+
// Clear BCB.
bool clear_bootloader_message(std::string* err);
diff --git a/common.h b/common.h
index b0901f4..e9585c1 100644
--- a/common.h
+++ b/common.h
@@ -40,6 +40,10 @@
#define STRINGIFY(x) #x
#define EXPAND(x) STRINGIFY(x)
+// Not using the command-line defined macro here because this header could be included by
+// device-specific recovery libraries. We static assert the value consistency in recovery.cpp.
+//static constexpr int kRecoveryApiVersion = 3;
+
class RecoveryUI;
extern RecoveryUI* ui;
@@ -57,7 +61,7 @@
void ui_print(const char* format, ...);
-static bool is_ro_debuggable();
+//static bool is_ro_debuggable();
#ifdef __cplusplus
}
diff --git a/crypto/ext4crypt/Android.mk b/crypto/ext4crypt/Android.mk
index 693b675..4aba9ef 100644
--- a/crypto/ext4crypt/Android.mk
+++ b/crypto/ext4crypt/Android.mk
@@ -6,7 +6,7 @@
LOCAL_MODULE_TAGS := eng optional
LOCAL_CFLAGS :=
LOCAL_SRC_FILES := Decrypt.cpp Ext4Crypt.cpp ScryptParameters.cpp Utils.cpp HashPassword.cpp ext4_crypt.cpp
-LOCAL_SHARED_LIBRARIES := libselinux libc libc++ libext4_utils libsoftkeymaster libbase libcrypto libcutils libkeymaster_messages libhardware libprotobuf-cpp-lite
+LOCAL_SHARED_LIBRARIES := libselinux libc libc++ libext4_utils libbase libcrypto libcutils libkeymaster_messages libhardware libprotobuf-cpp-lite
LOCAL_STATIC_LIBRARIES := libscrypt_static
LOCAL_C_INCLUDES := system/extras/ext4_utils system/extras/ext4_utils/include/ext4_utils external/scrypt/lib/crypto system/security/keystore hardware/libhardware/include/hardware system/security/softkeymaster/include/keymaster system/keymaster/include
@@ -28,10 +28,13 @@
LOCAL_CFLAGS += -DHAVE_LIBKEYUTILS
LOCAL_SHARED_LIBRARIES += libkeyutils
endif
- LOCAL_ADDITIONAL_DEPENDENCIES := keystore_auth
+ LOCAL_REQUIRED_MODULES := keystore_auth
else
LOCAL_SRC_FILES += Keymaster.cpp KeyStorage.cpp
endif
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 28; echo $$?),0)
+ LOCAL_SHARED_LIBRARIES += libsoftkeymaster
+endif
include $(BUILD_SHARED_LIBRARY)
diff --git a/crypto/ext4crypt/Ext4Crypt.cpp b/crypto/ext4crypt/Ext4Crypt.cpp
index ea5b1cf..048a0bd 100644
--- a/crypto/ext4crypt/Ext4Crypt.cpp
+++ b/crypto/ext4crypt/Ext4Crypt.cpp
@@ -312,7 +312,7 @@
return true;
}
-static bool ensure_policy(const std::string& raw_ref, const std::string& path) {
+static bool ensure_policy(const std::string& raw_ref __unused, const std::string& path) {
LOG(INFO) << "ensure_policy '" << path << "'\n";
return true;
return access(path.c_str(), F_OK) == 0; // ensure policy will set a policy if one is not set on an empty folder - we don't want to do this in recovery
@@ -438,7 +438,7 @@
}
// TODO: rename to 'install' for consistency, and take flags to know which keys to install
-bool e4crypt_unlock_user_key(userid_t user_id, int serial, const char* token_hex,
+bool e4crypt_unlock_user_key(userid_t user_id, int serial __unused, const char* token_hex,
const char* secret_hex) {
if (e4crypt_is_native()) {
if (s_ce_key_raw_refs.count(user_id) != 0) {
@@ -469,7 +469,7 @@
return true;
}
-bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int serial,
+bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int serial __unused,
int flags) {
if (flags & FLAG_STORAGE_DE) {
diff --git a/crypto/lollipop/Android.mk b/crypto/lollipop/Android.mk
index 6dc386a..1be4121 100644
--- a/crypto/lollipop/Android.mk
+++ b/crypto/lollipop/Android.mk
@@ -24,6 +24,8 @@
LOCAL_C_INCLUDES += external/boringssl/src/include
endif
+LOCAL_CFLAGS += -Wno-unused-function
+
LOCAL_WHOLE_STATIC_LIBRARIES += libscrypttwrp_static
include $(BUILD_SHARED_LIBRARY)
diff --git a/crypto/lollipop/cryptfs.c b/crypto/lollipop/cryptfs.c
index 80f433b..d3bf629 100644
--- a/crypto/lollipop/cryptfs.c
+++ b/crypto/lollipop/cryptfs.c
@@ -89,10 +89,7 @@
char *me = "cryptfs";
-static unsigned char saved_master_key[KEY_LEN_BYTES];
-static char *saved_mount_point;
static int master_key_saved = 0;
-static struct crypt_persist_data *persist_data = NULL;
static char key_fname[PROPERTY_VALUE_MAX] = "";
static char real_blkdev[PROPERTY_VALUE_MAX] = "";
static char file_system[PROPERTY_VALUE_MAX] = "";
@@ -629,24 +626,6 @@
}
#endif //#ifndef TW_CRYPTO_HAVE_KEYMASTERX
-/* Store password when userdata is successfully decrypted and mounted.
- * Cleared by cryptfs_clear_password
- *
- * To avoid a double prompt at boot, we need to store the CryptKeeper
- * password and pass it to KeyGuard, which uses it to unlock KeyStore.
- * Since the entire framework is torn down and rebuilt after encryption,
- * we have to use a daemon or similar to store the password. Since vold
- * is secured against IPC except from system processes, it seems a reasonable
- * place to store this.
- *
- * password should be cleared once it has been used.
- *
- * password is aged out after password_max_age_seconds seconds.
- */
-static char* password = 0;
-static int password_expiry_time = 0;
-static const int password_max_age_seconds = 60;
-
static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags)
{
memset(io, 0, dataSize);
@@ -774,7 +753,7 @@
static int get_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr)
{
int fd;
- unsigned int nr_sec, cnt;
+ unsigned int cnt;
off64_t starting_off;
int rc = -1;
char *fname = NULL;
@@ -979,8 +958,6 @@
char buffer[DM_CRYPT_BUF_SIZE];
struct dm_ioctl *io;
struct dm_target_versions *v;
- int flag;
- int i;
io = (struct dm_ioctl *) buffer;
@@ -996,6 +973,7 @@
v = (struct dm_target_versions *) &buffer[sizeof(struct dm_ioctl)];
while (v->next) {
#ifdef CONFIG_HW_DISK_ENCRYPTION
+ int flag;
if (is_hw_fde_enabled()) {
flag = (!strcmp(v->name, "crypt") || !strcmp(v->name, "req-crypt"));
} else {
@@ -1022,13 +1000,9 @@
const char *real_blk_name, char *crypto_blk_name, const char *name)
{
char buffer[DM_CRYPT_BUF_SIZE];
- char master_key_ascii[129]; /* Large enough to hold 512 bit key and null */
- char *crypt_params;
struct dm_ioctl *io;
- struct dm_target_spec *tgt;
unsigned int minor;
int fd=0;
- int i;
int retval = -1;
int version[3];
char *extra_params;
@@ -1223,7 +1197,7 @@
unsigned char* master_key = convert_hex_ascii_to_key(passwd, &key_size);
if (!master_key) {
printf("Failed to convert passwd from hex, using passwd instead\n");
- master_key = strdup(passwd);
+ master_key = (unsigned char*)strdup(passwd);
}
rc = crypto_scrypt(master_key, key_size, salt, SALT_LEN,
@@ -1365,10 +1339,6 @@
char crypto_blkdev[MAXPATHLEN];
char tmp_mount_point[64];
int rc = 0;
- kdf_func kdf;
- void *kdf_params;
- int use_keymaster = 0;
- int upgrade = 0;
unsigned char* intermediate_key = 0;
size_t intermediate_key_size = 0;
diff --git a/crypto/scrypt/lib/crypto/crypto_scrypt-neon.c b/crypto/scrypt/lib/crypto/crypto_scrypt-neon.c
index d05ee1b..158bf96 100644
--- a/crypto/scrypt/lib/crypto/crypto_scrypt-neon.c
+++ b/crypto/scrypt/lib/crypto/crypto_scrypt-neon.c
@@ -135,9 +135,7 @@
uint8x16_t * X = XY;
uint8x16_t * Y = (void *)((uintptr_t)(XY) + 128 * r);
uint8x16_t * Z = (void *)((uintptr_t)(XY) + 256 * r);
- uint32_t * X32 = (void *)X;
uint64_t i, j;
- size_t k;
/* 1: X <-- B */
blkcpy(X, B, 128 * r);
diff --git a/device.cpp b/device.cpp
index 6150186..f881daf 100644
--- a/device.cpp
+++ b/device.cpp
@@ -17,34 +17,36 @@
#include "device.h"
static const char* MENU_ITEMS[] = {
- "Reboot system now",
- "Reboot to bootloader",
- "Apply update from ADB",
- "Apply update from SD card",
- "Wipe data/factory reset",
+ "Reboot system now",
+ "Reboot to bootloader",
+ "Apply update from ADB",
+ "Apply update from SD card",
+ "Wipe data/factory reset",
#ifndef AB_OTA_UPDATER
- "Wipe cache partition",
+ "Wipe cache partition",
#endif // !AB_OTA_UPDATER
- "Mount /system",
- "View recovery logs",
- "Run graphics test",
- "Power off",
- NULL,
+ "Mount /system",
+ "View recovery logs",
+ "Run graphics test",
+ "Run locale test",
+ "Power off",
+ nullptr,
};
static const Device::BuiltinAction MENU_ACTIONS[] = {
- Device::REBOOT,
- Device::REBOOT_BOOTLOADER,
- Device::APPLY_ADB_SIDELOAD,
- Device::APPLY_SDCARD,
- Device::WIPE_DATA,
+ Device::REBOOT,
+ Device::REBOOT_BOOTLOADER,
+ Device::APPLY_ADB_SIDELOAD,
+ Device::APPLY_SDCARD,
+ Device::WIPE_DATA,
#ifndef AB_OTA_UPDATER
- Device::WIPE_CACHE,
+ Device::WIPE_CACHE,
#endif // !AB_OTA_UPDATER
- Device::MOUNT_SYSTEM,
- Device::VIEW_RECOVERY_LOGS,
- Device::RUN_GRAPHICS_TEST,
- Device::SHUTDOWN,
+ Device::MOUNT_SYSTEM,
+ Device::VIEW_RECOVERY_LOGS,
+ Device::RUN_GRAPHICS_TEST,
+ Device::RUN_LOCALE_TEST,
+ Device::SHUTDOWN,
};
static_assert(sizeof(MENU_ITEMS) / sizeof(MENU_ITEMS[0]) ==
diff --git a/device.h b/device.h
index 639e2bf..74745b3 100644
--- a/device.h
+++ b/device.h
@@ -66,6 +66,7 @@
VIEW_RECOVERY_LOGS = 9,
MOUNT_SYSTEM = 10,
RUN_GRAPHICS_TEST = 11,
+ RUN_LOCALE_TEST = 12,
};
// Return the list of menu items (an array of strings, NULL-terminated). The menu_position passed
diff --git a/dosfstools/Android.mk b/dosfstools/Android.mk
index b241a73..7b6d623 100644
--- a/dosfstools/Android.mk
+++ b/dosfstools/Android.mk
@@ -15,6 +15,7 @@
LOCAL_SHARED_LIBRARIES := libc
LOCAL_CFLAGS += -D_USING_BIONIC_
LOCAL_CFLAGS += -DUSE_ANDROID_RETVALS
+LOCAL_CFLAGS += -Wno-sign-compare
LOCAL_MODULE = fsck.fat
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
@@ -35,6 +36,7 @@
LOCAL_C_INCLUDES += bionic/libc/kernel/common
LOCAL_SHARED_LIBRARIES := libc
LOCAL_CFLAGS += -D_USING_BIONIC_
+LOCAL_CFLAGS += -Wno-sign-compare
LOCAL_MODULE = fatlabel
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
@@ -46,6 +48,7 @@
LOCAL_SHARED_LIBRARIES := libc
LOCAL_CFLAGS += -D_USING_BIONIC_
+LOCAL_CFLAGS += -Wno-sign-compare
LOCAL_MODULE = mkfs.fat
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
diff --git a/bootloader_message/Android.NObp b/edify/Android.bp
similarity index 63%
copy from bootloader_message/Android.NObp
copy to edify/Android.bp
index f0d76e7..42947eb 100644
--- a/bootloader_message/Android.NObp
+++ b/edify/Android.bp
@@ -1,4 +1,3 @@
-//
// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,15 +11,35 @@
// 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_library_static {
- name: "libbootloader_message",
- srcs: ["bootloader_message.cpp"],
- cppflags: ["-Werror"],
+ name: "libedify",
+
+ host_supported: true,
+
+ srcs: [
+ "expr.cpp",
+ "lexer.ll",
+ "parser.yy",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-deprecated-register",
+ "-Wno-unused-parameter",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+
static_libs: [
"libbase",
- "libfs_mgr",
+ "libotautil",
],
- export_include_dirs: ["include"],
}
diff --git a/edify/edify_parser.cpp b/edify/edify_parser.cpp
deleted file mode 100644
index f1b5628..0000000
--- a/edify/edify_parser.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2009 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 is a host-side tool for validating a given edify script file.
- *
- * We used to have edify test cases here, which have been moved to
- * tests/component/edify_test.cpp.
- *
- * Caveat: It doesn't recognize functions defined through updater, which
- * makes the tool less useful. We should either extend the tool or remove it.
- */
-
-#include <errno.h>
-#include <stdio.h>
-
-#include <memory>
-#include <string>
-
-#include <android-base/file.h>
-
-#include "expr.h"
-
-static void ExprDump(int depth, const std::unique_ptr<Expr>& n, const std::string& script) {
- printf("%*s", depth*2, "");
- printf("%s %p (%d-%d) \"%s\"\n",
- n->name.c_str(), n->fn, n->start, n->end,
- script.substr(n->start, n->end - n->start).c_str());
- for (size_t i = 0; i < n->argv.size(); ++i) {
- ExprDump(depth+1, n->argv[i], script);
- }
-}
-
-int main(int argc, char** argv) {
- RegisterBuiltins();
-
- if (argc != 2) {
- printf("Usage: %s <edify script>\n", argv[0]);
- return 1;
- }
-
- std::string buffer;
- if (!android::base::ReadFileToString(argv[1], &buffer)) {
- printf("%s: failed to read %s: %s\n", argv[0], argv[1], strerror(errno));
- return 1;
- }
-
- std::unique_ptr<Expr> root;
- int error_count = 0;
- int error = parse_string(buffer.data(), &root, &error_count);
- printf("parse returned %d; %d errors encountered\n", error, error_count);
- if (error == 0 || error_count > 0) {
-
- ExprDump(0, root, buffer);
-
- State state(buffer, nullptr);
- std::string result;
- if (!Evaluate(&state, root, &result)) {
- printf("result was NULL, message is: %s\n",
- (state.errmsg.empty() ? "(NULL)" : state.errmsg.c_str()));
- } else {
- printf("result is [%s]\n", result.c_str());
- }
- }
- return 0;
-}
diff --git a/edify/expr.cpp b/edify/expr.cpp
index 54ab332..6823b73 100644
--- a/edify/expr.cpp
+++ b/edify/expr.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "expr.h"
+#include "edify/expr.h"
#include <stdarg.h>
#include <stdio.h>
@@ -31,6 +31,8 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include "otautil/error_code.h"
+
// Functions should:
//
// - return a malloc()'d string
@@ -112,9 +114,9 @@
Value* AbortFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
std::string msg;
if (!argv.empty() && Evaluate(state, argv[0], &msg)) {
- state->errmsg = msg;
+ state->errmsg += msg;
} else {
- state->errmsg = "called abort()";
+ state->errmsg += "called abort()";
}
return nullptr;
}
@@ -408,16 +410,16 @@
}
Value* ErrorAbort(State* state, CauseCode cause_code, const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- android::base::StringAppendV(&state->errmsg, format, ap);
- va_end(ap);
- state->cause_code = cause_code;
- return nullptr;
+ std::string err_message;
+ va_list ap;
+ va_start(ap, format);
+ android::base::StringAppendV(&err_message, format, ap);
+ va_end(ap);
+ // Ensure that there's exactly one line break at the end of the error message.
+ state->errmsg = android::base::Trim(err_message) + "\n";
+ state->cause_code = cause_code;
+ return nullptr;
}
-State::State(const std::string& script, void* cookie) :
- script(script),
- cookie(cookie) {
-}
-
+State::State(const std::string& script, void* cookie)
+ : script(script), cookie(cookie), error_code(kNoError), cause_code(kNoCause) {}
diff --git a/edify/expr.h b/edify/include/edify/expr.h
similarity index 86%
rename from edify/expr.h
rename to edify/include/edify/expr.h
index 4838d20..770d1cf 100644
--- a/edify/expr.h
+++ b/edify/include/edify/expr.h
@@ -23,32 +23,34 @@
#include <string>
#include <vector>
-#include "error_code.h"
+// Forward declaration to avoid including "otautil/error_code.h".
+enum ErrorCode : int;
+enum CauseCode : int;
struct State {
- State(const std::string& script, void* cookie);
+ State(const std::string& script, void* cookie);
- // The source of the original script.
- const std::string& script;
+ // The source of the original script.
+ const std::string& script;
- // Optional pointer to app-specific data; the core of edify never
- // uses this value.
- void* cookie;
+ // Optional pointer to app-specific data; the core of edify never
+ // uses this value.
+ void* cookie;
- // The error message (if any) returned if the evaluation aborts.
- // Should be empty initially, will be either empty or a string that
- // Evaluate() returns.
- std::string errmsg;
+ // The error message (if any) returned if the evaluation aborts.
+ // Should be empty initially, will be either empty or a string that
+ // Evaluate() returns.
+ std::string errmsg;
- // error code indicates the type of failure (e.g. failure to update system image)
- // during the OTA process.
- ErrorCode error_code = kNoError;
+ // error code indicates the type of failure (e.g. failure to update system image)
+ // during the OTA process.
+ ErrorCode error_code;
- // cause code provides more detailed reason of an OTA failure (e.g. fsync error)
- // in addition to the error code.
- CauseCode cause_code = kNoCause;
+ // cause code provides more detailed reason of an OTA failure (e.g. fsync error)
+ // in addition to the error code.
+ CauseCode cause_code;
- bool is_retry = false;
+ bool is_retry = false;
};
enum ValueType {
diff --git a/edify/lexer.ll b/edify/lexer.ll
index b764d16..4e04003 100644
--- a/edify/lexer.ll
+++ b/edify/lexer.ll
@@ -18,7 +18,7 @@
#include <string.h>
#include <string>
-#include "expr.h"
+#include "edify/expr.h"
#include "yydefs.h"
#include "parser.h"
@@ -35,6 +35,8 @@
%x STR
+%option noinput
+%option nounput
%option noyywrap
%%
diff --git a/edify/parser.yy b/edify/parser.yy
index b1685eb..bd2e010 100644
--- a/edify/parser.yy
+++ b/edify/parser.yy
@@ -25,7 +25,7 @@
#include <android-base/macros.h>
-#include "expr.h"
+#include "edify/expr.h"
#include "yydefs.h"
#include "parser.h"
diff --git a/etc/init.rc b/etc/init.rc
index d1c4526..bcd519b 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -29,8 +29,9 @@
export ANDROID_DATA /data
export EXTERNAL_STORAGE /sdcard
- mkdir /boot
- mkdir /recovery
+ mount cgroup none /acct cpuacct
+ mkdir /acct/uid
+
mkdir /system
mkdir /data
mkdir /cache
diff --git a/exfat/fsck/Android.mk b/exfat/fsck/Android.mk
index 5ad0302..64ebc0f 100644
--- a/exfat/fsck/Android.mk
+++ b/exfat/fsck/Android.mk
@@ -6,7 +6,7 @@
LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
-LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64
+LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -Wno-sign-compare
LOCAL_SRC_FILES = main.c
LOCAL_C_INCLUDES += $(LOCAL_PATH) \
$(commands_recovery_local_path)/exfat/libexfat \
diff --git a/exfat/fuse/Android.mk b/exfat/fuse/Android.mk
index 1b5d084..57f35be 100644
--- a/exfat/fuse/Android.mk
+++ b/exfat/fuse/Android.mk
@@ -5,7 +5,7 @@
LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
-LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64
+LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -Wno-sign-compare -Wno-unused-parameter
LOCAL_SRC_FILES = main.c
LOCAL_C_INCLUDES += $(LOCAL_PATH) \
$(commands_recovery_local_path)/exfat/libexfat \
diff --git a/exfat/libexfat/Android.mk b/exfat/libexfat/Android.mk
index 5476486..64adef7 100644
--- a/exfat/libexfat/Android.mk
+++ b/exfat/libexfat/Android.mk
@@ -3,7 +3,7 @@
LOCAL_MODULE := libexfat_twrp
LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64
+LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -Wno-sign-compare -Wno-address-of-packed-member -Wno-missing-field-initializers
LOCAL_SRC_FILES = cluster.c io.c log.c lookup.c mount.c node.c time.c utf.c utils.c
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_SHARED_LIBRARIES += libc
diff --git a/exfat/libexfat/lookup.c b/exfat/libexfat/lookup.c
index d5bb389..3caef74 100644
--- a/exfat/libexfat/lookup.c
+++ b/exfat/libexfat/lookup.c
@@ -46,7 +46,7 @@
it->current = NULL;
}
-struct exfat_node* exfat_readdir(struct exfat* ef, struct exfat_iterator* it)
+struct exfat_node* exfat_readdir(struct exfat* ef __unused, struct exfat_iterator* it)
{
if (it->current == NULL)
it->current = it->parent->child;
diff --git a/exfat/mkfs/Android.mk b/exfat/mkfs/Android.mk
index 0b81aa4..9f3e7cb 100644
--- a/exfat/mkfs/Android.mk
+++ b/exfat/mkfs/Android.mk
@@ -5,7 +5,7 @@
LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
-LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64
+LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -Wno-sign-compare
LOCAL_SRC_FILES = cbm.c fat.c main.c mkexfat.c rootdir.c uct.c uctc.c vbr.c
LOCAL_C_INCLUDES += $(LOCAL_PATH) \
$(commands_recovery_local_path)/exfat/libexfat \
diff --git a/fuse/Android.mk b/fuse/Android.mk
index 5260e14..00763ea 100644
--- a/fuse/Android.mk
+++ b/fuse/Android.mk
@@ -45,6 +45,8 @@
-DFUSE_USE_VERSION=26 \
-fno-strict-aliasing
+LOCAL_CFLAGS += -Wno-pointer-arith -Wno-sign-compare -Wno-unused-parameter
+
LOCAL_MODULE := libfusetwrp
LOCAL_MODULE_TAGS := optional
diff --git a/fuse/mount.c b/fuse/mount.c
index eb0bb17..8736856 100644
--- a/fuse/mount.c
+++ b/fuse/mount.c
@@ -282,7 +282,7 @@
}
cmsg = CMSG_FIRSTHDR(&msg);
- if (!cmsg->cmsg_type == SCM_RIGHTS) {
+ if (cmsg->cmsg_type != SCM_RIGHTS) {
fprintf(stderr, "got control message of unknown type %d\n",
cmsg->cmsg_type);
return -1;
diff --git a/fuse_sdcard_provider.cpp b/fuse_sdcard_provider.cpp
index b0ecf96..46bdf17 100644
--- a/fuse_sdcard_provider.cpp
+++ b/fuse_sdcard_provider.cpp
@@ -14,72 +14,70 @@
* limitations under the License.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "fuse_sdcard_provider.h"
+
#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <unistd.h>
-#include <fcntl.h>
+
+#include <functional>
#include <android-base/file.h>
#include "fuse_sideload.h"
struct file_data {
- int fd; // the underlying sdcard file
+ int fd; // the underlying sdcard file
- uint64_t file_size;
- uint32_t block_size;
+ uint64_t file_size;
+ uint32_t block_size;
};
-static int read_block_file(void* cookie, uint32_t block, uint8_t* buffer, uint32_t fetch_size) {
- file_data* fd = reinterpret_cast<file_data*>(cookie);
+static int read_block_file(const file_data& fd, uint32_t block, uint8_t* buffer,
+ uint32_t fetch_size) {
+ off64_t offset = static_cast<off64_t>(block) * fd.block_size;
+ if (TEMP_FAILURE_RETRY(lseek64(fd.fd, offset, SEEK_SET)) == -1) {
+ fprintf(stderr, "seek on sdcard failed: %s\n", strerror(errno));
+ return -EIO;
+ }
- off64_t offset = ((off64_t) block) * fd->block_size;
- if (TEMP_FAILURE_RETRY(lseek64(fd->fd, offset, SEEK_SET)) == -1) {
- fprintf(stderr, "seek on sdcard failed: %s\n", strerror(errno));
- return -EIO;
- }
+ if (!android::base::ReadFully(fd.fd, buffer, fetch_size)) {
+ fprintf(stderr, "read on sdcard failed: %s\n", strerror(errno));
+ return -EIO;
+ }
- if (!android::base::ReadFully(fd->fd, buffer, fetch_size)) {
- fprintf(stderr, "read on sdcard failed: %s\n", strerror(errno));
- return -EIO;
- }
-
- return 0;
-}
-
-static void close_file(void* cookie) {
- file_data* fd = reinterpret_cast<file_data*>(cookie);
- close(fd->fd);
+ return 0;
}
bool start_sdcard_fuse(const char* path) {
- struct stat sb;
- if (stat(path, &sb) == -1) {
- fprintf(stderr, "failed to stat %s: %s\n", path, strerror(errno));
- return false;
- }
+ struct stat sb;
+ if (stat(path, &sb) == -1) {
+ fprintf(stderr, "failed to stat %s: %s\n", path, strerror(errno));
+ return false;
+ }
- file_data fd;
- fd.fd = open(path, O_RDONLY);
- if (fd.fd == -1) {
- fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
- return false;
- }
- fd.file_size = sb.st_size;
- fd.block_size = 65536;
+ file_data fd;
+ fd.fd = open(path, O_RDONLY);
+ if (fd.fd == -1) {
+ fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
+ return false;
+ }
+ fd.file_size = sb.st_size;
+ fd.block_size = 65536;
- provider_vtab vtab;
- vtab.read_block = read_block_file;
- vtab.close = close_file;
+ provider_vtab vtab;
+ vtab.read_block = std::bind(&read_block_file, fd, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3);
+ vtab.close = [&fd]() { close(fd.fd); };
- // The installation process expects to find the sdcard unmounted.
- // Unmount it with MNT_DETACH so that our open file continues to
- // work but new references see it as unmounted.
- umount2("/sdcard", MNT_DETACH);
+ // The installation process expects to find the sdcard unmounted. Unmount it with MNT_DETACH so
+ // that our open file continues to work but new references see it as unmounted.
+ umount2("/sdcard", MNT_DETACH);
- return run_fuse_sideload(&vtab, &fd, fd.file_size, fd.block_size) == 0;
+ return run_fuse_sideload(vtab, fd.file_size, fd.block_size) == 0;
}
diff --git a/fuse_sideload.cpp b/fuse_sideload.cpp
index f667cd4..45c79f9 100644
--- a/fuse_sideload.cpp
+++ b/fuse_sideload.cpp
@@ -41,23 +41,20 @@
// two files is implemented. In particular, you can't opendir() or
// readdir() on the "/sideload" directory; ls on it won't work.
-#include <ctype.h>
-#include <dirent.h>
+#include "fuse_sideload.h"
+
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include "fuse.h"
#include <pthread.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/inotify.h>
#include <sys/mount.h>
-#include <sys/param.h>
-#include <sys/resource.h>
+#include <sys/param.h> // MIN
#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/time.h>
#include <sys/uio.h>
#include <unistd.h>
@@ -68,320 +65,304 @@
#include <openssl/sha.h>
#endif
-#include "fuse_sideload.h"
+#include <array>
+#include <string>
+#include <vector>
-#define PACKAGE_FILE_ID (FUSE_ROOT_ID+1)
-#define EXIT_FLAG_ID (FUSE_ROOT_ID+2)
+//#include <android-base/stringprintf.h>
+//#include <android-base/unique_fd.h>
-#define NO_STATUS 1
-#define NO_STATUS_EXIT 2
+static constexpr uint64_t PACKAGE_FILE_ID = FUSE_ROOT_ID + 1;
+static constexpr uint64_t EXIT_FLAG_ID = FUSE_ROOT_ID + 2;
+
+static constexpr int NO_STATUS = 1;
+static constexpr int NO_STATUS_EXIT = 2;
+
+using SHA256Digest = std::array<uint8_t, SHA256_DIGEST_LENGTH>;
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
struct fuse_data {
- int ffd; // file descriptor for the fuse socket
+ int ffd; // file descriptor for the fuse socket
- struct provider_vtab* vtab;
- void* cookie;
+ provider_vtab vtab;
- uint64_t file_size; // bytes
+ uint64_t file_size; // bytes
- uint32_t block_size; // block size that the adb host is using to send the file to us
- uint32_t file_blocks; // file size in block_size blocks
+ uint32_t block_size; // block size that the adb host is using to send the file to us
+ uint32_t file_blocks; // file size in block_size blocks
- uid_t uid;
- gid_t gid;
+ uid_t uid;
+ gid_t gid;
- uint32_t curr_block; // cache the block most recently read from the host
- uint8_t* block_data;
+ uint32_t curr_block; // cache the block most recently read from the host
+ uint8_t* block_data;
- uint8_t* extra_block; // another block of storage for reads that
- // span two blocks
+ uint8_t* extra_block; // another block of storage for reads that span two blocks
- uint8_t* hashes; // SHA-256 hash of each block (all zeros
- // if block hasn't been read yet)
+ uint8_t* hashes; // SHA-256 hash of each block (all zeros
+ // if block hasn't been read yet)
};
-static void fuse_reply(struct fuse_data* fd, __u64 unique, const void *data, size_t len)
-{
- struct fuse_out_header hdr;
- struct iovec vec[2];
- int res;
+static void fuse_reply(const fuse_data* fd, uint64_t unique, const void* data, size_t len) {
+ fuse_out_header hdr;
+ hdr.len = len + sizeof(hdr);
+ hdr.error = 0;
+ hdr.unique = unique;
- hdr.len = len + sizeof(hdr);
- hdr.error = 0;
- hdr.unique = unique;
+ struct iovec vec[2];
+ vec[0].iov_base = &hdr;
+ vec[0].iov_len = sizeof(hdr);
+ vec[1].iov_base = const_cast<void*>(data);
+ vec[1].iov_len = len;
- vec[0].iov_base = &hdr;
- vec[0].iov_len = sizeof(hdr);
- vec[1].iov_base = /* const_cast */(void*)(data);
- vec[1].iov_len = len;
-
- res = writev(fd->ffd, vec, 2);
- if (res < 0) {
- printf("*** REPLY FAILED *** %s\n", strerror(errno));
- }
+ int res = writev(fd->ffd, vec, 2);
+ if (res == -1) {
+ printf("*** REPLY FAILED *** %s\n", strerror(errno));
+ }
}
-static int handle_init(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) {
- const struct fuse_init_in* req = reinterpret_cast<const struct fuse_init_in*>(data);
- struct fuse_init_out out;
- size_t fuse_struct_size;
+static int handle_init(void* data, fuse_data* fd, const fuse_in_header* hdr) {
+ const fuse_init_in* req = static_cast<const fuse_init_in*>(data);
+ // Kernel 2.6.16 is the first stable kernel with struct fuse_init_out defined (fuse version 7.6).
+ // The structure is the same from 7.6 through 7.22. Beginning with 7.23, the structure increased
+ // in size and added new parameters.
+ if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) {
+ printf("Fuse kernel version mismatch: Kernel version %d.%d, Expected at least %d.6", req->major,
+ req->minor, FUSE_KERNEL_VERSION);
+ return -1;
+ }
- /* Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
- * defined (fuse version 7.6). The structure is the same from 7.6 through
- * 7.22. Beginning with 7.23, the structure increased in size and added
- * new parameters.
- */
- if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) {
- printf("Fuse kernel version mismatch: Kernel version %d.%d, Expected at least %d.6",
- req->major, req->minor, FUSE_KERNEL_VERSION);
- return -1;
- }
-
- out.minor = MIN(req->minor, FUSE_KERNEL_MINOR_VERSION);
- fuse_struct_size = sizeof(out);
+ fuse_init_out out;
+ out.minor = MIN(req->minor, FUSE_KERNEL_MINOR_VERSION);
+ size_t fuse_struct_size = sizeof(out);
#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
- /* FUSE_KERNEL_VERSION >= 23. */
+ /* FUSE_KERNEL_VERSION >= 23. */
- /* If the kernel only works on minor revs older than or equal to 22,
- * then use the older structure size since this code only uses the 7.22
- * version of the structure. */
- if (req->minor <= 22) {
- fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
- }
+ // If the kernel only works on minor revs older than or equal to 22, then use the older structure
+ // size since this code only uses the 7.22 version of the structure.
+ if (req->minor <= 22) {
+ fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
+ }
#endif
- out.major = FUSE_KERNEL_VERSION;
- out.max_readahead = req->max_readahead;
- out.flags = 0;
- out.max_background = 32;
- out.congestion_threshold = 32;
- out.max_write = 4096;
- fuse_reply(fd, hdr->unique, &out, fuse_struct_size);
+ out.major = FUSE_KERNEL_VERSION;
+ out.max_readahead = req->max_readahead;
+ out.flags = 0;
+ out.max_background = 32;
+ out.congestion_threshold = 32;
+ out.max_write = 4096;
+ fuse_reply(fd, hdr->unique, &out, fuse_struct_size);
- return NO_STATUS;
+ return NO_STATUS;
}
-static void fill_attr(struct fuse_attr* attr, struct fuse_data* fd,
- uint64_t nodeid, uint64_t size, uint32_t mode) {
- memset(attr, 0, sizeof(*attr));
- attr->nlink = 1;
- attr->uid = fd->uid;
- attr->gid = fd->gid;
- attr->blksize = 4096;
+static void fill_attr(fuse_attr* attr, const fuse_data* fd, uint64_t nodeid, uint64_t size,
+ uint32_t mode) {
+ memset(attr, 0, sizeof(*attr));
+ attr->nlink = 1;
+ attr->uid = fd->uid;
+ attr->gid = fd->gid;
+ attr->blksize = 4096;
- attr->ino = nodeid;
- attr->size = size;
- attr->blocks = (size == 0) ? 0 : (((size-1) / attr->blksize) + 1);
- attr->mode = mode;
+ attr->ino = nodeid;
+ attr->size = size;
+ attr->blocks = (size == 0) ? 0 : (((size - 1) / attr->blksize) + 1);
+ attr->mode = mode;
}
-static int handle_getattr(void* /* data */, struct fuse_data* fd, const struct fuse_in_header* hdr) {
- struct fuse_attr_out out;
- memset(&out, 0, sizeof(out));
- out.attr_valid = 10;
+static int handle_getattr(void* /* data */, const fuse_data* fd, const fuse_in_header* hdr) {
+ struct fuse_attr_out out;
+ memset(&out, 0, sizeof(out));
+ out.attr_valid = 10;
- if (hdr->nodeid == FUSE_ROOT_ID) {
- fill_attr(&(out.attr), fd, hdr->nodeid, 4096, S_IFDIR | 0555);
- } else if (hdr->nodeid == PACKAGE_FILE_ID) {
- fill_attr(&(out.attr), fd, PACKAGE_FILE_ID, fd->file_size, S_IFREG | 0444);
- } else if (hdr->nodeid == EXIT_FLAG_ID) {
- fill_attr(&(out.attr), fd, EXIT_FLAG_ID, 0, S_IFREG | 0);
- } else {
- return -ENOENT;
- }
+ if (hdr->nodeid == FUSE_ROOT_ID) {
+ fill_attr(&(out.attr), fd, hdr->nodeid, 4096, S_IFDIR | 0555);
+ } else if (hdr->nodeid == PACKAGE_FILE_ID) {
+ fill_attr(&(out.attr), fd, PACKAGE_FILE_ID, fd->file_size, S_IFREG | 0444);
+ } else if (hdr->nodeid == EXIT_FLAG_ID) {
+ fill_attr(&(out.attr), fd, EXIT_FLAG_ID, 0, S_IFREG | 0);
+ } else {
+ return -ENOENT;
+ }
- fuse_reply(fd, hdr->unique, &out, sizeof(out));
- return (hdr->nodeid == EXIT_FLAG_ID) ? NO_STATUS_EXIT : NO_STATUS;
+ fuse_reply(fd, hdr->unique, &out, sizeof(out));
+ return (hdr->nodeid == EXIT_FLAG_ID) ? NO_STATUS_EXIT : NO_STATUS;
}
-static int handle_lookup(void* data, struct fuse_data* fd,
- const struct fuse_in_header* hdr) {
- struct fuse_entry_out out;
- memset(&out, 0, sizeof(out));
- out.entry_valid = 10;
- out.attr_valid = 10;
+static int handle_lookup(void* data, const fuse_data* fd, const fuse_in_header* hdr) {
+ if (data == nullptr) return -ENOENT;
- if (strncmp(FUSE_SIDELOAD_HOST_FILENAME, reinterpret_cast<const char*>(data),
- sizeof(FUSE_SIDELOAD_HOST_FILENAME)) == 0) {
- out.nodeid = PACKAGE_FILE_ID;
- out.generation = PACKAGE_FILE_ID;
- fill_attr(&(out.attr), fd, PACKAGE_FILE_ID, fd->file_size, S_IFREG | 0444);
- } else if (strncmp(FUSE_SIDELOAD_HOST_EXIT_FLAG, reinterpret_cast<const char*>(data),
- sizeof(FUSE_SIDELOAD_HOST_EXIT_FLAG)) == 0) {
- out.nodeid = EXIT_FLAG_ID;
- out.generation = EXIT_FLAG_ID;
- fill_attr(&(out.attr), fd, EXIT_FLAG_ID, 0, S_IFREG | 0);
- } else {
- return -ENOENT;
- }
+ struct fuse_entry_out out;
+ memset(&out, 0, sizeof(out));
+ out.entry_valid = 10;
+ out.attr_valid = 10;
- fuse_reply(fd, hdr->unique, &out, sizeof(out));
- return (out.nodeid == EXIT_FLAG_ID) ? NO_STATUS_EXIT : NO_STATUS;
+ std::string filename(static_cast<const char*>(data));
+ if (filename == FUSE_SIDELOAD_HOST_FILENAME) {
+ out.nodeid = PACKAGE_FILE_ID;
+ out.generation = PACKAGE_FILE_ID;
+ fill_attr(&(out.attr), fd, PACKAGE_FILE_ID, fd->file_size, S_IFREG | 0444);
+ } else if (filename == FUSE_SIDELOAD_HOST_EXIT_FLAG) {
+ out.nodeid = EXIT_FLAG_ID;
+ out.generation = EXIT_FLAG_ID;
+ fill_attr(&(out.attr), fd, EXIT_FLAG_ID, 0, S_IFREG | 0);
+ } else {
+ return -ENOENT;
+ }
+
+ fuse_reply(fd, hdr->unique, &out, sizeof(out));
+ return (out.nodeid == EXIT_FLAG_ID) ? NO_STATUS_EXIT : NO_STATUS;
}
-static int handle_open(void* /* data */, struct fuse_data* fd, const struct fuse_in_header* hdr) {
- if (hdr->nodeid == EXIT_FLAG_ID) return -EPERM;
- if (hdr->nodeid != PACKAGE_FILE_ID) return -ENOENT;
+static int handle_open(void* /* data */, const fuse_data* fd, const fuse_in_header* hdr) {
+ if (hdr->nodeid == EXIT_FLAG_ID) return -EPERM;
+ if (hdr->nodeid != PACKAGE_FILE_ID) return -ENOENT;
- struct fuse_open_out out;
- memset(&out, 0, sizeof(out));
- out.fh = 10; // an arbitrary number; we always use the same handle
- fuse_reply(fd, hdr->unique, &out, sizeof(out));
- return NO_STATUS;
+ struct fuse_open_out out;
+ memset(&out, 0, sizeof(out));
+ out.fh = 10; // an arbitrary number; we always use the same handle
+ fuse_reply(fd, hdr->unique, &out, sizeof(out));
+ return NO_STATUS;
}
-static int handle_flush(void* /* data */, struct fuse_data* /* fd */,
- const struct fuse_in_header* /* hdr */) {
- return 0;
+static int handle_flush(void* /* data */, fuse_data* /* fd */, const fuse_in_header* /* hdr */) {
+ return 0;
}
-static int handle_release(void* /* data */, struct fuse_data* /* fd */,
- const struct fuse_in_header* /* hdr */) {
- return 0;
+static int handle_release(void* /* data */, fuse_data* /* fd */, const fuse_in_header* /* hdr */) {
+ return 0;
}
// Fetch a block from the host into fd->curr_block and fd->block_data.
// Returns 0 on successful fetch, negative otherwise.
-static int fetch_block(struct fuse_data* fd, uint32_t block) {
- if (block == fd->curr_block) {
- return 0;
- }
-
- if (block >= fd->file_blocks) {
- memset(fd->block_data, 0, fd->block_size);
- fd->curr_block = block;
- return 0;
- }
-
- size_t fetch_size = fd->block_size;
- if (block * fd->block_size + fetch_size > fd->file_size) {
- // If we're reading the last (partial) block of the file,
- // expect a shorter response from the host, and pad the rest
- // of the block with zeroes.
- fetch_size = fd->file_size - (block * fd->block_size);
- memset(fd->block_data + fetch_size, 0, fd->block_size - fetch_size);
- }
-
- int result = fd->vtab->read_block(fd->cookie, block, fd->block_data, fetch_size);
- if (result < 0) return result;
-
- fd->curr_block = block;
-
- // Verify the hash of the block we just got from the host.
- //
- // - If the hash of the just-received data matches the stored hash
- // for the block, accept it.
- // - If the stored hash is all zeroes, store the new hash and
- // accept the block (this is the first time we've read this
- // block).
- // - Otherwise, return -EINVAL for the read.
-
- uint8_t hash[SHA256_DIGEST_LENGTH];
-#ifdef USE_MINCRYPT
- SHA256_hash(fd->block_data, fd->block_size, hash);
-#else
- SHA256(fd->block_data, fd->block_size, hash);
-#endif
- uint8_t* blockhash = fd->hashes + block * SHA256_DIGEST_LENGTH;
- if (memcmp(hash, blockhash, SHA256_DIGEST_LENGTH) == 0) {
- return 0;
- }
-
- int i;
- for (i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
- if (blockhash[i] != 0) {
- fd->curr_block = -1;
- return -EIO;
- }
- }
-
- memcpy(blockhash, hash, SHA256_DIGEST_LENGTH);
+static int fetch_block(fuse_data* fd, uint32_t block) {
+ if (block == fd->curr_block) {
return 0;
+ }
+
+ if (block >= fd->file_blocks) {
+ memset(fd->block_data, 0, fd->block_size);
+ fd->curr_block = block;
+ return 0;
+ }
+
+ size_t fetch_size = fd->block_size;
+ if (block * fd->block_size + fetch_size > fd->file_size) {
+ // If we're reading the last (partial) block of the file, expect a shorter response from the
+ // host, and pad the rest of the block with zeroes.
+ fetch_size = fd->file_size - (block * fd->block_size);
+ memset(fd->block_data + fetch_size, 0, fd->block_size - fetch_size);
+ }
+
+ int result = fd->vtab.read_block(block, fd->block_data, fetch_size);
+ if (result < 0) return result;
+
+ fd->curr_block = block;
+
+ // Verify the hash of the block we just got from the host.
+ //
+ // - If the hash of the just-received data matches the stored hash for the block, accept it.
+ // - If the stored hash is all zeroes, store the new hash and accept the block (this is the first
+ // time we've read this block).
+ // - Otherwise, return -EINVAL for the read.
+
+ uint8_t hash[SHA256_DIGEST_LENGTH];
+#ifdef USE_MINCRYPT
+ SHA256_hash(fd->block_data, fd->block_size, hash);
+#else
+ SHA256(fd->block_data, fd->block_size, hash);
+#endif
+ uint8_t* blockhash = fd->hashes + block * SHA256_DIGEST_LENGTH;
+ if (memcmp(hash, blockhash, SHA256_DIGEST_LENGTH) == 0) {
+ return 0;
+ }
+
+ int i;
+ for (i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
+ if (blockhash[i] != 0) {
+ fd->curr_block = -1;
+ return -EIO;
+ }
+ }
+
+ memcpy(blockhash, hash, SHA256_DIGEST_LENGTH);
+ return 0;
}
-static int handle_read(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) {
- const struct fuse_read_in* req = reinterpret_cast<const struct fuse_read_in*>(data);
- struct fuse_out_header outhdr;
- struct iovec vec[3];
- int vec_used;
- int result;
+static int handle_read(void* data, fuse_data* fd, const fuse_in_header* hdr) {
+ if (hdr->nodeid != PACKAGE_FILE_ID) return -ENOENT;
- if (hdr->nodeid != PACKAGE_FILE_ID) return -ENOENT;
+ const fuse_read_in* req = static_cast<const fuse_read_in*>(data);
+ uint64_t offset = req->offset;
+ uint32_t size = req->size;
- uint64_t offset = req->offset;
- uint32_t size = req->size;
+ // The docs on the fuse kernel interface are vague about what to do when a read request extends
+ // past the end of the file. We can return a short read -- the return structure does include a
+ // length field -- but in testing that caused the program using the file to segfault. (I
+ // speculate that this is due to the reading program accessing it via mmap; maybe mmap dislikes
+ // when you return something short of a whole page?) To fix this we zero-pad reads that extend
+ // past the end of the file so we're always returning exactly as many bytes as were requested.
+ // (Users of the mapped file have to know its real length anyway.)
- // The docs on the fuse kernel interface are vague about what to
- // do when a read request extends past the end of the file. We
- // can return a short read -- the return structure does include a
- // length field -- but in testing that caused the program using
- // the file to segfault. (I speculate that this is due to the
- // reading program accessing it via mmap; maybe mmap dislikes when
- // you return something short of a whole page?) To fix this we
- // zero-pad reads that extend past the end of the file so we're
- // always returning exactly as many bytes as were requested.
- // (Users of the mapped file have to know its real length anyway.)
+ fuse_out_header outhdr;
+ outhdr.len = sizeof(outhdr) + size;
+ outhdr.error = 0;
+ outhdr.unique = hdr->unique;
- outhdr.len = sizeof(outhdr) + size;
- outhdr.error = 0;
- outhdr.unique = hdr->unique;
- vec[0].iov_base = &outhdr;
- vec[0].iov_len = sizeof(outhdr);
+ struct iovec vec[3];
+ vec[0].iov_base = &outhdr;
+ vec[0].iov_len = sizeof(outhdr);
- uint32_t block = offset / fd->block_size;
- result = fetch_block(fd, block);
+ uint32_t block = offset / fd->block_size;
+ int result = fetch_block(fd, block);
+ if (result != 0) return result;
+
+ // Two cases:
+ //
+ // - the read request is entirely within this block. In this case we can reply immediately.
+ //
+ // - the read request goes over into the next block. Note that since we mount the filesystem
+ // with max_read=block_size, a read can never span more than two blocks. In this case we copy
+ // the block to extra_block and issue a fetch for the following block.
+
+ uint32_t block_offset = offset - (block * fd->block_size);
+
+ int vec_used;
+ if (size + block_offset <= fd->block_size) {
+ // First case: the read fits entirely in the first block.
+
+ vec[1].iov_base = fd->block_data + block_offset;
+ vec[1].iov_len = size;
+ vec_used = 2;
+ } else {
+ // Second case: the read spills over into the next block.
+
+ memcpy(fd->extra_block, fd->block_data + block_offset, fd->block_size - block_offset);
+ vec[1].iov_base = fd->extra_block;
+ vec[1].iov_len = fd->block_size - block_offset;
+
+ result = fetch_block(fd, block + 1);
if (result != 0) return result;
+ vec[2].iov_base = fd->block_data;
+ vec[2].iov_len = size - vec[1].iov_len;
+ vec_used = 3;
+ }
- // Two cases:
- //
- // - the read request is entirely within this block. In this
- // case we can reply immediately.
- //
- // - the read request goes over into the next block. Note that
- // since we mount the filesystem with max_read=block_size, a
- // read can never span more than two blocks. In this case we
- // copy the block to extra_block and issue a fetch for the
- // following block.
-
- uint32_t block_offset = offset - (block * fd->block_size);
-
- if (size + block_offset <= fd->block_size) {
- // First case: the read fits entirely in the first block.
-
- vec[1].iov_base = fd->block_data + block_offset;
- vec[1].iov_len = size;
- vec_used = 2;
- } else {
- // Second case: the read spills over into the next block.
-
- memcpy(fd->extra_block, fd->block_data + block_offset,
- fd->block_size - block_offset);
- vec[1].iov_base = fd->extra_block;
- vec[1].iov_len = fd->block_size - block_offset;
-
- result = fetch_block(fd, block+1);
- if (result != 0) return result;
- vec[2].iov_base = fd->block_data;
- vec[2].iov_len = size - vec[1].iov_len;
- vec_used = 3;
- }
-
- if (writev(fd->ffd, vec, vec_used) < 0) {
- printf("*** READ REPLY FAILED: %s ***\n", strerror(errno));
- }
- return NO_STATUS;
+ if (writev(fd->ffd, vec, vec_used) == -1) {
+ printf("*** READ REPLY FAILED: %s ***\n", strerror(errno));
+ }
+ return NO_STATUS;
}
-int run_fuse_sideload(struct provider_vtab* vtab, void* cookie, uint64_t file_size,
- uint32_t block_size) {
+int run_fuse_sideload(const provider_vtab& vtab, uint64_t file_size, uint32_t block_size,
+ const char* mount_point) {
// If something's already mounted on our mountpoint, try to remove it. (Mostly in case of a
// previous abnormal exit.)
- umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_FORCE);
+ umount2(mount_point, MNT_FORCE);
// fs/fuse/inode.c in kernel code uses the greater of 4096 and the passed-in max_read.
if (block_size < 4096) {
@@ -393,9 +374,9 @@
return -1;
}
- struct fuse_data fd = {};
+ fuse_data fd;
+ memset(&fd, 0, sizeof(fd));
fd.vtab = vtab;
- fd.cookie = cookie;
fd.file_size = file_size;
fd.block_size = block_size;
fd.file_blocks = (file_size == 0) ? 0 : (((file_size - 1) / block_size) + 1);
@@ -419,42 +400,42 @@
fd.gid = getgid();
fd.curr_block = -1;
- fd.block_data = (uint8_t*)malloc(block_size);
- if (fd.block_data == NULL) {
+ fd.block_data = static_cast<uint8_t*>(malloc(block_size));
+ if (fd.block_data == nullptr) {
fprintf(stderr, "failed to allocate %d bites for block_data\n", block_size);
result = -1;
goto done;
}
- fd.extra_block = (uint8_t*)malloc(block_size);
- if (fd.extra_block == NULL) {
+ fd.extra_block = static_cast<uint8_t*>(malloc(block_size));
+ if (fd.extra_block == nullptr) {
fprintf(stderr, "failed to allocate %d bites for extra_block\n", block_size);
result = -1;
goto done;
}
fd.ffd = open("/dev/fuse", O_RDWR);
- if (fd.ffd < 0) {
+ if (!fd.ffd) {
perror("open /dev/fuse");
result = -1;
goto done;
}
{
- char opts[256];
- snprintf(opts, sizeof(opts),
- ("fd=%d,user_id=%d,group_id=%d,max_read=%u,"
- "allow_other,rootmode=040000"),
- fd.ffd, fd.uid, fd.gid, block_size);
+ char opts[256];
+ snprintf(opts, sizeof(opts),
+ ("fd=%d,user_id=%d,group_id=%d,max_read=%u,"
+ "allow_other,rootmode=040000"),
+ fd.ffd, fd.uid, fd.gid, block_size);
- result = mount("/dev/fuse", FUSE_SIDELOAD_HOST_MOUNTPOINT, "fuse",
- MS_NOSUID | MS_NODEV | MS_RDONLY | MS_NOEXEC, opts);
- if (result < 0) {
+ result = mount("/dev/fuse", FUSE_SIDELOAD_HOST_MOUNTPOINT, "fuse",
+ MS_NOSUID | MS_NODEV | MS_RDONLY | MS_NOEXEC, opts);
+ if (result < 0) {
perror("mount");
goto done;
}
}
- uint8_t request_buffer[sizeof(struct fuse_in_header) + PATH_MAX * 8];
+ uint8_t request_buffer[sizeof(fuse_in_header) + PATH_MAX * 8];
for (;;) {
ssize_t len = TEMP_FAILURE_RETRY(read(fd.ffd, request_buffer, sizeof(request_buffer)));
if (len == -1) {
@@ -466,13 +447,13 @@
continue;
}
- if (static_cast<size_t>(len) < sizeof(struct fuse_in_header)) {
+ if (static_cast<size_t>(len) < sizeof(fuse_in_header)) {
fprintf(stderr, "request too short: len=%zd\n", len);
continue;
}
- struct fuse_in_header* hdr = reinterpret_cast<struct fuse_in_header*>(request_buffer);
- void* data = request_buffer + sizeof(struct fuse_in_header);
+ fuse_in_header* hdr = reinterpret_cast<fuse_in_header*>(request_buffer);
+ void* data = request_buffer + sizeof(fuse_in_header);
result = -ENOSYS;
@@ -516,7 +497,7 @@
}
if (result != NO_STATUS) {
- struct fuse_out_header outhdr;
+ fuse_out_header outhdr;
outhdr.len = sizeof(outhdr);
outhdr.error = result;
outhdr.unique = hdr->unique;
@@ -525,23 +506,20 @@
}
done:
- fd.vtab->close(fd.cookie);
+ fd.vtab.close();
- result = umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_DETACH);
- if (result < 0) {
- printf("fuse_sideload umount failed: %s\n", strerror(errno));
+ if (umount2(mount_point, MNT_DETACH) == -1) {
+ fprintf(stderr, "fuse_sideload umount failed: %s\n", strerror(errno));
}
- if (fd.ffd) close(fd.ffd);
- free(fd.hashes);
free(fd.block_data);
free(fd.extra_block);
return result;
}
-extern "C" int run_old_fuse_sideload(struct provider_vtab* vtab, void* cookie,
+extern "C" int run_old_fuse_sideload(const struct provider_vtab& vtab, void* cookie __unused,
uint64_t file_size, uint32_t block_size)
{
- return run_fuse_sideload(vtab, cookie, file_size, block_size);
+ return run_fuse_sideload(vtab, file_size, block_size, FUSE_SIDELOAD_HOST_MOUNTPOINT);
}
diff --git a/fuse_sideload.h b/fuse_sideload.h
index 2a8ebfc..1ea1eb8 100644
--- a/fuse_sideload.h
+++ b/fuse_sideload.h
@@ -17,31 +17,39 @@
#ifndef __FUSE_SIDELOAD_H
#define __FUSE_SIDELOAD_H
-// define the filenames created by the sideload FUSE filesystem
-#define FUSE_SIDELOAD_HOST_MOUNTPOINT "/sideload"
-#define FUSE_SIDELOAD_HOST_FILENAME "package.zip"
-#define FUSE_SIDELOAD_HOST_PATHNAME (FUSE_SIDELOAD_HOST_MOUNTPOINT "/" FUSE_SIDELOAD_HOST_FILENAME)
-#define FUSE_SIDELOAD_HOST_EXIT_FLAG "exit"
-#define FUSE_SIDELOAD_HOST_EXIT_PATHNAME (FUSE_SIDELOAD_HOST_MOUNTPOINT "/" FUSE_SIDELOAD_HOST_EXIT_FLAG)
+#ifdef USE_FUSE_SIDELOAD22
+#include "fuse_sideload22.h"
+#else
+
+#include <functional>
+
+// Define the filenames created by the sideload FUSE filesystem.
+static constexpr const char* FUSE_SIDELOAD_HOST_MOUNTPOINT = "/sideload";
+static constexpr const char* FUSE_SIDELOAD_HOST_FILENAME = "package.zip";
+static constexpr const char* FUSE_SIDELOAD_HOST_PATHNAME = "/sideload/package.zip";
+static constexpr const char* FUSE_SIDELOAD_HOST_EXIT_FLAG = "exit";
+static constexpr const char* FUSE_SIDELOAD_HOST_EXIT_PATHNAME = "/sideload/exit";
struct provider_vtab {
- // read a block
- int (*read_block)(void* cookie, uint32_t block, uint8_t* buffer, uint32_t fetch_size);
+ // read a block
+ std::function<int(uint32_t block, uint8_t* buffer, uint32_t fetch_size)> read_block;
- // close down
- void (*close)(void* cookie);
+ // close down
+ std::function<void(void)> close;
};
-int run_fuse_sideload(struct provider_vtab* vtab, void* cookie,
- uint64_t file_size, uint32_t block_size);
+int run_fuse_sideload(const provider_vtab& vtab, uint64_t file_size, uint32_t block_size,
+ const char* mount_point = FUSE_SIDELOAD_HOST_MOUNTPOINT);
#ifdef __cplusplus
extern "C" {
#endif
-int run_old_fuse_sideload(struct provider_vtab* vtab, void* cookie,
+int run_old_fuse_sideload(const struct provider_vtab& vtab, void* cookie,
uint64_t file_size, uint32_t block_size);
#ifdef __cplusplus
}
#endif
#endif
+
+#endif
diff --git a/fuse_sideload22.cpp b/fuse_sideload22.cpp
new file mode 100644
index 0000000..f57d479
--- /dev/null
+++ b/fuse_sideload22.cpp
@@ -0,0 +1,544 @@
+/*
+ * 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.
+ */
+
+// This module creates a special filesystem containing two files.
+//
+// "/sideload/package.zip" appears to be a normal file, but reading
+// from it causes data to be fetched from the adb host. We can use
+// this to sideload packages over an adb connection without having to
+// store the entire package in RAM on the device.
+//
+// Because we may not trust the adb host, this filesystem maintains
+// the following invariant: each read of a given position returns the
+// same data as the first read at that position. That is, once a
+// section of the file is read, future reads of that section return
+// the same data. (Otherwise, a malicious adb host process could
+// return one set of bits when the package is read for signature
+// verification, and then different bits for when the package is
+// accessed by the installer.) If the adb host returns something
+// different than it did on the first read, the reader of the file
+// will see their read fail with EINVAL.
+//
+// The other file, "/sideload/exit", is used to control the subprocess
+// that creates this filesystem. Calling stat() on the exit file
+// causes the filesystem to be unmounted and the adb process on the
+// device shut down.
+//
+// Note that only the minimal set of file operations needed for these
+// two files is implemented. In particular, you can't opendir() or
+// readdir() on the "/sideload" directory; ls on it won't work.
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include "fuse.h"
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/inotify.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#ifdef USE_MINCRYPT
+#include "mincrypt/sha256.h"
+#define SHA256_DIGEST_LENGTH SHA256_DIGEST_SIZE
+#else
+#include <openssl/sha.h>
+#endif
+
+#include "fuse_sideload.h"
+
+#define PACKAGE_FILE_ID (FUSE_ROOT_ID+1)
+#define EXIT_FLAG_ID (FUSE_ROOT_ID+2)
+
+#define NO_STATUS 1
+#define NO_STATUS_EXIT 2
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+struct fuse_data {
+ int ffd; // file descriptor for the fuse socket
+
+ struct provider_vtab* vtab;
+ void* cookie;
+
+ uint64_t file_size; // bytes
+
+ uint32_t block_size; // block size that the adb host is using to send the file to us
+ uint32_t file_blocks; // file size in block_size blocks
+
+ uid_t uid;
+ gid_t gid;
+
+ uint32_t curr_block; // cache the block most recently read from the host
+ uint8_t* block_data;
+
+ uint8_t* extra_block; // another block of storage for reads that
+ // span two blocks
+
+ uint8_t* hashes; // SHA-256 hash of each block (all zeros
+ // if block hasn't been read yet)
+};
+
+static void fuse_reply(struct fuse_data* fd, __u64 unique, const void *data, size_t len)
+{
+ struct fuse_out_header hdr;
+ struct iovec vec[2];
+ int res;
+
+ hdr.len = len + sizeof(hdr);
+ hdr.error = 0;
+ hdr.unique = unique;
+
+ vec[0].iov_base = &hdr;
+ vec[0].iov_len = sizeof(hdr);
+ vec[1].iov_base = /* const_cast */(void*)(data);
+ vec[1].iov_len = len;
+
+ res = writev(fd->ffd, vec, 2);
+ if (res < 0) {
+ printf("*** REPLY FAILED *** %s\n", strerror(errno));
+ }
+}
+
+static int handle_init(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) {
+ const struct fuse_init_in* req = reinterpret_cast<const struct fuse_init_in*>(data);
+ struct fuse_init_out out;
+ size_t fuse_struct_size;
+
+
+ /* Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
+ * defined (fuse version 7.6). The structure is the same from 7.6 through
+ * 7.22. Beginning with 7.23, the structure increased in size and added
+ * new parameters.
+ */
+ if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) {
+ printf("Fuse kernel version mismatch: Kernel version %d.%d, Expected at least %d.6",
+ req->major, req->minor, FUSE_KERNEL_VERSION);
+ return -1;
+ }
+
+ out.minor = MIN(req->minor, FUSE_KERNEL_MINOR_VERSION);
+ fuse_struct_size = sizeof(out);
+#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
+ /* FUSE_KERNEL_VERSION >= 23. */
+
+ /* If the kernel only works on minor revs older than or equal to 22,
+ * then use the older structure size since this code only uses the 7.22
+ * version of the structure. */
+ if (req->minor <= 22) {
+ fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
+ }
+#endif
+
+ out.major = FUSE_KERNEL_VERSION;
+ out.max_readahead = req->max_readahead;
+ out.flags = 0;
+ out.max_background = 32;
+ out.congestion_threshold = 32;
+ out.max_write = 4096;
+ fuse_reply(fd, hdr->unique, &out, fuse_struct_size);
+
+ return NO_STATUS;
+}
+
+static void fill_attr(struct fuse_attr* attr, struct fuse_data* fd,
+ uint64_t nodeid, uint64_t size, uint32_t mode) {
+ memset(attr, 0, sizeof(*attr));
+ attr->nlink = 1;
+ attr->uid = fd->uid;
+ attr->gid = fd->gid;
+ attr->blksize = 4096;
+
+ attr->ino = nodeid;
+ attr->size = size;
+ attr->blocks = (size == 0) ? 0 : (((size-1) / attr->blksize) + 1);
+ attr->mode = mode;
+}
+
+static int handle_getattr(void* /* data */, struct fuse_data* fd, const struct fuse_in_header* hdr) {
+ struct fuse_attr_out out;
+ memset(&out, 0, sizeof(out));
+ out.attr_valid = 10;
+
+ if (hdr->nodeid == FUSE_ROOT_ID) {
+ fill_attr(&(out.attr), fd, hdr->nodeid, 4096, S_IFDIR | 0555);
+ } else if (hdr->nodeid == PACKAGE_FILE_ID) {
+ fill_attr(&(out.attr), fd, PACKAGE_FILE_ID, fd->file_size, S_IFREG | 0444);
+ } else if (hdr->nodeid == EXIT_FLAG_ID) {
+ fill_attr(&(out.attr), fd, EXIT_FLAG_ID, 0, S_IFREG | 0);
+ } else {
+ return -ENOENT;
+ }
+
+ fuse_reply(fd, hdr->unique, &out, sizeof(out));
+ return (hdr->nodeid == EXIT_FLAG_ID) ? NO_STATUS_EXIT : NO_STATUS;
+}
+
+static int handle_lookup(void* data, struct fuse_data* fd,
+ const struct fuse_in_header* hdr) {
+ struct fuse_entry_out out;
+ memset(&out, 0, sizeof(out));
+ out.entry_valid = 10;
+ out.attr_valid = 10;
+
+ if (strncmp(FUSE_SIDELOAD_HOST_FILENAME, reinterpret_cast<const char*>(data),
+ sizeof(FUSE_SIDELOAD_HOST_FILENAME)) == 0) {
+ out.nodeid = PACKAGE_FILE_ID;
+ out.generation = PACKAGE_FILE_ID;
+ fill_attr(&(out.attr), fd, PACKAGE_FILE_ID, fd->file_size, S_IFREG | 0444);
+ } else if (strncmp(FUSE_SIDELOAD_HOST_EXIT_FLAG, reinterpret_cast<const char*>(data),
+ sizeof(FUSE_SIDELOAD_HOST_EXIT_FLAG)) == 0) {
+ out.nodeid = EXIT_FLAG_ID;
+ out.generation = EXIT_FLAG_ID;
+ fill_attr(&(out.attr), fd, EXIT_FLAG_ID, 0, S_IFREG | 0);
+ } else {
+ return -ENOENT;
+ }
+
+ fuse_reply(fd, hdr->unique, &out, sizeof(out));
+ return (out.nodeid == EXIT_FLAG_ID) ? NO_STATUS_EXIT : NO_STATUS;
+}
+
+static int handle_open(void* /* data */, struct fuse_data* fd, const struct fuse_in_header* hdr) {
+ if (hdr->nodeid == EXIT_FLAG_ID) return -EPERM;
+ if (hdr->nodeid != PACKAGE_FILE_ID) return -ENOENT;
+
+ struct fuse_open_out out;
+ memset(&out, 0, sizeof(out));
+ out.fh = 10; // an arbitrary number; we always use the same handle
+ fuse_reply(fd, hdr->unique, &out, sizeof(out));
+ return NO_STATUS;
+}
+
+static int handle_flush(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) {
+ return 0;
+}
+
+static int handle_release(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) {
+ return 0;
+}
+
+// Fetch a block from the host into fd->curr_block and fd->block_data.
+// Returns 0 on successful fetch, negative otherwise.
+static int fetch_block(struct fuse_data* fd, uint32_t block) {
+ if (block == fd->curr_block) {
+ return 0;
+ }
+
+ if (block >= fd->file_blocks) {
+ memset(fd->block_data, 0, fd->block_size);
+ fd->curr_block = block;
+ return 0;
+ }
+
+ size_t fetch_size = fd->block_size;
+ if (block * fd->block_size + fetch_size > fd->file_size) {
+ // If we're reading the last (partial) block of the file,
+ // expect a shorter response from the host, and pad the rest
+ // of the block with zeroes.
+ fetch_size = fd->file_size - (block * fd->block_size);
+ memset(fd->block_data + fetch_size, 0, fd->block_size - fetch_size);
+ }
+
+ int result = fd->vtab->read_block(fd->cookie, block, fd->block_data, fetch_size);
+ if (result < 0) return result;
+
+ fd->curr_block = block;
+
+ // Verify the hash of the block we just got from the host.
+ //
+ // - If the hash of the just-received data matches the stored hash
+ // for the block, accept it.
+ // - If the stored hash is all zeroes, store the new hash and
+ // accept the block (this is the first time we've read this
+ // block).
+ // - Otherwise, return -EINVAL for the read.
+
+ uint8_t hash[SHA256_DIGEST_LENGTH];
+#ifdef USE_MINCRYPT
+ SHA256_hash(fd->block_data, fd->block_size, hash);
+#else
+ SHA256(fd->block_data, fd->block_size, hash);
+#endif
+ uint8_t* blockhash = fd->hashes + block * SHA256_DIGEST_LENGTH;
+ if (memcmp(hash, blockhash, SHA256_DIGEST_LENGTH) == 0) {
+ return 0;
+ }
+
+ int i;
+ for (i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
+ if (blockhash[i] != 0) {
+ fd->curr_block = -1;
+ return -EIO;
+ }
+ }
+
+ memcpy(blockhash, hash, SHA256_DIGEST_LENGTH);
+ return 0;
+}
+
+static int handle_read(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) {
+ const struct fuse_read_in* req = reinterpret_cast<const struct fuse_read_in*>(data);
+ struct fuse_out_header outhdr;
+ struct iovec vec[3];
+ int vec_used;
+ int result;
+
+ if (hdr->nodeid != PACKAGE_FILE_ID) return -ENOENT;
+
+ uint64_t offset = req->offset;
+ uint32_t size = req->size;
+
+ // The docs on the fuse kernel interface are vague about what to
+ // do when a read request extends past the end of the file. We
+ // can return a short read -- the return structure does include a
+ // length field -- but in testing that caused the program using
+ // the file to segfault. (I speculate that this is due to the
+ // reading program accessing it via mmap; maybe mmap dislikes when
+ // you return something short of a whole page?) To fix this we
+ // zero-pad reads that extend past the end of the file so we're
+ // always returning exactly as many bytes as were requested.
+ // (Users of the mapped file have to know its real length anyway.)
+
+ outhdr.len = sizeof(outhdr) + size;
+ outhdr.error = 0;
+ outhdr.unique = hdr->unique;
+ vec[0].iov_base = &outhdr;
+ vec[0].iov_len = sizeof(outhdr);
+
+ uint32_t block = offset / fd->block_size;
+ result = fetch_block(fd, block);
+ if (result != 0) return result;
+
+ // Two cases:
+ //
+ // - the read request is entirely within this block. In this
+ // case we can reply immediately.
+ //
+ // - the read request goes over into the next block. Note that
+ // since we mount the filesystem with max_read=block_size, a
+ // read can never span more than two blocks. In this case we
+ // copy the block to extra_block and issue a fetch for the
+ // following block.
+
+ uint32_t block_offset = offset - (block * fd->block_size);
+
+ if (size + block_offset <= fd->block_size) {
+ // First case: the read fits entirely in the first block.
+
+ vec[1].iov_base = fd->block_data + block_offset;
+ vec[1].iov_len = size;
+ vec_used = 2;
+ } else {
+ // Second case: the read spills over into the next block.
+
+ memcpy(fd->extra_block, fd->block_data + block_offset,
+ fd->block_size - block_offset);
+ vec[1].iov_base = fd->extra_block;
+ vec[1].iov_len = fd->block_size - block_offset;
+
+ result = fetch_block(fd, block+1);
+ if (result != 0) return result;
+ vec[2].iov_base = fd->block_data;
+ vec[2].iov_len = size - vec[1].iov_len;
+ vec_used = 3;
+ }
+
+ if (writev(fd->ffd, vec, vec_used) < 0) {
+ printf("*** READ REPLY FAILED: %s ***\n", strerror(errno));
+ }
+ return NO_STATUS;
+}
+
+int run_fuse_sideload(struct provider_vtab* vtab, void* cookie,
+ uint64_t file_size, uint32_t block_size)
+{
+ int result;
+
+ // If something's already mounted on our mountpoint, try to remove
+ // it. (Mostly in case of a previous abnormal exit.)
+ umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_FORCE);
+
+ if (block_size < 1024) {
+ fprintf(stderr, "block size (%u) is too small\n", block_size);
+ return -1;
+ }
+ if (block_size > (1<<22)) { // 4 MiB
+ fprintf(stderr, "block size (%u) is too large\n", block_size);
+ return -1;
+ }
+
+ struct fuse_data fd;
+ memset(&fd, 0, sizeof(fd));
+ fd.vtab = vtab;
+ fd.cookie = cookie;
+ fd.file_size = file_size;
+ fd.block_size = block_size;
+ fd.file_blocks = (file_size == 0) ? 0 : (((file_size-1) / block_size) + 1);
+
+ if (fd.file_blocks > (1<<18)) {
+ fprintf(stderr, "file has too many blocks (%u)\n", fd.file_blocks);
+ result = -1;
+ goto done;
+ }
+
+ fd.hashes = (uint8_t*)calloc(fd.file_blocks, SHA256_DIGEST_LENGTH);
+ if (fd.hashes == NULL) {
+ fprintf(stderr, "failed to allocate %d bites for hashes\n",
+ fd.file_blocks * SHA256_DIGEST_LENGTH);
+ result = -1;
+ goto done;
+ }
+
+ fd.uid = getuid();
+ fd.gid = getgid();
+
+ fd.curr_block = -1;
+ fd.block_data = (uint8_t*)malloc(block_size);
+ if (fd.block_data == NULL) {
+ fprintf(stderr, "failed to allocate %d bites for block_data\n", block_size);
+ result = -1;
+ goto done;
+ }
+ fd.extra_block = (uint8_t*)malloc(block_size);
+ if (fd.extra_block == NULL) {
+ fprintf(stderr, "failed to allocate %d bites for extra_block\n", block_size);
+ result = -1;
+ goto done;
+ }
+
+ fd.ffd = open("/dev/fuse", O_RDWR);
+ if (fd.ffd < 0) {
+ perror("open /dev/fuse");
+ result = -1;
+ goto done;
+ }
+
+ char opts[256];
+ snprintf(opts, sizeof(opts),
+ ("fd=%d,user_id=%d,group_id=%d,max_read=%u,"
+ "allow_other,rootmode=040000"),
+ fd.ffd, fd.uid, fd.gid, block_size);
+
+ result = mount("/dev/fuse", FUSE_SIDELOAD_HOST_MOUNTPOINT,
+ "fuse", MS_NOSUID | MS_NODEV | MS_RDONLY | MS_NOEXEC, opts);
+ if (result < 0) {
+ perror("mount");
+ goto done;
+ }
+ uint8_t request_buffer[sizeof(struct fuse_in_header) + PATH_MAX*8];
+ for (;;) {
+ ssize_t len = TEMP_FAILURE_RETRY(read(fd.ffd, request_buffer, sizeof(request_buffer)));
+ if (len == -1) {
+ perror("read request");
+ if (errno == ENODEV) {
+ result = -1;
+ break;
+ }
+ continue;
+ }
+
+ if ((size_t)len < sizeof(struct fuse_in_header)) {
+ fprintf(stderr, "request too short: len=%zu\n", (size_t)len);
+ continue;
+ }
+
+ struct fuse_in_header* hdr = (struct fuse_in_header*) request_buffer;
+ void* data = request_buffer + sizeof(struct fuse_in_header);
+
+ result = -ENOSYS;
+
+ switch (hdr->opcode) {
+ case FUSE_INIT:
+ result = handle_init(data, &fd, hdr);
+ break;
+
+ case FUSE_LOOKUP:
+ result = handle_lookup(data, &fd, hdr);
+ break;
+
+ case FUSE_GETATTR:
+ result = handle_getattr(data, &fd, hdr);
+ break;
+
+ case FUSE_OPEN:
+ result = handle_open(data, &fd, hdr);
+ break;
+
+ case FUSE_READ:
+ result = handle_read(data, &fd, hdr);
+ break;
+
+ case FUSE_FLUSH:
+ result = handle_flush(data, &fd, hdr);
+ break;
+
+ case FUSE_RELEASE:
+ result = handle_release(data, &fd, hdr);
+ break;
+
+ default:
+ fprintf(stderr, "unknown fuse request opcode %d\n", hdr->opcode);
+ break;
+ }
+
+ if (result == NO_STATUS_EXIT) {
+ result = 0;
+ break;
+ }
+
+ if (result != NO_STATUS) {
+ struct fuse_out_header outhdr;
+ outhdr.len = sizeof(outhdr);
+ outhdr.error = result;
+ outhdr.unique = hdr->unique;
+ TEMP_FAILURE_RETRY(write(fd.ffd, &outhdr, sizeof(outhdr)));
+ }
+ }
+
+ done:
+ fd.vtab->close(fd.cookie);
+
+ result = umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_DETACH);
+ if (result < 0) {
+ printf("fuse_sideload umount failed: %s\n", strerror(errno));
+ }
+
+ if (fd.ffd) close(fd.ffd);
+ free(fd.hashes);
+ free(fd.block_data);
+ free(fd.extra_block);
+
+ return result;
+}
+
+extern "C" int run_old_fuse_sideload(struct provider_vtab* vtab, void* cookie,
+ uint64_t file_size, uint32_t block_size)
+{
+ return run_fuse_sideload(vtab, cookie, file_size, block_size);
+}
diff --git a/fuse_sideload22.h b/fuse_sideload22.h
new file mode 100644
index 0000000..98254d4
--- /dev/null
+++ b/fuse_sideload22.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#ifndef __FUSE_SIDELOAD22_H
+#define __FUSE_SIDELOAD22_H
+
+// define the filenames created by the sideload FUSE filesystem
+#define FUSE_SIDELOAD_HOST_MOUNTPOINT "/sideload"
+#define FUSE_SIDELOAD_HOST_FILENAME "package.zip"
+#define FUSE_SIDELOAD_HOST_PATHNAME (FUSE_SIDELOAD_HOST_MOUNTPOINT "/" FUSE_SIDELOAD_HOST_FILENAME)
+#define FUSE_SIDELOAD_HOST_EXIT_FLAG "exit"
+#define FUSE_SIDELOAD_HOST_EXIT_PATHNAME (FUSE_SIDELOAD_HOST_MOUNTPOINT "/" FUSE_SIDELOAD_HOST_EXIT_FLAG)
+
+struct provider_vtab {
+ // read a block
+ int (*read_block)(void* cookie, uint32_t block, uint8_t* buffer, uint32_t fetch_size);
+
+ // close down
+ void (*close)(void* cookie);
+};
+
+int run_fuse_sideload(struct provider_vtab* vtab, void* cookie,
+ uint64_t file_size, uint32_t block_size);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+int run_old_fuse_sideload(struct provider_vtab* vtab, void* cookie,
+ uint64_t file_size, uint32_t block_size);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/gpt/Android.mk b/gpt/Android.mk
index 3c2ec3b..bbd71eb 100644
--- a/gpt/Android.mk
+++ b/gpt/Android.mk
@@ -13,5 +13,7 @@
gpt.c \
gptcrc32.c
+LOCAL_CFLAGS := -Wno-format
+
LOCAL_SHARED_LIBRARIES := libc
include $(BUILD_SHARED_LIBRARY)
diff --git a/gui/Android.mk b/gui/Android.mk
index 909850f..22b5347 100644
--- a/gui/Android.mk
+++ b/gui/Android.mk
@@ -41,6 +41,7 @@
LOCAL_SHARED_LIBRARIES += libminuitwrp libc libstdc++ libaosprecovery libselinux
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26; echo $$?),0)
LOCAL_SHARED_LIBRARIES += libziparchive
+ LOCAL_C_INCLUDES += $(LOCAL_PATH)/../otautil/include
else
LOCAL_SHARED_LIBRARIES += libminzip
LOCAL_CFLAGS += -DUSE_MINZIP
@@ -87,6 +88,7 @@
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
LOCAL_C_INCLUDES += external/stlport/stlport
+ LOCAL_CFLAGS += -DUSE_FUSE_SIDELOAD22
endif
LOCAL_CFLAGS += -DTWRES=\"$(TWRES_PATH)\"
@@ -107,7 +109,7 @@
Could not find ui.xml for TW_THEME: $(TW_THEME)
Set TARGET_SCREEN_WIDTH and TARGET_SCREEN_HEIGHT to automatically select
an appropriate theme, or set TW_THEME to one of the following:
- $(notdir $(wildcard $(commands_recovery_local_path)/gui/theme/*_*))
+ $(notdir $(wildcard $(LOCAL_PATH)/theme/*_*))
****************************************************************************
endef
define TW_CUSTOM_THEME_WARNING_MSG
@@ -117,15 +119,15 @@
Expected to find custom theme's ui.xml at:
$(TWRP_THEME_LOC)/ui.xml
Please fix this or set TW_THEME to one of the following:
- $(notdir $(wildcard $(commands_recovery_local_path)/gui/theme/*_*))
+ $(notdir $(wildcard $(LOCAL_PATH)/theme/*_*))
****************************************************************************
endef
-TWRP_RES := $(commands_recovery_local_path)/gui/theme/common/fonts
-TWRP_RES += $(commands_recovery_local_path)/gui/theme/common/languages
+TWRP_RES := $(LOCAL_PATH)/theme/common/fonts
+TWRP_RES += $(LOCAL_PATH)/theme/common/languages
ifeq ($(TW_EXTRA_LANGUAGES),true)
- TWRP_RES += $(commands_recovery_local_path)/gui/theme/extra-languages/fonts
- TWRP_RES += $(commands_recovery_local_path)/gui/theme/extra-languages/languages
+ TWRP_RES += $(LOCAL_PATH)/theme/extra-languages/fonts
+ TWRP_RES += $(LOCAL_PATH)/theme/extra-languages/languages
endif
ifeq ($(TW_CUSTOM_THEME),)
@@ -163,13 +165,13 @@
endif
endif
- TWRP_THEME_LOC := $(commands_recovery_local_path)/gui/theme/$(TW_THEME)
+ TWRP_THEME_LOC := $(LOCAL_PATH)/theme/$(TW_THEME)
ifeq ($(wildcard $(TWRP_THEME_LOC)/ui.xml),)
$(warning $(TW_THEME_WARNING_MSG))
$(error Theme selection failed; exiting)
endif
- TWRP_RES += $(commands_recovery_local_path)/gui/theme/common/$(word 1,$(subst _, ,$(TW_THEME))).xml
+ TWRP_RES += $(LOCAL_PATH)/theme/common/$(word 1,$(subst _, ,$(TW_THEME))).xml
# for future copying of used include xmls and fonts:
# UI_XML := $(TWRP_THEME_LOC)/ui.xml
# TWRP_INCLUDE_XMLS := $(shell xmllint --xpath '/recovery/include/xmlfile/@name' $(UI_XML)|sed -n 's/[^\"]*\"\([^\"]*\)\"[^\"]*/\1\n/gp'|sort|uniq)
diff --git a/gui/blanktimer.cpp b/gui/blanktimer.cpp
index 2205253..63cd05c 100644
--- a/gui/blanktimer.cpp
+++ b/gui/blanktimer.cpp
@@ -16,7 +16,6 @@
along with TWRP. If not, see <http://www.gnu.org/licenses/>.
*/
-using namespace std;
#include <string>
#include <pthread.h>
#include <sys/time.h>
diff --git a/gui/button.cpp b/gui/button.cpp
index a9b02a3..dfae5e2 100644
--- a/gui/button.cpp
+++ b/gui/button.cpp
@@ -45,9 +45,6 @@
GUIButton::GUIButton(xml_node<>* node)
: GUIObject(node)
{
- xml_attribute<>* attr;
- xml_node<>* child;
-
mButtonImg = NULL;
mButtonIcon = NULL;
mButtonLabel = NULL;
@@ -201,9 +198,12 @@
mRenderW = w;
mRenderH = h;
}
+ mIconW = mIconH = 0;
- mIconW = mButtonIcon->GetWidth();
- mIconH = mButtonIcon->GetHeight();
+ if (mButtonIcon && mButtonIcon->GetResource()) {
+ mIconW = mButtonIcon->GetWidth();
+ mIconH = mButtonIcon->GetHeight();
+ }
mTextH = 0;
mTextW = 0;
diff --git a/gui/checkbox.cpp b/gui/checkbox.cpp
index a2958db..de63cba 100644
--- a/gui/checkbox.cpp
+++ b/gui/checkbox.cpp
@@ -82,10 +82,11 @@
DataManager::SetValue(mVarName, attr->value());
}
- mCheckW = mChecked->GetWidth();
- mCheckH = mChecked->GetHeight();
- if (mCheckW == 0)
- {
+ mCheckW = mCheckH = 0;
+ if (mChecked && mChecked->GetResource()) {
+ mCheckW = mChecked->GetWidth();
+ mCheckH = mChecked->GetHeight();
+ } else if (mUnchecked && mUnchecked->GetResource()) {
mCheckW = mUnchecked->GetWidth();
mCheckH = mUnchecked->GetHeight();
}
diff --git a/gui/fileselector.cpp b/gui/fileselector.cpp
index c4aaab1..fe378c8 100644
--- a/gui/fileselector.cpp
+++ b/gui/fileselector.cpp
@@ -112,8 +112,17 @@
mFolderIcon = LoadAttrImage(child, "folder");
mFileIcon = LoadAttrImage(child, "file");
}
- int iconWidth = std::max(mFolderIcon->GetWidth(), mFileIcon->GetWidth());
- int iconHeight = std::max(mFolderIcon->GetHeight(), mFileIcon->GetHeight());
+ int iconWidth = 0, iconHeight = 0;
+ if (mFolderIcon && mFolderIcon->GetResource() && mFileIcon && mFileIcon->GetResource()) {
+ iconWidth = std::max(mFolderIcon->GetWidth(), mFileIcon->GetWidth());
+ iconHeight = std::max(mFolderIcon->GetHeight(), mFileIcon->GetHeight());
+ } else if (mFolderIcon && mFolderIcon->GetResource()) {
+ iconWidth = mFolderIcon->GetWidth();
+ iconHeight = mFolderIcon->GetHeight();
+ } else if (mFileIcon && mFileIcon->GetResource()) {
+ iconWidth = mFileIcon->GetWidth();
+ iconHeight = mFileIcon->GetHeight();
+ }
SetMaxIconSize(iconWidth, iconHeight);
// Fetch the file/folder list
diff --git a/gui/input.cpp b/gui/input.cpp
index 8dd981c..91a1c11 100644
--- a/gui/input.cpp
+++ b/gui/input.cpp
@@ -122,7 +122,8 @@
if (child)
{
mFont = LoadAttrFont(child, "resource");
- mFontHeight = mFont->GetHeight();
+ if (mFont && mFont->GetResource())
+ mFontHeight = mFont->GetHeight();
}
child = FindNode(node, "data");
@@ -299,9 +300,6 @@
return 0;
}
- void* fontResource = NULL;
- if (mFont) fontResource = mFont->GetResource();
-
// First step, fill background
gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
gr_fill(mRenderX, mRenderY, mRenderW, mRenderH);
@@ -359,9 +357,6 @@
int GUIInput::NotifyTouch(TOUCH_STATE state, int x, int y)
{
static int startSelection = -1;
- void* fontResource = NULL;
-
- if (mFont) fontResource = mFont->GetResource();
if (!isConditionTrue())
return -1;
diff --git a/gui/keyboard.cpp b/gui/keyboard.cpp
index 849cf19..ca7006d 100644
--- a/gui/keyboard.cpp
+++ b/gui/keyboard.cpp
@@ -322,7 +322,7 @@
gr_color(mFontColorSmall.red, mFontColorSmall.green, mFontColorSmall.blue, mFontColorSmall.alpha);
}
- if (labelImage)
+ if (labelImage && labelImage->GetResource())
{
int w = labelImage->GetWidth();
int h = labelImage->GetHeight();
@@ -330,7 +330,7 @@
int y = keyY + (keyH - h) / 2;
gr_blit(labelImage->GetResource(), 0, 0, w, h, x, y);
}
- else if (!labelText.empty())
+ else if (!labelText.empty() && labelFont && labelFont->GetResource())
{
void* fontResource = labelFont->GetResource();
int textW = gr_ttf_measureEx(labelText.c_str(), fontResource);
@@ -342,7 +342,7 @@
// longpress key label (only if font is defined)
keychar = key.longpresskey;
- if (keychar > 32 && keychar < 127 && mLongpressFont->GetResource()) {
+ if (keychar > 32 && keychar < 127 && mLongpressFont && mLongpressFont->GetResource()) {
void* fontResource = mLongpressFont->GetResource();
gr_color(mLongpressFontColor.red, mLongpressFontColor.green, mLongpressFontColor.blue, mLongpressFontColor.alpha);
string text(1, keychar);
diff --git a/gui/listbox.cpp b/gui/listbox.cpp
index 05276e8..9d36bae 100644
--- a/gui/listbox.cpp
+++ b/gui/listbox.cpp
@@ -44,8 +44,17 @@
mIconSelected = LoadAttrImage(child, "selected");
mIconUnselected = LoadAttrImage(child, "unselected");
}
- int iconWidth = std::max(mIconSelected->GetWidth(), mIconUnselected->GetWidth());
- int iconHeight = std::max(mIconSelected->GetHeight(), mIconUnselected->GetHeight());
+ int iconWidth = 0, iconHeight = 0;
+ if (mIconSelected && mIconSelected->GetResource() && mIconUnselected && mIconUnselected->GetResource()) {
+ iconWidth = std::max(mIconSelected->GetWidth(), mIconUnselected->GetWidth());
+ iconHeight = std::max(mIconSelected->GetHeight(), mIconUnselected->GetHeight());
+ } else if (mIconSelected && mIconSelected->GetResource()) {
+ iconWidth = mIconSelected->GetWidth();
+ iconHeight = mIconSelected->GetHeight();
+ } else if (mIconUnselected && mIconUnselected->GetResource()) {
+ iconWidth = mIconUnselected->GetWidth();
+ iconHeight = mIconUnselected->GetHeight();
+ }
SetMaxIconSize(iconWidth, iconHeight);
// Handle the result variable
diff --git a/gui/mousecursor.cpp b/gui/mousecursor.cpp
index b87cac4..93c635a 100644
--- a/gui/mousecursor.cpp
+++ b/gui/mousecursor.cpp
@@ -78,7 +78,7 @@
{
m_color = LoadAttrColor(child, "color", m_color);
m_image = LoadAttrImage(child, "resource");
- if (m_image)
+ if (m_image && m_image->GetResource())
{
mRenderW = m_image->GetWidth();
mRenderH = m_image->GetHeight();
@@ -99,7 +99,7 @@
if (!m_present)
return 0;
- if (m_image)
+ if (m_image && m_image->GetResource())
{
gr_blit(m_image->GetResource(), 0, 0, mRenderW, mRenderH, mRenderX, mRenderY);
}
diff --git a/gui/pages.cpp b/gui/pages.cpp
index a3a1df3..fd0ad9b 100644
--- a/gui/pages.cpp
+++ b/gui/pages.cpp
@@ -42,7 +42,7 @@
#ifdef USE_MINZIP
#include "../minzip/SysUtil.h"
#else
-#include "../otautil/SysUtil.h"
+#include <otautil/SysUtil.h>
#endif
extern "C" {
diff --git a/gui/partitionlist.cpp b/gui/partitionlist.cpp
index c853391..16e0997 100644
--- a/gui/partitionlist.cpp
+++ b/gui/partitionlist.cpp
@@ -58,8 +58,17 @@
selectedList = attr->value();
}
- int iconWidth = std::max(mIconSelected->GetWidth(), mIconUnselected->GetWidth());
- int iconHeight = std::max(mIconSelected->GetHeight(), mIconUnselected->GetHeight());
+ int iconWidth = 0, iconHeight = 0;
+ if (mIconSelected && mIconSelected->GetResource() && mIconUnselected && mIconUnselected->GetResource()) {
+ iconWidth = std::max(mIconSelected->GetWidth(), mIconUnselected->GetWidth());
+ iconHeight = std::max(mIconSelected->GetHeight(), mIconUnselected->GetHeight());
+ } else if (mIconSelected && mIconSelected->GetResource()) {
+ iconWidth = mIconSelected->GetWidth();
+ iconHeight = mIconSelected->GetHeight();
+ } else if (mIconUnselected && mIconUnselected->GetResource()) {
+ iconWidth = mIconUnselected->GetWidth();
+ iconHeight = mIconUnselected->GetHeight();
+ }
SetMaxIconSize(iconWidth, iconHeight);
child = FindNode(node, "listtype");
diff --git a/gui/patternpassword.cpp b/gui/patternpassword.cpp
index c31737f..5559f9d 100644
--- a/gui/patternpassword.cpp
+++ b/gui/patternpassword.cpp
@@ -40,7 +40,6 @@
GUIPatternPassword::GUIPatternPassword(xml_node<>* node)
: GUIObject(node)
{
- xml_attribute<>* attr;
xml_node<>* child;
// 3x3 is the default.
@@ -107,7 +106,7 @@
mDotCircle = gr_render_circle(mDotRadius, mDotColor.red, mDotColor.green, mDotColor.blue, mDotColor.alpha);
mActiveDotCircle = gr_render_circle(mDotRadius/2, mActiveDotColor.red, mActiveDotColor.green, mActiveDotColor.blue, mActiveDotColor.alpha);
}
- else
+ else if (mDotImage && mDotImage->GetResource())
mDotRadius = mDotImage->GetWidth()/2;
SetRenderPos(mRenderX, mRenderY, mRenderW, mRenderH);
@@ -210,10 +209,10 @@
gr_blit(mActiveDotCircle, 0, 0, gr_get_width(mActiveDotCircle), gr_get_height(mActiveDotCircle), mDots[i].x + mDotRadius/2, mDots[i].y + mDotRadius/2);
}
} else {
- if (mDots[i].active) {
+ if (mDots[i].active && mActiveDotImage && mActiveDotImage->GetResource()) {
gr_blit(mActiveDotImage->GetResource(), 0, 0, mActiveDotImage->GetWidth(), mActiveDotImage->GetHeight(),
mDots[i].x + (mDotRadius - mActiveDotImage->GetWidth()/2), mDots[i].y + (mDotRadius - mActiveDotImage->GetHeight()/2));
- } else {
+ } else if (mDotImage && mDotImage->GetResource()) {
gr_blit(mDotImage->GetResource(), 0, 0, mDotImage->GetWidth(), mDotImage->GetHeight(), mDots[i].x, mDots[i].y);
}
}
diff --git a/gui/progressbar.cpp b/gui/progressbar.cpp
index 56ce480..defd951 100644
--- a/gui/progressbar.cpp
+++ b/gui/progressbar.cpp
@@ -45,7 +45,6 @@
GUIProgressBar::GUIProgressBar(xml_node<>* node) : GUIObject(node)
{
- xml_attribute<>* attr;
xml_node<>* child;
mEmptyBar = NULL;
@@ -79,8 +78,12 @@
mCurValVar = LoadAttrString(child, "name");
}
- mRenderW = mEmptyBar->GetWidth();
- mRenderH = mEmptyBar->GetHeight();
+ if (mEmptyBar && mEmptyBar->GetResource()) {
+ mRenderW = mEmptyBar->GetWidth();
+ mRenderH = mEmptyBar->GetHeight();
+ } else {
+ mRenderW = mRenderH = 0;
+ }
}
int GUIProgressBar::Render(void)
diff --git a/gui/resources.cpp b/gui/resources.cpp
index 59b8ed4..bb2fd50 100644
--- a/gui/resources.cpp
+++ b/gui/resources.cpp
@@ -294,38 +294,38 @@
std::string ResourceManager::FindString(const std::string& name) const
{
- if (this != NULL) {
+ //if (this != NULL) {
std::map<std::string, string_resource_struct>::const_iterator it = mStrings.find(name);
if (it != mStrings.end())
return it->second.value;
LOGERR("String resource '%s' not found. No default value.\n", name.c_str());
PageManager::AddStringResource("NO DEFAULT", name, "[" + name + ("]"));
- } else {
+ /*} else {
LOGINFO("String resources not loaded when looking for '%s'. No default value.\n", name.c_str());
- }
+ }*/
return "[" + name + ("]");
}
std::string ResourceManager::FindString(const std::string& name, const std::string& default_string) const
{
- if (this != NULL) {
+ //if (this != NULL) {
std::map<std::string, string_resource_struct>::const_iterator it = mStrings.find(name);
if (it != mStrings.end())
return it->second.value;
LOGERR("String resource '%s' not found. Using default value.\n", name.c_str());
PageManager::AddStringResource("DEFAULT", name, default_string);
- } else {
+ /*} else {
LOGINFO("String resources not loaded when looking for '%s'. Using default value.\n", name.c_str());
- }
+ }*/
return default_string;
}
void ResourceManager::DumpStrings() const
{
- if (this == NULL) {
+ /*if (this == NULL) {
gui_print("No string resources\n");
return;
- }
+ }*/
std::map<std::string, string_resource_struct>::const_iterator it;
gui_print("Dumping all strings:\n");
for (it = mStrings.begin(); it != mStrings.end(); it++)
@@ -363,7 +363,7 @@
if (type == "font")
{
FontResource* res = new FontResource(child, pZip);
- if (res->GetResource())
+ if (res && res->GetResource())
mFonts.push_back(res);
else {
error = true;
@@ -393,7 +393,7 @@
else if (type == "image")
{
ImageResource* res = new ImageResource(child, pZip);
- if (res->GetResource())
+ if (res && res->GetResource())
mImages.push_back(res);
else {
error = true;
@@ -403,7 +403,7 @@
else if (type == "animation")
{
AnimationResource* res = new AnimationResource(child, pZip);
- if (res->GetResourceCount())
+ if (res && res->GetResourceCount())
mAnimations.push_back(res);
else {
error = true;
diff --git a/gui/resources.hpp b/gui/resources.hpp
index de67318..69bebc7 100644
--- a/gui/resources.hpp
+++ b/gui/resources.hpp
@@ -57,8 +57,8 @@
virtual ~FontResource();
public:
- void* GetResource() { return this ? mFont : NULL; }
- int GetHeight() { return gr_ttf_getMaxFontHeight(this ? mFont : NULL); }
+ void* GetResource() { return mFont; }
+ int GetHeight() { return gr_ttf_getMaxFontHeight(mFont); }
void Override(xml_node<>* node, ZipWrap* pZip);
protected:
@@ -80,9 +80,9 @@
virtual ~ImageResource();
public:
- gr_surface GetResource() { return this ? mSurface : NULL; }
- int GetWidth() { return gr_get_width(this ? mSurface : NULL); }
- int GetHeight() { return gr_get_height(this ? mSurface : NULL); }
+ gr_surface GetResource() { return mSurface; }
+ int GetWidth() { return gr_get_width(mSurface); }
+ int GetHeight() { return gr_get_height(mSurface); }
protected:
gr_surface mSurface;
@@ -95,10 +95,10 @@
virtual ~AnimationResource();
public:
- gr_surface GetResource() { return (!this || mSurfaces.empty()) ? NULL : mSurfaces.at(0); }
- gr_surface GetResource(int entry) { return (!this || mSurfaces.empty()) ? NULL : mSurfaces.at(entry); }
- int GetWidth() { return gr_get_width(this ? GetResource() : NULL); }
- int GetHeight() { return gr_get_height(this ? GetResource() : NULL); }
+ gr_surface GetResource() { return mSurfaces.empty() ? NULL : mSurfaces.at(0); }
+ gr_surface GetResource(int entry) { return mSurfaces.empty() ? NULL : mSurfaces.at(entry); }
+ int GetWidth() { return gr_get_width(GetResource()); }
+ int GetHeight() { return gr_get_height(GetResource()); }
int GetResourceCount() { return mSurfaces.size(); }
protected:
diff --git a/gui/scrolllist.cpp b/gui/scrolllist.cpp
index 7540356..ecfb5fe 100644
--- a/gui/scrolllist.cpp
+++ b/gui/scrolllist.cpp
@@ -32,7 +32,6 @@
GUIScrollList::GUIScrollList(xml_node<>* node) : GUIObject(node)
{
- xml_attribute<>* attr;
xml_node<>* child;
firstDisplayedItem = mItemSpacing = mFontHeight = mSeparatorH = y_offset = scrollingSpeed = 0;
@@ -265,8 +264,10 @@
}
// render the text
- gr_color(mHeaderFontColor.red, mHeaderFontColor.green, mHeaderFontColor.blue, mHeaderFontColor.alpha);
- gr_textEx_scaleW(mRenderX + IconOffsetX + 5, yPos + (int)(mHeaderH / 2), mLastHeaderValue.c_str(), mFont->GetResource(), mRenderW, TEXT_ONLY_RIGHT, 0);
+ if (mFont && mFont->GetResource()) {
+ gr_color(mHeaderFontColor.red, mHeaderFontColor.green, mHeaderFontColor.blue, mHeaderFontColor.alpha);
+ gr_textEx_scaleW(mRenderX + IconOffsetX + 5, yPos + (int)(mHeaderH / 2), mLastHeaderValue.c_str(), mFont->GetResource(), mRenderW, TEXT_ONLY_RIGHT, 0);
+ }
// Add the separator
gr_color(mHeaderSeparatorColor.red, mHeaderSeparatorColor.green, mHeaderSeparatorColor.blue, mHeaderSeparatorColor.alpha);
@@ -345,9 +346,11 @@
}
// render label text
- int textX = mRenderX + maxIconWidth + 5;
- int textY = yPos + (iconAndTextH / 2);
- gr_textEx_scaleW(textX, textY, text, mFont->GetResource(), mRenderW, TEXT_ONLY_RIGHT, 0);
+ if (mFont && mFont->GetResource()) {
+ int textX = mRenderX + maxIconWidth + 5;
+ int textY = yPos + (iconAndTextH / 2);
+ gr_textEx_scaleW(textX, textY, text, mFont->GetResource(), mRenderW, TEXT_ONLY_RIGHT, 0);
+ }
}
int GUIScrollList::Update(void)
@@ -610,6 +613,8 @@
bool GUIScrollList::AddLines(std::vector<std::string>* origText, std::vector<std::string>* origColor, size_t* lastCount, std::vector<std::string>* rText, std::vector<std::string>* rColor)
{
+ if (!mFont || !mFont->GetResource())
+ return false;
if (*lastCount == origText->size())
return false; // nothing to add
diff --git a/gui/slider.cpp b/gui/slider.cpp
index ed5c615..fab5a2e 100644
--- a/gui/slider.cpp
+++ b/gui/slider.cpp
@@ -47,7 +47,6 @@
GUISlider::GUISlider(xml_node<>* node) : GUIObject(node)
{
- xml_attribute<>* attr;
xml_node<>* child;
sAction = NULL;
@@ -84,8 +83,12 @@
Placement TextPlacement = CENTER;
LoadPlacement(FindNode(node, "placement"), &mRenderX, &mRenderY, &mRenderW, &mRenderH, &TextPlacement);
- mRenderW = sSlider->GetWidth();
- mRenderH = sSlider->GetHeight();
+ if (sSlider && sSlider->GetResource()) {
+ mRenderW = sSlider->GetWidth();
+ mRenderH = sSlider->GetHeight();
+ } else {
+ mRenderW = mRenderH = 0;
+ }
if (TextPlacement == CENTER || TextPlacement == CENTER_X_ONLY) {
mRenderX = mRenderX - (mRenderW / 2);
if (TextPlacement == CENTER) {
diff --git a/gui/slidervalue.cpp b/gui/slidervalue.cpp
index 6f007e2..3aaffcc 100644
--- a/gui/slidervalue.cpp
+++ b/gui/slidervalue.cpp
@@ -172,7 +172,10 @@
mSliderH = LoadAttrIntScaleY(child, "sliderh", mSliderH);
}
- mFontHeight = mFont->GetHeight();
+ if (mFont && mFont->GetResource())
+ mFontHeight = mFont->GetHeight();
+ else
+ mFontHeight = 0;
if (mShowCurr)
{
diff --git a/gui/terminal.cpp b/gui/terminal.cpp
index 65ad2c0..b1799ce 100644
--- a/gui/terminal.cpp
+++ b/gui/terminal.cpp
@@ -861,9 +861,12 @@
return engine->getLinesCount();
}
-void GUITerminal::RenderItem(size_t itemindex, int yPos, bool selected)
+void GUITerminal::RenderItem(size_t itemindex, int yPos, bool selected __unused)
{
const TerminalEngine::Line& line = engine->getLine(itemindex);
+
+ if (!mFont || !mFont->GetResource())
+ return;
gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, mFontColor.alpha);
// later: handle attributes here
@@ -887,7 +890,7 @@
}
}
-void GUITerminal::NotifySelect(size_t item_selected)
+void GUITerminal::NotifySelect(size_t item_selected __unused)
{
// do nothing - terminal ignores selections
}
@@ -897,8 +900,10 @@
// make sure the shell is started
engine->initPty();
// send window resize
- int charWidth = gr_ttf_measureEx("N", mFont->GetResource());
- engine->setSize(mRenderW / charWidth, GetDisplayItemCount(), mRenderW, mRenderH);
+ if (mFont && mFont->GetResource()) {
+ int charWidth = gr_ttf_measureEx("N", mFont->GetResource());
+ engine->setSize(mRenderW / charWidth, GetDisplayItemCount(), mRenderW, mRenderH);
+ }
}
void GUITerminal::SetPageFocus(int inFocus)
diff --git a/gui/text.cpp b/gui/text.cpp
index 61940ff..123b249 100644
--- a/gui/text.cpp
+++ b/gui/text.cpp
@@ -64,7 +64,7 @@
// Load the font, and possibly override the color
mFont = LoadAttrFont(FindNode(node, "font"), "resource");
- if (!mFont)
+ if (!mFont || !mFont->GetResource())
return;
mColor = LoadAttrColor(FindNode(node, "font"), "color", mColor);
mHighlightColor = LoadAttrColor(FindNode(node, "font"), "highlightcolor", mColor);
diff --git a/gui/textbox.cpp b/gui/textbox.cpp
index 2c7d09f..824daf3 100644
--- a/gui/textbox.cpp
+++ b/gui/textbox.cpp
@@ -81,6 +81,9 @@
void GUITextBox::RenderItem(size_t itemindex, int yPos, bool selected __unused)
{
+ if (!mFont || !mFont->GetResource())
+ return;
+
// Set the color for the font
gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, mFontColor.alpha);
diff --git a/install.cpp b/install.cpp
index 4848755..5d7bda7 100644
--- a/install.cpp
+++ b/install.cpp
@@ -49,9 +49,9 @@
#include <ziparchive/zip_archive.h>
#include "common.h"
-#include "error_code.h"
#include "otautil/SysUtil.h"
#include "otautil/ThermalUtil.h"
+#include "otautil/error_code.h"
#include "private/install.h"
#include "roots.h"
#include "ui.h"
@@ -148,13 +148,23 @@
return INSTALL_ERROR;
}
- // We allow the package to not have any serialno, but if it has a non-empty
- // value it should match.
+ // 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.
value = android::base::GetProperty("ro.serialno", "");
const std::string& pkg_serial_no = metadata["serialno"];
- if (!pkg_serial_no.empty() && pkg_serial_no != value) {
- LOG(ERROR) << "Package is for serial " << pkg_serial_no;
- return INSTALL_ERROR;
+ if (!pkg_serial_no.empty()) {
+ bool match = false;
+ for (const std::string& number : android::base::Split(pkg_serial_no, "|")) {
+ if (value == android::base::Trim(number)) {
+ match = true;
+ break;
+ }
+ }
+ if (!match) {
+ LOG(ERROR) << "Package is for serial " << pkg_serial_no;
+ return INSTALL_ERROR;
+ }
}
if (metadata["ota-type"] != "AB") {
@@ -258,7 +268,7 @@
*cmd = {
binary_path,
- EXPAND(RECOVERY_API_VERSION), // defined in Android.mk
+ std::to_string(kRecoveryApiVersion),
std::to_string(status_fd),
package,
};
@@ -299,6 +309,7 @@
if (ret) {
close(pipefd[0]);
close(pipefd[1]);
+ log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure));
return ret;
}
@@ -363,6 +374,7 @@
close(pipefd[0]);
close(pipefd[1]);
PLOG(ERROR) << "Failed to fork update binary";
+ log_buffer->push_back(android::base::StringPrintf("error: %d", kForkUpdateBinaryFailure));
return INSTALL_ERROR;
}
@@ -551,6 +563,7 @@
MemMapping map;
if (!map.MapFile(path)) {
LOG(ERROR) << "failed to map file";
+ log_buffer->push_back(android::base::StringPrintf("error: %d", kMapFileFailure));
return INSTALL_CORRUPT;
}
@@ -618,7 +631,7 @@
std::chrono::duration<double> duration = std::chrono::system_clock::now() - start;
int time_total = static_cast<int>(duration.count());
- bool has_cache = volume_for_path("/cache") != nullptr;
+ 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";
diff --git a/installcommand.cpp b/installcommand.cpp
index b306e87..99f4c53 100644
--- a/installcommand.cpp
+++ b/installcommand.cpp
@@ -75,7 +75,7 @@
}
// Read the build.version.incremental of src/tgt from the metadata and log it to last_install.
-static void read_source_target_build(ZipWrap* zip, std::vector<std::string>& log_buffer) {
+void read_source_target_build(ZipWrap* zip/*, std::vector<std::string>& log_buffer*/) {
std::string meta_data;
if (!read_metadata_from_package(zip, &meta_data)) {
return;
@@ -89,14 +89,16 @@
if (android::base::StartsWith(str, "pre-build-incremental")){
int source_build = parse_build_number(str);
if (source_build != -1) {
- log_buffer.push_back(android::base::StringPrintf("source_build: %d",
- source_build));
+ printf("source_build: %d\n", source_build);
+ /*log_buffer.push_back(android::base::StringPrintf("source_build: %d",
+ source_build));*/
}
} else if (android::base::StartsWith(str, "post-build-incremental")) {
int target_build = parse_build_number(str);
if (target_build != -1) {
- log_buffer.push_back(android::base::StringPrintf("target_build: %d",
- target_build));
+ printf("target_build: %d\n", target_build);
+ /*log_buffer.push_back(android::base::StringPrintf("target_build: %d",
+ target_build));*/
}
}
}
@@ -163,9 +165,10 @@
}
int
-abupdate_binary_command(const char* path, ZipWrap* zip, int retry_count,
+abupdate_binary_command(const char* path, ZipWrap* zip, int retry_count __unused,
int status_fd, std::vector<std::string>* cmd)
{
+ read_source_target_build(zip);
int ret = check_newer_ab_build(zip);
if (ret) {
return ret;
@@ -202,6 +205,8 @@
#else
+void read_source_target_build(ZipWrap* zip __unused /*, std::vector<std::string>& log_buffer*/) {return;}
+
int
abupdate_binary_command(__unused const char* path, __unused ZipWrap* zip, __unused int retry_count,
__unused int status_fd, __unused std::vector<std::string>* cmd)
@@ -298,7 +303,7 @@
}
CloseArchive(zip_handle);
- // VintfObjectRecovery::CheckCompatibility returns zero on success.
+ // VintfObjectRecovery::CheckCompatibility returns zero on success. TODO THIS CAUSES A WEIRD COMPILE ERROR
std::string err;
int result = android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err);
if (result == 0) {
diff --git a/installcommand.h b/installcommand.h
index 16c034f..957f016 100644
--- a/installcommand.h
+++ b/installcommand.h
@@ -34,4 +34,6 @@
bool verify_package_compatibility(ZipWrap *package_zip);
+void read_source_target_build(ZipWrap* zip/*, std::vector<std::string>& log_buffer*/);
+
#endif // RECOVERY_INSTALL_COMMAND_H_
diff --git a/legacy_property_service.cpp b/legacy_property_service.cpp
index 90a0d47..c3990f7 100644
--- a/legacy_property_service.cpp
+++ b/legacy_property_service.cpp
@@ -40,11 +40,8 @@
#define INT32_MAX (2147483647)
#endif
-static int persistent_properties_loaded = 0;
static int property_area_inited = 0;
-static int property_set_fd = -1;
-
typedef struct {
void *data;
size_t size;
@@ -203,7 +200,7 @@
*sz = pa_workspace.size;
}
-static void copy_property_to_legacy(const char *key, const char *value, void *cookie)
+static void copy_property_to_legacy(const char *key, const char *value, void *cookie __unused)
{
legacy_property_set(key, value);
}
diff --git a/libblkid/Android.mk b/libblkid/Android.mk
index ab20bf5..42762e4 100644
--- a/libblkid/Android.mk
+++ b/libblkid/Android.mk
@@ -5,7 +5,8 @@
LOCAL_MODULE := libutil-linux
LOCAL_MODULE_TAGS := optional
#LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
-LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -DHAVE_ERR_H -DHAVE_MEMPCPY -DHAVE_FSYNC
+LOCAL_CFLAGS := -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -DHAVE_ERR_H -DHAVE_MEMPCPY -DHAVE_FSYNC
+LOCAL_CFLAGS += -Wno-missing-field-initializers -Wno-sign-compare -Wno-unused-parameter -Wno-format -Wno-pointer-arith
LOCAL_SRC_FILES = lib/at.c \
lib/blkdev.c \
lib/canonicalize.c \
@@ -43,7 +44,8 @@
LOCAL_MODULE := libuuid
LOCAL_MODULE_TAGS := optional
#LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
-LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -DHAVE_ERR_H -DHAVE_MEMPCPY -DHAVE_FSYNC
+LOCAL_CFLAGS := -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -DHAVE_ERR_H -DHAVE_MEMPCPY -DHAVE_FSYNC
+LOCAL_CFLAGS += -Wno-missing-field-initializers -Wno-sign-compare -Wno-unused-parameter -Wno-format -Wno-pointer-arith
LOCAL_SRC_FILES = libuuid/src/clear.c \
libuuid/src/copy.c \
libuuid/src/isnull.c \
@@ -69,7 +71,8 @@
LOCAL_MODULE := libfdisk
LOCAL_MODULE_TAGS := optional
#LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
-LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -DHAVE_ERR_H -DHAVE_MEMPCPY -DHAVE_FSYNC
+LOCAL_CFLAGS := -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -DHAVE_ERR_H -DHAVE_MEMPCPY -DHAVE_FSYNC
+LOCAL_CFLAGS += -Wno-missing-field-initializers -Wno-sign-compare -Wno-unused-parameter -Wno-format -Wno-pointer-arith
LOCAL_SRC_FILES = libfdisk/src/alignment.c \
libfdisk/src/context.c \
libfdisk/src/init.c \
@@ -101,7 +104,8 @@
LOCAL_MODULE := libblkid
LOCAL_MODULE_TAGS := optional
#LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
-LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -DHAVE_ERR_H -DHAVE_MEMPCPY -DHAVE_FSYNC
+LOCAL_CFLAGS := -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -DHAVE_ERR_H -DHAVE_MEMPCPY -DHAVE_FSYNC
+LOCAL_CFLAGS += -Wno-missing-field-initializers -Wno-sign-compare -Wno-unused-parameter -Wno-format -Wno-pointer-arith
LOCAL_SRC_FILES = src/cache.c \
src/config.c \
src/dev.c \
diff --git a/libblkid/lib/ismounted.c b/libblkid/lib/ismounted.c
index 8099bd7..00b575c 100644
--- a/libblkid/lib/ismounted.c
+++ b/libblkid/lib/ismounted.c
@@ -327,7 +327,7 @@
retval = check_getmntinfo(device, mount_flags, mtpt, mtlen);
#else
#ifdef __GNUC__
- #warning "Can't use getmntent or getmntinfo to check for mounted filesystems!"
+ //#warning "Can't use getmntent or getmntinfo to check for mounted filesystems!"
#endif
*mount_flags = 0;
#endif /* HAVE_GETMNTINFO */
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index 1cbde57..026e8ad 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -104,6 +104,7 @@
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
+LOCAL_CPPFLAGS := -Wno-unused-function
LOCAL_C_INCLUDES_x86 := $(PIXELFLINGER_C_INCLUDES_x86)
ifeq ($(TW_HAVE_X86_ACCELERATED_PIXELFLINGER),true)
LOCAL_WHOLE_STATIC_LIBRARIES += libenc
diff --git a/libtar/append.c b/libtar/append.c
index 66e3aa1..8f09de2 100644
--- a/libtar/append.c
+++ b/libtar/append.c
@@ -416,8 +416,7 @@
tar_append_buffer(TAR *t, void *buf, size_t len)
{
char block[T_BLOCKSIZE];
- int filefd;
- int i, j;
+ int i;
size_t size = len;
for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
diff --git a/libtar/basename.c b/libtar/basename.c
index 32108d6..3f4d315 100644
--- a/libtar/basename.c
+++ b/libtar/basename.c
@@ -28,7 +28,7 @@
*/
#ifndef lint
-static char rcsid[] = "$OpenBSD: basename.c,v 1.4 1999/05/30 17:10:30 espie Exp $";
+//static char rcsid[] = "$OpenBSD: basename.c,v 1.4 1999/05/30 17:10:30 espie Exp $";
#endif /* not lint */
#include <errno.h>
diff --git a/libtar/block.c b/libtar/block.c
index d0adb2b..834c164 100644
--- a/libtar/block.c
+++ b/libtar/block.c
@@ -357,7 +357,8 @@
if (*start == '2')
{
start++;
- if (start + sizeof(struct ext4_encryption_policy) != '\n')
+ char *newline_check = start + sizeof(struct ext4_encryption_policy);
+ if (*newline_check != '\n')
printf("did not find newline char in expected location, continuing anyway...\n");
memcpy(t->th_buf.eep, start, sizeof(struct ext4_encryption_policy));
#ifdef DEBUG
diff --git a/libtar/dirname.c b/libtar/dirname.c
index 4e06067..31dbe13 100644
--- a/libtar/dirname.c
+++ b/libtar/dirname.c
@@ -28,7 +28,7 @@
*/
#ifndef lint
-static char rcsid[] = "$OpenBSD: dirname.c,v 1.4 1999/05/30 17:10:30 espie Exp $";
+//static char rcsid[] = "$OpenBSD: dirname.c,v 1.4 1999/05/30 17:10:30 espie Exp $";
#endif /* not lint */
#include <errno.h>
diff --git a/libtar/extract.c b/libtar/extract.c
index fcd403a..ea86c23 100644
--- a/libtar/extract.c
+++ b/libtar/extract.c
@@ -12,6 +12,7 @@
#include <internal.h>
+#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <sys/param.h>
@@ -227,7 +228,7 @@
if (mkdirhier(dirname(filename)) == -1)
return -1;
- printf(" ==> extracting: %s (file size %lld bytes)\n",
+ printf(" ==> extracting: %s (file size %" PRId64 " bytes)\n",
filename, size);
fdout = open(filename, O_WRONLY | O_CREAT | O_TRUNC
diff --git a/libtar/handle.c b/libtar/handle.c
index 28a7dc2..a26c094 100644
--- a/libtar/handle.c
+++ b/libtar/handle.c
@@ -32,7 +32,7 @@
static int
tar_init(TAR **t, const char *pathname, tartype_t *type,
- int oflags, int mode, int options)
+ int oflags, int mode __unused, int options)
{
if ((oflags & O_ACCMODE) == O_RDWR)
{
diff --git a/minadbd/Android.mk b/minadbd/Android.mk
index dfeb85e..a50d844 100644
--- a/minadbd/Android.mk
+++ b/minadbd/Android.mk
@@ -1,14 +1,26 @@
# Copyright 2005 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
LOCAL_PATH:= $(call my-dir)
minadbd_cflags := \
-Wall -Werror \
- -Wno-unused-parameter \
- -Wno-missing-field-initializers \
-DADB_HOST=0 \
-DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION)
+# libminadbd (static library)
+# ===============================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
@@ -17,9 +29,8 @@
minadbd.cpp \
minadbd_services.cpp \
-LOCAL_CLANG := true
LOCAL_MODULE := libminadbd
-LOCAL_CFLAGS := $(minadbd_cflags)
+LOCAL_CFLAGS := $(minadbd_cflags) -Wno-unused-parameter
LOCAL_CONLY_FLAGS := -Wimplicit-function-declaration
LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. system/core/adb
LOCAL_WHOLE_STATIC_LIBRARIES := libadbd
@@ -32,6 +43,10 @@
else
LOCAL_SHARED_LIBRARIES += libcrypto \
$(if $(WITH_CRYPTO_UTILS),libcrypto_utils)
+ ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 27; echo $$?),0)
+ # Needed in Android 9.0
+ LOCAL_WHOLE_STATIC_LIBRARIES += libasyncio
+ endif
endif
include $(BUILD_SHARED_LIBRARY)
@@ -46,7 +61,7 @@
LOCAL_CLANG := true
LOCAL_MODULE := libminadbd
-LOCAL_CFLAGS := $(minadbd_cflags)
+LOCAL_CFLAGS := $(minadbd_cflags) -Wno-unused-parameter
LOCAL_CONLY_FLAGS := -Wimplicit-function-declaration
LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. system/core/adb
LOCAL_WHOLE_STATIC_LIBRARIES := libadbd
@@ -59,19 +74,29 @@
else
LOCAL_SHARED_LIBRARIES += libcrypto \
$(if $(WITH_CRYPTO_UTILS),libcrypto_utils)
+ ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 27; echo $$?),0)
+ # Needed in Android 9.0
+ LOCAL_WHOLE_STATIC_LIBRARIES += libasyncio
+ endif
endif
include $(BUILD_STATIC_LIBRARY)
+# minadbd_test (native test)
+# ===============================
include $(CLEAR_VARS)
-LOCAL_CLANG := true
LOCAL_MODULE := minadbd_test
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_SRC_FILES := fuse_adb_provider_test.cpp
LOCAL_CFLAGS := $(minadbd_cflags)
LOCAL_C_INCLUDES := $(LOCAL_PATH) system/core/adb
-LOCAL_STATIC_LIBRARIES := libminadbd
-LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
+LOCAL_STATIC_LIBRARIES := \
+ libBionicGtestMain \
+ libminadbd
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libbase \
+ libcutils
include $(BUILD_NATIVE_TEST)
diff --git a/minadbd/fuse_adb_provider.cpp b/minadbd/fuse_adb_provider.cpp
index 0f4c256..9bd3f23 100644
--- a/minadbd/fuse_adb_provider.cpp
+++ b/minadbd/fuse_adb_provider.cpp
@@ -14,46 +14,43 @@
* limitations under the License.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "fuse_adb_provider.h"
+
#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <functional>
#include "adb.h"
#include "adb_io.h"
-#include "fuse_adb_provider.h"
#include "fuse_sideload.h"
-int read_block_adb(void* data, uint32_t block, uint8_t* buffer, uint32_t fetch_size) {
- adb_data* ad = reinterpret_cast<adb_data*>(data);
+int read_block_adb(const adb_data& ad, uint32_t block, uint8_t* buffer, uint32_t fetch_size) {
+ if (!WriteFdFmt(ad.sfd, "%08u", block)) {
+ fprintf(stderr, "failed to write to adb host: %s\n", strerror(errno));
+ return -EIO;
+ }
- if (!WriteFdFmt(ad->sfd, "%08u", block)) {
- fprintf(stderr, "failed to write to adb host: %s\n", strerror(errno));
- return -EIO;
- }
+ if (!ReadFdExactly(ad.sfd, buffer, fetch_size)) {
+ fprintf(stderr, "failed to read from adb host: %s\n", strerror(errno));
+ return -EIO;
+ }
- if (!ReadFdExactly(ad->sfd, buffer, fetch_size)) {
- fprintf(stderr, "failed to read from adb host: %s\n", strerror(errno));
- return -EIO;
- }
-
- return 0;
-}
-
-static void close_adb(void* data) {
- adb_data* ad = reinterpret_cast<adb_data*>(data);
- WriteFdExactly(ad->sfd, "DONEDONE");
+ return 0;
}
int run_adb_fuse(int sfd, uint64_t file_size, uint32_t block_size) {
- adb_data ad;
- ad.sfd = sfd;
- ad.file_size = file_size;
- ad.block_size = block_size;
+ adb_data ad;
+ ad.sfd = sfd;
+ ad.file_size = file_size;
+ ad.block_size = block_size;
- provider_vtab vtab;
- vtab.read_block = read_block_adb;
- vtab.close = close_adb;
+ provider_vtab vtab;
+ vtab.read_block = std::bind(read_block_adb, ad, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3);
+ vtab.close = [&ad]() { WriteFdExactly(ad.sfd, "DONEDONE"); };
- return run_fuse_sideload(&vtab, &ad, file_size, block_size);
+ return run_fuse_sideload(vtab, file_size, block_size);
}
diff --git a/minadbd/fuse_adb_provider.h b/minadbd/fuse_adb_provider.h
index 9941709..36d86d5 100644
--- a/minadbd/fuse_adb_provider.h
+++ b/minadbd/fuse_adb_provider.h
@@ -20,13 +20,13 @@
#include <stdint.h>
struct adb_data {
- int sfd; // file descriptor for the adb channel
+ int sfd; // file descriptor for the adb channel
- uint64_t file_size;
- uint32_t block_size;
+ uint64_t file_size;
+ uint32_t block_size;
};
-int read_block_adb(void* cookie, uint32_t block, uint8_t* buffer, uint32_t fetch_size);
+int read_block_adb(const adb_data& ad, uint32_t block, uint8_t* buffer, uint32_t fetch_size);
int run_adb_fuse(int sfd, uint64_t file_size, uint32_t block_size);
#endif
diff --git a/minadbd/fuse_adb_provider_test.cpp b/minadbd/fuse_adb_provider_test.cpp
index 31be2a6..00250e5 100644
--- a/minadbd/fuse_adb_provider_test.cpp
+++ b/minadbd/fuse_adb_provider_test.cpp
@@ -46,8 +46,8 @@
uint32_t block = 1234U;
const char expected_block[] = "00001234";
- ASSERT_EQ(0, read_block_adb(static_cast<void*>(&data), block,
- reinterpret_cast<uint8_t*>(block_data), sizeof(expected_data) - 1));
+ ASSERT_EQ(0, read_block_adb(data, block, reinterpret_cast<uint8_t*>(block_data),
+ sizeof(expected_data) - 1));
// Check that read_block_adb requested the right block.
char block_req[sizeof(expected_block)] = {};
@@ -84,7 +84,7 @@
signal(SIGPIPE, SIG_IGN);
char buf[1];
- ASSERT_EQ(-EIO, read_block_adb(static_cast<void*>(&data), 0, reinterpret_cast<uint8_t*>(buf), 1));
+ ASSERT_EQ(-EIO, read_block_adb(data, 0, reinterpret_cast<uint8_t*>(buf), 1));
close(sockets[0]);
}
diff --git a/minadbd/minadbd_services.cpp b/minadbd/minadbd_services.cpp
index 6919cdd..03692d0 100644
--- a/minadbd/minadbd_services.cpp
+++ b/minadbd/minadbd_services.cpp
@@ -117,26 +117,30 @@
}
#endif
-int service_to_fd(const char* name, const atransport* transport) {
- 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)) {
-#if PLATFORM_SDK_VERSION < 26
- char* arg = strdup(name + 14);
+#if PLATFORM_SDK_VERSION >= 28
+int service_to_fd(const char* name, atransport* /* transport */) {
#else
- std::string arg(name + 14);
+int service_to_fd(const char* name, const atransport* transport __unused) {
#endif
- ret = create_service_thread(sideload_host_service, arg);
- }
- if (ret >= 0) {
- close_on_exec(ret);
- }
- return ret;
+ 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)) {
+#if PLATFORM_SDK_VERSION < 26
+ char* arg = strdup(name + 14);
+#else
+ std::string arg(name + 14);
+#endif
+ ret = create_service_thread(sideload_host_service, arg);
+ }
+ if (ret >= 0) {
+ close_on_exec(ret);
+ }
+ return ret;
}
#if PLATFORM_SDK_VERSION == 23
diff --git a/minadbd21/Android.mk b/minadbd21/Android.mk
index 19c8b60..201c795 100644
--- a/minadbd21/Android.mk
+++ b/minadbd21/Android.mk
@@ -23,6 +23,7 @@
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 := eng
LOCAL_MODULE := libminadbd
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../
diff --git a/minui/Android.mk b/minui/Android.mk
index cb56b73..ddec62b 100644
--- a/minui/Android.mk
+++ b/minui/Android.mk
@@ -13,6 +13,9 @@
# limitations under the License.
LOCAL_PATH := $(call my-dir)
+
+# libminui (static library)
+# ===============================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
@@ -33,13 +36,13 @@
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
else
ifeq ($(TARGET_CUSTOM_KERNEL_HEADERS),)
- LOCAL_C_INCLUDES += $(commands_recovery_local_path)/minui/include
+ LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
else
LOCAL_C_INCLUDES += $(TARGET_CUSTOM_KERNEL_HEADERS)
endif
endif
else
- LOCAL_C_INCLUDES += $(commands_recovery_local_path)/minui/include
+ LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
# The header files required for adf graphics can cause compile errors
# with adf graphics.
LOCAL_SRC_FILES += graphics_adf.cpp
@@ -50,7 +53,7 @@
LOCAL_CFLAGS += -DNEW_ION_HEAP
endif
-LOCAL_STATIC_LIBRARIES += libpng
+LOCAL_STATIC_LIBRARIES += libpng libbase
ifneq ($(wildcard external/libdrm/Android.common.mk),)
LOCAL_WHOLE_STATIC_LIBRARIES += libdrm_platform
else
@@ -61,11 +64,7 @@
LOCAL_WHOLE_STATIC_LIBRARIES += libsync_recovery
endif
-LOCAL_STATIC_LIBRARIES := \
- libpng \
- libbase
-
-LOCAL_CFLAGS += -Werror -std=c++14
+LOCAL_CFLAGS += -Wall -Werror -std=c++14 -Wno-unused-private-field
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
@@ -114,8 +113,16 @@
TARGET_GLOBAL_CFLAGS += -DTW_NO_MINUI_CUSTOM_FONTS
CLANG_TARGET_GLOBAL_CFLAGS += -DTW_NO_MINUI_CUSTOM_FONTS
endif
+ifneq ($(TARGET_RECOVERY_DEFAULT_ROTATION),)
+ LOCAL_CFLAGS += -DDEFAULT_ROTATION=$(TARGET_RECOVERY_DEFAULT_ROTATION)
+else
+ LOCAL_CFLAGS += -DDEFAULT_ROTATION=ROTATION_NONE
+endif
+
include $(BUILD_STATIC_LIBRARY)
+# libminui (shared library)
+# ===============================
# Used by OEMs for factory test images.
include $(CLEAR_VARS)
LOCAL_CLANG := true
@@ -125,8 +132,7 @@
libpng \
libbase
-LOCAL_CFLAGS := -Werror
-
+LOCAL_CFLAGS := -Wall -Werror -std=c++14 -Wno-unused-private-field
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
include $(BUILD_SHARED_LIBRARY)
diff --git a/minui/events.cpp b/minui/events.cpp
index e9383ca..f67684b 100644
--- a/minui/events.cpp
+++ b/minui/events.cpp
@@ -15,6 +15,7 @@
*/
#include <dirent.h>
+#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <stdio.h>
diff --git a/minui/graphics.cpp b/minui/graphics.cpp
index b45e22e..f3380aa 100644
--- a/minui/graphics.cpp
+++ b/minui/graphics.cpp
@@ -16,6 +16,7 @@
#include "graphics.h"
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -43,20 +44,26 @@
static int overscan_offset_x = 0;
static int overscan_offset_y = 0;
+#ifdef TW_NO_MINUI_CUSTOM_FONTS
static unsigned char gr_current_r = 255;
static unsigned char gr_current_g = 255;
static unsigned char gr_current_b = 255;
+#endif
static unsigned char gr_current_a = 255;
static unsigned char rgb_555[2];
static unsigned char gr_current_r5 = 31;
static unsigned char gr_current_g5 = 63;
static unsigned char gr_current_b5 = 31;
-static GRSurface* gr_draw = NULL;
+static uint32_t gr_current = ~0;
+static constexpr uint32_t alpha_mask = 0xff000000;
-static bool outside(int x, int y)
-{
- return x < 0 || x >= gr_draw->width || y < 0 || y >= gr_draw->height;
+static GRSurface* gr_draw = NULL;
+static GRRotation rotation = ROTATION_NONE;
+
+static bool outside(int x, int y) {
+ return x < 0 || x >= (rotation % 2 ? gr_draw->height : gr_draw->width) || y < 0 ||
+ y >= (rotation % 2 ? gr_draw->width : gr_draw->height);
}
#ifdef TW_NO_MINUI_CUSTOM_FONTS
@@ -71,20 +78,17 @@
*y = gr_font->char_height;
}
#else // TW_USE_MINUI_CUSTOM_FONTS
-const GRFont* gr_sys_font()
-{
- return gr_font;
+const GRFont* gr_sys_font() {
+ return gr_font;
}
-int gr_measure(const GRFont* font, const char *s)
-{
- return font->char_width * strlen(s);
+int gr_measure(const GRFont* font, const char* s) {
+ return font->char_width * strlen(s);
}
-void gr_font_size(const GRFont* font, int *x, int *y)
-{
- *x = font->char_width;
- *y = font->char_height;
+void gr_font_size(const GRFont* font, int* x, int* y) {
+ *x = font->char_width;
+ *y = font->char_height;
}
#endif // TW_NO_MINUI_CUSTOM_FONTS
@@ -112,7 +116,8 @@
*px++ = (newred << 3) + (newgreen >> 3);
}
-static void text_blend(unsigned char* src_p, int src_row_bytes,
+#ifdef TW_NO_MINUI_CUSTOM_FONTS
+static void text_blend_old(unsigned char* src_p, int src_row_bytes,
unsigned char* dst_p, int dst_row_bytes,
int width, int height)
{
@@ -153,6 +158,154 @@
dst_p += dst_row_bytes;
}
}
+#endif // TW_NO_MINUI_CUSTOM_FONTS
+
+// Blends gr_current onto pix value, assumes alpha as most significant byte.
+static inline uint16_t pixel_blend16(uint8_t a, uint16_t pix) {
+ unsigned char orig[2];
+ orig[0] = (pix & 0xFF00) >> 8;
+ orig[1] = pix & 0x00FF;
+
+ /* This code is a little easier to read
+ unsigned oldred = (orig[1] >> 3);
+ unsigned oldgreen = (((orig[0] >> 5) << 3) + (orig[1] & 0x7));
+ unsigned oldblue = (orig[0] & 0x1F);
+
+ unsigned newred = (oldred * (255-a) + r5 * a) / 255;
+ unsigned newgreen = (oldgreen * (255-a) + g5 * a) / 255;
+ unsigned newblue = (oldblue * (255-a) + b5 * a) / 255;
+ */
+
+ unsigned newred = ((orig[1] >> 3) * (255-a) + gr_current_r5 * a) / 255;
+ unsigned newgreen = ((((orig[0] >> 5) << 3) + (orig[1] & 0x7)) * (255-a) + gr_current_g5 * a) / 255;
+ unsigned newblue = ((orig[0] & 0x1F) * (255-a) + gr_current_b5 * a) / 255;
+
+ uint16_t newpix = (newred << 10) + (newgreen << 5) + newblue;
+ return newpix;
+}
+
+// Blends gr_current onto pix value, assumes alpha as most significant byte.
+static inline uint32_t pixel_blend(uint8_t alpha, uint32_t pix) {
+ if (alpha == 255) return gr_current;
+ if (alpha == 0) return pix;
+ uint32_t pix_r = pix & 0xff;
+ uint32_t pix_g = pix & 0xff00;
+ uint32_t pix_b = pix & 0xff0000;
+ uint32_t cur_r = gr_current & 0xff;
+ uint32_t cur_g = gr_current & 0xff00;
+ uint32_t cur_b = gr_current & 0xff0000;
+
+ uint32_t out_r = (pix_r * (255 - alpha) + cur_r * alpha) / 255;
+ uint32_t out_g = (pix_g * (255 - alpha) + cur_g * alpha) / 255;
+ uint32_t out_b = (pix_b * (255 - alpha) + cur_b * alpha) / 255;
+
+ return (out_r & 0xff) | (out_g & 0xff00) | (out_b & 0xff0000) | (gr_current & 0xff000000);
+}
+
+// increments pixel pointer right, with current rotation.
+static void incr_x16(uint16_t** p, int row_pixels) {
+ if (rotation % 2) {
+ *p = *p + (rotation == 1 ? 1 : -1) * row_pixels;
+ } else {
+ *p = *p + (rotation ? -1 : 1);
+ }
+}
+
+// increments pixel pointer down, with current rotation.
+static void incr_y16(uint16_t** p, int row_pixels) {
+ if (rotation % 2) {
+ *p = *p + (rotation == 1 ? -1 : 1);
+ } else {
+ *p = *p + (rotation ? -1 : 1) * row_pixels;
+ }
+}
+
+// increments pixel pointer right, with current rotation.
+static void incr_x(uint32_t** p, int row_pixels) {
+ if (rotation % 2) {
+ *p = *p + (rotation == 1 ? 1 : -1) * row_pixels;
+ } else {
+ *p = *p + (rotation ? -1 : 1);
+ }
+}
+
+// increments pixel pointer down, with current rotation.
+static void incr_y(uint32_t** p, int row_pixels) {
+ if (rotation % 2) {
+ *p = *p + (rotation == 1 ? -1 : 1);
+ } else {
+ *p = *p + (rotation ? -1 : 1) * row_pixels;
+ }
+}
+
+// returns pixel pointer at given coordinates with rotation adjustment.
+static uint16_t* pixel_at16(GRSurface* surf, int x, int y, int row_pixels) {
+ switch (rotation) {
+ case ROTATION_NONE:
+ return reinterpret_cast<uint16_t*>(surf->data) + y * row_pixels + x;
+ case ROTATION_RIGHT:
+ return reinterpret_cast<uint16_t*>(surf->data) + x * row_pixels + (surf->width - y);
+ case ROTATION_DOWN:
+ return reinterpret_cast<uint16_t*>(surf->data) + (surf->height - 1 - y) * row_pixels +
+ (surf->width - 1 - x);
+ case ROTATION_LEFT:
+ return reinterpret_cast<uint16_t*>(surf->data) + (surf->height - 1 - x) * row_pixels + y;
+ default:
+ printf("invalid rotation %d", rotation);
+ }
+ return nullptr;
+}
+
+// returns pixel pointer at given coordinates with rotation adjustment.
+static uint32_t* pixel_at(GRSurface* surf, int x, int y, int row_pixels) {
+ switch (rotation) {
+ case ROTATION_NONE:
+ return reinterpret_cast<uint32_t*>(surf->data) + y * row_pixels + x;
+ case ROTATION_RIGHT:
+ return reinterpret_cast<uint32_t*>(surf->data) + x * row_pixels + (surf->width - y);
+ case ROTATION_DOWN:
+ return reinterpret_cast<uint32_t*>(surf->data) + (surf->height - 1 - y) * row_pixels +
+ (surf->width - 1 - x);
+ case ROTATION_LEFT:
+ return reinterpret_cast<uint32_t*>(surf->data) + (surf->height - 1 - x) * row_pixels + y;
+ default:
+ printf("invalid rotation %d", rotation);
+ }
+ return nullptr;
+}
+
+static void text_blend16(uint8_t* src_p, int src_row_bytes, uint16_t* dst_p, int dst_row_pixels,
+ int width, int height) {
+ uint8_t alpha_current = static_cast<uint8_t>((alpha_mask & gr_current) >> 24);
+ for (int j = 0; j < height; ++j) {
+ uint8_t* sx = src_p;
+ uint16_t* px = dst_p;
+ for (int i = 0; i < width; ++i, incr_x16(&px, dst_row_pixels)) {
+ uint8_t a = *sx++;
+ if (alpha_current < 255) a = (static_cast<uint32_t>(a) * alpha_current) / 255;
+ *px = pixel_blend16(a, *px);
+ }
+ src_p += src_row_bytes;
+ incr_y16(&dst_p, dst_row_pixels);
+ }
+}
+
+static void text_blend(uint8_t* src_p, int src_row_bytes, uint32_t* dst_p, int dst_row_pixels,
+ int width, int height) {
+ uint8_t alpha_current = static_cast<uint8_t>((alpha_mask & gr_current) >> 24);
+ for (int j = 0; j < height; ++j) {
+ uint8_t* sx = src_p;
+ uint32_t* px = dst_p;
+ for (int i = 0; i < width; ++i, incr_x(&px, dst_row_pixels)) {
+ uint8_t a = *sx++;
+ if (alpha_current < 255) a = (static_cast<uint32_t>(a) * alpha_current) / 255;
+ *px = pixel_blend(a, *px);
+ }
+ src_p += src_row_bytes;
+ incr_y(&dst_p, dst_row_pixels);
+ }
+}
+
#ifdef TW_NO_MINUI_CUSTOM_FONTS
void gr_text(int x, int y, const char *s, bool bold)
@@ -178,248 +331,284 @@
(bold ? font->char_height * font->texture->row_bytes : 0);
unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes;
- text_blend(src_p, font->texture->row_bytes,
- dst_p, gr_draw->row_bytes,
- font->char_width, font->char_height);
+ text_blend_old(src_p, font->texture->row_bytes,
+ dst_p, gr_draw->row_bytes,
+ font->char_width, font->char_height);
x += font->char_width;
}
}
#else //TW_NO_MINUI_CUSTOM_FONTS
-void gr_text(const GRFont* font, int x, int y, const char *s, bool bold)
-{
- if (!font->texture || gr_current_a == 0) return;
+void gr_text(const GRFont* font, int x, int y, const char* s, bool bold) {
+ if (!font || !font->texture || (gr_current & alpha_mask) == 0) return;
- bold = bold && (font->texture->height != font->char_height);
+ if (font->texture->pixel_bytes != 1) {
+ printf("gr_text: font has wrong format\n");
+ return;
+ }
- x += overscan_offset_x;
- y += overscan_offset_y;
+ bold = bold && (font->texture->height != font->char_height);
- unsigned char ch;
- while ((ch = *s++)) {
- if (outside(x, y) || outside(x+font->char_width-1, y+font->char_height-1)) break;
+ x += overscan_offset_x;
+ y += overscan_offset_y;
- if (ch < ' ' || ch > '~') {
- ch = '?';
- }
+ unsigned char ch;
+ while ((ch = *s++)) {
+ if (outside(x, y) || outside(x + font->char_width - 1, y + font->char_height - 1)) break;
- unsigned char* src_p = font->texture->data + ((ch - ' ') * font->char_width) +
- (bold ? font->char_height * font->texture->row_bytes : 0);
- unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes;
-
- text_blend(src_p, font->texture->row_bytes,
- dst_p, gr_draw->row_bytes,
- font->char_width, font->char_height);
-
- x += font->char_width;
+ if (ch < ' ' || ch > '~') {
+ ch = '?';
}
+
+ int row_pixels = gr_draw->row_bytes / gr_draw->pixel_bytes;
+
+ uint8_t* src_p = font->texture->data + ((ch - ' ') * font->char_width) +
+ (bold ? font->char_height * font->texture->row_bytes : 0);
+ if (gr_draw->pixel_bytes == 2) {
+ uint16_t* dst_p = pixel_at16(gr_draw, x, y, row_pixels);
+
+ text_blend16(src_p, font->texture->row_bytes, dst_p, row_pixels, font->char_width,
+ font->char_height);
+ } else { // not indenting AOSP original code
+ uint32_t* dst_p = pixel_at(gr_draw, x, y, row_pixels);
+
+ text_blend(src_p, font->texture->row_bytes, dst_p, row_pixels, font->char_width,
+ font->char_height);
+ }
+ x += font->char_width;
+ }
}
#endif //TW_NO_MINUI_CUSTOM_FONTS
void gr_texticon(int x, int y, GRSurface* icon) {
- if (icon == NULL) return;
+ if (icon == NULL) return;
- if (icon->pixel_bytes != 1) {
- printf("gr_texticon: source has wrong format\n");
- return;
- }
+ if (icon->pixel_bytes != 1) {
+ printf("gr_texticon: source has wrong format\n");
+ return;
+ }
- x += overscan_offset_x;
- y += overscan_offset_y;
+ x += overscan_offset_x;
+ y += overscan_offset_y;
- if (outside(x, y) || outside(x+icon->width-1, y+icon->height-1)) return;
+ if (outside(x, y) || outside(x + icon->width - 1, y + icon->height - 1)) return;
- unsigned char* src_p = icon->data;
- unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes;
+ int row_pixels = gr_draw->row_bytes / gr_draw->pixel_bytes;
+ uint8_t* src_p = icon->data;
+ if (gr_draw->pixel_bytes == 2) {
+ uint16_t* dst_p = pixel_at16(gr_draw, x, y, row_pixels);
- text_blend(src_p, icon->row_bytes,
- dst_p, gr_draw->row_bytes,
- icon->width, icon->height);
+ text_blend16(src_p, icon->row_bytes, dst_p, row_pixels, icon->width, icon->height);
+ return;
+ }
+ uint32_t* dst_p = pixel_at(gr_draw, x, y, row_pixels);
+
+ text_blend(src_p, icon->row_bytes, dst_p, row_pixels, icon->width, icon->height);
}
-void gr_convert_rgb_555()
+void gr_convert_rgb_555(unsigned char r, unsigned char g, unsigned char b)
{
- gr_current_r5 = (((gr_current_r & 0xFF) * 0x1F) + 0x7F) / 0xFF;
- gr_current_g5 = (((gr_current_g & 0xFF) * 0x3F) + 0x7F) / 0xFF;
- gr_current_b5 = (((gr_current_b & 0xFF) * 0x1F) + 0x7F) / 0xFF;
+ gr_current_r5 = (((r & 0xFF) * 0x1F) + 0x7F) / 0xFF;
+ gr_current_g5 = (((g & 0xFF) * 0x3F) + 0x7F) / 0xFF;
+ gr_current_b5 = (((b & 0xFF) * 0x1F) + 0x7F) / 0xFF;
rgb_555[0] = (gr_current_g5 << 5) + (gr_current_b5);
rgb_555[1] = (gr_current_r5 << 3) + (gr_current_g5 >> 3);
}
-void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
-{
+void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
+#ifdef TW_NO_MINUI_CUSTOM_FONTS
#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
- gr_current_r = b;
- gr_current_g = g;
- gr_current_b = r;
- gr_current_a = a;
+ gr_current_r = b;
+ gr_current_g = g;
+ gr_current_b = r;
#else
- gr_current_r = r;
- gr_current_g = g;
- gr_current_b = b;
- gr_current_a = a;
+ gr_current_r = r;
+ gr_current_g = g;
+ gr_current_b = b;
#endif
- if (gr_draw->pixel_bytes == 2) {
- gr_convert_rgb_555();
- }
+#endif
+
+ if (gr_draw->pixel_bytes == 2) {
+ gr_current_a = a;
+ gr_convert_rgb_555(r, g, b);
+ return;
+ }
+
+ uint32_t r32 = r, g32 = g, b32 = b, a32 = a;
+#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
+ gr_current = (a32 << 24) | (r32 << 16) | (g32 << 8) | b32;
+#else
+ gr_current = (a32 << 24) | (b32 << 16) | (g32 << 8) | r32;
+#endif
}
-void gr_clear()
-{
- if (gr_draw->pixel_bytes == 2) {
- gr_fill(0, 0, gr_fb_width(), gr_fb_height());
- return;
- }
+void gr_clear() {
+ if (gr_draw->pixel_bytes == 2) {
+ gr_fill(0, 0, gr_fb_width(), gr_fb_height());
+ return;
+ }
- // This code only works on 32bpp devices
- if (gr_current_r == gr_current_g && gr_current_r == gr_current_b) {
- memset(gr_draw->data, gr_current_r, gr_draw->height * gr_draw->row_bytes);
- } else {
- unsigned char* px = gr_draw->data;
- for (int y = 0; y < gr_draw->height; ++y) {
- for (int x = 0; x < gr_draw->width; ++x) {
- *px++ = gr_current_r;
- *px++ = gr_current_g;
- *px++ = gr_current_b;
- px++;
- }
- px += gr_draw->row_bytes - (gr_draw->width * gr_draw->pixel_bytes);
- }
+ // This code only works on 32bpp devices
+ if ((gr_current & 0xff) == ((gr_current >> 8) & 0xff) &&
+ (gr_current & 0xff) == ((gr_current >> 16) & 0xff) &&
+ (gr_current & 0xff) == ((gr_current >> 24) & 0xff) &&
+ gr_draw->row_bytes == gr_draw->width * gr_draw->pixel_bytes) {
+ memset(gr_draw->data, gr_current & 0xff, gr_draw->height * gr_draw->row_bytes);
+ } else {
+ uint32_t* px = reinterpret_cast<uint32_t*>(gr_draw->data);
+ int row_diff = gr_draw->row_bytes / gr_draw->pixel_bytes - gr_draw->width;
+ for (int y = 0; y < gr_draw->height; ++y) {
+ for (int x = 0; x < gr_draw->width; ++x) {
+ *px++ = gr_current;
+ }
+ px += row_diff;
}
+ }
}
-void gr_fill(int x1, int y1, int x2, int y2)
-{
- x1 += overscan_offset_x;
- y1 += overscan_offset_y;
+void gr_fill(int x1, int y1, int x2, int y2) {
+ x1 += overscan_offset_x;
+ y1 += overscan_offset_y;
- x2 += overscan_offset_x;
- y2 += overscan_offset_y;
+ x2 += overscan_offset_x;
+ y2 += overscan_offset_y;
- if (outside(x1, y1) || outside(x2-1, y2-1)) return;
+ if (outside(x1, y1) || outside(x2 - 1, y2 - 1)) return;
- unsigned char* p = gr_draw->data + y1 * gr_draw->row_bytes + x1 * gr_draw->pixel_bytes;
- if (gr_current_a == 255) {
- int x, y;
- for (y = y1; y < y2; ++y) {
- unsigned char* px = p;
- for (x = x1; x < x2; ++x) {
- if (gr_draw->pixel_bytes == 2) {
- *px++ = rgb_555[0];
- *px++ = rgb_555[1];
- } else {
- *px++ = gr_current_r;
- *px++ = gr_current_g;
- *px++ = gr_current_b;
- px++;
- }
- }
- p += gr_draw->row_bytes;
+ int row_pixels = gr_draw->row_bytes / gr_draw->pixel_bytes;
+ if (gr_draw->pixel_bytes == 2) {
+ uint16_t* p = pixel_at16(gr_draw, x1, y1, row_pixels);
+ uint8_t alpha = static_cast<uint8_t>(((gr_current & alpha_mask) >> 24));
+ if (alpha > 0) {
+ for (int y = y1; y < y2; ++y) {
+ uint16_t* px = p;
+ for (int x = x1; x < x2; ++x) {
+ *px = pixel_blend16(alpha, *px);
+ incr_x16(&px, row_pixels);
}
- } else if (gr_current_a > 0) {
- int x, y;
- for (y = y1; y < y2; ++y) {
- unsigned char* px = p;
- for (x = x1; x < x2; ++x) {
- if (gr_draw->pixel_bytes == 2) {
- blend_16bpp(px, gr_current_r5, gr_current_g5, gr_current_b5, gr_current_a);
- px += gr_draw->row_bytes;
- } else {
- *px = (*px * (255-gr_current_a) + gr_current_r * gr_current_a) / 255;
- ++px;
- *px = (*px * (255-gr_current_a) + gr_current_g * gr_current_a) / 255;
- ++px;
- *px = (*px * (255-gr_current_a) + gr_current_b * gr_current_a) / 255;
- ++px;
- ++px;
- }
- }
- p += gr_draw->row_bytes;
- }
+ incr_y16(&p, row_pixels);
+ }
}
+ return;
+ }
+ { // open brace to maintain separation between uint16_t p and uint32_t p
+ uint32_t* p = pixel_at(gr_draw, x1, y1, row_pixels);
+ uint8_t alpha = static_cast<uint8_t>(((gr_current & alpha_mask) >> 24));
+ if (alpha > 0) {
+ for (int y = y1; y < y2; ++y) {
+ uint32_t* px = p;
+ for (int x = x1; x < x2; ++x) {
+ *px = pixel_blend(alpha, *px);
+ incr_x(&px, row_pixels);
+ }
+ incr_y(&p, row_pixels);
+ }
+ }
+ } // close brace to maintain separation between uint16_t p and uint32_t p
}
void gr_blit_32to16(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy) {
- dx += overscan_offset_x;
- dy += overscan_offset_y;
+ if (rotation)
+ printf("gr_blit_32to16 does not support rotation!\n"); // but we'll draw something in the wrong spot anyway because, why not!
- if (outside(dx, dy) || outside(dx+w-1, dy+h-1)) return;
+ dx += overscan_offset_x;
+ dy += overscan_offset_y;
- unsigned char* src_p = source->data + sy*source->row_bytes + sx*source->pixel_bytes;
- unsigned char* dst_p = gr_draw->data + dy*gr_draw->row_bytes + dx*gr_draw->pixel_bytes;
+ if (outside(dx, dy) || outside(dx+w-1, dy+h-1)) return;
- int i, j;
- for (i = 0; i < h; ++i) {
- unsigned char* spx = src_p;
- unsigned char* dpx = dst_p;
+ unsigned char* src_p = source->data + sy*source->row_bytes + sx*source->pixel_bytes;
+ unsigned char* dst_p = gr_draw->data + dy*gr_draw->row_bytes + dx*gr_draw->pixel_bytes;
- for (j = 0; j < w; ++j) {
- unsigned a = spx[3];
+ int i, j;
+ for (i = 0; i < h; ++i) {
+ unsigned char* spx = src_p;
+ unsigned char* dpx = dst_p;
- if (a == 0) {
- spx += source->pixel_bytes;
- dpx += gr_draw->pixel_bytes;
- } else {
- unsigned r5 = (((*spx++ & 0xFF) * 0x1F) + 0x7F) / 0xFF;
- unsigned g5 = (((*spx++ & 0xFF) * 0x3F) + 0x7F) / 0xFF;
- unsigned b5 = (((*spx++ & 0xFF) * 0x1F) + 0x7F) / 0xFF;
- spx++;
- if (a == 255) {
- *dpx++ = (g5 << 5) + (b5);
- *dpx++ = (r5 << 3) + (g5 >> 3);
- } else {
- blend_16bpp(dpx, r5, g5, b5, a);
- spx += source->pixel_bytes;
- }
- }
+ for (j = 0; j < w; ++j) {
+ unsigned a = spx[3];
+
+ if (a == 0) {
+ spx += source->pixel_bytes;
+ dpx += gr_draw->pixel_bytes;
+ } else {
+ unsigned r5 = (((*spx++ & 0xFF) * 0x1F) + 0x7F) / 0xFF;
+ unsigned g5 = (((*spx++ & 0xFF) * 0x3F) + 0x7F) / 0xFF;
+ unsigned b5 = (((*spx++ & 0xFF) * 0x1F) + 0x7F) / 0xFF;
+ spx++;
+ if (a == 255) {
+ *dpx++ = (g5 << 5) + (b5);
+ *dpx++ = (r5 << 3) + (g5 >> 3);
+ } else {
+ blend_16bpp(dpx, r5, g5, b5, a);
+ spx += source->pixel_bytes;
}
- src_p += source->row_bytes;
- dst_p += gr_draw->row_bytes;
+ }
}
+ src_p += source->row_bytes;
+ dst_p += gr_draw->row_bytes;
+ }
}
void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy) {
- if (source == NULL) return;
+ if (source == NULL) return;
- if (gr_draw->pixel_bytes != source->pixel_bytes) {
- if (gr_draw->pixel_bytes == 2 && source->pixel_bytes == 4) {
- gr_blit_32to16(source, sx, sy, w, h, dx, dy);
- return;
- } else {
- printf("gr_blit: source has wrong format\n");
- return;
- }
+ if (gr_draw->pixel_bytes != source->pixel_bytes) {
+ if (gr_draw->pixel_bytes == 2 && source->pixel_bytes == 4) {
+ gr_blit_32to16(source, sx, sy, w, h, dx, dy);
+ return;
+ } else {
+ printf("gr_blit: source has wrong format\n");
+ return;
}
+ }
- dx += overscan_offset_x;
- dy += overscan_offset_y;
+ dx += overscan_offset_x;
+ dy += overscan_offset_y;
- if (outside(dx, dy) || outside(dx+w-1, dy+h-1)) return;
+ if (outside(dx, dy) || outside(dx + w - 1, dy + h - 1)) return;
- unsigned char* src_p = source->data + sy*source->row_bytes + sx*source->pixel_bytes;
- unsigned char* dst_p = gr_draw->data + dy*gr_draw->row_bytes + dx*gr_draw->pixel_bytes;
+ if (rotation) {
+ int src_row_pixels = source->row_bytes / source->pixel_bytes;
+ int row_pixels = gr_draw->row_bytes / gr_draw->pixel_bytes;
+ uint32_t* src_py = reinterpret_cast<uint32_t*>(source->data) + sy * source->row_bytes / 4 + sx;
+ uint32_t* dst_py = pixel_at(gr_draw, dx, dy, row_pixels);
+
+ for (int y = 0; y < h; y += 1) {
+ uint32_t* src_px = src_py;
+ uint32_t* dst_px = dst_py;
+ for (int x = 0; x < w; x += 1) {
+ *dst_px = *src_px++;
+ incr_x(&dst_px, row_pixels);
+ }
+ src_py += src_row_pixels;
+ incr_y(&dst_py, row_pixels);
+ }
+ } else {
+ unsigned char* src_p = source->data + sy * source->row_bytes + sx * source->pixel_bytes;
+ unsigned char* dst_p = gr_draw->data + dy * gr_draw->row_bytes + dx * gr_draw->pixel_bytes;
int i;
for (i = 0; i < h; ++i) {
- memcpy(dst_p, src_p, w * source->pixel_bytes);
- src_p += source->row_bytes;
- dst_p += gr_draw->row_bytes;
+ memcpy(dst_p, src_p, w * source->pixel_bytes);
+ src_p += source->row_bytes;
+ dst_p += gr_draw->row_bytes;
}
+ }
}
unsigned int gr_get_width(GRSurface* surface) {
- if (surface == NULL) {
- return 0;
- }
- return surface->width;
+ if (surface == NULL) {
+ return 0;
+ }
+ return surface->width;
}
unsigned int gr_get_height(GRSurface* surface) {
- if (surface == NULL) {
- return 0;
- }
- return surface->height;
+ if (surface == NULL) {
+ return 0;
+ }
+ return surface->height;
}
#ifdef TW_NO_MINUI_CUSTOM_FONTS
@@ -466,58 +655,56 @@
}
#else // TW_NO_MINUI_CUSTOM_FONTS
int gr_init_font(const char* name, GRFont** dest) {
- GRFont* font = static_cast<GRFont*>(calloc(1, sizeof(*gr_font)));
- if (font == nullptr) {
- return -1;
- }
+ GRFont* font = static_cast<GRFont*>(calloc(1, sizeof(*gr_font)));
+ if (font == nullptr) {
+ return -1;
+ }
- int res = res_create_alpha_surface(name, &(font->texture));
- if (res < 0) {
- free(font);
- return res;
- }
+ int res = res_create_alpha_surface(name, &(font->texture));
+ if (res < 0) {
+ free(font);
+ return res;
+ }
- // The font image should be a 96x2 array of character images. The
- // columns are the printable ASCII characters 0x20 - 0x7f. The
- // top row is regular text; the bottom row is bold.
- font->char_width = font->texture->width / 96;
- font->char_height = font->texture->height / 2;
+ // The font image should be a 96x2 array of character images. The
+ // columns are the printable ASCII characters 0x20 - 0x7f. The
+ // top row is regular text; the bottom row is bold.
+ font->char_width = font->texture->width / 96;
+ font->char_height = font->texture->height / 2;
- *dest = font;
+ *dest = font;
- return 0;
+ return 0;
}
-static void gr_init_font(void)
-{
- int res = gr_init_font("font", &gr_font);
- if (res == 0) {
- return;
- }
+static void gr_init_font(void) {
+ int res = gr_init_font("font", &gr_font);
+ if (res == 0) {
+ return;
+ }
- printf("failed to read font: res=%d\n", res);
+ printf("failed to read font: res=%d\n", res);
+ // fall back to the compiled-in font.
+ gr_font = static_cast<GRFont*>(calloc(1, sizeof(*gr_font)));
+ gr_font->texture = static_cast<GRSurface*>(malloc(sizeof(*gr_font->texture)));
+ gr_font->texture->width = font.width;
+ gr_font->texture->height = font.height;
+ gr_font->texture->row_bytes = font.width;
+ gr_font->texture->pixel_bytes = 1;
- // fall back to the compiled-in font.
- gr_font = static_cast<GRFont*>(calloc(1, sizeof(*gr_font)));
- gr_font->texture = static_cast<GRSurface*>(malloc(sizeof(*gr_font->texture)));
- gr_font->texture->width = font.width;
- gr_font->texture->height = font.height;
- gr_font->texture->row_bytes = font.width;
- gr_font->texture->pixel_bytes = 1;
+ unsigned char* bits = static_cast<unsigned char*>(malloc(font.width * font.height));
+ gr_font->texture->data = bits;
- unsigned char* bits = static_cast<unsigned char*>(malloc(font.width * font.height));
- gr_font->texture->data = bits;
+ unsigned char data;
+ unsigned char* in = font.rundata;
+ while ((data = *in++)) {
+ memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
+ bits += (data & 0x7f);
+ }
- unsigned char data;
- unsigned char* in = font.rundata;
- while((data = *in++)) {
- memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
- bits += (data & 0x7f);
- }
-
- gr_font->char_width = font.char_width;
- gr_font->char_height = font.char_height;
+ gr_font->char_width = font.char_width;
+ gr_font->char_height = font.char_height;
}
#endif // TW_NO_MINUI_CUSTOM_FONTS
@@ -575,6 +762,12 @@
gr_flip();
gr_flip();
+ gr_rotate(DEFAULT_ROTATION);
+
+ if (gr_draw->pixel_bytes != 4) {
+ printf("gr_init: Only 4-byte pixel formats supported\n");
+ }
+
return 0;
}
@@ -583,13 +776,19 @@
}
int gr_fb_width() {
- return gr_draw->width - 2 * overscan_offset_x;
+ return rotation % 2 ? gr_draw->height - 2 * overscan_offset_y
+ : gr_draw->width - 2 * overscan_offset_x;
}
int gr_fb_height() {
- return gr_draw->height - 2 * overscan_offset_y;
+ return rotation % 2 ? gr_draw->width - 2 * overscan_offset_x
+ : gr_draw->height - 2 * overscan_offset_y;
}
void gr_fb_blank(bool blank) {
gr_backend->Blank(blank);
}
+
+void gr_rotate(GRRotation rot) {
+ rotation = rot;
+}
diff --git a/minui/graphics_overlay.cpp b/minui/graphics_overlay.cpp
index 082d385..b7e62d9 100644
--- a/minui/graphics_overlay.cpp
+++ b/minui/graphics_overlay.cpp
@@ -47,7 +47,6 @@
#define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1))
MinuiBackendOverlay::MinuiBackendOverlay() :
- gr_draw(nullptr),
fb_fd(-1),
isMDP5(false),
leftSplit(0),
@@ -76,7 +75,6 @@
bool MinuiBackendOverlay::target_has_overlay()
{
- int ret;
int mdp_version;
bool overlay_supported = false;
fb_fix_screeninfo fi;
@@ -524,6 +522,7 @@
}
GRSurface* MinuiBackendOverlay::Init() {
+ gr_draw = NULL; // this should be in the constructor but 9.0 was throwing a compile error
if (!target_has_overlay())
return NULL;
diff --git a/minui/include/minui/minui.h b/minui/include/minui/minui.h
index bd8c386..bff146a 100644
--- a/minui/include/minui/minui.h
+++ b/minui/include/minui/minui.h
@@ -23,23 +23,31 @@
#include <functional>
#include <string>
+#include <vector>
//
// Graphics.
//
struct GRSurface {
- int width;
- int height;
- int row_bytes;
- int pixel_bytes;
- unsigned char* data;
+ int width;
+ int height;
+ int row_bytes;
+ int pixel_bytes;
+ unsigned char* data;
};
struct GRFont {
- GRSurface* texture;
- int char_width;
- int char_height;
+ GRSurface* texture;
+ int char_width;
+ int char_height;
+};
+
+enum GRRotation {
+ ROTATION_NONE = 0,
+ ROTATION_RIGHT = 1,
+ ROTATION_DOWN = 2,
+ ROTATION_LEFT = 3,
};
int gr_init();
@@ -65,15 +73,18 @@
const GRFont* gr_sys_font();
int gr_init_font(const char* name, GRFont** dest);
-void gr_text(const GRFont* font, int x, int y, const char *s, bool bold);
-int gr_measure(const GRFont* font, const char *s);
-void gr_font_size(const GRFont* font, int *x, int *y);
+void gr_text(const GRFont* font, int x, int y, const char* s, bool bold);
+int gr_measure(const GRFont* font, const char* s);
+void gr_font_size(const GRFont* font, int* x, int* y);
#endif
void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy);
unsigned int gr_get_width(GRSurface* surface);
unsigned int gr_get_height(GRSurface* surface);
+// Set rotation, flips gr_fb_width/height if 90 degree rotation difference
+void gr_rotate(GRRotation rotation);
+
//
// Input events.
//
@@ -153,6 +164,9 @@
int res_create_localized_alpha_surface(const char* name, const char* locale,
GRSurface** pSurface);
+// Return a list of locale strings embedded in |png_name|. Return a empty list in case of failure.
+std::vector<std::string> get_locales_in_png(const std::string& png_name);
+
// Free a surface allocated by any of the res_create_*_surface()
// functions.
void res_free_surface(GRSurface* surface);
diff --git a/minui/main.cpp b/minui/main.cpp
index 13fee87..4c3c52c 100644
--- a/minui/main.cpp
+++ b/minui/main.cpp
@@ -89,11 +89,11 @@
gr_color(255, 255, 255, 255);
gr_fill(0, 0, gr_fb_width(), gr_fb_height());
gr_color(255, 0, 0, 255);
- gr_text(10, 10, "RED red RED", false);
+ gr_text(gr_sys_font(), 10, 10, "RED red RED", false);
gr_color(0, 255, 0, 255);
- gr_text(10, 50, "GREEN green GREEN", false);
+ gr_text(gr_sys_font(), 10, 50, "GREEN green GREEN", false);
gr_color(0, 0, 255, 255);
- gr_text(10, 90, "BLUE blue BLUE", false);
+ gr_text(gr_sys_font(), 10, 90, "BLUE blue BLUE", false);
gr_flip();
sleep(3);
printf("PNG test with /res/images/test.png\n");
diff --git a/minui/resources.cpp b/minui/resources.cpp
index b9797b9..fd57893 100644
--- a/minui/resources.cpp
+++ b/minui/resources.cpp
@@ -25,10 +25,12 @@
#include <sys/types.h>
#include <unistd.h>
+#include <memory>
#include <regex>
#include <string>
#include <vector>
+//#include <android-base/stringprintf.h> // does not exist in 6.0
//#include <android-base/strings.h> // does not exist in 6.0
#include <png.h>
@@ -46,89 +48,128 @@
return surface;
}
-static int open_png(const char* name, png_structp* png_ptr, png_infop* info_ptr,
- png_uint_32* width, png_uint_32* height, png_byte* channels) {
- char resPath[256];
- unsigned char header[8];
- int result = 0;
- int color_type, bit_depth;
- size_t bytesRead;
+// This class handles the png file parsing. It also holds the ownership of the png pointer and the
+// opened file pointer. Both will be destroyed/closed when this object goes out of scope.
+class PngHandler {
+ public:
+ PngHandler(const std::string& name);
- snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name);
- resPath[sizeof(resPath)-1] = '\0';
- FILE* fp = fopen(resPath, "rbe");
- if (fp == NULL) {
- result = -1;
- goto exit;
- }
+ ~PngHandler();
- bytesRead = fread(header, 1, sizeof(header), fp);
- if (bytesRead != sizeof(header)) {
- result = -2;
- goto exit;
- }
+ png_uint_32 width() const {
+ return width_;
+ }
- if (png_sig_cmp(header, 0, sizeof(header))) {
- result = -3;
- goto exit;
- }
+ png_uint_32 height() const {
+ return height_;
+ }
- *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (!*png_ptr) {
- result = -4;
- goto exit;
- }
+ png_byte channels() const {
+ return channels_;
+ }
- *info_ptr = png_create_info_struct(*png_ptr);
- if (!*info_ptr) {
- result = -5;
- goto exit;
- }
+ png_structp png_ptr() const {
+ return png_ptr_;
+ }
- if (setjmp(png_jmpbuf(*png_ptr))) {
- result = -6;
- goto exit;
- }
+ png_infop info_ptr() const {
+ return info_ptr_;
+ }
- png_init_io(*png_ptr, fp);
- png_set_sig_bytes(*png_ptr, sizeof(header));
- png_read_info(*png_ptr, *info_ptr);
+ int error_code() const {
+ return error_code_;
+ };
- png_get_IHDR(*png_ptr, *info_ptr, width, height, &bit_depth,
- &color_type, NULL, NULL, NULL);
+ operator bool() const {
+ return error_code_ == 0;
+ }
- *channels = png_get_channels(*png_ptr, *info_ptr);
+ private:
+ png_structp png_ptr_{ nullptr };
+ png_infop info_ptr_{ nullptr };
+ png_uint_32 width_;
+ png_uint_32 height_;
+ png_byte channels_;
- if (bit_depth == 8 && *channels == 3 && color_type == PNG_COLOR_TYPE_RGB) {
- // 8-bit RGB images: great, nothing to do.
- } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_GRAY) {
- // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray.
- png_set_expand_gray_1_2_4_to_8(*png_ptr);
- } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) {
- // paletted images: expand to 8-bit RGB. Note that we DON'T
- // currently expand the tRNS chunk (if any) to an alpha
- // channel, because minui doesn't support alpha channels in
- // general.
- png_set_palette_to_rgb(*png_ptr);
- *channels = 3;
- } else {
- fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n",
- bit_depth, *channels, color_type);
- result = -7;
- goto exit;
- }
+ // The |error_code_| is set to a negative value if an error occurs when opening the png file.
+ int error_code_;
+ // After initialization, we'll keep the file pointer open before destruction of PngHandler.
+ std::unique_ptr<FILE, decltype(&fclose)> png_fp_;
+};
- return result;
+PngHandler::PngHandler(const std::string& name) : error_code_(0), png_fp_(nullptr, fclose) {
+ char res_path[PATH_MAX];
+ sprintf(res_path, "/res/images/%s.png", name.c_str());
+ //std::string res_path = sprintf("/res/images/%s.png", name.c_str());
+ png_fp_.reset(fopen(res_path, "rbe"));
+ if (!png_fp_) {
+ error_code_ = -1;
+ return;
+ }
- exit:
- if (result < 0) {
- png_destroy_read_struct(png_ptr, info_ptr, NULL);
- }
- if (fp != NULL) {
- fclose(fp);
- }
+ unsigned char header[8];
+ size_t bytesRead = fread(header, 1, sizeof(header), png_fp_.get());
+ if (bytesRead != sizeof(header)) {
+ error_code_ = -2;
+ return;
+ }
- return result;
+ if (png_sig_cmp(header, 0, sizeof(header))) {
+ error_code_ = -3;
+ return;
+ }
+
+ png_ptr_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
+ if (!png_ptr_) {
+ error_code_ = -4;
+ return;
+ }
+
+ info_ptr_ = png_create_info_struct(png_ptr_);
+ if (!info_ptr_) {
+ error_code_ = -5;
+ return;
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr_))) {
+ error_code_ = -6;
+ return;
+ }
+
+ png_init_io(png_ptr_, png_fp_.get());
+ png_set_sig_bytes(png_ptr_, sizeof(header));
+ png_read_info(png_ptr_, info_ptr_);
+
+ int color_type;
+ int bit_depth;
+ png_get_IHDR(png_ptr_, info_ptr_, &width_, &height_, &bit_depth, &color_type, nullptr, nullptr,
+ nullptr);
+
+ channels_ = png_get_channels(png_ptr_, info_ptr_);
+
+ if (bit_depth == 8 && channels_ == 3 && color_type == PNG_COLOR_TYPE_RGB) {
+ // 8-bit RGB images: great, nothing to do.
+ } else if (bit_depth <= 8 && channels_ == 1 && color_type == PNG_COLOR_TYPE_GRAY) {
+ // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray.
+ png_set_expand_gray_1_2_4_to_8(png_ptr_);
+ } else if (bit_depth <= 8 && channels_ == 1 && color_type == PNG_COLOR_TYPE_PALETTE) {
+ // paletted images: expand to 8-bit RGB. Note that we DON'T
+ // currently expand the tRNS chunk (if any) to an alpha
+ // channel, because minui doesn't support alpha channels in
+ // general.
+ png_set_palette_to_rgb(png_ptr_);
+ channels_ = 3;
+ } else {
+ fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n", bit_depth,
+ channels_, color_type);
+ error_code_ = -7;
+ }
+}
+
+PngHandler::~PngHandler() {
+ if (png_ptr_) {
+ png_destroy_read_struct(&png_ptr_, &info_ptr_, nullptr);
+ }
}
// "display" surfaces are transformed into the framebuffer's required
@@ -198,131 +239,115 @@
}
int res_create_display_surface(const char* name, GRSurface** pSurface) {
- GRSurface* surface = NULL;
- int result = 0;
- png_structp png_ptr = NULL;
- png_infop info_ptr = NULL;
- png_uint_32 width, height;
- png_byte channels;
- unsigned char* p_row;
- unsigned int y;
+ *pSurface = nullptr;
- *pSurface = NULL;
+ PngHandler png_handler(name);
+ if (!png_handler) return png_handler.error_code();
- result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
- if (result < 0) return result;
+ png_structp png_ptr = png_handler.png_ptr();
+ png_uint_32 width = png_handler.width();
+ png_uint_32 height = png_handler.height();
- surface = init_display_surface(width, height);
- if (surface == NULL) {
- result = -8;
- goto exit;
- }
+ GRSurface* surface = init_display_surface(width, height);
+ if (!surface) {
+ return -8;
+ }
#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
- png_set_bgr(png_ptr);
+ png_set_bgr(png_ptr);
#endif
- p_row = static_cast<unsigned char*>(malloc(width * 4));
- for (y = 0; y < height; ++y) {
- png_read_row(png_ptr, p_row, NULL);
- transform_rgb_to_draw(p_row, surface->data + y * surface->row_bytes, channels, width);
- }
- free(p_row);
+ for (png_uint_32 y = 0; y < height; ++y) {
+ std::vector<unsigned char> p_row(width * 4);
+ png_read_row(png_ptr, p_row.data(), nullptr);
+ transform_rgb_to_draw(p_row.data(), surface->data + y * surface->row_bytes,
+ png_handler.channels(), width);
+ }
- *pSurface = surface;
+ *pSurface = surface;
- exit:
- png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- if (result < 0 && surface != NULL) free(surface);
- return result;
+ return 0;
}
int res_create_multi_display_surface(const char* name, int* frames, int* fps,
- GRSurface*** pSurface) {
- GRSurface** surface = NULL;
- int result = 0;
- png_structp png_ptr = NULL;
- png_infop info_ptr = NULL;
- png_uint_32 width, height;
- png_byte channels;
- png_textp text;
- int num_text;
- unsigned char* p_row;
- unsigned int y;
+ GRSurface*** pSurface) {
+ *pSurface = nullptr;
+ *frames = -1;
- *pSurface = NULL;
- *frames = -1;
+ PngHandler png_handler(name);
+ if (!png_handler) return png_handler.error_code();
- result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
- if (result < 0) return result;
+ png_structp png_ptr = png_handler.png_ptr();
+ png_uint_32 width = png_handler.width();
+ png_uint_32 height = png_handler.height();
- *frames = 1;
- *fps = 20;
- if (png_get_text(png_ptr, info_ptr, &text, &num_text)) {
- for (int i = 0; i < num_text; ++i) {
- if (text[i].key && strcmp(text[i].key, "Frames") == 0 && text[i].text) {
- *frames = atoi(text[i].text);
- } else if (text[i].key && strcmp(text[i].key, "FPS") == 0 && text[i].text) {
- *fps = atoi(text[i].text);
- }
- }
- printf(" found frames = %d\n", *frames);
- printf(" found fps = %d\n", *fps);
+ *frames = 1;
+ *fps = 20;
+ png_textp text;
+ int num_text;
+ if (png_get_text(png_ptr, png_handler.info_ptr(), &text, &num_text)) {
+ for (int i = 0; i < num_text; ++i) {
+ if (text[i].key && strcmp(text[i].key, "Frames") == 0 && text[i].text) {
+ *frames = atoi(text[i].text);
+ } else if (text[i].key && strcmp(text[i].key, "FPS") == 0 && text[i].text) {
+ *fps = atoi(text[i].text);
+ }
}
+ printf(" found frames = %d\n", *frames);
+ printf(" found fps = %d\n", *fps);
+ }
- if (*frames <= 0 || *fps <= 0) {
- printf("bad number of frames (%d) and/or FPS (%d)\n", *frames, *fps);
- result = -10;
- goto exit;
- }
+ int result = 0;
+ GRSurface** surface = nullptr;
+ if (*frames <= 0 || *fps <= 0) {
+ printf("bad number of frames (%d) and/or FPS (%d)\n", *frames, *fps);
+ result = -10;
+ goto exit;
+ }
- if (height % *frames != 0) {
- printf("bad height (%d) for frame count (%d)\n", height, *frames);
- result = -9;
- goto exit;
- }
+ if (height % *frames != 0) {
+ printf("bad height (%d) for frame count (%d)\n", height, *frames);
+ result = -9;
+ goto exit;
+ }
- surface = static_cast<GRSurface**>(calloc(*frames, sizeof(GRSurface*)));
- if (surface == NULL) {
- result = -8;
- goto exit;
+ surface = static_cast<GRSurface**>(calloc(*frames, sizeof(GRSurface*)));
+ if (!surface) {
+ result = -8;
+ goto exit;
+ }
+ for (int i = 0; i < *frames; ++i) {
+ surface[i] = init_display_surface(width, height / *frames);
+ if (!surface[i]) {
+ result = -8;
+ goto exit;
}
- for (int i = 0; i < *frames; ++i) {
- surface[i] = init_display_surface(width, height / *frames);
- if (surface[i] == NULL) {
- result = -8;
- goto exit;
- }
- }
+ }
#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
- png_set_bgr(png_ptr);
+ png_set_bgr(png_ptr);
#endif
- p_row = static_cast<unsigned char*>(malloc(width * 4));
- for (y = 0; y < height; ++y) {
- png_read_row(png_ptr, p_row, NULL);
- int frame = y % *frames;
- unsigned char* out_row = surface[frame]->data +
- (y / *frames) * surface[frame]->row_bytes;
- transform_rgb_to_draw(p_row, out_row, channels, width);
- }
- free(p_row);
+ for (png_uint_32 y = 0; y < height; ++y) {
+ std::vector<unsigned char> p_row(width * 4);
+ png_read_row(png_ptr, p_row.data(), nullptr);
+ int frame = y % *frames;
+ unsigned char* out_row = surface[frame]->data + (y / *frames) * surface[frame]->row_bytes;
+ transform_rgb_to_draw(p_row.data(), out_row, png_handler.channels(), width);
+ }
- *pSurface = surface;
+ *pSurface = surface;
exit:
- png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
-
- if (result < 0) {
- if (surface) {
- for (int i = 0; i < *frames; ++i) {
- free(surface[i]);
- }
- free(surface);
- }
+ if (result < 0) {
+ if (surface) {
+ for (int i = 0; i < *frames; ++i) {
+ free(surface[i]);
+ }
+ free(surface);
}
- return result;
+ }
+ return result;
}
int res_create_multi_display_surface(const char* name, int* frames,
@@ -332,50 +357,40 @@
}
int res_create_alpha_surface(const char* name, GRSurface** pSurface) {
- GRSurface* surface = NULL;
- int result = 0;
- png_structp png_ptr = NULL;
- png_infop info_ptr = NULL;
- png_uint_32 width, height;
- png_byte channels;
+ *pSurface = nullptr;
- *pSurface = NULL;
+ PngHandler png_handler(name);
+ if (!png_handler) return png_handler.error_code();
- result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
- if (result < 0) return result;
+ if (png_handler.channels() != 1) {
+ return -7;
+ }
- if (channels != 1) {
- result = -7;
- goto exit;
- }
+ png_structp png_ptr = png_handler.png_ptr();
+ png_uint_32 width = png_handler.width();
+ png_uint_32 height = png_handler.height();
- surface = malloc_surface(width * height);
- if (surface == NULL) {
- result = -8;
- goto exit;
- }
- surface->width = width;
- surface->height = height;
- surface->row_bytes = width;
- surface->pixel_bytes = 1;
+ GRSurface* surface = malloc_surface(width * height);
+ if (!surface) {
+ return -8;
+ }
+ surface->width = width;
+ surface->height = height;
+ surface->row_bytes = width;
+ surface->pixel_bytes = 1;
#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
- png_set_bgr(png_ptr);
+ png_set_bgr(png_ptr);
#endif
- unsigned char* p_row;
- unsigned int y;
- for (y = 0; y < height; ++y) {
- p_row = surface->data + y * surface->row_bytes;
- png_read_row(png_ptr, p_row, NULL);
- }
+ for (png_uint_32 y = 0; y < height; ++y) {
+ unsigned char* p_row = surface->data + y * surface->row_bytes;
+ png_read_row(png_ptr, p_row, nullptr);
+ }
- *pSurface = surface;
+ *pSurface = surface;
- exit:
- png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- if (result < 0 && surface != NULL) free(surface);
- return result;
+ return 0;
}
// This function tests if a locale string stored in PNG (prefix) matches
@@ -390,7 +405,7 @@
// match the locale string without the {script} section.
// For instance, prefix == "en" matches locale == "en-US", prefix == "sr-Latn" matches locale
// == "sr-Latn-BA", and prefix == "zh-CN" matches locale == "zh-Hans-CN".
- //if (android::base::StartsWith(locale, prefix.c_str())) { // does not exist in 6.0
+ //if (android::base::StartsWith(locale, prefix)) { // does not exist in 6.0
if (strncmp(prefix.c_str(), locale.c_str(), prefix.length()) == 0) {
return true;
}
@@ -403,75 +418,90 @@
return std::regex_match(locale, loc_regex);
}
+std::vector<std::string> get_locales_in_png(const std::string& png_name) {
+ PngHandler png_handler(png_name);
+ if (!png_handler) {
+ printf("Failed to open %s, error: %d\n", png_name.c_str(), png_handler.error_code());
+ return {};
+ }
+ if (png_handler.channels() != 1) {
+ printf("Expect input png to have 1 data channel, this file has %d\n", png_handler.channels());
+ return {};
+ }
+
+ std::vector<std::string> result;
+ std::vector<unsigned char> row(png_handler.width());
+ for (png_uint_32 y = 0; y < png_handler.height(); ++y) {
+ png_read_row(png_handler.png_ptr(), row.data(), nullptr);
+ int h = (row[3] << 8) | row[2];
+ std::string loc(reinterpret_cast<char*>(&row[5]));
+ if (!loc.empty()) {
+ result.push_back(loc);
+ }
+ for (int i = 0; i < h; ++i, ++y) {
+ png_read_row(png_handler.png_ptr(), row.data(), nullptr);
+ }
+ }
+
+ return result;
+}
+
int res_create_localized_alpha_surface(const char* name,
const char* locale,
GRSurface** pSurface) {
- GRSurface* surface = NULL;
- int result = 0;
- png_structp png_ptr = NULL;
- png_infop info_ptr = NULL;
- png_uint_32 width, height;
- png_byte channels;
- png_uint_32 y;
- std::vector<unsigned char> row;
+ *pSurface = nullptr;
+ if (locale == nullptr) {
+ return 0;
+ }
- *pSurface = NULL;
+ PngHandler png_handler(name);
+ if (!png_handler) return png_handler.error_code();
- if (locale == NULL) {
- return result;
+ if (png_handler.channels() != 1) {
+ return -7;
+ }
+
+ png_structp png_ptr = png_handler.png_ptr();
+ png_uint_32 width = png_handler.width();
+ png_uint_32 height = png_handler.height();
+
+ for (png_uint_32 y = 0; y < height; ++y) {
+ std::vector<unsigned char> row(width);
+ png_read_row(png_ptr, row.data(), nullptr);
+ int w = (row[1] << 8) | row[0];
+ int h = (row[3] << 8) | row[2];
+ __unused int len = row[4];
+ char* loc = reinterpret_cast<char*>(&row[5]);
+
+ if (y + 1 + h >= height || matches_locale(loc, locale)) {
+ printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
+
+ GRSurface* surface = malloc_surface(w * h);
+ if (!surface) {
+ return -8;
+ }
+ surface->width = w;
+ surface->height = h;
+ surface->row_bytes = w;
+ surface->pixel_bytes = 1;
+
+ for (int i = 0; i < h; ++i, ++y) {
+ png_read_row(png_ptr, row.data(), nullptr);
+ memcpy(surface->data + i * w, row.data(), w);
+ }
+
+ *pSurface = surface;
+ break;
}
- result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
- if (result < 0) return result;
-
- if (channels != 1) {
- result = -7;
- goto exit;
+ for (int i = 0; i < h; ++i, ++y) {
+ png_read_row(png_ptr, row.data(), nullptr);
}
+ }
- row.resize(width);
- for (y = 0; y < height; ++y) {
- png_read_row(png_ptr, row.data(), NULL);
- int w = (row[1] << 8) | row[0];
- int h = (row[3] << 8) | row[2];
- __unused int len = row[4];
- char* loc = reinterpret_cast<char*>(&row[5]);
-
- if (y+1+h >= height || matches_locale(loc, locale)) {
- printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
-
- surface = malloc_surface(w*h);
- if (surface == NULL) {
- result = -8;
- goto exit;
- }
- surface->width = w;
- surface->height = h;
- surface->row_bytes = w;
- surface->pixel_bytes = 1;
-
- int i;
- for (i = 0; i < h; ++i, ++y) {
- png_read_row(png_ptr, row.data(), NULL);
- memcpy(surface->data + i*w, row.data(), w);
- }
-
- *pSurface = surface;
- break;
- } else {
- int i;
- for (i = 0; i < h; ++i, ++y) {
- png_read_row(png_ptr, row.data(), NULL);
- }
- }
- }
-
-exit:
- png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- if (result < 0 && surface != NULL) free(surface);
- return result;
+ return 0;
}
void res_free_surface(GRSurface* surface) {
- free(surface);
+ free(surface);
}
diff --git a/minuitwrp/events.cpp b/minuitwrp/events.cpp
index 04545b6..94b800e 100644
--- a/minuitwrp/events.cpp
+++ b/minuitwrp/events.cpp
@@ -101,7 +101,7 @@
static struct ev evs[MAX_DEVICES];
static unsigned ev_count = 0;
static struct timeval lastInputStat;
-static unsigned long lastInputMTime;
+static time_t lastInputMTime;
static int has_mouse = 0;
static inline int ABS(int x) {
@@ -360,7 +360,7 @@
ev_count = 0;
}
-static int vk_inside_display(__s32 value, struct input_absinfo *info, int screen_size)
+/*static int vk_inside_display(__s32 value, struct input_absinfo *info, int screen_size)
{
int screen_pos;
@@ -369,7 +369,7 @@
screen_pos = (value - info->minimum) * (screen_size - 1) / (info->maximum - info->minimum);
return (screen_pos >= 0 && screen_pos < screen_size);
-}
+}*/
static int vk_tp_to_screen(struct position *p, int *x, int *y)
{
@@ -782,7 +782,7 @@
return -2;
}
-int ev_wait(int timeout)
+int ev_wait(int timeout __unused)
{
return -1;
}
@@ -792,7 +792,7 @@
return;
}
-int ev_get_input(int fd, short revents, struct input_event *ev)
+int ev_get_input(int fd __unused, short revents __unused, struct input_event *ev __unused)
{
return -1;
}
diff --git a/minuitwrp/graphics.cpp b/minuitwrp/graphics.cpp
index 3dc88d9..81e77a6 100644
--- a/minuitwrp/graphics.cpp
+++ b/minuitwrp/graphics.cpp
@@ -42,7 +42,6 @@
int cheight;
};
-static GRFont* gr_font = NULL;
static minui_backend* gr_backend = NULL;
static int overscan_percent = OVERSCAN_PERCENT;
@@ -52,11 +51,6 @@
static unsigned char gr_current_r = 255;
static unsigned char gr_current_g = 255;
static unsigned char gr_current_b = 255;
-static unsigned char gr_current_a = 255;
-static unsigned char rgb_555[2];
-static unsigned char gr_current_r5 = 31;
-static unsigned char gr_current_g5 = 63;
-static unsigned char gr_current_b5 = 31;
GRSurface* gr_draw = NULL;
@@ -64,19 +58,12 @@
GGLSurface gr_mem_surface;
static int gr_is_curr_clr_opaque = 0;
-static bool outside(int x, int y)
-{
- return x < 0 || x >= gr_draw->width || y < 0 || y >= gr_draw->height;
-}
-
int gr_textEx_scaleW(int x, int y, const char *s, void* pFont, int max_width, int placement, int scale)
{
GGLContext *gl = gr_context;
void* vfont = pFont;
GRFont *font = (GRFont*) pFont;
- unsigned off;
- unsigned cwidth;
- int y_scale = 0, measured_width, measured_height, ret, new_height;
+ int y_scale = 0, measured_width, measured_height, new_height;
if (!s || strlen(s) == 0 || !font)
return 0;
diff --git a/minuitwrp/truetype.cpp b/minuitwrp/truetype.cpp
index 18635a8..3e5f707 100644
--- a/minuitwrp/truetype.cpp
+++ b/minuitwrp/truetype.cpp
@@ -461,7 +461,7 @@
int utf_bytes = 0;
unsigned int unicode = 0;
int i, x, diff, char_idx, prev_idx = 0;
- int height, base;
+ int height;
FT_Vector delta;
uint8_t *data = NULL;
const char *text_itr = text;
@@ -547,7 +547,6 @@
static StringCacheEntry *gr_ttf_string_cache_peek(TrueTypeFont *font, const char *text, int max_width)
{
- StringCacheEntry *res;
StringCacheKey k = {
.text = (char*)text,
.max_width = max_width
@@ -785,8 +784,8 @@
" refcount: %d\n"
" max_height: %d\n"
" base: %d\n"
- " glyph_cache: %d entries\n"
- " string_cache: %d entries (%.2f kB)\n",
+ " glyph_cache: %zu entries\n"
+ " string_cache: %zu entries (%.2f kB)\n",
k->path, k->size, k->dpi,
f->refcount, f->max_height, f->base,
hashmapSize(f->glyph_cache),
@@ -808,7 +807,7 @@
else
{
int total_string_cache_size = 0;
- printf("%d fonts loaded.\n", hashmapSize(font_data.fonts));
+ printf("%zu fonts loaded.\n", hashmapSize(font_data.fonts));
hashmapForEach(font_data.fonts, gr_ttf_dump_stats_font, &total_string_cache_size);
printf(" Total string cache size: %.2f kB\n", ((double)total_string_cache_size)/1024);
}
diff --git a/mmcutils/mmcutils.c b/mmcutils/mmcutils.c
index 6d976b5..a003a2d 100644
--- a/mmcutils/mmcutils.c
+++ b/mmcutils/mmcutils.c
@@ -231,7 +231,6 @@
int
mmc_scan_partitions() {
int i;
- ssize_t nbytes;
if (g_mmc_state.partitions == NULL) {
const int nump = MAX_PARTITIONS;
@@ -321,7 +320,7 @@
#define E2FSCK_BIN "/sbin/e2fsck"
int
-run_exec_process ( char **argv) {
+run_exec_process ( char *const *argv) {
pid_t pid;
int status;
pid = fork();
@@ -339,7 +338,7 @@
}
int
-format_ext3_device (const char *device) {
+format_ext3_device (char *device) {
char *const mke2fs[] = {MKE2FS_BIN, "-j", "-q", device, NULL};
char *const tune2fs[] = {TUNE2FS_BIN, "-C", "1", device, NULL};
// Run mke2fs
@@ -365,7 +364,7 @@
}
int
-format_ext2_device (const char *device) {
+format_ext2_device (char *device) {
// Run mke2fs
char *const mke2fs[] = {MKE2FS_BIN, device, NULL};
if(run_exec_process(mke2fs))
@@ -385,7 +384,7 @@
}
int
-mmc_format_ext3 (MmcPartition *partition) {
+mmc_format_ext3 (const MmcPartition *partition) {
char device[128];
strcpy(device, partition->device_index);
return format_ext3_device(device);
@@ -419,11 +418,10 @@
}
int
-mmc_raw_copy (const MmcPartition *partition, char *in_file) {
+mmc_raw_copy (const MmcPartition *partition, const char *in_file) {
int ch;
FILE *in;
FILE *out;
- int val = 0;
char buf[512];
unsigned sz = 0;
unsigned i;
@@ -475,7 +473,6 @@
int ch;
FILE *in;
FILE *out;
- int val = 0;
char buf[512];
unsigned sz = 0;
unsigned i;
@@ -522,19 +519,15 @@
// TODO: refactor this to not be a giant copy paste mess
int
-mmc_raw_dump (const MmcPartition *partition, char *out_file) {
+mmc_raw_dump (const MmcPartition *partition, const char *out_file) {
return mmc_raw_dump_internal(partition->device_index, out_file);
}
int
mmc_raw_read (const MmcPartition *partition, char *data, int data_size) {
- int ch;
FILE *in;
- int val = 0;
- char buf[512];
unsigned sz = 0;
- unsigned i;
int ret = -1;
char *in_file = partition->device_index;
@@ -549,8 +542,6 @@
fread(data, data_size, 1, in);
ret = 0;
-ERROR1:
-ERROR2:
fclose ( in );
ERROR3:
return ret;
@@ -559,12 +550,7 @@
int
mmc_raw_write (const MmcPartition *partition, char *data, int data_size) {
- int ch;
FILE *out;
- int val = 0;
- char buf[512];
- unsigned sz = 0;
- unsigned i;
int ret = -1;
char *out_file = partition->device_index;
@@ -575,8 +561,6 @@
fwrite(data, data_size, 1, out);
ret = 0;
-ERROR1:
-ERROR2:
fclose ( out );
ERROR3:
return ret;
@@ -613,12 +597,12 @@
}
}
-int cmd_mmc_erase_raw_partition(const char *partition)
+int cmd_mmc_erase_raw_partition(const char *partition __unused)
{
return 0;
}
-int cmd_mmc_erase_partition(const char *partition, const char *filesystem)
+int cmd_mmc_erase_partition(const char *partition, const char *filesystem __unused)
{
mmc_scan_partitions();
const MmcPartition *p;
@@ -628,7 +612,7 @@
return mmc_format_ext3 (p);
}
-int cmd_mmc_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only)
+int cmd_mmc_mount_partition(const char *partition, const char *mount_point, const char *filesystem __unused, int read_only)
{
mmc_scan_partitions();
const MmcPartition *p;
diff --git a/mmcutils/mmcutils.h b/mmcutils/mmcutils.h
index 5b10fdc..4fece79 100644
--- a/mmcutils/mmcutils.h
+++ b/mmcutils/mmcutils.h
@@ -31,7 +31,9 @@
#define MMCUTILS_H_
/* Some useful define used to access the MBR/EBR table */
+#ifndef BLOCK_SIZE
#define BLOCK_SIZE 0x200
+#endif
#define TABLE_ENTRY_0 0x1BE
#define TABLE_ENTRY_1 0x1CE
#define TABLE_ENTRY_2 0x1DE
@@ -76,15 +78,15 @@
/* Functions */
int mmc_scan_partitions();
const MmcPartition *mmc_find_partition_by_name(const char *name);
-int mmc_format_ext3 (MmcPartition *partition);
+int mmc_format_ext3 (const MmcPartition *partition);
int mmc_mount_partition(const MmcPartition *partition, const char *mount_point, \
int read_only);
-int mmc_raw_copy (const MmcPartition *partition, char *in_file);
+int mmc_raw_copy (const MmcPartition *partition, const char *in_file);
int mmc_raw_read (const MmcPartition *partition, char *data, int data_size);
int mmc_raw_write (const MmcPartition *partition, char *data, int data_size);
-int format_ext2_device(const char *device);
-int format_ext3_device(const char *device);
+int format_ext2_device(char *device);
+int format_ext3_device(char *device);
#endif // MMCUTILS_H_
diff --git a/mtdutils/mtdutils.c b/mtdutils/mtdutils.c
index 7a22efe..b19c533 100644
--- a/mtdutils/mtdutils.c
+++ b/mtdutils/mtdutils.c
@@ -605,16 +605,12 @@
return pos;
}
-#define BLOCK_SIZE 2048
-#define SPARE_SIZE (BLOCK_SIZE >> 5)
+#define MTD_BLOCK_SIZE 2048
+#define SPARE_SIZE (MTD_BLOCK_SIZE >> 5)
#define HEADER_SIZE 2048
int cmd_mtd_restore_raw_partition(const char *partition_name, const char *filename)
{
- const MtdPartition *ptn;
- MtdWriteContext *write;
- void *data;
-
FILE* f = fopen(filename, "rb");
if (f == NULL) {
fprintf(stderr, "error opening %s", filename);
@@ -676,9 +672,8 @@
{
MtdReadContext *in;
const MtdPartition *partition;
- char buf[BLOCK_SIZE + SPARE_SIZE];
+ char buf[MTD_BLOCK_SIZE + SPARE_SIZE];
size_t partition_size;
- size_t read_size;
size_t total;
int fd;
int wrote;
@@ -724,7 +719,7 @@
}
total = 0;
- while ((len = mtd_read_data(in, buf, BLOCK_SIZE)) > 0) {
+ while ((len = mtd_read_data(in, buf, MTD_BLOCK_SIZE)) > 0) {
wrote = write(fd, buf, len);
if (wrote != len) {
close(fd);
@@ -732,7 +727,7 @@
printf("error writing %s", filename);
return -1;
}
- total += BLOCK_SIZE;
+ total += MTD_BLOCK_SIZE;
}
mtd_read_close(in);
@@ -749,8 +744,6 @@
{
MtdWriteContext *out;
size_t erased;
- size_t total_size;
- size_t erase_size;
if (mtd_scan_partitions() <= 0)
{
@@ -784,13 +777,13 @@
return 0;
}
-int cmd_mtd_erase_partition(const char *partition, const char *filesystem)
+int cmd_mtd_erase_partition(const char *partition, const char *filesystem __unused)
{
return cmd_mtd_erase_raw_partition(partition);
}
-int cmd_mtd_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only)
+int cmd_mtd_mount_partition(const char *partition, const char *mount_point, const char *filesystem __unused, int read_only)
{
mtd_scan_partitions();
const MtdPartition *p;
@@ -804,9 +797,9 @@
int cmd_mtd_get_partition_device(const char *partition, char *device)
{
mtd_scan_partitions();
- MtdPartition *p = mtd_find_partition_by_name(partition);
+ const MtdPartition *p = mtd_find_partition_by_name(partition);
if (p == NULL)
return -1;
sprintf(device, "/dev/block/mtdblock%d", p->device_index);
return 0;
-}
\ No newline at end of file
+}
diff --git a/openaes/src/oaes.c b/openaes/src/oaes.c
index 9a5d268..203da52 100644
--- a/openaes/src/oaes.c
+++ b/openaes/src/oaes.c
@@ -38,7 +38,7 @@
#if defined(_WIN32) && !defined(__SYMBIAN32__)
#include <io.h>
#else
-__inline static int setmode(int a, int b)
+__inline static int setmode(int a __unused, int b __unused)
{
return 0;
}
@@ -79,7 +79,7 @@
int main(int argc, char** argv)
{
- size_t _i = 0, _j = 0;
+ int _i = 0, _j = 0;
OAES_CTX * ctx = NULL;
uint8_t _buf_in[OAES_BUF_LEN_DEC];
uint8_t *_buf_out = NULL, _key_data[32] = "";
@@ -249,8 +249,8 @@
oaes_key_import_data( ctx, _key_data, _key_data_len );
- while( _buf_in_len =
- fread(_buf_in, sizeof(uint8_t), _read_len, _f_in) )
+ while( (_buf_in_len =
+ fread(_buf_in, sizeof(uint8_t), _read_len, _f_in)) )
{
switch(_op)
{
diff --git a/openaes/src/oaes_lib.c b/openaes/src/oaes_lib.c
index 0cc0394..2e28159 100644
--- a/openaes/src/oaes_lib.c
+++ b/openaes/src/oaes_lib.c
@@ -27,9 +27,9 @@
* POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------
*/
-static const char _NR[] = {
+/*static const char _NR[] = {
0x4e,0x61,0x62,0x69,0x6c,0x20,0x53,0x2e,0x20,
- 0x41,0x6c,0x20,0x52,0x61,0x6d,0x6c,0x69,0x00 };
+ 0x41,0x6c,0x20,0x52,0x61,0x6d,0x6c,0x69,0x00 };*/
#include <stddef.h>
#include <time.h>
@@ -96,162 +96,162 @@
static uint8_t oaes_sub_byte_value[16][16] = {
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f,
- /*0*/ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
- /*1*/ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
- /*2*/ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
- /*3*/ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
- /*4*/ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
- /*5*/ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
- /*6*/ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
- /*7*/ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
- /*8*/ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
- /*9*/ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
- /*a*/ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
- /*b*/ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
- /*c*/ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
- /*d*/ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
- /*e*/ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
- /*f*/ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
+ /*0*/{ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76},
+ /*1*/{ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0},
+ /*2*/{ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15},
+ /*3*/{ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75},
+ /*4*/{ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84},
+ /*5*/{ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf},
+ /*6*/{ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8},
+ /*7*/{ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2},
+ /*8*/{ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73},
+ /*9*/{ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb},
+ /*a*/{ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79},
+ /*b*/{ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08},
+ /*c*/{ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a},
+ /*d*/{ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e},
+ /*e*/{ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf},
+ /*f*/{ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16},
};
static uint8_t oaes_inv_sub_byte_value[16][16] = {
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f,
- /*0*/ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
- /*1*/ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
- /*2*/ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
- /*3*/ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
- /*4*/ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
- /*5*/ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
- /*6*/ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
- /*7*/ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
- /*8*/ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
- /*9*/ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
- /*a*/ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
- /*b*/ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
- /*c*/ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
- /*d*/ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
- /*e*/ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
- /*f*/ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
+ /*0*/{ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb},
+ /*1*/{ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb},
+ /*2*/{ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e},
+ /*3*/{ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25},
+ /*4*/{ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92},
+ /*5*/{ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84},
+ /*6*/{ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06},
+ /*7*/{ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b},
+ /*8*/{ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73},
+ /*9*/{ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e},
+ /*a*/{ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b},
+ /*b*/{ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4},
+ /*c*/{ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f},
+ /*d*/{ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef},
+ /*e*/{ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61},
+ /*f*/{ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d},
};
static uint8_t oaes_gf_mul_2[16][16] = {
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f,
- /*0*/ 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
- /*1*/ 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
- /*2*/ 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
- /*3*/ 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
- /*4*/ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
- /*5*/ 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
- /*6*/ 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
- /*7*/ 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
- /*8*/ 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,
- /*9*/ 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25,
- /*a*/ 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45,
- /*b*/ 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,
- /*c*/ 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85,
- /*d*/ 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5,
- /*e*/ 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,
- /*f*/ 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5,
+ /*0*/{ 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e},
+ /*1*/{ 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e},
+ /*2*/{ 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e},
+ /*3*/{ 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e},
+ /*4*/{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e},
+ /*5*/{ 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe},
+ /*6*/{ 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde},
+ /*7*/{ 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe},
+ /*8*/{ 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05},
+ /*9*/{ 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25},
+ /*a*/{ 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45},
+ /*b*/{ 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65},
+ /*c*/{ 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85},
+ /*d*/{ 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5},
+ /*e*/{ 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5},
+ /*f*/{ 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5},
};
static uint8_t oaes_gf_mul_3[16][16] = {
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f,
- /*0*/ 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
- /*1*/ 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
- /*2*/ 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,
- /*3*/ 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41,
- /*4*/ 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1,
- /*5*/ 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1,
- /*6*/ 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1,
- /*7*/ 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81,
- /*8*/ 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a,
- /*9*/ 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba,
- /*a*/ 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea,
- /*b*/ 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda,
- /*c*/ 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a,
- /*d*/ 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a,
- /*e*/ 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,
- /*f*/ 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a,
+ /*0*/{ 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11},
+ /*1*/{ 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21},
+ /*2*/{ 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71},
+ /*3*/{ 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41},
+ /*4*/{ 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1},
+ /*5*/{ 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1},
+ /*6*/{ 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1},
+ /*7*/{ 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81},
+ /*8*/{ 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a},
+ /*9*/{ 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba},
+ /*a*/{ 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea},
+ /*b*/{ 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda},
+ /*c*/{ 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a},
+ /*d*/{ 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a},
+ /*e*/{ 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a},
+ /*f*/{ 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a},
};
static uint8_t oaes_gf_mul_9[16][16] = {
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f,
- /*0*/ 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
- /*1*/ 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7,
- /*2*/ 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
- /*3*/ 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc,
- /*4*/ 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01,
- /*5*/ 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91,
- /*6*/ 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a,
- /*7*/ 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa,
- /*8*/ 0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b,
- /*9*/ 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b,
- /*a*/ 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0,
- /*b*/ 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30,
- /*c*/ 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed,
- /*d*/ 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d,
- /*e*/ 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6,
- /*f*/ 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46,
+ /*0*/{ 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77},
+ /*1*/{ 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7},
+ /*2*/{ 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c},
+ /*3*/{ 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc},
+ /*4*/{ 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01},
+ /*5*/{ 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91},
+ /*6*/{ 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a},
+ /*7*/{ 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa},
+ /*8*/{ 0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b},
+ /*9*/{ 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b},
+ /*a*/{ 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0},
+ /*b*/{ 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30},
+ /*c*/{ 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed},
+ /*d*/{ 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d},
+ /*e*/{ 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6},
+ /*f*/{ 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46},
};
static uint8_t oaes_gf_mul_b[16][16] = {
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f,
- /*0*/ 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69,
- /*1*/ 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9,
- /*2*/ 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12,
- /*3*/ 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2,
- /*4*/ 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f,
- /*5*/ 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f,
- /*6*/ 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4,
- /*7*/ 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54,
- /*8*/ 0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e,
- /*9*/ 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e,
- /*a*/ 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5,
- /*b*/ 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55,
- /*c*/ 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68,
- /*d*/ 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8,
- /*e*/ 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13,
- /*f*/ 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3,
+ /*0*/{ 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69},
+ /*1*/{ 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9},
+ /*2*/{ 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12},
+ /*3*/{ 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2},
+ /*4*/{ 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f},
+ /*5*/{ 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f},
+ /*6*/{ 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4},
+ /*7*/{ 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54},
+ /*8*/{ 0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e},
+ /*9*/{ 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e},
+ /*a*/{ 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5},
+ /*b*/{ 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55},
+ /*c*/{ 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68},
+ /*d*/{ 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8},
+ /*e*/{ 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13},
+ /*f*/{ 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3},
};
static uint8_t oaes_gf_mul_d[16][16] = {
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f,
- /*0*/ 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b,
- /*1*/ 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b,
- /*2*/ 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0,
- /*3*/ 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20,
- /*4*/ 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26,
- /*5*/ 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6,
- /*6*/ 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d,
- /*7*/ 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d,
- /*8*/ 0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91,
- /*9*/ 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41,
- /*a*/ 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a,
- /*b*/ 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa,
- /*c*/ 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc,
- /*d*/ 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c,
- /*e*/ 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47,
- /*f*/ 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97,
+ /*0*/{ 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b},
+ /*1*/{ 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b},
+ /*2*/{ 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0},
+ /*3*/{ 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20},
+ /*4*/{ 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26},
+ /*5*/{ 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6},
+ /*6*/{ 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d},
+ /*7*/{ 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d},
+ /*8*/{ 0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91},
+ /*9*/{ 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41},
+ /*a*/{ 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a},
+ /*b*/{ 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa},
+ /*c*/{ 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc},
+ /*d*/{ 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c},
+ /*e*/{ 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47},
+ /*f*/{ 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97},
};
static uint8_t oaes_gf_mul_e[16][16] = {
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f,
- /*0*/ 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a,
- /*1*/ 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba,
- /*2*/ 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81,
- /*3*/ 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61,
- /*4*/ 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7,
- /*5*/ 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17,
- /*6*/ 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c,
- /*7*/ 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc,
- /*8*/ 0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b,
- /*9*/ 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb,
- /*a*/ 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0,
- /*b*/ 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20,
- /*c*/ 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6,
- /*d*/ 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56,
- /*e*/ 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d,
- /*f*/ 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d,
+ /*0*/{ 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a},
+ /*1*/{ 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba},
+ /*2*/{ 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81},
+ /*3*/{ 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61},
+ /*4*/{ 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7},
+ /*5*/{ 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17},
+ /*6*/{ 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c},
+ /*7*/{ 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc},
+ /*8*/{ 0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b},
+ /*9*/{ 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb},
+ /*a*/{ 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0},
+ /*b*/{ 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20},
+ /*c*/{ 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6},
+ /*d*/{ 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56},
+ /*e*/{ 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d},
+ /*f*/{ 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d},
};
static OAES_RET oaes_sub_byte( uint8_t * byte )
@@ -286,7 +286,7 @@
return OAES_RET_SUCCESS;
}
-static OAES_RET oaes_word_rot_right( uint8_t word[OAES_COL_LEN] )
+/*static OAES_RET oaes_word_rot_right( uint8_t word[OAES_COL_LEN] )
{
uint8_t _temp[OAES_COL_LEN];
@@ -298,7 +298,7 @@
memcpy( word, _temp, OAES_COL_LEN );
return OAES_RET_SUCCESS;
-}
+}*/
static OAES_RET oaes_word_rot_left( uint8_t word[OAES_COL_LEN] )
{
@@ -783,7 +783,7 @@
return OAES_RET_HEADER;
}
- if( data_len != _key_length + OAES_BLOCK_SIZE )
+ if( data_len != (size_t)_key_length + OAES_BLOCK_SIZE )
return OAES_RET_ARG3;
if( _ctx->key )
@@ -877,7 +877,6 @@
#ifdef OAES_HAVE_ISAAC
{
- ub4 _i = 0;
char _seed[RANDSIZ + 1];
_ctx->rctx = (randctx *) calloc( sizeof( randctx ), 1 );
diff --git a/otafault/Android.bp b/otafault/Android.bp
new file mode 100644
index 0000000..b39d5be
--- /dev/null
+++ b/otafault/Android.bp
@@ -0,0 +1,68 @@
+// 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.
+
+cc_library_static {
+ name: "libotafault",
+
+ host_supported: true,
+
+ srcs: [
+ "config.cpp",
+ "ota_io.cpp",
+ ],
+
+ static_libs: [
+ "libbase",
+ "liblog",
+ "libziparchive",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS",
+ "-Wall",
+ "-Werror",
+ "-Wthread-safety",
+ "-Wthread-safety-negative",
+ ],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+cc_test {
+ name: "otafault_test",
+
+ srcs: ["test.cpp"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ static_executable: true,
+
+ static_libs: [
+ "libotafault",
+ "libziparchive",
+ "libbase",
+ "liblog",
+ ],
+}
diff --git a/otafault/config.cpp b/otafault/config.cpp
index 8590833..3993948 100644
--- a/otafault/config.cpp
+++ b/otafault/config.cpp
@@ -14,17 +14,15 @@
* limitations under the License.
*/
+#include "otafault/config.h"
+
#include <map>
#include <string>
-#include <stdio.h>
-#include <unistd.h>
-
#include <android-base/stringprintf.h>
#include <ziparchive/zip_archive.h>
-#include "config.h"
-#include "ota_io.h"
+#include "otafault/ota_io.h"
#define OTAIO_MAX_FNAME_SIZE 128
@@ -69,7 +67,9 @@
fname.resize(OTAIO_MAX_FNAME_SIZE);
ZipString zip_type_path(type_path.c_str());
ZipEntry entry;
- int status = FindEntry(archive, zip_type_path, &entry);
+ if (FindEntry(archive, zip_type_path, &entry) != 0) {
+ return {};
+ }
ExtractToMemory(archive, &entry, reinterpret_cast<uint8_t*>(&fname[0]), OTAIO_MAX_FNAME_SIZE);
return fname;
}
diff --git a/otafault/config.h b/otafault/include/otafault/config.h
similarity index 76%
rename from otafault/config.h
rename to otafault/include/otafault/config.h
index 4adbdd1..cc4bfd2 100644
--- a/otafault/config.h
+++ b/otafault/include/otafault/config.h
@@ -15,13 +15,13 @@
*/
/*
- * Read configuration files in the OTA package to determine which files, if any, will trigger errors.
+ * Read configuration files in the OTA package to determine which files, if any, will trigger
+ * errors.
*
- * OTA packages can be modified to trigger errors by adding a top-level
- * directory called .libotafault, which may optionally contain up to three
- * files called READ, WRITE, and FSYNC. Each one of these optional files
- * contains the name of a single file on the device disk which will cause
- * an IO error on the first call of the appropriate I/O action to that file.
+ * OTA packages can be modified to trigger errors by adding a top-level directory called
+ * .libotafault, which may optionally contain up to three files called READ, WRITE, and FSYNC.
+ * Each one of these optional files contains the name of a single file on the device disk which
+ * will cause an IO error on the first call of the appropriate I/O action to that file.
*
* Example:
* ota.zip
@@ -29,9 +29,9 @@
* .libotafault
* WRITE
*
- * If the contents of the file WRITE were /system/build.prop, the first write
- * action to /system/build.prop would fail with EIO. Note that READ and
- * FSYNC files are absent, so these actions will not cause an error.
+ * If the contents of the file WRITE were /system/build.prop, the first write action to
+ * /system/build.prop would fail with EIO. Note that READ and FSYNC files are absent, so these
+ * actions will not cause an error.
*/
#ifndef _UPDATER_OTA_IO_CFG_H_
@@ -39,8 +39,6 @@
#include <string>
-#include <stdbool.h>
-
#include <ziparchive/zip_archive.h>
#define OTAIO_BASE_DIR ".libotafault"
diff --git a/otafault/ota_io.h b/otafault/include/otafault/ota_io.h
similarity index 96%
rename from otafault/ota_io.h
rename to otafault/include/otafault/ota_io.h
index 9428f1b..45e481a 100644
--- a/otafault/ota_io.h
+++ b/otafault/include/otafault/ota_io.h
@@ -23,8 +23,9 @@
#ifndef _UPDATER_OTA_IO_H_
#define _UPDATER_OTA_IO_H_
+#include <stddef.h>
#include <stdio.h>
-#include <sys/stat.h>
+#include <sys/stat.h> // mode_t
#include <memory>
diff --git a/otafault/ota_io.cpp b/otafault/ota_io.cpp
index faae527..63ef18e 100644
--- a/otafault/ota_io.cpp
+++ b/otafault/ota_io.cpp
@@ -14,20 +14,23 @@
* limitations under the License.
*/
-#include "ota_io.h"
+#include "otafault/ota_io.h"
#include <errno.h>
#include <fcntl.h>
+#include <stdint.h>
#include <stdio.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include <map>
-#include <memory>
#include <mutex>
+#include <string>
#include <android-base/thread_annotations.h>
-#include "config.h"
+
+#include "otafault/config.h"
static std::mutex filename_mutex;
static std::map<intptr_t, const char*> filename_cache GUARDED_BY(filename_mutex);
diff --git a/otafault/test.cpp b/otafault/test.cpp
index 6514782..63e2445 100644
--- a/otafault/test.cpp
+++ b/otafault/test.cpp
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
-#include "ota_io.h"
+#include "otafault/ota_io.h"
int main(int /* argc */, char** /* argv */) {
int fd = open("testdata/test.file", O_RDWR);
diff --git a/otautil/Android.bp b/otautil/Android.bp
index 0b23143..a109d39 100644
--- a/otautil/Android.bp
+++ b/otautil/Android.bp
@@ -15,11 +15,15 @@
cc_library_static {
name: "libotautil",
+ host_supported: true,
+
srcs: [
"SysUtil.cpp",
"DirUtil.cpp",
"ZipUtil.cpp",
"ThermalUtil.cpp",
+ "cache_location.cpp",
+ "rangeset.cpp",
],
static_libs: [
@@ -28,7 +32,12 @@
],
cflags: [
+ "-D_FILE_OFFSET_BITS=64",
"-Werror",
"-Wall",
],
+
+ export_include_dirs: [
+ "include",
+ ],
}
diff --git a/otautil/Android.mk b/otautil/Android.mk
index 45e0f76..feb468d 100644
--- a/otautil/Android.mk
+++ b/otautil/Android.mk
@@ -36,4 +36,6 @@
-Werror \
-Wall
+LOCAL_C_INCLUDES := include
+
include $(BUILD_STATIC_LIBRARY)
diff --git a/otautil/DirUtil.cpp b/otautil/DirUtil.cpp
index e08e360..8d364b7 100644
--- a/otautil/DirUtil.cpp
+++ b/otautil/DirUtil.cpp
@@ -14,24 +14,107 @@
* limitations under the License.
*/
-#include "DirUtil.h"
+#include "otautil/DirUtil.h"
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
#include <dirent.h>
-#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utime.h>
#include <string>
#include <selinux/label.h>
#include <selinux/selinux.h>
-typedef enum { DMISSING, DDIR, DILLEGAL } DirStatus;
+enum class DirStatus { DMISSING, DDIR, DILLEGAL };
+
+static DirStatus dir_status(const std::string& path) {
+ struct stat sb;
+ if (stat(path.c_str(), &sb) == 0) {
+ // Something's there; make sure it's a directory.
+ if (S_ISDIR(sb.st_mode)) {
+ return DirStatus::DDIR;
+ }
+ errno = ENOTDIR;
+ return DirStatus::DILLEGAL;
+ } else if (errno != ENOENT) {
+ // Something went wrong, or something in the path is bad. Can't do anything in this situation.
+ return DirStatus::DILLEGAL;
+ }
+ return DirStatus::DMISSING;
+}
+
+int mkdir_recursively(const std::string& input_path, mode_t mode, bool strip_filename,
+ const selabel_handle* sehnd) {
+ // Check for an empty string before we bother making any syscalls.
+ if (input_path.empty()) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ // Allocate a path that we can modify; stick a slash on the end to make things easier.
+ std::string path = input_path;
+ if (strip_filename) {
+ // Strip everything after the last slash.
+ size_t pos = path.rfind('/');
+ if (pos == std::string::npos) {
+ errno = ENOENT;
+ return -1;
+ }
+ path.resize(pos + 1);
+ } else {
+ // Make sure that the path ends in a slash.
+ path.push_back('/');
+ }
+
+ // See if it already exists.
+ DirStatus ds = dir_status(path);
+ if (ds == DirStatus::DDIR) {
+ return 0;
+ } else if (ds == DirStatus::DILLEGAL) {
+ return -1;
+ }
+
+ // Walk up the path from the root and make each level.
+ size_t prev_end = 0;
+ while (prev_end < path.size()) {
+ size_t next_end = path.find('/', prev_end + 1);
+ if (next_end == std::string::npos) {
+ break;
+ }
+ std::string dir_path = path.substr(0, next_end);
+ // Check this part of the path and make a new directory if necessary.
+ switch (dir_status(dir_path)) {
+ case DirStatus::DILLEGAL:
+ // Could happen if some other process/thread is messing with the filesystem.
+ return -1;
+ case DirStatus::DMISSING: {
+ char* secontext = nullptr;
+ if (sehnd) {
+ selabel_lookup(const_cast<selabel_handle*>(sehnd), &secontext, dir_path.c_str(), mode);
+ setfscreatecon(secontext);
+ }
+ int err = mkdir(dir_path.c_str(), mode);
+ if (secontext) {
+ freecon(secontext);
+ setfscreatecon(nullptr);
+ }
+ if (err != 0) {
+ return -1;
+ }
+ break;
+ }
+ default:
+ // Already exists.
+ break;
+ }
+ prev_end = next_end;
+ }
+ return 0;
+}
static DirStatus
getPathDirStatus(const char *path)
@@ -44,17 +127,17 @@
/* Something's there; make sure it's a directory.
*/
if (S_ISDIR(st.st_mode)) {
- return DDIR;
+ return DirStatus::DDIR;
}
errno = ENOTDIR;
- return DILLEGAL;
+ return DirStatus::DILLEGAL;
} else if (errno != ENOENT) {
/* Something went wrong, or something in the path
* is bad. Can't do anything in this situation.
*/
- return DILLEGAL;
+ return DirStatus::DILLEGAL;
}
- return DMISSING;
+ return DirStatus::DMISSING;
}
int
@@ -90,9 +173,9 @@
/* See if it already exists.
*/
ds = getPathDirStatus(cpath.c_str());
- if (ds == DDIR) {
+ if (ds == DirStatus::DDIR) {
return 0;
- } else if (ds == DILLEGAL) {
+ } else if (ds == DirStatus::DILLEGAL) {
return -1;
}
@@ -124,12 +207,12 @@
* if necessary.
*/
ds = getPathDirStatus(path_start);
- if (ds == DILLEGAL) {
+ if (ds == DirStatus::DILLEGAL) {
/* Could happen if some other process/thread is
* messing with the filesystem.
*/
return -1;
- } else if (ds == DMISSING) {
+ } else if (ds == DirStatus::DMISSING) {
int err;
char *secontext = NULL;
diff --git a/otautil/SysUtil.cpp b/otautil/SysUtil.cpp
index dfa2150..48336ad 100644
--- a/otautil/SysUtil.cpp
+++ b/otautil/SysUtil.cpp
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-#include "SysUtil.h"
+#include "otautil/SysUtil.h"
+#include <errno.h> // TEMP_FAILURE_RETRY
#include <fcntl.h>
#include <stdint.h> // SIZE_MAX
#include <sys/mman.h>
@@ -100,7 +101,7 @@
}
// Reserve enough contiguous address space for the whole file.
- void* reserve = mmap64(nullptr, blocks * blksize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
+ void* reserve = mmap(nullptr, blocks * blksize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (reserve == MAP_FAILED) {
PLOG(ERROR) << "failed to reserve address space";
return false;
@@ -135,8 +136,8 @@
break;
}
- void* range_start = mmap64(next, range_size, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd,
- static_cast<off64_t>(start) * blksize);
+ void* range_start = mmap(next, range_size, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd,
+ static_cast<off_t>(start) * blksize);
if (range_start == MAP_FAILED) {
PLOG(ERROR) << "failed to map range " << i << ": " << line;
success = false;
diff --git a/otautil/ThermalUtil.cpp b/otautil/ThermalUtil.cpp
index 13d3643..5d9bd45 100644
--- a/otautil/ThermalUtil.cpp
+++ b/otautil/ThermalUtil.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "ThermalUtil.h"
+#include "otautil/ThermalUtil.h"
#include <dirent.h>
#include <stdio.h>
@@ -77,4 +77,4 @@
}
LOG(INFO) << "current maximum temperature: " << max_temperature;
return max_temperature;
-}
\ No newline at end of file
+}
diff --git a/otautil/ZipUtil.cpp b/otautil/ZipUtil.cpp
index 714c956..a2d0cba 100644
--- a/otautil/ZipUtil.cpp
+++ b/otautil/ZipUtil.cpp
@@ -28,7 +28,7 @@
#include <selinux/selinux.h>
#include <ziparchive/zip_archive.h>
-#include "DirUtil.h"
+#include "otautil/DirUtil.h"
static constexpr mode_t UNZIP_DIRMODE = 0755;
static constexpr mode_t UNZIP_FILEMODE = 0644;
diff --git a/otautil/cache_location.cpp b/otautil/cache_location.cpp
new file mode 100644
index 0000000..8ddefec
--- /dev/null
+++ b/otautil/cache_location.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 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 "otautil/cache_location.h"
+
+constexpr const char kDefaultCacheTempSource[] = "/cache/saved.file";
+constexpr const char kDefaultLastCommandFile[] = "/cache/recovery/last_command";
+constexpr const char kDefaultStashDirectoryBase[] = "/cache/recovery";
+
+CacheLocation& CacheLocation::location() {
+ static CacheLocation cache_location;
+ return cache_location;
+}
+
+CacheLocation::CacheLocation()
+ : cache_temp_source_(kDefaultCacheTempSource),
+ last_command_file_(kDefaultLastCommandFile),
+ stash_directory_base_(kDefaultStashDirectoryBase) {}
diff --git a/otautil/DirUtil.h b/otautil/include/otautil/DirUtil.h
similarity index 65%
rename from otautil/DirUtil.h
rename to otautil/include/otautil/DirUtil.h
index 85b83c3..e3d0219 100644
--- a/otautil/DirUtil.h
+++ b/otautil/include/otautil/DirUtil.h
@@ -14,18 +14,28 @@
* limitations under the License.
*/
-#ifndef MINZIP_DIRUTIL_H_
-#define MINZIP_DIRUTIL_H_
+#ifndef OTAUTIL_DIRUTIL_H_
+#define OTAUTIL_DIRUTIL_H_
-#include <stdbool.h>
-#include <utime.h>
+#include <sys/stat.h> // mode_t
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include <string>
struct selabel_handle;
+// Like "mkdir -p", try to guarantee that all directories specified in path are present, creating as
+// many directories as necessary. The specified mode is passed to all mkdir calls; no modifications
+// are made to umask.
+//
+// If strip_filename is set, everything after the final '/' is stripped before creating the
+// directory
+// hierarchy.
+//
+// Returns 0 on success; returns -1 (and sets errno) on failure (usually if some element of path is
+// not a directory).
+int mkdir_recursively(const std::string& path, mode_t mode, bool strip_filename,
+ const struct selabel_handle* sehnd);
+
/* Like "mkdir -p", try to guarantee that all directories
* specified in path are present, creating as many directories
* as necessary. The specified mode is passed to all mkdir
@@ -47,8 +57,4 @@
*/
int dirUnlinkHierarchy(const char *path);
-#ifdef __cplusplus
-}
-#endif
-
-#endif // MINZIP_DIRUTIL_H_
+#endif // OTAUTIL_DIRUTIL_H_
diff --git a/otautil/SysUtil.h b/otautil/include/otautil/SysUtil.h
similarity index 100%
rename from otautil/SysUtil.h
rename to otautil/include/otautil/SysUtil.h
diff --git a/otautil/ThermalUtil.h b/otautil/include/otautil/ThermalUtil.h
similarity index 100%
rename from otautil/ThermalUtil.h
rename to otautil/include/otautil/ThermalUtil.h
diff --git a/otautil/include/otautil/cache_location.h b/otautil/include/otautil/cache_location.h
new file mode 100644
index 0000000..f2f6638
--- /dev/null
+++ b/otautil/include/otautil/cache_location.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 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_OTAUTIL_CACHE_LOCATION_H_
+#define _OTAUTIL_OTAUTIL_CACHE_LOCATION_H_
+
+#include <string>
+
+#include "android-base/macros.h"
+
+// A singleton class to maintain the update related locations. The locations should be only set
+// once at the start of the program.
+class CacheLocation {
+ public:
+ static CacheLocation& location();
+
+ // getter and setter functions.
+ std::string cache_temp_source() const {
+ return cache_temp_source_;
+ }
+ void set_cache_temp_source(const std::string& temp_source) {
+ cache_temp_source_ = temp_source;
+ }
+
+ std::string last_command_file() const {
+ return last_command_file_;
+ }
+ void set_last_command_file(const std::string& last_command) {
+ last_command_file_ = last_command;
+ }
+
+ std::string stash_directory_base() const {
+ return stash_directory_base_;
+ }
+ void set_stash_directory_base(const std::string& base) {
+ stash_directory_base_ = base;
+ }
+
+ private:
+ CacheLocation();
+ DISALLOW_COPY_AND_ASSIGN(CacheLocation);
+
+ // When there isn't enough room on the target filesystem to hold the patched version of the file,
+ // we copy the original here and delete it to free up space. If the expected source file doesn't
+ // exist, or is corrupted, we look to see if the cached file contains the bits we want and use it
+ // as the source instead. The default location for the cached source is "/cache/saved.file".
+ std::string cache_temp_source_;
+
+ // Location to save the last command that stashes blocks.
+ std::string last_command_file_;
+
+ // The base directory to write stashes during update.
+ std::string stash_directory_base_;
+};
+
+#endif // _OTAUTIL_OTAUTIL_CACHE_LOCATION_H_
diff --git a/error_code.h b/otautil/include/otautil/error_code.h
similarity index 87%
rename from error_code.h
rename to otautil/include/otautil/error_code.h
index 9fe047c..b0ff42d 100644
--- a/error_code.h
+++ b/otautil/include/otautil/error_code.h
@@ -17,7 +17,7 @@
#ifndef _ERROR_CODE_H_
#define _ERROR_CODE_H_
-enum ErrorCode {
+enum ErrorCode : int {
kNoError = -1,
kLowBattery = 20,
kZipVerificationFailure,
@@ -25,9 +25,12 @@
kBootreasonInBlacklist,
kPackageCompatibilityFailure,
kScriptExecutionFailure,
+ kMapFileFailure,
+ kForkUpdateBinaryFailure,
+ kUpdateBinaryCommandFailure,
};
-enum CauseCode {
+enum CauseCode : int {
kNoCause = -1,
kArgsParsingFailure = 100,
kStashCreationFailure,
@@ -48,7 +51,7 @@
kVendorFailure = 200
};
-enum UncryptErrorCode {
+enum UncryptErrorCode : int {
kUncryptNoError = -1,
kUncryptErrorPlaceholder = 50,
kUncryptTimeoutError = 100,
@@ -68,6 +71,8 @@
kUncryptFileCloseError,
kUncryptFileRenameError,
kUncryptPackageMissingError,
+ kUncryptRealpathFindError,
+ kUncryptBlockDeviceFindError,
};
-#endif // _ERROR_CODE_H_
+#endif // _ERROR_CODE_H_
diff --git a/otautil/include/otautil/print_sha1.h b/otautil/include/otautil/print_sha1.h
new file mode 100644
index 0000000..03a8d29
--- /dev/null
+++ b/otautil/include/otautil/print_sha1.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 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_PRINT_SHA1_H
+#define RECOVERY_PRINT_SHA1_H
+
+#include <stdint.h>
+#include <string>
+
+#include <openssl/sha.h>
+
+static std::string print_sha1(const uint8_t* sha1, size_t len) {
+ const char* hex = "0123456789abcdef";
+ std::string result = "";
+ for (size_t i = 0; i < len; ++i) {
+ result.push_back(hex[(sha1[i] >> 4) & 0xf]);
+ result.push_back(hex[sha1[i] & 0xf]);
+ }
+ return result;
+}
+
+[[maybe_unused]] static std::string print_sha1(const uint8_t sha1[SHA_DIGEST_LENGTH]) {
+ return print_sha1(sha1, SHA_DIGEST_LENGTH);
+}
+
+[[maybe_unused]] static std::string short_sha1(const uint8_t sha1[SHA_DIGEST_LENGTH]) {
+ return print_sha1(sha1, 4);
+}
+
+[[maybe_unused]] static std::string print_hex(const uint8_t* bytes, size_t len) {
+ return print_sha1(bytes, len);
+}
+
+#endif // RECOVERY_PRINT_SHA1_H
diff --git a/otautil/include/otautil/rangeset.h b/otautil/include/otautil/rangeset.h
new file mode 100644
index 0000000..e91d02c
--- /dev/null
+++ b/otautil/include/otautil/rangeset.h
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stddef.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+using Range = std::pair<size_t, size_t>;
+
+class RangeSet {
+ public:
+ RangeSet() : blocks_(0) {}
+
+ explicit RangeSet(std::vector<Range>&& pairs);
+
+ // Parses the given string into a RangeSet. Returns the parsed RangeSet, or an empty RangeSet on
+ // errors.
+ static RangeSet Parse(const std::string& range_text);
+
+ // Appends the given Range to the current RangeSet.
+ bool PushBack(Range range);
+
+ // Clears all the ranges from the RangeSet.
+ void Clear();
+
+ std::string ToString() const;
+
+ // Gets the block number for the i-th (starting from 0) block in the RangeSet.
+ size_t GetBlockNumber(size_t idx) const;
+
+ // Returns whether the current RangeSet overlaps with other. RangeSet has half-closed half-open
+ // bounds. For example, "3,5" contains blocks 3 and 4. So "3,5" and "5,7" are not overlapped.
+ bool Overlaps(const RangeSet& other) const;
+
+ // Returns a vector of RangeSets that contain the same set of blocks represented by the current
+ // RangeSet. The RangeSets in the vector contain similar number of blocks, with a maximum delta
+ // of 1-block between any two of them. For example, 14 blocks would be split into 4 + 4 + 3 + 3,
+ // as opposed to 4 + 4 + 4 + 2. If the total number of blocks (T) is less than groups, it
+ // returns a vector of T 1-block RangeSets. Otherwise the number of the returned RangeSets must
+ // equal to groups. The current RangeSet remains intact after the split.
+ std::vector<RangeSet> Split(size_t groups) const;
+
+ // Returns the number of Range's in this RangeSet.
+ size_t size() const {
+ return ranges_.size();
+ }
+
+ // Returns the total number of blocks in this RangeSet.
+ size_t blocks() const {
+ return blocks_;
+ }
+
+ std::vector<Range>::const_iterator cbegin() const {
+ return ranges_.cbegin();
+ }
+
+ std::vector<Range>::const_iterator cend() const {
+ return ranges_.cend();
+ }
+
+ std::vector<Range>::iterator begin() {
+ return ranges_.begin();
+ }
+
+ std::vector<Range>::iterator end() {
+ return ranges_.end();
+ }
+
+ std::vector<Range>::const_iterator begin() const {
+ return ranges_.begin();
+ }
+
+ std::vector<Range>::const_iterator end() const {
+ return ranges_.end();
+ }
+
+ // Reverse const iterators for MoveRange().
+ std::vector<Range>::const_reverse_iterator crbegin() const {
+ return ranges_.crbegin();
+ }
+
+ std::vector<Range>::const_reverse_iterator crend() const {
+ return ranges_.crend();
+ }
+
+ // Returns whether the RangeSet is valid (i.e. non-empty).
+ explicit operator bool() const {
+ return !ranges_.empty();
+ }
+
+ const Range& operator[](size_t i) const {
+ return ranges_[i];
+ }
+
+ bool operator==(const RangeSet& other) const {
+ // The orders of Range's matter. "4,1,5,8,10" != "4,8,10,1,5".
+ return (ranges_ == other.ranges_);
+ }
+
+ bool operator!=(const RangeSet& other) const {
+ return ranges_ != other.ranges_;
+ }
+
+ protected:
+ // Actual limit for each value and the total number are both INT_MAX.
+ std::vector<Range> ranges_;
+ size_t blocks_;
+};
+
+// The class is a sorted version of a RangeSet; and it's useful in imgdiff to split the input
+// files when we're handling large zip files. Specifically, we can treat the input file as a
+// continuous RangeSet (i.e. RangeSet("0-99") for a 100 blocks file); and break it down into
+// several smaller chunks based on the zip entries.
+
+// For example, [source: 0-99] can be split into
+// [split_src1: 10-29]; [split_src2: 40-49, 60-69]; [split_src3: 70-89]
+// Here "10-29" simply means block 10th to block 29th with respect to the original input file.
+// Also, note that the split sources should be mutual exclusive, but they don't need to cover
+// every block in the original source.
+class SortedRangeSet : public RangeSet {
+ public:
+ // The block size when working with offset and file length.
+ static constexpr size_t kBlockSize = 4096;
+
+ SortedRangeSet() {}
+
+ // Ranges in the the set should be mutually exclusive; and they're sorted by the start block.
+ explicit SortedRangeSet(std::vector<Range>&& pairs);
+
+ void Insert(const Range& to_insert);
+
+ // Insert the input SortedRangeSet; keep the ranges sorted and merge the overlap ranges.
+ void Insert(const SortedRangeSet& rs);
+
+ // Compute the block range the file occupies, and insert that range.
+ void Insert(size_t start, size_t len);
+
+ using RangeSet::Overlaps;
+
+ bool Overlaps(size_t start, size_t len) const;
+
+ // Given an offset of the file, checks if the corresponding block (by considering the file as
+ // 0-based continuous block ranges) is covered by the SortedRangeSet. If so, returns the offset
+ // within this SortedRangeSet.
+ //
+ // For example, the 4106-th byte of a file is from block 1, assuming a block size of 4096-byte.
+ // The mapped offset within a SortedRangeSet("1-9 15-19") is 10.
+ //
+ // An offset of 65546 falls into the 16-th block in a file. Block 16 is contained as the 10-th
+ // item in SortedRangeSet("1-9 15-19"). So its data can be found at offset 40970 (i.e. 4096 * 10
+ // + 10) in a range represented by this SortedRangeSet.
+ size_t GetOffsetInRangeSet(size_t old_offset) const;
+};
diff --git a/otautil/rangeset.cpp b/otautil/rangeset.cpp
new file mode 100644
index 0000000..96955b9
--- /dev/null
+++ b/otautil/rangeset.cpp
@@ -0,0 +1,267 @@
+/*
+ * 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.
+ */
+
+#include "otautil/rangeset.h"
+
+#include <limits.h>
+#include <stddef.h>
+
+#include <algorithm>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+RangeSet::RangeSet(std::vector<Range>&& pairs) {
+ blocks_ = 0;
+ if (pairs.empty()) {
+ LOG(ERROR) << "Invalid number of tokens";
+ return;
+ }
+
+ for (const auto& range : pairs) {
+ if (!PushBack(range)) {
+ Clear();
+ return;
+ }
+ }
+}
+
+RangeSet RangeSet::Parse(const std::string& range_text) {
+ std::vector<std::string> pieces = android::base::Split(range_text, ",");
+ if (pieces.size() < 3) {
+ LOG(ERROR) << "Invalid range text: " << range_text;
+ return {};
+ }
+
+ size_t num;
+ if (!android::base::ParseUint(pieces[0], &num, static_cast<size_t>(INT_MAX))) {
+ LOG(ERROR) << "Failed to parse the number of tokens: " << range_text;
+ return {};
+ }
+ if (num == 0) {
+ LOG(ERROR) << "Invalid number of tokens: " << range_text;
+ return {};
+ }
+ if (num % 2 != 0) {
+ LOG(ERROR) << "Number of tokens must be even: " << range_text;
+ return {};
+ }
+ if (num != pieces.size() - 1) {
+ LOG(ERROR) << "Mismatching number of tokens: " << range_text;
+ return {};
+ }
+
+ std::vector<Range> pairs;
+ for (size_t i = 0; i < num; i += 2) {
+ size_t first;
+ size_t second;
+ if (!android::base::ParseUint(pieces[i + 1], &first, static_cast<size_t>(INT_MAX)) ||
+ !android::base::ParseUint(pieces[i + 2], &second, static_cast<size_t>(INT_MAX))) {
+ return {};
+ }
+ pairs.emplace_back(first, second);
+ }
+ return RangeSet(std::move(pairs));
+}
+
+bool RangeSet::PushBack(Range range) {
+ if (range.first >= range.second) {
+ LOG(ERROR) << "Empty or negative range: " << range.first << ", " << range.second;
+ return false;
+ }
+ size_t sz = range.second - range.first;
+ if (blocks_ >= SIZE_MAX - sz) {
+ LOG(ERROR) << "RangeSet size overflow";
+ return false;
+ }
+
+ ranges_.push_back(std::move(range));
+ blocks_ += sz;
+ return true;
+}
+
+void RangeSet::Clear() {
+ ranges_.clear();
+ blocks_ = 0;
+}
+
+std::vector<RangeSet> RangeSet::Split(size_t groups) const {
+ if (ranges_.empty() || groups == 0) return {};
+
+ if (blocks_ < groups) {
+ groups = blocks_;
+ }
+
+ // Evenly distribute blocks, with the first few groups possibly containing one more.
+ size_t mean = blocks_ / groups;
+ std::vector<size_t> blocks_per_group(groups, mean);
+ std::fill_n(blocks_per_group.begin(), blocks_ % groups, mean + 1);
+
+ std::vector<RangeSet> result;
+
+ // Forward iterate Ranges and fill up each group with the desired number of blocks.
+ auto it = ranges_.cbegin();
+ Range range = *it;
+ for (const auto& blocks : blocks_per_group) {
+ RangeSet buffer;
+ size_t needed = blocks;
+ while (needed > 0) {
+ size_t range_blocks = range.second - range.first;
+ if (range_blocks > needed) {
+ // Split the current range and don't advance the iterator.
+ buffer.PushBack({ range.first, range.first + needed });
+ range.first = range.first + needed;
+ break;
+ }
+ buffer.PushBack(range);
+ it++;
+ if (it != ranges_.cend()) {
+ range = *it;
+ }
+ needed -= range_blocks;
+ }
+ result.push_back(std::move(buffer));
+ }
+ return result;
+}
+
+std::string RangeSet::ToString() const {
+ if (ranges_.empty()) {
+ return "";
+ }
+ std::string result = std::to_string(ranges_.size() * 2);
+ for (const auto& r : ranges_) {
+ result += android::base::StringPrintf(",%zu,%zu", r.first, r.second);
+ }
+
+ return result;
+}
+
+// Get the block number for the i-th (starting from 0) block in the RangeSet.
+size_t RangeSet::GetBlockNumber(size_t idx) const {
+ CHECK_LT(idx, blocks_) << "Out of bound index " << idx << " (total blocks: " << blocks_ << ")";
+
+ for (const auto& range : ranges_) {
+ if (idx < range.second - range.first) {
+ return range.first + idx;
+ }
+ idx -= (range.second - range.first);
+ }
+
+ CHECK(false) << "Failed to find block number for index " << idx;
+ return 0; // Unreachable, but to make compiler happy.
+}
+
+// RangeSet has half-closed half-open bounds. For example, "3,5" contains blocks 3 and 4. So "3,5"
+// and "5,7" are not overlapped.
+bool RangeSet::Overlaps(const RangeSet& other) const {
+ for (const auto& range : ranges_) {
+ size_t start = range.first;
+ size_t end = range.second;
+ for (const auto& other_range : other.ranges_) {
+ size_t other_start = other_range.first;
+ size_t other_end = other_range.second;
+ // [start, end) vs [other_start, other_end)
+ if (!(other_start >= end || start >= other_end)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// Ranges in the the set should be mutually exclusive; and they're sorted by the start block.
+SortedRangeSet::SortedRangeSet(std::vector<Range>&& pairs) : RangeSet(std::move(pairs)) {
+ std::sort(ranges_.begin(), ranges_.end());
+}
+
+void SortedRangeSet::Insert(const Range& to_insert) {
+ SortedRangeSet rs({ to_insert });
+ Insert(rs);
+}
+
+// Insert the input SortedRangeSet; keep the ranges sorted and merge the overlap ranges.
+void SortedRangeSet::Insert(const SortedRangeSet& rs) {
+ if (rs.size() == 0) {
+ return;
+ }
+ // Merge and sort the two RangeSets.
+ std::vector<Range> temp = std::move(ranges_);
+ std::copy(rs.begin(), rs.end(), std::back_inserter(temp));
+ std::sort(temp.begin(), temp.end());
+
+ Clear();
+ // Trim overlaps and insert the result back to ranges_.
+ Range to_insert = temp.front();
+ for (auto it = temp.cbegin() + 1; it != temp.cend(); it++) {
+ if (it->first <= to_insert.second) {
+ to_insert.second = std::max(to_insert.second, it->second);
+ } else {
+ ranges_.push_back(to_insert);
+ blocks_ += (to_insert.second - to_insert.first);
+ to_insert = *it;
+ }
+ }
+ ranges_.push_back(to_insert);
+ blocks_ += (to_insert.second - to_insert.first);
+}
+
+// Compute the block range the file occupies, and insert that range.
+void SortedRangeSet::Insert(size_t start, size_t len) {
+ Range to_insert{ start / kBlockSize, (start + len - 1) / kBlockSize + 1 };
+ Insert(to_insert);
+}
+
+bool SortedRangeSet::Overlaps(size_t start, size_t len) const {
+ RangeSet rs({ { start / kBlockSize, (start + len - 1) / kBlockSize + 1 } });
+ return Overlaps(rs);
+}
+
+// Given an offset of the file, checks if the corresponding block (by considering the file as
+// 0-based continuous block ranges) is covered by the SortedRangeSet. If so, returns the offset
+// within this SortedRangeSet.
+//
+// For example, the 4106-th byte of a file is from block 1, assuming a block size of 4096-byte.
+// The mapped offset within a SortedRangeSet("1-9 15-19") is 10.
+//
+// An offset of 65546 falls into the 16-th block in a file. Block 16 is contained as the 10-th
+// item in SortedRangeSet("1-9 15-19"). So its data can be found at offset 40970 (i.e. 4096 * 10
+// + 10) in a range represented by this SortedRangeSet.
+size_t SortedRangeSet::GetOffsetInRangeSet(size_t old_offset) const {
+ size_t old_block_start = old_offset / kBlockSize;
+ size_t new_block_start = 0;
+ for (const auto& range : ranges_) {
+ // Find the index of old_block_start.
+ if (old_block_start >= range.second) {
+ new_block_start += (range.second - range.first);
+ } else if (old_block_start >= range.first) {
+ new_block_start += (old_block_start - range.first);
+ return (new_block_start * kBlockSize + old_offset % kBlockSize);
+ } else {
+ CHECK(false) << "block_start " << old_block_start
+ << " is missing between two ranges: " << this->ToString();
+ return 0;
+ }
+ }
+ CHECK(false) << "block_start " << old_block_start
+ << " exceeds the limit of current RangeSet: " << this->ToString();
+ return 0;
+}
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index 8784968..5c8a437 100644
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -754,7 +754,6 @@
int TWPartitionManager::Run_Backup(bool adbbackup) {
PartitionSettings part_settings;
int partition_count = 0, disable_free_space_check = 0, skip_digest = 0;
- int gui_adb_backup;
string Backup_Name, Backup_List, backup_path;
unsigned long long total_bytes = 0, free_space = 0;
TWPartition* storage = NULL;
diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk
index 6e9bcfe..fb27f0a 100644
--- a/prebuilt/Android.mk
+++ b/prebuilt/Android.mk
@@ -183,7 +183,6 @@
ifeq ($(TW_INCLUDE_CRYPTO_FBE), true)
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libe4crypt.so
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libgatekeeper.so
- RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libsoftkeymaster.so
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libkeymaster_messages.so
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libkeystore_binder.so
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libbinder.so
@@ -210,6 +209,9 @@
else
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libkeymaster1.so
endif
+ ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 28; echo $$?),0)
+ RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libsoftkeymaster.so
+ endif
endif
endif
ifeq ($(AB_OTA_UPDATER), true)
@@ -219,7 +221,9 @@
endif
endif
ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
- RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/make_ext4fs
+ ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 28; echo $$?),0)
+ RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/make_ext4fs
+ endif
endif
ifneq ($(wildcard system/core/libsparse/Android.*),)
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libsparse.so
@@ -313,10 +317,19 @@
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/android.hidl.base@1.0.so
endif
endif
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 27; echo $$?),0)
+ RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libclang_rt.ubsan_standalone-aarch64-android.so
+ RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/liblogwrap.so
+endif
+
+TW_BB_SYMLINKS :=
+ifneq ($(TW_USE_TOOLBOX), true)
+ TW_BB_SYMLINKS := busybox_symlinks
+endif
TWRP_AUTOGEN := $(intermediates)/teamwin
GEN := $(intermediates)/teamwin
-$(GEN): $(RELINK)
+$(GEN): $(RELINK) $(TW_BB_SYMLINKS)
$(GEN): $(RELINK_SOURCE_FILES) $(call intermediates-dir-for,EXECUTABLES,init)/init
$(RELINK) $(TARGET_RECOVERY_ROOT_OUT)/sbin $(RELINK_SOURCE_FILES)
diff --git a/print_sha1.h b/print_sha1.h
deleted file mode 100644
index 1f85895..0000000
--- a/print_sha1.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2015 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_PRINT_SHA1_H
-#define RECOVERY_PRINT_SHA1_H
-
-#include <stdint.h>
-#include <string>
-
-#include <openssl/sha.h>
-
-static std::string print_sha1(const uint8_t* sha1, size_t len) {
- const char* hex = "0123456789abcdef";
- std::string result = "";
- for (size_t i = 0; i < len; ++i) {
- result.push_back(hex[(sha1[i]>>4) & 0xf]);
- result.push_back(hex[sha1[i] & 0xf]);
- }
- return result;
-}
-
-static std::string print_sha1(const uint8_t sha1[SHA_DIGEST_LENGTH]) {
- return print_sha1(sha1, SHA_DIGEST_LENGTH);
-}
-
-static std::string short_sha1(const uint8_t sha1[SHA_DIGEST_LENGTH]) {
- return print_sha1(sha1, 4);
-}
-
-static std::string print_hex(const uint8_t* bytes, size_t len) {
- return print_sha1(bytes, len);
-}
-
-#endif // RECOVERY_PRINT_SHA1_H
diff --git a/recovery-persist.rc b/recovery-persist.rc
index 6761627..135a3c3 100644
--- a/recovery-persist.rc
+++ b/recovery-persist.rc
@@ -1,3 +1,3 @@
on post-fs-data
mkdir /data/misc/recovery 0770 system log
- exec - system log -- /system/bin/recovery-persist
+ exec_background - system log -- /system/bin/recovery-persist
diff --git a/recovery-refresh.rc b/recovery-refresh.rc
index 14b05cc..9fefc81 100644
--- a/recovery-refresh.rc
+++ b/recovery-refresh.rc
@@ -1,2 +1,2 @@
on post-fs
- exec - system log -- /system/bin/recovery-refresh
+ exec_background - system log -- /system/bin/recovery-refresh
diff --git a/recovery.cpp b/recovery.cpp
index 07bd7b9..07ec5cf 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -50,9 +50,9 @@
#include <bootloader_message/bootloader_message.h>
#include <cutils/android_reboot.h>
#include <cutils/properties.h> /* for property_list */
-#include <healthd/BatteryMonitor.h>
-#include <private/android_logger.h> /* private pmsg functions */
-#include <private/android_filesystem_config.h> /* for AID_SYSTEM */
+#include <health2/Health.h>
+#include <private/android_filesystem_config.h> /* for AID_SYSTEM */
+#include <private/android_logger.h> /* private pmsg functions */
#include <selinux/android.h>
#include <selinux/label.h>
#include <selinux/selinux.h>
@@ -61,13 +61,13 @@
#include "adb_install.h"
#include "common.h"
#include "device.h"
-#include "error_code.h"
#include "fuse_sdcard_provider.h"
#include "fuse_sideload.h"
#include "install.h"
#include "minadbd/minadbd.h"
#include "minui/minui.h"
#include "otautil/DirUtil.h"
+#include "otautil/error_code.h"
#include "roots.h"
#include "rotate_logs.h"
#include "screen_ui.h"
@@ -108,6 +108,7 @@
static const char *CONVERT_FBE_FILE = "/tmp/convert_fbe/convert_fbe";
static const char *CACHE_ROOT = "/cache";
static const char *DATA_ROOT = "/data";
+static const char* METADATA_ROOT = "/metadata";
static const char *SDCARD_ROOT = "/sdcard";
static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
@@ -125,6 +126,10 @@
static constexpr const char* RECOVERY_WIPE = "/etc/recovery.wipe";
static constexpr const char* DEFAULT_LOCALE = "en-US";
+// We define RECOVERY_API_VERSION in Android.mk, which will be picked up by build system and packed
+// into target_files.zip. Assert the version defined in code and in Android.mk are consistent.
+static_assert(kRecoveryApiVersion == RECOVERY_API_VERSION, "Mismatching recovery API versions.");
+
static std::string locale;
static bool has_cache = false;
@@ -179,19 +184,19 @@
* 7b. the user reboots (pulling the battery, etc) into the main system
*/
-// open a given path, mounting partitions as necessary
-FILE* fopen_path(const char *path, const char *mode) {
- if (ensure_path_mounted(path) != 0) {
- LOG(ERROR) << "Can't mount " << path;
- return NULL;
- }
+// Open a given path, mounting partitions as necessary.
+FILE* fopen_path(const char* path, const char* mode) {
+ if (ensure_path_mounted(path) != 0) {
+ LOG(ERROR) << "Can't mount " << path;
+ return nullptr;
+ }
- // When writing, try to create the containing directory, if necessary.
- // Use generous permissions, the system (init.rc) will reset them.
- if (strchr("wa", mode[0])) dirCreateHierarchy(path, 0777, NULL, 1, sehandle);
-
- FILE *fp = fopen(path, mode);
- return fp;
+ // When writing, try to create the containing directory, if necessary. Use generous permissions,
+ // the system (init.rc) will reset them.
+ if (strchr("wa", mode[0])) {
+ mkdir_recursively(path, 0777, true, sehandle);
+ }
+ return fopen(path, mode);
}
// close a file, log an error if the error indicator is set
@@ -594,7 +599,7 @@
if (is_cache) {
// Re-create the log dir and write back the log entries.
if (ensure_path_mounted(CACHE_LOG_DIR) == 0 &&
- dirCreateHierarchy(CACHE_LOG_DIR, 0777, nullptr, false, sehandle) == 0) {
+ mkdir_recursively(CACHE_LOG_DIR, 0777, false, sehandle) == 0) {
for (const auto& log : log_files) {
if (!android::base::WriteStringToFile(log.data, log.name, log.sb.st_mode, log.sb.st_uid,
log.sb.st_gid)) {
@@ -748,11 +753,19 @@
modified_flash = true;
ui->Print("\n-- Wiping data...\n");
- bool success =
- device->PreWipeData() &&
- erase_volume("/data") &&
- (has_cache ? erase_volume("/cache") : true) &&
- device->PostWipeData();
+ bool success = device->PreWipeData();
+ if (success) {
+ success &= erase_volume(DATA_ROOT);
+ if (has_cache) {
+ success &= erase_volume(CACHE_ROOT);
+ }
+ if (volume_for_mount_point(METADATA_ROOT) != nullptr) {
+ success &= erase_volume(METADATA_ROOT);
+ }
+ }
+ if (success) {
+ success &= device->PostWipeData();
+ }
ui->Print("Data wipe %s.\n", success ? "complete" : "failed");
return success;
}
@@ -1187,6 +1200,11 @@
run_graphics_test();
break;
+ case Device::RUN_LOCALE_TEST: {
+ ScreenRecoveryUI* screen_ui = static_cast<ScreenRecoveryUI*>(ui);
+ screen_ui->CheckBackgroundTextImages(locale);
+ break;
+ }
case Device::MOUNT_SYSTEM:
// For a system image built with the root directory (i.e. system_root_image == "true"), we
// mount it to /system_root, and symlink /system to /system_root/system to make adb shell
@@ -1205,9 +1223,8 @@
}
}
-static void
-print_property(const char *key, const char *name, void *cookie) {
- printf("%s=%s\n", key, name);
+static void print_property(const char* key, const char* name, void* /* cookie */) {
+ printf("%s=%s\n", key, name);
}
static std::string load_locale_from_cache() {
@@ -1241,70 +1258,91 @@
static constexpr char log_characters[] = "VDIWEF";
-void UiLogger(android::base::LogId id, android::base::LogSeverity severity,
- const char* tag, const char* file, unsigned int line,
- const char* message) {
- if (severity >= android::base::ERROR && ui != nullptr) {
- ui->Print("E:%s\n", message);
- } else {
- fprintf(stdout, "%c:%s\n", log_characters[severity], message);
- }
+void UiLogger(android::base::LogId /* id */, android::base::LogSeverity severity,
+ const char* /* tag */, const char* /* file */, unsigned int /* line */,
+ const char* message) {
+ if (severity >= android::base::ERROR && ui != nullptr) {
+ ui->Print("E:%s\n", message);
+ } else {
+ fprintf(stdout, "%c:%s\n", log_characters[severity], message);
+ }
}
static bool is_battery_ok() {
- struct healthd_config healthd_config = {
- .batteryStatusPath = android::String8(android::String8::kEmptyString),
- .batteryHealthPath = android::String8(android::String8::kEmptyString),
- .batteryPresentPath = android::String8(android::String8::kEmptyString),
- .batteryCapacityPath = android::String8(android::String8::kEmptyString),
- .batteryVoltagePath = android::String8(android::String8::kEmptyString),
- .batteryTemperaturePath = android::String8(android::String8::kEmptyString),
- .batteryTechnologyPath = android::String8(android::String8::kEmptyString),
- .batteryCurrentNowPath = android::String8(android::String8::kEmptyString),
- .batteryCurrentAvgPath = android::String8(android::String8::kEmptyString),
- .batteryChargeCounterPath = android::String8(android::String8::kEmptyString),
- .batteryFullChargePath = android::String8(android::String8::kEmptyString),
- .batteryCycleCountPath = android::String8(android::String8::kEmptyString),
- .energyCounter = NULL,
- .boot_min_cap = 0,
- .screen_on = NULL
- };
- healthd_board_init(&healthd_config);
+ using android::hardware::health::V1_0::BatteryStatus;
+ using android::hardware::health::V2_0::Result;
+ using android::hardware::health::V2_0::toString;
+ using android::hardware::health::V2_0::implementation::Health;
- android::BatteryMonitor monitor;
- monitor.init(&healthd_config);
+ struct healthd_config healthd_config = {
+ .batteryStatusPath = android::String8(android::String8::kEmptyString),
+ .batteryHealthPath = android::String8(android::String8::kEmptyString),
+ .batteryPresentPath = android::String8(android::String8::kEmptyString),
+ .batteryCapacityPath = android::String8(android::String8::kEmptyString),
+ .batteryVoltagePath = android::String8(android::String8::kEmptyString),
+ .batteryTemperaturePath = android::String8(android::String8::kEmptyString),
+ .batteryTechnologyPath = android::String8(android::String8::kEmptyString),
+ .batteryCurrentNowPath = android::String8(android::String8::kEmptyString),
+ .batteryCurrentAvgPath = android::String8(android::String8::kEmptyString),
+ .batteryChargeCounterPath = android::String8(android::String8::kEmptyString),
+ .batteryFullChargePath = android::String8(android::String8::kEmptyString),
+ .batteryCycleCountPath = android::String8(android::String8::kEmptyString),
+ .energyCounter = NULL,
+ .boot_min_cap = 0,
+ .screen_on = NULL
+ };
- int wait_second = 0;
- while (true) {
- int charge_status = monitor.getChargeStatus();
- // Treat unknown status as charged.
- bool charged = (charge_status != android::BATTERY_STATUS_DISCHARGING &&
- charge_status != android::BATTERY_STATUS_NOT_CHARGING);
- android::BatteryProperty capacity;
- android::status_t status = monitor.getProperty(android::BATTERY_PROP_CAPACITY, &capacity);
- ui_print("charge_status %d, charged %d, status %d, capacity %lld\n", charge_status,
- charged, status, capacity.valueInt64);
- // At startup, the battery drivers in devices like N5X/N6P take some time to load
- // the battery profile. Before the load finishes, it reports value 50 as a fake
- // capacity. BATTERY_READ_TIMEOUT_IN_SEC is set that the battery drivers are expected
- // to finish loading the battery profile earlier than 10 seconds after kernel startup.
- if (status == 0 && capacity.valueInt64 == 50) {
- if (wait_second < BATTERY_READ_TIMEOUT_IN_SEC) {
- sleep(1);
- wait_second++;
- continue;
- }
- }
- // If we can't read battery percentage, it may be a device without battery. In this
- // situation, use 100 as a fake battery percentage.
- if (status != 0) {
- capacity.valueInt64 = 100;
- }
- return (charged && capacity.valueInt64 >= BATTERY_WITH_CHARGER_OK_PERCENTAGE) ||
- (!charged && capacity.valueInt64 >= BATTERY_OK_PERCENTAGE);
+ auto health =
+ android::hardware::health::V2_0::implementation::Health::initInstance(&healthd_config);
+
+ int wait_second = 0;
+ while (true) {
+ auto charge_status = BatteryStatus::UNKNOWN;
+ health
+ ->getChargeStatus([&charge_status](auto res, auto out_status) {
+ if (res == Result::SUCCESS) {
+ charge_status = out_status;
+ }
+ })
+ .isOk(); // should not have transport error
+
+ // Treat unknown status as charged.
+ bool charged = (charge_status != BatteryStatus::DISCHARGING &&
+ charge_status != BatteryStatus::NOT_CHARGING);
+
+ Result res = Result::UNKNOWN;
+ int32_t capacity = INT32_MIN;
+ health
+ ->getCapacity([&res, &capacity](auto out_res, auto out_capacity) {
+ res = out_res;
+ capacity = out_capacity;
+ })
+ .isOk(); // should not have transport error
+
+ ui_print("charge_status %d, charged %d, status %s, capacity %" PRId32 "\n", charge_status,
+ charged, toString(res).c_str(), capacity);
+ // At startup, the battery drivers in devices like N5X/N6P take some time to load
+ // the battery profile. Before the load finishes, it reports value 50 as a fake
+ // capacity. BATTERY_READ_TIMEOUT_IN_SEC is set that the battery drivers are expected
+ // to finish loading the battery profile earlier than 10 seconds after kernel startup.
+ if (res == Result::SUCCESS && capacity == 50) {
+ if (wait_second < BATTERY_READ_TIMEOUT_IN_SEC) {
+ sleep(1);
+ wait_second++;
+ continue;
+ }
+ }
+ // If we can't read battery percentage, it may be a device without battery. In this
+ // situation, use 100 as a fake battery percentage.
+ if (res != Result::SUCCESS) {
+ capacity = 100;
+ }
+ return (charged && capacity >= BATTERY_WITH_CHARGER_OK_PERCENTAGE) ||
+ (!charged && capacity >= BATTERY_OK_PERCENTAGE);
}
}
+// Set the retry count to |retry_count| in BCB.
static void set_retry_bootloader_message(int retry_count, const std::vector<std::string>& args) {
std::vector<std::string> options;
for (const auto& arg : args) {
@@ -1313,8 +1351,8 @@
}
}
- // Increment the retry counter by 1.
- options.push_back(android::base::StringPrintf("--retry_count=%d", retry_count + 1));
+ // Update the retry counter in BCB.
+ options.push_back(android::base::StringPrintf("--retry_count=%d", retry_count));
std::string err;
if (!update_bootloader_message(options, &err)) {
LOG(ERROR) << err;
@@ -1349,303 +1387,331 @@
}
int main(int argc, char **argv) {
- // We don't have logcat yet under recovery; so we'll print error on screen and
- // log to stdout (which is redirected to recovery.log) as we used to do.
- android::base::InitLogging(argv, &UiLogger);
+ // We don't have logcat yet under recovery; so we'll print error on screen and
+ // log to stdout (which is redirected to recovery.log) as we used to do.
+ android::base::InitLogging(argv, &UiLogger);
- // Take last pmsg contents and rewrite it to the current pmsg session.
- static const char filter[] = "recovery/";
- // Do we need to rotate?
- bool doRotate = false;
+ // Take last pmsg contents and rewrite it to the current pmsg session.
+ static const char filter[] = "recovery/";
+ // Do we need to rotate?
+ bool doRotate = false;
- __android_log_pmsg_file_read(
- LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter,
- logbasename, &doRotate);
- // Take action to refresh pmsg contents
- __android_log_pmsg_file_read(
- LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter,
- logrotate, &doRotate);
+ __android_log_pmsg_file_read(LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, logbasename, &doRotate);
+ // Take action to refresh pmsg contents
+ __android_log_pmsg_file_read(LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, logrotate, &doRotate);
- // If this binary is started with the single argument "--adbd",
- // instead of being the normal recovery binary, it turns into kind
- // of a stripped-down version of adbd that only supports the
- // 'sideload' command. Note this must be a real argument, not
- // anything in the command file or bootloader control block; the
- // only way recovery should be run with this argument is when it
- // starts a copy of itself from the apply_from_adb() function.
- if (argc == 2 && strcmp(argv[1], "--adbd") == 0) {
- minadbd_main();
- return 0;
+ // If this binary is started with the single argument "--adbd",
+ // instead of being the normal recovery binary, it turns into kind
+ // of a stripped-down version of adbd that only supports the
+ // 'sideload' command. Note this must be a real argument, not
+ // anything in the command file or bootloader control block; the
+ // only way recovery should be run with this argument is when it
+ // starts a copy of itself from the apply_from_adb() function.
+ if (argc == 2 && strcmp(argv[1], "--adbd") == 0) {
+ minadbd_main();
+ return 0;
+ }
+
+ time_t start = time(nullptr);
+
+ // redirect_stdio should be called only in non-sideload mode. Otherwise
+ // we may have two logger instances with different timestamps.
+ redirect_stdio(TEMPORARY_LOG_FILE);
+
+ printf("Starting recovery (pid %d) on %s", getpid(), ctime(&start));
+
+ load_volume_table();
+ has_cache = volume_for_mount_point(CACHE_ROOT) != nullptr;
+
+ std::vector<std::string> args = get_args(argc, argv);
+ std::vector<char*> args_to_parse(args.size());
+ std::transform(args.cbegin(), args.cend(), args_to_parse.begin(),
+ [](const std::string& arg) { return const_cast<char*>(arg.c_str()); });
+
+ const char* update_package = nullptr;
+ bool should_wipe_data = false;
+ bool should_prompt_and_wipe_data = false;
+ bool should_wipe_cache = false;
+ bool should_wipe_ab = false;
+ size_t wipe_package_size = 0;
+ bool show_text = false;
+ bool sideload = false;
+ bool sideload_auto_reboot = false;
+ bool just_exit = false;
+ bool shutdown_after = false;
+ int retry_count = 0;
+ bool security_update = false;
+
+ int arg;
+ int option_index;
+ while ((arg = getopt_long(args_to_parse.size(), args_to_parse.data(), "", OPTIONS,
+ &option_index)) != -1) {
+ switch (arg) {
+ case 'n':
+ android::base::ParseInt(optarg, &retry_count, 0);
+ break;
+ case 'u':
+ update_package = optarg;
+ break;
+ case 'w':
+ should_wipe_data = true;
+ break;
+ case 'c':
+ should_wipe_cache = true;
+ break;
+ case 't':
+ show_text = true;
+ break;
+ case 's':
+ sideload = true;
+ break;
+ case 'a':
+ sideload = true;
+ sideload_auto_reboot = true;
+ break;
+ case 'x':
+ just_exit = true;
+ break;
+ case 'l':
+ locale = optarg;
+ break;
+ case 'p':
+ shutdown_after = true;
+ break;
+ case 'r':
+ reason = optarg;
+ break;
+ case 'e':
+ security_update = true;
+ break;
+ case 0: {
+ std::string option = OPTIONS[option_index].name;
+ if (option == "wipe_ab") {
+ should_wipe_ab = true;
+ } else if (option == "wipe_package_size") {
+ android::base::ParseUint(optarg, &wipe_package_size);
+ } else if (option == "prompt_and_wipe_data") {
+ should_prompt_and_wipe_data = true;
+ }
+ break;
+ }
+ case '?':
+ LOG(ERROR) << "Invalid command argument";
+ continue;
}
+ }
- time_t start = time(NULL);
-
- // redirect_stdio should be called only in non-sideload mode. Otherwise
- // we may have two logger instances with different timestamps.
- redirect_stdio(TEMPORARY_LOG_FILE);
-
- printf("Starting recovery (pid %d) on %s", getpid(), ctime(&start));
-
- load_volume_table();
- has_cache = volume_for_path(CACHE_ROOT) != nullptr;
-
- std::vector<std::string> args = get_args(argc, argv);
- std::vector<char*> args_to_parse(args.size());
- std::transform(args.cbegin(), args.cend(), args_to_parse.begin(),
- [](const std::string& arg) { return const_cast<char*>(arg.c_str()); });
-
- const char *update_package = NULL;
- bool should_wipe_data = false;
- bool should_prompt_and_wipe_data = false;
- bool should_wipe_cache = false;
- bool should_wipe_ab = false;
- size_t wipe_package_size = 0;
- bool show_text = false;
- bool sideload = false;
- bool sideload_auto_reboot = false;
- bool just_exit = false;
- bool shutdown_after = false;
- int retry_count = 0;
- bool security_update = false;
-
- int arg;
- int option_index;
- while ((arg = getopt_long(args_to_parse.size(), args_to_parse.data(), "", OPTIONS,
- &option_index)) != -1) {
- switch (arg) {
- case 'n': android::base::ParseInt(optarg, &retry_count, 0); break;
- case 'u': update_package = optarg; break;
- case 'w': should_wipe_data = true; break;
- case 'c': should_wipe_cache = true; break;
- case 't': show_text = true; break;
- case 's': sideload = true; break;
- case 'a': sideload = true; sideload_auto_reboot = true; break;
- case 'x': just_exit = true; break;
- case 'l': locale = optarg; break;
- case 'p': shutdown_after = true; break;
- case 'r': reason = optarg; break;
- case 'e': security_update = true; break;
- case 0: {
- std::string option = OPTIONS[option_index].name;
- if (option == "wipe_ab") {
- should_wipe_ab = true;
- } else if (option == "wipe_package_size") {
- android::base::ParseUint(optarg, &wipe_package_size);
- } else if (option == "prompt_and_wipe_data") {
- should_prompt_and_wipe_data = true;
- }
- break;
- }
- case '?':
- LOG(ERROR) << "Invalid command argument";
- continue;
- }
+ if (locale.empty()) {
+ if (has_cache) {
+ locale = load_locale_from_cache();
}
if (locale.empty()) {
- if (has_cache) {
- locale = load_locale_from_cache();
- }
-
- if (locale.empty()) {
- locale = DEFAULT_LOCALE;
- }
+ locale = DEFAULT_LOCALE;
}
+ }
- printf("locale is [%s]\n", locale.c_str());
- printf("stage is [%s]\n", stage.c_str());
- printf("reason is [%s]\n", reason);
+ printf("locale is [%s]\n", locale.c_str());
+ printf("stage is [%s]\n", stage.c_str());
+ printf("reason is [%s]\n", reason);
- Device* device = make_device();
- if (android::base::GetBoolProperty("ro.boot.quiescent", false)) {
- printf("Quiescent recovery mode.\n");
- ui = new StubRecoveryUI();
+ Device* device = make_device();
+ if (android::base::GetBoolProperty("ro.boot.quiescent", false)) {
+ printf("Quiescent recovery mode.\n");
+ ui = new StubRecoveryUI();
+ } else {
+ ui = device->GetUI();
+
+ if (!ui->Init(locale)) {
+ printf("Failed to initialize UI, use stub UI instead.\n");
+ ui = new StubRecoveryUI();
+ }
+ }
+
+ // Set background string to "installing security update" for security update,
+ // otherwise set it to "installing system update".
+ ui->SetSystemUpdateText(security_update);
+
+ int st_cur, st_max;
+ if (!stage.empty() && sscanf(stage.c_str(), "%d/%d", &st_cur, &st_max) == 2) {
+ ui->SetStage(st_cur, st_max);
+ }
+
+ ui->SetBackground(RecoveryUI::NONE);
+ if (show_text) ui->ShowText(true);
+
+ sehandle = selinux_android_file_context_handle();
+ selinux_android_set_sehandle(sehandle);
+ if (!sehandle) {
+ ui->Print("Warning: No file_contexts\n");
+ }
+
+ device->StartRecovery();
+
+ printf("Command:");
+ for (const auto& arg : args) {
+ printf(" \"%s\"", arg.c_str());
+ }
+ printf("\n\n");
+
+ property_list(print_property, nullptr);
+ printf("\n");
+
+ ui->Print("Supported API: %d\n", kRecoveryApiVersion);
+
+ int status = INSTALL_SUCCESS;
+
+ if (update_package != nullptr) {
+ // It's not entirely true that we will modify the flash. But we want
+ // to log the update attempt since update_package is non-NULL.
+ modified_flash = true;
+
+ if (!is_battery_ok()) {
+ ui->Print("battery capacity is not enough for installing package, needed is %d%%\n",
+ BATTERY_OK_PERCENTAGE);
+ // Log the error code to last_install when installation skips due to
+ // low battery.
+ log_failure_code(kLowBattery, update_package);
+ status = INSTALL_SKIPPED;
+ } else if (bootreason_in_blacklist()) {
+ // Skip update-on-reboot when bootreason is kernel_panic or similar
+ ui->Print("bootreason is in the blacklist; skip OTA installation\n");
+ log_failure_code(kBootreasonInBlacklist, update_package);
+ status = INSTALL_SKIPPED;
} else {
- ui = device->GetUI();
-
- if (!ui->Init(locale)) {
- printf("Failed to initialize UI, use stub UI instead.\n");
- ui = new StubRecoveryUI();
- }
- }
-
- // Set background string to "installing security update" for security update,
- // otherwise set it to "installing system update".
- ui->SetSystemUpdateText(security_update);
-
- int st_cur, st_max;
- if (!stage.empty() && sscanf(stage.c_str(), "%d/%d", &st_cur, &st_max) == 2) {
- ui->SetStage(st_cur, st_max);
- }
-
- ui->SetBackground(RecoveryUI::NONE);
- if (show_text) ui->ShowText(true);
-
- sehandle = selinux_android_file_context_handle();
- selinux_android_set_sehandle(sehandle);
- if (!sehandle) {
- ui->Print("Warning: No file_contexts\n");
- }
-
- device->StartRecovery();
-
- printf("Command:");
- for (const auto& arg : args) {
- printf(" \"%s\"", arg.c_str());
- }
- printf("\n\n");
-
- property_list(print_property, NULL);
- printf("\n");
-
- ui->Print("Supported API: %d\n", RECOVERY_API_VERSION);
-
- int status = INSTALL_SUCCESS;
-
- if (update_package != NULL) {
- // It's not entirely true that we will modify the flash. But we want
- // to log the update attempt since update_package is non-NULL.
- modified_flash = true;
-
- if (!is_battery_ok()) {
- ui->Print("battery capacity is not enough for installing package, needed is %d%%\n",
- BATTERY_OK_PERCENTAGE);
- // Log the error code to last_install when installation skips due to
- // low battery.
- log_failure_code(kLowBattery, update_package);
- status = INSTALL_SKIPPED;
- } else if (bootreason_in_blacklist()) {
- // Skip update-on-reboot when bootreason is kernel_panic or similar
- ui->Print("bootreason is in the blacklist; skip OTA installation\n");
- log_failure_code(kBootreasonInBlacklist, update_package);
- status = INSTALL_SKIPPED;
- } else {
- status = install_package(update_package, &should_wipe_cache,
- TEMPORARY_INSTALL_FILE, true, retry_count);
- if (status == INSTALL_SUCCESS && should_wipe_cache) {
- wipe_cache(false, device);
- }
- if (status != INSTALL_SUCCESS) {
- ui->Print("Installation aborted.\n");
- // When I/O error happens, reboot and retry installation RETRY_LIMIT
- // times before we abandon this OTA update.
- if (status == INSTALL_RETRY && retry_count < RETRY_LIMIT) {
- copy_logs();
- set_retry_bootloader_message(retry_count, args);
- // Print retry count on screen.
- ui->Print("Retry attempt %d\n", retry_count);
-
- // Reboot and retry the update
- if (!reboot("reboot,recovery")) {
- ui->Print("Reboot failed\n");
- } else {
- while (true) {
- pause();
- }
- }
- }
- // If this is an eng or userdebug build, then automatically
- // turn the text display on if the script fails so the error
- // message is visible.
- if (is_ro_debuggable()) {
- ui->ShowText(true);
- }
- }
- }
- } else if (should_wipe_data) {
- if (!wipe_data(device)) {
- status = INSTALL_ERROR;
- }
- } else if (should_prompt_and_wipe_data) {
- ui->ShowText(true);
- ui->SetBackground(RecoveryUI::ERROR);
- if (!prompt_and_wipe_data(device)) {
- status = INSTALL_ERROR;
- }
- ui->ShowText(false);
- } else if (should_wipe_cache) {
- if (!wipe_cache(false, device)) {
- status = INSTALL_ERROR;
- }
- } else if (should_wipe_ab) {
- if (!wipe_ab_device(wipe_package_size)) {
- status = INSTALL_ERROR;
- }
- } else if (sideload) {
- // 'adb reboot sideload' acts the same as user presses key combinations
- // to enter the sideload mode. When 'sideload-auto-reboot' is used, text
- // display will NOT be turned on by default. And it will reboot after
- // sideload finishes even if there are errors. Unless one turns on the
- // text display during the installation. This is to enable automated
- // testing.
- if (!sideload_auto_reboot) {
- ui->ShowText(true);
- }
- status = apply_from_adb(&should_wipe_cache, TEMPORARY_INSTALL_FILE);
- if (status == INSTALL_SUCCESS && should_wipe_cache) {
- if (!wipe_cache(false, device)) {
- status = INSTALL_ERROR;
- }
- }
- ui->Print("\nInstall from ADB complete (status: %d).\n", status);
- if (sideload_auto_reboot) {
- ui->Print("Rebooting automatically.\n");
- }
- } else if (!just_exit) {
- // If this is an eng or userdebug build, automatically turn on the text display if no command
- // is specified. Note that this should be called before setting the background to avoid
- // flickering the background image.
- if (is_ro_debuggable()) {
- ui->ShowText(true);
+ // It's a fresh update. Initialize the retry_count in the BCB to 1; therefore we can later
+ // identify the interrupted update due to unexpected reboots.
+ if (retry_count == 0) {
+ set_retry_bootloader_message(retry_count + 1, args);
}
- status = INSTALL_NONE; // No command specified
- ui->SetBackground(RecoveryUI::NO_COMMAND);
- }
- if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) {
- ui->SetBackground(RecoveryUI::ERROR);
- if (!ui->IsTextVisible()) {
- sleep(5);
+ status = install_package(update_package, &should_wipe_cache, TEMPORARY_INSTALL_FILE, true,
+ retry_count);
+ if (status == INSTALL_SUCCESS && should_wipe_cache) {
+ wipe_cache(false, device);
+ }
+ if (status != INSTALL_SUCCESS) {
+ ui->Print("Installation aborted.\n");
+ // When I/O error happens, reboot and retry installation RETRY_LIMIT
+ // times before we abandon this OTA update.
+ if (status == INSTALL_RETRY && retry_count < RETRY_LIMIT) {
+ copy_logs();
+ retry_count += 1;
+ set_retry_bootloader_message(retry_count, args);
+ // Print retry count on screen.
+ ui->Print("Retry attempt %d\n", retry_count);
+
+ // Reboot and retry the update
+ if (!reboot("reboot,recovery")) {
+ ui->Print("Reboot failed\n");
+ } else {
+ while (true) {
+ pause();
+ }
+ }
}
- }
-
- Device::BuiltinAction after = shutdown_after ? Device::SHUTDOWN : Device::REBOOT;
- // 1. If the recovery menu is visible, prompt and wait for commands.
- // 2. If the state is INSTALL_NONE, wait for commands. (i.e. In user build, manually reboot into
- // recovery to sideload a package.)
- // 3. sideload_auto_reboot is an option only available in user-debug build, reboot the device
- // without waiting.
- // 4. In all other cases, reboot the device. Therefore, normal users will observe the device
- // reboot after it shows the "error" screen for 5s.
- if ((status == INSTALL_NONE && !sideload_auto_reboot) || ui->IsTextVisible()) {
- Device::BuiltinAction temp = prompt_and_wait(device, status);
- if (temp != Device::NO_ACTION) {
- after = temp;
+ // If this is an eng or userdebug build, then automatically
+ // turn the text display on if the script fails so the error
+ // message is visible.
+ if (is_ro_debuggable()) {
+ ui->ShowText(true);
}
+ }
}
-
- // Save logs and clean up before rebooting or shutting down.
- finish_recovery();
-
- switch (after) {
- case Device::SHUTDOWN:
- ui->Print("Shutting down...\n");
- android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,");
- break;
-
- case Device::REBOOT_BOOTLOADER:
- ui->Print("Rebooting to bootloader...\n");
- android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader");
- break;
-
- default:
- ui->Print("Rebooting...\n");
- reboot("reboot,");
- break;
+ } else if (should_wipe_data) {
+ if (!wipe_data(device)) {
+ status = INSTALL_ERROR;
}
- while (true) {
- pause();
+ } else if (should_prompt_and_wipe_data) {
+ ui->ShowText(true);
+ ui->SetBackground(RecoveryUI::ERROR);
+ if (!prompt_and_wipe_data(device)) {
+ status = INSTALL_ERROR;
}
- // Should be unreachable.
- return EXIT_SUCCESS;
+ ui->ShowText(false);
+ } else if (should_wipe_cache) {
+ if (!wipe_cache(false, device)) {
+ status = INSTALL_ERROR;
+ }
+ } else if (should_wipe_ab) {
+ if (!wipe_ab_device(wipe_package_size)) {
+ status = INSTALL_ERROR;
+ }
+ } else if (sideload) {
+ // 'adb reboot sideload' acts the same as user presses key combinations
+ // to enter the sideload mode. When 'sideload-auto-reboot' is used, text
+ // display will NOT be turned on by default. And it will reboot after
+ // sideload finishes even if there are errors. Unless one turns on the
+ // text display during the installation. This is to enable automated
+ // testing.
+ if (!sideload_auto_reboot) {
+ ui->ShowText(true);
+ }
+ status = apply_from_adb(&should_wipe_cache, TEMPORARY_INSTALL_FILE);
+ if (status == INSTALL_SUCCESS && should_wipe_cache) {
+ if (!wipe_cache(false, device)) {
+ status = INSTALL_ERROR;
+ }
+ }
+ ui->Print("\nInstall from ADB complete (status: %d).\n", status);
+ if (sideload_auto_reboot) {
+ ui->Print("Rebooting automatically.\n");
+ }
+ } else if (!just_exit) {
+ // If this is an eng or userdebug build, automatically turn on the text display if no command
+ // is specified. Note that this should be called before setting the background to avoid
+ // flickering the background image.
+ if (is_ro_debuggable()) {
+ ui->ShowText(true);
+ }
+ status = INSTALL_NONE; // No command specified
+ ui->SetBackground(RecoveryUI::NO_COMMAND);
+ }
+
+ if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) {
+ ui->SetBackground(RecoveryUI::ERROR);
+ if (!ui->IsTextVisible()) {
+ sleep(5);
+ }
+ }
+
+ Device::BuiltinAction after = shutdown_after ? Device::SHUTDOWN : Device::REBOOT;
+ // 1. If the recovery menu is visible, prompt and wait for commands.
+ // 2. If the state is INSTALL_NONE, wait for commands. (i.e. In user build, manually reboot into
+ // recovery to sideload a package.)
+ // 3. sideload_auto_reboot is an option only available in user-debug build, reboot the device
+ // without waiting.
+ // 4. In all other cases, reboot the device. Therefore, normal users will observe the device
+ // reboot after it shows the "error" screen for 5s.
+ if ((status == INSTALL_NONE && !sideload_auto_reboot) || ui->IsTextVisible()) {
+ Device::BuiltinAction temp = prompt_and_wait(device, status);
+ if (temp != Device::NO_ACTION) {
+ after = temp;
+ }
+ }
+
+ // Save logs and clean up before rebooting or shutting down.
+ finish_recovery();
+
+ switch (after) {
+ case Device::SHUTDOWN:
+ ui->Print("Shutting down...\n");
+ android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,");
+ break;
+
+ case Device::REBOOT_BOOTLOADER:
+ ui->Print("Rebooting to bootloader...\n");
+ android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader");
+ break;
+
+ default:
+ ui->Print("Rebooting...\n");
+ reboot("reboot,");
+ break;
+ }
+ while (true) {
+ pause();
+ }
+ // Should be unreachable.
+ return EXIT_SUCCESS;
}
diff --git a/res-hdpi/images/erasing_text.png b/res-hdpi/images/erasing_text.png
new file mode 100644
index 0000000..34c56a9
--- /dev/null
+++ b/res-hdpi/images/erasing_text.png
Binary files differ
diff --git a/res-hdpi/images/error_text.png b/res-hdpi/images/error_text.png
new file mode 100644
index 0000000..2a96053
--- /dev/null
+++ b/res-hdpi/images/error_text.png
Binary files differ
diff --git a/res-hdpi/images/installing_security_text.png b/res-hdpi/images/installing_security_text.png
new file mode 100644
index 0000000..97e1f11
--- /dev/null
+++ b/res-hdpi/images/installing_security_text.png
Binary files differ
diff --git a/res-hdpi/images/installing_text.png b/res-hdpi/images/installing_text.png
new file mode 100644
index 0000000..1d591eb
--- /dev/null
+++ b/res-hdpi/images/installing_text.png
Binary files differ
diff --git a/res-hdpi/images/no_command_text.png b/res-hdpi/images/no_command_text.png
new file mode 100644
index 0000000..977fcfa
--- /dev/null
+++ b/res-hdpi/images/no_command_text.png
Binary files differ
diff --git a/res-mdpi/images/erasing_text.png b/res-mdpi/images/erasing_text.png
new file mode 100644
index 0000000..dcd0ea6
--- /dev/null
+++ b/res-mdpi/images/erasing_text.png
Binary files differ
diff --git a/res-mdpi/images/error_text.png b/res-mdpi/images/error_text.png
new file mode 100644
index 0000000..2152dad
--- /dev/null
+++ b/res-mdpi/images/error_text.png
Binary files differ
diff --git a/res-mdpi/images/installing_security_text.png b/res-mdpi/images/installing_security_text.png
new file mode 100644
index 0000000..d1ac4ca
--- /dev/null
+++ b/res-mdpi/images/installing_security_text.png
Binary files differ
diff --git a/res-mdpi/images/installing_text.png b/res-mdpi/images/installing_text.png
new file mode 100644
index 0000000..c9b6d71
--- /dev/null
+++ b/res-mdpi/images/installing_text.png
Binary files differ
diff --git a/res-mdpi/images/no_command_text.png b/res-mdpi/images/no_command_text.png
new file mode 100644
index 0000000..f77ad13
--- /dev/null
+++ b/res-mdpi/images/no_command_text.png
Binary files differ
diff --git a/res-xhdpi/images/erasing_text.png b/res-xhdpi/images/erasing_text.png
new file mode 100644
index 0000000..e22b274
--- /dev/null
+++ b/res-xhdpi/images/erasing_text.png
Binary files differ
diff --git a/res-xhdpi/images/error_text.png b/res-xhdpi/images/error_text.png
new file mode 100644
index 0000000..e4c27e1
--- /dev/null
+++ b/res-xhdpi/images/error_text.png
Binary files differ
diff --git a/res-xhdpi/images/installing_security_text.png b/res-xhdpi/images/installing_security_text.png
new file mode 100644
index 0000000..7ba12b6
--- /dev/null
+++ b/res-xhdpi/images/installing_security_text.png
Binary files differ
diff --git a/res-xhdpi/images/installing_text.png b/res-xhdpi/images/installing_text.png
new file mode 100644
index 0000000..567988e
--- /dev/null
+++ b/res-xhdpi/images/installing_text.png
Binary files differ
diff --git a/res-xhdpi/images/no_command_text.png b/res-xhdpi/images/no_command_text.png
new file mode 100644
index 0000000..a682abb
--- /dev/null
+++ b/res-xhdpi/images/no_command_text.png
Binary files differ
diff --git a/res-xxhdpi/images/erasing_text.png b/res-xxhdpi/images/erasing_text.png
new file mode 100644
index 0000000..6cc953b
--- /dev/null
+++ b/res-xxhdpi/images/erasing_text.png
Binary files differ
diff --git a/res-xxhdpi/images/error_text.png b/res-xxhdpi/images/error_text.png
new file mode 100644
index 0000000..0d5cea8
--- /dev/null
+++ b/res-xxhdpi/images/error_text.png
Binary files differ
diff --git a/res-xxhdpi/images/installing_security_text.png b/res-xxhdpi/images/installing_security_text.png
new file mode 100644
index 0000000..5d10598
--- /dev/null
+++ b/res-xxhdpi/images/installing_security_text.png
Binary files differ
diff --git a/res-xxhdpi/images/installing_text.png b/res-xxhdpi/images/installing_text.png
new file mode 100644
index 0000000..6e94fa2
--- /dev/null
+++ b/res-xxhdpi/images/installing_text.png
Binary files differ
diff --git a/res-xxhdpi/images/no_command_text.png b/res-xxhdpi/images/no_command_text.png
new file mode 100644
index 0000000..40ab484
--- /dev/null
+++ b/res-xxhdpi/images/no_command_text.png
Binary files differ
diff --git a/res-xxxhdpi/images/erasing_text.png b/res-xxxhdpi/images/erasing_text.png
new file mode 100644
index 0000000..cc73099
--- /dev/null
+++ b/res-xxxhdpi/images/erasing_text.png
Binary files differ
diff --git a/res-xxxhdpi/images/error_text.png b/res-xxxhdpi/images/error_text.png
new file mode 100644
index 0000000..fea3cfc
--- /dev/null
+++ b/res-xxxhdpi/images/error_text.png
Binary files differ
diff --git a/res-xxxhdpi/images/installing_security_text.png b/res-xxxhdpi/images/installing_security_text.png
new file mode 100644
index 0000000..ed77d08
--- /dev/null
+++ b/res-xxxhdpi/images/installing_security_text.png
Binary files differ
diff --git a/res-xxxhdpi/images/installing_text.png b/res-xxxhdpi/images/installing_text.png
new file mode 100644
index 0000000..9659106
--- /dev/null
+++ b/res-xxxhdpi/images/installing_text.png
Binary files differ
diff --git a/res-xxxhdpi/images/no_command_text.png b/res-xxxhdpi/images/no_command_text.png
new file mode 100644
index 0000000..4e6f363
--- /dev/null
+++ b/res-xxxhdpi/images/no_command_text.png
Binary files differ
diff --git a/roots.cpp b/roots.cpp
index 29f55b9..184e799 100644
--- a/roots.cpp
+++ b/roots.cpp
@@ -16,174 +16,208 @@
#include "roots.h"
-#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdint.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
-#include <ctype.h>
-#include <fcntl.h>
+
+#include <algorithm>
+#include <string>
+#include <vector>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
+#include <cryptfs.h>
#include <ext4_utils/wipe.h>
#include <fs_mgr.h>
-#include "common.h"
#include "mounts.h"
-#include "cryptfs.h"
-static struct fstab *fstab = NULL;
+static struct fstab* fstab = nullptr;
-extern struct selabel_handle *sehandle;
+extern struct selabel_handle* sehandle;
-void load_volume_table()
-{
- int i;
- int ret;
+void load_volume_table() {
+ fstab = fs_mgr_read_fstab_default();
+ if (!fstab) {
+ LOG(ERROR) << "Failed to read default fstab";
+ return;
+ }
- fstab = fs_mgr_read_fstab_default();
- if (!fstab) {
- LOG(ERROR) << "failed to read default fstab";
- return;
- }
+ int ret = fs_mgr_add_entry(fstab, "/tmp", "ramdisk", "ramdisk");
+ if (ret == -1) {
+ LOG(ERROR) << "Failed to add /tmp entry to fstab";
+ fs_mgr_free_fstab(fstab);
+ fstab = nullptr;
+ return;
+ }
- ret = fs_mgr_add_entry(fstab, "/tmp", "ramdisk", "ramdisk");
- if (ret < 0 ) {
- LOG(ERROR) << "failed to add /tmp entry to fstab";
- fs_mgr_free_fstab(fstab);
- fstab = NULL;
- return;
- }
-
- printf("recovery filesystem table\n");
- printf("=========================\n");
- for (i = 0; i < fstab->num_entries; ++i) {
- Volume* v = &fstab->recs[i];
- printf(" %d %s %s %s %lld\n", i, v->mount_point, v->fs_type,
- v->blk_device, v->length);
- }
- printf("\n");
+ printf("recovery filesystem table\n");
+ printf("=========================\n");
+ for (int i = 0; i < fstab->num_entries; ++i) {
+ const Volume* v = &fstab->recs[i];
+ printf(" %d %s %s %s %lld\n", i, v->mount_point, v->fs_type, v->blk_device, v->length);
+ }
+ printf("\n");
}
-Volume* volume_for_path(const char* path) {
- return fs_mgr_get_entry_for_mount_point(fstab, path);
+Volume* volume_for_mount_point(const std::string& mount_point) {
+ return fs_mgr_get_entry_for_mount_point(fstab, mount_point);
+}
+
+// Finds the volume specified by the given path. fs_mgr_get_entry_for_mount_point() does exact match
+// only, so it attempts the prefixes recursively (e.g. "/cache/recovery/last_log",
+// "/cache/recovery", "/cache", "/" for a given path of "/cache/recovery/last_log") and returns the
+// first match or nullptr.
+static Volume* volume_for_path(const char* path) {
+ if (path == nullptr || path[0] == '\0') return nullptr;
+ std::string str(path);
+ while (true) {
+ Volume* result = fs_mgr_get_entry_for_mount_point(fstab, str);
+ if (result != nullptr || str == "/") {
+ return result;
+ }
+ size_t slash = str.find_last_of('/');
+ if (slash == std::string::npos) return nullptr;
+ if (slash == 0) {
+ str = "/";
+ } else {
+ str = str.substr(0, slash);
+ }
+ }
+ return nullptr;
}
// Mount the volume specified by path at the given mount_point.
int ensure_path_mounted_at(const char* path, const char* mount_point) {
- Volume* v = volume_for_path(path);
- if (v == NULL) {
- LOG(ERROR) << "unknown volume for path [" << path << "]";
- return -1;
- }
- if (strcmp(v->fs_type, "ramdisk") == 0) {
- // the ramdisk is always mounted.
- return 0;
- }
-
- if (!scan_mounted_volumes()) {
- LOG(ERROR) << "failed to scan mounted volumes";
- return -1;
- }
-
- if (!mount_point) {
- mount_point = v->mount_point;
- }
-
- MountedVolume* mv = find_mounted_volume_by_mount_point(mount_point);
- if (mv) {
- // volume is already mounted
- return 0;
- }
-
- mkdir(mount_point, 0755); // in case it doesn't already exist
-
- if (strcmp(v->fs_type, "ext4") == 0 ||
- strcmp(v->fs_type, "squashfs") == 0 ||
- strcmp(v->fs_type, "vfat") == 0) {
- int result = mount(v->blk_device, mount_point, v->fs_type, v->flags, v->fs_options);
- if (result == -1 && fs_mgr_is_formattable(v)) {
- LOG(ERROR) << "failed to mount " << mount_point << " (" << strerror(errno)
- << ") , formatting.....";
- bool crypt_footer = fs_mgr_is_encryptable(v) && !strcmp(v->key_loc, "footer");
- if (fs_mgr_do_format(v, crypt_footer) == 0) {
- result = mount(v->blk_device, mount_point, v->fs_type, v->flags, v->fs_options);
- } else {
- PLOG(ERROR) << "failed to format " << mount_point;
- return -1;
- }
- }
-
- if (result == -1) {
- PLOG(ERROR) << "failed to mount " << mount_point;
- return -1;
- }
- return 0;
- }
-
- LOG(ERROR) << "unknown fs_type \"" << v->fs_type << "\" for " << mount_point;
+ Volume* v = volume_for_path(path);
+ if (v == nullptr) {
+ LOG(ERROR) << "unknown volume for path [" << path << "]";
return -1;
+ }
+ if (strcmp(v->fs_type, "ramdisk") == 0) {
+ // The ramdisk is always mounted.
+ return 0;
+ }
+
+ if (!scan_mounted_volumes()) {
+ LOG(ERROR) << "Failed to scan mounted volumes";
+ return -1;
+ }
+
+ if (!mount_point) {
+ mount_point = v->mount_point;
+ }
+
+ const MountedVolume* mv = find_mounted_volume_by_mount_point(mount_point);
+ if (mv != nullptr) {
+ // Volume is already mounted.
+ return 0;
+ }
+
+ mkdir(mount_point, 0755); // in case it doesn't already exist
+
+ if (strcmp(v->fs_type, "ext4") == 0 || strcmp(v->fs_type, "squashfs") == 0 ||
+ strcmp(v->fs_type, "vfat") == 0) {
+ int result = mount(v->blk_device, mount_point, v->fs_type, v->flags, v->fs_options);
+ if (result == -1 && fs_mgr_is_formattable(v)) {
+ PLOG(ERROR) << "Failed to mount " << mount_point << "; formatting";
+ bool crypt_footer = fs_mgr_is_encryptable(v) && !strcmp(v->key_loc, "footer");
+ if (fs_mgr_do_format(v, crypt_footer) == 0) {
+ result = mount(v->blk_device, mount_point, v->fs_type, v->flags, v->fs_options);
+ } else {
+ PLOG(ERROR) << "Failed to format " << mount_point;
+ return -1;
+ }
+ }
+
+ if (result == -1) {
+ PLOG(ERROR) << "Failed to mount " << mount_point;
+ return -1;
+ }
+ return 0;
+ }
+
+ LOG(ERROR) << "unknown fs_type \"" << v->fs_type << "\" for " << mount_point;
+ return -1;
}
int ensure_path_mounted(const char* path) {
- // Mount at the default mount point.
- return ensure_path_mounted_at(path, nullptr);
+ // Mount at the default mount point.
+ return ensure_path_mounted_at(path, nullptr);
}
int ensure_path_unmounted(const char* path) {
- Volume* v = volume_for_path(path);
- if (v == NULL) {
- LOG(ERROR) << "unknown volume for path [" << path << "]";
- return -1;
- }
- if (strcmp(v->fs_type, "ramdisk") == 0) {
- // the ramdisk is always mounted; you can't unmount it.
- return -1;
- }
+ const Volume* v = volume_for_path(path);
+ if (v == nullptr) {
+ LOG(ERROR) << "unknown volume for path [" << path << "]";
+ return -1;
+ }
+ if (strcmp(v->fs_type, "ramdisk") == 0) {
+ // The ramdisk is always mounted; you can't unmount it.
+ return -1;
+ }
- if (!scan_mounted_volumes()) {
- LOG(ERROR) << "failed to scan mounted volumes";
- return -1;
- }
+ if (!scan_mounted_volumes()) {
+ LOG(ERROR) << "Failed to scan mounted volumes";
+ return -1;
+ }
- MountedVolume* mv = find_mounted_volume_by_mount_point(v->mount_point);
- if (mv == NULL) {
- // volume is already unmounted
- return 0;
- }
+ MountedVolume* mv = find_mounted_volume_by_mount_point(v->mount_point);
+ if (mv == nullptr) {
+ // Volume is already unmounted.
+ return 0;
+ }
- return unmount_mounted_volume(mv);
+ return unmount_mounted_volume(mv);
}
-static int exec_cmd(const char* path, char* const argv[]) {
- int status;
- pid_t child;
- if ((child = vfork()) == 0) {
- execv(path, argv);
- _exit(EXIT_FAILURE);
- }
- waitpid(child, &status, 0);
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
- LOG(ERROR) << path << " failed with status " << WEXITSTATUS(status);
- }
- return WEXITSTATUS(status);
+static int exec_cmd(const std::vector<std::string>& args) {
+ CHECK_NE(static_cast<size_t>(0), args.size());
+
+ std::vector<char*> argv(args.size());
+ std::transform(args.cbegin(), args.cend(), argv.begin(),
+ [](const std::string& arg) { return const_cast<char*>(arg.c_str()); });
+ argv.push_back(nullptr);
+
+ pid_t child;
+ if ((child = fork()) == 0) {
+ execv(argv[0], argv.data());
+ _exit(EXIT_FAILURE);
+ }
+
+ int status;
+ waitpid(child, &status, 0);
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ LOG(ERROR) << args[0] << " failed with status " << WEXITSTATUS(status);
+ }
+ return WEXITSTATUS(status);
}
-static ssize_t get_file_size(int fd, uint64_t reserve_len) {
+static int64_t get_file_size(int fd, uint64_t reserve_len) {
struct stat buf;
int ret = fstat(fd, &buf);
if (ret) return 0;
- ssize_t computed_size;
+ int64_t computed_size;
if (S_ISREG(buf.st_mode)) {
computed_size = buf.st_size - reserve_len;
} else if (S_ISBLK(buf.st_mode)) {
- computed_size = get_block_device_size(fd) - reserve_len;
+ uint64_t block_device_size = get_block_device_size(fd);
+ if (block_device_size < reserve_len ||
+ block_device_size > std::numeric_limits<int64_t>::max()) {
+ computed_size = 0;
+ } else {
+ computed_size = block_device_size - reserve_len;
+ }
} else {
computed_size = 0;
}
@@ -192,136 +226,144 @@
}
int format_volume(const char* volume, const char* directory) {
- Volume* v = volume_for_path(volume);
- if (v == NULL) {
- LOG(ERROR) << "unknown volume \"" << volume << "\"";
- return -1;
- }
- if (strcmp(v->fs_type, "ramdisk") == 0) {
- // you can't format the ramdisk.
- LOG(ERROR) << "can't format_volume \"" << volume << "\"";
- return -1;
- }
- if (strcmp(v->mount_point, volume) != 0) {
- LOG(ERROR) << "can't give path \"" << volume << "\" to format_volume";
- return -1;
- }
-
- if (ensure_path_unmounted(volume) != 0) {
- LOG(ERROR) << "format_volume failed to unmount \"" << v->mount_point << "\"";
- return -1;
- }
-
- if (strcmp(v->fs_type, "ext4") == 0 || strcmp(v->fs_type, "f2fs") == 0) {
- // if there's a key_loc that looks like a path, it should be a
- // block device for storing encryption metadata. wipe it too.
- if (v->key_loc != NULL && v->key_loc[0] == '/') {
- LOG(INFO) << "wiping " << v->key_loc;
- int fd = open(v->key_loc, O_WRONLY | O_CREAT, 0644);
- if (fd < 0) {
- LOG(ERROR) << "format_volume: failed to open " << v->key_loc;
- return -1;
- }
- wipe_block_device(fd, get_file_size(fd));
- close(fd);
- }
-
- ssize_t length = 0;
- if (v->length != 0) {
- length = v->length;
- } else if (v->key_loc != NULL && strcmp(v->key_loc, "footer") == 0) {
- android::base::unique_fd fd(open(v->blk_device, O_RDONLY));
- if (fd < 0) {
- PLOG(ERROR) << "get_file_size: failed to open " << v->blk_device;
- return -1;
- }
- length = get_file_size(fd.get(), CRYPT_FOOTER_OFFSET);
- if (length <= 0) {
- LOG(ERROR) << "get_file_size: invalid size " << length << " for " << v->blk_device;
- return -1;
- }
- }
- int result;
- if (strcmp(v->fs_type, "ext4") == 0) {
- static constexpr int block_size = 4096;
- int raid_stride = v->logical_blk_size / block_size;
- int raid_stripe_width = v->erase_blk_size / block_size;
-
- // stride should be the max of 8kb and logical block size
- if (v->logical_blk_size != 0 && v->logical_blk_size < 8192) {
- raid_stride = 8192 / block_size;
- }
-
- const char* mke2fs_argv[] = { "/sbin/mke2fs_static",
- "-F",
- "-t",
- "ext4",
- "-b",
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr };
-
- int i = 5;
- std::string block_size_str = std::to_string(block_size);
- mke2fs_argv[i++] = block_size_str.c_str();
-
- std::string ext_args;
- if (v->erase_blk_size != 0 && v->logical_blk_size != 0) {
- ext_args = android::base::StringPrintf("stride=%d,stripe-width=%d", raid_stride,
- raid_stripe_width);
- mke2fs_argv[i++] = "-E";
- mke2fs_argv[i++] = ext_args.c_str();
- }
-
- mke2fs_argv[i++] = v->blk_device;
-
- std::string size_str = std::to_string(length / block_size);
- if (length != 0) {
- mke2fs_argv[i++] = size_str.c_str();
- }
-
- result = exec_cmd(mke2fs_argv[0], const_cast<char**>(mke2fs_argv));
- if (result == 0 && directory != nullptr) {
- const char* e2fsdroid_argv[] = { "/sbin/e2fsdroid_static",
- "-e",
- "-f",
- directory,
- "-a",
- volume,
- v->blk_device,
- nullptr };
-
- result = exec_cmd(e2fsdroid_argv[0], const_cast<char**>(e2fsdroid_argv));
- }
- } else { /* Has to be f2fs because we checked earlier. */
- char *num_sectors = nullptr;
- if (length >= 512 && asprintf(&num_sectors, "%zd", length / 512) <= 0) {
- LOG(ERROR) << "format_volume: failed to create " << v->fs_type
- << " command for " << v->blk_device;
- return -1;
- }
- const char *f2fs_path = "/sbin/mkfs.f2fs";
- const char* const f2fs_argv[] = {"mkfs.f2fs", "-t", "-d1", v->blk_device, num_sectors, nullptr};
-
- result = exec_cmd(f2fs_path, (char* const*)f2fs_argv);
- free(num_sectors);
- }
- if (result != 0) {
- PLOG(ERROR) << "format_volume: make " << v->fs_type << " failed on " << v->blk_device;
- return -1;
- }
- return 0;
- }
-
+ const Volume* v = volume_for_path(volume);
+ if (v == nullptr) {
+ LOG(ERROR) << "unknown volume \"" << volume << "\"";
+ return -1;
+ }
+ if (strcmp(v->fs_type, "ramdisk") == 0) {
+ LOG(ERROR) << "can't format_volume \"" << volume << "\"";
+ return -1;
+ }
+ if (strcmp(v->mount_point, volume) != 0) {
+ LOG(ERROR) << "can't give path \"" << volume << "\" to format_volume";
+ return -1;
+ }
+ if (ensure_path_unmounted(volume) != 0) {
+ LOG(ERROR) << "format_volume: Failed to unmount \"" << v->mount_point << "\"";
+ return -1;
+ }
+ if (strcmp(v->fs_type, "ext4") != 0 && strcmp(v->fs_type, "f2fs") != 0) {
LOG(ERROR) << "format_volume: fs_type \"" << v->fs_type << "\" unsupported";
return -1;
+ }
+
+ // If there's a key_loc that looks like a path, it should be a block device for storing encryption
+ // metadata. Wipe it too.
+ if (v->key_loc != nullptr && v->key_loc[0] == '/') {
+ LOG(INFO) << "Wiping " << v->key_loc;
+ int fd = open(v->key_loc, O_WRONLY | O_CREAT, 0644);
+ if (fd == -1) {
+ PLOG(ERROR) << "format_volume: Failed to open " << v->key_loc;
+ return -1;
+ }
+ wipe_block_device(fd, get_file_size(fd));
+ close(fd);
+ }
+
+ int64_t length = 0;
+ if (v->length > 0) {
+ length = v->length;
+ } else if (v->length < 0 ||
+ (v->key_loc != nullptr && strcmp(v->key_loc, "footer") == 0)) {
+ android::base::unique_fd fd(open(v->blk_device, O_RDONLY));
+ if (fd == -1) {
+ PLOG(ERROR) << "format_volume: failed to open " << v->blk_device;
+ return -1;
+ }
+ length =
+ get_file_size(fd.get(), v->length ? -v->length : CRYPT_FOOTER_OFFSET);
+ if (length <= 0) {
+ LOG(ERROR) << "get_file_size: invalid size " << length << " for "
+ << v->blk_device;
+ return -1;
+ }
+ }
+
+ if (strcmp(v->fs_type, "ext4") == 0) {
+ static constexpr int kBlockSize = 4096;
+ std::vector<std::string> mke2fs_args = {
+ "/sbin/mke2fs_static", "-F", "-t", "ext4", "-b", std::to_string(kBlockSize),
+ };
+
+ int raid_stride = v->logical_blk_size / kBlockSize;
+ int raid_stripe_width = v->erase_blk_size / kBlockSize;
+ // stride should be the max of 8KB and logical block size
+ if (v->logical_blk_size != 0 && v->logical_blk_size < 8192) {
+ raid_stride = 8192 / kBlockSize;
+ }
+ if (v->erase_blk_size != 0 && v->logical_blk_size != 0) {
+ mke2fs_args.push_back("-E");
+ mke2fs_args.push_back(
+ android::base::StringPrintf("stride=%d,stripe-width=%d", raid_stride, raid_stripe_width));
+ }
+ mke2fs_args.push_back(v->blk_device);
+ if (length != 0) {
+ mke2fs_args.push_back(std::to_string(length / kBlockSize));
+ }
+
+ int result = exec_cmd(mke2fs_args);
+ if (result == 0 && directory != nullptr) {
+ std::vector<std::string> e2fsdroid_args = {
+ "/sbin/e2fsdroid_static",
+ "-e",
+ "-f",
+ directory,
+ "-a",
+ volume,
+ v->blk_device,
+ };
+ result = exec_cmd(e2fsdroid_args);
+ }
+
+ if (result != 0) {
+ PLOG(ERROR) << "format_volume: Failed to make ext4 on " << v->blk_device;
+ return -1;
+ }
+ return 0;
+ }
+
+ // Has to be f2fs because we checked earlier.
+ static constexpr int kSectorSize = 4096;
+ std::string cmd("/sbin/mkfs.f2fs");
+ // clang-format off
+ std::vector<std::string> make_f2fs_cmd = {
+ cmd,
+ "-d1",
+ "-f",
+ "-O", "encrypt",
+ "-O", "quota",
+ "-O", "verity",
+ "-w", std::to_string(kSectorSize),
+ v->blk_device,
+ };
+ // clang-format on
+ if (length >= kSectorSize) {
+ make_f2fs_cmd.push_back(std::to_string(length / kSectorSize));
+ }
+
+ int result = exec_cmd(make_f2fs_cmd);
+ if (result == 0 && directory != nullptr) {
+ cmd = "/sbin/sload.f2fs";
+ // clang-format off
+ std::vector<std::string> sload_f2fs_cmd = {
+ cmd,
+ "-f", directory,
+ "-t", volume,
+ v->blk_device,
+ };
+ // clang-format on
+ result = exec_cmd(sload_f2fs_cmd);
+ }
+ if (result != 0) {
+ PLOG(ERROR) << "format_volume: Failed " << cmd << " on " << v->blk_device;
+ return -1;
+ }
+ return 0;
}
int format_volume(const char* volume) {
- return format_volume(volume, NULL);
+ return format_volume(volume, nullptr);
}
int setup_install_mounts() {
@@ -339,12 +381,12 @@
if (strcmp(v->mount_point, "/tmp") == 0 || strcmp(v->mount_point, "/cache") == 0) {
if (ensure_path_mounted(v->mount_point) != 0) {
- LOG(ERROR) << "failed to mount " << v->mount_point;
+ LOG(ERROR) << "Failed to mount " << v->mount_point;
return -1;
}
} else {
if (ensure_path_unmounted(v->mount_point) != 0) {
- LOG(ERROR) << "failed to unmount " << v->mount_point;
+ LOG(ERROR) << "Failed to unmount " << v->mount_point;
return -1;
}
}
diff --git a/roots.h b/roots.h
index 3246c5f..380f10f 100644
--- a/roots.h
+++ b/roots.h
@@ -17,6 +17,8 @@
#ifndef RECOVERY_ROOTS_H_
#define RECOVERY_ROOTS_H_
+#include <string>
+
typedef struct fstab_rec Volume;
typedef struct fstab_rec Volume;
@@ -24,8 +26,8 @@
// Load and parse volume data from /etc/recovery.fstab.
void load_volume_table();
-// Return the Volume* record for this path (or NULL).
-Volume* volume_for_path(const char* path);
+// Return the Volume* record for this mount point (or nullptr).
+Volume* volume_for_mount_point(const std::string& mount_point);
// Make sure that the volume 'path' is on is mounted. Returns 0 on
// success (volume is mounted).
diff --git a/rotate_logs.cpp b/rotate_logs.cpp
index 51557b1..76b7f4b 100644
--- a/rotate_logs.cpp
+++ b/rotate_logs.cpp
@@ -31,85 +31,77 @@
static const std::string LAST_KMSG_FILTER = "recovery/last_kmsg";
static const std::string LAST_LOG_FILTER = "recovery/last_log";
-ssize_t logbasename(
- log_id_t /* logId */,
- char /* prio */,
- const char *filename,
- const char * /* buf */, size_t len,
- void *arg) {
- bool* doRotate = static_cast<bool*>(arg);
- if (LAST_KMSG_FILTER.find(filename) != std::string::npos ||
- LAST_LOG_FILTER.find(filename) != std::string::npos) {
- *doRotate = true;
- }
- return len;
+ssize_t logbasename(log_id_t /* id */, char /* prio */, const char* filename, const char* /* buf */,
+ size_t len, void* arg) {
+ bool* do_rotate = static_cast<bool*>(arg);
+ if (LAST_KMSG_FILTER.find(filename) != std::string::npos ||
+ LAST_LOG_FILTER.find(filename) != std::string::npos) {
+ *do_rotate = true;
+ }
+ return len;
}
-ssize_t logrotate(
- log_id_t logId,
- char prio,
- const char *filename,
- const char *buf, size_t len,
- void *arg) {
- bool* doRotate = static_cast<bool*>(arg);
- if (!*doRotate) {
- return __android_log_pmsg_file_write(logId, prio, filename, buf, len);
- }
+ssize_t logrotate(log_id_t id, char prio, const char* filename, const char* buf, size_t len,
+ void* arg) {
+ bool* do_rotate = static_cast<bool*>(arg);
+ if (!*do_rotate) {
+ return __android_log_pmsg_file_write(id, prio, filename, buf, len);
+ }
- std::string name(filename);
- size_t dot = name.find_last_of('.');
- std::string sub = name.substr(0, dot);
+ std::string name(filename);
+ size_t dot = name.find_last_of('.');
+ std::string sub = name.substr(0, dot);
- if (LAST_KMSG_FILTER.find(sub) == std::string::npos &&
- LAST_LOG_FILTER.find(sub) == std::string::npos) {
- return __android_log_pmsg_file_write(logId, prio, filename, buf, len);
- }
+ if (LAST_KMSG_FILTER.find(sub) == std::string::npos &&
+ LAST_LOG_FILTER.find(sub) == std::string::npos) {
+ return __android_log_pmsg_file_write(id, prio, filename, buf, len);
+ }
- // filename rotation
- if (dot == std::string::npos) {
- name += ".1";
+ // filename rotation
+ if (dot == std::string::npos) {
+ name += ".1";
+ } else {
+ std::string number = name.substr(dot + 1);
+ if (!isdigit(number[0])) {
+ name += ".1";
} else {
- std::string number = name.substr(dot + 1);
- if (!isdigit(number[0])) {
- name += ".1";
- } else {
- size_t i;
- if (!android::base::ParseUint(number.c_str(), &i)) {
- LOG(ERROR) << "failed to parse uint in " << number;
- return -1;
- }
- name = sub + "." + std::to_string(i + 1);
- }
+ size_t i;
+ if (!android::base::ParseUint(number.c_str(), &i)) {
+ LOG(ERROR) << "failed to parse uint in " << number;
+ return -1;
+ }
+ name = sub + "." + std::to_string(i + 1);
}
+ }
- return __android_log_pmsg_file_write(logId, prio, name.c_str(), buf, len);
+ return __android_log_pmsg_file_write(id, prio, name.c_str(), buf, len);
}
// Rename last_log -> last_log.1 -> last_log.2 -> ... -> last_log.$max.
// Similarly rename last_kmsg -> last_kmsg.1 -> ... -> last_kmsg.$max.
// Overwrite any existing last_log.$max and last_kmsg.$max.
void rotate_logs(const char* last_log_file, const char* last_kmsg_file) {
- // Logs should only be rotated once.
- static bool rotated = false;
- if (rotated) {
- return;
- }
- rotated = true;
+ // Logs should only be rotated once.
+ static bool rotated = false;
+ if (rotated) {
+ return;
+ }
+ rotated = true;
- for (int i = KEEP_LOG_COUNT - 1; i >= 0; --i) {
- std::string old_log = android::base::StringPrintf("%s", last_log_file);
- if (i > 0) {
- old_log += "." + std::to_string(i);
- }
- std::string new_log = android::base::StringPrintf("%s.%d", last_log_file, i+1);
- // Ignore errors if old_log doesn't exist.
- rename(old_log.c_str(), new_log.c_str());
-
- std::string old_kmsg = android::base::StringPrintf("%s", last_kmsg_file);
- if (i > 0) {
- old_kmsg += "." + std::to_string(i);
- }
- std::string new_kmsg = android::base::StringPrintf("%s.%d", last_kmsg_file, i+1);
- rename(old_kmsg.c_str(), new_kmsg.c_str());
+ for (int i = KEEP_LOG_COUNT - 1; i >= 0; --i) {
+ std::string old_log = android::base::StringPrintf("%s", last_log_file);
+ if (i > 0) {
+ old_log += "." + std::to_string(i);
}
+ std::string new_log = android::base::StringPrintf("%s.%d", last_log_file, i + 1);
+ // Ignore errors if old_log doesn't exist.
+ rename(old_log.c_str(), new_log.c_str());
+
+ std::string old_kmsg = android::base::StringPrintf("%s", last_kmsg_file);
+ if (i > 0) {
+ old_kmsg += "." + std::to_string(i);
+ }
+ std::string new_kmsg = android::base::StringPrintf("%s.%d", last_kmsg_file, i + 1);
+ rename(old_kmsg.c_str(), new_kmsg.c_str());
+ }
}
diff --git a/rotate_logs.h b/rotate_logs.h
index 809c213..d65b7de 100644
--- a/rotate_logs.h
+++ b/rotate_logs.h
@@ -17,24 +17,19 @@
#ifndef _ROTATE_LOGS_H
#define _ROTATE_LOGS_H
-#include <string>
+#include <stddef.h>
+#include <sys/types.h>
+//#include <log/log_id.h>
#include <private/android_logger.h> /* private pmsg functions */
-constexpr int KEEP_LOG_COUNT = 10;
+static constexpr int KEEP_LOG_COUNT = 10;
-ssize_t logbasename(log_id_t /* logId */,
- char /* prio */,
- const char *filename,
- const char * /* buf */, size_t len,
- void *arg);
+ssize_t logbasename(log_id_t id, char prio, const char* filename, const char* buf, size_t len,
+ void* arg);
-ssize_t logrotate(
- log_id_t logId,
- char prio,
- const char *filename,
- const char *buf, size_t len,
- void *arg);
+ssize_t logrotate(log_id_t id, char prio, const char* filename, const char* buf, size_t len,
+ void* arg);
// Rename last_log -> last_log.1 -> last_log.2 -> ... -> last_log.$max.
// Similarly rename last_kmsg -> last_kmsg.1 -> ... -> last_kmsg.$max.
diff --git a/screen_ui.cpp b/screen_ui.cpp
index b8f6ea2..c8fb5aa 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "screen_ui.h"
+
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@@ -29,18 +31,19 @@
#include <time.h>
#include <unistd.h>
+#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
#include <android-base/logging.h>
#include <android-base/properties.h>
-#include <android-base/strings.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <minui/minui.h>
#include "common.h"
#include "device.h"
-#include "minui/minui.h"
-#include "screen_ui.h"
#include "ui.h"
// Return the current time as a double (including fractions of a second).
@@ -54,7 +57,7 @@
: kMarginWidth(RECOVERY_UI_MARGIN_WIDTH),
kMarginHeight(RECOVERY_UI_MARGIN_HEIGHT),
kAnimationFps(RECOVERY_UI_ANIMATION_FPS),
- density_(static_cast<float>(android::base::GetIntProperty("ro.sf.lcd_density", 160)) / 160.f),
+ kDensity(static_cast<float>(android::base::GetIntProperty("ro.sf.lcd_density", 160)) / 160.f),
currentIcon(NONE),
progressBarType(EMPTY),
progressScopeStart(0),
@@ -66,7 +69,6 @@
text_(nullptr),
text_col_(0),
text_row_(0),
- text_top_(0),
show_text(false),
show_text_ever(false),
menu_headers_(nullptr),
@@ -80,6 +82,8 @@
intro_done(false),
stage(-1),
max_stage(-1),
+ locale_(""),
+ rtl_locale_(false),
updateMutex(PTHREAD_MUTEX_INITIALIZER) {}
GRSurface* ScreenRecoveryUI::GetCurrentFrame() const {
@@ -105,7 +109,7 @@
}
int ScreenRecoveryUI::PixelsFromDp(int dp) const {
- return dp * density_;
+ return dp * kDensity;
}
// Here's the intended layout:
@@ -145,8 +149,8 @@
int elements_sum = gr_get_height(loopFrames[0]) + PixelsFromDp(kLayouts[layout_][ICON]) +
gr_get_height(installing_text) + PixelsFromDp(kLayouts[layout_][TEXT]) +
gr_get_height(progressBarFill);
- int bottom_gap = (gr_fb_height() - elements_sum) / 2;
- return gr_fb_height() - bottom_gap - gr_get_height(progressBarFill);
+ int bottom_gap = (ScreenHeight() - elements_sum) / 2;
+ return ScreenHeight() - bottom_gap - gr_get_height(progressBarFill);
}
// Clear the screen and draw the currently selected background icon (if any).
@@ -155,25 +159,24 @@
pagesIdentical = false;
gr_color(0, 0, 0, 255);
gr_clear();
-
if (currentIcon != NONE) {
if (max_stage != -1) {
int stage_height = gr_get_height(stageMarkerEmpty);
int stage_width = gr_get_width(stageMarkerEmpty);
- int x = (gr_fb_width() - max_stage * gr_get_width(stageMarkerEmpty)) / 2;
- int y = gr_fb_height() - stage_height;
+ int x = (ScreenWidth() - max_stage * gr_get_width(stageMarkerEmpty)) / 2;
+ int y = ScreenHeight() - stage_height - kMarginHeight;
for (int i = 0; i < max_stage; ++i) {
GRSurface* stage_surface = (i < stage) ? stageMarkerFill : stageMarkerEmpty;
- gr_blit(stage_surface, 0, 0, stage_width, stage_height, x, y);
+ DrawSurface(stage_surface, 0, 0, stage_width, stage_height, x, y);
x += stage_width;
}
}
GRSurface* text_surface = GetCurrentText();
- int text_x = (gr_fb_width() - gr_get_width(text_surface)) / 2;
+ int text_x = (ScreenWidth() - gr_get_width(text_surface)) / 2;
int text_y = GetTextBaseline();
gr_color(255, 255, 255, 255);
- gr_texticon(text_x, text_y, text_surface);
+ DrawTextIcon(text_x, text_y, text_surface);
}
}
@@ -184,21 +187,21 @@
GRSurface* frame = GetCurrentFrame();
int frame_width = gr_get_width(frame);
int frame_height = gr_get_height(frame);
- int frame_x = (gr_fb_width() - frame_width) / 2;
+ int frame_x = (ScreenWidth() - frame_width) / 2;
int frame_y = GetAnimationBaseline();
- gr_blit(frame, 0, 0, frame_width, frame_height, frame_x, frame_y);
+ DrawSurface(frame, 0, 0, frame_width, frame_height, frame_x, frame_y);
}
if (progressBarType != EMPTY) {
int width = gr_get_width(progressBarEmpty);
int height = gr_get_height(progressBarEmpty);
- int progress_x = (gr_fb_width() - width) / 2;
+ int progress_x = (ScreenWidth() - width) / 2;
int progress_y = GetProgressBaseline();
// Erase behind the progress bar (in case this was a progress-only update)
gr_color(0, 0, 0, 255);
- gr_fill(progress_x, progress_y, width, height);
+ DrawFill(progress_x, progress_y, width, height);
if (progressBarType == DETERMINATE) {
float p = progressScopeStart + progress * progressScopeSize;
@@ -207,19 +210,19 @@
if (rtl_locale_) {
// Fill the progress bar from right to left.
if (pos > 0) {
- gr_blit(progressBarFill, width - pos, 0, pos, height, progress_x + width - pos,
- progress_y);
+ DrawSurface(progressBarFill, width - pos, 0, pos, height, progress_x + width - pos,
+ progress_y);
}
if (pos < width - 1) {
- gr_blit(progressBarEmpty, 0, 0, width - pos, height, progress_x, progress_y);
+ DrawSurface(progressBarEmpty, 0, 0, width - pos, height, progress_x, progress_y);
}
} else {
// Fill the progress bar from left to right.
if (pos > 0) {
- gr_blit(progressBarFill, 0, 0, pos, height, progress_x, progress_y);
+ DrawSurface(progressBarFill, 0, 0, pos, height, progress_x, progress_y);
}
if (pos < width - 1) {
- gr_blit(progressBarEmpty, pos, 0, width - pos, height, progress_x + pos, progress_y);
+ DrawSurface(progressBarEmpty, pos, 0, width - pos, height, progress_x + pos, progress_y);
}
}
}
@@ -256,8 +259,96 @@
}
}
+void ScreenRecoveryUI::SelectAndShowBackgroundText(const std::vector<std::string>& locales_entries,
+ size_t sel) {
+ SetLocale(locales_entries[sel]);
+ std::vector<std::string> text_name = { "erasing_text", "error_text", "installing_text",
+ "installing_security_text", "no_command_text" };
+ std::unordered_map<std::string, std::unique_ptr<GRSurface, decltype(&free)>> surfaces;
+ for (const auto& name : text_name) {
+ GRSurface* text_image = nullptr;
+ LoadLocalizedBitmap(name.c_str(), &text_image);
+ if (!text_image) {
+ Print("Failed to load %s\n", name.c_str());
+ return;
+ }
+ surfaces.emplace(name, std::unique_ptr<GRSurface, decltype(&free)>(text_image, &free));
+ }
+
+ pthread_mutex_lock(&updateMutex);
+ gr_color(0, 0, 0, 255);
+ gr_clear();
+
+ int text_y = kMarginHeight;
+ int text_x = kMarginWidth;
+ int line_spacing = gr_sys_font()->char_height; // Put some extra space between images.
+ // Write the header and descriptive texts.
+ SetColor(INFO);
+ std::string header = "Show background text image";
+ text_y += DrawTextLine(text_x, text_y, header.c_str(), true);
+ std::string locale_selection = android::base::StringPrintf(
+ "Current locale: %s, %zu/%zu", locales_entries[sel].c_str(), sel, locales_entries.size());
+ const char* instruction[] = { locale_selection.c_str(),
+ "Use volume up/down to switch locales and power to exit.",
+ nullptr };
+ text_y += DrawWrappedTextLines(text_x, text_y, instruction);
+
+ // Iterate through the text images and display them in order for the current locale.
+ for (const auto& p : surfaces) {
+ text_y += line_spacing;
+ SetColor(LOG);
+ text_y += DrawTextLine(text_x, text_y, p.first.c_str(), false);
+ gr_color(255, 255, 255, 255);
+ gr_texticon(text_x, text_y, p.second.get());
+ text_y += gr_get_height(p.second.get());
+ }
+ // Update the whole screen.
+ gr_flip();
+ pthread_mutex_unlock(&updateMutex);
+}
+
+void ScreenRecoveryUI::CheckBackgroundTextImages(const std::string& saved_locale) {
+ // Load a list of locales embedded in one of the resource files.
+ std::vector<std::string> locales_entries = get_locales_in_png("installing_text");
+ if (locales_entries.empty()) {
+ Print("Failed to load locales from the resource files\n");
+ return;
+ }
+ size_t selected = 0;
+ SelectAndShowBackgroundText(locales_entries, selected);
+
+ FlushKeys();
+ while (true) {
+ int key = WaitKey();
+ if (key == KEY_POWER || key == KEY_ENTER) {
+ break;
+ } else if (key == KEY_UP || key == KEY_VOLUMEUP) {
+ selected = (selected == 0) ? locales_entries.size() - 1 : selected - 1;
+ SelectAndShowBackgroundText(locales_entries, selected);
+ } else if (key == KEY_DOWN || key == KEY_VOLUMEDOWN) {
+ selected = (selected == locales_entries.size() - 1) ? 0 : selected + 1;
+ SelectAndShowBackgroundText(locales_entries, selected);
+ }
+ }
+
+ SetLocale(saved_locale);
+}
+
+int ScreenRecoveryUI::ScreenWidth() const {
+ return gr_fb_width();
+}
+
+int ScreenRecoveryUI::ScreenHeight() const {
+ return gr_fb_height();
+}
+
+void ScreenRecoveryUI::DrawSurface(GRSurface* surface, int sx, int sy, int w, int h, int dx,
+ int dy) const {
+ gr_blit(surface, sx, sy, w, h, dx, dy);
+}
+
int ScreenRecoveryUI::DrawHorizontalRule(int y) const {
- gr_fill(0, y + 4, gr_fb_width(), y + 6);
+ gr_fill(0, y + 4, ScreenWidth(), y + 6);
return 8;
}
@@ -265,6 +356,14 @@
gr_fill(x, y, x + width, y + height);
}
+void ScreenRecoveryUI::DrawFill(int x, int y, int w, int h) const {
+ gr_fill(x, y, w, h);
+}
+
+void ScreenRecoveryUI::DrawTextIcon(int x, int y, GRSurface* surface) const {
+ gr_texticon(x, y, surface);
+}
+
int ScreenRecoveryUI::DrawTextLine(int x, int y, const char* line, bool bold) const {
gr_text(gr_sys_font(), x, y, line, bold);
return char_height_ + 4;
@@ -353,7 +452,7 @@
if (i == menu_sel) {
// Draw the highlight bar.
SetColor(IsLongPress() ? MENU_SEL_BG_ACTIVE : MENU_SEL_BG);
- DrawHighlightBar(0, y - 2, gr_fb_width(), char_height_ + 4);
+ DrawHighlightBar(0, y - 2, ScreenWidth(), char_height_ + 4);
// Bold white text for the selected item.
SetColor(MENU_SEL_FG);
y += DrawTextLine(x, y, menu_[i].c_str(), true);
@@ -368,9 +467,9 @@
// Display from the bottom up, until we hit the top of the screen, the bottom of the menu, or
// we've displayed the entire text buffer.
SetColor(LOG);
- int row = (text_top_ + text_rows_ - 1) % text_rows_;
+ int row = text_row_;
size_t count = 0;
- for (int ty = gr_fb_height() - kMarginHeight - char_height_; ty >= y && count < text_rows_;
+ for (int ty = ScreenHeight() - kMarginHeight - char_height_; ty >= y && count < text_rows_;
ty -= char_height_, ++count) {
DrawTextLine(kMarginWidth, ty, text_[row], false);
--row;
@@ -490,13 +589,14 @@
}
gr_font_size(gr_sys_font(), &char_width_, &char_height_);
- text_rows_ = (gr_fb_height() - kMarginHeight * 2) / char_height_;
- text_cols_ = (gr_fb_width() - kMarginWidth * 2) / char_width_;
+ text_rows_ = (ScreenHeight() - kMarginHeight * 2) / char_height_;
+ text_cols_ = (ScreenWidth() - kMarginWidth * 2) / char_width_;
return true;
}
bool ScreenRecoveryUI::Init(const std::string& locale) {
RecoveryUI::Init(locale);
+
if (!InitTextParams()) {
return false;
}
@@ -510,7 +610,9 @@
file_viewer_text_ = Alloc2d(text_rows_, text_cols_ + 1);
text_col_ = text_row_ = 0;
- text_top_ = 1;
+
+ // Set up the locale info.
+ SetLocale(locale);
LoadBitmap("icon_error", &error_icon);
@@ -643,7 +745,6 @@
text_[text_row_][text_col_] = '\0';
text_col_ = 0;
text_row_ = (text_row_ + 1) % text_rows_;
- if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_;
}
if (*ptr != '\n') text_[text_row_][text_col_++] = *ptr;
}
@@ -673,8 +774,6 @@
if (ch == '\n' || text_col_ >= text_cols_) {
text_col_ = 0;
++text_row_;
-
- if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_;
}
pthread_mutex_unlock(&updateMutex);
}
@@ -683,7 +782,6 @@
pthread_mutex_lock(&updateMutex);
text_col_ = 0;
text_row_ = 0;
- text_top_ = 1;
for (size_t i = 0; i < text_rows_; ++i) {
memset(text_[i], 0, text_cols_ + 1);
}
@@ -750,7 +848,6 @@
char** old_text = text_;
size_t old_text_col = text_col_;
size_t old_text_row = text_row_;
- size_t old_text_top = text_top_;
// Swap in the alternate screen and clear it.
text_ = file_viewer_text_;
@@ -762,7 +859,6 @@
text_ = old_text;
text_col_ = old_text_col;
text_row_ = old_text_row;
- text_top_ = old_text_top;
}
void ScreenRecoveryUI::StartMenu(const char* const* headers, const char* const* items,
@@ -841,3 +937,23 @@
// will change color to indicate a successful long press.
Redraw();
}
+
+void ScreenRecoveryUI::SetLocale(const std::string& new_locale) {
+ locale_ = new_locale;
+ rtl_locale_ = false;
+
+ if (!new_locale.empty()) {
+ size_t underscore = new_locale.find('_');
+ // lang has the language prefix prior to '_', or full string if '_' doesn't exist.
+ std::string lang = new_locale.substr(0, underscore);
+
+ // A bit cheesy: keep an explicit list of supported RTL languages.
+ if (lang == "ar" || // Arabic
+ lang == "fa" || // Persian (Farsi)
+ lang == "he" || // Hebrew (new language code)
+ lang == "iw" || // Hebrew (old language code)
+ lang == "ur") { // Urdu
+ rtl_locale_ = true;
+ }
+ }
+}
diff --git a/screen_ui.h b/screen_ui.h
index 8231a2b..f05761c 100644
--- a/screen_ui.h
+++ b/screen_ui.h
@@ -32,6 +32,17 @@
// (shows an icon + a progress bar, text logging, menu, etc.)
class ScreenRecoveryUI : public RecoveryUI {
public:
+ enum UIElement {
+ HEADER,
+ MENU,
+ MENU_SEL_BG,
+ MENU_SEL_BG_ACTIVE,
+ MENU_SEL_FG,
+ LOG,
+ TEXT_FILL,
+ INFO
+ };
+
ScreenRecoveryUI();
bool Init(const std::string& locale) override;
@@ -67,18 +78,12 @@
void Redraw();
- enum UIElement {
- HEADER,
- MENU,
- MENU_SEL_BG,
- MENU_SEL_BG_ACTIVE,
- MENU_SEL_FG,
- LOG,
- TEXT_FILL,
- INFO
- };
void SetColor(UIElement e) const;
+ // Check the background text image. Use volume up/down button to cycle through the locales
+ // embedded in the png file, and power button to go back to recovery main menu.
+ void CheckBackgroundTextImages(const std::string& saved_locale);
+
protected:
// The margin that we don't want to use for showing texts (e.g. round screen, or screen with
// rounded corners).
@@ -89,7 +94,58 @@
const int kAnimationFps;
// The scale factor from dp to pixels. 1.0 for mdpi, 4.0 for xxxhdpi.
- const float density_;
+ const float kDensity;
+
+ virtual bool InitTextParams();
+
+ virtual void draw_background_locked();
+ virtual void draw_foreground_locked();
+ virtual void draw_screen_locked();
+ virtual void update_screen_locked();
+ virtual void update_progress_locked();
+
+ GRSurface* GetCurrentFrame() const;
+ GRSurface* GetCurrentText() const;
+
+ static void* ProgressThreadStartRoutine(void* data);
+ void ProgressThreadLoop();
+
+ virtual void ShowFile(FILE*);
+ virtual void PrintV(const char*, bool, va_list);
+ void PutChar(char);
+ void ClearText();
+
+ void LoadAnimation();
+ void LoadBitmap(const char* filename, GRSurface** surface);
+ void LoadLocalizedBitmap(const char* filename, GRSurface** surface);
+
+ int PixelsFromDp(int dp) const;
+ virtual int GetAnimationBaseline() const;
+ virtual int GetProgressBaseline() const;
+ virtual int GetTextBaseline() const;
+
+ // Returns pixel width of draw buffer.
+ virtual int ScreenWidth() const;
+ // Returns pixel height of draw buffer.
+ virtual int ScreenHeight() const;
+
+ // Draws a highlight bar at (x, y) - (x + width, y + height).
+ virtual void DrawHighlightBar(int x, int y, int width, int height) const;
+ // Draws a horizontal rule at Y. Returns the offset it should be moving along Y-axis.
+ virtual int DrawHorizontalRule(int y) const;
+ // Draws a line of text. Returns the offset it should be moving along Y-axis.
+ virtual int DrawTextLine(int x, int y, const char* line, bool bold) const;
+ // Draws surface portion (sx, sy, w, h) at screen location (dx, dy).
+ virtual void DrawSurface(GRSurface* surface, int sx, int sy, int w, int h, int dx, int dy) const;
+ // Draws rectangle at (x, y) - (x + w, y + h).
+ virtual void DrawFill(int x, int y, int w, int h) const;
+ // Draws given surface (surface->pixel_bytes = 1) as text at (x, y).
+ virtual void DrawTextIcon(int x, int y, GRSurface* surface) const;
+ // Draws multiple text lines. Returns the offset it should be moving along Y-axis.
+ int DrawTextLines(int x, int y, const char* const* lines) const;
+ // Similar to DrawTextLines() to draw multiple text lines, but additionally wraps long lines.
+ // Returns the offset it should be moving along Y-axis.
+ int DrawWrappedTextLines(int x, int y, const char* const* lines) const;
Icon currentIcon;
@@ -123,7 +179,7 @@
// Log text overlay, displayed when a magic key is pressed.
char** text_;
- size_t text_col_, text_row_, text_top_;
+ size_t text_col_, text_row_;
bool show_text;
bool show_text_ever; // has show_text ever been true?
@@ -150,47 +206,18 @@
int char_width_;
int char_height_;
+ // The locale that's used to show the rendered texts.
+ std::string locale_;
+ bool rtl_locale_;
+
pthread_mutex_t updateMutex;
- virtual bool InitTextParams();
+ private:
+ void SetLocale(const std::string&);
- virtual void draw_background_locked();
- virtual void draw_foreground_locked();
- virtual void draw_screen_locked();
- virtual void update_screen_locked();
- virtual void update_progress_locked();
-
- GRSurface* GetCurrentFrame() const;
- GRSurface* GetCurrentText() const;
-
- static void* ProgressThreadStartRoutine(void* data);
- void ProgressThreadLoop();
-
- virtual void ShowFile(FILE*);
- virtual void PrintV(const char*, bool, va_list);
- void PutChar(char);
- void ClearText();
-
- void LoadAnimation();
- void LoadBitmap(const char* filename, GRSurface** surface);
- void LoadLocalizedBitmap(const char* filename, GRSurface** surface);
-
- int PixelsFromDp(int dp) const;
- virtual int GetAnimationBaseline() const;
- virtual int GetProgressBaseline() const;
- virtual int GetTextBaseline() const;
-
- // Draws a highlight bar at (x, y) - (x + width, y + height).
- virtual void DrawHighlightBar(int x, int y, int width, int height) const;
- // Draws a horizontal rule at Y. Returns the offset it should be moving along Y-axis.
- virtual int DrawHorizontalRule(int y) const;
- // Draws a line of text. Returns the offset it should be moving along Y-axis.
- virtual int DrawTextLine(int x, int y, const char* line, bool bold) const;
- // Draws multiple text lines. Returns the offset it should be moving along Y-axis.
- int DrawTextLines(int x, int y, const char* const* lines) const;
- // Similar to DrawTextLines() to draw multiple text lines, but additionally wraps long lines.
- // Returns the offset it should be moving along Y-axis.
- int DrawWrappedTextLines(int x, int y, const char* const* lines) const;
+ // Display the background texts for "erasing", "error", "no_command" and "installing" for the
+ // selected locale.
+ void SelectAndShowBackgroundText(const std::vector<std::string>& locales_entries, size_t sel);
};
#endif // RECOVERY_UI_H
diff --git a/stub_ui.h b/stub_ui.h
index 85dbcfd..1f6b29a 100644
--- a/stub_ui.h
+++ b/stub_ui.h
@@ -24,18 +24,18 @@
public:
StubRecoveryUI() = default;
- void SetBackground(Icon icon) override {}
- void SetSystemUpdateText(bool security_update) override {}
+ void SetBackground(Icon /* icon */) override {}
+ void SetSystemUpdateText(bool /* security_update */) override {}
// progress indicator
- void SetProgressType(ProgressType type) override {}
- void ShowProgress(float portion, float seconds) override {}
- void SetProgress(float fraction) override {}
+ void SetProgressType(ProgressType /* type */) override {}
+ void ShowProgress(float /* portion */, float /* seconds */) override {}
+ void SetProgress(float /* fraction */) override {}
- void SetStage(int current, int max) override {}
+ void SetStage(int /* current */, int /* max */) override {}
// text log
- void ShowText(bool visible) override {}
+ void ShowText(bool /* visible */) override {}
bool IsTextVisible() override {
return false;
}
@@ -50,12 +50,12 @@
vprintf(fmt, ap);
va_end(ap);
}
- void PrintOnScreenOnly(const char* fmt, ...) override {}
- void ShowFile(const char* filename) override {}
+ void PrintOnScreenOnly(const char* /* fmt */, ...) override {}
+ void ShowFile(const char* /* filename */) override {}
// menu display
- void StartMenu(const char* const* headers, const char* const* items,
- int initial_selection) override {}
+ void StartMenu(const char* const* /* headers */, const char* const* /* items */,
+ int /* initial_selection */) override {}
int SelectMenu(int sel) override {
return sel;
}
diff --git a/tests/Android.mk b/tests/Android.mk
index fe4de31..f19ca36 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -18,7 +18,7 @@
# Unit tests
include $(CLEAR_VARS)
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Wall -Werror
LOCAL_MODULE := recovery_unit_test
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_STATIC_LIBRARIES := \
@@ -30,7 +30,8 @@
libutils \
libz \
libselinux \
- libbase
+ libbase \
+ libBionicGtestMain
LOCAL_SRC_FILES := \
unit/asn1_decoder_test.cpp \
@@ -47,11 +48,12 @@
# Manual tests
include $(CLEAR_VARS)
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Wall -Werror
LOCAL_MODULE := recovery_manual_test
LOCAL_STATIC_LIBRARIES := \
libminui \
- libbase
+ libbase \
+ libBionicGtestMain
LOCAL_SRC_FILES := manual/recovery_test.cpp
LOCAL_SHARED_LIBRARIES := \
@@ -82,6 +84,7 @@
# Component tests
include $(CLEAR_VARS)
LOCAL_CFLAGS := \
+ -Wall \
-Werror \
-D_FILE_OFFSET_BITS=64
@@ -143,9 +146,9 @@
libdivsufsort \
libdivsufsort64 \
libfs_mgr \
- liblog \
libvintf_recovery \
libvintf \
+ libhidl-gen-utils \
libtinyxml2 \
libselinux \
libext4_utils \
@@ -154,6 +157,7 @@
libcrypto \
libbz \
libziparchive \
+ liblog \
libutils \
libz \
libbase \
@@ -163,6 +167,7 @@
libsquashfs_utils \
libcutils \
libbrotli \
+ libBionicGtestMain \
$(tune2fs_static_libraries)
testdata_files := $(call find-subdir-files, testdata/*)
@@ -192,7 +197,7 @@
# Host tests
include $(CLEAR_VARS)
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Wall -Werror
LOCAL_MODULE := recovery_host_test
LOCAL_MODULE_HOST_OS := linux
LOCAL_C_INCLUDES := bootable/recovery
@@ -201,16 +206,19 @@
LOCAL_STATIC_LIBRARIES := \
libimgdiff \
libimgpatch \
+ libotautil \
libbsdiff \
libbspatch \
libziparchive \
libutils \
libbase \
libcrypto \
+ libbrotli \
libbz \
libdivsufsort64 \
libdivsufsort \
- libz
+ libz \
+ libBionicGtestMain
LOCAL_SHARED_LIBRARIES := \
liblog
include $(BUILD_HOST_NATIVE_TEST)
diff --git a/tests/common/test_constants.h b/tests/common/test_constants.h
index f6b6922..514818e 100644
--- a/tests/common/test_constants.h
+++ b/tests/common/test_constants.h
@@ -19,6 +19,8 @@
#include <stdlib.h>
+#include <string>
+
// Zip entries in ziptest_valid.zip.
static const std::string kATxtContents("abcdefghabcdefgh\n");
static const std::string kBTxtContents("abcdefgh\n");
@@ -30,10 +32,14 @@
// echo -n -e "abcdefgh\n" | sha1sum
static const std::string kBTxtSha1Sum("e414af7161c9554089f4106d6f1797ef14a73666");
-static const char* data_root = getenv("ANDROID_DATA");
-
static std::string from_testdata_base(const std::string& fname) {
- return std::string(data_root) + "/nativetest/recovery/testdata/" + fname;
+#ifdef __ANDROID__
+ static std::string data_root = getenv("ANDROID_DATA");
+#else
+ static std::string data_root = std::string(getenv("ANDROID_PRODUCT_OUT")) + "/data";
+#endif
+
+ return data_root + "/nativetest/recovery/testdata/" + fname;
}
#endif // _OTA_TEST_CONSTANTS_H
diff --git a/tests/component/applypatch_test.cpp b/tests/component/applypatch_test.cpp
index 016fed9..61e06ad 100644
--- a/tests/component/applypatch_test.cpp
+++ b/tests/component/applypatch_test.cpp
@@ -30,12 +30,16 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/test_utils.h>
+#include <bsdiff/bsdiff.h>
#include <openssl/sha.h>
#include "applypatch/applypatch.h"
#include "applypatch/applypatch_modes.h"
#include "common/test_constants.h"
-#include "print_sha1.h"
+#include "otautil/cache_location.h"
+#include "otautil/print_sha1.h"
+
+using namespace std::string_literals;
static void sha1sum(const std::string& fname, std::string* sha1, size_t* fsize = nullptr) {
ASSERT_NE(nullptr, sha1);
@@ -53,34 +57,20 @@
}
static void mangle_file(const std::string& fname) {
- std::string content;
- content.reserve(1024);
+ std::string content(1024, '\0');
for (size_t i = 0; i < 1024; i++) {
content[i] = rand() % 256;
}
ASSERT_TRUE(android::base::WriteStringToFile(content, fname));
}
-static bool file_cmp(const std::string& f1, const std::string& f2) {
- std::string c1;
- android::base::ReadFileToString(f1, &c1);
- std::string c2;
- android::base::ReadFileToString(f2, &c2);
- return c1 == c2;
-}
-
class ApplyPatchTest : public ::testing::Test {
public:
- static void SetUpTestCase() {
+ virtual void SetUp() override {
// set up files
old_file = from_testdata_base("old.file");
new_file = from_testdata_base("new.file");
- patch_file = from_testdata_base("patch.bsdiff");
- rand_file = "/cache/applypatch_test_rand.file";
- cache_file = "/cache/saved.file";
-
- // write stuff to rand_file
- ASSERT_TRUE(android::base::WriteStringToFile("hello", rand_file));
+ nonexistent_file = from_testdata_base("nonexistent.file");
// set up SHA constants
sha1sum(old_file, &old_sha1, &old_size);
@@ -90,56 +80,35 @@
bad_sha1_b = android::base::StringPrintf("%040x", rand());
}
- static std::string old_file;
- static std::string new_file;
- static std::string rand_file;
- static std::string cache_file;
- static std::string patch_file;
+ std::string old_file;
+ std::string new_file;
+ std::string nonexistent_file;
- static std::string old_sha1;
- static std::string new_sha1;
- static std::string bad_sha1_a;
- static std::string bad_sha1_b;
+ std::string old_sha1;
+ std::string new_sha1;
+ std::string bad_sha1_a;
+ std::string bad_sha1_b;
- static size_t old_size;
- static size_t new_size;
+ size_t old_size;
+ size_t new_size;
};
-static void cp(const std::string& src, const std::string& tgt) {
- std::string cmd = "cp " + src + " " + tgt;
- system(cmd.c_str());
-}
-
-static void backup_old() {
- cp(ApplyPatchTest::old_file, ApplyPatchTest::cache_file);
-}
-
-static void restore_old() {
- cp(ApplyPatchTest::cache_file, ApplyPatchTest::old_file);
-}
-
class ApplyPatchCacheTest : public ApplyPatchTest {
- public:
- virtual void SetUp() {
- backup_old();
- }
-
- virtual void TearDown() {
- restore_old();
+ protected:
+ void SetUp() override {
+ ApplyPatchTest::SetUp();
+ CacheLocation::location().set_cache_temp_source(old_file);
}
};
-std::string ApplyPatchTest::old_file;
-std::string ApplyPatchTest::new_file;
-std::string ApplyPatchTest::rand_file;
-std::string ApplyPatchTest::patch_file;
-std::string ApplyPatchTest::cache_file;
-std::string ApplyPatchTest::old_sha1;
-std::string ApplyPatchTest::new_sha1;
-std::string ApplyPatchTest::bad_sha1_a;
-std::string ApplyPatchTest::bad_sha1_b;
-size_t ApplyPatchTest::old_size;
-size_t ApplyPatchTest::new_size;
+class ApplyPatchModesTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ CacheLocation::location().set_cache_temp_source(cache_source.path);
+ }
+
+ TemporaryFile cache_source;
+};
TEST_F(ApplyPatchTest, CheckModeSkip) {
std::vector<std::string> sha1s;
@@ -197,43 +166,31 @@
ASSERT_EQ(0, applypatch_check(src_file.c_str(), sha1s));
}
-TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) {
- mangle_file(old_file);
- std::vector<std::string> sha1s = { old_sha1 };
- ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
+TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSourceSingle) {
+ TemporaryFile temp_file;
+ mangle_file(temp_file.path);
+ std::vector<std::string> sha1s_single = { old_sha1 };
+ ASSERT_EQ(0, applypatch_check(temp_file.path, sha1s_single));
+ ASSERT_EQ(0, applypatch_check(nonexistent_file.c_str(), sha1s_single));
}
-TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedMultiple) {
- mangle_file(old_file);
- std::vector<std::string> sha1s = { bad_sha1_a, old_sha1, bad_sha1_b };
- ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
+TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSourceMultiple) {
+ TemporaryFile temp_file;
+ mangle_file(temp_file.path);
+ std::vector<std::string> sha1s_multiple = { bad_sha1_a, old_sha1, bad_sha1_b };
+ ASSERT_EQ(0, applypatch_check(temp_file.path, sha1s_multiple));
+ ASSERT_EQ(0, applypatch_check(nonexistent_file.c_str(), sha1s_multiple));
}
-TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedFailure) {
- mangle_file(old_file);
- std::vector<std::string> sha1s = { bad_sha1_a, bad_sha1_b };
- ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
+TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSourceFailure) {
+ TemporaryFile temp_file;
+ mangle_file(temp_file.path);
+ std::vector<std::string> sha1s_failure = { bad_sha1_a, bad_sha1_b };
+ ASSERT_NE(0, applypatch_check(temp_file.path, sha1s_failure));
+ ASSERT_NE(0, applypatch_check(nonexistent_file.c_str(), sha1s_failure));
}
-TEST_F(ApplyPatchCacheTest, CheckCacheMissingSingle) {
- unlink(&old_file[0]);
- std::vector<std::string> sha1s = { old_sha1 };
- ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
-}
-
-TEST_F(ApplyPatchCacheTest, CheckCacheMissingMultiple) {
- unlink(&old_file[0]);
- std::vector<std::string> sha1s = { bad_sha1_a, old_sha1, bad_sha1_b };
- ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
-}
-
-TEST_F(ApplyPatchCacheTest, CheckCacheMissingFailure) {
- unlink(&old_file[0]);
- std::vector<std::string> sha1s = { bad_sha1_a, bad_sha1_b };
- ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
-}
-
-TEST(ApplyPatchModesTest, InvalidArgs) {
+TEST_F(ApplyPatchModesTest, InvalidArgs) {
// At least two args (including the filename).
ASSERT_EQ(2, applypatch_modes(1, (const char* []){ "applypatch" }));
@@ -241,7 +198,7 @@
ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-x" }));
}
-TEST(ApplyPatchModesTest, PatchModeEmmcTarget) {
+TEST_F(ApplyPatchModesTest, PatchModeEmmcTarget) {
std::string boot_img = from_testdata_base("boot.img");
size_t boot_img_size;
std::string boot_img_sha1;
@@ -311,7 +268,55 @@
ASSERT_EQ(0, applypatch_modes(args3.size(), args3.data()));
}
-TEST(ApplyPatchModesTest, PatchModeInvalidArgs) {
+// Ensures that applypatch works with a bsdiff based recovery-from-boot.p.
+TEST_F(ApplyPatchModesTest, PatchModeEmmcTargetWithBsdiffPatch) {
+ std::string boot_img_file = from_testdata_base("boot.img");
+ std::string boot_img_sha1;
+ size_t boot_img_size;
+ sha1sum(boot_img_file, &boot_img_sha1, &boot_img_size);
+
+ std::string recovery_img_file = from_testdata_base("recovery.img");
+ std::string recovery_img_sha1;
+ size_t recovery_img_size;
+ sha1sum(recovery_img_file, &recovery_img_sha1, &recovery_img_size);
+
+ // Generate the bsdiff patch of recovery-from-boot.p.
+ std::string src_content;
+ ASSERT_TRUE(android::base::ReadFileToString(boot_img_file, &src_content));
+
+ std::string tgt_content;
+ ASSERT_TRUE(android::base::ReadFileToString(recovery_img_file, &tgt_content));
+
+ TemporaryFile patch_file;
+ ASSERT_EQ(0,
+ bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(src_content.data()), src_content.size(),
+ reinterpret_cast<const uint8_t*>(tgt_content.data()), tgt_content.size(),
+ patch_file.path, nullptr));
+
+ // applypatch <src-file> <tgt-file> <tgt-sha1> <tgt-size> <src-sha1>:<patch>
+ std::string src_file_arg =
+ "EMMC:" + boot_img_file + ":" + std::to_string(boot_img_size) + ":" + boot_img_sha1;
+ TemporaryFile tgt_file;
+ std::string tgt_file_arg = "EMMC:"s + tgt_file.path;
+ std::string recovery_img_size_arg = std::to_string(recovery_img_size);
+ std::string patch_arg = boot_img_sha1 + ":" + patch_file.path;
+ std::vector<const char*> args = { "applypatch",
+ src_file_arg.c_str(),
+ tgt_file_arg.c_str(),
+ recovery_img_sha1.c_str(),
+ recovery_img_size_arg.c_str(),
+ patch_arg.c_str() };
+ ASSERT_EQ(0, applypatch_modes(args.size(), args.data()));
+
+ // Double check the patched recovery image.
+ std::string tgt_file_sha1;
+ size_t tgt_file_size;
+ sha1sum(tgt_file.path, &tgt_file_sha1, &tgt_file_size);
+ ASSERT_EQ(recovery_img_size, tgt_file_size);
+ ASSERT_EQ(recovery_img_sha1, tgt_file_sha1);
+}
+
+TEST_F(ApplyPatchModesTest, PatchModeInvalidArgs) {
// Invalid bonus file.
ASSERT_NE(0, applypatch_modes(3, (const char* []){ "applypatch", "-b", "/doesntexist" }));
@@ -372,11 +377,11 @@
ASSERT_NE(0, applypatch_modes(args6.size(), args6.data()));
}
-TEST(ApplyPatchModesTest, CheckModeInvalidArgs) {
+TEST_F(ApplyPatchModesTest, CheckModeInvalidArgs) {
// Insufficient args.
ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-c" }));
}
-TEST(ApplyPatchModesTest, ShowLicenses) {
+TEST_F(ApplyPatchModesTest, ShowLicenses) {
ASSERT_EQ(0, applypatch_modes(2, (const char* []){ "applypatch", "-l" }));
}
diff --git a/tests/component/bootloader_message_test.cpp b/tests/component/bootloader_message_test.cpp
index b38bc71..6cc59a4 100644
--- a/tests/component/bootloader_message_test.cpp
+++ b/tests/component/bootloader_message_test.cpp
@@ -18,53 +18,12 @@
#include <vector>
#include <android-base/strings.h>
+#include <android-base/test_utils.h>
#include <bootloader_message/bootloader_message.h>
#include <gtest/gtest.h>
-class BootloaderMessageTest : public ::testing::Test {
- protected:
- BootloaderMessageTest() : has_misc(true) {}