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:
Ethan Yonker
2018-08-24 11:17:36 -05:00
208 changed files with 9097 additions and 4512 deletions

View File

@@ -10,6 +10,5 @@ IndentWidth: 2
PointerAlignment: Left
TabWidth: 2
UseTab: Never
PenaltyExcessCharacter: 32
Cpp11BracedListStyle: false

View File

@@ -1,4 +1,8 @@
subdirs = [
// "bootloader_message",
// "applypatch",
"bootloader_message",
// "edify",
// "otafault",
// "otautil",
// "uncrypt",
]

View File

@@ -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
View File

@@ -1,3 +1,3 @@
enh+aosp-gerrit@google.com
enh@google.com
tbao@google.com
xunchang@google.com

6
PREUPLOAD.cfg Normal file
View 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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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
View 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,
},
},
}

View File

@@ -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 $@ $^

View File

@@ -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, &copy_file) < 0) {
if (LoadFileContents(CacheLocation::location().cache_temp_source().c_str(), &copy_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;

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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 := \

View File

@@ -17,7 +17,10 @@
cc_library_static {
name: "libbootloader_message",
srcs: ["bootloader_message.cpp"],
cppflags: ["-Werror"],
cflags: [
"-Wall",
"-Werror",
],
static_libs: [
"libbase",
"libfs_mgr",

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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;

View File

@@ -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);

View File

@@ -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]) ==

View File

@@ -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

View File

@@ -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
View 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",
],
}

View File

@@ -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;
}

View File

@@ -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) {}

View File

@@ -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 {

View File

@@ -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
%%

View File

@@ -25,7 +25,7 @@
#include <android-base/macros.h>
#include "expr.h"
#include "edify/expr.h"
#include "yydefs.h"
#include "parser.h"

View File

@@ -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

View File

@@ -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 \

View File

@@ -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 \

View File

@@ -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

View File

@@ -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;

View File

@@ -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 \

View File

@@ -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

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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
View 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
View 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

View File

@@ -13,5 +13,7 @@ LOCAL_SRC_FILES = \
gpt.c \
gptcrc32.c
LOCAL_CFLAGS := -Wno-format
LOCAL_SHARED_LIBRARIES := libc
include $(BUILD_SHARED_LIBRARY)

View File

@@ -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)

View File

@@ -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>

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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);
}

View File

@@ -42,7 +42,7 @@
#ifdef USE_MINZIP
#include "../minzip/SysUtil.h"
#else
#include "../otautil/SysUtil.h"
#include <otautil/SysUtil.h>
#endif
extern "C" {

View File

@@ -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");

View File

@@ -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);
}
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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:

View File

@@ -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

View File

@@ -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) {

View File

@@ -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)
{

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);

View File

@@ -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";

View File

@@ -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) {

View File

@@ -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_

View File

@@ -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);
}

View File

@@ -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 \

View File

@@ -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 */

View File

@@ -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

View File

@@ -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)

View File

@@ -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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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]);
}

View File

@@ -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

View File

@@ -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)/../

View File

@@ -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)

View File

@@ -15,6 +15,7 @@
*/
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <stdio.h>

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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");

View File

@@ -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);
}

View File

@@ -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