auto import from //branches/cupcake/...@126645

This commit is contained in:
The Android Open Source Project 2009-01-15 16:12:07 -08:00
parent 4f85cc54b3
commit 66339ad5ce
34 changed files with 1849 additions and 119 deletions

View File

@ -16,7 +16,7 @@
######################################################################
# This is a do-nothing template file. To use it, copy it to a file
# named "buildspec.mk" in the same directory, and uncomment or change
# named "buildspec.mk" in the root directory, and uncomment or change
# the variables necessary for your desired configuration. The file
# "buildspec.mk" should never be checked in to source control.
######################################################################

View File

@ -55,6 +55,10 @@ INTERNAL_CLEAN_BUILD_VERSION := 2
#$(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)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************

View File

@ -112,6 +112,7 @@ $(INSTALLED_BUILD_PROP_TARGET): $(BUILDINFO_SH) $(INTERNAL_BUILD_ID_MAKEFILE)
BUILD_VERSION_TAGS="$(BUILD_VERSION_TAGS)" \
TARGET_BOOTLOADER_BOARD_NAME="$(TARGET_BOOTLOADER_BOARD_NAME)" \
BUILD_FINGERPRINT="$(BUILD_FINGERPRINT)" \
TARGET_BOARD_PLATFORM="$(TARGET_BOARD_PLATFORM)" \
bash $(BUILDINFO_SH) > $@
$(hide) if [ -f $(TARGET_DEVICE_DIR)/system.prop ]; then \
cat $(TARGET_DEVICE_DIR)/system.prop >> $@; \
@ -399,6 +400,7 @@ endef
target_notice_file_txt := $(TARGET_OUT_INTERMEDIATES)/NOTICE.txt
target_notice_file_html := $(TARGET_OUT_INTERMEDIATES)/NOTICE.html
target_notice_file_html_gz := $(TARGET_OUT_INTERMEDIATES)/NOTICE.html.gz
tools_notice_file_txt := $(HOST_OUT_INTERMEDIATES)/NOTICE.txt
tools_notice_file_html := $(HOST_OUT_INTERMEDIATES)/NOTICE.html
@ -418,15 +420,17 @@ $(eval $(call combine-notice-files, \
$(HOST_OUT_NOTICE_FILES), \
$(ALL_DEFAULT_INSTALLED_MODULES)))
# Install the html file at /system/NOTICE.html.
# Install the html file at /system/etc/NOTICE.html.gz.
# This is not ideal, but this is very late in the game, after a lot of
# the module processing has already been done -- in fact, we used the
# fact that all that has been done to get the list of modules that we
# need notice files for.
installed_notice_html := $(TARGET_OUT)/etc/NOTICE.html
$(installed_notice_html): $(target_notice_file_html) | $(ACP)
$(target_notice_file_html_gz): $(target_notice_file_html)
gzip -c $< > $@
installed_notice_html_gz := $(TARGET_OUT)/etc/NOTICE.html.gz
$(installed_notice_html_gz): $(target_notice_file_html_gz) | $(ACP)
$(copy-file-to-target)
ALL_DEFAULT_INSTALLED_MODULES += $(installed_notice_html)
ALL_DEFAULT_INSTALLED_MODULES += $(installed_notice_html_gz)
# The kernel isn't really a module, so to get its module file in there, we
# make the target NOTICE files depend on this particular file too, which will

View File

@ -57,8 +57,8 @@ endif
LOCAL_MODULE_TAGS := $(sort $(LOCAL_MODULE_TAGS))
ifeq (,$(LOCAL_MODULE_TAGS))
# Modules without tags fall back to the default set
LOCAL_MODULE_TAGS := eng user development
# Modules without tags fall back to user (which is changed to user eng below)
LOCAL_MODULE_TAGS := user
#$(warning default tags: $(lastword $(filter-out config/% out/%,$(MAKEFILE_LIST))))
endif

View File

@ -81,6 +81,8 @@ LOCAL_ALLOW_UNDEFINED_SYMBOLS:=
LOCAL_DX_FLAGS:=
LOCAL_CERTIFICATE:=
LOCAL_SDK_VERSION:=
LOCAL_NO_EMMA_INSTRUMENT:=
LOCAL_NO_EMMA_COMPILE:=
# Trim MAKEFILE_LIST so that $(call my-dir) doesn't need to
# iterate over thousands of entries every time.

View File

@ -16,6 +16,7 @@ SRC_DOCS:= $(TOPDIR)docs
SRC_HEADERS := \
$(TOPDIR)system/core/include \
$(TOPDIR)hardware/libhardware/include \
$(TOPDIR)hardware/libhardware_legacy/include \
$(TOPDIR)hardware/ril/include \
$(TOPDIR)dalvik/libnativehelper/include \
$(TOPDIR)frameworks/base/include \
@ -171,6 +172,7 @@ KCM := $(HOST_OUT_EXECUTABLES)/kcm$(HOST_EXECUTABLE_SUFFIX)
ZIPALIGN := $(HOST_OUT_EXECUTABLES)/zipalign$(HOST_EXECUTABLE_SUFFIX)
FINDBUGS := prebuilt/common/findbugs/bin/findbugs
LOCALIZE := $(HOST_OUT_EXECUTABLES)/localize$(HOST_EXECUTABLE_SUFFIX)
EMMA_JAR := external/emma/lib/emma$(COMMON_JAVA_PACKAGE_SUFFIX)
# Binary prelinker/compressor tools
APRIORI := $(HOST_OUT_EXECUTABLES)/apriori$(HOST_EXECUTABLE_SUFFIX)
@ -292,3 +294,4 @@ TARGET_AVAILABLE_SDK_VERSIONS := current \
INTERNAL_PLATFORM_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/public_api.xml

View File

@ -243,9 +243,15 @@ endef
###########################################################
define find-subdir-assets
$(if $(1),$(patsubst ./%,%, \
$(shell if [ -d $(1) ] ; then cd $(1) ; find ./ -type f -and -not -type l ; fi)), \
$(warning Empty argument supplied to find-subdir-assets) \
$(if $(1),\
$(patsubst ./%,%, $(foreach dir,$(1),\
$(shell if [ -d $(dir) ] ; then\
cd $(dir) ; find ./ -type f -and -not -type l ;\
fi \
) \
)) \
, \
$(warning Empty argument supplied to find-subdir-assets) \
)
endef
@ -1135,7 +1141,7 @@ $(hide) tr ' ' '\n' < $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list \
$(hide) $(TARGET_JAVAC) -encoding ascii $(PRIVATE_BOOTCLASSPATH) \
$(addprefix -classpath ,$(strip \
$(call normalize-path-list,$(PRIVATE_ALL_JAVA_LIBRARIES)))) \
-g $(xlint_unchecked) \
$(strip $(PRIVATE_JAVAC_DEBUG_FLAGS)) $(xlint_unchecked) \
-extdirs "" -d $(PRIVATE_CLASS_INTERMEDIATES_DIR) \
\@$(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq \
|| ( rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR) ; exit 41 )
@ -1147,6 +1153,11 @@ $(hide) jar $(if $(strip $(PRIVATE_JAR_MANIFEST)),-cfm,-cf) \
@rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR)
endef
define transform-classes.jar-to-emma
$(hide) java -classpath $(EMMA_JAR) emma instr -outmode fullcopy -outfile \
$(PRIVATE_EMMA_COVERAGE_FILE) -ip $< -d $(PRIVATE_EMMA_INTERMEDIATES_DIR)
endef
#TODO: use a smaller -Xmx value for most libraries;
# only core.jar and framework.jar need a heap this big.
define transform-classes.jar-to-dex
@ -1477,3 +1488,4 @@ include $(BUILD_SYSTEM)/distdir.mk
# sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
# -e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
# rm -f $*.d

View File

@ -66,24 +66,70 @@ ifneq (,$(strip $(all_java_sources)))
# variable definitions.
full_classes_jar := $(intermediates.COMMON)/classes.jar
# Emma source code coverage
ifneq ($(EMMA_INSTRUMENT),true)
LOCAL_NO_EMMA_INSTRUMENT := true
LOCAL_NO_EMMA_COMPILE := true
endif
ifneq ($(LOCAL_NO_EMMA_COMPILE),true)
# If you instrument class files that have local variable debug information in
# them emma does not correctly maintain the local variable table.
# This will cause an error when you try to convert the class files for Android.
# The workaround for this to compile the java classes with only
# line and source debug information, not local information.
full_classes_compiled_name_jar := classes-no-debug-var.jar
$(full_classes_compiled_jar): PRIVATE_JAVAC_DEBUG_FLAGS := -g:{lines,source}
else
# when emma is off, compile with the default flags, which contain full debug
# info
full_classes_compiled_name_jar := classes-full-debug.jar
$(full_classes_compiled_jar): PRIVATE_JAVAC_DEBUG_FLAGS := -g
endif
# Compile the java files to a .jar file.
# This intentionally depends on java_sources, not all_java_sources.
# Deps for generated source files must be handled separately,
# via deps on the target that generates the sources.
full_classes_compiled_jar := $(intermediates.COMMON)/classes-compiled.jar
full_classes_compiled_jar := $(intermediates.COMMON)/$(full_classes_compiled_name_jar)
$(full_classes_compiled_jar): $(java_sources) $(full_java_lib_deps)
$(transform-java-to-classes.jar)
emma_intermediates_dir := $(intermediates.COMMON)/emma_out
# the 'lib/$(full_classes_compiled_name_jar)' portion of this path is fixed in
# the emma tool
full_classes_emma_jar := $(emma_intermediates_dir)/lib/$(full_classes_compiled_name_jar)
ifeq ($(LOCAL_IS_STATIC_JAVA_LIBRARY),true)
# Skip adding emma instrumentation to class files if this is a static library,
# since it will be instrumented by the package that includes it
LOCAL_NO_EMMA_INSTRUMENT:= true
endif
ifneq ($(LOCAL_NO_EMMA_INSTRUMENT),true)
$(full_classes_emma_jar): PRIVATE_EMMA_COVERAGE_FILE := $(intermediates.COMMON)/coverage.em
$(full_classes_emma_jar): PRIVATE_EMMA_INTERMEDIATES_DIR := $(emma_intermediates_dir)
# this rule will generate both $(PRIVATE_EMMA_COVERAGE_FILE) and
# $(full_classes_emma_jar)
$(full_classes_emma_jar): $(full_classes_compiled_jar)
$(transform-classes.jar-to-emma)
$(PRIVATE_EMMA_COVERAGE_FILE): $(full_classes_emma_jar)
else
$(full_classes_emma_jar): $(full_classes_compiled_jar) | $(ACP)
@echo Copying $<
$(copy-file-to-target)
endif
# Run jarjar if necessary, otherwise just copy the file. This is the last
# part of this step, so the output of this command is full_classes_jar.
full_classes_jarjar_jar := $(full_classes_jar)
ifneq ($(strip $(LOCAL_JARJAR_RULES)),)
$(full_classes_jarjar_jar): PRIVATE_JARJAR_RULES := $(LOCAL_JARJAR_RULES)
$(full_classes_jarjar_jar): $(full_classes_compiled_jar) | jarjar
$(full_classes_jarjar_jar): $(full_classes_emma_jar) | jarjar
@echo JarJar: $@
$(hide) $(JARJAR) process $(PRIVATE_JARJAR_RULES) $< $@
else
$(full_classes_jarjar_jar): $(full_classes_compiled_jar) | $(ACP)
$(full_classes_jarjar_jar): $(full_classes_emma_jar) | $(ACP)
@echo Copying: $@
$(hide) $(ACP) $< $@
endif

View File

@ -165,7 +165,7 @@ ifneq ($(filter sdk,$(MAKECMDGOALS)),)
ifneq ($(words $(filter-out $(INTERNAL_MODIFIER_TARGETS),$(MAKECMDGOALS))),1)
$(error The 'sdk' target may not be specified with any other targets)
endif
override_build_tags := development
override_build_tags := user
ADDITIONAL_BUILD_PROPERTIES += xmpp.auto-presence=true
ADDITIONAL_BUILD_PROPERTIES += ro.config.nocheckin=yes
else # !sdk
@ -488,35 +488,12 @@ eng_MODULES := $(sort $(call get-tagged-modules,eng,restricted))
debug_MODULES := $(sort $(call get-tagged-modules,debug,restricted))
tests_MODULES := $(sort $(call get-tagged-modules,tests,restricted))
# Don't include any GNU targets in the SDK. It's ok (and necessary)
# to build the host tools, but nothing that's going to be installed
# on the target (including static libraries).
all_development_MODULES := \
$(sort $(call get-tagged-modules,development,restricted))
target_gnu_MODULES := \
$(filter \
$(TARGET_OUT_INTERMEDIATES)/% \
$(TARGET_OUT)/% \
$(TARGET_OUT_DATA)/%, \
$(sort $(call get-tagged-modules,gnu)))
#$(info Removing from development:)$(foreach d,$(target_gnu_MODULES),$(info : $(d)))
development_MODULES := \
$(filter-out $(target_gnu_MODULES),$(all_development_MODULES))
droid_MODULES := $(sort $(Default_MODULES) \
$(eng_MODULES) \
$(debug_MODULES) \
$(user_MODULES) \
$(all_development_MODULES))
# The list of everything that's not on droid_MODULES.
# Also skip modules tagged as "restricted", which are
# never installed unless explicitly mentioned in
# CUSTOM_MODULES.
nonDroid_MODULES := $(sort $(call get-tagged-modules,\
$(ALL_MODULE_TAGS),\
eng debug user development restricted))
# THIS IS A TOTAL HACK AND SHOULD NOT BE USED AS AN EXAMPLE
modules_to_build := $(droid_MODULES)
ifneq ($(override_build_tags),)
@ -536,6 +513,22 @@ ifdef overridden_packages
endif
#$(error filtered out $(filter-out $(modules_to_build),$(old_modules_to_build)))
# Don't include any GNU targets in the SDK. It's ok (and necessary)
# to build the host tools, but nothing that's going to be installed
# on the target (including static libraries).
ifneq ($(filter sdk,$(MAKECMDGOALS)),)
target_gnu_MODULES := \
$(filter \
$(TARGET_OUT_INTERMEDIATES)/% \
$(TARGET_OUT)/% \
$(TARGET_OUT_DATA)/%, \
$(sort $(call get-tagged-modules,gnu)))
$(info Removing from sdk:)$(foreach d,$(target_gnu_MODULES),$(info : $(d)))
modules_to_build := \
$(filter-out $(target_gnu_MODULES),$(modules_to_build))
endif
# config/Makefile contains extra stuff that we don't want to pollute this
# top-level makefile with. It expects that ALL_DEFAULT_INSTALLED_MODULES
# contains everything that's built during the current make, but it also further

View File

@ -65,7 +65,8 @@ LOCAL_ASSET_DIR := $(LOCAL_PATH)/assets
endif
ifeq (,$(LOCAL_RESOURCE_DIR))
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_RESOURCE_DIR := $(wildcard $(addsuffix /$(LOCAL_PATH)/res, $(PRODUCT_PACKAGE_OVERLAYS))) \
$(LOCAL_PATH)/res
endif
# this is an app, so add the system libraries to the search path

View File

@ -39,6 +39,7 @@ pathmap_INCL := \
libdrm1:frameworks/base/media/libdrm/mobile1/include \
libdrm2:frameworks/base/media/libdrm/mobile2/include \
libhardware:hardware/libhardware/include \
libhardware_legacy:hardware/libhardware_legacy/include \
libhost:build/libs/host/include \
libm:bionic/libm/include \
libnativehelper:dalvik/libnativehelper/include \

View File

@ -75,7 +75,8 @@ libexpat.so 0xAAB00000
libwebcore.so 0xAA000000
libutils.so 0xA9D00000
libcameraservice.so 0xA9C80000
libhardware.so 0xA9C00000
libhardware.so 0xA9C70000
libhardware_legacy.so 0xA9C00000
libapp_process.so 0xA9B00000
libsystem_server.so 0xA9A00000
libime.so 0xA9800000

View File

@ -66,7 +66,8 @@ _product_var_list := \
PRODUCT_PROPERTY_OVERRIDES \
PRODUCT_COPY_FILES \
PRODUCT_OTA_PUBLIC_KEYS \
PRODUCT_POLICY
PRODUCT_POLICY \
PRODUCT_PACKAGE_OVERLAYS
define dump-product
$(info ==== $(1) ====)\

View File

@ -186,6 +186,10 @@ PRODUCT_COPY_FILES := \
PRODUCT_PROPERTY_OVERRIDES := \
$(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PROPERTY_OVERRIDES))
# Should we use the default resources or add any product specific overlays
PRODUCT_PACKAGE_OVERLAYS := \
$(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGE_OVERLAYS))
# Add the product-defined properties to the build properties.
ADDITIONAL_BUILD_PROPERTIES := \
$(ADDITIONAL_BUILD_PROPERTIES) \

View File

@ -1,10 +1,23 @@
PRODUCT_PROPERTY_OVERRIDES :=
PRODUCT_PACKAGES := \
AlarmClock \
ApiDemos \
Camera \
Development \
DrmProvider \
Email \
Fallback \
GPSEnable
GPSEnable \
Launcher \
Maps \
Music \
Mms \
Settings \
SdkSetup \
gpstest \
sqlite3
$(call inherit-product, $(SRC_TARGET_DIR)/product/core.mk)

View File

@ -0,0 +1,29 @@
# Copyright (C) 2008 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
ifneq ($(TARGET_SIMULATOR),true)
LOCAL_SRC_FILES := applypatch.c xdelta3.c bsdiff.c freecache.c
LOCAL_MODULE := applypatch
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_TAGS := eng
LOCAL_C_INCLUDES += external/xdelta3 external/bzip2
LOCAL_STATIC_LIBRARIES += libxdelta3 libmincrypt libbz libc
include $(BUILD_EXECUTABLE)
endif # !TARGET_SIMULATOR

View File

@ -0,0 +1,482 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <errno.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <unistd.h>
#include "mincrypt/sha.h"
#include "applypatch.h"
// Read a file into memory; store it and its associated metadata in
// *file. Return 0 on success.
int LoadFileContents(const char* filename, FileContents* file) {
file->data = NULL;
if (stat(filename, &file->st) != 0) {
fprintf(stderr, "failed to stat \"%s\": %s\n", filename, strerror(errno));
return -1;
}
file->size = file->st.st_size;
file->data = malloc(file->size);
FILE* f = fopen(filename, "rb");
if (f == NULL) {
fprintf(stderr, "failed to open \"%s\": %s\n", filename, strerror(errno));
free(file->data);
return -1;
}
size_t bytes_read = fread(file->data, 1, file->size, f);
if (bytes_read != file->size) {
fprintf(stderr, "short read of \"%s\" (%d bytes of %d)\n",
filename, bytes_read, file->size);
free(file->data);
return -1;
}
fclose(f);
SHA(file->data, file->size, file->sha1);
return 0;
}
// Save the contents of the given FileContents object under the given
// filename. Return 0 on success.
int SaveFileContents(const char* filename, FileContents file) {
FILE* f = fopen(filename, "wb");
if (f == NULL) {
fprintf(stderr, "failed to open \"%s\" for write: %s\n",
filename, strerror(errno));
return -1;
}
size_t bytes_written = fwrite(file.data, 1, file.size, f);
if (bytes_written != file.size) {
fprintf(stderr, "short write of \"%s\" (%d bytes of %d)\n",
filename, bytes_written, file.size);
return -1;
}
fflush(f);
fsync(fileno(f));
fclose(f);
if (chmod(filename, file.st.st_mode) != 0) {
fprintf(stderr, "chmod of \"%s\" failed: %s\n", filename, strerror(errno));
return -1;
}
if (chown(filename, file.st.st_uid, file.st.st_gid) != 0) {
fprintf(stderr, "chown of \"%s\" failed: %s\n", filename, strerror(errno));
return -1;
}
return 0;
}
// Take a string 'str' of 40 hex digits and parse it into the 20
// byte array 'digest'. 'str' may contain only the digest or be of
// the form "<digest>:<anything>". Return 0 on success, -1 on any
// error.
int ParseSha1(const char* str, uint8_t* digest) {
int i;
const char* ps = str;
uint8_t* pd = digest;
for (i = 0; i < SHA_DIGEST_SIZE * 2; ++i, ++ps) {
int digit;
if (*ps >= '0' && *ps <= '9') {
digit = *ps - '0';
} else if (*ps >= 'a' && *ps <= 'f') {
digit = *ps - 'a' + 10;
} else if (*ps >= 'A' && *ps <= 'F') {
digit = *ps - 'A' + 10;
} else {
return -1;
}
if (i % 2 == 0) {
*pd = digit << 4;
} else {
*pd |= digit;
++pd;
}
}
if (*ps != '\0' && *ps != ':') return -1;
return 0;
}
// Parse arguments (which should be of the form "<sha1>" or
// "<sha1>:<filename>" into the array *patches, returning the number
// of Patch objects in *num_patches. Return 0 on success.
int ParseShaArgs(int argc, char** argv, Patch** patches, int* num_patches) {
*num_patches = argc;
*patches = malloc(*num_patches * sizeof(Patch));
int i;
for (i = 0; i < *num_patches; ++i) {
if (ParseSha1(argv[i], (*patches)[i].sha1) != 0) {
fprintf(stderr, "failed to parse sha1 \"%s\"\n", argv[i]);
return -1;
}
if (argv[i][SHA_DIGEST_SIZE*2] == '\0') {
(*patches)[i].patch_filename = NULL;
} else if (argv[i][SHA_DIGEST_SIZE*2] == ':') {
(*patches)[i].patch_filename = argv[i] + (SHA_DIGEST_SIZE*2+1);
} else {
fprintf(stderr, "failed to parse filename \"%s\"\n", argv[i]);
return -1;
}
}
return 0;
}
// Search an array of Patch objects for one matching the given sha1.
// Return the Patch object on success, or NULL if no match is found.
const Patch* FindMatchingPatch(uint8_t* sha1, Patch* patches, int num_patches) {
int i;
for (i = 0; i < num_patches; ++i) {
if (memcmp(patches[i].sha1, sha1, SHA_DIGEST_SIZE) == 0) {
return patches+i;
}
}
return NULL;
}
// Returns 0 if the contents of the file (argv[2]) or the cached file
// match any of the sha1's on the command line (argv[3:]). Returns
// nonzero otherwise.
int CheckMode(int argc, char** argv) {
if (argc < 3) {
fprintf(stderr, "no filename given\n");
return 2;
}
int num_patches;
Patch* patches;
if (ParseShaArgs(argc-3, argv+3, &patches, &num_patches) != 0) { return 1; }
FileContents file;
file.data = NULL;
if (LoadFileContents(argv[2], &file) != 0 ||
FindMatchingPatch(file.sha1, patches, num_patches) == NULL) {
fprintf(stderr, "file \"%s\" doesn't have any of expected "
"sha1 sums; checking cache\n", argv[2]);
free(file.data);
// If the source file is missing or corrupted, it might be because
// we were killed in the middle of patching it. A copy of it
// should have been made in CACHE_TEMP_SOURCE. If that file
// exists and matches the sha1 we're looking for, the check still
// passes.
if (LoadFileContents(CACHE_TEMP_SOURCE, &file) != 0) {
fprintf(stderr, "failed to load cache file\n");
return 1;
}
if (FindMatchingPatch(file.sha1, patches, num_patches) == NULL) {
fprintf(stderr, "cache bits don't match any sha1 for \"%s\"\n",
argv[2]);
return 1;
}
}
free(file.data);
return 0;
}
int ShowLicenses() {
puts("\nCopyright (C) 2008 The Android Open Source Project\n"
"\n"
"This program is free software; you can redistribute it and/or\n"
"modify it under the terms of the GNU General Public License\n"
"as published by the Free Software Foundation; either version 2\n"
"of the License, or (at your option) any later version.\n"
"\n"
"This program is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n"
"\n"
"You should have received a copy of the GNU General Public License\n"
"along with this program; if not, write to the Free Software\n"
"Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\n"
"02110-1301, USA.\n"
"\n------------------\n"
);
ShowBSDiffLicense();
return 0;
}
// Return the amount of free space (in bytes) on the filesystem
// containing filename. filename must exist. Return -1 on error.
size_t FreeSpaceForFile(const char* filename) {
struct statfs sf;
if (statfs(filename, &sf) != 0) {
fprintf(stderr, "failed to statfs %s: %s\n", filename, strerror(errno));
return -1;
}
return sf.f_bsize * sf.f_bfree;
}
// This program applies binary patches to files in a way that is safe
// (the original file is not touched until we have the desired
// replacement for it) and idempotent (it's okay to run this program
// multiple times).
//
// - if the sha1 hash of <file> is <tgt-sha1>, does nothing and exits
// successfully.
//
// - otherwise, if the sha1 hash of <file> is <src-sha1>, applies the
// xdelta3 or bsdiff <patch> to <file> to produce a new file (the
// type of patch is automatically detected from the file header).
// If that new file has sha1 hash <tgt-sha1>, moves it to replace
// <file>, and exits successfully.
//
// - otherwise, or if any error is encountered, exits with non-zero
// status.
int main(int argc, char** argv) {
if (argc < 2) {
usage:
fprintf(stderr, "usage: %s <file> <tgt-sha1> <tgt-size> [<src-sha1>:<patch> ...]\n"
" or %s -c <file> [<sha1> ...]\n"
" or %s -s <bytes>\n"
" or %s -l\n",
argv[0], argv[0], argv[0], argv[0]);
return 1;
}
if (strncmp(argv[1], "-l", 3) == 0) {
return ShowLicenses();
}
if (strncmp(argv[1], "-c", 3) == 0) {
return CheckMode(argc, argv);
}
if (strncmp(argv[1], "-s", 3) == 0) {
if (argc != 3) {
goto usage;
}
size_t bytes = strtol(argv[2], NULL, 10);
if (MakeFreeSpaceOnCache(bytes) < 0) {
printf("unable to make %ld bytes available on /cache\n", (long)bytes);
return 1;
} else {
return 0;
}
}
uint8_t target_sha1[SHA_DIGEST_SIZE];
const char* source_filename = argv[1];
// assume that source_filename (eg "/system/app/Foo.apk") is located
// on the same filesystem as its top-level directory ("/system").
// We need something that exists for calling statfs().
char* source_fs = strdup(argv[1]);
char* slash = strchr(source_fs+1, '/');
if (slash != NULL) {
*slash = '\0';
}
if (ParseSha1(argv[2], target_sha1) != 0) {
fprintf(stderr, "failed to parse tgt-sha1 \"%s\"\n", argv[2]);
return 1;
}
unsigned long target_size = strtoul(argv[3], NULL, 0);
int num_patches;
Patch* patches;
if (ParseShaArgs(argc-4, argv+4, &patches, &num_patches) < 0) { return 1; }
FileContents copy_file;
FileContents source_file;
const char* source_patch_filename = NULL;
const char* copy_patch_filename = NULL;
int made_copy = 0;
if (LoadFileContents(source_filename, &source_file) == 0) {
if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) {
// The early-exit case: the patch was already applied, this file
// has the desired hash, nothing for us to do.
fprintf(stderr, "\"%s\" is already target; no patch needed\n",
source_filename);
return 0;
}
const Patch* to_use =
FindMatchingPatch(source_file.sha1, patches, num_patches);
if (to_use != NULL) {
source_patch_filename = to_use->patch_filename;
}
}
if (source_patch_filename == NULL) {
free(source_file.data);
fprintf(stderr, "source file is bad; trying copy\n");
if (LoadFileContents(CACHE_TEMP_SOURCE, &copy_file) < 0) {
// fail.
fprintf(stderr, "failed to read copy file\n");
return 1;
}
const Patch* to_use =
FindMatchingPatch(copy_file.sha1, patches, num_patches);
if (to_use != NULL) {
copy_patch_filename = to_use->patch_filename;
}
if (copy_patch_filename == NULL) {
// fail.
fprintf(stderr, "copy file doesn't match source SHA-1s either\n");
return 1;
}
}
// Is there enough room in the target filesystem to hold the patched file?
size_t free_space = FreeSpaceForFile(source_fs);
int enough_space = free_space > (target_size * 3 / 2); // 50% margin of error
printf("target %ld bytes; free space %ld bytes; enough %d\n",
(long)target_size, (long)free_space, enough_space);
if (!enough_space && source_patch_filename != NULL) {
// Using the original source, but not enough free space. First
// copy the source file to cache, then delete it from the original
// location.
if (MakeFreeSpaceOnCache(source_file.size) < 0) {
fprintf(stderr, "not enough free space on /cache\n");
return 1;
}
if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) {
fprintf(stderr, "failed to back up source file\n");
return 1;
}
made_copy = 1;
unlink(source_filename);
size_t free_space = FreeSpaceForFile(source_fs);
printf("(now %ld bytes free for source)\n", (long)free_space);
}
FileContents* source_to_use;
const char* patch_filename;
if (source_patch_filename != NULL) {
source_to_use = &source_file;
patch_filename = source_patch_filename;
} else {
source_to_use = &copy_file;
patch_filename = copy_patch_filename;
}
// We write the decoded output to "<file>.patch".
char* outname = (char*)malloc(strlen(source_filename) + 10);
strcpy(outname, source_filename);
strcat(outname, ".patch");
FILE* output = fopen(outname, "wb");
if (output == NULL) {
fprintf(stderr, "failed to patch file %s: %s\n",
source_filename, strerror(errno));
return 1;
}
#define MAX_HEADER_LENGTH 8
unsigned char header[MAX_HEADER_LENGTH];
FILE* patchf = fopen(patch_filename, "rb");
if (patchf == NULL) {
fprintf(stderr, "failed to open patch file %s: %s\n",
patch_filename, strerror(errno));
return 1;
}
int header_bytes_read = fread(header, 1, MAX_HEADER_LENGTH, patchf);
fclose(patchf);
SHA_CTX ctx;
SHA_init(&ctx);
if (header_bytes_read >= 4 &&
header[0] == 0xd6 && header[1] == 0xc3 &&
header[2] == 0xc4 && header[3] == 0) {
// xdelta3 patches begin "VCD" (with the high bits set) followed
// by a zero byte (the version number).
int result = ApplyXDelta3Patch(source_to_use->data, source_to_use->size,
patch_filename, output, &ctx);
if (result != 0) {
fprintf(stderr, "ApplyXDelta3Patch failed\n");
return result;
}
} else if (header_bytes_read >= 8 &&
memcmp(header, "BSDIFF40", 8) == 0) {
int result = ApplyBSDiffPatch(source_to_use->data, source_to_use->size,
patch_filename, output, &ctx);
if (result != 0) {
fprintf(stderr, "ApplyBSDiffPatch failed\n");
return result;
}
} else {
fprintf(stderr, "Unknown patch file format");
return 1;
}
fflush(output);
fsync(fileno(output));
fclose(output);
const uint8_t* current_target_sha1 = SHA_final(&ctx);
if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_SIZE) != 0) {
fprintf(stderr, "patch did not produce expected sha1\n");
return 1;
}
// Give the .patch file the same owner, group, and mode of the
// original source file.
if (chmod(outname, source_to_use->st.st_mode) != 0) {
fprintf(stderr, "chmod of \"%s\" failed: %s\n", outname, strerror(errno));
return 1;
}
if (chown(outname, source_to_use->st.st_uid, source_to_use->st.st_gid) != 0) {
fprintf(stderr, "chown of \"%s\" failed: %s\n", outname, strerror(errno));
return 1;
}
// Finally, rename the .patch file to replace the original source file.
if (rename(outname, source_filename) != 0) {
fprintf(stderr, "rename of .patch to \"%s\" failed: %s\n",
source_filename, strerror(errno));
return 1;
}
// If this run of applypatch created the copy, and we're here, we
// can delete it.
if (made_copy) unlink(CACHE_TEMP_SOURCE);
// Success!
return 0;
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#ifndef _APPLYPATCH_H
#define _APPLYPATCH_H
#include "mincrypt/sha.h"
typedef struct _Patch {
uint8_t sha1[SHA_DIGEST_SIZE];
const char* patch_filename;
} Patch;
typedef struct _FileContents {
uint8_t sha1[SHA_DIGEST_SIZE];
unsigned char* data;
size_t size;
struct stat st;
} FileContents;
// When there isn't enough room on the target filesystem to hold the
// patched version of the file, we copy the original here and delete
// it to free up space. If the expected source file doesn't exist, or
// is corrupted, we look to see if this file contains the bits we want
// and use it as the source instead.
#define CACHE_TEMP_SOURCE "/cache/saved.file"
// applypatch.c
size_t FreeSpaceForFile(const char* filename);
// xdelta3.c
int ApplyXDelta3Patch(const unsigned char* old_data, ssize_t old_size,
const char* patch_filename,
FILE* output, SHA_CTX* ctx);
// bsdiff.c
void ShowBSDiffLicense();
int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
const char* patch_filename,
FILE* output, SHA_CTX* ctx);
// freecache.c
int MakeFreeSpaceOnCache(size_t bytes_needed);
#endif

299
tools/applypatch/applypatch.sh Executable file
View File

@ -0,0 +1,299 @@
#!/bin/bash
#
# A test suite for applypatch. Run in a client where you have done
# envsetup, choosecombo, etc.
#
# DO NOT RUN THIS ON A DEVICE YOU CARE ABOUT. It will mess up your
# system partition.
#
#
# TODO: find some way to get this run regularly along with the rest of
# the tests.
EMULATOR_PORT=5580
DATA_DIR=$ANDROID_BUILD_TOP/build/tools/applypatch/testdata
# This must be the filename that applypatch uses for its copies.
CACHE_TEMP_SOURCE=/cache/saved.file
# Put all binaries and files here. We use /cache because it's a
# temporary filesystem in the emulator; it's created fresh each time
# the emulator starts.
WORK_DIR=/system
# partition that WORK_DIR is located on, without the leading slash
WORK_FS=system
# ------------------------
tmpdir=$(mktemp -d)
emulator -wipe-data -noaudio -no-window -port $EMULATOR_PORT &
pid_emulator=$!
ADB="adb -s emulator-$EMULATOR_PORT "
echo "emulator is $pid_emulator; waiting for startup"
$ADB wait-for-device
echo "device is available"
$ADB remount
# free up enough space on the system partition for the test to run.
$ADB shell rm -r /system/media
# run a command on the device; exit with the exit status of the device
# command.
run_command() {
$ADB shell "$@" \; echo \$? | awk '{if (b) {print a}; a=$0; b=1} END {exit a}'
}
testname() {
echo
echo "$1"...
testname="$1"
}
fail() {
echo
echo FAIL: $testname
echo
kill $pid_emulator
exit 1
}
sha1() {
sha1sum $1 | awk '{print $1}'
}
free_space() {
run_command df | awk "/$1/ {print gensub(/K/, \"\", \"g\", \$6)}"
}
$ADB push $ANDROID_PRODUCT_OUT/system/bin/applypatch $WORK_DIR/applypatch
BAD1_SHA1=$(printf "%040x" $RANDOM)
BAD2_SHA1=$(printf "%040x" $RANDOM)
OLD_SHA1=$(sha1 $DATA_DIR/old.file)
NEW_SHA1=$(sha1 $DATA_DIR/new.file)
NEW_SIZE=$(stat -c %s $DATA_DIR/new.file)
# --------------- basic execution ----------------------
testname "usage message"
run_command $WORK_DIR/applypatch && fail
testname "display license"
run_command $WORK_DIR/applypatch -l | grep -q -i copyright || fail
# --------------- check mode ----------------------
$ADB push $DATA_DIR/old.file $WORK_DIR
testname "check mode single"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail
testname "check mode multiple"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail
testname "check mode failure"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 && fail
$ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE
# put some junk in the old file
run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail
testname "check mode cache (corrupted) single"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail
testname "check mode cache (corrupted) multiple"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail
testname "check mode cache (corrupted) failure"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 && fail
# remove the old file entirely
run_command rm $WORK_DIR/old.file
testname "check mode cache (missing) single"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail
testname "check mode cache (missing) multiple"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail
testname "check mode cache (missing) failure"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 && fail
# --------------- apply patch ----------------------
$ADB push $DATA_DIR/old.file $WORK_DIR
$ADB push $DATA_DIR/patch.xdelta3 $WORK_DIR
# Check that the partition has enough space to apply the patch without
# copying. If it doesn't, we'll be testing the low-space condition
# when we intend to test the not-low-space condition.
testname "apply patches (with enough space)"
free_kb=$(free_space $WORK_FS)
echo "${free_kb}kb free on /$WORK_FS."
if (( free_kb * 1024 < NEW_SIZE * 3 / 2 )); then
echo "Not enough space on /$WORK_FS to patch test file."
echo
echo "This doesn't mean that applypatch is necessarily broken;"
echo "just that /$WORK_FS doesn't have enough free space to"
echo "properly run this test."
exit 1
fi
testname "apply xdelta3 patch"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.xdelta3 || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
testname "reapply xdelta3 patch"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.xdelta3 || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
$ADB push $DATA_DIR/old.file $WORK_DIR
$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR
testname "apply bsdiff patch"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
testname "reapply bsdiff patch"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
# --------------- apply patch with low space on /system ----------------------
$ADB push $DATA_DIR/old.file $WORK_DIR
$ADB push $DATA_DIR/patch.xdelta3 $WORK_DIR
$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR
free_kb=$(free_space $WORK_FS)
echo "${free_kb}kb free on /$WORK_FS; we'll soon fix that."
echo run_command dd if=/dev/zero of=$WORK_DIR/bloat.dat count=$((free_kb-512)) bs=1024 || fail
run_command dd if=/dev/zero of=$WORK_DIR/bloat.dat count=$((free_kb-512)) bs=1024 || fail
free_kb=$(free_space $WORK_FS)
echo "${free_kb}kb free on /$WORK_FS now."
testname "apply xdelta3 patch with low space"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.xdelta3 || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
testname "reapply xdelta3 patch with low space"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.xdelta3 || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
$ADB push $DATA_DIR/old.file $WORK_DIR
testname "apply bsdiff patch with low space"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
testname "reapply bsdiff patch with low space"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
# --------------- apply patch with low space on /system and /cache ----------------------
$ADB push $DATA_DIR/old.file $WORK_DIR
$ADB push $DATA_DIR/patch.xdelta3 $WORK_DIR
$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR
free_kb=$(free_space $WORK_FS)
echo "${free_kb}kb free on /$WORK_FS"
run_command mkdir /cache/subdir
run_command 'echo > /cache/subdir/a.file'
run_command 'echo > /cache/a.file'
run_command mkdir -p /cache/recovery/otatest
run_command 'echo > /cache/recovery/otatest/b.file'
run_command "echo > $CACHE_TEMP_SOURCE"
free_kb=$(free_space cache)
echo "${free_kb}kb free on /cache; we'll soon fix that."
run_command dd if=/dev/zero of=/cache/bloat_small.dat count=128 bs=1024 || fail
run_command dd if=/dev/zero of=/cache/bloat_large.dat count=$((free_kb-640)) bs=1024 || fail
free_kb=$(free_space cache)
echo "${free_kb}kb free on /cache now."
testname "apply bsdiff patch with low space, full cache, can't delete enough"
$ADB shell 'cat >> /cache/bloat_large.dat' & open_pid=$!
echo "open_pid is $open_pid"
# size check should fail even though it deletes some stuff
run_command $WORK_DIR/applypatch -s $NEW_SIZE && fail
run_command ls /cache/bloat_small.dat && fail # was deleted
run_command ls /cache/a.file && fail # was deleted
run_command ls /cache/recovery/otatest/b.file && fail # was deleted
run_command ls /cache/bloat_large.dat || fail # wasn't deleted because it was open
run_command ls /cache/subdir/a.file || fail # wasn't deleted because it's in a subdir
run_command ls $CACHE_TEMP_SOURCE || fail # wasn't deleted because it's the source file copy
# should fail; not enough files can be deleted
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff && fail
run_command ls /cache/bloat_large.dat || fail # wasn't deleted because it was open
run_command ls /cache/subdir/a.file || fail # wasn't deleted because it's in a subdir
run_command ls $CACHE_TEMP_SOURCE || fail # wasn't deleted because it's the source file copy
kill $open_pid # /cache/bloat_large.dat is no longer open
testname "apply bsdiff patch with low space, full cache, can delete enough"
# should succeed after deleting /cache/bloat_large.dat
run_command $WORK_DIR/applypatch -s $NEW_SIZE || fail
run_command ls /cache/bloat_large.dat && fail # was deleted
run_command ls /cache/subdir/a.file || fail # still wasn't deleted because it's in a subdir
run_command ls $CACHE_TEMP_SOURCE || fail # wasn't deleted because it's the source file copy
# should succeed
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
run_command ls /cache/subdir/a.file || fail # still wasn't deleted because it's in a subdir
run_command ls $CACHE_TEMP_SOURCE && fail # was deleted because patching overwrote it, then deleted it
# --------------- apply patch from cache ----------------------
$ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE
# put some junk in the old file
run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail
testname "apply xdelta3 patch from cache (corrupted source) with low space"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.xdelta3 || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
$ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE
# remove the old file entirely
run_command rm $WORK_DIR/old.file
testname "apply bsdiff patch from cache (missing source) with low space"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
# --------------- cleanup ----------------------
# not necessary if we're about to kill the emulator, but nice for
# running on real devices or already-running emulators.
run_command rm /cache/bloat*.dat $WORK_DIR/bloat.dat $CACHE_TEMP_SOURCE $WORK_DIR/old.file $WORK_DIR/patch.xdelta3 $WORK_DIR/patch.bsdiff $WORK_DIR/applypatch
kill $pid_emulator
rm -rf $tmpdir
echo
echo PASS
echo

235
tools/applypatch/bsdiff.c Normal file
View File

@ -0,0 +1,235 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
// This file is a nearly line-for-line copy of bspatch.c from the
// bsdiff-4.3 distribution; the primary differences being how the
// input and output data are read and the error handling. Running
// applypatch with the -l option will display the bsdiff license
// notice.
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <bzlib.h>
#include "mincrypt/sha.h"
void ShowBSDiffLicense() {
puts("The bsdiff library used herein is:\n"
"\n"
"Copyright 2003-2005 Colin Percival\n"
"All rights reserved\n"
"\n"
"Redistribution and use in source and binary forms, with or without\n"
"modification, are permitted providing that the following conditions\n"
"are met:\n"
"1. Redistributions of source code must retain the above copyright\n"
" notice, this list of conditions and the following disclaimer.\n"
"2. Redistributions in binary form must reproduce the above copyright\n"
" notice, this list of conditions and the following disclaimer in the\n"
" documentation and/or other materials provided with the distribution.\n"
"\n"
"THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"
"IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"
"WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
"ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n"
"DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n"
"DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n"
"OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n"
"HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n"
"STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n"
"IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
"POSSIBILITY OF SUCH DAMAGE.\n"
"\n------------------\n\n"
"This program uses Julian R Seward's \"libbzip2\" library, available\n"
"from http://www.bzip.org/.\n"
);
}
static off_t offtin(u_char *buf)
{
off_t y;
y=buf[7]&0x7F;
y=y*256;y+=buf[6];
y=y*256;y+=buf[5];
y=y*256;y+=buf[4];
y=y*256;y+=buf[3];
y=y*256;y+=buf[2];
y=y*256;y+=buf[1];
y=y*256;y+=buf[0];
if(buf[7]&0x80) y=-y;
return y;
}
int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
const char* patch_filename,
FILE* output, SHA_CTX* ctx) {
FILE* f;
if ((f = fopen(patch_filename, "rb")) == NULL) {
fprintf(stderr, "failed to open patch file\n");
return 1;
}
// File format:
// 0 8 "BSDIFF40"
// 8 8 X
// 16 8 Y
// 24 8 sizeof(newfile)
// 32 X bzip2(control block)
// 32+X Y bzip2(diff block)
// 32+X+Y ??? bzip2(extra block)
// with control block a set of triples (x,y,z) meaning "add x bytes
// from oldfile to x bytes from the diff block; copy y bytes from the
// extra block; seek forwards in oldfile by z bytes".
unsigned char header[32];
if (fread(header, 1, 32, f) < 32) {
fprintf(stderr, "failed to read patch file header\n");
return 1;
}
if (memcmp(header, "BSDIFF40", 8) != 0) {
fprintf(stderr, "corrupt patch file header (magic number)\n");
return 1;
}
ssize_t ctrl_len, data_len;
ssize_t new_size;
ctrl_len = offtin(header+8);
data_len = offtin(header+16);
new_size = offtin(header+24);
if (ctrl_len < 0 || data_len < 0 || new_size < 0) {
fprintf(stderr, "corrupt patch file header (data lengths)\n");
return 1;
}
fclose(f);
int bzerr;
#define OPEN_AT(f, bzf, offset) \
FILE* f; \
BZFILE* bzf; \
if ((f = fopen(patch_filename, "rb")) == NULL) { \
fprintf(stderr, "failed to open patch file\n"); \
return 1; \
} \
if (fseeko(f, offset, SEEK_SET)) { \
fprintf(stderr, "failed to seek in patch file\n"); \
return 1; \
} \
if ((bzf = BZ2_bzReadOpen(&bzerr, f, 0, 0, NULL, 0)) == NULL) { \
fprintf(stderr, "failed to bzReadOpen in patch file (%d)\n", bzerr); \
return 1; \
}
OPEN_AT(cpf, cpfbz2, 32);
OPEN_AT(dpf, dpfbz2, 32+ctrl_len);
OPEN_AT(epf, epfbz2, 32+ctrl_len+data_len);
#undef OPEN_AT
unsigned char* new_data = malloc(new_size);
if (new_data == NULL) {
fprintf(stderr, "failed to allocate memory for output file\n");
return 1;
}
off_t oldpos = 0, newpos = 0;
off_t ctrl[3];
off_t len_read;
int i;
unsigned char buf[8];
while (newpos < new_size) {
// Read control data
for (i = 0; i < 3; ++i) {
len_read = BZ2_bzRead(&bzerr, cpfbz2, buf, 8);
if (len_read < 8 || !(bzerr == BZ_OK || bzerr == BZ_STREAM_END)) {
fprintf(stderr, "corrupt patch (read control)\n");
return 1;
}
ctrl[i] = offtin(buf);
}
// Sanity check
if (newpos + ctrl[0] > new_size) {
fprintf(stderr, "corrupt patch (new file overrun)\n");
return 1;
}
// Read diff string
len_read = BZ2_bzRead(&bzerr, dpfbz2, new_data + newpos, ctrl[0]);
if (len_read < ctrl[0] || !(bzerr == BZ_OK || bzerr == BZ_STREAM_END)) {
fprintf(stderr, "corrupt patch (read diff)\n");
return 1;
}
// Add old data to diff string
for (i = 0; i < ctrl[0]; ++i) {
if ((oldpos+i >= 0) && (oldpos+i < old_size)) {
new_data[newpos+i] += old_data[oldpos+i];
}
}
// Adjust pointers
newpos += ctrl[0];
oldpos += ctrl[0];
// Sanity check
if (newpos + ctrl[1] > new_size) {
fprintf(stderr, "corrupt patch (new file overrun)\n");
return 1;
}
// Read extra string
len_read = BZ2_bzRead(&bzerr, epfbz2, new_data + newpos, ctrl[1]);
if (len_read < ctrl[1] || !(bzerr == BZ_OK || bzerr == BZ_STREAM_END)) {
fprintf(stderr, "corrupt patch (read extra)\n");
return 1;
}
// Adjust pointers
newpos += ctrl[1];
oldpos += ctrl[2];
}
BZ2_bzReadClose(&bzerr, cpfbz2);
BZ2_bzReadClose(&bzerr, dpfbz2);
BZ2_bzReadClose(&bzerr, epfbz2);
fclose(cpf);
fclose(dpf);
fclose(epf);
if (fwrite(new_data, 1, new_size, output) < new_size) {
fprintf(stderr, "short write of output: %d (%s)\n", errno, strerror(errno));
return 1;
}
SHA_update(ctx, new_data, new_size);
free(new_data);
return 0;
}

View File

@ -0,0 +1,172 @@
#include <errno.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <unistd.h>
#include <dirent.h>
#include <ctype.h>
#include "applypatch.h"
static int EliminateOpenFiles(char** files, int file_count) {
DIR* d;
struct dirent* de;
d = opendir("/proc");
if (d == NULL) {
fprintf(stderr, "error opening /proc: %s\n", strerror(errno));
return -1;
}
while ((de = readdir(d)) != 0) {
int i;
for (i = 0; de->d_name[i] != '\0' && isdigit(de->d_name[i]); ++i);
if (de->d_name[i]) continue;
// de->d_name[i] is numeric
char path[FILENAME_MAX];
strcpy(path, "/proc/");
strcat(path, de->d_name);
strcat(path, "/fd/");
DIR* fdd;
struct dirent* fdde;
fdd = opendir(path);
if (fdd == NULL) {
fprintf(stderr, "error opening %s: %s\n", path, strerror(errno));
continue;
}
while ((fdde = readdir(fdd)) != 0) {
char fd_path[FILENAME_MAX];
char link[FILENAME_MAX];
strcpy(fd_path, path);
strcat(fd_path, fdde->d_name);
int count;
count = readlink(fd_path, link, sizeof(link)-1);
if (count >= 0) {
link[count] = '\0';
// This is inefficient, but it should only matter if there are
// lots of files in /cache, and lots of them are open (neither
// of which should be true, especially in recovery).
if (strncmp(link, "/cache/", 7) == 0) {
int j;
for (j = 0; j < file_count; ++j) {
if (files[j] && strcmp(files[j], link) == 0) {
printf("%s is open by %s\n", link, de->d_name);
free(files[j]);
files[j] = NULL;
}
}
}
}
}
closedir(fdd);
}
closedir(d);
return 0;
}
int FindExpendableFiles(char*** names, int* entries) {
DIR* d;
struct dirent* de;
int size = 32;
*entries = 0;
*names = malloc(size * sizeof(char*));
char path[FILENAME_MAX];
// We're allowed to delete unopened regular files in any of these
// directories.
const char* dirs[2] = {"/cache", "/cache/recovery/otatest"};
unsigned int i;
for (i = 0; i < sizeof(dirs)/sizeof(dirs[0]); ++i) {
d = opendir(dirs[i]);
if (d == NULL) {
fprintf(stderr, "error opening %s: %s\n", dirs[i], strerror(errno));
continue;
}
// Look for regular files in the directory (not in any subdirectories).
while ((de = readdir(d)) != 0) {
strcpy(path, dirs[i]);
strcat(path, "/");
strcat(path, de->d_name);
// We can't delete CACHE_TEMP_SOURCE; if it's there we might have
// restarted during installation and could be depending on it to
// be there.
if (strcmp(path, CACHE_TEMP_SOURCE) == 0) continue;
struct stat st;
if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
if (*entries >= size) {
size *= 2;
*names = realloc(*names, size * sizeof(char*));
}
(*names)[(*entries)++] = strdup(path);
}
}
closedir(d);
}
printf("%d regular files in deletable directories\n", *entries);
if (EliminateOpenFiles(*names, *entries) < 0) {
return -1;
}
return 0;
}
int MakeFreeSpaceOnCache(size_t bytes_needed) {
size_t free_now = FreeSpaceForFile("/cache");
printf("%ld bytes free on /cache (%ld needed)\n",
(long)free_now, (long)bytes_needed);
if (free_now >= bytes_needed) {
return 0;
}
char** names;
int entries;
if (FindExpendableFiles(&names, &entries) < 0) {
return -1;
}
if (entries == 0) {
// nothing we can delete to free up space!
fprintf(stderr, "no files can be deleted to free space on /cache\n");
return -1;
}
// We could try to be smarter about which files to delete: the
// biggest ones? the smallest ones that will free up enough space?
// the oldest? the newest?
//
// Instead, we'll be dumb.
int i;
for (i = 0; i < entries && free_now < bytes_needed; ++i) {
if (names[i]) {
unlink(names[i]);
free_now = FreeSpaceForFile("/cache");
printf("deleted %s; now %ld bytes free\n", names[i], (long)free_now);
free(names[i]);
}
}
for (; i < entries; ++i) {
free(names[i]);
}
free(names);
return (free_now >= bytes_needed) ? 0 : -1;
}

BIN
tools/applypatch/testdata/new.file vendored Normal file

Binary file not shown.

BIN
tools/applypatch/testdata/old.file vendored Normal file

Binary file not shown.

BIN
tools/applypatch/testdata/patch.bsdiff vendored Normal file

Binary file not shown.

BIN
tools/applypatch/testdata/patch.xdelta3 vendored Normal file

Binary file not shown.

121
tools/applypatch/xdelta3.c Normal file
View File

@ -0,0 +1,121 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include "xdelta3.h"
#include "mincrypt/sha.h"
int ApplyXDelta3Patch(const unsigned char* old_data, ssize_t old_size,
const char* patch_filename,
FILE* output, SHA_CTX* ctx) {
#define WINDOW_SIZE 32768
int ret;
xd3_stream stream;
xd3_config config;
xd3_init_config(&config, 0);
config.winsize = WINDOW_SIZE;
ret = xd3_config_stream(&stream, &config);
if (ret != 0) {
fprintf(stderr, "xd3_config_stream error: %s\n", xd3_strerror(ret));
return 1;
}
// In xdelta3 terms, the "input" is the patch file: it contains a
// sequence of instruction codes and data that will be executed to
// produce the output file. The "source" is the original data file;
// it is a blob of data to which instructions in the input may refer
// (eg, an instruction may say "copy such-and-such range of bytes
// from the source to the output").
// For simplicity, we provide the entire source to xdelta as a
// single block. This means it should never have to ask us to load
// blocks of the source file.
xd3_source source;
source.name = "old name";
source.size = old_size;
source.ioh = NULL;
source.blksize = old_size;
source.curblkno = 0;
source.curblk = old_data;
source.onblk = old_size;
ret = xd3_set_source(&stream, &source);
if (ret != 0) {
fprintf(stderr, "xd3_set_source error: %s\n", xd3_strerror(ret));
return 1;
}
unsigned char buffer[WINDOW_SIZE];
FILE* input = fopen(patch_filename, "rb");
if (input == NULL) {
fprintf(stderr, "failed to open patch file %s: %d (%s)\n",
patch_filename, errno, strerror(errno));
return 1;
}
size_t bytes_read;
do {
bytes_read = fread(buffer, 1, WINDOW_SIZE, input);
if (feof(input)) {
xd3_set_flags(&stream, XD3_FLUSH);
}
xd3_avail_input(&stream, buffer, bytes_read);
process:
ret = xd3_decode_input(&stream);
switch (ret) {
case XD3_INPUT:
continue;
case XD3_OUTPUT:
SHA_update(ctx, stream.next_out, stream.avail_out);
if (fwrite(stream.next_out, 1, stream.avail_out, output) !=
stream.avail_out) {
fprintf(stderr, "short write of output file: %d (%s)\n",
errno, strerror(errno));
return 1;
}
xd3_consume_output(&stream);
goto process;
case XD3_GETSRCBLK:
// We provided the entire source file already; it should never
// have to ask us for a block.
fprintf(stderr, "xd3_decode_input: unexpected GETSRCBLK\n");
return 1;
case XD3_GOTHEADER:
case XD3_WINSTART:
case XD3_WINFINISH:
// These are informational events we don't care about.
goto process;
default:
fprintf(stderr, "xd3_decode_input: unknown error %s (%s)\n",
xd3_strerror(ret), stream.msg);
return 1;
}
} while (!feof(input));
fclose(input);
return 0;
#undef WINDOW_SIZE
}

View File

@ -21,6 +21,7 @@ echo "ro.product.board=$TARGET_BOOTLOADER_BOARD_NAME"
echo "ro.product.manufacturer=$PRODUCT_MANUFACTURER"
echo "ro.product.locale.language=$PRODUCT_DEFAULT_LANGUAGE"
echo "ro.product.locale.region=$PRODUCT_DEFAULT_REGION"
echo "ro.board.platform=$TARGET_BOARD_PLATFORM"
echo "# ro.build.product is obsolete; use ro.product.device"
echo "ro.build.product=$TARGET_DEVICE"

View File

@ -0,0 +1,30 @@
# Copyright (C) 2009 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
ifneq ($(TARGET_SIMULATOR),true)
LOCAL_SRC_FILES := check_prereq.c
LOCAL_MODULE := check_prereq
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_TAGS := eng
LOCAL_C_INCLUDES +=
LOCAL_STATIC_LIBRARIES += libcutils libc
include $(BUILD_EXECUTABLE)
endif # !TARGET_SIMULATOR

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/system_properties.h>
#include <cutils/properties.h>
// Compare the timestamp of the new build (passed on the command line)
// against the current value of ro.build.date.utc. Exit successfully
// if the new build is newer than the current build (or if the
// timestamps are the same).
int main(int argc, char** argv) {
if (argc != 2) {
usage:
fprintf(stderr, "usage: %s <timestamp>\n", argv[0]);
return 2;
}
char value[PROPERTY_VALUE_MAX];
char* default_value = "0";
property_get("ro.build.date.utc", value, default_value);
long current = strtol(value, NULL, 10);
char* end;
long install = strtol(argv[1], &end, 10);
printf("current build time: [%ld] new build time: [%ld]\n",
current, install);
return (*end == 0 && current > 0 && install >= current) ? 0 : 1;
}

View File

@ -26,7 +26,7 @@ import java.io.FileNotFoundException;
import java.io.PrintStream;
public class Stubs {
private static HashSet<ClassInfo> notStrippable;
private static HashSet<ClassInfo> notStrippable;
public static void writeStubs(String stubsDir, Boolean writeXML, String xmlFile,
HashSet<String> stubPackages) {
// figure out which classes we need
@ -90,7 +90,7 @@ public class Stubs {
}
}
}
// annotations are handled like methods
methods = cl.annotationElements();
for (MethodInfo m: methods) {
@ -156,14 +156,14 @@ public class Stubs {
}
public static void cantStripThis(ClassInfo cl, HashSet<ClassInfo> notStrippable, String why) {
if (!notStrippable.add(cl)) {
// slight optimization: if it already contains cl, it already contains
// all of cl's parents
return;
}
cl.setReasonIncluded(why);
// cant strip annotations
/*if (cl.annotations() != null){
for (AnnotationInstanceInfo ai : cl.annotations()){
@ -233,7 +233,7 @@ public class Stubs {
}
}
}
private static void cantStripThis(MethodInfo[] mInfos , HashSet<ClassInfo> notStrippable) {
//for each method, blow open the parameters, throws and return types. also blow open their generics
if (mInfos != null){
@ -241,8 +241,8 @@ public class Stubs {
if (mInfo.getTypeParameters() != null){
for (TypeInfo tInfo : mInfo.getTypeParameters()){
if (tInfo.asClassInfo() != null){
cantStripThis(tInfo.asClassInfo(), notStrippable, "8:" +
mInfo.realContainingClass().qualifiedName() + ":" +
cantStripThis(tInfo.asClassInfo(), notStrippable, "8:" +
mInfo.realContainingClass().qualifiedName() + ":" +
mInfo.name());
}
}
@ -250,8 +250,8 @@ public class Stubs {
if (mInfo.parameters() != null){
for (ParameterInfo pInfo : mInfo.parameters()){
if (pInfo.type() != null && pInfo.type().asClassInfo() != null){
cantStripThis(pInfo.type().asClassInfo(), notStrippable,
"9:"+ mInfo.realContainingClass().qualifiedName()
cantStripThis(pInfo.type().asClassInfo(), notStrippable,
"9:"+ mInfo.realContainingClass().qualifiedName()
+ ":" + mInfo.name());
if (pInfo.type().typeArguments() != null){
for (TypeInfo tInfoType : pInfo.type().typeArguments()){
@ -264,9 +264,9 @@ public class Stubs {
+ mInfo.containingClass().qualifiedName()
+ '.' + mInfo.name() + "()");
} else {
cantStripThis(tcl, notStrippable,
"10:" +
mInfo.realContainingClass().qualifiedName() + ":" +
cantStripThis(tcl, notStrippable,
"10:" +
mInfo.realContainingClass().qualifiedName() + ":" +
mInfo.name());
}
}
@ -276,19 +276,19 @@ public class Stubs {
}
}
for (ClassInfo thrown : mInfo.thrownExceptions()){
cantStripThis(thrown, notStrippable, "11:" +
cantStripThis(thrown, notStrippable, "11:" +
mInfo.realContainingClass().qualifiedName()
+":" + mInfo.name());
}
if (mInfo.returnType() != null && mInfo.returnType().asClassInfo() != null){
cantStripThis(mInfo.returnType().asClassInfo(), notStrippable,
"12:" + mInfo.realContainingClass().qualifiedName() +
cantStripThis(mInfo.returnType().asClassInfo(), notStrippable,
"12:" + mInfo.realContainingClass().qualifiedName() +
":" + mInfo.name());
if (mInfo.returnType().typeArguments() != null){
for (TypeInfo tyInfo: mInfo.returnType().typeArguments() ){
if (tyInfo.asClassInfo() != null){
cantStripThis(tyInfo.asClassInfo(), notStrippable,
"13:" +
cantStripThis(tyInfo.asClassInfo(), notStrippable,
"13:" +
mInfo.realContainingClass().qualifiedName()
+ ":" + mInfo.name());
}
@ -417,18 +417,18 @@ public class Stubs {
for (ClassInfo inner: cl.getRealInnerClasses()) {
if (notStrippable.contains(inner)
&& !inner.isDocOnly()){
&& !inner.isDocOnly()){
writeClass(stream, inner);
}
}
for (MethodInfo method: cl.constructors()) {
if (!method.isDocOnly()) {
writeMethod(stream, method, true);
}
}
boolean fieldNeedsInitialization = false;
boolean staticFieldNeedsInitialization = false;
for (FieldInfo field: cl.allSelfFields()) {
@ -441,12 +441,12 @@ public class Stubs {
}
}
}
// The compiler includes a default public constructor that calls the super classes
// default constructor in the case where there are no written constructors.
// The compiler includes a default public constructor that calls the super classes
// default constructor in the case where there are no written constructors.
// So, if we hide all the constructors, java may put in a constructor
// that calls a nonexistent super class constructor. So, if there are no constructors,
// and the super class doesn't have a default constructor, write in a private constructor
// that calls a nonexistent super class constructor. So, if there are no constructors,
// and the super class doesn't have a default constructor, write in a private constructor
// that works. TODO -- we generate this as protected, but we really should generate
// it as private unless it also exists in the real code.
if ((cl.constructors().length == 0 && (cl.getNonWrittenConstructors().length != 0
@ -454,7 +454,7 @@ public class Stubs {
&& !cl.isAnnotation()
&& !cl.isInterface()
&& !cl.isEnum() ) {
//Errors.error(Errors.HIDDEN_CONSTRUCTOR,
//Errors.error(Errors.HIDDEN_CONSTRUCTOR,
// cl.position(), "No constructors " +
// "found and superclass has no parameterless constructor. A constructor " +
// "that calls an appropriate superclass constructor " +
@ -463,7 +463,7 @@ public class Stubs {
+ "() { " + superCtorCall(cl,null)
+ "throw new" + " RuntimeException(\"Stub!\"); }");
}
for (MethodInfo method: cl.allSelfMethods()) {
if (cl.isEnum()) {
if (("values".equals(method.name())
@ -484,11 +484,11 @@ public class Stubs {
//These can't be hidden.
for (MethodInfo method : cl.getHiddenMethods()){
MethodInfo overriddenMethod = method.findRealOverriddenMethod(method.name(), method.signature(), notStrippable);
ClassInfo classContainingMethod = method.findRealOverriddenClass(method.name(),
ClassInfo classContainingMethod = method.findRealOverriddenClass(method.name(),
method.signature());
if (overriddenMethod != null && !overriddenMethod.isHidden()
&& !overriddenMethod.isDocOnly() &&
(overriddenMethod.isAbstract() ||
(overriddenMethod.isAbstract() ||
overriddenMethod.containingClass().isInterface())) {
method.setReason("1:" + classContainingMethod.qualifiedName());
cl.addMethod(method);
@ -519,11 +519,11 @@ public class Stubs {
}
stream.println("}");
}
stream.println("}");
}
static void writeMethod(PrintStream stream, MethodInfo method, boolean isConstructor) {
String comma;
@ -627,7 +627,7 @@ public class Stubs {
if (mi.isAbstract() || mi.isStatic() || mi.isFinal()) {
return false;
}
// Find any relevant ancestor declaration and inspect it
MethodInfo om = mi.findSuperclassImplementation(notStrippable);
if (om != null) {
@ -735,8 +735,8 @@ public class Stubs {
//put null in each super class method. Cast null to the correct type
//to avoid collisions with other constructors. If the type is generic
//don't cast it
result += (!t.isTypeVariable() ? "(" + t.qualifiedTypeName() + t.dimension() +
")" : "") + "null";
result += (!t.isTypeVariable() ? "(" + t.qualifiedTypeName() + t.dimension() +
")" : "") + "null";
}
if (i != N-1) {
result += ",";
@ -769,8 +769,8 @@ public class Stubs {
}
stream.println(";");
}
static void writeXML(PrintStream xmlWriter, HashMap<PackageInfo, List<ClassInfo>> allClasses,
static void writeXML(PrintStream xmlWriter, HashMap<PackageInfo, List<ClassInfo>> allClasses,
HashSet notStrippable) {
// extract the set of packages, sort them by name, and write them out in that order
Set<PackageInfo> allClassKeys = allClasses.keySet();
@ -783,22 +783,22 @@ public class Stubs {
}
xmlWriter.println("</api>");
}
static void writePackageXML(PrintStream xmlWriter, PackageInfo pack, List<ClassInfo> classList,
HashSet notStrippable) {
ClassInfo[] classes = classList.toArray(new ClassInfo[classList.size()]);
Arrays.sort(classes, ClassInfo.comparator);
xmlWriter.println("<package name=\"" + pack.name() + "\"\n"
//+ " source=\"" + pack.position() + "\"\n"
//+ " source=\"" + pack.position() + "\"\n"
+ ">");
for (ClassInfo cl : classes) {
writeClassXML(xmlWriter, cl, notStrippable);
}
xmlWriter.println("</package>");
}
static void writeClassXML(PrintStream xmlWriter, ClassInfo cl, HashSet notStrippable) {
String scope = DroidDoc.scope(cl);
String deprecatedString = "";
@ -821,7 +821,7 @@ public class Stubs {
+ " visibility=\"" + scope + "\"\n"
//+ " source=\"" + cl.position() + "\"\n"
+ ">");
ClassInfo[] interfaces = cl.realInterfaces();
Arrays.sort(interfaces, ClassInfo.comparator);
for (ClassInfo iface : interfaces) {
@ -830,13 +830,13 @@ public class Stubs {
xmlWriter.println("</implements>");
}
}
MethodInfo[] constructors = cl.constructors();
Arrays.sort(constructors, MethodInfo.comparator);
for (MethodInfo mi : constructors) {
writeConstructorXML(xmlWriter, mi);
}
MethodInfo[] methods = cl.allSelfMethods();
Arrays.sort(methods, MethodInfo.comparator);
for (MethodInfo mi : methods) {
@ -844,16 +844,16 @@ public class Stubs {
writeMethodXML(xmlWriter, mi);
}
}
FieldInfo[] fields = cl.allSelfFields();
Arrays.sort(fields, FieldInfo.comparator);
for (FieldInfo fi : fields) {
writeFieldXML(xmlWriter, fi);
}
xmlWriter.println("</" + declString + ">");
}
static void writeMethodXML(PrintStream xmlWriter, MethodInfo mi) {
String scope = DroidDoc.scope(mi);
@ -863,10 +863,10 @@ public class Stubs {
} else {
deprecatedString = "not deprecated";
}
xmlWriter.println("<method name=\"" + mi.name() + "\"\n"
xmlWriter.println("<method name=\"" + mi.name() + "\"\n"
+ ((mi.returnType() != null)
? " return=\"" + makeXMLcompliant(fullParameterTypeName(mi, mi.returnType(), false)) + "\"\n"
: "")
: "")
+ " abstract=\"" + mi.isAbstract() + "\"\n"
+ " native=\"" + mi.isNative() + "\"\n"
+ " synchronized=\"" + mi.isSynchronized() + "\"\n"
@ -884,7 +884,7 @@ public class Stubs {
count++;
writeParameterXML(xmlWriter, mi, pi, count == numParameters);
}
// but write exceptions in canonicalized order
ClassInfo[] exceptions = mi.thrownExceptions();
Arrays.sort(exceptions, ClassInfo.comparator);
@ -895,7 +895,7 @@ public class Stubs {
}
xmlWriter.println("</method>");
}
static void writeConstructorXML(PrintStream xmlWriter, MethodInfo mi) {
String scope = DroidDoc.scope(mi);
String deprecatedString = "";
@ -919,7 +919,7 @@ public class Stubs {
count++;
writeParameterXML(xmlWriter, mi, pi, count == numParameters);
}
ClassInfo[] exceptions = mi.thrownExceptions();
Arrays.sort(exceptions, ClassInfo.comparator);
for (ClassInfo pi : exceptions) {
@ -929,14 +929,14 @@ public class Stubs {
}
xmlWriter.println("</constructor>");
}
static void writeParameterXML(PrintStream xmlWriter, MethodInfo method,
ParameterInfo pi, boolean isLast) {
xmlWriter.println("<parameter name=\"" + pi.name() + "\" type=\"" +
makeXMLcompliant(fullParameterTypeName(method, pi.type(), isLast)) + "\">");
xmlWriter.println("</parameter>");
}
static void writeFieldXML(PrintStream xmlWriter, FieldInfo fi) {
String scope = DroidDoc.scope(fi);
String deprecatedString = "";
@ -955,7 +955,7 @@ public class Stubs {
+ " type=\"" + fullTypeName + "\"\n"
+ " transient=\"" + fi.isTransient() + "\"\n"
+ " volatile=\"" + fi.isVolatile() + "\"\n"
+ (fieldIsInitialized(fi) ? " value=\"" + value + "\"\n" : "")
+ (fieldIsInitialized(fi) ? " value=\"" + value + "\"\n" : "")
+ " static=\"" + fi.isStatic() + "\"\n"
+ " final=\"" + fi.isFinal() + "\"\n"
+ " deprecated=\"" + deprecatedString + "\"\n"
@ -964,7 +964,7 @@ public class Stubs {
+ ">");
xmlWriter.println("</field>");
}
static String makeXMLcompliant(String s) {
String returnString = "";
returnString = s.replaceAll("&", "&amp;");
@ -974,16 +974,15 @@ public class Stubs {
returnString = returnString.replaceAll("'", "&pos;");
return returnString;
}
static String fullParameterTypeName(MethodInfo method, TypeInfo type, boolean isLast) {
String fullTypeName = type.fullName(method.typeVariables());
if (isLast && method.isVarArgs()) {
// TODO: note that this does not attempt to handle hypothetical
// vararg methods whose last parameter is a list of arrays, e.g.
// "Object[]...".
fullTypeName = type.qualifiedTypeName() + "...";
fullTypeName = type.fullNameNoDimension(method.typeVariables()) + "...";
}
return fullTypeName;
}
}

View File

@ -81,37 +81,43 @@ public class TypeInfo
public String fullName(HashSet<String> typeVars)
{
mFullName = fullNameNoDimension(typeVars) + mDimension;
return mFullName;
}
public String fullNameNoDimension(HashSet<String> typeVars)
{
String fullName = null;
if (mIsTypeVariable) {
if (typeVars.contains(mQualifiedTypeName)) {
// don't recurse forever with the parameters. This handles
// Enum<K extends Enum<K>>
return mQualifiedTypeName + mDimension;
return mQualifiedTypeName;
}
typeVars.add(mQualifiedTypeName);
}
/*
if (mFullName != null) {
return mFullName;
if (fullName != null) {
return fullName;
}
*/
mFullName = mQualifiedTypeName;
fullName = mQualifiedTypeName;
if (mTypeArguments != null && mTypeArguments.length > 0) {
mFullName += typeArgumentsName(mTypeArguments, typeVars);
fullName += typeArgumentsName(mTypeArguments, typeVars);
}
else if (mSuperBounds != null && mSuperBounds.length > 0) {
mFullName += " super " + mSuperBounds[0].fullName(typeVars);
fullName += " super " + mSuperBounds[0].fullName(typeVars);
for (int i=1; i<mSuperBounds.length; i++) {
mFullName += " & " + mSuperBounds[i].fullName(typeVars);
fullName += " & " + mSuperBounds[i].fullName(typeVars);
}
}
else if (mExtendsBounds != null && mExtendsBounds.length > 0) {
mFullName += " extends " + mExtendsBounds[0].fullName(typeVars);
fullName += " extends " + mExtendsBounds[0].fullName(typeVars);
for (int i=1; i<mExtendsBounds.length; i++) {
mFullName += " & " + mExtendsBounds[i].fullName(typeVars);
fullName += " & " + mExtendsBounds[i].fullName(typeVars);
}
}
mFullName += mDimension;
return mFullName;
return fullName;
}
public TypeInfo[] typeArguments()
@ -241,13 +247,13 @@ public class TypeInfo
return "null";
}
}
public String toString(){
String returnString = "";
returnString += "Primitive?: " + mIsPrimitive + " TypeVariable?: " +
mIsTypeVariable + " Wildcard?: " + mIsWildcard + " Dimension: " + mDimension
+ " QualifedTypeName: " + mQualifiedTypeName;
if (mTypeArguments != null){
returnString += "\nTypeArguments: ";
for (TypeInfo tA : mTypeArguments){

View File

@ -0,0 +1,27 @@
# Copyright (C) 2008 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
ifneq ($(TARGET_SIMULATOR),true)
LOCAL_SRC_FILES := fs_config.c
LOCAL_MODULE := fs_config
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_TAGS := eng
include $(BUILD_HOST_EXECUTABLE)
endif # !TARGET_SIMULATOR

View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include "private/android_filesystem_config.h"
// This program takes a list of files and directories (indicated by a
// trailing slash) on the stdin, and prints to stdout each input
// filename along with its desired uid, gid, and mode (in octal).
// The leading slash should be stripped from the input.
//
// Example input:
//
// system/etc/dbus.conf
// data/app/
//
// Output:
//
// system/etc/dbus.conf 1002 1002 440
// data/app 1000 1000 771
//
// Note that the output will omit the trailing slash from
// directories.
int main(int argc, char** argv) {
char buffer[1024];
while (fgets(buffer, 1023, stdin) != NULL) {
int is_dir = 0;
int i;
for (i = 0; i < 1024 && buffer[i]; ++i) {
switch (buffer[i]) {
case '\n':
buffer[i-is_dir] = '\0';
i = 1025;
break;
case '/':
is_dir = 1;
break;
default:
is_dir = 0;
break;
}
}
unsigned uid = 0, gid = 0, mode = 0;
fs_config(buffer, is_dir, &uid, &gid, &mode);
printf("%s %d %d %o\n", buffer, uid, gid, mode);
}
return 0;
}

View File

@ -13,20 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define to565(r,g,b) \
#define to565(r,g,b) \
((((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3))
#define from565_r(x) ((((x) >> 11) & 0x1f) * 255 / 31)
#define from565_g(x) ((((x) >> 5) & 0x3f) * 255 / 63)
#define from565_b(x) (((x) & 0x1f) * 255 / 31)
void to_565_raw(void)
{
unsigned char in[3];
unsigned short out;
while(read(0, in, 3) == 3) {
out = to565(in[0],in[1],in[2]);
write(1, &out, 2);
@ -34,6 +38,66 @@ void to_565_raw(void)
return;
}
void to_565_raw_dither(int width)
{
unsigned char in[3];
unsigned short out;
int i = 0;
int e;
int* error = malloc((width+2) * 3 * sizeof(int));
int* next_error = malloc((width+2) * 3 * sizeof(int));
memset(error, 0, (width+2) * 3 * sizeof(int));
memset(next_error, 0, (width+2) * 3 * sizeof(int));
error += 3; // array goes from [-3..((width+1)*3+2)]
next_error += 3;
while(read(0, in, 3) == 3) {
int r = in[0] + error[i*3+0];
int rb = (r < 0) ? 0 : ((r > 255) ? 255 : r);
int g = in[1] + error[i*3+1];
int gb = (g < 0) ? 0 : ((g > 255) ? 255 : g);
int b = in[2] + error[i*3+2];
int bb = (b < 0) ? 0 : ((b > 255) ? 255 : b);
out = to565(rb, gb, bb);
write(1, &out, 2);
#define apply_error(ch) { \
next_error[(i-1)*3+ch] += e * 3 / 16; \
next_error[(i)*3+ch] += e * 5 / 16; \
next_error[(i+1)*3+ch] += e * 1 / 16; \
error[(i+1)*3+ch] += e - ((e*1/16) + (e*3/16) + (e*5/16)); \
}
e = r - from565_r(out);
apply_error(0);
e = g - from565_g(out);
apply_error(1);
e = b - from565_b(out);
apply_error(2);
#undef apply_error
++i;
if (i == width) {
// error <- next_error; next_error <- 0
int* temp = error; error = next_error; next_error = temp;
memset(next_error, 0, (width+1) * 3 * sizeof(int));
i = 0;
}
}
free(error-3);
free(next_error-3);
return;
}
void to_565_rle(void)
{
unsigned char in[3];
@ -66,10 +130,14 @@ void to_565_rle(void)
int main(int argc, char **argv)
{
if ((argc > 1) && (!strcmp(argv[1],"-rle"))) {
if ((argc == 2) && (!strcmp(argv[1],"-rle"))) {
to_565_rle();
} else {
to_565_raw();
if (argc > 2 && (!strcmp(argv[1], "-w"))) {
to_565_raw_dither(atoi(argv[2]));
} else {
to_565_raw();
}
}
return 0;
}