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
This commit is contained in:
@@ -10,6 +10,5 @@ IndentWidth: 2
|
||||
PointerAlignment: Left
|
||||
TabWidth: 2
|
||||
UseTab: Never
|
||||
PenaltyExcessCharacter: 32
|
||||
|
||||
Cpp11BracedListStyle: false
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
subdirs = [
|
||||
// "bootloader_message",
|
||||
// "applypatch",
|
||||
"bootloader_message",
|
||||
// "edify",
|
||||
// "otafault",
|
||||
// "otautil",
|
||||
// "uncrypt",
|
||||
]
|
||||
|
||||
229
Android.mk
229
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 += \
|
||||
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 @@ endif
|
||||
|
||||
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 @@ ifeq ($(TW_OEM_BUILD),true)
|
||||
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 @@ LOCAL_SHARED_LIBRARIES += libselinux
|
||||
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 @@ endif
|
||||
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 @@ else
|
||||
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 @@ ifneq ($(TW_USE_TOOLBOX), true)
|
||||
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
|
||||
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 := file_contexts_text
|
||||
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 @@ endif
|
||||
# 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 @@ ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 24; echo $$?),0)
|
||||
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 @@ ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 24; echo $$?),0)
|
||||
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 @@ endif
|
||||
LOCAL_MODULE := librecovery
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libminui \
|
||||
libotautil \
|
||||
libvintf_recovery \
|
||||
libcrypto_utils \
|
||||
libcrypto \
|
||||
@@ -646,6 +661,7 @@ include $(BUILD_STATIC_LIBRARY)
|
||||
# ===============================
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
LOCAL_MODULE := libaosprecovery
|
||||
LOCAL_MODULE_TAGS := eng optional
|
||||
LOCAL_CFLAGS := -std=gnu++0x
|
||||
@@ -655,6 +671,7 @@ LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
|
||||
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 @@ ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 24; echo $$?),0)
|
||||
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 $(BUILD_STATIC_LIBRARY)
|
||||
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 @@ include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
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 @@ ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 22; echo $$?),0)
|
||||
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 :=
|
||||
|
||||
2
OWNERS
2
OWNERS
@@ -1,3 +1,3 @@
|
||||
enh+aosp-gerrit@google.com
|
||||
enh@google.com
|
||||
tbao@google.com
|
||||
xunchang@google.com
|
||||
|
||||
6
PREUPLOAD.cfg
Normal file
6
PREUPLOAD.cfg
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ bool twrpback::backup(std::string command) {
|
||||
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 @@ bool twrpback::backup(std::string command) {
|
||||
}
|
||||
|
||||
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 @@ bool twrpback::backup(std::string command) {
|
||||
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 @@ bool twrpback::backup(std::string command) {
|
||||
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 @@ bool twrpback::restore(void) {
|
||||
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 @@ bool twrpback::restore(void) {
|
||||
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 @@ bool twrpback::checkMD5Trailer(char readAdbStream[], uint64_t md5fnsize, twrpMD5
|
||||
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;
|
||||
|
||||
|
||||
206
applypatch/Android.bp
Normal file
206
applypatch/Android.bp
Normal file
@@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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 $@ $^
|
||||
@@ -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 @@ int LoadFileContents(const char* filename, FileContents* file) {
|
||||
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 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file
|
||||
|
||||
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 @@ int SaveFileContents(const char* filename, const FileContents* file) {
|
||||
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 @@ int applypatch_check(const char* filename, const std::vector<std::string>& patch
|
||||
(!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 @@ int CacheSizeCheck(size_t bytes) {
|
||||
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 @@ int CacheSizeCheck(size_t bytes) {
|
||||
// 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 @@ int applypatch(const char* source_filename, const char* target_filename,
|
||||
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 @@ static int GenerateTarget(const FileContents& source_file, const std::unique_ptr
|
||||
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 @@ static int GenerateTarget(const FileContents& source_file, const std::unique_ptr
|
||||
|
||||
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 @@ static int GenerateTarget(const FileContents& source_file, const std::unique_ptr
|
||||
}
|
||||
|
||||
// Delete the backup copy of the source.
|
||||
unlink(CACHE_TEMP_SOURCE);
|
||||
unlink(CacheLocation::location().cache_temp_source().c_str());
|
||||
|
||||
// Success!
|
||||
return 0;
|
||||
|
||||
@@ -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 @@ void ShowBSDiffLicense() {
|
||||
);
|
||||
}
|
||||
|
||||
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 @@ int ApplyBSDiffPatch(const unsigned char* old_data, size_t old_size, const Value
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 @@ static std::set<std::string> FindExpendableFiles() {
|
||||
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 @@ static std::set<std::string> FindExpendableFiles() {
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 @@ static inline int32_t Read4(const void *address) {
|
||||
// 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 @@ static bool ApplyBSDiffPatchAndStreamOutput(const uint8_t* src_data, size_t src_
|
||||
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 @@ static bool ApplyBSDiffPatchAndStreamOutput(const uint8_t* src_data, size_t src_
|
||||
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 @@ static bool ApplyBSDiffPatchAndStreamOutput(const uint8_t* src_data, size_t src_
|
||||
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 @@ static bool ApplyBSDiffPatchAndStreamOutput(const uint8_t* src_data, size_t src_
|
||||
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 @@ int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const Value*
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 LoadFileContents(const char* filename, FileContents* file);
|
||||
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
|
||||
|
||||
306
applypatch/include/applypatch/imgdiff_image.h
Normal file
306
applypatch/include/applypatch/imgdiff_image.h
Normal file
@@ -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
|
||||
@@ -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
|
||||
@@ -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_restore_raw_partition(const char *partition, const char *filename)
|
||||
|
||||
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 cmd_bml_backup_raw_partition(const char *partition, const char *out_file)
|
||||
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 @@ ERROR3:
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -24,8 +24,7 @@ LOCAL_CFLAGS := \
|
||||
-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 := \
|
||||
|
||||
@@ -17,7 +17,10 @@
|
||||
cc_library_static {
|
||||
name: "libbootloader_message",
|
||||
srcs: ["bootloader_message.cpp"],
|
||||
cppflags: ["-Werror"],
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
],
|
||||
static_libs: [
|
||||
"libbase",
|
||||
"libfs_mgr",
|
||||
@@ -186,14 +186,8 @@ bool clear_bootloader_message(std::string* err) {
|
||||
|
||||
bool write_bootloader_message(const std::vector<std::string>& options, std::string* err) {
|
||||
bootloader_message boot = {};
|
||||
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
|
||||
strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
|
||||
for (const auto& s : options) {
|
||||
strlcat(boot.recovery, s.c_str(), sizeof(boot.recovery));
|
||||
if (s.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 @@ bool update_bootloader_message(const std::vector<std::string>& options, std::str
|
||||
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) {
|
||||
|
||||
@@ -114,13 +114,17 @@ static_assert(sizeof(struct bootloader_message) == 2048,
|
||||
* 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 @@ bool write_bootloader_message(const std::vector<std::string>& options, std::stri
|
||||
// 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);
|
||||
|
||||
|
||||
6
common.h
6
common.h
@@ -40,6 +40,10 @@ extern "C" {
|
||||
#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 @@ FILE* fopen_path(const char *path, const char *mode);
|
||||
|
||||
void ui_print(const char* format, ...);
|
||||
|
||||
static bool is_ro_debuggable();
|
||||
//static bool is_ro_debuggable();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ LOCAL_MODULE := libe4crypt
|
||||
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 @@ ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26; echo $$?),0)
|
||||
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)
|
||||
|
||||
|
||||
@@ -312,7 +312,7 @@ bool lookup_key_ref(const std::map<userid_t, std::string>& key_map, userid_t use
|
||||
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 @@ static bool parse_hex(const char* hex, std::string* result) {
|
||||
}
|
||||
|
||||
// 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 @@ bool e4crypt_unlock_user_key(userid_t user_id, int serial, const char* token_hex
|
||||
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) {
|
||||
|
||||
@@ -24,6 +24,8 @@ ifneq ($(wildcard hardware/libhardware/include/hardware/keymaster0.h),)
|
||||
LOCAL_C_INCLUDES += external/boringssl/src/include
|
||||
endif
|
||||
|
||||
LOCAL_CFLAGS += -Wno-unused-function
|
||||
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES += libscrypttwrp_static
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
@@ -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 @@ static int keymaster_sign_object(struct crypt_mnt_ftr *ftr,
|
||||
}
|
||||
#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_info(char **metadata_fname, off64_t *off)
|
||||
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 @@ static int get_dm_crypt_version(int fd, const char *name, int *version)
|
||||
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 @@ static int get_dm_crypt_version(int fd, const char *name, int *version)
|
||||
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 @@ static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, const unsigned
|
||||
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 @@ static int scrypt_keymaster(const char *passwd, const unsigned char *salt,
|
||||
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 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr,
|
||||
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;
|
||||
|
||||
|
||||
@@ -135,9 +135,7 @@ smix(uint8_t * B, size_t r, uint64_t N, void * V, void * XY)
|
||||
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);
|
||||
|
||||
44
device.cpp
44
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]) ==
|
||||
|
||||
1
device.h
1
device.h
@@ -66,6 +66,7 @@ class Device {
|
||||
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
|
||||
|
||||
@@ -15,6 +15,7 @@ LOCAL_SRC_FILES := \
|
||||
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_SRC_FILES := \
|
||||
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_SRC_FILES := src/mkfs.fat.c
|
||||
|
||||
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
|
||||
|
||||
45
edify/Android.bp
Normal file
45
edify/Android.bp
Normal file
@@ -0,0 +1,45 @@
|
||||
// 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: "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",
|
||||
"libotautil",
|
||||
],
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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* IfElseFn(const char* name, State* state, const std::vector<std::unique_pt
|
||||
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, const char* format, ...) {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
State::State(const std::string& script, void* cookie) :
|
||||
script(script),
|
||||
cookie(cookie) {
|
||||
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), error_code(kNoError), cause_code(kNoCause) {}
|
||||
|
||||
@@ -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 {
|
||||
@@ -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 @@ std::string string_buffer;
|
||||
|
||||
%x STR
|
||||
|
||||
%option noinput
|
||||
%option nounput
|
||||
%option noyywrap
|
||||
|
||||
%%
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
#include <android-base/macros.h>
|
||||
|
||||
#include "expr.h"
|
||||
#include "edify/expr.h"
|
||||
#include "yydefs.h"
|
||||
#include "parser.h"
|
||||
|
||||
|
||||
@@ -29,8 +29,9 @@ on init
|
||||
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
|
||||
|
||||
@@ -6,7 +6,7 @@ LOCAL_MODULE_STEM := fsck.exfat
|
||||
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 \
|
||||
|
||||
@@ -5,7 +5,7 @@ LOCAL_MODULE := exfat-fuse
|
||||
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 \
|
||||
|
||||
@@ -3,7 +3,7 @@ include $(CLEAR_VARS)
|
||||
|
||||
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
|
||||
|
||||
@@ -46,7 +46,7 @@ void exfat_closedir(struct exfat* ef, struct exfat_iterator* it)
|
||||
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;
|
||||
|
||||
@@ -5,7 +5,7 @@ LOCAL_MODULE := mkexfatfs
|
||||
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 \
|
||||
|
||||
@@ -45,6 +45,8 @@ LOCAL_CFLAGS := \
|
||||
-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
|
||||
|
||||
|
||||
@@ -282,7 +282,7 @@ static int receive_fd(int fd)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 @@ int run_fuse_sideload(struct provider_vtab* vtab, void* cookie, uint64_t file_si
|
||||
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 @@ int run_fuse_sideload(struct provider_vtab* vtab, void* cookie, uint64_t file_si
|
||||
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 @@ int run_fuse_sideload(struct provider_vtab* vtab, void* cookie, uint64_t file_si
|
||||
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 @@ int run_fuse_sideload(struct provider_vtab* vtab, void* cookie, uint64_t file_si
|
||||
}
|
||||
|
||||
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 @@ int run_fuse_sideload(struct provider_vtab* vtab, void* cookie, uint64_t file_si
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
544
fuse_sideload22.cpp
Normal file
544
fuse_sideload22.cpp
Normal file
@@ -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);
|
||||
}
|
||||
47
fuse_sideload22.h
Normal file
47
fuse_sideload22.h
Normal file
@@ -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
|
||||
@@ -13,5 +13,7 @@ LOCAL_SRC_FILES = \
|
||||
gpt.c \
|
||||
gptcrc32.c
|
||||
|
||||
LOCAL_CFLAGS := -Wno-format
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := libc
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
@@ -41,6 +41,7 @@ endif
|
||||
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 @@ LOCAL_C_INCLUDES += \
|
||||
|
||||
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 @@ define TW_THEME_WARNING_MSG
|
||||
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 @@ define TW_CUSTOM_THEME_WARNING_MSG
|
||||
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 @@ ifeq ($(TW_CUSTOM_THEME),)
|
||||
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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -45,9 +45,6 @@ extern "C" {
|
||||
GUIButton::GUIButton(xml_node<>* node)
|
||||
: GUIObject(node)
|
||||
{
|
||||
xml_attribute<>* attr;
|
||||
xml_node<>* child;
|
||||
|
||||
mButtonImg = NULL;
|
||||
mButtonIcon = NULL;
|
||||
mButtonLabel = NULL;
|
||||
@@ -201,9 +198,12 @@ int GUIButton::SetRenderPos(int x, int y, int w, int h)
|
||||
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;
|
||||
|
||||
@@ -82,10 +82,11 @@ GUICheckbox::GUICheckbox(xml_node<>* node)
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -112,8 +112,17 @@ GUIFileSelector::GUIFileSelector(xml_node<>* node) : GUIScrollList(node)
|
||||
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
|
||||
|
||||
@@ -122,7 +122,8 @@ GUIInput::GUIInput(xml_node<>* node)
|
||||
if (child)
|
||||
{
|
||||
mFont = LoadAttrFont(child, "resource");
|
||||
mFontHeight = mFont->GetHeight();
|
||||
if (mFont && mFont->GetResource())
|
||||
mFontHeight = mFont->GetHeight();
|
||||
}
|
||||
|
||||
child = FindNode(node, "data");
|
||||
@@ -299,9 +300,6 @@ int GUIInput::Render(void)
|
||||
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::GetSelection(int x, int y)
|
||||
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;
|
||||
|
||||
@@ -322,7 +322,7 @@ void GUIKeyboard::DrawKey(Key& key, int keyX, int keyY, int keyW, int keyH)
|
||||
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 @@ void GUIKeyboard::DrawKey(Key& key, int keyX, int keyY, int keyW, int keyH)
|
||||
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 @@ void GUIKeyboard::DrawKey(Key& key, int keyX, int keyY, int keyW, int keyH)
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -44,8 +44,17 @@ GUIListBox::GUIListBox(xml_node<>* node) : GUIScrollList(node)
|
||||
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
|
||||
|
||||
@@ -78,7 +78,7 @@ void MouseCursor::LoadData(xml_node<>* node)
|
||||
{
|
||||
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 @@ int MouseCursor::Render(void)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
#ifdef USE_MINZIP
|
||||
#include "../minzip/SysUtil.h"
|
||||
#else
|
||||
#include "../otautil/SysUtil.h"
|
||||
#include <otautil/SysUtil.h>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
@@ -58,8 +58,17 @@ GUIPartitionList::GUIPartitionList(xml_node<>* node) : GUIScrollList(node)
|
||||
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");
|
||||
|
||||
@@ -40,7 +40,6 @@ extern "C" {
|
||||
GUIPatternPassword::GUIPatternPassword(xml_node<>* node)
|
||||
: GUIObject(node)
|
||||
{
|
||||
xml_attribute<>* attr;
|
||||
xml_node<>* child;
|
||||
|
||||
// 3x3 is the default.
|
||||
@@ -107,7 +106,7 @@ GUIPatternPassword::GUIPatternPassword(xml_node<>* node)
|
||||
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 @@ int GUIPatternPassword::Render(void)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ extern "C" {
|
||||
|
||||
GUIProgressBar::GUIProgressBar(xml_node<>* node) : GUIObject(node)
|
||||
{
|
||||
xml_attribute<>* attr;
|
||||
xml_node<>* child;
|
||||
|
||||
mEmptyBar = NULL;
|
||||
@@ -79,8 +78,12 @@ GUIProgressBar::GUIProgressBar(xml_node<>* node) : GUIObject(node)
|
||||
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)
|
||||
|
||||
@@ -294,38 +294,38 @@ AnimationResource* ResourceManager::FindAnimation(const std::string& name) const
|
||||
|
||||
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 @@ void ResourceManager::LoadResources(xml_node<>* resList, ZipWrap* pZip, std::str
|
||||
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 @@ void ResourceManager::LoadResources(xml_node<>* resList, ZipWrap* pZip, std::str
|
||||
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 @@ void ResourceManager::LoadResources(xml_node<>* resList, ZipWrap* pZip, std::str
|
||||
else if (type == "animation")
|
||||
{
|
||||
AnimationResource* res = new AnimationResource(child, pZip);
|
||||
if (res->GetResourceCount())
|
||||
if (res && res->GetResourceCount())
|
||||
mAnimations.push_back(res);
|
||||
else {
|
||||
error = true;
|
||||
|
||||
@@ -57,8 +57,8 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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:
|
||||
|
||||
@@ -32,7 +32,6 @@ const int SCROLLING_FLOOR = 2; // minimum pixels for scrolling to stop
|
||||
|
||||
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 @@ int GUIScrollList::Render(void)
|
||||
}
|
||||
|
||||
// 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 @@ void GUIScrollList::RenderStdItem(int yPos, bool selected, ImageResource* icon,
|
||||
}
|
||||
|
||||
// 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 @@ void GUIScrollList::SetPageFocus(int inFocus)
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ extern "C" {
|
||||
|
||||
GUISlider::GUISlider(xml_node<>* node) : GUIObject(node)
|
||||
{
|
||||
xml_attribute<>* attr;
|
||||
xml_node<>* child;
|
||||
|
||||
sAction = NULL;
|
||||
@@ -84,8 +83,12 @@ GUISlider::GUISlider(xml_node<>* node) : GUIObject(node)
|
||||
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) {
|
||||
|
||||
@@ -172,7 +172,10 @@ GUISliderValue::GUISliderValue(xml_node<>* node) : GUIObject(node)
|
||||
mSliderH = LoadAttrIntScaleY(child, "sliderh", mSliderH);
|
||||
}
|
||||
|
||||
mFontHeight = mFont->GetHeight();
|
||||
if (mFont && mFont->GetResource())
|
||||
mFontHeight = mFont->GetHeight();
|
||||
else
|
||||
mFontHeight = 0;
|
||||
|
||||
if (mShowCurr)
|
||||
{
|
||||
|
||||
@@ -861,9 +861,12 @@ size_t GUITerminal::GetItemCount()
|
||||
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::RenderItem(size_t itemindex, int yPos, bool selected)
|
||||
}
|
||||
}
|
||||
|
||||
void GUITerminal::NotifySelect(size_t item_selected)
|
||||
void GUITerminal::NotifySelect(size_t item_selected __unused)
|
||||
{
|
||||
// do nothing - terminal ignores selections
|
||||
}
|
||||
@@ -897,8 +900,10 @@ void GUITerminal::InitAndResize()
|
||||
// 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)
|
||||
|
||||
@@ -64,7 +64,7 @@ GUIText::GUIText(xml_node<>* node)
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -81,6 +81,9 @@ size_t GUITextBox::GetItemCount()
|
||||
|
||||
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);
|
||||
|
||||
|
||||
29
install.cpp
29
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 @@ static int check_newer_ab_build(ZipArchiveHandle zip) {
|
||||
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 @@ int update_binary_command(const std::string& package, ZipArchiveHandle zip,
|
||||
|
||||
*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 @@ static int try_update_binary(const std::string& package, ZipArchiveHandle zip, b
|
||||
if (ret) {
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -363,6 +374,7 @@ static int try_update_binary(const std::string& package, ZipArchiveHandle zip, b
|
||||
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 @@ static int really_install_package(const std::string& path, bool* wipe_cache, boo
|
||||
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 @@ int install_package(const std::string& path, bool* wipe_cache, const std::string
|
||||
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";
|
||||
|
||||
@@ -75,7 +75,7 @@ bool read_metadata_from_package(ZipWrap* zip, std::string* meta_data) {
|
||||
}
|
||||
|
||||
// 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 @@ static void read_source_target_build(ZipWrap* zip, std::vector<std::string>& log
|
||||
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 @@ static int check_newer_ab_build(ZipWrap* zip)
|
||||
}
|
||||
|
||||
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 @@ abupdate_binary_command(const char* path, ZipWrap* zip, int retry_count,
|
||||
|
||||
#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 @@ bool verify_package_compatibility(ZipWrap *zw) {
|
||||
}
|
||||
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) {
|
||||
|
||||
@@ -34,4 +34,6 @@ update_binary_command(const char* path, int retry_count,
|
||||
|
||||
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_
|
||||
|
||||
@@ -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 @@ void legacy_get_property_workspace(int *fd, int *sz)
|
||||
*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);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ include $(CLEAR_VARS)
|
||||
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 @@ include $(CLEAR_VARS)
|
||||
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 @@ include $(CLEAR_VARS)
|
||||
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 @@ include $(CLEAR_VARS)
|
||||
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 \
|
||||
|
||||
@@ -327,7 +327,7 @@ int check_mount_point(const char *device, int *mount_flags,
|
||||
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 */
|
||||
|
||||
@@ -104,6 +104,7 @@ endif
|
||||
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
|
||||
|
||||
@@ -416,8 +416,7 @@ int
|
||||
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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -357,7 +357,8 @@ th_read(TAR *t)
|
||||
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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <internal.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
@@ -227,7 +228,7 @@ tar_extract_regfile(TAR *t, const char *realname, const int *progress_fd)
|
||||
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
|
||||
|
||||
@@ -32,7 +32,7 @@ static tartype_t default_type = { open, close, read, write };
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -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 @@ LOCAL_SRC_FILES := \
|
||||
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 @@ ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 24; echo $$?),0)
|
||||
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_SRC_FILES := \
|
||||
|
||||
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 @@ ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 24; echo $$?),0)
|
||||
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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -46,8 +46,8 @@ TEST(fuse_adb_provider, read_block_adb) {
|
||||
|
||||
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 @@ TEST(fuse_adb_provider, read_block_adb_fail_write) {
|
||||
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]);
|
||||
}
|
||||
|
||||
@@ -117,26 +117,30 @@ static int create_service_thread(void (*func)(int, const std::string&), const st
|
||||
}
|
||||
#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
|
||||
|
||||
@@ -23,6 +23,7 @@ LOCAL_SRC_FILES := \
|
||||
|
||||
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)/../
|
||||
|
||||
@@ -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 @@ ifeq ($(TW_TARGET_USES_QCOM_BSP), true)
|
||||
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 @@ ifeq ($(TW_NEW_ION_HEAP), true)
|
||||
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 @@ ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26; echo $$?),0)
|
||||
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 @@ ifeq ($(wildcard system/core/healthd/animation.h),)
|
||||
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 @@ LOCAL_SHARED_LIBRARIES := \
|
||||
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)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/input.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -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_percent = OVERSCAN_PERCENT;
|
||||
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 @@ void gr_font_size(int *x, int *y)
|
||||
*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 @@ void blend_16bpp(unsigned char* px, unsigned r5, unsigned g5, unsigned b5, unsig
|
||||
*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 @@ static void text_blend(unsigned char* src_p, int src_row_bytes,
|
||||
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 @@ void gr_text(int x, int y, const char *s, bool bold)
|
||||
(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
|
||||
#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
|
||||
if (gr_draw->pixel_bytes == 2) {
|
||||
gr_convert_rgb_555();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
} 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;
|
||||
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);
|
||||
}
|
||||
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 @@ void gr_set_font(__attribute__ ((unused))const char* name) {
|
||||
}
|
||||
#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 @@ int gr_init(void)
|
||||
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 @@ void gr_exit() {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 @@ static memInfo mem_info;
|
||||
|
||||
bool MinuiBackendOverlay::target_has_overlay()
|
||||
{
|
||||
int ret;
|
||||
int mdp_version;
|
||||
bool overlay_supported = false;
|
||||
fb_fix_screeninfo fi;
|
||||
@@ -524,6 +522,7 @@ int MinuiBackendOverlay::free_overlay(int fd)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -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 @@ void gr_set_font(__attribute__ ((unused))const char* name);
|
||||
|
||||
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_alpha_surface(const char* name, GRSurface** pSurface);
|
||||
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);
|
||||
|
||||
@@ -89,11 +89,11 @@ int main() {
|
||||
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");
|
||||
|
||||
@@ -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 @@ static GRSurface* malloc_surface(size_t data_size) {
|
||||
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 @@ static void transform_rgb_to_draw(unsigned char* input_row,
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
for (int i = 0; i < *frames; ++i) {
|
||||
surface[i] = init_display_surface(width, height / *frames);
|
||||
if (surface[i] == 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;
|
||||
}
|
||||
}
|
||||
|
||||
#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_multi_display_surface(const char* name, int* frames,
|
||||
}
|
||||
|
||||
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 @@ bool matches_locale(const std::string& prefix, const std::string& locale) {
|
||||
// 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 @@ bool matches_locale(const std::string& prefix, const std::string& locale) {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ static struct pollfd ev_fds[MAX_DEVICES];
|
||||
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 @@ void ev_exit(void)
|
||||
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 @@ static int vk_inside_display(__s32 value, struct input_absinfo *info, int screen
|
||||
|
||||
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 @@ int ev_get(struct input_event *ev, int timeout_ms)
|
||||
return -2;
|
||||
}
|
||||
|
||||
int ev_wait(int timeout)
|
||||
int ev_wait(int timeout __unused)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -792,7 +792,7 @@ void ev_dispatch(void)
|
||||
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;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user