merge from open-source master
diff --git a/buildspec.mk.default b/buildspec.mk.default
index 861bb0d..6fd93da 100644
--- a/buildspec.mk.default
+++ b/buildspec.mk.default
@@ -88,10 +88,16 @@
#NO_FALLBACK_FONT:=true
endif
-# To enabled instrumentation in webcore based apps like gmail and
+# To enable instrumentation in webcore based apps like gmail and
# the browser, define WEBCORE_INSTRUMENTATION:=true
+ifndef WEBCORE_INSTRUMENTATION
#WEBCORE_INSTRUMENTATION:=true
-#endif
+endif
+
+# To enable SVG in webcore define ENABLE_SVG:=true
+ifndef ENABLE_SVG
+#ENABLE_SVG:=true
+endif
# when the build system changes such that this file must be updated, this
# variable will be changed. After you have modified this file with the new
diff --git a/cleanspec.mk b/cleanspec.mk
index c244c46..26f8e0c 100644
--- a/cleanspec.mk
+++ b/cleanspec.mk
@@ -18,7 +18,7 @@
# WHEN DOING SO, DELETE ANY "add-clean-step" ENTRIES THAT HAVE PILED UP.
# **********************************************************************
#
-INTERNAL_CLEAN_BUILD_VERSION := 2
+INTERNAL_CLEAN_BUILD_VERSION := 3
#
# ***********************************************************************
# Do not touch INTERNAL_CLEAN_BUILD_VERSION if you've added a clean step!
@@ -31,7 +31,7 @@
#
# E.g.:
# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
-# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/external/zlib/)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
#
# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
# files that are missing or have been moved.
@@ -54,38 +54,25 @@
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
-
-$(call add-clean-step, rm -f $(PRODUCT_OUT)/system/etc/NOTICE.html)
-# Remove generated java files after CL 126153
-$(call add-clean-step, find $(OUT_DIR) -type f -name "*.java" -print0 | xargs -0 rm -f)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/product/sapphire/obj/SHARED_LIBRARIES/libhardware_legacy_intermediates/led)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/mountd)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/mountd.conf)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Browser_intermediates)
-$(call add-clean-step, rm -f vendor/google/apps/Talk/res/drawable/%*)
-$(call add-clean-step, rm -rf $(OUT_DIR)/product/*/obj/SHARED_LIBRARIES/libandroid_runtime_intermediates/android_os_NetStat.o)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/product/*/obj/SHARED_LIBRARIES/libjni_andpyime_intermediates)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/product/*/obj/SHARED_LIBRARIES/share)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/product/*/obj/SHARED_LIBRARIES/libwebcore_intermediates)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/PinyinIME_intermediates)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/com.android.inputmethod.pinyin.lib_intermediates)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/PinyinIMEGoogleService_intermediates)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/com.android.inputmethod.pinyin.lib_intermediates)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/PinyinIMEGoogleService_intermediates)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/product/*/obj)
-$(call add-clean-step, rm -f $(PRODUCT_OUT)/system/bin/tcpdump)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/location)
-
-$(call add-clean-step, rm -rf $(OUT_DIR)/product/*/obj/SHARED_LIBRARIES/lib?camera_intermediates)
-$(call add-clean-step, rm -rf $(OUT_DIR)/product/*/obj/STATIC_LIBRARIES/lib?camera_intermediates)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/product/*/obj/SHARED_LIBRARIES/libwebcore_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libwebcore_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libwebcore_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libwebcore_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libwebcore_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/com.google.android.datamessaging_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/product/sholes/obj/SHARED_LIBRARIES/libhardware_legacy_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/pvasflocal.cfg)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/product/sholes)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libwebcore_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libwebcore_intermediates)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/ringtones/Silence.ogg)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/ringtones/notifications/Silence.ogg)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/product/passion/obj/SHARED_LIBRARIES/libhardware_legacy_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/com.google.android.datamessaging_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libcrypto_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libssl_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/openssl_intermediates)
+
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
diff --git a/core/Makefile b/core/Makefile
index 9247c75..307a217 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -118,6 +118,7 @@
PRODUCT_BRAND="$(PRODUCT_BRAND)" \
PRODUCT_DEFAULT_LANGUAGE="$(call default-locale-language,$(PRODUCT_LOCALES))" \
PRODUCT_DEFAULT_REGION="$(call default-locale-region,$(PRODUCT_LOCALES))" \
+ PRODUCT_DEFAULT_WIFI_CHANNELS="$(PRODUCT_DEFAULT_WIFI_CHANNELS)" \
PRODUCT_MODEL="$(PRODUCT_MODEL)" \
PRODUCT_MANUFACTURER="$(PRODUCT_MANUFACTURER)" \
PRIVATE_BUILD_DESC="$(PRIVATE_BUILD_DESC)" \
@@ -842,6 +843,9 @@
ifdef BOARD_KERNEL_CMDLINE
$(hide) echo "$(BOARD_KERNEL_CMDLINE)" > $(zip_root)/RECOVERY/cmdline
endif
+ifdef BOARD_KERNEL_BASE
+ $(hide) echo "$(BOARD_KERNEL_BASE)" > $(zip_root)/RECOVERY/base
+endif
@# Components of the boot image
$(hide) mkdir -p $(zip_root)/BOOT
$(hide) $(call package_files-copy-root, \
@@ -856,11 +860,12 @@
ifdef BOARD_KERNEL_CMDLINE
$(hide) echo "$(BOARD_KERNEL_CMDLINE)" > $(zip_root)/BOOT/cmdline
endif
-ifdef INSTALLED_RADIOIMAGE_TARGET
- @# The radio image
- $(hide) mkdir -p $(zip_root)/RADIO
- $(hide) $(ACP) $(INSTALLED_RADIOIMAGE_TARGET) $(zip_root)/RADIO/image
+ifdef BOARD_KERNEL_BASE
+ $(hide) echo "$(BOARD_KERNEL_BASE)" > $(zip_root)/BOOT/base
endif
+ $(hide) $(foreach t,$(INSTALLED_RADIOIMAGE_TARGET),\
+ mkdir -p $(zip_root)/RADIO; \
+ $(ACP) $(t) $(zip_root)/RADIO/$(notdir $(t));)
@# Contents of the system image
$(hide) $(call package_files-copy-root, \
$(SYSTEMIMAGE_SOURCE_DIR),$(zip_root)/SYSTEM)
@@ -904,9 +909,24 @@
$(INTERNAL_OTA_PACKAGE_TARGET): KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR)
+ifeq ($(TARGET_RELEASETOOLS_EXTENSIONS),)
+# default to common dir for device vendor
+$(INTERNAL_OTA_PACKAGE_TARGET): extensions := $(TARGET_DEVICE_DIR)/../common
+else
+$(INTERNAL_OTA_PACKAGE_TARGET): extensions := $(TARGET_RELEASETOOLS_EXTENSIONS)
+endif
+
+ifeq ($(TARGET_OTA_SCRIPT_MODE),)
+# default to "auto"
+$(INTERNAL_OTA_PACKAGE_TARGET): scriptmode := auto
+else
+$(INTERNAL_OTA_PACKAGE_TARGET): scriptmode := $(TARGET_OTA_SCRIPT_MODE)
+endif
+
$(INTERNAL_OTA_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) otatools
@echo "Package OTA: $@"
$(hide) ./build/tools/releasetools/ota_from_target_files \
+ -s $(extensions) -m $(scriptmode) \
-p $(HOST_OUT) \
-k $(KEY_CERT_PAIR) \
$(BUILT_TARGET_FILES_PACKAGE) $@
@@ -1030,9 +1050,17 @@
INTERNAL_UPDATE_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip
+ifeq ($(TARGET_RELEASETOOLS_EXTENSIONS),)
+# default to common dir for device vendor
+$(INTERNAL_UPDATE_PACKAGE_TARGET): extensions := $(TARGET_DEVICE_DIR)/../common
+else
+$(INTERNAL_UPDATE_PACKAGE_TARGET): extensions := $(TARGET_RELEASETOOLS_EXTENSIONS)
+endif
+
$(INTERNAL_UPDATE_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) otatools
@echo "Package: $@"
$(hide) ./build/tools/releasetools/img_from_target_files \
+ -s $(extensions) \
-p $(HOST_OUT) \
$(BUILT_TARGET_FILES_PACKAGE) $@
diff --git a/core/base_rules.mk b/core/base_rules.mk
index a6bf504..82c7dec 100644
--- a/core/base_rules.mk
+++ b/core/base_rules.mk
@@ -350,7 +350,6 @@
$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_POST_PROCESS_COMMAND:= $(LOCAL_POST_PROCESS_COMMAND)
$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_AAPT_FLAGS:= $(LOCAL_AAPT_FLAGS)
$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_JAVA_LIBRARIES:= $(LOCAL_JAVA_LIBRARIES)
-#TODO: add this: $(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_ADDITIONAL_DEPENDENCIES:= $(LOCAL_ADDITIONAL_DEPENDENCIES)
$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_ALL_JAVA_LIBRARIES:= $(full_java_libs)
$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_IS_HOST_MODULE := $(LOCAL_IS_HOST_MODULE)
diff --git a/core/binary.mk b/core/binary.mk
index ddcdc6f..4413d47 100644
--- a/core/binary.mk
+++ b/core/binary.mk
@@ -87,7 +87,7 @@
ifneq ($(strip $(yacc_cpps)),)
$(yacc_cpps): $(intermediates)/%$(LOCAL_CPP_EXTENSION): \
$(TOPDIR)$(LOCAL_PATH)/%.y \
- $(lex_cpps) $(PRIVATE_ADDITIONAL_DEPENDENCIES)
+ $(lex_cpps) $(LOCAL_ADDITIONAL_DEPENDENCIES)
$(call transform-y-to-cpp,$(PRIVATE_CPP_EXTENSION))
$(yacc_headers): $(intermediates)/%.h: $(intermediates)/%$(LOCAL_CPP_EXTENSION)
@@ -115,7 +115,7 @@
$(lex_objects): PRIVATE_ARM_CFLAGS := $(normal_objects_cflags)
$(lex_objects): $(intermediates)/%.o: \
$(intermediates)/%$(LOCAL_CPP_EXTENSION) \
- $(PRIVATE_ADDITIONAL_DEPENDENCIES) \
+ $(LOCAL_ADDITIONAL_DEPENDENCIES) \
$(yacc_headers)
$(transform-$(PRIVATE_HOST)cpp-to-o)
endif
@@ -142,7 +142,7 @@
ifneq ($(strip $(cpp_objects)),)
$(cpp_objects): $(intermediates)/%.o: \
$(TOPDIR)$(LOCAL_PATH)/%$(LOCAL_CPP_EXTENSION) \
- $(yacc_cpps) $(PRIVATE_ADDITIONAL_DEPENDENCIES)
+ $(yacc_cpps) $(LOCAL_ADDITIONAL_DEPENDENCIES)
$(transform-$(PRIVATE_HOST)cpp-to-o)
-include $(cpp_objects:%.o=%.P)
endif
@@ -159,7 +159,7 @@
# TODO: support compiling certain generated files as arm.
$(gen_cpp_objects): PRIVATE_ARM_MODE := $(normal_objects_mode)
$(gen_cpp_objects): PRIVATE_ARM_CFLAGS := $(normal_objects_cflags)
-$(gen_cpp_objects): $(intermediates)/%.o: $(intermediates)/%$(LOCAL_CPP_EXTENSION) $(yacc_cpps) $(PRIVATE_ADDITIONAL_DEPENDENCIES)
+$(gen_cpp_objects): $(intermediates)/%.o: $(intermediates)/%$(LOCAL_CPP_EXTENSION) $(yacc_cpps) $(LOCAL_ADDITIONAL_DEPENDENCIES)
$(transform-$(PRIVATE_HOST)cpp-to-o)
-include $(gen_cpp_objects:%.o=%.P)
endif
@@ -172,7 +172,7 @@
gen_S_objects := $(gen_S_sources:%.S=%.o)
ifneq ($(strip $(gen_S_sources)),)
-$(gen_S_objects): $(intermediates)/%.o: $(intermediates)/%.S $(PRIVATE_ADDITIONAL_DEPENDENCIES)
+$(gen_S_objects): $(intermediates)/%.o: $(intermediates)/%.S $(LOCAL_ADDITIONAL_DEPENDENCIES)
$(transform-$(PRIVATE_HOST)s-to-o)
-include $(gen_S_objects:%.o=%.P)
endif
@@ -181,7 +181,7 @@
gen_s_objects := $(gen_s_sources:%.s=%.o)
ifneq ($(strip $(gen_s_objects)),)
-$(gen_s_objects): $(intermediates)/%.o: $(intermediates)/%.s $(PRIVATE_ADDITIONAL_DEPENDENCIES)
+$(gen_s_objects): $(intermediates)/%.o: $(intermediates)/%.s $(LOCAL_ADDITIONAL_DEPENDENCIES)
$(transform-$(PRIVATE_HOST)s-to-o-no-deps)
-include $(gen_s_objects:%.o=%.P)
endif
@@ -206,12 +206,29 @@
c_objects := $(c_arm_objects) $(c_normal_objects)
ifneq ($(strip $(c_objects)),)
-$(c_objects): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.c $(yacc_cpps) $(PRIVATE_ADDITIONAL_DEPENDENCIES)
+$(c_objects): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.c $(yacc_cpps) $(LOCAL_ADDITIONAL_DEPENDENCIES)
$(transform-$(PRIVATE_HOST)c-to-o)
-include $(c_objects:%.o=%.P)
endif
###########################################################
+## C: Compile generated .c files to .o.
+###########################################################
+
+gen_c_sources := $(filter %.c,$(LOCAL_GENERATED_SOURCES))
+gen_c_objects := $(gen_c_sources:%.c=%.o)
+
+ifneq ($(strip $(gen_c_objects)),)
+# Compile all generated files as thumb.
+# TODO: support compiling certain generated files as arm.
+$(gen_c_objects): PRIVATE_ARM_MODE := $(normal_objects_mode)
+$(gen_c_objects): PRIVATE_ARM_CFLAGS := $(normal_objects_cflags)
+$(gen_c_objects): $(intermediates)/%.o: $(intermediates)/%.c $(yacc_cpps) $(LOCAL_ADDITIONAL_DEPENDENCIES)
+ $(transform-$(PRIVATE_HOST)c-to-o)
+-include $(gen_c_objects:%.o=%.P)
+endif
+
+###########################################################
## ObjC: Compile .m files to .o
###########################################################
@@ -232,7 +249,7 @@
asm_objects_S := $(addprefix $(intermediates)/,$(asm_sources_S:.S=.o))
ifneq ($(strip $(asm_objects_S)),)
-$(asm_objects_S): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.S $(PRIVATE_ADDITIONAL_DEPENDENCIES)
+$(asm_objects_S): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.S $(LOCAL_ADDITIONAL_DEPENDENCIES)
$(transform-$(PRIVATE_HOST)s-to-o)
-include $(asm_objects_S:%.o=%.P)
endif
@@ -241,7 +258,7 @@
asm_objects_s := $(addprefix $(intermediates)/,$(asm_sources_s:.s=.o))
ifneq ($(strip $(asm_objects_s)),)
-$(asm_objects_s): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.s $(PRIVATE_ADDITIONAL_DEPENDENCIES)
+$(asm_objects_s): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.s $(LOCAL_ADDITIONAL_DEPENDENCIES)
$(transform-$(PRIVATE_HOST)s-to-o-no-deps)
-include $(asm_objects_s:%.o=%.P)
endif
@@ -261,6 +278,7 @@
$(gen_cpp_objects) \
$(gen_asm_objects) \
$(c_objects) \
+ $(gen_c_objects) \
$(yacc_objects) \
$(lex_objects) \
$(addprefix $(TOPDIR)$(LOCAL_PATH)/,$(LOCAL_PREBUILT_OBJ_FILES))
diff --git a/core/build_id.mk b/core/build_id.mk
index 060c9b5..40bb35d 100644
--- a/core/build_id.mk
+++ b/core/build_id.mk
@@ -23,7 +23,7 @@
# (like "TC1-RC5"). It must be a single word, and is
# capitalized by convention.
#
-BUILD_ID := Donut
+BUILD_ID := MASTER
# DISPLAY_BUILD_NUMBER should only be set for development branches,
# If set, the BUILD_NUMBER (cl) is appended to the BUILD_ID for
diff --git a/core/combo/arch/arm/armv4t.mk b/core/combo/arch/arm/armv4t.mk
new file mode 100644
index 0000000..abc8fa2
--- /dev/null
+++ b/core/combo/arch/arm/armv4t.mk
@@ -0,0 +1,23 @@
+# Configuration for Linux on ARM.
+# Generating binaries for the ARMv4T architecture and higher
+#
+# Supporting armv4 (without thumb) does not make much sense since
+# it's mostly an obsoleted instruction set architecture (only available
+# in StrongArm and arm8). Supporting armv4 will require a lot of conditional
+# code in assembler source since the bx (branch and exchange) instruction is
+# not supported.
+#
+$(warning ARMv4t support is currently a work in progress. It does not work right now!)
+ARCH_ARM_HAVE_THUMB_SUPPORT := false
+ARCH_ARM_HAVE_THUMB_INTERWORKING := false
+ARCH_ARM_HAVE_64BIT_DATA := false
+ARCH_ARM_HAVE_HALFWORD_MULTIPLY := false
+ARCH_ARM_HAVE_CLZ := false
+ARCH_ARM_HAVE_FFS := false
+
+DEFAULT_TARGET_CPU := arm920t
+
+# Note: Hard coding the 'tune' value here is probably not ideal,
+# and a better solution should be found in the future.
+#
+arch_variant_cflags := -march=armv4t -mtune=arm920t -D__ARM_ARCH_4T__
diff --git a/core/combo/arch/arm/armv5te-vfp.mk b/core/combo/arch/arm/armv5te-vfp.mk
new file mode 100644
index 0000000..75299ac
--- /dev/null
+++ b/core/combo/arch/arm/armv5te-vfp.mk
@@ -0,0 +1,7 @@
+# At the moment, use the same settings than the one
+# for armv5te, since TARGET_ARCH_VARIANT := armv5te-vfp
+# will only be used to select an optimized VFP-capable assembly
+# interpreter loop for Dalvik.
+#
+include $(BUILD_COMBOS)/arch/arm/armv5te.mk
+
diff --git a/core/combo/arch/arm/armv5te.mk b/core/combo/arch/arm/armv5te.mk
new file mode 100644
index 0000000..29aada6
--- /dev/null
+++ b/core/combo/arch/arm/armv5te.mk
@@ -0,0 +1,21 @@
+# Configuration for Linux on ARM.
+# Generating binaries for the ARMv5TE architecture and higher
+#
+ARCH_ARM_HAVE_THUMB_SUPPORT := true
+ARCH_ARM_HAVE_FAST_INTERWORKING := true
+ARCH_ARM_HAVE_64BIT_DATA := true
+ARCH_ARM_HAVE_HALFWORD_MULTIPLY := true
+ARCH_ARM_HAVE_CLZ := true
+ARCH_ARM_HAVE_FFS := true
+
+# Note: Hard coding the 'tune' value here is probably not ideal,
+# and a better solution should be found in the future.
+#
+arch_variant_cflags := \
+ -march=armv5te \
+ -mtune=xscale \
+ -D__ARM_ARCH_5__ \
+ -D__ARM_ARCH_5T__ \
+ -D__ARM_ARCH_5E__ \
+ -D__ARM_ARCH_5TE__
+
diff --git a/core/combo/arch/arm/armv7-a.mk b/core/combo/arch/arm/armv7-a.mk
new file mode 100644
index 0000000..7a3ecc4
--- /dev/null
+++ b/core/combo/arch/arm/armv7-a.mk
@@ -0,0 +1,22 @@
+# Configuration for Linux on ARM.
+# Generating binaries for the ARMv7-a architecture and higher
+#
+ARCH_ARM_HAVE_THUMB_SUPPORT := true
+ARCH_ARM_HAVE_FAST_INTERWORKING := true
+ARCH_ARM_HAVE_64BIT_DATA := true
+ARCH_ARM_HAVE_HALFWORD_MULTIPLY := true
+ARCH_ARM_HAVE_CLZ := true
+ARCH_ARM_HAVE_FFS := true
+ARCH_ARM_HAVE_VFP := true
+ARCH_ARM_HAVE_NEON := true
+
+# Note: Hard coding the 'tune' value here is probably not ideal,
+# and a better solution should be found in the future.
+#
+arch_variant_cflags := \
+ -march=armv7-a \
+ -mfloat-abi=softfp \
+ -mfpu=neon
+
+arch_variant_ldflags := \
+ -Wl,--fix-cortex-a8
\ No newline at end of file
diff --git a/core/combo/linux-arm.mk b/core/combo/linux-arm.mk
index 11a8ac7..6011351 100644
--- a/core/combo/linux-arm.mk
+++ b/core/combo/linux-arm.mk
@@ -1,68 +1,44 @@
# Configuration for Linux on ARM.
# Included by combo/select.make
-# You can set TARGET_ARCH_VERSION to use an arch version other
-# than ARMv5TE
-ifeq ($(strip $(TARGET_ARCH_VERSION)),)
-TARGET_ARCH_VERSION := armv5te
-endif
-
-# This set of if blocks sets makefile variables similar to preprocesser
+# You can set TARGET_ARCH_VARIANT to use an arch version other
+# than ARMv5TE. Each value should correspond to a file named
+# $(BUILD_COMBOS)/arch/<name>.mk which must contain
+# makefile variable definitions similar to the preprocessor
# defines in system/core/include/arch/<combo>/AndroidConfig.h. Their
-# purpose is to allow module Android.mk files to selctively compile
-# different versions of code based upon the funtionality and
+# purpose is to allow module Android.mk files to selectively compile
+# different versions of code based upon the funtionality and
# instructions available in a given architecture version.
#
-# The blocks also define specific arch_version_cflags, which
+# The blocks also define specific arch_variant_cflags, which
# include defines, and compiler settings for the given architecture
# version.
#
-# Note: Hard coding the 'tune' value here is probably not ideal,
-# and a better solution should be found in the future.
-#
-# With two or three different versions this if block approach is
-# fine. If/when this becomes large, please change this to include
-# architecture versions specific Makefiles which define these
-# variables.
-#
-# Supporting armv4 (without thumb) does not make much sense since
-# it's mostly an obsoleted instruction set architecture (only available
-# in StrongArm and arm8). Supporting armv4 will require a lot of conditional
-# code in assembler source since the bx (branch and exchange) instruction is
-# not supported.
-#
-ifeq ($(TARGET_ARCH_VERSION),armv5te)
-ARCH_ARM_HAVE_THUMB_SUPPORT := true
-ARCH_ARM_HAVE_FAST_INTERWORKING := true
-ARCH_ARM_HAVE_64BIT_DATA := true
-ARCH_ARM_HAVE_HALFWORD_MULTIPLY := true
-ARCH_ARM_HAVE_CLZ := true
-ARCH_ARM_HAVE_FFS := true
-
-arch_version_cflags := -march=armv5te -mtune=xscale -D__ARM_ARCH_5__ \
- -D__ARM_ARCH_5T__ -D__ARM_ARCH_5TE__
-else
-ifeq ($(TARGET_ARCH_VERSION),armv4t)
-$(warning ARMv4t support is currently a work in progress. It does not work right now!)
-ARCH_ARM_HAVE_THUMB_SUPPORT := false
-ARCH_ARM_HAVE_THUMB_INTERWORKING := false
-ARCH_ARM_HAVE_64BIT_DATA := false
-ARCH_ARM_HAVE_HALFWORD_MULTIPLY := false
-ARCH_ARM_HAVE_CLZ := false
-ARCH_ARM_HAVE_FFS := false
-
-DEFAULT_TARGET_CPU := arm920t
-
-arch_version_cflags := -march=armv4t -mtune=arm920t -D__ARM_ARCH_4T__
-else
-$(error Unknown ARM architecture version: $(TARGET_ARCH_VERSION))
+ifeq ($(strip $(TARGET_ARCH_VARIANT)),)
+TARGET_ARCH_VARIANT := armv5te
endif
+
+# TARGET_ARCH_VARIANT used to be called TARGET_ARCH_VERSION
+# to avoid any weirdness, issue an error message if the latter
+# is defined.
+#
+ifneq ($(strip $(TARGET_ARCH_VERSION)),)
+$(info Definition for TARGET_ARCH_VERSION encountered !)
+$(info This variable has been renamed TARGET_ARCH_VARIANT, please update your build files !!)
+$(error Aborting the build.)
endif
+TARGET_ARCH_SPECIFIC_MAKEFILE := $(BUILD_COMBOS)/arch/$(TARGET_ARCH)/$(TARGET_ARCH_VARIANT).mk
+ifeq ($(strip $(wildcard $(TARGET_ARCH_SPECIFIC_MAKEFILE))),)
+$(error Unknown ARM architecture version: $(TARGET_ARCH_VARIANT))
+endif
+
+include $(TARGET_ARCH_SPECIFIC_MAKEFILE)
+
# You can set TARGET_TOOLS_PREFIX to get gcc from somewhere else
ifeq ($(strip $($(combo_target)TOOLS_PREFIX)),)
$(combo_target)TOOLS_PREFIX := \
- prebuilt/$(HOST_PREBUILT_TAG)/toolchain/arm-eabi-4.2.1/bin/arm-eabi-
+ prebuilt/$(HOST_PREBUILT_TAG)/toolchain/arm-eabi-4.4.0/bin/arm-eabi-
endif
$(combo_target)CC := $($(combo_target)TOOLS_PREFIX)gcc$(HOST_EXECUTABLE_SUFFIX)
@@ -79,7 +55,7 @@
-funswitch-loops \
-finline-limit=300
-# Modules can choose to compile some source as thumb. As
+# Modules can choose to compile some source as thumb. As
# non-thumb enabled targets are supported, this is treated
# as a 'hint'. If thumb is not enabled, these files are just
# compiled as ARM.
@@ -103,7 +79,7 @@
# with -mlong-calls. When built at -O0, those libraries are
# too big for a thumb "BL <label>" to go from one end to the other.
ifeq ($(FORCE_ARM_DEBUGGING),true)
- TARGET_arm_CFLAGS += -fno-omit-frame-pointer
+ TARGET_arm_CFLAGS += -fno-omit-frame-pointer -fno-strict-aliasing
TARGET_thumb_CFLAGS += -marm -fno-omit-frame-pointer
endif
@@ -116,10 +92,13 @@
-funwind-tables \
-fstack-protector \
-fno-short-enums \
- $(arch_version_cflags) \
+ $(arch_variant_cflags) \
-include $(android_config_h) \
-I $(arch_include_dir)
+$(combo_target)GLOBAL_LDFLAGS += \
+ $(arch_variant_ldflags)
+
# We only need thumb interworking in cases where thumb support
# is available in the architecture, and just to be sure, (and
# since sometimes thumb-interwork appears to be default), we
@@ -150,7 +129,7 @@
## on some hosts, the target cross-compiler is not available so do not run this command
ifneq ($(wildcard $($(combo_target)CC)),)
-# We compile with the global cflags to ensure that
+# We compile with the global cflags to ensure that
# any flags which affect libgcc are correctly taken
# into account.
$(combo_target)LIBGCC := $(shell $($(combo_target)CC) $($(combo_target)GLOBAL_CFLAGS) -print-libgcc-file-name)
@@ -201,6 +180,7 @@
$(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
-o $@ \
$(PRIVATE_LDFLAGS) \
+ $(TARGET_GLOBAL_LDFLAGS) \
$(TARGET_LIBGCC)
endef
@@ -217,6 +197,7 @@
$(PRIVATE_ALL_OBJECTS) \
$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
$(PRIVATE_LDFLAGS) \
+ $(TARGET_GLOBAL_LDFLAGS) \
$(TARGET_LIBGCC) \
$(TARGET_CRTEND_O)
endef
@@ -228,6 +209,7 @@
$(TARGET_GLOBAL_LD_DIRS) \
$(TARGET_CRTBEGIN_STATIC_O) \
$(PRIVATE_LDFLAGS) \
+ $(TARGET_GLOBAL_LDFLAGS) \
$(PRIVATE_ALL_OBJECTS) \
$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
$(TARGET_LIBGCC) \
diff --git a/core/combo/select.mk b/core/combo/select.mk
index 273b660..793b0a9 100644
--- a/core/combo/select.mk
+++ b/core/combo/select.mk
@@ -39,6 +39,7 @@
# These flags might (will) be overridden by the target makefiles
$(combo_target)GLOBAL_CFLAGS := -fno-exceptions -Wno-multichar
$(combo_target)RELEASE_CFLAGS := -O2 -g -fno-strict-aliasing
+$(combo_target)GLOBAL_LDFLAGS :=
$(combo_target)GLOBAL_ARFLAGS := crs
$(combo_target)EXECUTABLE_SUFFIX :=
diff --git a/core/config.mk b/core/config.mk
index b705de5..ec4c3ac 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -75,11 +75,11 @@
# ###############################################################
# These can be changed to modify both host and device modules.
-COMMON_GLOBAL_CFLAGS:= -DANDROID -fmessage-length=0 -W -Wall -Wno-unused
+COMMON_GLOBAL_CFLAGS:= -DANDROID -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith
COMMON_RELEASE_CFLAGS:= -DNDEBUG -UDEBUG
-COMMON_GLOBAL_CPPFLAGS:= -DANDROID -fmessage-length=0 -W -Wall -Wno-unused -Wnon-virtual-dtor
-COMMON_RELEASE_CPPFLAGS:= -DNDEBUG -UDEBUG
+COMMON_GLOBAL_CPPFLAGS:= $(COMMON_GLOBAL_CFLAGS) -Wsign-promo -Wctor-dtor-privacy
+COMMON_RELEASE_CPPFLAGS:= $(COMMON_RELEASE_CFLAGS)
# Set the extensions used for various packages
COMMON_PACKAGE_SUFFIX := .zip
@@ -87,7 +87,13 @@
COMMON_ANDROID_PACKAGE_SUFFIX := .apk
# list of flags to turn specific warnings in to errors
-TARGET_ERROR_FLAGS := -Werror=return-type
+TARGET_ERROR_FLAGS := -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point
+
+# TODO: do symbol compression
+TARGET_COMPRESS_MODULE_SYMBOLS := false
+
+# Default is to prelink modules.
+TARGET_PRELINK_MODULE := true
# ###############################################################
# Include sub-configuration files
@@ -105,6 +111,32 @@
# are specific to the user's build configuration.
include $(BUILD_SYSTEM)/envsetup.mk
+# Boards may be defined under $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)
+# or under vendor/*/$(TARGET_DEVICE). Search in both places, but
+# make sure only one exists.
+# Real boards should always be associated with an OEM vendor.
+board_config_mk := \
+ $(strip $(wildcard \
+ $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \
+ vendor/*/$(TARGET_DEVICE)/BoardConfig.mk \
+ ))
+ifeq ($(board_config_mk),)
+ $(error No config file found for TARGET_DEVICE $(TARGET_DEVICE))
+endif
+ifneq ($(words $(board_config_mk)),1)
+ $(error Multiple board config files for TARGET_DEVICE $(TARGET_DEVICE): $(board_config_mk))
+endif
+include $(board_config_mk)
+TARGET_DEVICE_DIR := $(patsubst %/,%,$(dir $(board_config_mk)))
+board_config_mk :=
+
+# Clean up/verify variables defined by the board config file.
+TARGET_BOOTLOADER_BOARD_NAME := $(strip $(TARGET_BOOTLOADER_BOARD_NAME))
+TARGET_CPU_ABI := $(strip $(TARGET_CPU_ABI))
+ifeq ($(TARGET_CPU_ABI),)
+ $(error No TARGET_CPU_ABI defined by board config: $(board_config_mk))
+endif
+
# $(1): os/arch
define select-android-config-h
system/core/include/arch/$(1)/AndroidConfig.h
@@ -259,10 +291,6 @@
TARGET_GLOBAL_CFLAGS += $(TARGET_RELEASE_CFLAGS)
TARGET_GLOBAL_CPPFLAGS += $(TARGET_RELEASE_CPPFLAGS)
-# TODO: do symbol compression
-TARGET_COMPRESS_MODULE_SYMBOLS := false
-TARGET_PRELINK_MODULE := true
-
PREBUILT_IS_PRESENT := $(if $(wildcard prebuilt/Android.mk),true)
diff --git a/core/definitions.mk b/core/definitions.mk
index c84cbd8..b4e4b50 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -1575,6 +1575,25 @@
)
endef
+
+###########################################################
+## Define device-specific radio files
+###########################################################
+
+# Copy a radio image file to the output location, and add it to
+# INSTALLED_RADIOIMAGE_TARGET.
+# $(1): filename
+define add-radio-file
+ $(eval $(call add-radio-file-internal,$(1)))
+endef
+define add-radio-file-internal
+INSTALLED_RADIOIMAGE_TARGET += $$(PRODUCT_OUT)/$(1)
+ALL_PREBUILT += $$(PRODUCT_OUT)/$(1)
+$$(PRODUCT_OUT)/$(1) : $$(LOCAL_PATH)/$(1) | $$(ACP)
+ $$(transform-prebuilt-to-target)
+endef
+
+
###########################################################
## Other includes
###########################################################
diff --git a/core/envsetup.mk b/core/envsetup.mk
index 31901e9..0ee7cfc 100644
--- a/core/envsetup.mk
+++ b/core/envsetup.mk
@@ -270,7 +270,7 @@
ABP:=$(ABP):$(TARGET_OUT_EXECUTABLES)
else
# this should be copied to HOST_OUT_EXECUTABLES instead
- ABP:=$(ABP):$(PWD)/prebuilt/$(HOST_PREBUILT_TAG)/toolchain/arm-eabi-4.2.1/bin
+ ABP:=$(ABP):$(PWD)/prebuilt/$(HOST_PREBUILT_TAG)/toolchain/arm-eabi-4.4.0/bin
endif
ANDROID_BUILD_PATHS := $(ABP)
ANDROID_PREBUILTS := prebuilt/$(HOST_PREBUILT_TAG)
@@ -335,5 +335,3 @@
$(info BUILD_ID=$(BUILD_ID))
$(info ============================================)
endif
-
-
diff --git a/core/main.mk b/core/main.mk
index 71bbc08..482fefd 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -54,6 +54,12 @@
# be generated correctly
include $(BUILD_SYSTEM)/cleanbuild.mk
+VERSION_CHECK_SEQUENCE_NUMBER := 1
+-include $(OUT_DIR)/versions_checked.mk
+ifneq ($(VERSION_CHECK_SEQUENCE_NUMBER),$(VERSIONS_CHECKED))
+
+$(info Checking build tools versions...)
+
ifneq ($(HOST_OS),windows)
ifneq ($(HOST_OS)-$(HOST_ARCH),darwin-ppc)
# check for a case sensitive file system
@@ -123,6 +129,10 @@
endif # windows
+$(shell echo 'VERSIONS_CHECKED := $(VERSION_CHECK_SEQUENCE_NUMBER)' \
+ > $(OUT_DIR)/versions_checked.mk)
+endif
+
# These are the modifier targets that don't do anything themselves, but
# change the behavior of the build.
# (must be defined before including definitions.make)
@@ -245,6 +255,16 @@
ADDITIONAL_BUILD_PROPERTIES += ro.config.sync=yes
endif
+## precise GC ##
+
+ifneq ($(filter dalvik.gc.type-precise,$(PRODUCT_TAGS)),)
+ # Enabling type-precise GC results in larger optimized DEX files. The
+ # additional storage requirements for ".odex" files can cause /system
+ # to overflow on some devices, so this is configured separately for
+ # each product.
+ ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.dexopt-flags=m=y
+endif
+
# Install an apns-conf.xml file if one's not already being installed.
ifeq (,$(filter %:system/etc/apns-conf.xml, $(PRODUCT_COPY_FILES)))
PRODUCT_COPY_FILES += \
@@ -253,18 +273,10 @@
$(warning implicitly installing apns-conf_sdk.xml)
endif
endif
-# Install a vold.conf file is one's not already being installed.
-ifeq (,$(filter %:system/etc/vold.conf, $(PRODUCT_COPY_FILES)))
- PRODUCT_COPY_FILES += \
- development/data/etc/vold.conf:system/etc/vold.conf
- ifeq ($(filter eng tests,$(TARGET_BUILD_VARIANT)),)
- $(warning implicitly installing vold.conf)
- endif
-endif
# If we're on an eng or tests build, but not on the sdk, and we have
# a better one, use that instead.
ifneq ($(filter eng tests,$(TARGET_BUILD_VARIANT)),)
- ifdef is_sdk_build
+ ifndef is_sdk_build
apns_to_use := $(wildcard vendor/google/etc/apns-conf.xml)
ifneq ($(strip $(apns_to_use)),)
PRODUCT_COPY_FILES := \
@@ -325,8 +337,6 @@
# Bring in all modules that need to be built.
ifneq ($(dont_bother),true)
-subdir_makefiles :=
-
ifeq ($(HOST_OS),windows)
SDK_ONLY := true
endif
@@ -398,8 +408,6 @@
# TINY_ANDROID is a super-minimal build configuration, handy for board
# bringup and very low level debugging
-INTERNAL_DEFAULT_DOCS_TARGETS :=
-
subdirs := \
bionic \
system/core \
@@ -418,7 +426,6 @@
#
# Typical build; include any Android.mk files we can find.
#
-INTERNAL_DEFAULT_DOCS_TARGETS := offline-sdk-docs
subdirs := $(TOP)
FULL_BUILD := true
@@ -427,41 +434,6 @@
endif # !SDK_ONLY
-# Can't use first-makefiles-under here because
-# --mindepth=2 makes the prunes not work.
-subdir_makefiles += \
- $(shell build/tools/findleaves.sh --prune="./out" $(subdirs) Android.mk)
-
-# Boards may be defined under $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)
-# or under vendor/*/$(TARGET_DEVICE). Search in both places, but
-# make sure only one exists.
-# Real boards should always be associated with an OEM vendor.
-board_config_mk := \
- $(strip $(wildcard \
- $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \
- vendor/*/$(TARGET_DEVICE)/BoardConfig.mk \
- ))
-ifeq ($(board_config_mk),)
- $(error No config file found for TARGET_DEVICE $(TARGET_DEVICE))
-endif
-ifneq ($(words $(board_config_mk)),1)
- $(error Multiple board config files for TARGET_DEVICE $(TARGET_DEVICE): $(board_config_mk))
-endif
-include $(board_config_mk)
-TARGET_DEVICE_DIR := $(patsubst %/,%,$(dir $(board_config_mk)))
-board_config_mk :=
-
-# Clean up/verify variables defined by the board config file.
-TARGET_BOOTLOADER_BOARD_NAME := $(strip $(TARGET_BOOTLOADER_BOARD_NAME))
-TARGET_CPU_ABI := $(strip $(TARGET_CPU_ABI))
-ifeq ($(TARGET_CPU_ABI),)
- $(error No TARGET_CPU_ABI defined by board config: $(board_config_mk))
-endif
-
-#
-# Include all of the makefiles in the system
-#
-
ifneq ($(ONE_SHOT_MAKEFILE),)
# We've probably been invoked by the "mm" shell function
# with a subdirectory's makefile.
@@ -473,14 +445,25 @@
# would have been with a normal make.
CUSTOM_MODULES := $(sort $(call get-tagged-modules,$(ALL_MODULE_TAGS),))
FULL_BUILD :=
-INTERNAL_DEFAULT_DOCS_TARGETS :=
# Stub out the notice targets, which probably aren't defined
# when using ONE_SHOT_MAKEFILE.
NOTICE-HOST-%: ;
NOTICE-TARGET-%: ;
-else
+
+else # ONE_SHOT_MAKEFILE
+
+#
+# Include all of the makefiles in the system
+#
+
+# Can't use first-makefiles-under here because
+# --mindepth=2 makes the prunes not work.
+subdir_makefiles := \
+ $(shell build/tools/findleaves.sh --prune="./out" $(subdirs) Android.mk)
+
include $(subdir_makefiles)
-endif
+endif # ONE_SHOT_MAKEFILE
+
# -------------------------------------------------------------------
# All module makefiles have been included at this point.
# -------------------------------------------------------------------
@@ -681,7 +664,6 @@
$(INSTALLED_BOOTIMAGE_TARGET) \
$(INSTALLED_RECOVERYIMAGE_TARGET) \
$(INSTALLED_USERDATAIMAGE_TARGET) \
- $(INTERNAL_DEFAULT_DOCS_TARGETS) \
$(INSTALLED_FILES_FILE)
# The actual files built by the droidcore target changes depending
diff --git a/core/notice_files.mk b/core/notice_files.mk
index 24295c7..fd76d51 100644
--- a/core/notice_files.mk
+++ b/core/notice_files.mk
@@ -20,12 +20,19 @@
# We can't use xxx_OUT_STATIC_LIBRARIES because it points into
# device-obj or host-obj.
module_installed_filename := \
- $(patsubst $(PRODUCT_OUT)%,%,$($(my_prefix)OUT_SHARED_LIBRARIES))/$(notdir $(LOCAL_BUILT_MODULE))
+ $(patsubst $(PRODUCT_OUT)%,%,$($(my_prefix)OUT_SHARED_LIBRARIES))/$(notdir $(LOCAL_BUILT_MODULE))
else
ifeq ($(LOCAL_MODULE_CLASS),JAVA_LIBRARIES)
# Stick the static java libraries with the regular java libraries.
+ module_leaf := $(notdir $(LOCAL_BUILT_MODULE))
+ # javalib.jar is the default name for the build module (and isn't meaningful)
+ # If that's what we have, substitute the module name instead. These files
+ # aren't included on the device, so this name is synthetic anyway.
+ ifeq ($(module_leaf),javalib.jar)
+ module_leaf := $(LOCAL_MODULE).jar
+ endif
module_installed_filename := \
- $(patsubst $(PRODUCT_OUT)%,%,$($(my_prefix)OUT_JAVA_LIBRARIES))/$(notdir $(LOCAL_BUILT_MODULE))
+ $(patsubst $(PRODUCT_OUT)%,%,$($(my_prefix)OUT_JAVA_LIBRARIES))/$(module_leaf)
else
$(error Cannot determine where to install NOTICE file for $(LOCAL_MODULE))
endif # JAVA_LIBRARIES
diff --git a/core/pathmap.mk b/core/pathmap.mk
index e281b9d..992e3ef 100644
--- a/core/pathmap.mk
+++ b/core/pathmap.mk
@@ -28,8 +28,8 @@
#
pathmap_INCL := \
bluedroid:system/bluetooth/bluedroid/include \
- bluez-libs:external/bluez/libs/include \
- bluez-utils:external/bluez/utils \
+ bluez:external/bluetooth/bluez \
+ glib:external/bluetooth/glib \
bootloader:bootable/bootloader/legacy/include \
corecg:external/skia/include/core \
dbus:external/dbus \
diff --git a/core/prelink-linux-arm.map b/core/prelink-linux-arm.map
index 6892885..bd86397 100644
--- a/core/prelink-linux-arm.map
+++ b/core/prelink-linux-arm.map
@@ -27,7 +27,7 @@
liba2dp.so 0xAEE00000
audio.so 0xAED00000
input.so 0xAEC00000
-libhcid.so 0xAEB00000
+libbluetoothd.so 0xAEB00000
libbluedroid.so 0xAEA00000
libbluetooth.so 0xAE900000
libdbus.so 0xAE800000
@@ -50,8 +50,8 @@
# graphics
libpixelflinger.so 0xACF00000
-libcorecg.so 0xACE00000
libsurfaceflinger.so 0xACD00000
+libGLES_android.so 0xACC80000
libagl.so 0xACC00000
libGLESv1_CM.so 0xACB00000
@@ -60,15 +60,22 @@
libOpenVGU_CM.so 0xAC800000
libEGL.so 0xAC700000
+libacc.so 0xAC600000
+
libexif.so 0xAC500000
libui.so 0xAC400000
-libsgl.so 0xAC000000
+libskia.so 0xAC000000
+librs_jni.so 0xABF00000
+libRS.so 0xAB900000
+
# audio
-libspeech.so 0xAB800000
+libaudiopolicy.so 0xAB880000
+libaudiopolicygeneric.so 0xAB800000
+libsoundpool.so 0xAB780000
libaudio.so 0xAB700000
-libsonivox.so 0xAB600000
-libsoundpool.so 0xAB500000
+libspeech.so 0xAB600000
+libsonivox.so 0xAB500000
libvorbisidec.so 0xAB400000
libmedia_jni.so 0xAB300000
libmediaplayerservice.so 0xAB280000
@@ -80,6 +87,7 @@
libsqlite.so 0xAAC00000
libexpat.so 0xAAB00000
libwebcore.so 0xAA000000
+libbinder.so 0xA9D80000
libutils.so 0xA9D00000
libcameraservice.so 0xA9C80000
libhardware.so 0xA9C70000
@@ -89,13 +97,29 @@
libime.so 0xA9800000
libgps.so 0xA9700000
libcamera.so 0xA9680000
-libqcamera.so 0xA9400000
+liboemcamera.so 0xA9400000
-# pv opencore libraries
-libopencore_author.so 0xA7B00000
-libopencore_player.so 0xA7800000
-libopencore_common.so 0xA7300000
-libopencore_2way.so 0xA7000000
+# pv libraries
+libpvasf.so 0xA7C26000
+libpvasfreg.so 0xA7C00000
+libomx_sharedlibrary.so 0xA7BA0000
+libopencore_download.so 0xA7B40000
+libopencore_downloadreg.so 0xA7B00000
+libopencore_net_support.so 0xA7A00000
+libopencore_rtsp.so 0xA7900000
+libopencore_rtspreg.so 0xA7890000
+libopencore_author.so 0xA7800000
+libomx_aacdec_sharedlibrary.so 0xA7700000
+libomx_amrdec_sharedlibrary.so 0xA76A0000
+libomx_amrenc_sharedlibrary.so 0xA7680000
+libomx_avcdec_sharedlibrary.so 0xA7660000
+libomx_avcenc_sharedlibrary.so 0xA7610000
+libomx_m4vdec_sharedlibrary.so 0xA75C0000
+libomx_m4venc_sharedlibrary.so 0xA7590000
+libomx_mp3dec_sharedlibrary.so 0xA7450000
+libopencore_mp4local.so 0xA7400000
+libopencore_mp4localreg.so 0xA7300000
+libopencore_player.so 0xA7000000
# opencore hardware support
libmm-adspsvc.so 0xA6FFD000
@@ -134,3 +158,4 @@
libtrace_test.so 0x9A300000
libsrec_jni.so 0x9A200000
libcerttool_jni.so 0x9A100000
+
diff --git a/core/product.mk b/core/product.mk
index adc81c3..a9a24d2 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -68,7 +68,8 @@
PRODUCT_SDK_ADDON_NAME \
PRODUCT_SDK_ADDON_COPY_FILES \
PRODUCT_SDK_ADDON_COPY_MODULES \
- PRODUCT_SDK_ADDON_DOC_MODULE
+ PRODUCT_SDK_ADDON_DOC_MODULE \
+ PRODUCT_DEFAULT_WIFI_CHANNELS
define dump-product
$(info ==== $(1) ====)\
diff --git a/core/product_config.mk b/core/product_config.mk
index 7cfa5f4..3237801 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -214,6 +214,9 @@
PRODUCT_MANUFACTURER := unknown
endif
+PRODUCT_DEFAULT_WIFI_CHANNELS := \
+ $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEFAULT_WIFI_CHANNELS))
+
# Which policy should this product use
PRODUCT_POLICY := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_POLICY))
diff --git a/core/tasks/product-graph.mk b/core/tasks/product-graph.mk
index ead1406..5dc13a6 100644
--- a/core/tasks/product-graph.mk
+++ b/core/tasks/product-graph.mk
@@ -25,6 +25,7 @@
$(products_pdf):
$(hide) ( \
echo 'digraph {'; \
+ echo 'graph [ ratio = .6, pack=false];'; \
$(foreach p,$(ALL_PRODUCTS), \
$(foreach d,$(PRODUCTS.$(strip $(p)).INHERITS_FROM), \
echo \"$(d)\" -\> \"$(p)\";)) \
diff --git a/core/version_defaults.mk b/core/version_defaults.mk
index ca8487f..bbcbb51 100644
--- a/core/version_defaults.mk
+++ b/core/version_defaults.mk
@@ -41,7 +41,7 @@
# which is the version that we reveal to the end user.
# Update this value when the platform version changes (rather
# than overriding it somewhere else). Can be an arbitrary string.
- PLATFORM_VERSION := Donut
+ PLATFORM_VERSION := Eclair
endif
ifeq "" "$(PLATFORM_SDK_VERSION)"
@@ -57,9 +57,9 @@
endif
ifeq "" "$(PLATFORM_VERSION_CODENAME)"
- # If the build is not a final release build, then this is the current
- # development code-name. If this is a final release build, it is simply "REL".
- PLATFORM_VERSION_CODENAME := Donut
+ # This is the current development code-name, if the build is not a final
+ # release build. If this is a final release build, it is simply "REL".
+ PLATFORM_VERSION_CODENAME := Eclair
endif
ifeq "" "$(DEFAULT_APP_TARGET_SDK)"
diff --git a/envsetup.sh b/envsetup.sh
index 6325c3d..9eeab02 100644
--- a/envsetup.sh
+++ b/envsetup.sh
@@ -102,7 +102,7 @@
# and in with the new
CODE_REVIEWS=
prebuiltdir=$(getprebuilt)
- export ANDROID_EABI_TOOLCHAIN=$prebuiltdir/toolchain/arm-eabi-4.2.1/bin
+ export ANDROID_EABI_TOOLCHAIN=$prebuiltdir/toolchain/arm-eabi-4.4.0/bin
export ANDROID_TOOLCHAIN=$ANDROID_EABI_TOOLCHAIN
export ANDROID_QTOOLS=$T/development/emulator/qtools
export ANDROID_BUILD_PATHS=:$(get_build_var ANDROID_BUILD_PATHS):$ANDROID_QTOOLS:$ANDROID_TOOLCHAIN:$ANDROID_EABI_TOOLCHAIN$CODE_REVIEWS
@@ -596,6 +596,8 @@
# Find the closest Android.mk file.
T=$(gettop)
local M=$(findmakefile)
+ # Remove the path to top as the makefilepath needs to be relative
+ local M=`echo $M|sed 's:'$T'/::'`
if [ ! "$T" ]; then
echo "Couldn't locate the top of the tree. Try setting TOP."
elif [ ! "$M" ]; then
@@ -634,6 +636,7 @@
ARGS="$ARGS showcommands"
else
echo "No Android.mk in $DIR."
+ return 1
fi
fi
done
@@ -653,6 +656,26 @@
fi
}
+function cproj()
+{
+ TOPFILE=build/core/envsetup.mk
+ # We redirect cd to /dev/null in case it's aliased to
+ # a command that prints something as a side-effect
+ # (like pushd)
+ local HERE=$PWD
+ T=
+ while [ \( ! \( -f $TOPFILE \) \) -a \( $PWD != "/" \) ]; do
+ T=$PWD
+ if [ -f "$T/Android.mk" ]; then
+ cd $T
+ return
+ fi
+ cd .. > /dev/null
+ done
+ cd $HERE > /dev/null
+ echo "can't find Android.mk"
+}
+
function pid()
{
local EXE="$1"
diff --git a/target/board/Android.mk b/target/board/Android.mk
index 64e3a74..fc2f651 100644
--- a/target/board/Android.mk
+++ b/target/board/Android.mk
@@ -20,11 +20,8 @@
INSTALLED_KERNEL_TARGET :=
endif
-ifneq ($(strip $(TARGET_NO_RADIOIMAGE)),true)
- INSTALLED_RADIOIMAGE_TARGET := $(PRODUCT_OUT)/radio.img
-else
- INSTALLED_RADIOIMAGE_TARGET :=
-endif
+# Use the add-radio-file function to add values to this variable.
+INSTALLED_RADIOIMAGE_TARGET :=
ifeq (,$(wildcard $(TARGET_DEVICE_DIR)/AndroidBoard.mk))
ifeq (,$(wildcard $(TARGET_DEVICE_DIR)/Android.mk))
diff --git a/target/board/generic/BoardConfig.mk b/target/board/generic/BoardConfig.mk
index 6ec2de3..2b72d01 100644
--- a/target/board/generic/BoardConfig.mk
+++ b/target/board/generic/BoardConfig.mk
@@ -1,12 +1,11 @@
# config.mk
-#
+#
# Product-specific compile-time definitions.
#
# The generic product target doesn't have any hardware-specific pieces.
TARGET_NO_BOOTLOADER := true
TARGET_NO_KERNEL := true
-TARGET_NO_RADIOIMAGE := true
TARGET_CPU_ABI := armeabi
HAVE_HTC_AUDIO_DRIVER := true
BOARD_USES_GENERIC_AUDIO := true
diff --git a/target/product/core.mk b/target/product/core.mk
index 204345e..79372a1 100644
--- a/target/product/core.mk
+++ b/target/product/core.mk
@@ -3,7 +3,8 @@
PRODUCT_DEVICE :=
PRODUCT_POLICY := android.policy_phone
PRODUCT_PROPERTY_OVERRIDES := \
- ro.config.notification_sound=F1_New_SMS.ogg
+ ro.config.notification_sound=F1_New_SMS.ogg \
+ ro.config.alarm_alert=Alarm_Classic.ogg
PRODUCT_PACKAGES := \
framework-res \
@@ -26,4 +27,3 @@
PackageInstaller \
WebSearchProvider \
Bugreport
-
diff --git a/target/product/generic.mk b/target/product/generic.mk
index b9bc070..4189b0e 100644
--- a/target/product/generic.mk
+++ b/target/product/generic.mk
@@ -5,9 +5,11 @@
PRODUCT_PACKAGES := \
AlarmClock \
AlarmProvider \
+ Calculator \
Calendar \
Camera \
DrmProvider \
+ Email \
LatinIME \
Mms \
Music \
diff --git a/target/product/generic_with_google.mk b/target/product/generic_with_google.mk
index dddbbb7..d691e99 100644
--- a/target/product/generic_with_google.mk
+++ b/target/product/generic_with_google.mk
@@ -5,12 +5,15 @@
PRODUCT_PACKAGES := \
GoogleContactsProvider \
+ GoogleContactsSyncAdapter \
GoogleSubscribedFeedsProvider \
com.google.android.gtalkservice \
+ com.google.android.datamessaging \
com.google.android.maps
PRODUCT_COPY_FILES := \
vendor/google/frameworks/maps/com.google.android.maps.xml:system/etc/permissions/com.google.android.maps.xml \
+ vendor/google/frameworks/datamessaging/com.google.android.datamessaging.xml:system/etc/permissions/com.google.android.datamessaging.xml \
vendor/google/apps/GTalkService/com.google.android.gtalkservice.xml:system/etc/permissions/com.google.android.gtalkservice.xml
diff --git a/target/product/min_dev.mk b/target/product/min_dev.mk
index 005af70..056c2b8 100644
--- a/target/product/min_dev.mk
+++ b/target/product/min_dev.mk
@@ -1,7 +1,8 @@
PRODUCT_POLICY := android.policy_phone
PRODUCT_PROPERTY_OVERRIDES := \
- ro.config.notification_sound=F1_New_SMS.ogg
+ ro.config.notification_sound=F1_New_SMS.ogg \
+ ro.config.alarm_alert=Alarm_Classic.ogg
PRODUCT_BRAND := generic
PRODUCT_NAME := min_dev
PRODUCT_DEVICE := generic
diff --git a/tools/apriori/prelinkmap.c b/tools/apriori/prelinkmap.c
index 739c181..9fb00e4 100644
--- a/tools/apriori/prelinkmap.c
+++ b/tools/apriori/prelinkmap.c
@@ -7,11 +7,14 @@
typedef struct mapentry mapentry;
+#define MAX_ALIASES 10
+
struct mapentry
{
mapentry *next;
unsigned base;
- char name[0];
+ char *names[MAX_ALIASES];
+ int num_names;
};
static mapentry *maplist = 0;
@@ -22,14 +25,13 @@
*/
#define PRELINK_MIN 0x90000000
-#define PRELINK_MAX 0xB0000000
+#define PRELINK_MAX 0xBFFFFFFF
void pm_init(const char *file)
{
unsigned line = 0;
char buf[256];
char *x;
- unsigned n;
FILE *fp;
mapentry *me;
unsigned last = -1UL;
@@ -65,26 +67,52 @@
continue;
}
- n = strtoul(x, 0, 16);
- /* Note that this is not the only bounds check. If a library's size
- exceeds its slot as defined in the prelink map, the prelinker will
- exit with an error. See pm_report_library_size_in_memory().
- */
- FAILIF((n < PRELINK_MIN) || (n > PRELINK_MAX),
- "%s:%d base 0x%08x out of range.\n",
- file, line, n);
-
- me = malloc(sizeof(mapentry) + strlen(buf) + 1);
- FAILIF(me == NULL, "Out of memory parsing %s\n", file);
+ if (isalpha(*x)) {
+ /* Assume that this is an alias, and look through the list of
+ already-installed libraries.
+ */
+ me = maplist;
+ while(me) {
+ /* The strlen() call ignores the newline at the end of x */
+ if (!strncmp(me->names[0], x, strlen(me->names[0]))) {
+ PRINT("Aliasing library %s to %s at %08x\n",
+ buf, x, me->base);
+ break;
+ }
+ me = me->next;
+ }
+ FAILIF(!me, "Nonexistent alias %s -> %s\n", buf, x);
+ }
+ else {
+ unsigned n = strtoul(x, 0, 16);
+ /* Note that this is not the only bounds check. If a library's
+ size exceeds its slot as defined in the prelink map, the
+ prelinker will exit with an error. See
+ pm_report_library_size_in_memory().
+ */
+ FAILIF((n < PRELINK_MIN) || (n > PRELINK_MAX),
+ "%s:%d base 0x%08x out of range.\n",
+ file, line, n);
- FAILIF(last <= n, "The prelink map is not in descending order "
- "at entry %s (%08x)!\n", buf, n);
- last = n;
-
- me->base = n;
- strcpy(me->name, buf);
- me->next = maplist;
- maplist = me;
+ me = malloc(sizeof(mapentry));
+ FAILIF(me == NULL, "Out of memory parsing %s\n", file);
+
+ FAILIF(last <= n, "The prelink map is not in descending order "
+ "at entry %s (%08x)!\n", buf, n);
+ last = n;
+
+ me->base = n;
+ me->next = maplist;
+ me->num_names = 0;
+ maplist = me;
+ }
+
+ FAILIF(me->num_names >= MAX_ALIASES,
+ "Too many aliases for library %s, maximum is %d.\n",
+ me->names[0],
+ MAX_ALIASES);
+ me->names[me->num_names] = strdup(buf);
+ me->num_names++;
}
fclose(fp);
@@ -99,41 +127,44 @@
{
char *x;
mapentry *me;
+ int n;
x = strrchr(name,'/');
if(x) name = x+1;
for(me = maplist; me; me = me->next){
- if(!strcmp(name, me->name)) {
- off_t slot = me->next ? me->next->base : PRELINK_MAX;
- slot -= me->base;
- FAILIF(fsize > slot,
- "prelink map error: library %s@0x%08x is too big "
- "at %lld bytes, it runs %lld bytes into "
- "library %s@0x%08x!\n",
- me->name, me->base, fsize, fsize - slot,
- me->next->name, me->next->base);
- break;
+ for (n = 0; n < me->num_names; n++) {
+ if(!strcmp(name, me->names[n])) {
+ off_t slot = me->next ? me->next->base : PRELINK_MAX;
+ slot -= me->base;
+ FAILIF(fsize > slot,
+ "prelink map error: library %s@0x%08x is too big "
+ "at %lld bytes, it runs %lld bytes into "
+ "library %s@0x%08x!\n",
+ me->names[0], me->base, fsize, fsize - slot,
+ me->next->names[0], me->next->base);
+ return;
+ }
}
}
- FAILIF(!me,"library '%s' not in prelink map\n", name);
+ FAILIF(1, "library '%s' not in prelink map\n", name);
}
unsigned pm_get_next_link_address(const char *lookup_name)
{
char *x;
mapentry *me;
+ int n;
x = strrchr(lookup_name,'/');
if(x) lookup_name = x+1;
- for(me = maplist; me; me = me->next){
- if(!strcmp(lookup_name, me->name)) {
- return me->base;
- }
- }
-
- FAILIF(1==1,"library '%s' not in prelink map\n", lookup_name);
+ for(me = maplist; me; me = me->next)
+ for (n = 0; n < me->num_names; n++)
+ if(!strcmp(lookup_name, me->names[n]))
+ return me->base;
+
+ FAILIF(1, "library '%s' not in prelink map\n", lookup_name);
return 0;
}
diff --git a/tools/buildinfo.sh b/tools/buildinfo.sh
index 5c738a2..af5aa47 100755
--- a/tools/buildinfo.sh
+++ b/tools/buildinfo.sh
@@ -24,6 +24,7 @@
echo "ro.product.manufacturer=$PRODUCT_MANUFACTURER"
echo "ro.product.locale.language=$PRODUCT_DEFAULT_LANGUAGE"
echo "ro.product.locale.region=$PRODUCT_DEFAULT_REGION"
+echo "ro.wifi.channels=$PRODUCT_DEFAULT_WIFI_CHANNELS"
echo "ro.board.platform=$TARGET_BOARD_PLATFORM"
echo "# ro.build.product is obsolete; use ro.product.device"
diff --git a/tools/droiddoc/src/DroidDoc.java b/tools/droiddoc/src/DroidDoc.java
index a8b9c73..667c47b 100644
--- a/tools/droiddoc/src/DroidDoc.java
+++ b/tools/droiddoc/src/DroidDoc.java
@@ -94,6 +94,7 @@
String stubsDir = null;
//Create the dependency graph for the stubs directory
boolean apiXML = false;
+ boolean noDocs = false;
String apiFile = null;
String debugStubsFile = "";
HashSet<String> stubPackages = null;
@@ -187,6 +188,9 @@
apiXML = true;
apiFile = a[1];
}
+ else if (a[0].equals("-nodocs")) {
+ noDocs = true;
+ }
else if (a[0].equals("-since")) {
sinceTagger.addVersion(a[1], a[2]);
}
@@ -200,62 +204,70 @@
// Set up the data structures
Converter.makeInfo(r);
- // Files for proofreading
- if (proofreadFile != null) {
- Proofread.initProofread(proofreadFile);
+ if (!noDocs) {
+ long startTime = System.nanoTime();
+
+ // Apply @since tags from the XML file
+ sinceTagger.tagAll(Converter.rootClasses());
+
+ // Files for proofreading
+ if (proofreadFile != null) {
+ Proofread.initProofread(proofreadFile);
+ }
+ if (todoFile != null) {
+ TodoFile.writeTodoFile(todoFile);
+ }
+
+ // HTML Pages
+ if (ClearPage.htmlDir != null) {
+ writeHTMLPages();
+ }
+
+ // Navigation tree
+ NavTree.writeNavTree(javadocDir);
+
+ // Packages Pages
+ writePackages(javadocDir
+ + (ClearPage.htmlDir!=null
+ ? "packages" + htmlExtension
+ : "index" + htmlExtension));
+
+ // Classes
+ writeClassLists();
+ writeClasses();
+ writeHierarchy();
+ // writeKeywords();
+
+ // Lists for JavaScript
+ writeLists();
+ if (keepListFile != null) {
+ writeKeepList(keepListFile);
+ }
+
+ // Sample Code
+ for (SampleCode sc: sampleCodes) {
+ sc.write();
+ }
+
+ // Index page
+ writeIndex();
+
+ Proofread.finishProofread(proofreadFile);
+
+ if (sdkValuePath != null) {
+ writeSdkValues(sdkValuePath);
+ }
+
+ long time = System.nanoTime() - startTime;
+ System.out.println("DroidDoc took " + (time / 1000000000) + " sec. to write docs to "
+ + ClearPage.outputDir);
}
- if (todoFile != null) {
- TodoFile.writeTodoFile(todoFile);
- }
-
- // Apply @since tags from the XML file
- sinceTagger.tagAll(Converter.rootClasses());
-
- // HTML Pages
- if (ClearPage.htmlDir != null) {
- writeHTMLPages();
- }
-
- // Navigation tree
- NavTree.writeNavTree(javadocDir);
-
- // Packages Pages
- writePackages(javadocDir
- + (ClearPage.htmlDir!=null
- ? "packages" + htmlExtension
- : "index" + htmlExtension));
-
- // Classes
- writeClassLists();
- writeClasses();
- writeHierarchy();
- // writeKeywords();
-
- // Lists for JavaScript
- writeLists();
- if (keepListFile != null) {
- writeKeepList(keepListFile);
- }
-
- // Sample Code
- for (SampleCode sc: sampleCodes) {
- sc.write();
- }
-
- // Index page
- writeIndex();
-
- Proofread.finishProofread(proofreadFile);
// Stubs
if (stubsDir != null) {
Stubs.writeStubs(stubsDir, apiXML, apiFile, stubPackages);
}
- if (sdkValuePath != null) {
- writeSdkValues(sdkValuePath);
- }
-
Errors.printErrors();
return !Errors.hadError;
}
@@ -401,6 +413,9 @@
if (option.equals("-apixml")) {
return 2;
}
+ if (option.equals("-nodocs")) {
+ return 1;
+ }
if (option.equals("-since")) {
return 3;
}
diff --git a/tools/releasetools/amend_generator.py b/tools/releasetools/amend_generator.py
index 3e8af13..70e71d4 100644
--- a/tools/releasetools/amend_generator.py
+++ b/tools/releasetools/amend_generator.py
@@ -180,6 +180,7 @@
def MakeSymlinks(self, symlink_list):
"""Create symlinks, given a list of (dest, link) pairs."""
+ self.DeleteFiles([i[1] for i in symlink_list])
self.script.extend(["symlink %s %s" % (i[0], self._FileRoot(i[1]))
for i in sorted(symlink_list)])
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index a07ff7c..4174db5 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -15,6 +15,7 @@
import errno
import getopt
import getpass
+import imp
import os
import re
import shutil
@@ -33,7 +34,7 @@
OPTIONS.max_image_size = {}
OPTIONS.verbose = False
OPTIONS.tempfiles = []
-
+OPTIONS.device_specific = None
class ExternalError(RuntimeError): pass
@@ -245,6 +246,10 @@
Prepend <dir>/bin to the list of places to search for binaries
run by this script, and expect to find jars in <dir>/framework.
+ -s (--device_specific) <file>
+ Path to the python module containing device-specific
+ releasetools code.
+
-v (--verbose)
Show command lines being executed.
@@ -269,8 +274,9 @@
try:
opts, args = getopt.getopt(
- argv, "hvp:" + extra_opts,
- ["help", "verbose", "path="] + list(extra_long_opts))
+ argv, "hvp:s:" + extra_opts,
+ ["help", "verbose", "path=", "device_specific="] +
+ list(extra_long_opts))
except getopt.GetoptError, err:
Usage(docstring)
print "**", str(err), "**"
@@ -286,6 +292,8 @@
OPTIONS.verbose = True
elif o in ("-p", "--path"):
OPTIONS.search_path = a
+ elif o in ("-s", "--device_specific"):
+ OPTIONS.device_specific = a
else:
if extra_option_handler is None or not extra_option_handler(o, a):
assert False, "unknown option \"%s\"" % (o,)
@@ -410,3 +418,68 @@
zinfo.compress_type = zip.compression
zinfo.external_attr = perms << 16
zip.writestr(zinfo, data)
+
+
+class DeviceSpecificParams(object):
+ module = None
+ def __init__(self, **kwargs):
+ """Keyword arguments to the constructor become attributes of this
+ object, which is passed to all functions in the device-specific
+ module."""
+ for k, v in kwargs.iteritems():
+ setattr(self, k, v)
+
+ if self.module is None:
+ path = OPTIONS.device_specific
+ if path is None: return
+ try:
+ if os.path.isdir(path):
+ info = imp.find_module("releasetools", [path])
+ else:
+ d, f = os.path.split(path)
+ b, x = os.path.splitext(f)
+ if x == ".py":
+ f = b
+ info = imp.find_module(f, [d])
+ self.module = imp.load_module("device_specific", *info)
+ except ImportError:
+ print "unable to load device-specific module; assuming none"
+
+ def _DoCall(self, function_name, *args, **kwargs):
+ """Call the named function in the device-specific module, passing
+ the given args and kwargs. The first argument to the call will be
+ the DeviceSpecific object itself. If there is no module, or the
+ module does not define the function, return the value of the
+ 'default' kwarg (which itself defaults to None)."""
+ if self.module is None or not hasattr(self.module, function_name):
+ return kwargs.get("default", None)
+ return getattr(self.module, function_name)(*((self,) + args), **kwargs)
+
+ def FullOTA_Assertions(self):
+ """Called after emitting the block of assertions at the top of a
+ full OTA package. Implementations can add whatever additional
+ assertions they like."""
+ return self._DoCall("FullOTA_Assertions")
+
+ def FullOTA_InstallEnd(self):
+ """Called at the end of full OTA installation; typically this is
+ used to install the image for the device's baseband processor."""
+ return self._DoCall("FullOTA_InstallEnd")
+
+ def IncrementalOTA_Assertions(self):
+ """Called after emitting the block of assertions at the top of an
+ incremental OTA package. Implementations can add whatever
+ additional assertions they like."""
+ return self._DoCall("IncrementalOTA_Assertions")
+
+ def IncrementalOTA_VerifyEnd(self):
+ """Called at the end of the verification phase of incremental OTA
+ installation; additional checks can be placed here to abort the
+ script before any changes are made."""
+ return self._DoCall("IncrementalOTA_VerifyEnd")
+
+ def IncrementalOTA_InstallEnd(self):
+ """Called at the end of incremental OTA installation; typically
+ this is used to install the image for the device's baseband
+ processor."""
+ return self._DoCall("IncrementalOTA_InstallEnd")
diff --git a/tools/releasetools/ota_from_target_files b/tools/releasetools/ota_from_target_files
index 4cda44a..58177b4 100755
--- a/tools/releasetools/ota_from_target_files
+++ b/tools/releasetools/ota_from_target_files
@@ -285,7 +285,8 @@
m = re.search(r"require\s+version-bootloader\s*=\s*(\S+)", info)
if m:
bootloaders = m.group(1).split("|")
- script.AssertSomeBootloader(*bootloaders)
+ if "*" not in bootloaders:
+ script.AssertSomeBootloader(*bootloaders)
def MakeRecoveryPatch(output_zip, recovery_img, boot_img):
@@ -340,19 +341,18 @@
# change very often.
script = edify_generator.EdifyGenerator(2)
+ device_specific = common.DeviceSpecificParams(
+ input_zip=input_zip,
+ output_zip=output_zip,
+ script=script,
+ input_tmp=OPTIONS.input_tmp)
+
if not OPTIONS.omit_prereq:
ts = GetBuildProp("ro.build.date.utc", input_zip)
script.AssertOlderBuild(ts)
AppendAssertions(script, input_zip)
-
- script.ShowProgress(0.1, 0)
-
- try:
- common.ZipWriteStr(output_zip, "radio.img", input_zip.read("RADIO/image"))
- script.WriteFirmwareImage("radio", "radio.img")
- except KeyError:
- print "warning: no radio image in input target_files; not flashing radio"
+ device_specific.FullOTA_Assertions()
script.ShowProgress(0.5, 0)
@@ -386,8 +386,11 @@
common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
script.ShowProgress(0.2, 0)
- script.WriteRawImage("boot", "boot.img")
script.ShowProgress(0.2, 10)
+ script.WriteRawImage("boot", "boot.img")
+
+ script.ShowProgress(0.1, 0)
+ device_specific.FullOTA_InstallEnd()
if OPTIONS.extra_script is not None:
script.AppendExtra(OPTIONS.extra_script)
@@ -503,6 +506,12 @@
else:
raise ValueError('unknown script mode "%s"' % (OPTIONS.script_mode,))
+ device_specific = common.DeviceSpecificParams(
+ source_zip=source_zip,
+ target_zip=target_zip,
+ output_zip=output_zip,
+ script=script)
+
print "Loading target..."
target_data = LoadSystemFiles(target_zip)
print "Loading source..."
@@ -567,19 +576,15 @@
os.path.join(OPTIONS.target_tmp, "RECOVERY")))
updating_recovery = (source_recovery.data != target_recovery.data)
- source_radio = source_zip.read("RADIO/image")
- target_radio = target_zip.read("RADIO/image")
- updating_radio = (source_radio != target_radio)
-
- # The last 0.1 is reserved for creating symlinks, fixing
- # permissions, and writing the boot image (if necessary).
- progress_bar_total = 1.0
+ # We reserve the last 0.3 of the progress bar for the
+ # device-specific IncrementalOTA_InstallEnd() call at the end, which
+ # will typically install a radio image.
+ progress_bar_total = 0.7
if updating_boot:
progress_bar_total -= 0.1
- if updating_radio:
- progress_bar_total -= 0.3
AppendAssertions(script, target_zip)
+ device_specific.IncrementalOTA_Assertions()
script.Print("Verifying current system...")
@@ -610,6 +615,8 @@
script.Print("Unpacking patches...")
script.UnpackPackageDir("patch", "/tmp/patchtmp")
+ device_specific.IncrementalOTA_VerifyEnd()
+
script.Comment("---- start making changes here ----")
if OPTIONS.wipe_user_data:
@@ -654,15 +661,6 @@
else:
print "recovery image unchanged; skipping."
- if updating_radio:
- script.ShowProgress(0.3, 10)
- script.Print("Writing radio image...")
- script.WriteFirmwareImage("radio", "radio.img")
- common.ZipWriteStr(output_zip, "radio.img", target_radio)
- print "radio image changed; including."
- else:
- print "radio image unchanged; skipping."
-
script.Print("Patching system files...")
pb_apply = progress_bar_total * 0.7 * \
(total_patched_size /
@@ -707,7 +705,7 @@
script.Print("Unpacking new files...")
script.UnpackPackageDir("system", "/system")
- script.Print("Finishing up...")
+ script.Print("Symlinks and permissions...")
# Create all the symlinks that don't already exist, or point to
# somewhere different than what we want. Delete each symlink before
@@ -726,6 +724,10 @@
# permissions.
script.AppendScript(temp_script)
+ # Write the radio image, if necessary.
+ script.ShowProgress(0.3, 10)
+ device_specific.IncrementalOTA_InstallEnd()
+
if OPTIONS.extra_script is not None:
scirpt.AppendExtra(OPTIONS.extra_script)
diff --git a/tools/releasetools/sign_target_files_apks b/tools/releasetools/sign_target_files_apks
index 6dd8ede..5153398 100755
--- a/tools/releasetools/sign_target_files_apks
+++ b/tools/releasetools/sign_target_files_apks
@@ -20,10 +20,6 @@
Usage: sign_target_files_apks [flags] input_target_files output_target_files
- -s (--signapk_jar) <path>
- Path of the signapks.jar file used to sign an individual APK
- file.
-
-e (--extra_apks) <name,name,...=key>
Add extra APK name/key pairs as though they appeared in
apkcerts.txt (so mappings specified by -k and -d are applied).
@@ -302,9 +298,7 @@
def main(argv):
def option_handler(o, a):
- if o in ("-s", "--signapk_jar"):
- OPTIONS.signapk_jar = a
- elif o in ("-e", "--extra_apks"):
+ if o in ("-e", "--extra_apks"):
names, key = a.split("=")
names = names.split(",")
for n in names:
@@ -334,9 +328,8 @@
return True
args = common.ParseOptions(argv, __doc__,
- extra_opts="s:e:d:k:ot:",
- extra_long_opts=["signapk_jar=",
- "extra_apks=",
+ extra_opts="e:d:k:ot:",
+ extra_long_opts=["extra_apks=",
"default_key_mappings=",
"key_mapping=",
"replace_ota_keys",
diff --git a/tools/warn.py b/tools/warn.py
new file mode 100755
index 0000000..b379849
--- /dev/null
+++ b/tools/warn.py
@@ -0,0 +1,521 @@
+#!/usr/bin/env python
+
+import sys
+import re
+
+if len(sys.argv) == 1:
+ print 'usage: ' + sys.argv[0] + ' <build.log>'
+ sys.exit()
+
+# if you add another level, don't forget to give it a color below
+class severity:
+ UNKNOWN=0
+ SKIP=100
+ FIXMENOW=1
+ HIGH=2
+ MEDIUM=3
+ LOW=4
+ HARMLESS=5
+
+def colorforseverity(sev):
+ if sev == severity.FIXMENOW:
+ return 'fuchsia'
+ if sev == severity.HIGH:
+ return 'red'
+ if sev == severity.MEDIUM:
+ return 'orange'
+ if sev == severity.LOW:
+ return 'yellow'
+ if sev == severity.HARMLESS:
+ return 'limegreen'
+ if sev == severity.UNKNOWN:
+ return 'blue'
+ return 'grey'
+
+warnpatterns = [
+ { 'category':'make', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'make: overriding commands/ignoring old commands',
+ 'patterns':[r".*: warning: overriding commands for target .+",
+ r".*: warning: ignoring old commands for target .+"] },
+ { 'category':'C/C++', 'severity':severity.HIGH, 'members':[], 'option':'-Wimplicit-function-declaration',
+ 'description':'Implicit function declaration',
+ 'patterns':[r".*: warning: implicit declaration of function .+"] },
+ { 'category':'C/C++', 'severity':severity.SKIP, 'members':[], 'option':'',
+ 'description':'',
+ 'patterns':[r".*: warning: conflicting types for '.+'"] },
+ { 'category':'C/C++', 'severity':severity.HIGH, 'members':[], 'option':'-Wtype-limits',
+ 'description':'Expression always evaluates to true or false',
+ 'patterns':[r".*: warning: comparison is always false due to limited range of data type",
+ r".*: warning: comparison of unsigned expression >= 0 is always true",
+ r".*: warning: comparison of unsigned expression < 0 is always false"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Incompatible pointer types',
+ 'patterns':[r".*: warning: assignment from incompatible pointer type",
+ r".*: warning: passing argument [0-9]+ of '.*' from incompatible pointer type",
+ r".*: warning: initialization from incompatible pointer type"] },
+ { 'category':'C/C++', 'severity':severity.HIGH, 'members':[], 'option':'-fno-builtin',
+ 'description':'Incompatible declaration of built in function',
+ 'patterns':[r".*: warning: incompatible implicit declaration of built-in function .+"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wunused-parameter',
+ 'description':'Unused parameter',
+ 'patterns':[r".*: warning: unused parameter '.*'"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wunused',
+ 'description':'Unused function, variable or label',
+ 'patterns':[r".*: warning: '.+' defined but not used"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wunused-value',
+ 'description':'Statement with no effect',
+ 'patterns':[r".*: warning: statement with no effect"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wmissing-field-initializers',
+ 'description':'Missing initializer',
+ 'patterns':[r".*: warning: missing initializer"] },
+ { 'category':'cont.', 'severity':severity.SKIP, 'members':[], 'option':'',
+ 'description':'',
+ 'patterns':[r".*: warning: \(near initialization for '.+'\)"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wformat',
+ 'description':'Format string does not match arguments',
+ 'patterns':[r".*: warning: format '.+' expects type '.+', but argument [0-9]+ has type '.+'"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wformat-extra-args',
+ 'description':'Too many arguments for format string',
+ 'patterns':[r".*: warning: too many arguments for format"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wsign-compare',
+ 'description':'Comparison between signed and unsigned',
+ 'patterns':[r".*: warning: comparison between signed and unsigned",
+ r".*: warning: comparison of promoted \~unsigned with unsigned",
+ r".*: warning: signed and unsigned type in conditional expression"] },
+ { 'category':'libpng', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'libpng: zero area',
+ 'patterns':[r".*libpng warning: Ignoring attempt to set cHRM RGB triangle with zero area"] },
+ { 'category':'aapt', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'aapt: no comment for public symbol',
+ 'patterns':[r".*: warning: No comment for public symbol .+"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wmissing-braces',
+ 'description':'Missing braces around initializer',
+ 'patterns':[r".*: warning: missing braces around initializer.*"] },
+ { 'category':'C/C++', 'severity':severity.HARMLESS, 'members':[], 'option':'',
+ 'description':'No newline at end of file',
+ 'patterns':[r".*: warning: no newline at end of file"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wcast-qual',
+ 'description':'Qualifier discarded',
+ 'patterns':[r".*: warning: passing argument [0-9]+ of '.+' discards qualifiers from pointer target type",
+ r".*: warning: assignment discards qualifiers from pointer target type",
+ r".*: warning: return discards qualifiers from pointer target type"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wattributes',
+ 'description':'Attribute ignored',
+ 'patterns':[r".*: warning: '_*packed_*' attribute ignored"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wattributes',
+ 'description':'Visibility mismatch',
+ 'patterns':[r".*: warning: '.+' declared with greater visibility than the type of its field '.+'"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Shift count greater than width of type',
+ 'patterns':[r".*: warning: (left|right) shift count >= width of type"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'extern <foo> is initialized',
+ 'patterns':[r".*: warning: '.+' initialized and declared 'extern'"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wold-style-declaration',
+ 'description':'Old style declaration',
+ 'patterns':[r".*: warning: 'static' is not at beginning of declaration"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wuninitialized',
+ 'description':'Variable may be used uninitialized',
+ 'patterns':[r".*: warning: '.+' may be used uninitialized in this function"] },
+ { 'category':'C/C++', 'severity':severity.HIGH, 'members':[], 'option':'-Wuninitialized',
+ 'description':'Variable is used uninitialized',
+ 'patterns':[r".*: warning: '.+' is used uninitialized in this function"] },
+ { 'category':'ld', 'severity':severity.MEDIUM, 'members':[], 'option':'-fshort-enums',
+ 'description':'ld: possible enum size mismatch',
+ 'patterns':[r".*: warning: .* uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wpointer-sign',
+ 'description':'Pointer targets differ in signedness',
+ 'patterns':[r".*: warning: pointer targets in initialization differ in signedness",
+ r".*: warning: pointer targets in assignment differ in signedness",
+ r".*: warning: pointer targets in return differ in signedness",
+ r".*: warning: pointer targets in passing argument [0-9]+ of '.+' differ in signedness"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wstrict-overflow',
+ 'description':'Assuming overflow does not occur',
+ 'patterns':[r".*: warning: assuming signed overflow does not occur when assuming that .* is always (true|false)"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wempty-body',
+ 'description':'Suggest adding braces around empty body',
+ 'patterns':[r".*: warning: suggest braces around empty body in an 'if' statement",
+ r".*: warning: empty body in an if-statement",
+ r".*: warning: suggest braces around empty body in an 'else' statement",
+ r".*: warning: empty body in an else-statement"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wparentheses',
+ 'description':'Suggest adding parentheses',
+ 'patterns':[r".*: warning: suggest explicit braces to avoid ambiguous 'else'",
+ r".*: warning: suggest parentheses around arithmetic in operand of '.+'",
+ r".*: warning: suggest parentheses around comparison in operand of '.+'",
+ r".*: warning: suggest parentheses around '.+?' .+ '.+?'",
+ r".*: warning: suggest parentheses around assignment used as truth value"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Static variable used in non-static inline function',
+ 'patterns':[r".*: warning: '.+' is static but used in inline function '.+' which is not static"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wimplicit int',
+ 'description':'No type or storage class (will default to int)',
+ 'patterns':[r".*: warning: data definition has no type or storage class"] },
+ { 'category':'cont.', 'severity':severity.SKIP, 'members':[], 'option':'',
+ 'description':'',
+ 'patterns':[r".*: warning: type defaults to 'int' in declaration of '.+'"] },
+ { 'category':'cont.', 'severity':severity.SKIP, 'members':[], 'option':'',
+ 'description':'',
+ 'patterns':[r".*: warning: parameter names \(without types\) in function declaration"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wstrict-aliasing',
+ 'description':'Dereferencing <foo> breaks strict aliasing rules',
+ 'patterns':[r".*: warning: dereferencing .* break strict-aliasing rules"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wpointer-to-int-cast',
+ 'description':'Cast from pointer to integer of different size',
+ 'patterns':[r".*: warning: cast from pointer to integer of different size"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wint-to-pointer-cast',
+ 'description':'Cast to pointer from integer of different size',
+ 'patterns':[r".*: warning: cast to pointer from integer of different size"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Symbol redefined',
+ 'patterns':[r".*: warning: "".+"" redefined"] },
+ { 'category':'cont.', 'severity':severity.SKIP, 'members':[], 'option':'',
+ 'description':'',
+ 'patterns':[r".*: warning: this is the location of the previous definition"] },
+ { 'category':'ld', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'ld: type and size of dynamic symbol are not defined',
+ 'patterns':[r".*: warning: type and size of dynamic symbol `.+' are not defined"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Pointer from integer without cast',
+ 'patterns':[r".*: warning: assignment makes pointer from integer without a cast"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Pointer from integer without cast',
+ 'patterns':[r".*: warning: passing argument [0-9]+ of '.+' makes pointer from integer without a cast"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Integer from pointer without cast',
+ 'patterns':[r".*: warning: assignment makes integer from pointer without a cast"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Integer from pointer without cast',
+ 'patterns':[r".*: warning: passing argument [0-9]+ of '.+' makes integer from pointer without a cast"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Integer from pointer without cast',
+ 'patterns':[r".*: warning: return makes integer from pointer without a cast"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wunknown-pragmas',
+ 'description':'Ignoring pragma',
+ 'patterns':[r".*: warning: ignoring #pragma .+"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wclobbered',
+ 'description':'Variable might be clobbered by longjmp or vfork',
+ 'patterns':[r".*: warning: variable '.+' might be clobbered by 'longjmp' or 'vfork'"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wclobbered',
+ 'description':'Argument might be clobbered by longjmp or vfork',
+ 'patterns':[r".*: warning: argument '.+' might be clobbered by 'longjmp' or 'vfork'"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wredundant-decls',
+ 'description':'Redundant declaration',
+ 'patterns':[r".*: warning: redundant redeclaration of '.+'"] },
+ { 'category':'cont.', 'severity':severity.SKIP, 'members':[], 'option':'',
+ 'description':'',
+ 'patterns':[r".*: warning: previous declaration of '.+' was here"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wswitch-enum',
+ 'description':'Enum value not handled in switch',
+ 'patterns':[r".*: warning: enumeration value '.+' not handled in switch"] },
+ { 'category':'java', 'severity':severity.MEDIUM, 'members':[], 'option':'-encoding',
+ 'description':'Java: Non-ascii characters used, but ascii encoding specified',
+ 'patterns':[r".*: warning: unmappable character for encoding ascii"] },
+ { 'category':'java', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Java: Non-varargs call of varargs method with inexact argument type for last parameter',
+ 'patterns':[r".*: warning: non-varargs call of varargs method with inexact argument type for last parameter"] },
+ { 'category':'aapt', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'aapt: String marked untranslatable, but translation exists',
+ 'patterns':[r".*: warning: string '.+' in .* marked untranslatable but exists in locale '??_??'"] },
+ { 'category':'aapt', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'aapt: empty span in string',
+ 'patterns':[r".*: warning: empty '.+' span found in text '.+"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Taking address of temporary',
+ 'patterns':[r".*: warning: taking address of temporary"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Possible broken line continuation',
+ 'patterns':[r".*: warning: backslash and newline separated by space"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Warray-bounds',
+ 'description':'Array subscript out of bounds',
+ 'patterns':[r".*: warning: array subscript is above array bounds"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Decimal constant is unsigned only in ISO C90',
+ 'patterns':[r".*: warning: this decimal constant is unsigned only in ISO C90"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wmain',
+ 'description':'main is usually a function',
+ 'patterns':[r".*: warning: 'main' is usually a function"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Typedef ignored',
+ 'patterns':[r".*: warning: 'typedef' was ignored in this declaration"] },
+ { 'category':'C/C++', 'severity':severity.HIGH, 'members':[], 'option':'-Waddress',
+ 'description':'Address always evaluates to true',
+ 'patterns':[r".*: warning: the address of '.+' will always evaluate as 'true'"] },
+ { 'category':'C/C++', 'severity':severity.FIXMENOW, 'members':[], 'option':'',
+ 'description':'Freeing a non-heap object',
+ 'patterns':[r".*: warning: attempt to free a non-heap object '.+'"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wchar-subscripts',
+ 'description':'Array subscript has type char',
+ 'patterns':[r".*: warning: array subscript has type 'char'"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Constant too large for type',
+ 'patterns':[r".*: warning: integer constant is too large for '.+' type"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Woverflow',
+ 'description':'Constant too large for type, truncated',
+ 'patterns':[r".*: warning: large integer implicitly truncated to unsigned type"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Woverflow',
+ 'description':'Overflow in implicit constant conversion',
+ 'patterns':[r".*: warning: overflow in implicit constant conversion"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Declaration does not declare anything',
+ 'patterns':[r".*: warning: declaration 'class .+' does not declare anything"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wreorder',
+ 'description':'Initialization order will be different',
+ 'patterns':[r".*: warning: '.+' will be initialized after"] },
+ { 'category':'cont.', 'severity':severity.SKIP, 'members':[], 'option':'',
+ 'description':'',
+ 'patterns':[r".*: warning: '.+'"] },
+ { 'category':'cont.', 'severity':severity.SKIP, 'members':[], 'option':'',
+ 'description':'',
+ 'patterns':[r".*: warning: when initialized here"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wmissing-parameter-type',
+ 'description':'Parameter type not specified',
+ 'patterns':[r".*: warning: type of '.+' defaults to 'int'"] },
+ { 'category':'gcc', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Invalid option for C file',
+ 'patterns':[r".*: warning: command line option "".+"" is valid for C\+\+\/ObjC\+\+ but not for C"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'User warning',
+ 'patterns':[r".*: warning: #warning "".+"""] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wextra',
+ 'description':'Dereferencing void*',
+ 'patterns':[r".*: warning: dereferencing 'void \*' pointer"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wextra',
+ 'description':'Comparison of pointer to zero',
+ 'patterns':[r".*: warning: ordered comparison of pointer with integer zero"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wwrite-strings',
+ 'description':'Conversion of string constant to non-const char*',
+ 'patterns':[r".*: warning: deprecated conversion from string constant to '.+'"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wstrict-prototypes',
+ 'description':'Function declaration isn''t a prototype',
+ 'patterns':[r".*: warning: function declaration isn't a prototype"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wignored-qualifiers',
+ 'description':'Type qualifiers ignored on function return value',
+ 'patterns':[r".*: warning: type qualifiers ignored on function return type"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'<foo> declared inside parameter list, scope limited to this definition',
+ 'patterns':[r".*: warning: '.+' declared inside parameter list"] },
+ { 'category':'cont.', 'severity':severity.SKIP, 'members':[], 'option':'',
+ 'description':'',
+ 'patterns':[r".*: warning: its scope is only this definition or declaration, which is probably not what you want"] },
+ { 'category':'C/C++', 'severity':severity.LOW, 'members':[], 'option':'-Wcomment',
+ 'description':'Line continuation inside comment',
+ 'patterns':[r".*: warning: multi-line comment"] },
+ { 'category':'C/C++', 'severity':severity.HARMLESS, 'members':[], 'option':'',
+ 'description':'Extra tokens after #endif',
+ 'patterns':[r".*: warning: extra tokens at end of #endif directive"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wenum-compare',
+ 'description':'Comparison between different enums',
+ 'patterns':[r".*: warning: comparison between 'enum .+' and 'enum .+'"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wconversion',
+ 'description':'Implicit conversion of negative number to unsigned type',
+ 'patterns':[r".*: warning: converting negative value '.+' to '.+'"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Passing NULL as non-pointer argument',
+ 'patterns':[r".*: warning: passing NULL to non-pointer argument [0-9]+ of '.+'"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wctor-dtor-privacy',
+ 'description':'Class seems unusable because of private ctor/dtor' ,
+ 'patterns':[r".*: warning: all member functions in class '.+' are private"] },
+ # skip this next one, because it only points out some RefBase-based classes where having a private destructor is perfectly fine
+ { 'category':'C/C++', 'severity':severity.SKIP, 'members':[], 'option':'-Wctor-dtor-privacy',
+ 'description':'Class seems unusable because of private ctor/dtor' ,
+ 'patterns':[r".*: warning: 'class .+' only defines a private destructor and has no friends"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wctor-dtor-privacy',
+ 'description':'Class seems unusable because of private ctor/dtor' ,
+ 'patterns':[r".*: warning: 'class .+' only defines private constructors and has no friends"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wpointer-arith',
+ 'description':'void* used in arithmetic' ,
+ 'patterns':[r".*: warning: pointer of type 'void \*' used in (arithmetic|subtraction)",
+ r".*: warning: wrong type argument to increment"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'-Wsign-promo',
+ 'description':'Overload resolution chose to promote from unsigned or enum to signed type' ,
+ 'patterns':[r".*: warning: passing '.+' chooses 'int' over '.* int'"] },
+ { 'category':'cont.', 'severity':severity.SKIP, 'members':[], 'option':'',
+ 'description':'',
+ 'patterns':[r".*: warning: in call to '.+'"] },
+ { 'category':'C/C++', 'severity':severity.HIGH, 'members':[], 'option':'-Wextra',
+ 'description':'Base should be explicitly initialized in copy constructor',
+ 'patterns':[r".*: warning: base class '.+' should be explicitly initialized in the copy constructor"] },
+ { 'category':'C/C++', 'severity':severity.MEDIUM, 'members':[], 'option':'',
+ 'description':'Converting from <type> to <other type>',
+ 'patterns':[r".*: warning: converting to '.+' from '.+'"] },
+
+ # these next ones are to deal with formatting problems resulting from the log being mixed up by 'make -j'
+ { 'category':'C/C++', 'severity':severity.SKIP, 'members':[], 'option':'',
+ 'description':'',
+ 'patterns':[r".*: warning: ,$"] },
+ { 'category':'C/C++', 'severity':severity.SKIP, 'members':[], 'option':'',
+ 'description':'',
+ 'patterns':[r".*: warning: $"] },
+ { 'category':'C/C++', 'severity':severity.SKIP, 'members':[], 'option':'',
+ 'description':'',
+ 'patterns':[r".*: warning: In file included from .+,"] },
+
+ # catch-all for warnings this script doesn't know about yet
+ { 'category':'C/C++', 'severity':severity.UNKNOWN, 'members':[], 'option':'',
+ 'description':'Unclassified/unrecognized warnings',
+ 'patterns':[r".*: warning: .+"] },
+]
+
+anchor = 0
+cur_row_color = 0
+row_colors = [ 'e0e0e0', 'd0d0d0' ]
+
+def output(text):
+ print text,
+
+def htmlbig(param):
+ return '<font size="+2">' + param + '</font>'
+
+def dumphtmlprologue(title):
+ output('<html>\n<head>\n<title>' + title + '</title>\n<body>\n')
+ output(htmlbig(title))
+ output('<p>\n')
+
+def tablerow(text):
+ global cur_row_color
+ output('<tr bgcolor="' + row_colors[cur_row_color] + '"><td colspan="2">',)
+ cur_row_color = 1 - cur_row_color
+ output(text,)
+ output('</td></tr>')
+
+def begintable(text, backgroundcolor):
+ global anchor
+ output('<table border="1" rules="cols" frame="box" width="100%" bgcolor="black"><tr bgcolor="' +
+ backgroundcolor + '"><a name="anchor' + str(anchor) + '"><td>')
+ output(htmlbig(text[0]) + '<br>')
+ for i in text[1:]:
+ output(i + '<br>')
+ output('</td>')
+ output('<td width="100" bgcolor="grey"><a align="right" href="#anchor' + str(anchor-1) +
+ '">previous</a><br><a align="right" href="#anchor' + str(anchor+1) + '">next</a>')
+ output('</td></a></tr>')
+ anchor += 1
+
+def endtable():
+ output('</table><p>')
+
+
+# dump some stats about total number of warnings and such
+def dumpstats():
+ known = 0
+ unknown = 0
+ for i in warnpatterns:
+ if i['severity'] == severity.UNKNOWN:
+ unknown += len(i['members'])
+ elif i['severity'] != severity.SKIP:
+ known += len(i['members'])
+ output('Number of classified warnings: <b>' + str(known) + '</b><br>' )
+ output('Number of unclassified warnings: <b>' + str(unknown) + '</b><br>')
+ total = unknown + known
+ output('Total number of warnings: <b>' + str(total) + '</b>')
+ if total < 1000:
+ output('(low count may indicate incremental build)')
+ output('<p>')
+
+def allpatterns(cat):
+ pats = ''
+ for i in cat['patterns']:
+ pats += i
+ pats += ' / '
+ return pats
+
+def descriptionfor(cat):
+ if cat['description'] != '':
+ return cat['description']
+ return allpatterns(cat)
+
+
+# show which warnings no longer occur
+def dumpfixed():
+ tablestarted = False
+ for i in warnpatterns:
+ if len(i['members']) == 0 and i['severity'] != severity.SKIP:
+ if tablestarted == False:
+ tablestarted = True
+ begintable(['Fixed warnings', 'No more occurences. Please consider turning these in to errors if possible, before they are reintroduced in to the build'], 'blue')
+ tablerow(i['description'] + ' (' + allpatterns(i) + ') ' + i['option'])
+ if tablestarted:
+ endtable()
+
+
+# dump a category, provided it is not marked as 'SKIP' and has more than 0 occurrences
+def dumpcategory(cat):
+ if cat['severity'] != severity.SKIP and len(cat['members']) != 0:
+ header = [descriptionfor(cat),str(len(cat['members'])) + ' occurences:']
+ if cat['option'] != '':
+ header[1:1] = [' (related option: ' + cat['option'] +')']
+ begintable(header, colorforseverity(cat['severity']))
+ for i in cat['members']:
+ tablerow(i)
+ endtable()
+
+
+# dump everything for a given severity
+def dumpseverity(sev):
+ for i in warnpatterns:
+ if i['severity'] == sev:
+ dumpcategory(i)
+
+
+def classifywarning(line):
+ for i in warnpatterns:
+ for pat in i['patterns']:
+ if re.match(pat, line):
+ i['members'].append(line)
+ return
+ else:
+ # If we end up here, there was a problem parsing the log
+ # probably caused by 'make -j' mixing the output from
+ # 2 or more concurrent compiles
+ pass
+
+
+
+infile = open(sys.argv[1], 'r')
+warnings = []
+
+platformversion = 'unknown'
+targetproduct = 'unknown'
+targetvariant = 'unknown'
+linecounter = 0
+
+warningpattern = re.compile('.* warning:.*')
+
+# read the log file and classify all the warnings
+lastmatchedline = ''
+for line in infile:
+ if warningpattern.match(line):
+ if line != lastmatchedline:
+ classifywarning(line)
+ lastmatchedline = line
+ else:
+ # save a little bit of time by only doing this for the first few lines
+ if linecounter < 50:
+ linecounter +=1
+ m = re.search('(?<=^PLATFORM_VERSION=).*', line)
+ if m != None:
+ platformversion = m.group(0)
+ m = re.search('(?<=^TARGET_PRODUCT=).*', line)
+ if m != None:
+ targetproduct = m.group(0)
+ m = re.search('(?<=^TARGET_BUILD_VARIANT=).*', line)
+ if m != None:
+ targetvariant = m.group(0)
+
+
+# dump the html output to stdout
+dumphtmlprologue('Warnings for ' + platformversion + ' - ' + targetproduct + ' - ' + targetvariant)
+dumpstats()
+dumpseverity(severity.FIXMENOW)
+dumpseverity(severity.HIGH)
+dumpseverity(severity.MEDIUM)
+dumpseverity(severity.LOW)
+dumpseverity(severity.HARMLESS)
+dumpseverity(severity.UNKNOWN)
+dumpfixed()
+
+
+
+
+
diff --git a/tools/zipalign/Android.mk b/tools/zipalign/Android.mk
index e23b699..f90a31c 100644
--- a/tools/zipalign/Android.mk
+++ b/tools/zipalign/Android.mk
@@ -8,7 +8,9 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- ZipAlign.cpp
+ ZipAlign.cpp \
+ ZipEntry.cpp \
+ ZipFile.cpp
LOCAL_C_INCLUDES += external/zlib
diff --git a/tools/zipalign/ZipAlign.cpp b/tools/zipalign/ZipAlign.cpp
index 058f9ed..eab2f04 100644
--- a/tools/zipalign/ZipAlign.cpp
+++ b/tools/zipalign/ZipAlign.cpp
@@ -16,7 +16,7 @@
/*
* Zip alignment tool
*/
-#include "utils/ZipFile.h"
+#include "ZipFile.h"
#include <stdlib.h>
#include <stdio.h>
diff --git a/tools/zipalign/ZipEntry.cpp b/tools/zipalign/ZipEntry.cpp
new file mode 100644
index 0000000..bed0333
--- /dev/null
+++ b/tools/zipalign/ZipEntry.cpp
@@ -0,0 +1,696 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Access to entries in a Zip archive.
+//
+
+#define LOG_TAG "zip"
+
+#include "ZipEntry.h"
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * Initialize a new ZipEntry structure from a FILE* positioned at a
+ * CentralDirectoryEntry.
+ *
+ * On exit, the file pointer will be at the start of the next CDE or
+ * at the EOCD.
+ */
+status_t ZipEntry::initFromCDE(FILE* fp)
+{
+ status_t result;
+ long posn;
+ bool hasDD;
+
+ //LOGV("initFromCDE ---\n");
+
+ /* read the CDE */
+ result = mCDE.read(fp);
+ if (result != NO_ERROR) {
+ LOGD("mCDE.read failed\n");
+ return result;
+ }
+
+ //mCDE.dump();
+
+ /* using the info in the CDE, go load up the LFH */
+ posn = ftell(fp);
+ if (fseek(fp, mCDE.mLocalHeaderRelOffset, SEEK_SET) != 0) {
+ LOGD("local header seek failed (%ld)\n",
+ mCDE.mLocalHeaderRelOffset);
+ return UNKNOWN_ERROR;
+ }
+
+ result = mLFH.read(fp);
+ if (result != NO_ERROR) {
+ LOGD("mLFH.read failed\n");
+ return result;
+ }
+
+ if (fseek(fp, posn, SEEK_SET) != 0)
+ return UNKNOWN_ERROR;
+
+ //mLFH.dump();
+
+ /*
+ * We *might* need to read the Data Descriptor at this point and
+ * integrate it into the LFH. If this bit is set, the CRC-32,
+ * compressed size, and uncompressed size will be zero. In practice
+ * these seem to be rare.
+ */
+ hasDD = (mLFH.mGPBitFlag & kUsesDataDescr) != 0;
+ if (hasDD) {
+ // do something clever
+ //LOGD("+++ has data descriptor\n");
+ }
+
+ /*
+ * Sanity-check the LFH. Note that this will fail if the "kUsesDataDescr"
+ * flag is set, because the LFH is incomplete. (Not a problem, since we
+ * prefer the CDE values.)
+ */
+ if (!hasDD && !compareHeaders()) {
+ LOGW("WARNING: header mismatch\n");
+ // keep going?
+ }
+
+ /*
+ * If the mVersionToExtract is greater than 20, we may have an
+ * issue unpacking the record -- could be encrypted, compressed
+ * with something we don't support, or use Zip64 extensions. We
+ * can defer worrying about that to when we're extracting data.
+ */
+
+ return NO_ERROR;
+}
+
+/*
+ * Initialize a new entry. Pass in the file name and an optional comment.
+ *
+ * Initializes the CDE and the LFH.
+ */
+void ZipEntry::initNew(const char* fileName, const char* comment)
+{
+ assert(fileName != NULL && *fileName != '\0'); // name required
+
+ /* most fields are properly initialized by constructor */
+ mCDE.mVersionMadeBy = kDefaultMadeBy;
+ mCDE.mVersionToExtract = kDefaultVersion;
+ mCDE.mCompressionMethod = kCompressStored;
+ mCDE.mFileNameLength = strlen(fileName);
+ if (comment != NULL)
+ mCDE.mFileCommentLength = strlen(comment);
+ mCDE.mExternalAttrs = 0x81b60020; // matches what WinZip does
+
+ if (mCDE.mFileNameLength > 0) {
+ mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
+ strcpy((char*) mCDE.mFileName, fileName);
+ }
+ if (mCDE.mFileCommentLength > 0) {
+ /* TODO: stop assuming null-terminated ASCII here? */
+ mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
+ strcpy((char*) mCDE.mFileComment, comment);
+ }
+
+ copyCDEtoLFH();
+}
+
+/*
+ * Initialize a new entry, starting with the ZipEntry from a different
+ * archive.
+ *
+ * Initializes the CDE and the LFH.
+ */
+status_t ZipEntry::initFromExternal(const ZipFile* pZipFile,
+ const ZipEntry* pEntry)
+{
+ /*
+ * Copy everything in the CDE over, then fix up the hairy bits.
+ */
+ memcpy(&mCDE, &pEntry->mCDE, sizeof(mCDE));
+
+ if (mCDE.mFileNameLength > 0) {
+ mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
+ if (mCDE.mFileName == NULL)
+ return NO_MEMORY;
+ strcpy((char*) mCDE.mFileName, (char*)pEntry->mCDE.mFileName);
+ }
+ if (mCDE.mFileCommentLength > 0) {
+ mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
+ if (mCDE.mFileComment == NULL)
+ return NO_MEMORY;
+ strcpy((char*) mCDE.mFileComment, (char*)pEntry->mCDE.mFileComment);
+ }
+ if (mCDE.mExtraFieldLength > 0) {
+ /* we null-terminate this, though it may not be a string */
+ mCDE.mExtraField = new unsigned char[mCDE.mExtraFieldLength+1];
+ if (mCDE.mExtraField == NULL)
+ return NO_MEMORY;
+ memcpy(mCDE.mExtraField, pEntry->mCDE.mExtraField,
+ mCDE.mExtraFieldLength+1);
+ }
+
+ /* construct the LFH from the CDE */
+ copyCDEtoLFH();
+
+ /*
+ * The LFH "extra" field is independent of the CDE "extra", so we
+ * handle it here.
+ */
+ assert(mLFH.mExtraField == NULL);
+ mLFH.mExtraFieldLength = pEntry->mLFH.mExtraFieldLength;
+ if (mLFH.mExtraFieldLength > 0) {
+ mLFH.mExtraField = new unsigned char[mLFH.mExtraFieldLength+1];
+ if (mLFH.mExtraField == NULL)
+ return NO_MEMORY;
+ memcpy(mLFH.mExtraField, pEntry->mLFH.mExtraField,
+ mLFH.mExtraFieldLength+1);
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Insert pad bytes in the LFH by tweaking the "extra" field. This will
+ * potentially confuse something that put "extra" data in here earlier,
+ * but I can't find an actual problem.
+ */
+status_t ZipEntry::addPadding(int padding)
+{
+ if (padding <= 0)
+ return INVALID_OPERATION;
+
+ //LOGI("HEY: adding %d pad bytes to existing %d in %s\n",
+ // padding, mLFH.mExtraFieldLength, mCDE.mFileName);
+
+ if (mLFH.mExtraFieldLength > 0) {
+ /* extend existing field */
+ unsigned char* newExtra;
+
+ newExtra = new unsigned char[mLFH.mExtraFieldLength + padding];
+ if (newExtra == NULL)
+ return NO_MEMORY;
+ memset(newExtra + mLFH.mExtraFieldLength, 0, padding);
+ memcpy(newExtra, mLFH.mExtraField, mLFH.mExtraFieldLength);
+
+ delete[] mLFH.mExtraField;
+ mLFH.mExtraField = newExtra;
+ mLFH.mExtraFieldLength += padding;
+ } else {
+ /* create new field */
+ mLFH.mExtraField = new unsigned char[padding];
+ memset(mLFH.mExtraField, 0, padding);
+ mLFH.mExtraFieldLength = padding;
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Set the fields in the LFH equal to the corresponding fields in the CDE.
+ *
+ * This does not touch the LFH "extra" field.
+ */
+void ZipEntry::copyCDEtoLFH(void)
+{
+ mLFH.mVersionToExtract = mCDE.mVersionToExtract;
+ mLFH.mGPBitFlag = mCDE.mGPBitFlag;
+ mLFH.mCompressionMethod = mCDE.mCompressionMethod;
+ mLFH.mLastModFileTime = mCDE.mLastModFileTime;
+ mLFH.mLastModFileDate = mCDE.mLastModFileDate;
+ mLFH.mCRC32 = mCDE.mCRC32;
+ mLFH.mCompressedSize = mCDE.mCompressedSize;
+ mLFH.mUncompressedSize = mCDE.mUncompressedSize;
+ mLFH.mFileNameLength = mCDE.mFileNameLength;
+ // the "extra field" is independent
+
+ delete[] mLFH.mFileName;
+ if (mLFH.mFileNameLength > 0) {
+ mLFH.mFileName = new unsigned char[mLFH.mFileNameLength+1];
+ strcpy((char*) mLFH.mFileName, (const char*) mCDE.mFileName);
+ } else {
+ mLFH.mFileName = NULL;
+ }
+}
+
+/*
+ * Set some information about a file after we add it.
+ */
+void ZipEntry::setDataInfo(long uncompLen, long compLen, unsigned long crc32,
+ int compressionMethod)
+{
+ mCDE.mCompressionMethod = compressionMethod;
+ mCDE.mCRC32 = crc32;
+ mCDE.mCompressedSize = compLen;
+ mCDE.mUncompressedSize = uncompLen;
+ mCDE.mCompressionMethod = compressionMethod;
+ if (compressionMethod == kCompressDeflated) {
+ mCDE.mGPBitFlag |= 0x0002; // indicates maximum compression used
+ }
+ copyCDEtoLFH();
+}
+
+/*
+ * See if the data in mCDE and mLFH match up. This is mostly useful for
+ * debugging these classes, but it can be used to identify damaged
+ * archives.
+ *
+ * Returns "false" if they differ.
+ */
+bool ZipEntry::compareHeaders(void) const
+{
+ if (mCDE.mVersionToExtract != mLFH.mVersionToExtract) {
+ LOGV("cmp: VersionToExtract\n");
+ return false;
+ }
+ if (mCDE.mGPBitFlag != mLFH.mGPBitFlag) {
+ LOGV("cmp: GPBitFlag\n");
+ return false;
+ }
+ if (mCDE.mCompressionMethod != mLFH.mCompressionMethod) {
+ LOGV("cmp: CompressionMethod\n");
+ return false;
+ }
+ if (mCDE.mLastModFileTime != mLFH.mLastModFileTime) {
+ LOGV("cmp: LastModFileTime\n");
+ return false;
+ }
+ if (mCDE.mLastModFileDate != mLFH.mLastModFileDate) {
+ LOGV("cmp: LastModFileDate\n");
+ return false;
+ }
+ if (mCDE.mCRC32 != mLFH.mCRC32) {
+ LOGV("cmp: CRC32\n");
+ return false;
+ }
+ if (mCDE.mCompressedSize != mLFH.mCompressedSize) {
+ LOGV("cmp: CompressedSize\n");
+ return false;
+ }
+ if (mCDE.mUncompressedSize != mLFH.mUncompressedSize) {
+ LOGV("cmp: UncompressedSize\n");
+ return false;
+ }
+ if (mCDE.mFileNameLength != mLFH.mFileNameLength) {
+ LOGV("cmp: FileNameLength\n");
+ return false;
+ }
+#if 0 // this seems to be used for padding, not real data
+ if (mCDE.mExtraFieldLength != mLFH.mExtraFieldLength) {
+ LOGV("cmp: ExtraFieldLength\n");
+ return false;
+ }
+#endif
+ if (mCDE.mFileName != NULL) {
+ if (strcmp((char*) mCDE.mFileName, (char*) mLFH.mFileName) != 0) {
+ LOGV("cmp: FileName\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+/*
+ * Convert the DOS date/time stamp into a UNIX time stamp.
+ */
+time_t ZipEntry::getModWhen(void) const
+{
+ struct tm parts;
+
+ parts.tm_sec = (mCDE.mLastModFileTime & 0x001f) << 1;
+ parts.tm_min = (mCDE.mLastModFileTime & 0x07e0) >> 5;
+ parts.tm_hour = (mCDE.mLastModFileTime & 0xf800) >> 11;
+ parts.tm_mday = (mCDE.mLastModFileDate & 0x001f);
+ parts.tm_mon = ((mCDE.mLastModFileDate & 0x01e0) >> 5) -1;
+ parts.tm_year = ((mCDE.mLastModFileDate & 0xfe00) >> 9) + 80;
+ parts.tm_wday = parts.tm_yday = 0;
+ parts.tm_isdst = -1; // DST info "not available"
+
+ return mktime(&parts);
+}
+
+/*
+ * Set the CDE/LFH timestamp from UNIX time.
+ */
+void ZipEntry::setModWhen(time_t when)
+{
+#ifdef HAVE_LOCALTIME_R
+ struct tm tmResult;
+#endif
+ time_t even;
+ unsigned short zdate, ztime;
+
+ struct tm* ptm;
+
+ /* round up to an even number of seconds */
+ even = (time_t)(((unsigned long)(when) + 1) & (~1));
+
+ /* expand */
+#ifdef HAVE_LOCALTIME_R
+ ptm = localtime_r(&even, &tmResult);
+#else
+ ptm = localtime(&even);
+#endif
+
+ int year;
+ year = ptm->tm_year;
+ if (year < 80)
+ year = 80;
+
+ zdate = (year - 80) << 9 | (ptm->tm_mon+1) << 5 | ptm->tm_mday;
+ ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
+
+ mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime;
+ mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate;
+}
+
+
+/*
+ * ===========================================================================
+ * ZipEntry::LocalFileHeader
+ * ===========================================================================
+ */
+
+/*
+ * Read a local file header.
+ *
+ * On entry, "fp" points to the signature at the start of the header.
+ * On exit, "fp" points to the start of data.
+ */
+status_t ZipEntry::LocalFileHeader::read(FILE* fp)
+{
+ status_t result = NO_ERROR;
+ unsigned char buf[kLFHLen];
+
+ assert(mFileName == NULL);
+ assert(mExtraField == NULL);
+
+ if (fread(buf, 1, kLFHLen, fp) != kLFHLen) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
+ LOGD("whoops: didn't find expected signature\n");
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ mVersionToExtract = ZipEntry::getShortLE(&buf[0x04]);
+ mGPBitFlag = ZipEntry::getShortLE(&buf[0x06]);
+ mCompressionMethod = ZipEntry::getShortLE(&buf[0x08]);
+ mLastModFileTime = ZipEntry::getShortLE(&buf[0x0a]);
+ mLastModFileDate = ZipEntry::getShortLE(&buf[0x0c]);
+ mCRC32 = ZipEntry::getLongLE(&buf[0x0e]);
+ mCompressedSize = ZipEntry::getLongLE(&buf[0x12]);
+ mUncompressedSize = ZipEntry::getLongLE(&buf[0x16]);
+ mFileNameLength = ZipEntry::getShortLE(&buf[0x1a]);
+ mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1c]);
+
+ // TODO: validate sizes
+
+ /* grab filename */
+ if (mFileNameLength != 0) {
+ mFileName = new unsigned char[mFileNameLength+1];
+ if (mFileName == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mFileName[mFileNameLength] = '\0';
+ }
+
+ /* grab extra field */
+ if (mExtraFieldLength != 0) {
+ mExtraField = new unsigned char[mExtraFieldLength+1];
+ if (mExtraField == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mExtraField[mExtraFieldLength] = '\0';
+ }
+
+bail:
+ return result;
+}
+
+/*
+ * Write a local file header.
+ */
+status_t ZipEntry::LocalFileHeader::write(FILE* fp)
+{
+ unsigned char buf[kLFHLen];
+
+ ZipEntry::putLongLE(&buf[0x00], kSignature);
+ ZipEntry::putShortLE(&buf[0x04], mVersionToExtract);
+ ZipEntry::putShortLE(&buf[0x06], mGPBitFlag);
+ ZipEntry::putShortLE(&buf[0x08], mCompressionMethod);
+ ZipEntry::putShortLE(&buf[0x0a], mLastModFileTime);
+ ZipEntry::putShortLE(&buf[0x0c], mLastModFileDate);
+ ZipEntry::putLongLE(&buf[0x0e], mCRC32);
+ ZipEntry::putLongLE(&buf[0x12], mCompressedSize);
+ ZipEntry::putLongLE(&buf[0x16], mUncompressedSize);
+ ZipEntry::putShortLE(&buf[0x1a], mFileNameLength);
+ ZipEntry::putShortLE(&buf[0x1c], mExtraFieldLength);
+
+ if (fwrite(buf, 1, kLFHLen, fp) != kLFHLen)
+ return UNKNOWN_ERROR;
+
+ /* write filename */
+ if (mFileNameLength != 0) {
+ if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
+ return UNKNOWN_ERROR;
+ }
+
+ /* write "extra field" */
+ if (mExtraFieldLength != 0) {
+ if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+
+/*
+ * Dump the contents of a LocalFileHeader object.
+ */
+void ZipEntry::LocalFileHeader::dump(void) const
+{
+ LOGD(" LocalFileHeader contents:\n");
+ LOGD(" versToExt=%u gpBits=0x%04x compression=%u\n",
+ mVersionToExtract, mGPBitFlag, mCompressionMethod);
+ LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
+ mLastModFileTime, mLastModFileDate, mCRC32);
+ LOGD(" compressedSize=%lu uncompressedSize=%lu\n",
+ mCompressedSize, mUncompressedSize);
+ LOGD(" filenameLen=%u extraLen=%u\n",
+ mFileNameLength, mExtraFieldLength);
+ if (mFileName != NULL)
+ LOGD(" filename: '%s'\n", mFileName);
+}
+
+
+/*
+ * ===========================================================================
+ * ZipEntry::CentralDirEntry
+ * ===========================================================================
+ */
+
+/*
+ * Read the central dir entry that appears next in the file.
+ *
+ * On entry, "fp" should be positioned on the signature bytes for the
+ * entry. On exit, "fp" will point at the signature word for the next
+ * entry or for the EOCD.
+ */
+status_t ZipEntry::CentralDirEntry::read(FILE* fp)
+{
+ status_t result = NO_ERROR;
+ unsigned char buf[kCDELen];
+
+ /* no re-use */
+ assert(mFileName == NULL);
+ assert(mExtraField == NULL);
+ assert(mFileComment == NULL);
+
+ if (fread(buf, 1, kCDELen, fp) != kCDELen) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
+ LOGD("Whoops: didn't find expected signature\n");
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ mVersionMadeBy = ZipEntry::getShortLE(&buf[0x04]);
+ mVersionToExtract = ZipEntry::getShortLE(&buf[0x06]);
+ mGPBitFlag = ZipEntry::getShortLE(&buf[0x08]);
+ mCompressionMethod = ZipEntry::getShortLE(&buf[0x0a]);
+ mLastModFileTime = ZipEntry::getShortLE(&buf[0x0c]);
+ mLastModFileDate = ZipEntry::getShortLE(&buf[0x0e]);
+ mCRC32 = ZipEntry::getLongLE(&buf[0x10]);
+ mCompressedSize = ZipEntry::getLongLE(&buf[0x14]);
+ mUncompressedSize = ZipEntry::getLongLE(&buf[0x18]);
+ mFileNameLength = ZipEntry::getShortLE(&buf[0x1c]);
+ mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1e]);
+ mFileCommentLength = ZipEntry::getShortLE(&buf[0x20]);
+ mDiskNumberStart = ZipEntry::getShortLE(&buf[0x22]);
+ mInternalAttrs = ZipEntry::getShortLE(&buf[0x24]);
+ mExternalAttrs = ZipEntry::getLongLE(&buf[0x26]);
+ mLocalHeaderRelOffset = ZipEntry::getLongLE(&buf[0x2a]);
+
+ // TODO: validate sizes and offsets
+
+ /* grab filename */
+ if (mFileNameLength != 0) {
+ mFileName = new unsigned char[mFileNameLength+1];
+ if (mFileName == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mFileName[mFileNameLength] = '\0';
+ }
+
+ /* read "extra field" */
+ if (mExtraFieldLength != 0) {
+ mExtraField = new unsigned char[mExtraFieldLength+1];
+ if (mExtraField == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mExtraField[mExtraFieldLength] = '\0';
+ }
+
+
+ /* grab comment, if any */
+ if (mFileCommentLength != 0) {
+ mFileComment = new unsigned char[mFileCommentLength+1];
+ if (mFileComment == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
+ {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mFileComment[mFileCommentLength] = '\0';
+ }
+
+bail:
+ return result;
+}
+
+/*
+ * Write a central dir entry.
+ */
+status_t ZipEntry::CentralDirEntry::write(FILE* fp)
+{
+ unsigned char buf[kCDELen];
+
+ ZipEntry::putLongLE(&buf[0x00], kSignature);
+ ZipEntry::putShortLE(&buf[0x04], mVersionMadeBy);
+ ZipEntry::putShortLE(&buf[0x06], mVersionToExtract);
+ ZipEntry::putShortLE(&buf[0x08], mGPBitFlag);
+ ZipEntry::putShortLE(&buf[0x0a], mCompressionMethod);
+ ZipEntry::putShortLE(&buf[0x0c], mLastModFileTime);
+ ZipEntry::putShortLE(&buf[0x0e], mLastModFileDate);
+ ZipEntry::putLongLE(&buf[0x10], mCRC32);
+ ZipEntry::putLongLE(&buf[0x14], mCompressedSize);
+ ZipEntry::putLongLE(&buf[0x18], mUncompressedSize);
+ ZipEntry::putShortLE(&buf[0x1c], mFileNameLength);
+ ZipEntry::putShortLE(&buf[0x1e], mExtraFieldLength);
+ ZipEntry::putShortLE(&buf[0x20], mFileCommentLength);
+ ZipEntry::putShortLE(&buf[0x22], mDiskNumberStart);
+ ZipEntry::putShortLE(&buf[0x24], mInternalAttrs);
+ ZipEntry::putLongLE(&buf[0x26], mExternalAttrs);
+ ZipEntry::putLongLE(&buf[0x2a], mLocalHeaderRelOffset);
+
+ if (fwrite(buf, 1, kCDELen, fp) != kCDELen)
+ return UNKNOWN_ERROR;
+
+ /* write filename */
+ if (mFileNameLength != 0) {
+ if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
+ return UNKNOWN_ERROR;
+ }
+
+ /* write "extra field" */
+ if (mExtraFieldLength != 0) {
+ if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
+ return UNKNOWN_ERROR;
+ }
+
+ /* write comment */
+ if (mFileCommentLength != 0) {
+ if (fwrite(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Dump the contents of a CentralDirEntry object.
+ */
+void ZipEntry::CentralDirEntry::dump(void) const
+{
+ LOGD(" CentralDirEntry contents:\n");
+ LOGD(" versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n",
+ mVersionMadeBy, mVersionToExtract, mGPBitFlag, mCompressionMethod);
+ LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
+ mLastModFileTime, mLastModFileDate, mCRC32);
+ LOGD(" compressedSize=%lu uncompressedSize=%lu\n",
+ mCompressedSize, mUncompressedSize);
+ LOGD(" filenameLen=%u extraLen=%u commentLen=%u\n",
+ mFileNameLength, mExtraFieldLength, mFileCommentLength);
+ LOGD(" diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n",
+ mDiskNumberStart, mInternalAttrs, mExternalAttrs,
+ mLocalHeaderRelOffset);
+
+ if (mFileName != NULL)
+ LOGD(" filename: '%s'\n", mFileName);
+ if (mFileComment != NULL)
+ LOGD(" comment: '%s'\n", mFileComment);
+}
+
diff --git a/tools/zipalign/ZipEntry.h b/tools/zipalign/ZipEntry.h
new file mode 100644
index 0000000..7f721b4
--- /dev/null
+++ b/tools/zipalign/ZipEntry.h
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Zip archive entries.
+//
+// The ZipEntry class is tightly meshed with the ZipFile class.
+//
+#ifndef __LIBS_ZIPENTRY_H
+#define __LIBS_ZIPENTRY_H
+
+#include <utils/Errors.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+namespace android {
+
+class ZipFile;
+
+/*
+ * ZipEntry objects represent a single entry in a Zip archive.
+ *
+ * You can use one of these to get or set information about an entry, but
+ * there are no functions here for accessing the data itself. (We could
+ * tuck a pointer to the ZipFile in here for convenience, but that raises
+ * the likelihood of using ZipEntry objects after discarding the ZipFile.)
+ *
+ * File information is stored in two places: next to the file data (the Local
+ * File Header, and possibly a Data Descriptor), and at the end of the file
+ * (the Central Directory Entry). The two must be kept in sync.
+ */
+class ZipEntry {
+public:
+ friend class ZipFile;
+
+ ZipEntry(void)
+ : mDeleted(false), mMarked(false)
+ {}
+ ~ZipEntry(void) {}
+
+ /*
+ * Returns "true" if the data is compressed.
+ */
+ bool isCompressed(void) const {
+ return mCDE.mCompressionMethod != kCompressStored;
+ }
+ int getCompressionMethod(void) const { return mCDE.mCompressionMethod; }
+
+ /*
+ * Return the uncompressed length.
+ */
+ off_t getUncompressedLen(void) const { return mCDE.mUncompressedSize; }
+
+ /*
+ * Return the compressed length. For uncompressed data, this returns
+ * the same thing as getUncompresesdLen().
+ */
+ off_t getCompressedLen(void) const { return mCDE.mCompressedSize; }
+
+ /*
+ * Return the absolute file offset of the start of the compressed or
+ * uncompressed data.
+ */
+ off_t getFileOffset(void) const {
+ return mCDE.mLocalHeaderRelOffset +
+ LocalFileHeader::kLFHLen +
+ mLFH.mFileNameLength +
+ mLFH.mExtraFieldLength;
+ }
+
+ /*
+ * Return the data CRC.
+ */
+ unsigned long getCRC32(void) const { return mCDE.mCRC32; }
+
+ /*
+ * Return file modification time in UNIX seconds-since-epoch.
+ */
+ time_t getModWhen(void) const;
+
+ /*
+ * Return the archived file name.
+ */
+ const char* getFileName(void) const { return (const char*) mCDE.mFileName; }
+
+ /*
+ * Application-defined "mark". Can be useful when synchronizing the
+ * contents of an archive with contents on disk.
+ */
+ bool getMarked(void) const { return mMarked; }
+ void setMarked(bool val) { mMarked = val; }
+
+ /*
+ * Some basic functions for raw data manipulation. "LE" means
+ * Little Endian.
+ */
+ static inline unsigned short getShortLE(const unsigned char* buf) {
+ return buf[0] | (buf[1] << 8);
+ }
+ static inline unsigned long getLongLE(const unsigned char* buf) {
+ return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+ }
+ static inline void putShortLE(unsigned char* buf, short val) {
+ buf[0] = (unsigned char) val;
+ buf[1] = (unsigned char) (val >> 8);
+ }
+ static inline void putLongLE(unsigned char* buf, long val) {
+ buf[0] = (unsigned char) val;
+ buf[1] = (unsigned char) (val >> 8);
+ buf[2] = (unsigned char) (val >> 16);
+ buf[3] = (unsigned char) (val >> 24);
+ }
+
+ /* defined for Zip archives */
+ enum {
+ kCompressStored = 0, // no compression
+ // shrunk = 1,
+ // reduced 1 = 2,
+ // reduced 2 = 3,
+ // reduced 3 = 4,
+ // reduced 4 = 5,
+ // imploded = 6,
+ // tokenized = 7,
+ kCompressDeflated = 8, // standard deflate
+ // Deflate64 = 9,
+ // lib imploded = 10,
+ // reserved = 11,
+ // bzip2 = 12,
+ };
+
+ /*
+ * Deletion flag. If set, the entry will be removed on the next
+ * call to "flush".
+ */
+ bool getDeleted(void) const { return mDeleted; }
+
+protected:
+ /*
+ * Initialize the structure from the file, which is pointing at
+ * our Central Directory entry.
+ */
+ status_t initFromCDE(FILE* fp);
+
+ /*
+ * Initialize the structure for a new file. We need the filename
+ * and comment so that we can properly size the LFH area. The
+ * filename is mandatory, the comment is optional.
+ */
+ void initNew(const char* fileName, const char* comment);
+
+ /*
+ * Initialize the structure with the contents of a ZipEntry from
+ * another file.
+ */
+ status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry);
+
+ /*
+ * Add some pad bytes to the LFH. We do this by adding or resizing
+ * the "extra" field.
+ */
+ status_t addPadding(int padding);
+
+ /*
+ * Set information about the data for this entry.
+ */
+ void setDataInfo(long uncompLen, long compLen, unsigned long crc32,
+ int compressionMethod);
+
+ /*
+ * Set the modification date.
+ */
+ void setModWhen(time_t when);
+
+ /*
+ * Return the offset of the local file header.
+ */
+ off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
+
+ /*
+ * Set the offset of the local file header, relative to the start of
+ * the current file.
+ */
+ void setLFHOffset(off_t offset) {
+ mCDE.mLocalHeaderRelOffset = (long) offset;
+ }
+
+ /* mark for deletion; used by ZipFile::remove() */
+ void setDeleted(void) { mDeleted = true; }
+
+private:
+ /* these are private and not defined */
+ ZipEntry(const ZipEntry& src);
+ ZipEntry& operator=(const ZipEntry& src);
+
+ /* returns "true" if the CDE and the LFH agree */
+ bool compareHeaders(void) const;
+ void copyCDEtoLFH(void);
+
+ bool mDeleted; // set if entry is pending deletion
+ bool mMarked; // app-defined marker
+
+ /*
+ * Every entry in the Zip archive starts off with one of these.
+ */
+ class LocalFileHeader {
+ public:
+ LocalFileHeader(void) :
+ mVersionToExtract(0),
+ mGPBitFlag(0),
+ mCompressionMethod(0),
+ mLastModFileTime(0),
+ mLastModFileDate(0),
+ mCRC32(0),
+ mCompressedSize(0),
+ mUncompressedSize(0),
+ mFileNameLength(0),
+ mExtraFieldLength(0),
+ mFileName(NULL),
+ mExtraField(NULL)
+ {}
+ virtual ~LocalFileHeader(void) {
+ delete[] mFileName;
+ delete[] mExtraField;
+ }
+
+ status_t read(FILE* fp);
+ status_t write(FILE* fp);
+
+ // unsigned long mSignature;
+ unsigned short mVersionToExtract;
+ unsigned short mGPBitFlag;
+ unsigned short mCompressionMethod;
+ unsigned short mLastModFileTime;
+ unsigned short mLastModFileDate;
+ unsigned long mCRC32;
+ unsigned long mCompressedSize;
+ unsigned long mUncompressedSize;
+ unsigned short mFileNameLength;
+ unsigned short mExtraFieldLength;
+ unsigned char* mFileName;
+ unsigned char* mExtraField;
+
+ enum {
+ kSignature = 0x04034b50,
+ kLFHLen = 30, // LocalFileHdr len, excl. var fields
+ };
+
+ void dump(void) const;
+ };
+
+ /*
+ * Every entry in the Zip archive has one of these in the "central
+ * directory" at the end of the file.
+ */
+ class CentralDirEntry {
+ public:
+ CentralDirEntry(void) :
+ mVersionMadeBy(0),
+ mVersionToExtract(0),
+ mGPBitFlag(0),
+ mCompressionMethod(0),
+ mLastModFileTime(0),
+ mLastModFileDate(0),
+ mCRC32(0),
+ mCompressedSize(0),
+ mUncompressedSize(0),
+ mFileNameLength(0),
+ mExtraFieldLength(0),
+ mFileCommentLength(0),
+ mDiskNumberStart(0),
+ mInternalAttrs(0),
+ mExternalAttrs(0),
+ mLocalHeaderRelOffset(0),
+ mFileName(NULL),
+ mExtraField(NULL),
+ mFileComment(NULL)
+ {}
+ virtual ~CentralDirEntry(void) {
+ delete[] mFileName;
+ delete[] mExtraField;
+ delete[] mFileComment;
+ }
+
+ status_t read(FILE* fp);
+ status_t write(FILE* fp);
+
+ // unsigned long mSignature;
+ unsigned short mVersionMadeBy;
+ unsigned short mVersionToExtract;
+ unsigned short mGPBitFlag;
+ unsigned short mCompressionMethod;
+ unsigned short mLastModFileTime;
+ unsigned short mLastModFileDate;
+ unsigned long mCRC32;
+ unsigned long mCompressedSize;
+ unsigned long mUncompressedSize;
+ unsigned short mFileNameLength;
+ unsigned short mExtraFieldLength;
+ unsigned short mFileCommentLength;
+ unsigned short mDiskNumberStart;
+ unsigned short mInternalAttrs;
+ unsigned long mExternalAttrs;
+ unsigned long mLocalHeaderRelOffset;
+ unsigned char* mFileName;
+ unsigned char* mExtraField;
+ unsigned char* mFileComment;
+
+ void dump(void) const;
+
+ enum {
+ kSignature = 0x02014b50,
+ kCDELen = 46, // CentralDirEnt len, excl. var fields
+ };
+ };
+
+ enum {
+ //kDataDescriptorSignature = 0x08074b50, // currently unused
+ kDataDescriptorLen = 16, // four 32-bit fields
+
+ kDefaultVersion = 20, // need deflate, nothing much else
+ kDefaultMadeBy = 0x0317, // 03=UNIX, 17=spec v2.3
+ kUsesDataDescr = 0x0008, // GPBitFlag bit 3
+ };
+
+ LocalFileHeader mLFH;
+ CentralDirEntry mCDE;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ZIPENTRY_H
diff --git a/tools/zipalign/ZipFile.cpp b/tools/zipalign/ZipFile.cpp
new file mode 100644
index 0000000..62c9383
--- /dev/null
+++ b/tools/zipalign/ZipFile.cpp
@@ -0,0 +1,1297 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Access to Zip archives.
+//
+
+#define LOG_TAG "zip"
+
+#include <utils/ZipUtils.h>
+#include <utils/Log.h>
+
+#include "ZipFile.h"
+
+#include <zlib.h>
+#define DEF_MEM_LEVEL 8 // normally in zutil.h?
+
+#include <memory.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * Some environments require the "b", some choke on it.
+ */
+#define FILE_OPEN_RO "rb"
+#define FILE_OPEN_RW "r+b"
+#define FILE_OPEN_RW_CREATE "w+b"
+
+/* should live somewhere else? */
+static status_t errnoToStatus(int err)
+{
+ if (err == ENOENT)
+ return NAME_NOT_FOUND;
+ else if (err == EACCES)
+ return PERMISSION_DENIED;
+ else
+ return UNKNOWN_ERROR;
+}
+
+/*
+ * Open a file and parse its guts.
+ */
+status_t ZipFile::open(const char* zipFileName, int flags)
+{
+ bool newArchive = false;
+
+ assert(mZipFp == NULL); // no reopen
+
+ if ((flags & kOpenTruncate))
+ flags |= kOpenCreate; // trunc implies create
+
+ if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite))
+ return INVALID_OPERATION; // not both
+ if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite)))
+ return INVALID_OPERATION; // not neither
+ if ((flags & kOpenCreate) && !(flags & kOpenReadWrite))
+ return INVALID_OPERATION; // create requires write
+
+ if (flags & kOpenTruncate) {
+ newArchive = true;
+ } else {
+ newArchive = (access(zipFileName, F_OK) != 0);
+ if (!(flags & kOpenCreate) && newArchive) {
+ /* not creating, must already exist */
+ LOGD("File %s does not exist", zipFileName);
+ return NAME_NOT_FOUND;
+ }
+ }
+
+ /* open the file */
+ const char* openflags;
+ if (flags & kOpenReadWrite) {
+ if (newArchive)
+ openflags = FILE_OPEN_RW_CREATE;
+ else
+ openflags = FILE_OPEN_RW;
+ } else {
+ openflags = FILE_OPEN_RO;
+ }
+ mZipFp = fopen(zipFileName, openflags);
+ if (mZipFp == NULL) {
+ int err = errno;
+ LOGD("fopen failed: %d\n", err);
+ return errnoToStatus(err);
+ }
+
+ status_t result;
+ if (!newArchive) {
+ /*
+ * Load the central directory. If that fails, then this probably
+ * isn't a Zip archive.
+ */
+ result = readCentralDir();
+ } else {
+ /*
+ * Newly-created. The EndOfCentralDir constructor actually
+ * sets everything to be the way we want it (all zeroes). We
+ * set mNeedCDRewrite so that we create *something* if the
+ * caller doesn't add any files. (We could also just unlink
+ * the file if it's brand new and nothing was added, but that's
+ * probably doing more than we really should -- the user might
+ * have a need for empty zip files.)
+ */
+ mNeedCDRewrite = true;
+ result = NO_ERROR;
+ }
+
+ if (flags & kOpenReadOnly)
+ mReadOnly = true;
+ else
+ assert(!mReadOnly);
+
+ return result;
+}
+
+/*
+ * Return the Nth entry in the archive.
+ */
+ZipEntry* ZipFile::getEntryByIndex(int idx) const
+{
+ if (idx < 0 || idx >= (int) mEntries.size())
+ return NULL;
+
+ return mEntries[idx];
+}
+
+/*
+ * Find an entry by name.
+ */
+ZipEntry* ZipFile::getEntryByName(const char* fileName) const
+{
+ /*
+ * Do a stupid linear string-compare search.
+ *
+ * There are various ways to speed this up, especially since it's rare
+ * to intermingle changes to the archive with "get by name" calls. We
+ * don't want to sort the mEntries vector itself, however, because
+ * it's used to recreate the Central Directory.
+ *
+ * (Hash table works, parallel list of pointers in sorted order is good.)
+ */
+ int idx;
+
+ for (idx = mEntries.size()-1; idx >= 0; idx--) {
+ ZipEntry* pEntry = mEntries[idx];
+ if (!pEntry->getDeleted() &&
+ strcmp(fileName, pEntry->getFileName()) == 0)
+ {
+ return pEntry;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Empty the mEntries vector.
+ */
+void ZipFile::discardEntries(void)
+{
+ int count = mEntries.size();
+
+ while (--count >= 0)
+ delete mEntries[count];
+
+ mEntries.clear();
+}
+
+
+/*
+ * Find the central directory and read the contents.
+ *
+ * The fun thing about ZIP archives is that they may or may not be
+ * readable from start to end. In some cases, notably for archives
+ * that were written to stdout, the only length information is in the
+ * central directory at the end of the file.
+ *
+ * Of course, the central directory can be followed by a variable-length
+ * comment field, so we have to scan through it backwards. The comment
+ * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
+ * itself, plus apparently sometimes people throw random junk on the end
+ * just for the fun of it.
+ *
+ * This is all a little wobbly. If the wrong value ends up in the EOCD
+ * area, we're hosed. This appears to be the way that everbody handles
+ * it though, so we're in pretty good company if this fails.
+ */
+status_t ZipFile::readCentralDir(void)
+{
+ status_t result = NO_ERROR;
+ unsigned char* buf = NULL;
+ off_t fileLength, seekStart;
+ long readAmount;
+ int i;
+
+ fseek(mZipFp, 0, SEEK_END);
+ fileLength = ftell(mZipFp);
+ rewind(mZipFp);
+
+ /* too small to be a ZIP archive? */
+ if (fileLength < EndOfCentralDir::kEOCDLen) {
+ LOGD("Length is %ld -- too small\n", (long)fileLength);
+ result = INVALID_OPERATION;
+ goto bail;
+ }
+
+ buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch];
+ if (buf == NULL) {
+ LOGD("Failure allocating %d bytes for EOCD search",
+ EndOfCentralDir::kMaxEOCDSearch);
+ result = NO_MEMORY;
+ goto bail;
+ }
+
+ if (fileLength > EndOfCentralDir::kMaxEOCDSearch) {
+ seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch;
+ readAmount = EndOfCentralDir::kMaxEOCDSearch;
+ } else {
+ seekStart = 0;
+ readAmount = (long) fileLength;
+ }
+ if (fseek(mZipFp, seekStart, SEEK_SET) != 0) {
+ LOGD("Failure seeking to end of zip at %ld", (long) seekStart);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /* read the last part of the file into the buffer */
+ if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) {
+ LOGD("short file? wanted %ld\n", readAmount);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /* find the end-of-central-dir magic */
+ for (i = readAmount - 4; i >= 0; i--) {
+ if (buf[i] == 0x50 &&
+ ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature)
+ {
+ LOGV("+++ Found EOCD at buf+%d\n", i);
+ break;
+ }
+ }
+ if (i < 0) {
+ LOGD("EOCD not found, not Zip\n");
+ result = INVALID_OPERATION;
+ goto bail;
+ }
+
+ /* extract eocd values */
+ result = mEOCD.readBuf(buf + i, readAmount - i);
+ if (result != NO_ERROR) {
+ LOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
+ goto bail;
+ }
+ //mEOCD.dump();
+
+ if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 ||
+ mEOCD.mNumEntries != mEOCD.mTotalNumEntries)
+ {
+ LOGD("Archive spanning not supported\n");
+ result = INVALID_OPERATION;
+ goto bail;
+ }
+
+ /*
+ * So far so good. "mCentralDirSize" is the size in bytes of the
+ * central directory, so we can just seek back that far to find it.
+ * We can also seek forward mCentralDirOffset bytes from the
+ * start of the file.
+ *
+ * We're not guaranteed to have the rest of the central dir in the
+ * buffer, nor are we guaranteed that the central dir will have any
+ * sort of convenient size. We need to skip to the start of it and
+ * read the header, then the other goodies.
+ *
+ * The only thing we really need right now is the file comment, which
+ * we're hoping to preserve.
+ */
+ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+ LOGD("Failure seeking to central dir offset %ld\n",
+ mEOCD.mCentralDirOffset);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /*
+ * Loop through and read the central dir entries.
+ */
+ LOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries);
+ int entry;
+ for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) {
+ ZipEntry* pEntry = new ZipEntry;
+
+ result = pEntry->initFromCDE(mZipFp);
+ if (result != NO_ERROR) {
+ LOGD("initFromCDE failed\n");
+ delete pEntry;
+ goto bail;
+ }
+
+ mEntries.add(pEntry);
+ }
+
+
+ /*
+ * If all went well, we should now be back at the EOCD.
+ */
+ {
+ unsigned char checkBuf[4];
+ if (fread(checkBuf, 1, 4, mZipFp) != 4) {
+ LOGD("EOCD check read failed\n");
+ result = INVALID_OPERATION;
+ goto bail;
+ }
+ if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) {
+ LOGD("EOCD read check failed\n");
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ LOGV("+++ EOCD read check passed\n");
+ }
+
+bail:
+ delete[] buf;
+ return result;
+}
+
+
+/*
+ * Add a new file to the archive.
+ *
+ * This requires creating and populating a ZipEntry structure, and copying
+ * the data into the file at the appropriate position. The "appropriate
+ * position" is the current location of the central directory, which we
+ * casually overwrite (we can put it back later).
+ *
+ * If we were concerned about safety, we would want to make all changes
+ * in a temp file and then overwrite the original after everything was
+ * safely written. Not really a concern for us.
+ */
+status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size,
+ const char* storageName, int sourceType, int compressionMethod,
+ ZipEntry** ppEntry)
+{
+ ZipEntry* pEntry = NULL;
+ status_t result = NO_ERROR;
+ long lfhPosn, startPosn, endPosn, uncompressedLen;
+ FILE* inputFp = NULL;
+ unsigned long crc;
+ time_t modWhen;
+
+ if (mReadOnly)
+ return INVALID_OPERATION;
+
+ assert(compressionMethod == ZipEntry::kCompressDeflated ||
+ compressionMethod == ZipEntry::kCompressStored);
+
+ /* make sure we're in a reasonable state */
+ assert(mZipFp != NULL);
+ assert(mEntries.size() == mEOCD.mTotalNumEntries);
+
+ /* make sure it doesn't already exist */
+ if (getEntryByName(storageName) != NULL)
+ return ALREADY_EXISTS;
+
+ if (!data) {
+ inputFp = fopen(fileName, FILE_OPEN_RO);
+ if (inputFp == NULL)
+ return errnoToStatus(errno);
+ }
+
+ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ pEntry = new ZipEntry;
+ pEntry->initNew(storageName, NULL);
+
+ /*
+ * From here on out, failures are more interesting.
+ */
+ mNeedCDRewrite = true;
+
+ /*
+ * Write the LFH, even though it's still mostly blank. We need it
+ * as a place-holder. In theory the LFH isn't necessary, but in
+ * practice some utilities demand it.
+ */
+ lfhPosn = ftell(mZipFp);
+ pEntry->mLFH.write(mZipFp);
+ startPosn = ftell(mZipFp);
+
+ /*
+ * Copy the data in, possibly compressing it as we go.
+ */
+ if (sourceType == ZipEntry::kCompressStored) {
+ if (compressionMethod == ZipEntry::kCompressDeflated) {
+ bool failed = false;
+ result = compressFpToFp(mZipFp, inputFp, data, size, &crc);
+ if (result != NO_ERROR) {
+ LOGD("compression failed, storing\n");
+ failed = true;
+ } else {
+ /*
+ * Make sure it has compressed "enough". This probably ought
+ * to be set through an API call, but I don't expect our
+ * criteria to change over time.
+ */
+ long src = inputFp ? ftell(inputFp) : size;
+ long dst = ftell(mZipFp) - startPosn;
+ if (dst + (dst / 10) > src) {
+ LOGD("insufficient compression (src=%ld dst=%ld), storing\n",
+ src, dst);
+ failed = true;
+ }
+ }
+
+ if (failed) {
+ compressionMethod = ZipEntry::kCompressStored;
+ if (inputFp) rewind(inputFp);
+ fseek(mZipFp, startPosn, SEEK_SET);
+ /* fall through to kCompressStored case */
+ }
+ }
+ /* handle "no compression" request, or failed compression from above */
+ if (compressionMethod == ZipEntry::kCompressStored) {
+ if (inputFp) {
+ result = copyFpToFp(mZipFp, inputFp, &crc);
+ } else {
+ result = copyDataToFp(mZipFp, data, size, &crc);
+ }
+ if (result != NO_ERROR) {
+ // don't need to truncate; happens in CDE rewrite
+ LOGD("failed copying data in\n");
+ goto bail;
+ }
+ }
+
+ // currently seeked to end of file
+ uncompressedLen = inputFp ? ftell(inputFp) : size;
+ } else if (sourceType == ZipEntry::kCompressDeflated) {
+ /* we should support uncompressed-from-compressed, but it's not
+ * important right now */
+ assert(compressionMethod == ZipEntry::kCompressDeflated);
+
+ bool scanResult;
+ int method;
+ long compressedLen;
+
+ scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen,
+ &compressedLen, &crc);
+ if (!scanResult || method != ZipEntry::kCompressDeflated) {
+ LOGD("this isn't a deflated gzip file?");
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL);
+ if (result != NO_ERROR) {
+ LOGD("failed copying gzip data in\n");
+ goto bail;
+ }
+ } else {
+ assert(false);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /*
+ * We could write the "Data Descriptor", but there doesn't seem to
+ * be any point since we're going to go back and write the LFH.
+ *
+ * Update file offsets.
+ */
+ endPosn = ftell(mZipFp); // seeked to end of compressed data
+
+ /*
+ * Success! Fill out new values.
+ */
+ pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc,
+ compressionMethod);
+ modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp));
+ pEntry->setModWhen(modWhen);
+ pEntry->setLFHOffset(lfhPosn);
+ mEOCD.mNumEntries++;
+ mEOCD.mTotalNumEntries++;
+ mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
+ mEOCD.mCentralDirOffset = endPosn;
+
+ /*
+ * Go back and write the LFH.
+ */
+ if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ pEntry->mLFH.write(mZipFp);
+
+ /*
+ * Add pEntry to the list.
+ */
+ mEntries.add(pEntry);
+ if (ppEntry != NULL)
+ *ppEntry = pEntry;
+ pEntry = NULL;
+
+bail:
+ if (inputFp != NULL)
+ fclose(inputFp);
+ delete pEntry;
+ return result;
+}
+
+/*
+ * Add an entry by copying it from another zip file. If "padding" is
+ * nonzero, the specified number of bytes will be added to the "extra"
+ * field in the header.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
+ int padding, ZipEntry** ppEntry)
+{
+ ZipEntry* pEntry = NULL;
+ status_t result;
+ long lfhPosn, endPosn;
+
+ if (mReadOnly)
+ return INVALID_OPERATION;
+
+ /* make sure we're in a reasonable state */
+ assert(mZipFp != NULL);
+ assert(mEntries.size() == mEOCD.mTotalNumEntries);
+
+ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ pEntry = new ZipEntry;
+ if (pEntry == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+
+ result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
+ if (result != NO_ERROR)
+ goto bail;
+ if (padding != 0) {
+ result = pEntry->addPadding(padding);
+ if (result != NO_ERROR)
+ goto bail;
+ }
+
+ /*
+ * From here on out, failures are more interesting.
+ */
+ mNeedCDRewrite = true;
+
+ /*
+ * Write the LFH. Since we're not recompressing the data, we already
+ * have all of the fields filled out.
+ */
+ lfhPosn = ftell(mZipFp);
+ pEntry->mLFH.write(mZipFp);
+
+ /*
+ * Copy the data over.
+ *
+ * If the "has data descriptor" flag is set, we want to copy the DD
+ * fields as well. This is a fixed-size area immediately following
+ * the data.
+ */
+ if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
+ {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ off_t copyLen;
+ copyLen = pSourceEntry->getCompressedLen();
+ if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
+ copyLen += ZipEntry::kDataDescriptorLen;
+
+ if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
+ != NO_ERROR)
+ {
+ LOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /*
+ * Update file offsets.
+ */
+ endPosn = ftell(mZipFp);
+
+ /*
+ * Success! Fill out new values.
+ */
+ pEntry->setLFHOffset(lfhPosn); // sets mCDE.mLocalHeaderRelOffset
+ mEOCD.mNumEntries++;
+ mEOCD.mTotalNumEntries++;
+ mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
+ mEOCD.mCentralDirOffset = endPosn;
+
+ /*
+ * Add pEntry to the list.
+ */
+ mEntries.add(pEntry);
+ if (ppEntry != NULL)
+ *ppEntry = pEntry;
+ pEntry = NULL;
+
+ result = NO_ERROR;
+
+bail:
+ delete pEntry;
+ return result;
+}
+
+/*
+ * Copy all of the bytes in "src" to "dst".
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the data.
+ */
+status_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32)
+{
+ unsigned char tmpBuf[32768];
+ size_t count;
+
+ *pCRC32 = crc32(0L, Z_NULL, 0);
+
+ while (1) {
+ count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp);
+ if (ferror(srcFp) || ferror(dstFp))
+ return errnoToStatus(errno);
+ if (count == 0)
+ break;
+
+ *pCRC32 = crc32(*pCRC32, tmpBuf, count);
+
+ if (fwrite(tmpBuf, 1, count, dstFp) != count) {
+ LOGD("fwrite %d bytes failed\n", (int) count);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Copy all of the bytes in "src" to "dst".
+ *
+ * On exit, "dstFp" will be seeked immediately past the data.
+ */
+status_t ZipFile::copyDataToFp(FILE* dstFp,
+ const void* data, size_t size, unsigned long* pCRC32)
+{
+ size_t count;
+
+ *pCRC32 = crc32(0L, Z_NULL, 0);
+ if (size > 0) {
+ *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size);
+ if (fwrite(data, 1, size, dstFp) != size) {
+ LOGD("fwrite %d bytes failed\n", (int) size);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Copy some of the bytes in "src" to "dst".
+ *
+ * If "pCRC32" is NULL, the CRC will not be computed.
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the data just written.
+ */
+status_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
+ unsigned long* pCRC32)
+{
+ unsigned char tmpBuf[32768];
+ size_t count;
+
+ if (pCRC32 != NULL)
+ *pCRC32 = crc32(0L, Z_NULL, 0);
+
+ while (length) {
+ long readSize;
+
+ readSize = sizeof(tmpBuf);
+ if (readSize > length)
+ readSize = length;
+
+ count = fread(tmpBuf, 1, readSize, srcFp);
+ if ((long) count != readSize) { // error or unexpected EOF
+ LOGD("fread %d bytes failed\n", (int) readSize);
+ return UNKNOWN_ERROR;
+ }
+
+ if (pCRC32 != NULL)
+ *pCRC32 = crc32(*pCRC32, tmpBuf, count);
+
+ if (fwrite(tmpBuf, 1, count, dstFp) != count) {
+ LOGD("fwrite %d bytes failed\n", (int) count);
+ return UNKNOWN_ERROR;
+ }
+
+ length -= readSize;
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Compress all of the data in "srcFp" and write it to "dstFp".
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the compressed data.
+ */
+status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp,
+ const void* data, size_t size, unsigned long* pCRC32)
+{
+ status_t result = NO_ERROR;
+ const size_t kBufSize = 32768;
+ unsigned char* inBuf = NULL;
+ unsigned char* outBuf = NULL;
+ z_stream zstream;
+ bool atEof = false; // no feof() aviailable yet
+ unsigned long crc;
+ int zerr;
+
+ /*
+ * Create an input buffer and an output buffer.
+ */
+ inBuf = new unsigned char[kBufSize];
+ outBuf = new unsigned char[kBufSize];
+ if (inBuf == NULL || outBuf == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+
+ /*
+ * Initialize the zlib stream.
+ */
+ memset(&zstream, 0, sizeof(zstream));
+ zstream.zalloc = Z_NULL;
+ zstream.zfree = Z_NULL;
+ zstream.opaque = Z_NULL;
+ zstream.next_in = NULL;
+ zstream.avail_in = 0;
+ zstream.next_out = outBuf;
+ zstream.avail_out = kBufSize;
+ zstream.data_type = Z_UNKNOWN;
+
+ zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION,
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+ if (zerr != Z_OK) {
+ result = UNKNOWN_ERROR;
+ if (zerr == Z_VERSION_ERROR) {
+ LOGE("Installed zlib is not compatible with linked version (%s)\n",
+ ZLIB_VERSION);
+ } else {
+ LOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr);
+ }
+ goto bail;
+ }
+
+ crc = crc32(0L, Z_NULL, 0);
+
+ /*
+ * Loop while we have data.
+ */
+ do {
+ size_t getSize;
+ int flush;
+
+ /* only read if the input buffer is empty */
+ if (zstream.avail_in == 0 && !atEof) {
+ LOGV("+++ reading %d bytes\n", (int)kBufSize);
+ if (data) {
+ getSize = size > kBufSize ? kBufSize : size;
+ memcpy(inBuf, data, getSize);
+ data = ((const char*)data) + getSize;
+ size -= getSize;
+ } else {
+ getSize = fread(inBuf, 1, kBufSize, srcFp);
+ if (ferror(srcFp)) {
+ LOGD("deflate read failed (errno=%d)\n", errno);
+ goto z_bail;
+ }
+ }
+ if (getSize < kBufSize) {
+ LOGV("+++ got %d bytes, EOF reached\n",
+ (int)getSize);
+ atEof = true;
+ }
+
+ crc = crc32(crc, inBuf, getSize);
+
+ zstream.next_in = inBuf;
+ zstream.avail_in = getSize;
+ }
+
+ if (atEof)
+ flush = Z_FINISH; /* tell zlib that we're done */
+ else
+ flush = Z_NO_FLUSH; /* more to come! */
+
+ zerr = deflate(&zstream, flush);
+ if (zerr != Z_OK && zerr != Z_STREAM_END) {
+ LOGD("zlib deflate call failed (zerr=%d)\n", zerr);
+ result = UNKNOWN_ERROR;
+ goto z_bail;
+ }
+
+ /* write when we're full or when we're done */
+ if (zstream.avail_out == 0 ||
+ (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize))
+ {
+ LOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf));
+ if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) !=
+ (size_t)(zstream.next_out - outBuf))
+ {
+ LOGD("write %d failed in deflate\n",
+ (int) (zstream.next_out - outBuf));
+ goto z_bail;
+ }
+
+ zstream.next_out = outBuf;
+ zstream.avail_out = kBufSize;
+ }
+ } while (zerr == Z_OK);
+
+ assert(zerr == Z_STREAM_END); /* other errors should've been caught */
+
+ *pCRC32 = crc;
+
+z_bail:
+ deflateEnd(&zstream); /* free up any allocated structures */
+
+bail:
+ delete[] inBuf;
+ delete[] outBuf;
+
+ return result;
+}
+
+/*
+ * Mark an entry as deleted.
+ *
+ * We will eventually need to crunch the file down, but if several files
+ * are being removed (perhaps as part of an "update" process) we can make
+ * things considerably faster by deferring the removal to "flush" time.
+ */
+status_t ZipFile::remove(ZipEntry* pEntry)
+{
+ /*
+ * Should verify that pEntry is actually part of this archive, and
+ * not some stray ZipEntry from a different file.
+ */
+
+ /* mark entry as deleted, and mark archive as dirty */
+ pEntry->setDeleted();
+ mNeedCDRewrite = true;
+ return NO_ERROR;
+}
+
+/*
+ * Flush any pending writes.
+ *
+ * In particular, this will crunch out deleted entries, and write the
+ * Central Directory and EOCD if we have stomped on them.
+ */
+status_t ZipFile::flush(void)
+{
+ status_t result = NO_ERROR;
+ long eocdPosn;
+ int i, count;
+
+ if (mReadOnly)
+ return INVALID_OPERATION;
+ if (!mNeedCDRewrite)
+ return NO_ERROR;
+
+ assert(mZipFp != NULL);
+
+ result = crunchArchive();
+ if (result != NO_ERROR)
+ return result;
+
+ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0)
+ return UNKNOWN_ERROR;
+
+ count = mEntries.size();
+ for (i = 0; i < count; i++) {
+ ZipEntry* pEntry = mEntries[i];
+ pEntry->mCDE.write(mZipFp);
+ }
+
+ eocdPosn = ftell(mZipFp);
+ mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset;
+
+ mEOCD.write(mZipFp);
+
+ /*
+ * If we had some stuff bloat up during compression and get replaced
+ * with plain files, or if we deleted some entries, there's a lot
+ * of wasted space at the end of the file. Remove it now.
+ */
+ if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) {
+ LOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno));
+ // not fatal
+ }
+
+ /* should we clear the "newly added" flag in all entries now? */
+
+ mNeedCDRewrite = false;
+ return NO_ERROR;
+}
+
+/*
+ * Crunch deleted files out of an archive by shifting the later files down.
+ *
+ * Because we're not using a temp file, we do the operation inside the
+ * current file.
+ */
+status_t ZipFile::crunchArchive(void)
+{
+ status_t result = NO_ERROR;
+ int i, count;
+ long delCount, adjust;
+
+#if 0
+ printf("CONTENTS:\n");
+ for (i = 0; i < (int) mEntries.size(); i++) {
+ printf(" %d: lfhOff=%ld del=%d\n",
+ i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted());
+ }
+ printf(" END is %ld\n", (long) mEOCD.mCentralDirOffset);
+#endif
+
+ /*
+ * Roll through the set of files, shifting them as appropriate. We
+ * could probably get a slight performance improvement by sliding
+ * multiple files down at once (because we could use larger reads
+ * when operating on batches of small files), but it's not that useful.
+ */
+ count = mEntries.size();
+ delCount = adjust = 0;
+ for (i = 0; i < count; i++) {
+ ZipEntry* pEntry = mEntries[i];
+ long span;
+
+ if (pEntry->getLFHOffset() != 0) {
+ long nextOffset;
+
+ /* Get the length of this entry by finding the offset
+ * of the next entry. Directory entries don't have
+ * file offsets, so we need to find the next non-directory
+ * entry.
+ */
+ nextOffset = 0;
+ for (int ii = i+1; nextOffset == 0 && ii < count; ii++)
+ nextOffset = mEntries[ii]->getLFHOffset();
+ if (nextOffset == 0)
+ nextOffset = mEOCD.mCentralDirOffset;
+ span = nextOffset - pEntry->getLFHOffset();
+
+ assert(span >= ZipEntry::LocalFileHeader::kLFHLen);
+ } else {
+ /* This is a directory entry. It doesn't have
+ * any actual file contents, so there's no need to
+ * move anything.
+ */
+ span = 0;
+ }
+
+ //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n",
+ // i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count);
+
+ if (pEntry->getDeleted()) {
+ adjust += span;
+ delCount++;
+
+ delete pEntry;
+ mEntries.removeAt(i);
+
+ /* adjust loop control */
+ count--;
+ i--;
+ } else if (span != 0 && adjust > 0) {
+ /* shuffle this entry back */
+ //printf("+++ Shuffling '%s' back %ld\n",
+ // pEntry->getFileName(), adjust);
+ result = filemove(mZipFp, pEntry->getLFHOffset() - adjust,
+ pEntry->getLFHOffset(), span);
+ if (result != NO_ERROR) {
+ /* this is why you use a temp file */
+ LOGE("error during crunch - archive is toast\n");
+ return result;
+ }
+
+ pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust);
+ }
+ }
+
+ /*
+ * Fix EOCD info. We have to wait until the end to do some of this
+ * because we use mCentralDirOffset to determine "span" for the
+ * last entry.
+ */
+ mEOCD.mCentralDirOffset -= adjust;
+ mEOCD.mNumEntries -= delCount;
+ mEOCD.mTotalNumEntries -= delCount;
+ mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
+
+ assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries);
+ assert(mEOCD.mNumEntries == count);
+
+ return result;
+}
+
+/*
+ * Works like memmove(), but on pieces of a file.
+ */
+status_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n)
+{
+ if (dst == src || n <= 0)
+ return NO_ERROR;
+
+ unsigned char readBuf[32768];
+
+ if (dst < src) {
+ /* shift stuff toward start of file; must read from start */
+ while (n != 0) {
+ size_t getSize = sizeof(readBuf);
+ if (getSize > n)
+ getSize = n;
+
+ if (fseek(fp, (long) src, SEEK_SET) != 0) {
+ LOGD("filemove src seek %ld failed\n", (long) src);
+ return UNKNOWN_ERROR;
+ }
+
+ if (fread(readBuf, 1, getSize, fp) != getSize) {
+ LOGD("filemove read %ld off=%ld failed\n",
+ (long) getSize, (long) src);
+ return UNKNOWN_ERROR;
+ }
+
+ if (fseek(fp, (long) dst, SEEK_SET) != 0) {
+ LOGD("filemove dst seek %ld failed\n", (long) dst);
+ return UNKNOWN_ERROR;
+ }
+
+ if (fwrite(readBuf, 1, getSize, fp) != getSize) {
+ LOGD("filemove write %ld off=%ld failed\n",
+ (long) getSize, (long) dst);
+ return UNKNOWN_ERROR;
+ }
+
+ src += getSize;
+ dst += getSize;
+ n -= getSize;
+ }
+ } else {
+ /* shift stuff toward end of file; must read from end */
+ assert(false); // write this someday, maybe
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+
+/*
+ * Get the modification time from a file descriptor.
+ */
+time_t ZipFile::getModTime(int fd)
+{
+ struct stat sb;
+
+ if (fstat(fd, &sb) < 0) {
+ LOGD("HEY: fstat on fd %d failed\n", fd);
+ return (time_t) -1;
+ }
+
+ return sb.st_mtime;
+}
+
+
+#if 0 /* this is a bad idea */
+/*
+ * Get a copy of the Zip file descriptor.
+ *
+ * We don't allow this if the file was opened read-write because we tend
+ * to leave the file contents in an uncertain state between calls to
+ * flush(). The duplicated file descriptor should only be valid for reads.
+ */
+int ZipFile::getZipFd(void) const
+{
+ if (!mReadOnly)
+ return INVALID_OPERATION;
+ assert(mZipFp != NULL);
+
+ int fd;
+ fd = dup(fileno(mZipFp));
+ if (fd < 0) {
+ LOGD("didn't work, errno=%d\n", errno);
+ }
+
+ return fd;
+}
+#endif
+
+
+#if 0
+/*
+ * Expand data.
+ */
+bool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const
+{
+ return false;
+}
+#endif
+
+// free the memory when you're done
+void* ZipFile::uncompress(const ZipEntry* entry)
+{
+ size_t unlen = entry->getUncompressedLen();
+ size_t clen = entry->getCompressedLen();
+
+ void* buf = malloc(unlen);
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ fseek(mZipFp, 0, SEEK_SET);
+
+ off_t offset = entry->getFileOffset();
+ if (fseek(mZipFp, offset, SEEK_SET) != 0) {
+ goto bail;
+ }
+
+ switch (entry->getCompressionMethod())
+ {
+ case ZipEntry::kCompressStored: {
+ ssize_t amt = fread(buf, 1, unlen, mZipFp);
+ if (amt != (ssize_t)unlen) {
+ goto bail;
+ }
+#if 0
+ printf("data...\n");
+ const unsigned char* p = (unsigned char*)buf;
+ const unsigned char* end = p+unlen;
+ for (int i=0; i<32 && p < end; i++) {
+ printf("0x%08x ", (int)(offset+(i*0x10)));
+ for (int j=0; j<0x10 && p < end; j++) {
+ printf(" %02x", *p);
+ p++;
+ }
+ printf("\n");
+ }
+#endif
+
+ }
+ break;
+ case ZipEntry::kCompressDeflated: {
+ if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) {
+ goto bail;
+ }
+ }
+ break;
+ default:
+ goto bail;
+ }
+ return buf;
+
+bail:
+ free(buf);
+ return NULL;
+}
+
+
+/*
+ * ===========================================================================
+ * ZipFile::EndOfCentralDir
+ * ===========================================================================
+ */
+
+/*
+ * Read the end-of-central-dir fields.
+ *
+ * "buf" should be positioned at the EOCD signature, and should contain
+ * the entire EOCD area including the comment.
+ */
+status_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len)
+{
+ /* don't allow re-use */
+ assert(mComment == NULL);
+
+ if (len < kEOCDLen) {
+ /* looks like ZIP file got truncated */
+ LOGD(" Zip EOCD: expected >= %d bytes, found %d\n",
+ kEOCDLen, len);
+ return INVALID_OPERATION;
+ }
+
+ /* this should probably be an assert() */
+ if (ZipEntry::getLongLE(&buf[0x00]) != kSignature)
+ return UNKNOWN_ERROR;
+
+ mDiskNumber = ZipEntry::getShortLE(&buf[0x04]);
+ mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]);
+ mNumEntries = ZipEntry::getShortLE(&buf[0x08]);
+ mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]);
+ mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]);
+ mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]);
+ mCommentLen = ZipEntry::getShortLE(&buf[0x14]);
+
+ // TODO: validate mCentralDirOffset
+
+ if (mCommentLen > 0) {
+ if (kEOCDLen + mCommentLen > len) {
+ LOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n",
+ kEOCDLen, mCommentLen, len);
+ return UNKNOWN_ERROR;
+ }
+ mComment = new unsigned char[mCommentLen];
+ memcpy(mComment, buf + kEOCDLen, mCommentLen);
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Write an end-of-central-directory section.
+ */
+status_t ZipFile::EndOfCentralDir::write(FILE* fp)
+{
+ unsigned char buf[kEOCDLen];
+
+ ZipEntry::putLongLE(&buf[0x00], kSignature);
+ ZipEntry::putShortLE(&buf[0x04], mDiskNumber);
+ ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir);
+ ZipEntry::putShortLE(&buf[0x08], mNumEntries);
+ ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries);
+ ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize);
+ ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset);
+ ZipEntry::putShortLE(&buf[0x14], mCommentLen);
+
+ if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen)
+ return UNKNOWN_ERROR;
+ if (mCommentLen > 0) {
+ assert(mComment != NULL);
+ if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen)
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Dump the contents of an EndOfCentralDir object.
+ */
+void ZipFile::EndOfCentralDir::dump(void) const
+{
+ LOGD(" EndOfCentralDir contents:\n");
+ LOGD(" diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n",
+ mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries);
+ LOGD(" centDirSize=%lu centDirOff=%lu commentLen=%u\n",
+ mCentralDirSize, mCentralDirOffset, mCommentLen);
+}
+
diff --git a/tools/zipalign/ZipFile.h b/tools/zipalign/ZipFile.h
new file mode 100644
index 0000000..dbbd072
--- /dev/null
+++ b/tools/zipalign/ZipFile.h
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// General-purpose Zip archive access. This class allows both reading and
+// writing to Zip archives, including deletion of existing entries.
+//
+#ifndef __LIBS_ZIPFILE_H
+#define __LIBS_ZIPFILE_H
+
+#include <utils/Vector.h>
+#include <utils/Errors.h>
+#include <stdio.h>
+
+#include "ZipEntry.h"
+
+namespace android {
+
+/*
+ * Manipulate a Zip archive.
+ *
+ * Some changes will not be visible in the until until "flush" is called.
+ *
+ * The correct way to update a file archive is to make all changes to a
+ * copy of the archive in a temporary file, and then unlink/rename over
+ * the original after everything completes. Because we're only interested
+ * in using this for packaging, we don't worry about such things. Crashing
+ * after making changes and before flush() completes could leave us with
+ * an unusable Zip archive.
+ */
+class ZipFile {
+public:
+ ZipFile(void)
+ : mZipFp(NULL), mReadOnly(false), mNeedCDRewrite(false)
+ {}
+ ~ZipFile(void) {
+ if (!mReadOnly)
+ flush();
+ if (mZipFp != NULL)
+ fclose(mZipFp);
+ discardEntries();
+ }
+
+ /*
+ * Open a new or existing archive.
+ */
+ typedef enum {
+ kOpenReadOnly = 0x01,
+ kOpenReadWrite = 0x02,
+ kOpenCreate = 0x04, // create if it doesn't exist
+ kOpenTruncate = 0x08, // if it exists, empty it
+ };
+ status_t open(const char* zipFileName, int flags);
+
+ /*
+ * Add a file to the end of the archive. Specify whether you want the
+ * library to try to store it compressed.
+ *
+ * If "storageName" is specified, the archive will use that instead
+ * of "fileName".
+ *
+ * If there is already an entry with the same name, the call fails.
+ * Existing entries with the same name must be removed first.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t add(const char* fileName, int compressionMethod,
+ ZipEntry** ppEntry)
+ {
+ return add(fileName, fileName, compressionMethod, ppEntry);
+ }
+ status_t add(const char* fileName, const char* storageName,
+ int compressionMethod, ZipEntry** ppEntry)
+ {
+ return addCommon(fileName, NULL, 0, storageName,
+ ZipEntry::kCompressStored,
+ compressionMethod, ppEntry);
+ }
+
+ /*
+ * Add a file that is already compressed with gzip.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t addGzip(const char* fileName, const char* storageName,
+ ZipEntry** ppEntry)
+ {
+ return addCommon(fileName, NULL, 0, storageName,
+ ZipEntry::kCompressDeflated,
+ ZipEntry::kCompressDeflated, ppEntry);
+ }
+
+ /*
+ * Add a file from an in-memory data buffer.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t add(const void* data, size_t size, const char* storageName,
+ int compressionMethod, ZipEntry** ppEntry)
+ {
+ return addCommon(NULL, data, size, storageName,
+ ZipEntry::kCompressStored,
+ compressionMethod, ppEntry);
+ }
+
+ /*
+ * Add an entry by copying it from another zip file. If "padding" is
+ * nonzero, the specified number of bytes will be added to the "extra"
+ * field in the header.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
+ int padding, ZipEntry** ppEntry);
+
+ /*
+ * Mark an entry as having been removed. It is not actually deleted
+ * from the archive or our internal data structures until flush() is
+ * called.
+ */
+ status_t remove(ZipEntry* pEntry);
+
+ /*
+ * Flush changes. If mNeedCDRewrite is set, this writes the central dir.
+ */
+ status_t flush(void);
+
+ /*
+ * Expand the data into the buffer provided. The buffer must hold
+ * at least <uncompressed len> bytes. Variation expands directly
+ * to a file.
+ *
+ * Returns "false" if an error was encountered in the compressed data.
+ */
+ //bool uncompress(const ZipEntry* pEntry, void* buf) const;
+ //bool uncompress(const ZipEntry* pEntry, FILE* fp) const;
+ void* uncompress(const ZipEntry* pEntry);
+
+ /*
+ * Get an entry, by name. Returns NULL if not found.
+ *
+ * Does not return entries pending deletion.
+ */
+ ZipEntry* getEntryByName(const char* fileName) const;
+
+ /*
+ * Get the Nth entry in the archive.
+ *
+ * This will return an entry that is pending deletion.
+ */
+ int getNumEntries(void) const { return mEntries.size(); }
+ ZipEntry* getEntryByIndex(int idx) const;
+
+private:
+ /* these are private and not defined */
+ ZipFile(const ZipFile& src);
+ ZipFile& operator=(const ZipFile& src);
+
+ class EndOfCentralDir {
+ public:
+ EndOfCentralDir(void) :
+ mDiskNumber(0),
+ mDiskWithCentralDir(0),
+ mNumEntries(0),
+ mTotalNumEntries(0),
+ mCentralDirSize(0),
+ mCentralDirOffset(0),
+ mCommentLen(0),
+ mComment(NULL)
+ {}
+ virtual ~EndOfCentralDir(void) {
+ delete[] mComment;
+ }
+
+ status_t readBuf(const unsigned char* buf, int len);
+ status_t write(FILE* fp);
+
+ //unsigned long mSignature;
+ unsigned short mDiskNumber;
+ unsigned short mDiskWithCentralDir;
+ unsigned short mNumEntries;
+ unsigned short mTotalNumEntries;
+ unsigned long mCentralDirSize;
+ unsigned long mCentralDirOffset; // offset from first disk
+ unsigned short mCommentLen;
+ unsigned char* mComment;
+
+ enum {
+ kSignature = 0x06054b50,
+ kEOCDLen = 22, // EndOfCentralDir len, excl. comment
+
+ kMaxCommentLen = 65535, // longest possible in ushort
+ kMaxEOCDSearch = kMaxCommentLen + EndOfCentralDir::kEOCDLen,
+
+ };
+
+ void dump(void) const;
+ };
+
+
+ /* read all entries in the central dir */
+ status_t readCentralDir(void);
+
+ /* crunch deleted entries out */
+ status_t crunchArchive(void);
+
+ /* clean up mEntries */
+ void discardEntries(void);
+
+ /* common handler for all "add" functions */
+ status_t addCommon(const char* fileName, const void* data, size_t size,
+ const char* storageName, int sourceType, int compressionMethod,
+ ZipEntry** ppEntry);
+
+ /* copy all of "srcFp" into "dstFp" */
+ status_t copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32);
+ /* copy all of "data" into "dstFp" */
+ status_t copyDataToFp(FILE* dstFp,
+ const void* data, size_t size, unsigned long* pCRC32);
+ /* copy some of "srcFp" into "dstFp" */
+ status_t copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
+ unsigned long* pCRC32);
+ /* like memmove(), but on parts of a single file */
+ status_t filemove(FILE* fp, off_t dest, off_t src, size_t n);
+ /* compress all of "srcFp" into "dstFp", using Deflate */
+ status_t compressFpToFp(FILE* dstFp, FILE* srcFp,
+ const void* data, size_t size, unsigned long* pCRC32);
+
+ /* get modification date from a file descriptor */
+ time_t getModTime(int fd);
+
+ /*
+ * We use stdio FILE*, which gives us buffering but makes dealing
+ * with files >2GB awkward. Until we support Zip64, we're fine.
+ */
+ FILE* mZipFp; // Zip file pointer
+
+ /* one of these per file */
+ EndOfCentralDir mEOCD;
+
+ /* did we open this read-only? */
+ bool mReadOnly;
+
+ /* set this when we trash the central dir */
+ bool mNeedCDRewrite;
+
+ /*
+ * One ZipEntry per entry in the zip file. I'm using pointers instead
+ * of objects because it's easier than making operator= work for the
+ * classes and sub-classes.
+ */
+ Vector<ZipEntry*> mEntries;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ZIPFILE_H