From e1a16af3ea497c8b4df62cec99bf36bde28df409 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 4 Feb 2016 11:30:42 -0800 Subject: verifier_test: Suppress the unused parameter warnings. Change-Id: I51fec30114c0a31efc9c2ac8472654baf8bb3e84 --- tests/component/verifier_test.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp index 7f7b1b448..71fa028ca 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -138,13 +138,13 @@ class MockUI : public RecoveryUI { void Init() { } void SetStage(int, int) { } void SetLocale(const char*) { } - void SetBackground(Icon icon) { } + void SetBackground(Icon /*icon*/) { } - void SetProgressType(ProgressType determinate) { } - void ShowProgress(float portion, float seconds) { } - void SetProgress(float fraction) { } + void SetProgressType(ProgressType /*determinate*/) { } + void ShowProgress(float /*portion*/, float /*seconds*/) { } + void SetProgress(float /*fraction*/) { } - void ShowText(bool visible) { } + void ShowText(bool /*visible*/) { } bool IsTextVisible() { return false; } bool WasTextEverVisible() { return false; } void Print(const char* fmt, ...) { @@ -161,9 +161,10 @@ class MockUI : public RecoveryUI { } void ShowFile(const char*) { } - void StartMenu(const char* const * headers, const char* const * items, - int initial_selection) { } - int SelectMenu(int sel) { return 0; } + void StartMenu(const char* const* /*headers*/, + const char* const* /*items*/, + int /*initial_selection*/) { } + int SelectMenu(int /*sel*/) { return 0; } void EndMenu() { } }; -- cgit v1.2.3 From d5a14c6a492d8609b2ce9c621fa9fe489fc45cdc Mon Sep 17 00:00:00 2001 From: Jed Estep Date: Fri, 5 Feb 2016 11:24:27 -0800 Subject: Change on-device directory for recovery test data Test data needs to go outside the gtest module. Change-Id: Ic444ca838cbafa651ec97ff8730129da84fafc09 --- tests/Android.mk | 2 +- tests/component/verifier_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Android.mk b/tests/Android.mk index 3f3c433eb..262fb8bfd 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -43,7 +43,7 @@ LOCAL_STATIC_LIBRARIES := \ libcutils \ libc -testdata_out_path := $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) +testdata_out_path := $(TARGET_OUT_DATA_NATIVE_TESTS)/recovery testdata_files := $(call find-subdir-files, testdata/*) GEN := $(addprefix $(testdata_out_path)/, $(testdata_files)) diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp index 7f7b1b448..c54aa111f 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -42,7 +42,7 @@ #endif static const char* DATA_PATH = getenv("ANDROID_DATA"); -static const char* TESTDATA_PATH = "/recovery_component_test/testdata/"; +static const char* TESTDATA_PATH = "/recovery/testdata/"; // This is build/target/product/security/testkey.x509.pem after being // dumped out by dumpkey.jar. -- cgit v1.2.3 From 696692a3c9fe4bd8879f98f3e85341303f85afd5 Mon Sep 17 00:00:00 2001 From: Sen Jiang Date: Tue, 2 Feb 2016 16:01:23 +0800 Subject: applypatch: Add a Makefile to build imgdiff in Chrome OS. Also fixed some warnings and added check for target_len. Test: mma; emerge-peppy imgdiff; emerge-nyan imgdiff; sudo emerge imgdiff Bug: 26866274 Change-Id: Ifbcd3afd6701c769ccf626e33ed94461706f7ee6 --- applypatch/Makefile | 32 ++++++++++++++++++++++++++++++++ applypatch/applypatch.h | 1 + applypatch/bsdiff.cpp | 1 - applypatch/bspatch.cpp | 1 - applypatch/imgdiff.cpp | 2 -- applypatch/imgpatch.cpp | 6 ++++++ 6 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 applypatch/Makefile diff --git a/applypatch/Makefile b/applypatch/Makefile new file mode 100644 index 000000000..fa6298d46 --- /dev/null +++ b/applypatch/Makefile @@ -0,0 +1,32 @@ +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file is for building imgdiff in Chrome OS. + +CPPFLAGS += -iquote.. +CXXFLAGS += -std=c++11 -O3 -Wall -Werror +LDLIBS += -lbz2 -lz + +.PHONY: all clean + +all: imgdiff libimgpatch.a + +clean: + rm -f *.o imgdiff libimgpatch.a + +imgdiff: imgdiff.o bsdiff.o utils.o + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDLIBS) -o $@ $^ + +libimgpatch.a: imgpatch.o bspatch.o utils.o + ${AR} rcs $@ $^ diff --git a/applypatch/applypatch.h b/applypatch/applypatch.h index 14fb490ba..096596f03 100644 --- a/applypatch/applypatch.h +++ b/applypatch/applypatch.h @@ -17,6 +17,7 @@ #ifndef _APPLYPATCH_H #define _APPLYPATCH_H +#include #include #include diff --git a/applypatch/bsdiff.cpp b/applypatch/bsdiff.cpp index 55dbe5cf1..cca1b32fb 100644 --- a/applypatch/bsdiff.cpp +++ b/applypatch/bsdiff.cpp @@ -224,7 +224,6 @@ static void offtout(off_t x,u_char *buf) int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* newdata, off_t newsize, const char* patch_filename) { - int fd; off_t *I; off_t scan,pos,len; off_t lastscan,lastpos,lastoffset; diff --git a/applypatch/bspatch.cpp b/applypatch/bspatch.cpp index ebb55f1d1..1fc1455a6 100644 --- a/applypatch/bspatch.cpp +++ b/applypatch/bspatch.cpp @@ -182,7 +182,6 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, off_t oldpos = 0, newpos = 0; off_t ctrl[3]; - off_t len_read; int i; unsigned char buf[24]; while (newpos < new_size) { diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index f22502e38..a3c10b40a 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -598,7 +598,6 @@ int ReconstructDeflateChunk(ImageChunk* chunk) { return -1; } - size_t p = 0; unsigned char* out = reinterpret_cast(malloc(BUFFER_SIZE)); // We only check two combinations of encoder parameters: level 6 @@ -844,7 +843,6 @@ int main(int argc, char** argv) { } if (argc != 4) { - usage: printf("usage: %s [-z] [-b ] \n", argv[0]); return 2; diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp index 8824038ea..0ab995b30 100644 --- a/applypatch/imgpatch.cpp +++ b/applypatch/imgpatch.cpp @@ -130,6 +130,7 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, size_t src_len = Read8(deflate_header+8); size_t patch_offset = Read8(deflate_header+16); size_t expanded_len = Read8(deflate_header+24); + size_t target_len = Read8(deflate_header+32); int level = Read4(deflate_header+40); int method = Read4(deflate_header+44); int windowBits = Read4(deflate_header+48); @@ -195,6 +196,11 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, &uncompressed_target_data) != 0) { return -1; } + if (uncompressed_target_data.size() != target_len) { + printf("expected target len to be %zu, but it's %zu\n", + target_len, uncompressed_target_data.size()); + return -1; + } // Now compress the target data and append it to the output. -- cgit v1.2.3 From a7b9a4660c18a88413280c84c03917ae953d62b0 Mon Sep 17 00:00:00 2001 From: Jed Estep Date: Tue, 15 Dec 2015 16:04:53 -0800 Subject: IO fault injection for OTA packages Bug: 25951086 Change-Id: I31c74c735eb7a975b7f41fe2b2eff042e5699c0c (cherry-picked from commit f1fc48c6e62cfee42d25ad12f443e22d50c15d0b) --- Android.mk | 1 + applypatch/Android.mk | 4 +- applypatch/applypatch.cpp | 53 +++++++-------- otafault/Android.mk | 58 +++++++++++++++++ otafault/ota_io.cpp | 160 ++++++++++++++++++++++++++++++++++++++++++++++ otafault/ota_io.h | 49 ++++++++++++++ otafault/test.cpp | 32 ++++++++++ updater/Android.mk | 2 +- updater/blockimg.cpp | 25 ++++---- updater/install.cpp | 43 +++++++------ 10 files changed, 365 insertions(+), 62 deletions(-) create mode 100644 otafault/Android.mk create mode 100644 otafault/ota_io.cpp create mode 100644 otafault/ota_io.h create mode 100644 otafault/test.cpp diff --git a/Android.mk b/Android.mk index a48980fe8..4da34eef5 100644 --- a/Android.mk +++ b/Android.mk @@ -117,6 +117,7 @@ include $(LOCAL_PATH)/minui/Android.mk \ $(LOCAL_PATH)/tools/Android.mk \ $(LOCAL_PATH)/edify/Android.mk \ $(LOCAL_PATH)/uncrypt/Android.mk \ + $(LOCAL_PATH)/otafault/Android.mk \ $(LOCAL_PATH)/updater/Android.mk \ $(LOCAL_PATH)/update_verifier/Android.mk \ $(LOCAL_PATH)/applypatch/Android.mk diff --git a/applypatch/Android.mk b/applypatch/Android.mk index 23d0f7bb1..90a86dcb0 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -21,7 +21,7 @@ LOCAL_SRC_FILES := applypatch.cpp bspatch.cpp freecache.cpp imgpatch.cpp utils.c LOCAL_MODULE := libapplypatch LOCAL_MODULE_TAGS := eng LOCAL_C_INCLUDES += bootable/recovery -LOCAL_STATIC_LIBRARIES += libbase libmtdutils libcrypto_static libbz libz +LOCAL_STATIC_LIBRARIES += libbase libotafault libmtdutils libcrypto_static libbz libz include $(BUILD_STATIC_LIBRARY) @@ -55,7 +55,7 @@ LOCAL_CLANG := true LOCAL_SRC_FILES := main.cpp LOCAL_MODULE := applypatch LOCAL_C_INCLUDES += bootable/recovery -LOCAL_STATIC_LIBRARIES += libapplypatch libbase libmtdutils libcrypto_static libbz libedify +LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libmtdutils libcrypto_static libbz libedify LOCAL_SHARED_LIBRARIES += libz libcutils libc include $(BUILD_EXECUTABLE) diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 75d77372e..4eec33256 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -35,6 +35,7 @@ #include "mtdutils/mtdutils.h" #include "edify/expr.h" #include "print_sha1.h" +#include "otafault/ota_io.h" static int LoadPartitionContents(const char* filename, FileContents* file); static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token); @@ -79,19 +80,19 @@ int LoadFileContents(const char* filename, FileContents* file) { return -1; } - FILE* f = fopen(filename, "rb"); + FILE* f = ota_fopen(filename, "rb"); if (f == NULL) { printf("failed to open \"%s\": %s\n", filename, strerror(errno)); return -1; } - size_t bytes_read = fread(data.get(), 1, file->size, f); + size_t bytes_read = ota_fread(data.get(), 1, file->size, f); if (bytes_read != static_cast(file->size)) { printf("short read of \"%s\" (%zu bytes of %zd)\n", filename, bytes_read, file->size); - fclose(f); + ota_fclose(f); return -1; } - fclose(f); + ota_fclose(f); file->data = data.release(); SHA1(file->data, file->size, file->sha1); return 0; @@ -180,7 +181,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { } case EMMC: - dev = fopen(partition, "rb"); + dev = ota_fopen(partition, "rb"); if (dev == NULL) { printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); return -1; @@ -209,7 +210,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { break; case EMMC: - read = fread(p, 1, next, dev); + read = ota_fread(p, 1, next, dev); break; } if (next != read) { @@ -255,7 +256,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { break; case EMMC: - fclose(dev); + ota_fclose(dev); break; } @@ -282,7 +283,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { // Save the contents of the given FileContents object under the given // filename. Return 0 on success. int SaveFileContents(const char* filename, const FileContents* file) { - int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR); + int fd = ota_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR); if (fd < 0) { printf("failed to open \"%s\" for write: %s\n", filename, strerror(errno)); return -1; @@ -292,14 +293,14 @@ int SaveFileContents(const char* filename, const FileContents* file) { if (bytes_written != file->size) { printf("short write of \"%s\" (%zd bytes of %zd) (%s)\n", filename, bytes_written, file->size, strerror(errno)); - close(fd); + ota_close(fd); return -1; } - if (fsync(fd) != 0) { + if (ota_fsync(fd) != 0) { printf("fsync of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } - if (close(fd) != 0) { + if (ota_close(fd) != 0) { printf("close of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } @@ -382,7 +383,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) case EMMC: { size_t start = 0; bool success = false; - int fd = open(partition, O_RDWR | O_SYNC); + int fd = ota_open(partition, O_RDWR | O_SYNC); if (fd < 0) { printf("failed to open %s: %s\n", partition, strerror(errno)); return -1; @@ -397,22 +398,22 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) size_t to_write = len - start; if (to_write > 1<<20) to_write = 1<<20; - ssize_t written = TEMP_FAILURE_RETRY(write(fd, data+start, to_write)); + ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data+start, to_write)); if (written == -1) { printf("failed write writing to %s: %s\n", partition, strerror(errno)); return -1; } start += written; } - if (fsync(fd) != 0) { + if (ota_fsync(fd) != 0) { printf("failed to sync to %s (%s)\n", partition, strerror(errno)); return -1; } - if (close(fd) != 0) { + if (ota_close(fd) != 0) { printf("failed to close %s (%s)\n", partition, strerror(errno)); return -1; } - fd = open(partition, O_RDONLY); + fd = ota_open(partition, O_RDONLY); if (fd < 0) { printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno)); return -1; @@ -421,13 +422,13 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) // Drop caches so our subsequent verification read // won't just be reading the cache. sync(); - int dc = open("/proc/sys/vm/drop_caches", O_WRONLY); - if (TEMP_FAILURE_RETRY(write(dc, "3\n", 2)) == -1) { + int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY); + if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) { printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno)); } else { printf(" caches dropped\n"); } - close(dc); + ota_close(dc); sleep(1); // verify @@ -447,7 +448,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) size_t so_far = 0; while (so_far < to_read) { ssize_t read_count = - TEMP_FAILURE_RETRY(read(fd, buffer+so_far, to_read-so_far)); + TEMP_FAILURE_RETRY(ota_read(fd, buffer+so_far, to_read-so_far)); if (read_count == -1) { printf("verify read error %s at %zu: %s\n", partition, p, strerror(errno)); @@ -479,7 +480,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) return -1; } - if (close(fd) != 0) { + if (ota_close(fd) != 0) { printf("error closing %s (%s)\n", partition, strerror(errno)); return -1; } @@ -589,7 +590,7 @@ ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) { ssize_t done = 0; ssize_t wrote; while (done < len) { - wrote = TEMP_FAILURE_RETRY(write(fd, data+done, len-done)); + wrote = TEMP_FAILURE_RETRY(ota_write(fd, data+done, len-done)); if (wrote == -1) { printf("error writing %zd bytes: %s\n", (len-done), strerror(errno)); return done; @@ -934,8 +935,8 @@ static int GenerateTarget(FileContents* source_file, token = &memory_sink_str; } else { // We write the decoded output to ".patch". - output_fd = open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, - S_IRUSR | S_IWUSR); + output_fd = ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, + S_IRUSR | S_IWUSR); if (output_fd < 0) { printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(), strerror(errno)); @@ -958,12 +959,12 @@ static int GenerateTarget(FileContents* source_file, } if (!target_is_partition) { - if (fsync(output_fd) != 0) { + if (ota_fsync(output_fd) != 0) { printf("failed to fsync file \"%s\" (%s)\n", tmp_target_filename.c_str(), strerror(errno)); result = 1; } - if (close(output_fd) != 0) { + if (ota_close(output_fd) != 0) { printf("failed to close file \"%s\" (%s)\n", tmp_target_filename.c_str(), strerror(errno)); result = 1; diff --git a/otafault/Android.mk b/otafault/Android.mk new file mode 100644 index 000000000..75617a146 --- /dev/null +++ b/otafault/Android.mk @@ -0,0 +1,58 @@ +# Copyright 2015 The ANdroid Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific languae governing permissions and +# limitations under the License. + +LOCAL_PATH := $(call my-dir) + +empty := +space := $(empty) $(empty) +comma := , + +ifneq ($(TARGET_INJECT_FAULTS),) +TARGET_INJECT_FAULTS := $(subst $(comma),$(space),$(strip $(TARGET_INJECT_FAULTS))) +endif + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := ota_io.cpp +LOCAL_MODULE_TAGS := eng +LOCAL_MODULE := libotafault +LOCAL_CLANG := true + +ifneq ($(TARGET_INJECT_FAULTS),) +$(foreach ft,$(TARGET_INJECT_FAULTS),\ + $(eval LOCAL_CFLAGS += -DTARGET_$(ft)_FAULT=$(TARGET_$(ft)_FAULT_FILE))) +LOCAL_CFLAGS += -Wno-unused-parameter +LOCAL_CFLAGS += -DTARGET_INJECT_FAULTS +endif + +LOCAL_STATIC_LIBRARIES := libc + +include $(BUILD_STATIC_LIBRARY) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := ota_io.cpp test.cpp +LOCAL_MODULE_TAGS := tests +LOCAL_MODULE := otafault_test +LOCAL_STATIC_LIBRARIES := libc +LOCAL_FORCE_STATIC_EXECUTABLE := true +LOCAL_CFLAGS += -Wno-unused-parameter -Wno-writable-strings + +ifneq ($(TARGET_INJECT_FAULTS),) +$(foreach ft,$(TARGET_INJECT_FAULTS),\ + $(eval LOCAL_CFLAGS += -DTARGET_$(ft)_FAULT=$(TARGET_$(ft)_FAULT_FILE))) +LOCAL_CFLAGS += -DTARGET_INJECT_FAULTS +endif + +include $(BUILD_EXECUTABLE) diff --git a/otafault/ota_io.cpp b/otafault/ota_io.cpp new file mode 100644 index 000000000..02e80f9bf --- /dev/null +++ b/otafault/ota_io.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined (TARGET_INJECT_FAULTS) +#include +#endif + +#include +#include +#include +#include +#include + +#include "ota_io.h" + +#if defined (TARGET_INJECT_FAULTS) +static std::map FilenameCache; +static std::string FaultFileName = +#if defined (TARGET_READ_FAULT) + TARGET_READ_FAULT; +#elif defined (TARGET_WRITE_FAULT) + TARGET_WRITE_FAULT; +#elif defined (TARGET_FSYNC_FAULT) + TARGET_FSYNC_FAULT; +#endif // defined (TARGET_READ_FAULT) +#endif // defined (TARGET_INJECT_FAULTS) + +int ota_open(const char* path, int oflags) { +#if defined (TARGET_INJECT_FAULTS) + // Let the caller handle errors; we do not care if open succeeds or fails + int fd = open(path, oflags); + FilenameCache[fd] = path; + return fd; +#else + return open(path, oflags); +#endif +} + +int ota_open(const char* path, int oflags, mode_t mode) { +#if defined (TARGET_INJECT_FAULTS) + int fd = open(path, oflags, mode); + FilenameCache[fd] = path; + return fd; +#else + return open(path, oflags, mode); +#endif +} + +FILE* ota_fopen(const char* path, const char* mode) { +#if defined (TARGET_INJECT_FAULTS) + FILE* fh = fopen(path, mode); + FilenameCache[(intptr_t)fh] = path; + return fh; +#else + return fopen(path, mode); +#endif +} + +int ota_close(int fd) { +#if defined (TARGET_INJECT_FAULTS) + // descriptors can be reused, so make sure not to leave them in the cahce + FilenameCache.erase(fd); +#endif + return close(fd); +} + +int ota_fclose(FILE* fh) { +#if defined (TARGET_INJECT_FAULTS) + FilenameCache.erase((intptr_t)fh); +#endif + return fclose(fh); +} + +size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream) { +#if defined (TARGET_READ_FAULT) + if (FilenameCache.find((intptr_t)stream) != FilenameCache.end() + && FilenameCache[(intptr_t)stream] == FaultFileName) { + FaultFileName = ""; + errno = EIO; + return 0; + } else { + return fread(ptr, size, nitems, stream); + } +#else + return fread(ptr, size, nitems, stream); +#endif +} + +ssize_t ota_read(int fd, void* buf, size_t nbyte) { +#if defined (TARGET_READ_FAULT) + if (FilenameCache.find(fd) != FilenameCache.end() + && FilenameCache[fd] == FaultFileName) { + FaultFileName = ""; + errno = EIO; + return -1; + } else { + return read(fd, buf, nbyte); + } +#else + return read(fd, buf, nbyte); +#endif +} + +size_t ota_fwrite(const void* ptr, size_t size, size_t count, FILE* stream) { +#if defined (TARGET_WRITE_FAULT) + if (FilenameCache.find((intptr_t)stream) != FilenameCache.end() + && FilenameCache[(intptr_t)stream] == FaultFileName) { + FaultFileName = ""; + errno = EIO; + return 0; + } else { + return fwrite(ptr, size, count, stream); + } +#else + return fwrite(ptr, size, count, stream); +#endif +} + +ssize_t ota_write(int fd, const void* buf, size_t nbyte) { +#if defined (TARGET_WRITE_FAULT) + if (FilenameCache.find(fd) != FilenameCache.end() + && FilenameCache[fd] == FaultFileName) { + FaultFileName = ""; + errno = EIO; + return -1; + } else { + return write(fd, buf, nbyte); + } +#else + return write(fd, buf, nbyte); +#endif +} + +int ota_fsync(int fd) { +#if defined (TARGET_FSYNC_FAULT) + if (FilenameCache.find(fd) != FilenameCache.end() + && FilenameCache[fd] == FaultFileName) { + FaultFileName = ""; + errno = EIO; + return -1; + } else { + return fsync(fd); + } +#else + return fsync(fd); +#endif +} diff --git a/otafault/ota_io.h b/otafault/ota_io.h new file mode 100644 index 000000000..641a5ae0a --- /dev/null +++ b/otafault/ota_io.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Provide a series of proxy functions for basic file accessors. + * The behavior of these functions can be changed to return different + * errors under a variety of conditions. + */ + +#ifndef _UPDATER_OTA_IO_H_ +#define _UPDATER_OTA_IO_H_ + +#include +#include + +int ota_open(const char* path, int oflags); + +int ota_open(const char* path, int oflags, mode_t mode); + +FILE* ota_fopen(const char* filename, const char* mode); + +int ota_close(int fd); + +int ota_fclose(FILE* fh); + +size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream); + +ssize_t ota_read(int fd, void* buf, size_t nbyte); + +size_t ota_fwrite(const void* ptr, size_t size, size_t count, FILE* stream); + +ssize_t ota_write(int fd, const void* buf, size_t nbyte); + +int ota_fsync(int fd); + +#endif diff --git a/otafault/test.cpp b/otafault/test.cpp new file mode 100644 index 000000000..a0f731517 --- /dev/null +++ b/otafault/test.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "ota_io.h" + +int main(int argc, char **argv) { + int fd = open("testdata/test.file", O_RDWR); + char buf[8]; + char *out = "321"; + int readv = ota_read(fd, buf, 4); + printf("Read returned %d\n", readv); + int writev = ota_write(fd, out, 4); + printf("Write returned %d\n", writev); + return 0; +} diff --git a/updater/Android.mk b/updater/Android.mk index 6fdd30895..d7aa613e9 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -45,7 +45,7 @@ LOCAL_STATIC_LIBRARIES += \ endif LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS) -LOCAL_STATIC_LIBRARIES += libapplypatch libbase libedify libmtdutils libminzip libz +LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libedify libmtdutils libminzip libz LOCAL_STATIC_LIBRARIES += libbz LOCAL_STATIC_LIBRARIES += libcutils liblog libc LOCAL_STATIC_LIBRARIES += libselinux diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 6e056006c..44de4e031 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -45,6 +45,7 @@ #include "install.h" #include "openssl/sha.h" #include "minzip/Hash.h" +#include "otafault/ota_io.h" #include "print_sha1.h" #include "unique_fd.h" #include "updater.h" @@ -139,7 +140,7 @@ static bool range_overlaps(const RangeSet& r1, const RangeSet& r2) { static int read_all(int fd, uint8_t* data, size_t size) { size_t so_far = 0; while (so_far < size) { - ssize_t r = TEMP_FAILURE_RETRY(read(fd, data+so_far, size-so_far)); + ssize_t r = TEMP_FAILURE_RETRY(ota_read(fd, data+so_far, size-so_far)); if (r == -1) { fprintf(stderr, "read failed: %s\n", strerror(errno)); return -1; @@ -156,7 +157,7 @@ static int read_all(int fd, std::vector& buffer, size_t size) { static int write_all(int fd, const uint8_t* data, size_t size) { size_t written = 0; while (written < size) { - ssize_t w = TEMP_FAILURE_RETRY(write(fd, data+written, size-written)); + ssize_t w = TEMP_FAILURE_RETRY(ota_write(fd, data+written, size-written)); if (w == -1) { fprintf(stderr, "write failed: %s\n", strerror(errno)); return -1; @@ -553,7 +554,7 @@ static int LoadStash(const std::string& base, const std::string& id, bool verify return -1; } - int fd = TEMP_FAILURE_RETRY(open(fn.c_str(), O_RDONLY)); + int fd = TEMP_FAILURE_RETRY(ota_open(fn.c_str(), O_RDONLY)); unique_fd fd_holder(fd); if (fd == -1) { @@ -610,7 +611,7 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks fprintf(stderr, " writing %d blocks to %s\n", blocks, cn.c_str()); - int fd = TEMP_FAILURE_RETRY(open(fn.c_str(), O_WRONLY | O_CREAT | O_TRUNC, STASH_FILE_MODE)); + int fd = TEMP_FAILURE_RETRY(ota_open(fn.c_str(), O_WRONLY | O_CREAT | O_TRUNC, STASH_FILE_MODE)); unique_fd fd_holder(fd); if (fd == -1) { @@ -622,7 +623,7 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks return -1; } - if (fsync(fd) == -1) { + if (ota_fsync(fd) == -1) { fprintf(stderr, "fsync \"%s\" failed: %s\n", fn.c_str(), strerror(errno)); return -1; } @@ -634,7 +635,7 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks } std::string dname = GetStashFileName(base, "", ""); - int dfd = TEMP_FAILURE_RETRY(open(dname.c_str(), O_RDONLY | O_DIRECTORY)); + int dfd = TEMP_FAILURE_RETRY(ota_open(dname.c_str(), O_RDONLY | O_DIRECTORY)); unique_fd dfd_holder(dfd); if (dfd == -1) { @@ -642,7 +643,7 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks return -1; } - if (fsync(dfd) == -1) { + if (ota_fsync(dfd) == -1) { fprintf(stderr, "fsync \"%s\" failed: %s\n", dname.c_str(), strerror(errno)); return -1; } @@ -1346,7 +1347,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg return StringValue(strdup("")); } - params.fd = TEMP_FAILURE_RETRY(open(blockdev_filename->data, O_RDWR)); + params.fd = TEMP_FAILURE_RETRY(ota_open(blockdev_filename->data, O_RDWR)); unique_fd fd_holder(params.fd); if (params.fd == -1) { @@ -1465,7 +1466,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg } if (params.canwrite) { - if (fsync(params.fd) == -1) { + if (ota_fsync(params.fd) == -1) { fprintf(stderr, "fsync failed: %s\n", strerror(errno)); goto pbiudone; } @@ -1490,7 +1491,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg rc = 0; pbiudone: - if (fsync(params.fd) == -1) { + if (ota_fsync(params.fd) == -1) { fprintf(stderr, "fsync failed: %s\n", strerror(errno)); } // params.fd will be automatically closed because of the fd_holder above. @@ -1614,7 +1615,7 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) return StringValue(strdup("")); } - int fd = open(blockdev_filename->data, O_RDWR); + int fd = ota_open(blockdev_filename->data, O_RDWR); unique_fd fd_holder(fd); if (fd < 0) { ErrorAbort(state, "open \"%s\" failed: %s", blockdev_filename->data, strerror(errno)); @@ -1668,7 +1669,7 @@ Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[]) return StringValue(strdup("")); } - int fd = open(arg_filename->data, O_RDONLY); + int fd = ota_open(arg_filename->data, O_RDONLY); unique_fd fd_holder(fd); if (fd == -1) { ErrorAbort(state, "open \"%s\" failed: %s", arg_filename->data, strerror(errno)); diff --git a/updater/install.cpp b/updater/install.cpp index 45bbf2bc1..1cd9a5690 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -51,6 +51,7 @@ #include "minzip/DirUtil.h" #include "mtdutils/mounts.h" #include "mtdutils/mtdutils.h" +#include "otafault/ota_io.h" #include "updater.h" #include "install.h" #include "tune2fs.h" @@ -557,18 +558,18 @@ Value* PackageExtractFileFn(const char* name, State* state, } { - int fd = TEMP_FAILURE_RETRY(open(dest_path, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, + int fd = TEMP_FAILURE_RETRY(ota_open(dest_path, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR)); if (fd == -1) { printf("%s: can't open %s for write: %s\n", name, dest_path, strerror(errno)); goto done2; } success = mzExtractZipEntryToFile(za, entry, fd); - if (fsync(fd) == -1) { + if (ota_fsync(fd) == -1) { printf("fsync of \"%s\" failed: %s\n", dest_path, strerror(errno)); success = false; } - if (close(fd) == -1) { + if (ota_close(fd) == -1) { printf("close of \"%s\" failed: %s\n", dest_path, strerror(errno)); success = false; } @@ -995,21 +996,21 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { } FILE* f; - f = fopen(filename, "rb"); + f = ota_fopen(filename, "rb"); if (f == NULL) { ErrorAbort(state, "%s: failed to open %s: %s", name, filename, strerror(errno)); goto done; } - if (fread(buffer, 1, st.st_size, f) != static_cast(st.st_size)) { + if (ota_fread(buffer, 1, st.st_size, f) != static_cast(st.st_size)) { ErrorAbort(state, "%s: failed to read %lld bytes from %s", name, (long long)st.st_size+1, filename); - fclose(f); + ota_fclose(f); goto done; } buffer[st.st_size] = '\0'; - fclose(f); + ota_fclose(f); char* line; line = strtok(buffer, "\n"); @@ -1104,7 +1105,7 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { if (contents->type == VAL_STRING) { // we're given a filename as the contents char* filename = contents->data; - FILE* f = fopen(filename, "rb"); + FILE* f = ota_fopen(filename, "rb"); if (f == NULL) { printf("%s: can't open %s: %s\n", name, filename, strerror(errno)); result = strdup(""); @@ -1114,12 +1115,12 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { success = true; char* buffer = reinterpret_cast(malloc(BUFSIZ)); int read; - while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) { + while (success && (read = ota_fread(buffer, 1, BUFSIZ, f)) > 0) { int wrote = mtd_write_data(ctx, buffer, read); success = success && (wrote == read); } free(buffer); - fclose(f); + ota_fclose(f); } else { // we're given a blob as the contents ssize_t wrote = mtd_write_data(ctx, contents->data, contents->size); @@ -1438,10 +1439,10 @@ Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) { // zero out the 'command' field of the bootloader message. memset(buffer, 0, sizeof(((struct bootloader_message*)0)->command)); - FILE* f = fopen(filename, "r+b"); + FILE* f = ota_fopen(filename, "r+b"); fseek(f, offsetof(struct bootloader_message, command), SEEK_SET); - fwrite(buffer, sizeof(((struct bootloader_message*)0)->command), 1, f); - fclose(f); + ota_fwrite(buffer, sizeof(((struct bootloader_message*)0)->command), 1, f); + ota_fclose(f); free(filename); strcpy(buffer, "reboot,"); @@ -1480,7 +1481,7 @@ Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) { // bootloader message that the main recovery uses to save its // arguments in case of the device restarting midway through // package installation. - FILE* f = fopen(filename, "r+b"); + FILE* f = ota_fopen(filename, "r+b"); fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET); int to_write = strlen(stagestr)+1; int max_size = sizeof(((struct bootloader_message*)0)->stage); @@ -1488,8 +1489,8 @@ Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) { to_write = max_size; stagestr[max_size-1] = 0; } - fwrite(stagestr, to_write, 1, f); - fclose(f); + ota_fwrite(stagestr, to_write, 1, f); + ota_fclose(f); free(stagestr); return StringValue(filename); @@ -1506,10 +1507,10 @@ Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) { if (ReadArgs(state, argv, 1, &filename) < 0) return NULL; char buffer[sizeof(((struct bootloader_message*)0)->stage)]; - FILE* f = fopen(filename, "rb"); + FILE* f = ota_fopen(filename, "rb"); fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET); - fread(buffer, sizeof(buffer), 1, f); - fclose(f); + ota_fread(buffer, sizeof(buffer), 1, f); + ota_fclose(f); buffer[sizeof(buffer)-1] = '\0'; return StringValue(strdup(buffer)); @@ -1526,13 +1527,13 @@ Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[]) size_t len; android::base::ParseUint(len_str, &len); - int fd = open(filename, O_WRONLY, 0644); + int fd = ota_open(filename, O_WRONLY, 0644); int success = wipe_block_device(fd, len); free(filename); free(len_str); - close(fd); + ota_close(fd); return StringValue(strdup(success ? "t" : "")); } -- cgit v1.2.3 From 4425c1d960234ae5db904b199ccf39c4ec64b37f Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Wed, 10 Feb 2016 13:47:32 -0800 Subject: Fix some memory leaks. Bug: 26906328 Change-Id: Iebaf03db0cb3054f91715f8c849be6087d01b27b --- install.cpp | 10 +-- minui/resources.cpp | 22 ++--- minzip/Android.mk | 2 +- minzip/DirUtil.c | 236 ---------------------------------------------------- minzip/DirUtil.cpp | 215 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 230 insertions(+), 255 deletions(-) delete mode 100644 minzip/DirUtil.c create mode 100644 minzip/DirUtil.cpp diff --git a/install.cpp b/install.cpp index c0d007709..33c1f5498 100644 --- a/install.cpp +++ b/install.cpp @@ -124,20 +124,20 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) { // - the name of the package zip file. // - const char** args = (const char**)malloc(sizeof(char*) * 5); + const char* args[5]; args[0] = binary; args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk - char* temp = (char*)malloc(10); - sprintf(temp, "%d", pipefd[1]); + char temp[16]; + snprintf(temp, sizeof(temp), "%d", pipefd[1]); args[2] = temp; - args[3] = (char*)path; + args[3] = path; args[4] = NULL; pid_t pid = fork(); if (pid == 0) { umask(022); close(pipefd[0]); - execv(binary, (char* const*)args); + execv(binary, const_cast(args)); fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno)); _exit(-1); } diff --git a/minui/resources.cpp b/minui/resources.cpp index 63a0dff28..fdbe554fe 100644 --- a/minui/resources.cpp +++ b/minui/resources.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include "minui.h" @@ -398,18 +399,13 @@ int res_create_localized_alpha_surface(const char* name, png_infop info_ptr = NULL; png_uint_32 width, height; png_byte channels; - unsigned char* row; png_uint_32 y; + std::vector row; *pSurface = NULL; if (locale == NULL) { - surface = malloc_surface(0); - surface->width = 0; - surface->height = 0; - surface->row_bytes = 0; - surface->pixel_bytes = 1; - goto exit; + return result; } result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); @@ -420,13 +416,13 @@ int res_create_localized_alpha_surface(const char* name, goto exit; } - row = reinterpret_cast(malloc(width)); + row.resize(width); for (y = 0; y < height; ++y) { - png_read_row(png_ptr, row, NULL); + png_read_row(png_ptr, row.data(), NULL); int w = (row[1] << 8) | row[0]; int h = (row[3] << 8) | row[2]; int len = row[4]; - char* loc = (char*)row+5; + char* loc = reinterpret_cast(&row[5]); if (y+1+h >= height || matches_locale(loc, locale)) { printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y); @@ -443,8 +439,8 @@ int res_create_localized_alpha_surface(const char* name, int i; for (i = 0; i < h; ++i, ++y) { - png_read_row(png_ptr, row, NULL); - memcpy(surface->data + i*w, row, w); + png_read_row(png_ptr, row.data(), NULL); + memcpy(surface->data + i*w, row.data(), w); } *pSurface = reinterpret_cast(surface); @@ -452,7 +448,7 @@ int res_create_localized_alpha_surface(const char* name, } else { int i; for (i = 0; i < h; ++i, ++y) { - png_read_row(png_ptr, row, NULL); + png_read_row(png_ptr, row.data(), NULL); } } } diff --git a/minzip/Android.mk b/minzip/Android.mk index 22eabfbb1..3d36fd64e 100644 --- a/minzip/Android.mk +++ b/minzip/Android.mk @@ -4,7 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ Hash.c \ SysUtil.c \ - DirUtil.c \ + DirUtil.cpp \ Inlines.c \ Zip.c diff --git a/minzip/DirUtil.c b/minzip/DirUtil.c deleted file mode 100644 index 97cb2e0ee..000000000 --- a/minzip/DirUtil.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (C) 2007 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include "DirUtil.h" - -typedef enum { DMISSING, DDIR, DILLEGAL } DirStatus; - -static DirStatus -getPathDirStatus(const char *path) -{ - struct stat st; - int err; - - err = stat(path, &st); - if (err == 0) { - /* Something's there; make sure it's a directory. - */ - if (S_ISDIR(st.st_mode)) { - return DDIR; - } - errno = ENOTDIR; - return DILLEGAL; - } else if (errno != ENOENT) { - /* Something went wrong, or something in the path - * is bad. Can't do anything in this situation. - */ - return DILLEGAL; - } - return DMISSING; -} - -int -dirCreateHierarchy(const char *path, int mode, - const struct utimbuf *timestamp, bool stripFileName, - struct selabel_handle *sehnd) -{ - DirStatus ds; - - /* Check for an empty string before we bother - * making any syscalls. - */ - if (path[0] == '\0') { - errno = ENOENT; - return -1; - } - - /* Allocate a path that we can modify; stick a slash on - * the end to make things easier. - */ - size_t pathLen = strlen(path); - char *cpath = (char *)malloc(pathLen + 2); - if (cpath == NULL) { - errno = ENOMEM; - return -1; - } - memcpy(cpath, path, pathLen); - if (stripFileName) { - /* Strip everything after the last slash. - */ - char *c = cpath + pathLen - 1; - while (c != cpath && *c != '/') { - c--; - } - if (c == cpath) { - //xxx test this path - /* No directory component. Act like the path was empty. - */ - errno = ENOENT; - free(cpath); - return -1; - } - c[1] = '\0'; // Terminate after the slash we found. - } else { - /* Make sure that the path ends in a slash. - */ - cpath[pathLen] = '/'; - cpath[pathLen + 1] = '\0'; - } - - /* See if it already exists. - */ - ds = getPathDirStatus(cpath); - if (ds == DDIR) { - return 0; - } else if (ds == DILLEGAL) { - return -1; - } - - /* Walk up the path from the root and make each level. - * If a directory already exists, no big deal. - */ - char *p = cpath; - while (*p != '\0') { - /* Skip any slashes, watching out for the end of the string. - */ - while (*p != '\0' && *p == '/') { - p++; - } - if (*p == '\0') { - break; - } - - /* Find the end of the next path component. - * We know that we'll see a slash before the NUL, - * because we added it, above. - */ - while (*p != '/') { - p++; - } - *p = '\0'; - - /* Check this part of the path and make a new directory - * if necessary. - */ - ds = getPathDirStatus(cpath); - if (ds == DILLEGAL) { - /* Could happen if some other process/thread is - * messing with the filesystem. - */ - free(cpath); - return -1; - } else if (ds == DMISSING) { - int err; - - char *secontext = NULL; - - if (sehnd) { - selabel_lookup(sehnd, &secontext, cpath, mode); - setfscreatecon(secontext); - } - - err = mkdir(cpath, mode); - - if (secontext) { - freecon(secontext); - setfscreatecon(NULL); - } - - if (err != 0) { - free(cpath); - return -1; - } - if (timestamp != NULL && utime(cpath, timestamp)) { - free(cpath); - return -1; - } - } - // else, this directory already exists. - - /* Repair the path and continue. - */ - *p = '/'; - } - free(cpath); - - return 0; -} - -int -dirUnlinkHierarchy(const char *path) -{ - struct stat st; - DIR *dir; - struct dirent *de; - int fail = 0; - - /* is it a file or directory? */ - if (lstat(path, &st) < 0) { - return -1; - } - - /* a file, so unlink it */ - if (!S_ISDIR(st.st_mode)) { - return unlink(path); - } - - /* a directory, so open handle */ - dir = opendir(path); - if (dir == NULL) { - return -1; - } - - /* recurse over components */ - errno = 0; - while ((de = readdir(dir)) != NULL) { - //TODO: don't blow the stack - char dn[PATH_MAX]; - if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) { - continue; - } - snprintf(dn, sizeof(dn), "%s/%s", path, de->d_name); - if (dirUnlinkHierarchy(dn) < 0) { - fail = 1; - break; - } - errno = 0; - } - /* in case readdir or unlink_recursive failed */ - if (fail || errno < 0) { - int save = errno; - closedir(dir); - errno = save; - return -1; - } - - /* close directory handle */ - if (closedir(dir) < 0) { - return -1; - } - - /* delete target directory */ - return rmdir(path); -} diff --git a/minzip/DirUtil.cpp b/minzip/DirUtil.cpp new file mode 100644 index 000000000..823b6ed2f --- /dev/null +++ b/minzip/DirUtil.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2007 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "DirUtil.h" + +typedef enum { DMISSING, DDIR, DILLEGAL } DirStatus; + +static DirStatus +getPathDirStatus(const char *path) +{ + struct stat st; + int err; + + err = stat(path, &st); + if (err == 0) { + /* Something's there; make sure it's a directory. + */ + if (S_ISDIR(st.st_mode)) { + return DDIR; + } + errno = ENOTDIR; + return DILLEGAL; + } else if (errno != ENOENT) { + /* Something went wrong, or something in the path + * is bad. Can't do anything in this situation. + */ + return DILLEGAL; + } + return DMISSING; +} + +int +dirCreateHierarchy(const char *path, int mode, + const struct utimbuf *timestamp, bool stripFileName, + struct selabel_handle *sehnd) +{ + DirStatus ds; + + /* Check for an empty string before we bother + * making any syscalls. + */ + if (path[0] == '\0') { + errno = ENOENT; + return -1; + } + // Allocate a path that we can modify; stick a slash on + // the end to make things easier. + std::string cpath = path; + if (stripFileName) { + // Strip everything after the last slash. + size_t pos = cpath.rfind('/'); + if (pos == std::string::npos) { + errno = ENOENT; + return -1; + } + cpath.resize(pos + 1); + } else { + // Make sure that the path ends in a slash. + cpath.push_back('/'); + } + + /* See if it already exists. + */ + ds = getPathDirStatus(cpath.c_str()); + if (ds == DDIR) { + return 0; + } else if (ds == DILLEGAL) { + return -1; + } + + /* Walk up the path from the root and make each level. + * If a directory already exists, no big deal. + */ + const char *path_start = &cpath[0]; + char *p = &cpath[0]; + while (*p != '\0') { + /* Skip any slashes, watching out for the end of the string. + */ + while (*p != '\0' && *p == '/') { + p++; + } + if (*p == '\0') { + break; + } + + /* Find the end of the next path component. + * We know that we'll see a slash before the NUL, + * because we added it, above. + */ + while (*p != '/') { + p++; + } + *p = '\0'; + + /* Check this part of the path and make a new directory + * if necessary. + */ + ds = getPathDirStatus(path_start); + if (ds == DILLEGAL) { + /* Could happen if some other process/thread is + * messing with the filesystem. + */ + return -1; + } else if (ds == DMISSING) { + int err; + + char *secontext = NULL; + + if (sehnd) { + selabel_lookup(sehnd, &secontext, path_start, mode); + setfscreatecon(secontext); + } + + err = mkdir(path_start, mode); + + if (secontext) { + freecon(secontext); + setfscreatecon(NULL); + } + + if (err != 0) { + return -1; + } + if (timestamp != NULL && utime(path_start, timestamp)) { + return -1; + } + } + // else, this directory already exists. + + // Repair the path and continue. + *p = '/'; + } + return 0; +} + +int +dirUnlinkHierarchy(const char *path) +{ + struct stat st; + DIR *dir; + struct dirent *de; + int fail = 0; + + /* is it a file or directory? */ + if (lstat(path, &st) < 0) { + return -1; + } + + /* a file, so unlink it */ + if (!S_ISDIR(st.st_mode)) { + return unlink(path); + } + + /* a directory, so open handle */ + dir = opendir(path); + if (dir == NULL) { + return -1; + } + + /* recurse over components */ + errno = 0; + while ((de = readdir(dir)) != NULL) { + //TODO: don't blow the stack + char dn[PATH_MAX]; + if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) { + continue; + } + snprintf(dn, sizeof(dn), "%s/%s", path, de->d_name); + if (dirUnlinkHierarchy(dn) < 0) { + fail = 1; + break; + } + errno = 0; + } + /* in case readdir or unlink_recursive failed */ + if (fail || errno < 0) { + int save = errno; + closedir(dir); + errno = save; + return -1; + } + + /* close directory handle */ + if (closedir(dir) < 0) { + return -1; + } + + /* delete target directory */ + return rmdir(path); +} -- cgit v1.2.3 From d6c93afcc28cc65217ba65eeb646009c4f15a2ad Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Wed, 10 Feb 2016 16:41:10 -0800 Subject: applypatch: use vector to store data in FileContents. Bug: 26906416 Change-Id: Ib53b445cd415a1ed5e95733fbc4073f9ef4dbc43 --- applypatch/applypatch.cpp | 103 ++++++++++++++-------------------------------- applypatch/applypatch.h | 12 ++---- applypatch/main.cpp | 67 ++++++++++++++---------------- updater/install.cpp | 21 +++++----- 4 files changed, 77 insertions(+), 126 deletions(-) diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 4eec33256..f66dbe3bf 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -56,8 +56,6 @@ static bool mtd_partitions_scanned = false; // // Return 0 on success. int LoadFileContents(const char* filename, FileContents* file) { - file->data = NULL; - // A special 'filename' beginning with "MTD:" or "EMMC:" means to // load the contents of a partition. if (strncmp(filename, "MTD:", 4) == 0 || @@ -70,31 +68,22 @@ int LoadFileContents(const char* filename, FileContents* file) { return -1; } - file->size = file->st.st_size; - file->data = nullptr; - - std::unique_ptr data( - static_cast(malloc(file->size)), free); - if (data == nullptr) { - printf("failed to allocate memory: %s\n", strerror(errno)); - return -1; - } - + std::vector data(file->st.st_size); FILE* f = ota_fopen(filename, "rb"); if (f == NULL) { printf("failed to open \"%s\": %s\n", filename, strerror(errno)); return -1; } - size_t bytes_read = ota_fread(data.get(), 1, file->size, f); - if (bytes_read != static_cast(file->size)) { - printf("short read of \"%s\" (%zu bytes of %zd)\n", filename, bytes_read, file->size); + size_t bytes_read = ota_fread(data.data(), 1, data.size(), f); + if (bytes_read != data.size()) { + printf("short read of \"%s\" (%zu bytes of %zu)\n", filename, bytes_read, data.size()); ota_fclose(f); return -1; } ota_fclose(f); - file->data = data.release(); - SHA1(file->data, file->size, file->sha1); + file->data = std::move(data); + SHA1(file->data.data(), file->data.size(), file->sha1); return 0; } @@ -193,17 +182,17 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { uint8_t parsed_sha[SHA_DIGEST_LENGTH]; // Allocate enough memory to hold the largest size. - file->data = static_cast(malloc(size[index[pairs-1]])); - char* p = (char*)file->data; - file->size = 0; // # bytes read so far + std::vector data(size[index[pairs-1]]); + char* p = reinterpret_cast(data.data()); + size_t data_size = 0; // # bytes read so far bool found = false; for (size_t i = 0; i < pairs; ++i) { // Read enough additional bytes to get us up to the next size. (Again, // we're trying the possibilities in order of increasing size). - size_t next = size[index[i]] - file->size; - size_t read = 0; + size_t next = size[index[i]] - data_size; if (next > 0) { + size_t read = 0; switch (type) { case MTD: read = mtd_read_data(ctx, p, next); @@ -216,12 +205,11 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { if (next != read) { printf("short read (%zu bytes of %zu) for partition \"%s\"\n", read, next, partition); - free(file->data); - file->data = NULL; return -1; } SHA1_Update(&sha_ctx, p, read); - file->size += read; + data_size += read; + p += read; } // Duplicate the SHA context and finalize the duplicate so we can @@ -233,8 +221,6 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { if (ParseSha1(sha1sum[index[i]].c_str(), parsed_sha) != 0) { printf("failed to parse sha1 %s in %s\n", sha1sum[index[i]].c_str(), filename); - free(file->data); - file->data = NULL; return -1; } @@ -246,8 +232,6 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { found = true; break; } - - p += read; } switch (type) { @@ -264,13 +248,13 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { if (!found) { // Ran off the end of the list of (size,sha1) pairs without finding a match. printf("contents of partition \"%s\" didn't match %s\n", partition, filename); - free(file->data); - file->data = NULL; return -1; } SHA1_Final(file->sha1, &sha_ctx); + data.resize(data_size); + file->data = std::move(data); // Fake some stat() info. file->st.st_mode = 0644; file->st.st_uid = 0; @@ -289,10 +273,10 @@ int SaveFileContents(const char* filename, const FileContents* file) { return -1; } - ssize_t bytes_written = FileSink(file->data, file->size, &fd); - if (bytes_written != file->size) { - printf("short write of \"%s\" (%zd bytes of %zd) (%s)\n", - filename, bytes_written, file->size, strerror(errno)); + ssize_t bytes_written = FileSink(file->data.data(), file->data.size(), &fd); + if (bytes_written != static_cast(file->data.size())) { + printf("short write of \"%s\" (%zd bytes of %zu) (%s)\n", + filename, bytes_written, file->data.size(), strerror(errno)); ota_close(fd); return -1; } @@ -543,7 +527,6 @@ int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, int applypatch_check(const char* filename, int num_patches, char** const patch_sha1_str) { FileContents file; - file.data = NULL; // It's okay to specify no sha1s; the check will pass if the // LoadFileContents is successful. (Useful for reading @@ -555,9 +538,6 @@ int applypatch_check(const char* filename, int num_patches, printf("file \"%s\" doesn't have any of expected " "sha1 sums; checking cache\n", filename); - free(file.data); - file.data = NULL; - // 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 @@ -571,12 +551,9 @@ int applypatch_check(const char* filename, int num_patches, if (FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0) { printf("cache bits don't match any sha1 for \"%s\"\n", filename); - free(file.data); return 1; } } - - free(file.data); return 0; } @@ -674,8 +651,6 @@ int applypatch(const char* source_filename, FileContents copy_file; FileContents source_file; - copy_file.data = NULL; - source_file.data = NULL; const Value* source_patch_value = NULL; const Value* copy_patch_value = NULL; @@ -685,22 +660,20 @@ int applypatch(const char* source_filename, // The early-exit case: the patch was already applied, this file // has the desired hash, nothing for us to do. printf("already %s\n", short_sha1(target_sha1).c_str()); - free(source_file.data); return 0; } } - if (source_file.data == NULL || + if (source_file.data.empty() || (target_filename != source_filename && strcmp(target_filename, source_filename) != 0)) { // Need to load the source file: either we failed to load the // target file, or we did but it's different from the source file. - free(source_file.data); - source_file.data = NULL; + source_file.data.clear(); LoadFileContents(source_filename, &source_file); } - if (source_file.data != NULL) { + if (!source_file.data.empty()) { int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str, num_patches); if (to_use >= 0) { source_patch_value = patch_data[to_use]; @@ -708,8 +681,7 @@ int applypatch(const char* source_filename, } if (source_patch_value == NULL) { - free(source_file.data); - source_file.data = NULL; + source_file.data.clear(); printf("source file is bad; trying copy\n"); if (LoadFileContents(CACHE_TEMP_SOURCE, ©_file) < 0) { @@ -726,19 +698,14 @@ int applypatch(const char* source_filename, if (copy_patch_value == NULL) { // fail. printf("copy file doesn't match source SHA-1s either\n"); - free(copy_file.data); return 1; } } - int result = GenerateTarget(&source_file, source_patch_value, - ©_file, copy_patch_value, - source_filename, target_filename, - target_sha1, target_size, bonus_data); - free(source_file.data); - free(copy_file.data); - - return result; + return GenerateTarget(&source_file, source_patch_value, + ©_file, copy_patch_value, + source_filename, target_filename, + target_sha1, target_size, bonus_data); } /* @@ -759,7 +726,6 @@ int applypatch_flash(const char* source_filename, const char* target_filename, } FileContents source_file; - source_file.data = NULL; std::string target_str(target_filename); std::vector pieces = android::base::Split(target_str, ":"); @@ -777,7 +743,6 @@ int applypatch_flash(const char* source_filename, const char* target_filename, // The early-exit case: the image was already applied, this partition // has the desired hash, nothing for us to do. printf("already %s\n", short_sha1(target_sha1).c_str()); - free(source_file.data); return 0; } @@ -787,18 +752,14 @@ int applypatch_flash(const char* source_filename, const char* target_filename, printf("source \"%s\" doesn't have expected sha1 sum\n", source_filename); printf("expected: %s, found: %s\n", short_sha1(target_sha1).c_str(), short_sha1(source_file.sha1).c_str()); - free(source_file.data); return 1; } } - if (WriteToPartition(source_file.data, target_size, target_filename) != 0) { + if (WriteToPartition(source_file.data.data(), target_size, target_filename) != 0) { printf("write of copied data to %s failed\n", target_filename); - free(source_file.data); return 1; } - - free(source_file.data); return 0; } @@ -867,7 +828,7 @@ static int GenerateTarget(FileContents* source_file, // We still write the original source to cache, in case // the partition write is interrupted. - if (MakeFreeSpaceOnCache(source_file->size) < 0) { + if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { printf("not enough free space on /cache\n"); return 1; } @@ -908,7 +869,7 @@ static int GenerateTarget(FileContents* source_file, return 1; } - if (MakeFreeSpaceOnCache(source_file->size) < 0) { + if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { printf("not enough free space on /cache\n"); return 1; } @@ -951,10 +912,10 @@ static int GenerateTarget(FileContents* source_file, int result; if (use_bsdiff) { - result = ApplyBSDiffPatch(source_to_use->data, source_to_use->size, + result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(), patch, 0, sink, token, &ctx); } else { - result = ApplyImagePatch(source_to_use->data, source_to_use->size, + result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(), patch, sink, token, &ctx, bonus_data); } diff --git a/applypatch/applypatch.h b/applypatch/applypatch.h index 096596f03..9ee39d293 100644 --- a/applypatch/applypatch.h +++ b/applypatch/applypatch.h @@ -25,17 +25,11 @@ #include "openssl/sha.h" #include "edify/expr.h" -typedef struct _Patch { +struct FileContents { uint8_t sha1[SHA_DIGEST_LENGTH]; - const char* patch_filename; -} Patch; - -typedef struct _FileContents { - uint8_t sha1[SHA_DIGEST_LENGTH]; - unsigned char* data; - ssize_t size; + std::vector data; 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 diff --git a/applypatch/main.cpp b/applypatch/main.cpp index 7606d5d3c..9013760c4 100644 --- a/applypatch/main.cpp +++ b/applypatch/main.cpp @@ -46,40 +46,32 @@ static int SpaceMode(int argc, char** argv) { return CacheSizeCheck(bytes); } -// Parse arguments (which should be of the form "" or -// ":" into the new parallel arrays *sha1s and -// *patches (loading file contents into the patches). Returns true on +// Parse arguments (which should be of the form ":" +// into the new parallel arrays *sha1s and *files.Returns true on // success. static bool ParsePatchArgs(int argc, char** argv, std::vector* sha1s, - std::vector>* patches) { + std::vector* files) { uint8_t digest[SHA_DIGEST_LENGTH]; for (int i = 0; i < argc; ++i) { char* colon = strchr(argv[i], ':'); - if (colon != NULL) { - *colon = '\0'; - ++colon; + if (colon == nullptr) { + printf("no ':' in patch argument \"%s\"\n", argv[i]); + return false; } - + *colon = '\0'; + ++colon; if (ParseSha1(argv[i], digest) != 0) { printf("failed to parse sha1 \"%s\"\n", argv[i]); return false; } sha1s->push_back(argv[i]); - if (colon == NULL) { - patches->emplace_back(nullptr, FreeValue); - } else { - FileContents fc; - if (LoadFileContents(colon, &fc) != 0) { - return false; - } - std::unique_ptr value(new Value, FreeValue); - value->type = VAL_BLOB; - value->size = fc.size; - value->data = reinterpret_cast(fc.data); - patches->push_back(std::move(value)); + FileContents fc; + if (LoadFileContents(colon, &fc) != 0) { + return false; } + files->push_back(std::move(fc)); } return true; } @@ -90,17 +82,19 @@ static int FlashMode(const char* src_filename, const char* tgt_filename, } static int PatchMode(int argc, char** argv) { - std::unique_ptr bonus(nullptr, FreeValue); + FileContents bonusFc; + Value bonusValue; + Value* bonus = nullptr; + if (argc >= 3 && strcmp(argv[1], "-b") == 0) { - FileContents fc; - if (LoadFileContents(argv[2], &fc) != 0) { + if (LoadFileContents(argv[2], &bonusFc) != 0) { printf("failed to load bonus file %s\n", argv[2]); return 1; } - bonus.reset(new Value); + bonus = &bonusValue; bonus->type = VAL_BLOB; - bonus->size = fc.size; - bonus->data = reinterpret_cast(fc.data); + bonus->size = bonusFc.data.size(); + bonus->data = reinterpret_cast(bonusFc.data.data()); argc -= 2; argv += 2; } @@ -118,28 +112,29 @@ static int PatchMode(int argc, char** argv) { // If no : is provided, it is in flash mode. if (argc == 5) { - if (bonus != NULL) { + if (bonus != nullptr) { printf("bonus file not supported in flash mode\n"); return 1; } return FlashMode(argv[1], argv[2], argv[3], target_size); } - - std::vector sha1s; - std::vector> patches; - if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &patches)) { + std::vector files; + if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &files)) { printf("failed to parse patch args\n"); return 1; } - - std::vector patch_ptrs; - for (const auto& p : patches) { - patch_ptrs.push_back(p.get()); + std::vector patches(files.size()); + std::vector patch_ptrs(files.size()); + for (size_t i = 0; i < files.size(); ++i) { + patches[i].type = VAL_BLOB; + patches[i].size = files[i].data.size(); + patches[i].data = reinterpret_cast(files[i].data.data()); + patch_ptrs[i] = &patches[i]; } return applypatch(argv[1], argv[2], argv[3], target_size, patch_ptrs.size(), sha1s.data(), - patch_ptrs.data(), bonus.get()); + patch_ptrs.data(), bonus); } // This program applies binary patches to files in a way that is safe diff --git a/updater/install.cpp b/updater/install.cpp index 1cd9a5690..413e147a1 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -1398,21 +1398,22 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) { char* filename; if (ReadArgs(state, argv, 1, &filename) < 0) return NULL; - Value* v = reinterpret_cast(malloc(sizeof(Value))); + Value* v = static_cast(malloc(sizeof(Value))); + if (v == nullptr) { + return nullptr; + } v->type = VAL_BLOB; + v->size = -1; + v->data = nullptr; FileContents fc; if (LoadFileContents(filename, &fc) != 0) { - free(filename); - v->size = -1; - v->data = NULL; - free(fc.data); - return v; + v->data = static_cast(malloc(fc.data.size())); + if (v->data != nullptr) { + memcpy(v->data, fc.data.data(), fc.data.size()); + v->size = fc.data.size(); + } } - - v->size = fc.size; - v->data = (char*)fc.data; - free(filename); return v; } -- cgit v1.2.3 From fa4f1b75b6686f73a253536d6ce6deb3ed065148 Mon Sep 17 00:00:00 2001 From: Sen Jiang Date: Thu, 11 Feb 2016 16:14:23 -0800 Subject: imgdiff: don't fail if gzip is corrupted. Treat it as a normal chunk if inflate() fails. Test: run imgdiff on corrupted gzip and apply the patch Bug: 27153028 Change-Id: Idcbb3c1360ec0774e6c7861b21d99af8ee10604a --- applypatch/imgdiff.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index a3c10b40a..2aa4a6862 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -407,7 +407,6 @@ unsigned char* ReadImage(const char* filename, while (pos < sz) { unsigned char* p = img+pos; - bool processed_deflate = false; if (sz - pos >= 4 && p[0] == 0x1f && p[1] == 0x8b && p[2] == 0x08 && // deflate compression @@ -461,28 +460,27 @@ unsigned char* ReadImage(const char* filename, strm.next_out = curr->data + curr->len; ret = inflate(&strm, Z_NO_FLUSH); if (ret < 0) { - if (!processed_deflate) { - // This is the first chunk, assume that it's just a spurious - // gzip header instead of a real one. - break; - } - printf("Error: inflate failed [%s] at file offset [%zu]\n" - "imgdiff only supports gzip kernel compression," - " did you try CONFIG_KERNEL_LZO?\n", + printf("Warning: inflate failed [%s] at offset [%zu]," + " treating as a normal chunk\n", strm.msg, chunk_offset); - free(img); - return NULL; + break; } curr->len = allocated - strm.avail_out; if (strm.avail_out == 0) { allocated *= 2; curr->data = reinterpret_cast(realloc(curr->data, allocated)); } - processed_deflate = true; } while (ret != Z_STREAM_END); curr->deflate_len = sz - strm.avail_in - pos; inflateEnd(&strm); + + if (ret < 0) { + free(curr->data); + *num_chunks -= 2; + continue; + } + pos += curr->deflate_len; p += curr->deflate_len; ++curr; -- cgit v1.2.3 From cc07b3556510d03e389a8994a8e5dbed3f3bbbb4 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Fri, 12 Feb 2016 15:00:52 -0800 Subject: minadbd: update for adb_thread_create signature change. Change-Id: Ifa0b4d8c1cf0bb39abac61984ff165e82e41222c --- minadbd/services.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/minadbd/services.cpp b/minadbd/services.cpp index d25648fb4..658a43f36 100644 --- a/minadbd/services.cpp +++ b/minadbd/services.cpp @@ -35,11 +35,10 @@ struct stinfo { void *cookie; }; -void* service_bootstrap_func(void* x) { +void service_bootstrap_func(void* x) { stinfo* sti = reinterpret_cast(x); sti->func(sti->fd, sti->cookie); free(sti); - return 0; } static void sideload_host_service(int sfd, void* data) { -- cgit v1.2.3 From f3e05f504d9ef387228e5bcd28723f6617991e8c Mon Sep 17 00:00:00 2001 From: Sen Jiang Date: Tue, 16 Feb 2016 11:23:09 -0800 Subject: applypatch: Add libimgpatch.pc Test: pkg-config --libs libimgpatch Bug: 26866274 Change-Id: I79a103099d951943a88768c577224fccacbb79e3 --- applypatch/libimgpatch.pc | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 applypatch/libimgpatch.pc diff --git a/applypatch/libimgpatch.pc b/applypatch/libimgpatch.pc new file mode 100644 index 000000000..e5002934f --- /dev/null +++ b/applypatch/libimgpatch.pc @@ -0,0 +1,6 @@ +# This file is for libimgpatch in Chrome OS. + +Name: libimgpatch +Description: Apply imgdiff patch +Version: 0.0.1 +Libs: -limgpatch -lbz2 -lz -- cgit v1.2.3 From a029c9a45888141a2fa382e0b1868e55db1f36d2 Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Thu, 18 Feb 2016 11:32:10 -0800 Subject: Fix integer overflows in recovery procedure. Bug: 26960931 Change-Id: Ieae45caccfb4728fcf514f0d920976585d8e6caf --- minzip/SysUtil.c | 32 +++++++++++++++++++++++++++----- updater/updater.cpp | 13 ++++++------- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/minzip/SysUtil.c b/minzip/SysUtil.c index 09ec8768f..491951c9e 100644 --- a/minzip/SysUtil.c +++ b/minzip/SysUtil.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,11 @@ static bool sysMapFD(int fd, MemMapping* pMap) { pMap->length = sb.st_size; pMap->range_count = 1; pMap->ranges = malloc(sizeof(MappedRange)); + if (pMap->ranges == NULL) { + LOGE("malloc failed: %s\n", strerror(errno)); + munmap(memPtr, sb.st_size); + return false; + } pMap->ranges[0].addr = memPtr; pMap->ranges[0].length = sb.st_size; @@ -50,7 +56,7 @@ static int sysMapBlockFile(FILE* mapf, MemMapping* pMap) char block_dev[PATH_MAX+1]; size_t size; unsigned int blksize; - unsigned int blocks; + size_t blocks; unsigned int range_count; unsigned int i; @@ -69,18 +75,28 @@ static int sysMapBlockFile(FILE* mapf, MemMapping* pMap) LOGE("failed to parse block map header\n"); return -1; } - - blocks = ((size-1) / blksize) + 1; + if (blksize != 0) { + blocks = ((size-1) / blksize) + 1; + } + if (size == 0 || blksize == 0 || blocks > SIZE_MAX / blksize) { + LOGE("invalid data in block map file: size %zu, blksize %u, range_count %u\n", + size, blksize, range_count); + return -1; + } pMap->range_count = range_count; - pMap->ranges = malloc(range_count * sizeof(MappedRange)); - memset(pMap->ranges, 0, range_count * sizeof(MappedRange)); + pMap->ranges = calloc(range_count, sizeof(MappedRange)); + if (pMap->ranges == NULL) { + LOGE("calloc(%u, %zu) failed: %s\n", range_count, sizeof(MappedRange), strerror(errno)); + return -1; + } // Reserve enough contiguous address space for the whole file. unsigned char* reserve; reserve = mmap64(NULL, blocks * blksize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); if (reserve == MAP_FAILED) { LOGE("failed to reserve address space: %s\n", strerror(errno)); + free(pMap->ranges); return -1; } @@ -90,6 +106,8 @@ static int sysMapBlockFile(FILE* mapf, MemMapping* pMap) int fd = open(block_dev, O_RDONLY); if (fd < 0) { LOGE("failed to open block device %s: %s\n", block_dev, strerror(errno)); + munmap(reserve, blocks * blksize); + free(pMap->ranges); return -1; } @@ -98,12 +116,16 @@ static int sysMapBlockFile(FILE* mapf, MemMapping* pMap) int start, end; if (fscanf(mapf, "%d %d\n", &start, &end) != 2) { LOGE("failed to parse range %d in block map\n", i); + munmap(reserve, blocks * blksize); + free(pMap->ranges); return -1; } void* addr = mmap64(next, (end-start)*blksize, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, ((off64_t)start)*blksize); if (addr == MAP_FAILED) { LOGE("failed to map block %d: %s\n", i, strerror(errno)); + munmap(reserve, blocks * blksize); + free(pMap->ranges); return -1; } pMap->ranges[i].addr = addr; diff --git a/updater/updater.cpp b/updater/updater.cpp index 0f22e6d04..80e75037c 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -19,6 +19,8 @@ #include #include +#include + #include "edify/expr.h" #include "updater.h" #include "install.h" @@ -89,12 +91,11 @@ int main(int argc, char** argv) { return 4; } - char* script = reinterpret_cast(malloc(script_entry->uncompLen+1)); - if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) { + std::string script(script_entry->uncompLen, '\0'); + if (!mzReadZipEntry(&za, script_entry, &script[0], script_entry->uncompLen)) { printf("failed to read script from package\n"); return 5; } - script[script_entry->uncompLen] = '\0'; // Configure edify's functions. @@ -108,7 +109,7 @@ int main(int argc, char** argv) { Expr* root; int error_count = 0; - int error = parse_string(script, &root, &error_count); + int error = parse_string(script.c_str(), &root, &error_count); if (error != 0 || error_count > 0) { printf("%d parse errors\n", error_count); return 6; @@ -135,7 +136,7 @@ int main(int argc, char** argv) { State state; state.cookie = &updater_info; - state.script = script; + state.script = &script[0]; state.errmsg = NULL; char* result = Evaluate(&state, root); @@ -163,7 +164,5 @@ int main(int argc, char** argv) { mzCloseZipArchive(updater_info.package_zip); } sysReleaseMap(&map); - free(script); - return 0; } -- cgit v1.2.3 From 7d626df079196780635068ae13de2fdadccdfa2c Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 19 Feb 2016 10:33:01 -0800 Subject: Fix minui cleanup path on error. bootable/recovery/minui/resources.cpp:321:21: warning: Branch condition evaluates to a garbage value if (surface[i]) free(surface[i]); ^~~~~~~~~~ bootable/recovery/minui/resources.cpp:424:13: warning: Value stored to 'len' during its initialization is never read int len = row[4]; ^~~ ~~~~~~ Bug: http://b/27264652 Change-Id: Icc1a914c59d6a89dab1b752b2cd2b40549566481 --- minui/resources.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/minui/resources.cpp b/minui/resources.cpp index fdbe554fe..8489d60ef 100644 --- a/minui/resources.cpp +++ b/minui/resources.cpp @@ -283,7 +283,7 @@ int res_create_multi_display_surface(const char* name, int* frames, int* fps, goto exit; } - surface = reinterpret_cast(malloc(*frames * sizeof(GRSurface*))); + surface = reinterpret_cast(calloc(*frames, sizeof(GRSurface*))); if (surface == NULL) { result = -8; goto exit; @@ -318,7 +318,7 @@ exit: if (result < 0) { if (surface) { for (int i = 0; i < *frames; ++i) { - if (surface[i]) free(surface[i]); + free(surface[i]); } free(surface); } @@ -421,7 +421,7 @@ int res_create_localized_alpha_surface(const char* name, png_read_row(png_ptr, row.data(), NULL); int w = (row[1] << 8) | row[0]; int h = (row[3] << 8) | row[2]; - int len = row[4]; + __unused int len = row[4]; char* loc = reinterpret_cast(&row[5]); if (y+1+h >= height || matches_locale(loc, locale)) { -- cgit v1.2.3 From d940887dde23597dc358b16d96ca48dd7480fee6 Mon Sep 17 00:00:00 2001 From: Jed Estep Date: Tue, 15 Dec 2015 16:04:53 -0800 Subject: Control fault injection with config files instead of build flags Bug: 26570379 Change-Id: I76109d09276d6e3ed3a32b6fedafb2582f545c0c --- applypatch/applypatch.cpp | 2 +- otafault/Android.mk | 43 ++++-------- otafault/config.cpp | 65 ++++++++++++++++++ otafault/config.h | 74 +++++++++++++++++++++ otafault/ota_io.cpp | 163 +++++++++++++++++++++------------------------- otafault/ota_io.h | 4 ++ otafault/test.cpp | 6 +- updater/blockimg.cpp | 2 +- updater/install.cpp | 2 +- updater/updater.cpp | 2 + 10 files changed, 242 insertions(+), 121 deletions(-) create mode 100644 otafault/config.cpp create mode 100644 otafault/config.h diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index f66dbe3bf..644515997 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -34,8 +34,8 @@ #include "applypatch.h" #include "mtdutils/mtdutils.h" #include "edify/expr.h" +#include "ota_io.h" #include "print_sha1.h" -#include "otafault/ota_io.h" static int LoadPartitionContents(const char* filename, FileContents* file); static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token); diff --git a/otafault/Android.mk b/otafault/Android.mk index 75617a146..7468de6c4 100644 --- a/otafault/Android.mk +++ b/otafault/Android.mk @@ -1,10 +1,10 @@ -# Copyright 2015 The ANdroid Open Source Project +# Copyright 2015 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -14,45 +14,30 @@ LOCAL_PATH := $(call my-dir) -empty := -space := $(empty) $(empty) -comma := , - -ifneq ($(TARGET_INJECT_FAULTS),) -TARGET_INJECT_FAULTS := $(subst $(comma),$(space),$(strip $(TARGET_INJECT_FAULTS))) -endif - include $(CLEAR_VARS) -LOCAL_SRC_FILES := ota_io.cpp +otafault_static_libs := \ + libminzip \ + libz \ + libselinux \ + +LOCAL_SRC_FILES := config.cpp ota_io.cpp LOCAL_MODULE_TAGS := eng LOCAL_MODULE := libotafault LOCAL_CLANG := true - -ifneq ($(TARGET_INJECT_FAULTS),) -$(foreach ft,$(TARGET_INJECT_FAULTS),\ - $(eval LOCAL_CFLAGS += -DTARGET_$(ft)_FAULT=$(TARGET_$(ft)_FAULT_FILE))) -LOCAL_CFLAGS += -Wno-unused-parameter -LOCAL_CFLAGS += -DTARGET_INJECT_FAULTS -endif - -LOCAL_STATIC_LIBRARIES := libc +LOCAL_C_INCLUDES := bootable/recovery +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) +LOCAL_WHOLE_STATIC_LIBRARIES := $(otafault_static_libs) include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) -LOCAL_SRC_FILES := ota_io.cpp test.cpp +LOCAL_SRC_FILES := config.cpp ota_io.cpp test.cpp LOCAL_MODULE_TAGS := tests LOCAL_MODULE := otafault_test -LOCAL_STATIC_LIBRARIES := libc +LOCAL_STATIC_LIBRARIES := $(otafault_static_libs) +LOCAL_C_INCLUDES := bootable/recovery LOCAL_FORCE_STATIC_EXECUTABLE := true -LOCAL_CFLAGS += -Wno-unused-parameter -Wno-writable-strings - -ifneq ($(TARGET_INJECT_FAULTS),) -$(foreach ft,$(TARGET_INJECT_FAULTS),\ - $(eval LOCAL_CFLAGS += -DTARGET_$(ft)_FAULT=$(TARGET_$(ft)_FAULT_FILE))) -LOCAL_CFLAGS += -DTARGET_INJECT_FAULTS -endif include $(BUILD_EXECUTABLE) diff --git a/otafault/config.cpp b/otafault/config.cpp new file mode 100644 index 000000000..c87f9a631 --- /dev/null +++ b/otafault/config.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include + +#include "minzip/Zip.h" +#include "config.h" +#include "ota_io.h" + +#define OTAIO_MAX_FNAME_SIZE 128 + +static ZipArchive* archive; +static std::map should_inject_cache; + +static const char* get_type_path(const char* io_type) { + char* path = (char*)calloc(strlen(io_type) + strlen(OTAIO_BASE_DIR) + 2, sizeof(char)); + sprintf(path, "%s/%s", OTAIO_BASE_DIR, io_type); + return path; +} + +void ota_io_init(ZipArchive* za) { + archive = za; + ota_set_fault_files(); +} + +bool should_fault_inject(const char* io_type) { + if (should_inject_cache.find(io_type) != should_inject_cache.end()) { + return should_inject_cache[io_type]; + } + const char* type_path = get_type_path(io_type); + const ZipEntry* entry = mzFindZipEntry(archive, type_path); + should_inject_cache[type_path] = entry != nullptr; + free((void*)type_path); + return entry != NULL; +} + +bool should_hit_cache() { + return should_fault_inject(OTAIO_CACHE); +} + +std::string fault_fname(const char* io_type) { + const char* type_path = get_type_path(io_type); + char* fname = (char*) calloc(OTAIO_MAX_FNAME_SIZE, sizeof(char)); + const ZipEntry* entry = mzFindZipEntry(archive, type_path); + mzReadZipEntry(archive, entry, fname, OTAIO_MAX_FNAME_SIZE); + free((void*)type_path); + return std::string(fname); +} diff --git a/otafault/config.h b/otafault/config.h new file mode 100644 index 000000000..4430be3fb --- /dev/null +++ b/otafault/config.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Read configuration files in the OTA package to determine which files, if any, will trigger errors. + * + * OTA packages can be modified to trigger errors by adding a top-level + * directory called .libotafault, which may optionally contain up to three + * files called READ, WRITE, and FSYNC. Each one of these optional files + * contains the name of a single file on the device disk which will cause + * an IO error on the first call of the appropriate I/O action to that file. + * + * Example: + * ota.zip + * + * .libotafault + * WRITE + * + * If the contents of the file WRITE were /system/build.prop, the first write + * action to /system/build.prop would fail with EIO. Note that READ and + * FSYNC files are absent, so these actions will not cause an error. + */ + +#ifndef _UPDATER_OTA_IO_CFG_H_ +#define _UPDATER_OTA_IO_CFG_H_ + +#include + +#include + +#include "minzip/Zip.h" + +#define OTAIO_BASE_DIR ".libotafault" +#define OTAIO_READ "READ" +#define OTAIO_WRITE "WRITE" +#define OTAIO_FSYNC "FSYNC" +#define OTAIO_CACHE "CACHE" + +/* + * Initialize libotafault by providing a reference to the OTA package. + */ +void ota_io_init(ZipArchive* za); + +/* + * Return true if a config file is present for the given IO type. + */ +bool should_fault_inject(const char* io_type); + +/* + * Return true if an EIO should occur on the next hit to /cache/saved.file + * instead of the next hit to the specified file. + */ +bool should_hit_cache(); + +/* + * Return the name of the file that should cause an error for the + * given IO type. + */ +std::string fault_fname(const char* io_type); + +#endif diff --git a/otafault/ota_io.cpp b/otafault/ota_io.cpp index 02e80f9bf..2ce3dfcc2 100644 --- a/otafault/ota_io.cpp +++ b/otafault/ota_io.cpp @@ -14,9 +14,7 @@ * limitations under the License. */ -#if defined (TARGET_INJECT_FAULTS) #include -#endif #include #include @@ -24,137 +22,128 @@ #include #include +#include "config.h" #include "ota_io.h" -#if defined (TARGET_INJECT_FAULTS) -static std::map FilenameCache; -static std::string FaultFileName = -#if defined (TARGET_READ_FAULT) - TARGET_READ_FAULT; -#elif defined (TARGET_WRITE_FAULT) - TARGET_WRITE_FAULT; -#elif defined (TARGET_FSYNC_FAULT) - TARGET_FSYNC_FAULT; -#endif // defined (TARGET_READ_FAULT) -#endif // defined (TARGET_INJECT_FAULTS) +static std::map filename_cache; +static std::string read_fault_file_name = ""; +static std::string write_fault_file_name = ""; +static std::string fsync_fault_file_name = ""; + +static bool get_hit_file(const char* cached_path, std::string ffn) { + return should_hit_cache() + ? !strncmp(cached_path, OTAIO_CACHE_FNAME, strlen(cached_path)) + : !strncmp(cached_path, ffn.c_str(), strlen(cached_path)); +} + +void ota_set_fault_files() { + if (should_fault_inject(OTAIO_READ)) { + read_fault_file_name = fault_fname(OTAIO_READ); + } + if (should_fault_inject(OTAIO_WRITE)) { + write_fault_file_name = fault_fname(OTAIO_WRITE); + } + if (should_fault_inject(OTAIO_FSYNC)) { + fsync_fault_file_name = fault_fname(OTAIO_FSYNC); + } +} int ota_open(const char* path, int oflags) { -#if defined (TARGET_INJECT_FAULTS) // Let the caller handle errors; we do not care if open succeeds or fails int fd = open(path, oflags); - FilenameCache[fd] = path; + filename_cache[fd] = path; return fd; -#else - return open(path, oflags); -#endif } int ota_open(const char* path, int oflags, mode_t mode) { -#if defined (TARGET_INJECT_FAULTS) int fd = open(path, oflags, mode); - FilenameCache[fd] = path; - return fd; -#else - return open(path, oflags, mode); -#endif -} + filename_cache[fd] = path; + return fd; } FILE* ota_fopen(const char* path, const char* mode) { -#if defined (TARGET_INJECT_FAULTS) FILE* fh = fopen(path, mode); - FilenameCache[(intptr_t)fh] = path; + filename_cache[(intptr_t)fh] = path; return fh; -#else - return fopen(path, mode); -#endif } int ota_close(int fd) { -#if defined (TARGET_INJECT_FAULTS) - // descriptors can be reused, so make sure not to leave them in the cahce - FilenameCache.erase(fd); -#endif + // descriptors can be reused, so make sure not to leave them in the cache + filename_cache.erase(fd); return close(fd); } int ota_fclose(FILE* fh) { -#if defined (TARGET_INJECT_FAULTS) - FilenameCache.erase((intptr_t)fh); -#endif + filename_cache.erase((intptr_t)fh); return fclose(fh); } size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream) { -#if defined (TARGET_READ_FAULT) - if (FilenameCache.find((intptr_t)stream) != FilenameCache.end() - && FilenameCache[(intptr_t)stream] == FaultFileName) { - FaultFileName = ""; - errno = EIO; - return 0; - } else { - return fread(ptr, size, nitems, stream); + if (should_fault_inject(OTAIO_READ)) { + auto cached = filename_cache.find((intptr_t)stream); + const char* cached_path = cached->second; + if (cached != filename_cache.end() && + get_hit_file(cached_path, read_fault_file_name)) { + read_fault_file_name = ""; + errno = EIO; + return 0; + } } -#else return fread(ptr, size, nitems, stream); -#endif } ssize_t ota_read(int fd, void* buf, size_t nbyte) { -#if defined (TARGET_READ_FAULT) - if (FilenameCache.find(fd) != FilenameCache.end() - && FilenameCache[fd] == FaultFileName) { - FaultFileName = ""; - errno = EIO; - return -1; - } else { - return read(fd, buf, nbyte); + if (should_fault_inject(OTAIO_READ)) { + auto cached = filename_cache.find(fd); + const char* cached_path = cached->second; + if (cached != filename_cache.end() + && get_hit_file(cached_path, read_fault_file_name)) { + read_fault_file_name = ""; + errno = EIO; + return -1; + } } -#else return read(fd, buf, nbyte); -#endif } size_t ota_fwrite(const void* ptr, size_t size, size_t count, FILE* stream) { -#if defined (TARGET_WRITE_FAULT) - if (FilenameCache.find((intptr_t)stream) != FilenameCache.end() - && FilenameCache[(intptr_t)stream] == FaultFileName) { - FaultFileName = ""; - errno = EIO; - return 0; - } else { - return fwrite(ptr, size, count, stream); + if (should_fault_inject(OTAIO_WRITE)) { + auto cached = filename_cache.find((intptr_t)stream); + const char* cached_path = cached->second; + if (cached != filename_cache.end() && + get_hit_file(cached_path, write_fault_file_name)) { + write_fault_file_name = ""; + errno = EIO; + return 0; + } } -#else return fwrite(ptr, size, count, stream); -#endif } ssize_t ota_write(int fd, const void* buf, size_t nbyte) { -#if defined (TARGET_WRITE_FAULT) - if (FilenameCache.find(fd) != FilenameCache.end() - && FilenameCache[fd] == FaultFileName) { - FaultFileName = ""; - errno = EIO; - return -1; - } else { - return write(fd, buf, nbyte); + if (should_fault_inject(OTAIO_WRITE)) { + auto cached = filename_cache.find(fd); + const char* cached_path = cached->second; + if (cached != filename_cache.end() && + get_hit_file(cached_path, write_fault_file_name)) { + write_fault_file_name = ""; + errno = EIO; + return -1; + } } -#else return write(fd, buf, nbyte); -#endif } int ota_fsync(int fd) { -#if defined (TARGET_FSYNC_FAULT) - if (FilenameCache.find(fd) != FilenameCache.end() - && FilenameCache[fd] == FaultFileName) { - FaultFileName = ""; - errno = EIO; - return -1; - } else { - return fsync(fd); + if (should_fault_inject(OTAIO_FSYNC)) { + auto cached = filename_cache.find(fd); + const char* cached_path = cached->second; + if (cached != filename_cache.end() && + get_hit_file(cached_path, fsync_fault_file_name)) { + fsync_fault_file_name = ""; + errno = EIO; + return -1; + } } -#else return fsync(fd); -#endif } + diff --git a/otafault/ota_io.h b/otafault/ota_io.h index 641a5ae0a..84187a76e 100644 --- a/otafault/ota_io.h +++ b/otafault/ota_io.h @@ -26,6 +26,10 @@ #include #include +#define OTAIO_CACHE_FNAME "/cache/saved.file" + +void ota_set_fault_files(); + int ota_open(const char* path, int oflags); int ota_open(const char* path, int oflags, mode_t mode); diff --git a/otafault/test.cpp b/otafault/test.cpp index a0f731517..6514782bf 100644 --- a/otafault/test.cpp +++ b/otafault/test.cpp @@ -17,16 +17,18 @@ #include #include #include +#include #include "ota_io.h" -int main(int argc, char **argv) { +int main(int /* argc */, char** /* argv */) { int fd = open("testdata/test.file", O_RDWR); char buf[8]; - char *out = "321"; + const char* out = "321"; int readv = ota_read(fd, buf, 4); printf("Read returned %d\n", readv); int writev = ota_write(fd, out, 4); printf("Write returned %d\n", writev); + close(fd); return 0; } diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 44de4e031..56378d4f5 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -45,7 +45,7 @@ #include "install.h" #include "openssl/sha.h" #include "minzip/Hash.h" -#include "otafault/ota_io.h" +#include "ota_io.h" #include "print_sha1.h" #include "unique_fd.h" #include "updater.h" diff --git a/updater/install.cpp b/updater/install.cpp index 413e147a1..bc4cca913 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -51,7 +51,7 @@ #include "minzip/DirUtil.h" #include "mtdutils/mounts.h" #include "mtdutils/mtdutils.h" -#include "otafault/ota_io.h" +#include "ota_io.h" #include "updater.h" #include "install.h" #include "tune2fs.h" diff --git a/updater/updater.cpp b/updater/updater.cpp index 0f22e6d04..efb4a8cec 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -25,6 +25,7 @@ #include "blockimg.h" #include "minzip/Zip.h" #include "minzip/SysUtil.h" +#include "config.h" // Generated by the makefile, this function defines the // RegisterDeviceExtensions() function, which calls all the @@ -82,6 +83,7 @@ int main(int argc, char** argv) { argv[3], strerror(err)); return 3; } + ota_io_init(&za); const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME); if (script_entry == NULL) { -- cgit v1.2.3 From 2e947ea55eb2a6bd18351237bb3d83a4ad3df62c Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Fri, 19 Feb 2016 14:44:37 -0800 Subject: Check each value read from block map file. Bug: 26960931 Change-Id: I50b266ecb899db043831f528c2518bea76168c88 --- minzip/SysUtil.c | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/minzip/SysUtil.c b/minzip/SysUtil.c index 491951c9e..de47edfd9 100644 --- a/minzip/SysUtil.c +++ b/minzip/SysUtil.c @@ -78,7 +78,7 @@ static int sysMapBlockFile(FILE* mapf, MemMapping* pMap) if (blksize != 0) { blocks = ((size-1) / blksize) + 1; } - if (size == 0 || blksize == 0 || blocks > SIZE_MAX / blksize) { + if (size == 0 || blksize == 0 || blocks > SIZE_MAX / blksize || range_count == 0) { LOGE("invalid data in block map file: size %zu, blksize %u, range_count %u\n", size, blksize, range_count); return -1; @@ -100,9 +100,6 @@ static int sysMapBlockFile(FILE* mapf, MemMapping* pMap) return -1; } - pMap->ranges[range_count-1].addr = reserve; - pMap->ranges[range_count-1].length = blocks * blksize; - int fd = open(block_dev, O_RDONLY); if (fd < 0) { LOGE("failed to open block device %s: %s\n", block_dev, strerror(errno)); @@ -112,28 +109,46 @@ static int sysMapBlockFile(FILE* mapf, MemMapping* pMap) } unsigned char* next = reserve; + size_t remaining_size = blocks * blksize; + bool success = true; for (i = 0; i < range_count; ++i) { - int start, end; - if (fscanf(mapf, "%d %d\n", &start, &end) != 2) { + size_t start, end; + if (fscanf(mapf, "%zu %zu\n", &start, &end) != 2) { LOGE("failed to parse range %d in block map\n", i); - munmap(reserve, blocks * blksize); - free(pMap->ranges); - return -1; + success = false; + break; + } + size_t length = (end - start) * blksize; + if (end <= start || ((end - start) > SIZE_MAX / blksize) || length > remaining_size) { + LOGE("unexpected range in block map: %zu %zu\n", start, end); + success = false; + break; } - void* addr = mmap64(next, (end-start)*blksize, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, ((off64_t)start)*blksize); + void* addr = mmap64(next, length, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, ((off64_t)(start*blksize))); if (addr == MAP_FAILED) { LOGE("failed to map block %d: %s\n", i, strerror(errno)); - munmap(reserve, blocks * blksize); - free(pMap->ranges); - return -1; + success = false; + break; } pMap->ranges[i].addr = addr; - pMap->ranges[i].length = (end-start)*blksize; + pMap->ranges[i].length = length; - next += pMap->ranges[i].length; + next += length; + remaining_size -= length; + } + if (success && remaining_size != 0) { + LOGE("ranges in block map are invalid: remaining_size = %zu\n", remaining_size); + success = false; + } + if (!success) { + close(fd); + munmap(reserve, blocks * blksize); + free(pMap->ranges); + return -1; } + close(fd); pMap->addr = reserve; pMap->length = size; @@ -156,6 +171,7 @@ int sysMapFile(const char* fn, MemMapping* pMap) if (sysMapBlockFile(mapf, pMap) != 0) { LOGE("Map of '%s' failed\n", fn); + fclose(mapf); return -1; } -- cgit v1.2.3 From 53e7a0628f4acc95481f556ba51800df4a1de37d Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Wed, 17 Feb 2016 12:21:52 -0800 Subject: recovery: check battery level before installing package. Bug: 26879394 Change-Id: I63dce5bc50c2e104129f1bcab7d3cad5682bf45d --- Android.mk | 4 +++ install.h | 2 +- recovery.cpp | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 89 insertions(+), 16 deletions(-) diff --git a/Android.mk b/Android.mk index 4da34eef5..4477fefe3 100644 --- a/Android.mk +++ b/Android.mk @@ -64,6 +64,7 @@ LOCAL_C_INCLUDES += \ system/core/adb \ LOCAL_STATIC_LIBRARIES := \ + libbatterymonitor \ libext4_utils_static \ libsparse_static \ libminzip \ @@ -77,11 +78,14 @@ LOCAL_STATIC_LIBRARIES := \ libfs_mgr \ libbase \ libcutils \ + libutils \ liblog \ libselinux \ libm \ libc +LOCAL_HAL_STATIC_LIBRARIES := libhealthd + ifeq ($(TARGET_USERIMAGES_USE_EXT4), true) LOCAL_CFLAGS += -DUSE_EXT4 LOCAL_C_INCLUDES += system/extras/ext4_utils diff --git a/install.h b/install.h index 680499db3..f92f061df 100644 --- a/install.h +++ b/install.h @@ -23,7 +23,7 @@ extern "C" { #endif -enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_NONE }; +enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_NONE, INSTALL_SKIPPED }; // Install the package specified by root_path. If INSTALL_SUCCESS is // returned and *wipe_cache is true on exit, caller should wipe the // cache partition. diff --git a/recovery.cpp b/recovery.cpp index 17e9eb66f..3ce218548 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -40,6 +40,8 @@ #include #include +#include + #include "adb_install.h" #include "bootloader.h" #include "common.h" @@ -84,6 +86,12 @@ static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install"; static const char *LAST_KMSG_FILE = "/cache/recovery/last_kmsg"; static const char *LAST_LOG_FILE = "/cache/recovery/last_log"; static const int KEEP_LOG_COUNT = 10; +static const int BATTERY_READ_TIMEOUT_IN_SEC = 10; +// GmsCore enters recovery mode to install package when having enough battery +// percentage. Normally, the threshold is 40% without charger and 20% with charger. +// So we should check battery with a slightly lower limitation. +static const int BATTERY_OK_PERCENTAGE = 20; +static const int BATTERY_WITH_CHARGER_OK_PERCENTAGE = 15; RecoveryUI* ui = NULL; char* locale = NULL; @@ -1058,8 +1066,61 @@ ui_print(const char* format, ...) { } } -int -main(int argc, char **argv) { +static bool is_battery_ok() { + struct healthd_config healthd_config = { + .batteryStatusPath = android::String8(android::String8::kEmptyString), + .batteryHealthPath = android::String8(android::String8::kEmptyString), + .batteryPresentPath = android::String8(android::String8::kEmptyString), + .batteryCapacityPath = android::String8(android::String8::kEmptyString), + .batteryVoltagePath = android::String8(android::String8::kEmptyString), + .batteryTemperaturePath = android::String8(android::String8::kEmptyString), + .batteryTechnologyPath = android::String8(android::String8::kEmptyString), + .batteryCurrentNowPath = android::String8(android::String8::kEmptyString), + .batteryCurrentAvgPath = android::String8(android::String8::kEmptyString), + .batteryChargeCounterPath = android::String8(android::String8::kEmptyString), + .batteryFullChargePath = android::String8(android::String8::kEmptyString), + .batteryCycleCountPath = android::String8(android::String8::kEmptyString), + .energyCounter = NULL, + .boot_min_cap = 0, + .screen_on = NULL + }; + healthd_board_init(&healthd_config); + + android::BatteryMonitor monitor; + monitor.init(&healthd_config); + + int wait_second = 0; + while (true) { + int charge_status = monitor.getChargeStatus(); + // Treat unknown status as charged. + bool charged = (charge_status != android::BATTERY_STATUS_DISCHARGING && + charge_status != android::BATTERY_STATUS_NOT_CHARGING); + android::BatteryProperty capacity; + android::status_t status = monitor.getProperty(android::BATTERY_PROP_CAPACITY, &capacity); + ui_print("charge_status %d, charged %d, status %d, capacity %lld\n", charge_status, + charged, status, capacity.valueInt64); + // At startup, the battery drivers in devices like N5X/N6P take some time to load + // the battery profile. Before the load finishes, it reports value 50 as a fake + // capacity. BATTERY_READ_TIMEOUT_IN_SEC is set that the battery drivers are expected + // to finish loading the battery profile earlier than 10 seconds after kernel startup. + if (status == 0 && capacity.valueInt64 == 50) { + if (wait_second < BATTERY_READ_TIMEOUT_IN_SEC) { + sleep(1); + wait_second++; + continue; + } + } + // If we can't read battery percentage, it may be a device without battery. In this + // situation, use 100 as a fake battery percentage. + if (status != 0) { + capacity.valueInt64 = 100; + } + return (charged && capacity.valueInt64 >= BATTERY_WITH_CHARGER_OK_PERCENTAGE) || + (!charged && capacity.valueInt64 >= BATTERY_OK_PERCENTAGE); + } +} + +int main(int argc, char **argv) { // If this binary is started with the single argument "--adbd", // instead of being the normal recovery binary, it turns into kind // of a stripped-down version of adbd that only supports the @@ -1189,18 +1250,25 @@ main(int argc, char **argv) { int status = INSTALL_SUCCESS; if (update_package != NULL) { - status = install_package(update_package, &should_wipe_cache, TEMPORARY_INSTALL_FILE, true); - if (status == INSTALL_SUCCESS && should_wipe_cache) { - wipe_cache(false, device); - } - if (status != INSTALL_SUCCESS) { - ui->Print("Installation aborted.\n"); - - // If this is an eng or userdebug build, then automatically - // turn the text display on if the script fails so the error - // message is visible. - if (is_ro_debuggable()) { - ui->ShowText(true); + if (!is_battery_ok()) { + ui->Print("battery capacity is not enough for installing package, needed is %d%%\n", + BATTERY_OK_PERCENTAGE); + status = INSTALL_SKIPPED; + } else { + status = install_package(update_package, &should_wipe_cache, + TEMPORARY_INSTALL_FILE, true); + if (status == INSTALL_SUCCESS && should_wipe_cache) { + wipe_cache(false, device); + } + if (status != INSTALL_SUCCESS) { + ui->Print("Installation aborted.\n"); + + // If this is an eng or userdebug build, then automatically + // turn the text display on if the script fails so the error + // message is visible. + if (is_ro_debuggable()) { + ui->ShowText(true); + } } } } else if (should_wipe_data) { @@ -1249,7 +1317,8 @@ main(int argc, char **argv) { } Device::BuiltinAction after = shutdown_after ? Device::SHUTDOWN : Device::REBOOT; - if ((status != INSTALL_SUCCESS && !sideload_auto_reboot) || ui->IsTextVisible()) { + if ((status != INSTALL_SUCCESS && status != INSTALL_SKIPPED && !sideload_auto_reboot) || + ui->IsTextVisible()) { Device::BuiltinAction temp = prompt_and_wait(device, status); if (temp != Device::NO_ACTION) { after = temp; -- cgit v1.2.3 From 39c1b5e8722dbf0bbb3ee45e201373099f075345 Mon Sep 17 00:00:00 2001 From: Jed Estep Date: Tue, 15 Dec 2015 16:04:53 -0800 Subject: Control fault injection with config files instead of build flags Bug: 26570379 Change-Id: I76109d09276d6e3ed3a32b6fedafb2582f545c0c (cherry picked from commit d940887dde23597dc358b16d96ca48dd7480fee6) --- applypatch/applypatch.cpp | 2 +- otafault/Android.mk | 43 ++++-------- otafault/config.cpp | 65 ++++++++++++++++++ otafault/config.h | 74 +++++++++++++++++++++ otafault/ota_io.cpp | 163 +++++++++++++++++++++------------------------- otafault/ota_io.h | 4 ++ otafault/test.cpp | 6 +- updater/blockimg.cpp | 2 +- updater/install.cpp | 2 +- updater/updater.cpp | 2 + 10 files changed, 242 insertions(+), 121 deletions(-) create mode 100644 otafault/config.cpp create mode 100644 otafault/config.h diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index f66dbe3bf..644515997 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -34,8 +34,8 @@ #include "applypatch.h" #include "mtdutils/mtdutils.h" #include "edify/expr.h" +#include "ota_io.h" #include "print_sha1.h" -#include "otafault/ota_io.h" static int LoadPartitionContents(const char* filename, FileContents* file); static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token); diff --git a/otafault/Android.mk b/otafault/Android.mk index 75617a146..7468de6c4 100644 --- a/otafault/Android.mk +++ b/otafault/Android.mk @@ -1,10 +1,10 @@ -# Copyright 2015 The ANdroid Open Source Project +# Copyright 2015 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -14,45 +14,30 @@ LOCAL_PATH := $(call my-dir) -empty := -space := $(empty) $(empty) -comma := , - -ifneq ($(TARGET_INJECT_FAULTS),) -TARGET_INJECT_FAULTS := $(subst $(comma),$(space),$(strip $(TARGET_INJECT_FAULTS))) -endif - include $(CLEAR_VARS) -LOCAL_SRC_FILES := ota_io.cpp +otafault_static_libs := \ + libminzip \ + libz \ + libselinux \ + +LOCAL_SRC_FILES := config.cpp ota_io.cpp LOCAL_MODULE_TAGS := eng LOCAL_MODULE := libotafault LOCAL_CLANG := true - -ifneq ($(TARGET_INJECT_FAULTS),) -$(foreach ft,$(TARGET_INJECT_FAULTS),\ - $(eval LOCAL_CFLAGS += -DTARGET_$(ft)_FAULT=$(TARGET_$(ft)_FAULT_FILE))) -LOCAL_CFLAGS += -Wno-unused-parameter -LOCAL_CFLAGS += -DTARGET_INJECT_FAULTS -endif - -LOCAL_STATIC_LIBRARIES := libc +LOCAL_C_INCLUDES := bootable/recovery +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) +LOCAL_WHOLE_STATIC_LIBRARIES := $(otafault_static_libs) include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) -LOCAL_SRC_FILES := ota_io.cpp test.cpp +LOCAL_SRC_FILES := config.cpp ota_io.cpp test.cpp LOCAL_MODULE_TAGS := tests LOCAL_MODULE := otafault_test -LOCAL_STATIC_LIBRARIES := libc +LOCAL_STATIC_LIBRARIES := $(otafault_static_libs) +LOCAL_C_INCLUDES := bootable/recovery LOCAL_FORCE_STATIC_EXECUTABLE := true -LOCAL_CFLAGS += -Wno-unused-parameter -Wno-writable-strings - -ifneq ($(TARGET_INJECT_FAULTS),) -$(foreach ft,$(TARGET_INJECT_FAULTS),\ - $(eval LOCAL_CFLAGS += -DTARGET_$(ft)_FAULT=$(TARGET_$(ft)_FAULT_FILE))) -LOCAL_CFLAGS += -DTARGET_INJECT_FAULTS -endif include $(BUILD_EXECUTABLE) diff --git a/otafault/config.cpp b/otafault/config.cpp new file mode 100644 index 000000000..c87f9a631 --- /dev/null +++ b/otafault/config.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include + +#include "minzip/Zip.h" +#include "config.h" +#include "ota_io.h" + +#define OTAIO_MAX_FNAME_SIZE 128 + +static ZipArchive* archive; +static std::map should_inject_cache; + +static const char* get_type_path(const char* io_type) { + char* path = (char*)calloc(strlen(io_type) + strlen(OTAIO_BASE_DIR) + 2, sizeof(char)); + sprintf(path, "%s/%s", OTAIO_BASE_DIR, io_type); + return path; +} + +void ota_io_init(ZipArchive* za) { + archive = za; + ota_set_fault_files(); +} + +bool should_fault_inject(const char* io_type) { + if (should_inject_cache.find(io_type) != should_inject_cache.end()) { + return should_inject_cache[io_type]; + } + const char* type_path = get_type_path(io_type); + const ZipEntry* entry = mzFindZipEntry(archive, type_path); + should_inject_cache[type_path] = entry != nullptr; + free((void*)type_path); + return entry != NULL; +} + +bool should_hit_cache() { + return should_fault_inject(OTAIO_CACHE); +} + +std::string fault_fname(const char* io_type) { + const char* type_path = get_type_path(io_type); + char* fname = (char*) calloc(OTAIO_MAX_FNAME_SIZE, sizeof(char)); + const ZipEntry* entry = mzFindZipEntry(archive, type_path); + mzReadZipEntry(archive, entry, fname, OTAIO_MAX_FNAME_SIZE); + free((void*)type_path); + return std::string(fname); +} diff --git a/otafault/config.h b/otafault/config.h new file mode 100644 index 000000000..4430be3fb --- /dev/null +++ b/otafault/config.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Read configuration files in the OTA package to determine which files, if any, will trigger errors. + * + * OTA packages can be modified to trigger errors by adding a top-level + * directory called .libotafault, which may optionally contain up to three + * files called READ, WRITE, and FSYNC. Each one of these optional files + * contains the name of a single file on the device disk which will cause + * an IO error on the first call of the appropriate I/O action to that file. + * + * Example: + * ota.zip + * + * .libotafault + * WRITE + * + * If the contents of the file WRITE were /system/build.prop, the first write + * action to /system/build.prop would fail with EIO. Note that READ and + * FSYNC files are absent, so these actions will not cause an error. + */ + +#ifndef _UPDATER_OTA_IO_CFG_H_ +#define _UPDATER_OTA_IO_CFG_H_ + +#include + +#include + +#include "minzip/Zip.h" + +#define OTAIO_BASE_DIR ".libotafault" +#define OTAIO_READ "READ" +#define OTAIO_WRITE "WRITE" +#define OTAIO_FSYNC "FSYNC" +#define OTAIO_CACHE "CACHE" + +/* + * Initialize libotafault by providing a reference to the OTA package. + */ +void ota_io_init(ZipArchive* za); + +/* + * Return true if a config file is present for the given IO type. + */ +bool should_fault_inject(const char* io_type); + +/* + * Return true if an EIO should occur on the next hit to /cache/saved.file + * instead of the next hit to the specified file. + */ +bool should_hit_cache(); + +/* + * Return the name of the file that should cause an error for the + * given IO type. + */ +std::string fault_fname(const char* io_type); + +#endif diff --git a/otafault/ota_io.cpp b/otafault/ota_io.cpp index 02e80f9bf..2ce3dfcc2 100644 --- a/otafault/ota_io.cpp +++ b/otafault/ota_io.cpp @@ -14,9 +14,7 @@ * limitations under the License. */ -#if defined (TARGET_INJECT_FAULTS) #include -#endif #include #include @@ -24,137 +22,128 @@ #include #include +#include "config.h" #include "ota_io.h" -#if defined (TARGET_INJECT_FAULTS) -static std::map FilenameCache; -static std::string FaultFileName = -#if defined (TARGET_READ_FAULT) - TARGET_READ_FAULT; -#elif defined (TARGET_WRITE_FAULT) - TARGET_WRITE_FAULT; -#elif defined (TARGET_FSYNC_FAULT) - TARGET_FSYNC_FAULT; -#endif // defined (TARGET_READ_FAULT) -#endif // defined (TARGET_INJECT_FAULTS) +static std::map filename_cache; +static std::string read_fault_file_name = ""; +static std::string write_fault_file_name = ""; +static std::string fsync_fault_file_name = ""; + +static bool get_hit_file(const char* cached_path, std::string ffn) { + return should_hit_cache() + ? !strncmp(cached_path, OTAIO_CACHE_FNAME, strlen(cached_path)) + : !strncmp(cached_path, ffn.c_str(), strlen(cached_path)); +} + +void ota_set_fault_files() { + if (should_fault_inject(OTAIO_READ)) { + read_fault_file_name = fault_fname(OTAIO_READ); + } + if (should_fault_inject(OTAIO_WRITE)) { + write_fault_file_name = fault_fname(OTAIO_WRITE); + } + if (should_fault_inject(OTAIO_FSYNC)) { + fsync_fault_file_name = fault_fname(OTAIO_FSYNC); + } +} int ota_open(const char* path, int oflags) { -#if defined (TARGET_INJECT_FAULTS) // Let the caller handle errors; we do not care if open succeeds or fails int fd = open(path, oflags); - FilenameCache[fd] = path; + filename_cache[fd] = path; return fd; -#else - return open(path, oflags); -#endif } int ota_open(const char* path, int oflags, mode_t mode) { -#if defined (TARGET_INJECT_FAULTS) int fd = open(path, oflags, mode); - FilenameCache[fd] = path; - return fd; -#else - return open(path, oflags, mode); -#endif -} + filename_cache[fd] = path; + return fd; } FILE* ota_fopen(const char* path, const char* mode) { -#if defined (TARGET_INJECT_FAULTS) FILE* fh = fopen(path, mode); - FilenameCache[(intptr_t)fh] = path; + filename_cache[(intptr_t)fh] = path; return fh; -#else - return fopen(path, mode); -#endif } int ota_close(int fd) { -#if defined (TARGET_INJECT_FAULTS) - // descriptors can be reused, so make sure not to leave them in the cahce - FilenameCache.erase(fd); -#endif + // descriptors can be reused, so make sure not to leave them in the cache + filename_cache.erase(fd); return close(fd); } int ota_fclose(FILE* fh) { -#if defined (TARGET_INJECT_FAULTS) - FilenameCache.erase((intptr_t)fh); -#endif + filename_cache.erase((intptr_t)fh); return fclose(fh); } size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream) { -#if defined (TARGET_READ_FAULT) - if (FilenameCache.find((intptr_t)stream) != FilenameCache.end() - && FilenameCache[(intptr_t)stream] == FaultFileName) { - FaultFileName = ""; - errno = EIO; - return 0; - } else { - return fread(ptr, size, nitems, stream); + if (should_fault_inject(OTAIO_READ)) { + auto cached = filename_cache.find((intptr_t)stream); + const char* cached_path = cached->second; + if (cached != filename_cache.end() && + get_hit_file(cached_path, read_fault_file_name)) { + read_fault_file_name = ""; + errno = EIO; + return 0; + } } -#else return fread(ptr, size, nitems, stream); -#endif } ssize_t ota_read(int fd, void* buf, size_t nbyte) { -#if defined (TARGET_READ_FAULT) - if (FilenameCache.find(fd) != FilenameCache.end() - && FilenameCache[fd] == FaultFileName) { - FaultFileName = ""; - errno = EIO; - return -1; - } else { - return read(fd, buf, nbyte); + if (should_fault_inject(OTAIO_READ)) { + auto cached = filename_cache.find(fd); + const char* cached_path = cached->second; + if (cached != filename_cache.end() + && get_hit_file(cached_path, read_fault_file_name)) { + read_fault_file_name = ""; + errno = EIO; + return -1; + } } -#else return read(fd, buf, nbyte); -#endif } size_t ota_fwrite(const void* ptr, size_t size, size_t count, FILE* stream) { -#if defined (TARGET_WRITE_FAULT) - if (FilenameCache.find((intptr_t)stream) != FilenameCache.end() - && FilenameCache[(intptr_t)stream] == FaultFileName) { - FaultFileName = ""; - errno = EIO; - return 0; - } else { - return fwrite(ptr, size, count, stream); + if (should_fault_inject(OTAIO_WRITE)) { + auto cached = filename_cache.find((intptr_t)stream); + const char* cached_path = cached->second; + if (cached != filename_cache.end() && + get_hit_file(cached_path, write_fault_file_name)) { + write_fault_file_name = ""; + errno = EIO; + return 0; + } } -#else return fwrite(ptr, size, count, stream); -#endif } ssize_t ota_write(int fd, const void* buf, size_t nbyte) { -#if defined (TARGET_WRITE_FAULT) - if (FilenameCache.find(fd) != FilenameCache.end() - && FilenameCache[fd] == FaultFileName) { - FaultFileName = ""; - errno = EIO; - return -1; - } else { - return write(fd, buf, nbyte); + if (should_fault_inject(OTAIO_WRITE)) { + auto cached = filename_cache.find(fd); + const char* cached_path = cached->second; + if (cached != filename_cache.end() && + get_hit_file(cached_path, write_fault_file_name)) { + write_fault_file_name = ""; + errno = EIO; + return -1; + } } -#else return write(fd, buf, nbyte); -#endif } int ota_fsync(int fd) { -#if defined (TARGET_FSYNC_FAULT) - if (FilenameCache.find(fd) != FilenameCache.end() - && FilenameCache[fd] == FaultFileName) { - FaultFileName = ""; - errno = EIO; - return -1; - } else { - return fsync(fd); + if (should_fault_inject(OTAIO_FSYNC)) { + auto cached = filename_cache.find(fd); + const char* cached_path = cached->second; + if (cached != filename_cache.end() && + get_hit_file(cached_path, fsync_fault_file_name)) { + fsync_fault_file_name = ""; + errno = EIO; + return -1; + } } -#else return fsync(fd); -#endif } + diff --git a/otafault/ota_io.h b/otafault/ota_io.h index 641a5ae0a..84187a76e 100644 --- a/otafault/ota_io.h +++ b/otafault/ota_io.h @@ -26,6 +26,10 @@ #include #include +#define OTAIO_CACHE_FNAME "/cache/saved.file" + +void ota_set_fault_files(); + int ota_open(const char* path, int oflags); int ota_open(const char* path, int oflags, mode_t mode); diff --git a/otafault/test.cpp b/otafault/test.cpp index a0f731517..6514782bf 100644 --- a/otafault/test.cpp +++ b/otafault/test.cpp @@ -17,16 +17,18 @@ #include #include #include +#include #include "ota_io.h" -int main(int argc, char **argv) { +int main(int /* argc */, char** /* argv */) { int fd = open("testdata/test.file", O_RDWR); char buf[8]; - char *out = "321"; + const char* out = "321"; int readv = ota_read(fd, buf, 4); printf("Read returned %d\n", readv); int writev = ota_write(fd, out, 4); printf("Write returned %d\n", writev); + close(fd); return 0; } diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 44de4e031..56378d4f5 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -45,7 +45,7 @@ #include "install.h" #include "openssl/sha.h" #include "minzip/Hash.h" -#include "otafault/ota_io.h" +#include "ota_io.h" #include "print_sha1.h" #include "unique_fd.h" #include "updater.h" diff --git a/updater/install.cpp b/updater/install.cpp index 413e147a1..bc4cca913 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -51,7 +51,7 @@ #include "minzip/DirUtil.h" #include "mtdutils/mounts.h" #include "mtdutils/mtdutils.h" -#include "otafault/ota_io.h" +#include "ota_io.h" #include "updater.h" #include "install.h" #include "tune2fs.h" diff --git a/updater/updater.cpp b/updater/updater.cpp index 0f22e6d04..efb4a8cec 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -25,6 +25,7 @@ #include "blockimg.h" #include "minzip/Zip.h" #include "minzip/SysUtil.h" +#include "config.h" // Generated by the makefile, this function defines the // RegisterDeviceExtensions() function, which calls all the @@ -82,6 +83,7 @@ int main(int argc, char** argv) { argv[3], strerror(err)); return 3; } + ota_io_init(&za); const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME); if (script_entry == NULL) { -- cgit v1.2.3 From 6629655476ee346d64634579cac32377c1195dd1 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Mon, 22 Feb 2016 19:49:38 -0800 Subject: Surpress warnings in minzip/Zip.c bootable/recovery/minzip/Zip.c:514:5: warning: Value stored to 'compRemaining' is never read compRemaining = pEntry->compLen; ^ ~~~~~~~~~~~~~~~ bootable/recovery/minzip/Zip.c:778:9: warning: Null pointer argument in call to memory copy function memcpy(p, helper->targetDir, helper->targetDirLen); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Bug: 27229894 Change-Id: I0482bac3a4fcddc191783d1e5b5a83cf29fa4e85 --- minzip/Zip.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/minzip/Zip.c b/minzip/Zip.c index bdb565c64..38f939fb2 100644 --- a/minzip/Zip.c +++ b/minzip/Zip.c @@ -509,9 +509,6 @@ static bool processDeflatedEntry(const ZipArchive *pArchive, unsigned char procBuf[32 * 1024]; z_stream zstream; int zerr; - long compRemaining; - - compRemaining = pEntry->compLen; /* * Initialize the zlib stream. @@ -759,7 +756,7 @@ static const char *targetEntryPath(MzPathHelper *helper, ZipEntry *pEntry) */ needLen = helper->targetDirLen + 1 + pEntry->fileNameLen - helper->zipDirLen + 1; - if (needLen > helper->bufLen) { + if (firstTime || needLen > helper->bufLen) { char *newBuf; needLen *= 2; -- cgit v1.2.3 From 03b72b0f377d352a7197b2cbb3c90ebed3321bcc Mon Sep 17 00:00:00 2001 From: Mattias Nissler Date: Wed, 24 Feb 2016 14:45:06 +0100 Subject: Move dumpkey tool to the recovery repo. The dumpkey tool is used to dump encryption keys in a custom format used by the recovery code. Nobody else uses this format AFAICT, so it's more appropriate to keep the code of the tool alongside the recovery code instead of next to mincrypt. BUG:27326256 Change-Id: I30176845617972be1d6e46e9a9218e161fbf0680 --- tools/dumpkey/Android.mk | 32 +++++ tools/dumpkey/DumpPublicKey.java | 270 +++++++++++++++++++++++++++++++++++++++ tools/dumpkey/DumpPublicKey.mf | 1 + 3 files changed, 303 insertions(+) create mode 100644 tools/dumpkey/Android.mk create mode 100644 tools/dumpkey/DumpPublicKey.java create mode 100644 tools/dumpkey/DumpPublicKey.mf diff --git a/tools/dumpkey/Android.mk b/tools/dumpkey/Android.mk new file mode 100644 index 000000000..bbd065664 --- /dev/null +++ b/tools/dumpkey/Android.mk @@ -0,0 +1,32 @@ +# 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) + +# Determine whether to build dumpkey from system/core/libmincrypt or from +# bootable/recovery/tools. The dumpkey source is temporarily present in both +# locations during the process of moving the tool to the recovery repository. +# TODO(mnissler): Remove the guard after the transition is complete. +ifndef BUILD_DUMPKEY_FROM_RECOVERY +BUILD_DUMPKEY_FROM_RECOVERY := true +endif + +ifeq ($(BUILD_DUMPKEY_FROM_RECOVERY),true) +include $(CLEAR_VARS) +LOCAL_MODULE := dumpkey +LOCAL_SRC_FILES := DumpPublicKey.java +LOCAL_JAR_MANIFEST := DumpPublicKey.mf +LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host +include $(BUILD_HOST_JAVA_LIBRARY) +endif diff --git a/tools/dumpkey/DumpPublicKey.java b/tools/dumpkey/DumpPublicKey.java new file mode 100644 index 000000000..3eb139842 --- /dev/null +++ b/tools/dumpkey/DumpPublicKey.java @@ -0,0 +1,270 @@ +/* + * 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. + */ + +package com.android.dumpkey; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import java.io.FileInputStream; +import java.math.BigInteger; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.KeyStore; +import java.security.Key; +import java.security.PublicKey; +import java.security.Security; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.ECPoint; + +/** + * Command line tool to extract RSA public keys from X.509 certificates + * and output source code with data initializers for the keys. + * @hide + */ +class DumpPublicKey { + /** + * @param key to perform sanity checks on + * @return version number of key. Supported versions are: + * 1: 2048-bit RSA key with e=3 and SHA-1 hash + * 2: 2048-bit RSA key with e=65537 and SHA-1 hash + * 3: 2048-bit RSA key with e=3 and SHA-256 hash + * 4: 2048-bit RSA key with e=65537 and SHA-256 hash + * @throws Exception if the key has the wrong size or public exponent + */ + static int checkRSA(RSAPublicKey key, boolean useSHA256) throws Exception { + BigInteger pubexp = key.getPublicExponent(); + BigInteger modulus = key.getModulus(); + int version; + + if (pubexp.equals(BigInteger.valueOf(3))) { + version = useSHA256 ? 3 : 1; + } else if (pubexp.equals(BigInteger.valueOf(65537))) { + version = useSHA256 ? 4 : 2; + } else { + throw new Exception("Public exponent should be 3 or 65537 but is " + + pubexp.toString(10) + "."); + } + + if (modulus.bitLength() != 2048) { + throw new Exception("Modulus should be 2048 bits long but is " + + modulus.bitLength() + " bits."); + } + + return version; + } + + /** + * @param key to perform sanity checks on + * @return version number of key. Supported versions are: + * 5: 256-bit EC key with curve NIST P-256 + * @throws Exception if the key has the wrong size or public exponent + */ + static int checkEC(ECPublicKey key) throws Exception { + if (key.getParams().getCurve().getField().getFieldSize() != 256) { + throw new Exception("Curve must be NIST P-256"); + } + + return 5; + } + + /** + * Perform sanity check on public key. + */ + static int check(PublicKey key, boolean useSHA256) throws Exception { + if (key instanceof RSAPublicKey) { + return checkRSA((RSAPublicKey) key, useSHA256); + } else if (key instanceof ECPublicKey) { + if (!useSHA256) { + throw new Exception("Must use SHA-256 with EC keys!"); + } + return checkEC((ECPublicKey) key); + } else { + throw new Exception("Unsupported key class: " + key.getClass().getName()); + } + } + + /** + * @param key to output + * @return a String representing this public key. If the key is a + * version 1 key, the string will be a C initializer; this is + * not true for newer key versions. + */ + static String printRSA(RSAPublicKey key, boolean useSHA256) throws Exception { + int version = check(key, useSHA256); + + BigInteger N = key.getModulus(); + + StringBuilder result = new StringBuilder(); + + int nwords = N.bitLength() / 32; // # of 32 bit integers in modulus + + if (version > 1) { + result.append("v"); + result.append(Integer.toString(version)); + result.append(" "); + } + + result.append("{"); + result.append(nwords); + + BigInteger B = BigInteger.valueOf(0x100000000L); // 2^32 + BigInteger N0inv = B.subtract(N.modInverse(B)); // -1 / N[0] mod 2^32 + + result.append(",0x"); + result.append(N0inv.toString(16)); + + BigInteger R = BigInteger.valueOf(2).pow(N.bitLength()); + BigInteger RR = R.multiply(R).mod(N); // 2^4096 mod N + + // Write out modulus as little endian array of integers. + result.append(",{"); + for (int i = 0; i < nwords; ++i) { + long n = N.mod(B).longValue(); + result.append(n); + + if (i != nwords - 1) { + result.append(","); + } + + N = N.divide(B); + } + result.append("}"); + + // Write R^2 as little endian array of integers. + result.append(",{"); + for (int i = 0; i < nwords; ++i) { + long rr = RR.mod(B).longValue(); + result.append(rr); + + if (i != nwords - 1) { + result.append(","); + } + + RR = RR.divide(B); + } + result.append("}"); + + result.append("}"); + return result.toString(); + } + + /** + * @param key to output + * @return a String representing this public key. If the key is a + * version 1 key, the string will be a C initializer; this is + * not true for newer key versions. + */ + static String printEC(ECPublicKey key) throws Exception { + int version = checkEC(key); + + StringBuilder result = new StringBuilder(); + + result.append("v"); + result.append(Integer.toString(version)); + result.append(" "); + + BigInteger X = key.getW().getAffineX(); + BigInteger Y = key.getW().getAffineY(); + int nbytes = key.getParams().getCurve().getField().getFieldSize() / 8; // # of 32 bit integers in X coordinate + + result.append("{"); + result.append(nbytes); + + BigInteger B = BigInteger.valueOf(0x100L); // 2^8 + + // Write out Y coordinate as array of characters. + result.append(",{"); + for (int i = 0; i < nbytes; ++i) { + long n = X.mod(B).longValue(); + result.append(n); + + if (i != nbytes - 1) { + result.append(","); + } + + X = X.divide(B); + } + result.append("}"); + + // Write out Y coordinate as array of characters. + result.append(",{"); + for (int i = 0; i < nbytes; ++i) { + long n = Y.mod(B).longValue(); + result.append(n); + + if (i != nbytes - 1) { + result.append(","); + } + + Y = Y.divide(B); + } + result.append("}"); + + result.append("}"); + return result.toString(); + } + + static String print(PublicKey key, boolean useSHA256) throws Exception { + if (key instanceof RSAPublicKey) { + return printRSA((RSAPublicKey) key, useSHA256); + } else if (key instanceof ECPublicKey) { + return printEC((ECPublicKey) key); + } else { + throw new Exception("Unsupported key class: " + key.getClass().getName()); + } + } + + public static void main(String[] args) { + if (args.length < 1) { + System.err.println("Usage: DumpPublicKey certfile ... > source.c"); + System.exit(1); + } + Security.addProvider(new BouncyCastleProvider()); + try { + for (int i = 0; i < args.length; i++) { + FileInputStream input = new FileInputStream(args[i]); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(input); + + boolean useSHA256 = false; + String sigAlg = cert.getSigAlgName(); + if ("SHA1withRSA".equals(sigAlg) || "MD5withRSA".equals(sigAlg)) { + // SignApk has historically accepted "MD5withRSA" + // certificates, but treated them as "SHA1withRSA" + // anyway. Continue to do so for backwards + // compatibility. + useSHA256 = false; + } else if ("SHA256withRSA".equals(sigAlg) || "SHA256withECDSA".equals(sigAlg)) { + useSHA256 = true; + } else { + System.err.println(args[i] + ": unsupported signature algorithm \"" + + sigAlg + "\""); + System.exit(1); + } + + PublicKey key = cert.getPublicKey(); + check(key, useSHA256); + System.out.print(print(key, useSHA256)); + System.out.println(i < args.length - 1 ? "," : ""); + } + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + System.exit(0); + } +} diff --git a/tools/dumpkey/DumpPublicKey.mf b/tools/dumpkey/DumpPublicKey.mf new file mode 100644 index 000000000..7bb3bc88d --- /dev/null +++ b/tools/dumpkey/DumpPublicKey.mf @@ -0,0 +1 @@ +Main-Class: com.android.dumpkey.DumpPublicKey -- cgit v1.2.3 From b66f047d41f3ff5e06baa63b3705d189a697035c Mon Sep 17 00:00:00 2001 From: Mattias Nissler Date: Fri, 26 Feb 2016 11:04:32 +0100 Subject: Remove dumpkey build guards after completing code move. Bug: 27326256 Change-Id: Ia713b23e3c898c1f10af7c61ea67f34601fdcbe3 --- tools/dumpkey/Android.mk | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tools/dumpkey/Android.mk b/tools/dumpkey/Android.mk index bbd065664..31549146d 100644 --- a/tools/dumpkey/Android.mk +++ b/tools/dumpkey/Android.mk @@ -14,19 +14,9 @@ LOCAL_PATH := $(call my-dir) -# Determine whether to build dumpkey from system/core/libmincrypt or from -# bootable/recovery/tools. The dumpkey source is temporarily present in both -# locations during the process of moving the tool to the recovery repository. -# TODO(mnissler): Remove the guard after the transition is complete. -ifndef BUILD_DUMPKEY_FROM_RECOVERY -BUILD_DUMPKEY_FROM_RECOVERY := true -endif - -ifeq ($(BUILD_DUMPKEY_FROM_RECOVERY),true) include $(CLEAR_VARS) LOCAL_MODULE := dumpkey LOCAL_SRC_FILES := DumpPublicKey.java LOCAL_JAR_MANIFEST := DumpPublicKey.mf LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host include $(BUILD_HOST_JAVA_LIBRARY) -endif -- cgit v1.2.3 From 6bcc8af6e5a5bf9cc0987305cdfa24d4f6e4afa9 Mon Sep 17 00:00:00 2001 From: Alex Deymo Date: Wed, 2 Mar 2016 14:21:02 -0800 Subject: Restore labels on /postinstall during recovery. This patch mirrors what was done in the main init.rc to relabel /postinstall. Bug: 27178350 Bug: 27177071 Change-Id: I39cd03f3c55a42c03367957e8c259c9a3155203c --- etc/init.rc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/etc/init.rc b/etc/init.rc index dc1865986..5915b8d80 100644 --- a/etc/init.rc +++ b/etc/init.rc @@ -1,6 +1,9 @@ import /init.recovery.${ro.hardware}.rc on early-init + # Set the security context of /postinstall if present. + restorecon /postinstall + start ueventd start healthd -- cgit v1.2.3 From 26112e587084e8b066c28a696533328adde406a9 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 25 Feb 2016 12:29:40 -0800 Subject: recovery: Handle devices without /cache partition. Since we may not have /cache partition on A/B devices, let recovery handle /cache related operations gracefully if /cache doesn't exist. (1) Disable the wipe for /cache partition. (2) Skip wiping /cache while wiping /data (i.e. factory reset). (3) Disable logging-related features, until we figure out better ways / places to store recovery logs (mainly for factory resets on A/B devices). Bug: 27176738 Change-Id: I7b14e53ce18960fe801ddfc15380dac6ceef1198 --- recovery.cpp | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/recovery.cpp b/recovery.cpp index 3ce218548..9d6f51178 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -98,6 +98,7 @@ char* locale = NULL; char* stage = NULL; char* reason = NULL; bool modified_flash = false; +static bool has_cache = false; /* * The recovery tool communicates with the main system through /cache files. @@ -310,8 +311,8 @@ get_args(int *argc, char ***argv) { } } - // --- if that doesn't work, try the command file - if (*argc <= 1) { + // --- if that doesn't work, try the command file (if we have /cache). + if (*argc <= 1 && has_cache) { FILE *fp = fopen_path(COMMAND_FILE, "r"); if (fp != NULL) { char *token; @@ -433,6 +434,11 @@ static void rotate_logs(int max) { } static void copy_logs() { + // We can do nothing for now if there's no /cache partition. + if (!has_cache) { + return; + } + // We only rotate and record the log of the current session if there are // actual attempts to modify the flash, such as wipes, installs from BCB // or menu selections. This is to avoid unnecessary rotation (and @@ -464,7 +470,7 @@ static void copy_logs() { static void finish_recovery(const char *send_intent) { // By this point, we're ready to return to the main system... - if (send_intent != NULL) { + if (send_intent != NULL && has_cache) { FILE *fp = fopen_path(INTENT_FILE, "w"); if (fp == NULL) { LOGE("Can't open %s\n", INTENT_FILE); @@ -477,7 +483,7 @@ finish_recovery(const char *send_intent) { // Save the locale to cache, so if recovery is next started up // without a --locale argument (eg, directly from the bootloader) // it will use the last-known locale. - if (locale != NULL) { + if (locale != NULL && has_cache) { LOGI("Saving locale \"%s\"\n", locale); FILE* fp = fopen_path(LOCALE_FILE, "w"); fwrite(locale, 1, strlen(locale), fp); @@ -494,12 +500,13 @@ finish_recovery(const char *send_intent) { set_bootloader_message(&boot); // Remove the command file, so recovery won't repeat indefinitely. - if (ensure_path_mounted(COMMAND_FILE) != 0 || - (unlink(COMMAND_FILE) && errno != ENOENT)) { - LOGW("Can't unlink %s\n", COMMAND_FILE); + if (has_cache) { + if (ensure_path_mounted(COMMAND_FILE) != 0 || (unlink(COMMAND_FILE) && errno != ENOENT)) { + LOGW("Can't unlink %s\n", COMMAND_FILE); + } + ensure_path_unmounted(CACHE_ROOT); } - ensure_path_unmounted(CACHE_ROOT); sync(); // For good measure. } @@ -768,7 +775,7 @@ static bool wipe_data(int should_confirm, Device* device) { bool success = device->PreWipeData() && erase_volume("/data") && - erase_volume("/cache") && + (has_cache ? erase_volume("/cache") : true) && device->PostWipeData(); ui->Print("Data wipe %s.\n", success ? "complete" : "failed"); return success; @@ -776,6 +783,11 @@ static bool wipe_data(int should_confirm, Device* device) { // Return true on success. static bool wipe_cache(bool should_confirm, Device* device) { + if (!has_cache) { + ui->Print("No /cache partition found.\n"); + return false; + } + if (should_confirm && !yes_no(device, "Wipe cache?", " THIS CAN NOT BE UNDONE!")) { return false; } @@ -789,6 +801,11 @@ static bool wipe_cache(bool should_confirm, Device* device) { } static void choose_recovery_file(Device* device) { + if (!has_cache) { + ui->Print("No /cache partition found.\n"); + return; + } + // "Back" + KEEP_LOG_COUNT * 2 + terminating nullptr entry char* entries[1 + KEEP_LOG_COUNT * 2 + 1]; memset(entries, 0, sizeof(entries)); @@ -1142,6 +1159,8 @@ int main(int argc, char **argv) { printf("Starting recovery (pid %d) on %s", getpid(), ctime(&start)); load_volume_table(); + has_cache = volume_for_path(CACHE_ROOT) != nullptr; + get_args(&argc, &argv); const char *send_intent = NULL; @@ -1182,7 +1201,7 @@ int main(int argc, char **argv) { } } - if (locale == NULL) { + if (locale == nullptr && has_cache) { load_locale_from_cache(); } printf("locale is [%s]\n", locale); -- cgit v1.2.3 From 3c62b67faf8a25f1dd1c44dc19759c3997fdfd36 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Fri, 5 Feb 2016 18:25:58 -0800 Subject: Reboot and retry on I/O errors When I/O error happens, reboot and retry installation two times before we abort this OTA update. Bug: 25633753 Change-Id: Iba6d4203a343a725aa625a41d237606980d62f69 --- install.cpp | 6 ++++++ install.h | 3 ++- otafault/ota_io.cpp | 37 ++++++++++++++++++++++++++++++++----- recovery.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++++++- updater/updater.cpp | 7 +++++++ 5 files changed, 93 insertions(+), 7 deletions(-) diff --git a/install.cpp b/install.cpp index 33c1f5498..144a353d6 100644 --- a/install.cpp +++ b/install.cpp @@ -144,6 +144,7 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) { close(pipefd[1]); *wipe_cache = false; + bool retry_update = false; char buffer[1024]; FILE* from_child = fdopen(pipefd[0], "r"); @@ -180,6 +181,8 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) { // to be able to reboot during installation (useful for // debugging packages that don't exit). ui->SetEnableReboot(true); + } else if (strcmp(command, "retry_update") == 0) { + retry_update = true; } else { LOGE("unknown command [%s]\n", command); } @@ -188,6 +191,9 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) { int status; waitpid(pid, &status, 0); + if (retry_update) { + return INSTALL_RETRY; + } if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status)); return INSTALL_ERROR; diff --git a/install.h b/install.h index f92f061df..fd08e3c49 100644 --- a/install.h +++ b/install.h @@ -23,7 +23,8 @@ extern "C" { #endif -enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_NONE, INSTALL_SKIPPED }; +enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_NONE, INSTALL_SKIPPED, + INSTALL_RETRY }; // Install the package specified by root_path. If INSTALL_SUCCESS is // returned and *wipe_cache is true on exit, caller should wipe the // cache partition. diff --git a/otafault/ota_io.cpp b/otafault/ota_io.cpp index 2ce3dfcc2..dd805e56e 100644 --- a/otafault/ota_io.cpp +++ b/otafault/ota_io.cpp @@ -29,6 +29,7 @@ static std::map filename_cache; static std::string read_fault_file_name = ""; static std::string write_fault_file_name = ""; static std::string fsync_fault_file_name = ""; +bool have_eio_error = false; static bool get_hit_file(const char* cached_path, std::string ffn) { return should_hit_cache() @@ -85,10 +86,16 @@ size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream) { get_hit_file(cached_path, read_fault_file_name)) { read_fault_file_name = ""; errno = EIO; + have_eio_error = true; return 0; } } - return fread(ptr, size, nitems, stream); + size_t status = fread(ptr, size, nitems, stream); + // If I/O error occurs, set the retry-update flag. + if (status != nitems && errno == EIO) { + have_eio_error = true; + } + return status; } ssize_t ota_read(int fd, void* buf, size_t nbyte) { @@ -99,10 +106,15 @@ ssize_t ota_read(int fd, void* buf, size_t nbyte) { && get_hit_file(cached_path, read_fault_file_name)) { read_fault_file_name = ""; errno = EIO; + have_eio_error = true; return -1; } } - return read(fd, buf, nbyte); + ssize_t status = read(fd, buf, nbyte); + if (status == -1 && errno == EIO) { + have_eio_error = true; + } + return status; } size_t ota_fwrite(const void* ptr, size_t size, size_t count, FILE* stream) { @@ -113,10 +125,15 @@ size_t ota_fwrite(const void* ptr, size_t size, size_t count, FILE* stream) { get_hit_file(cached_path, write_fault_file_name)) { write_fault_file_name = ""; errno = EIO; + have_eio_error = true; return 0; } } - return fwrite(ptr, size, count, stream); + size_t status = fwrite(ptr, size, count, stream); + if (status != count && errno == EIO) { + have_eio_error = true; + } + return status; } ssize_t ota_write(int fd, const void* buf, size_t nbyte) { @@ -127,10 +144,15 @@ ssize_t ota_write(int fd, const void* buf, size_t nbyte) { get_hit_file(cached_path, write_fault_file_name)) { write_fault_file_name = ""; errno = EIO; + have_eio_error = true; return -1; } } - return write(fd, buf, nbyte); + ssize_t status = write(fd, buf, nbyte); + if (status == -1 && errno == EIO) { + have_eio_error = true; + } + return status; } int ota_fsync(int fd) { @@ -141,9 +163,14 @@ int ota_fsync(int fd) { get_hit_file(cached_path, fsync_fault_file_name)) { fsync_fault_file_name = ""; errno = EIO; + have_eio_error = true; return -1; } } - return fsync(fd); + int status = fsync(fd); + if (status == -1 && errno == EIO) { + have_eio_error = true; + } + return status; } diff --git a/recovery.cpp b/recovery.cpp index 3ce218548..90742d879 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -60,6 +61,7 @@ struct selabel_handle *sehandle; static const struct option OPTIONS[] = { { "send_intent", required_argument, NULL, 'i' }, { "update_package", required_argument, NULL, 'u' }, + { "retry_count", required_argument, NULL, 'n' }, { "wipe_data", no_argument, NULL, 'w' }, { "wipe_cache", no_argument, NULL, 'c' }, { "show_text", no_argument, NULL, 't' }, @@ -86,6 +88,7 @@ static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install"; static const char *LAST_KMSG_FILE = "/cache/recovery/last_kmsg"; static const char *LAST_LOG_FILE = "/cache/recovery/last_log"; static const int KEEP_LOG_COUNT = 10; +static const int EIO_RETRY_COUNT = 2; static const int BATTERY_READ_TIMEOUT_IN_SEC = 10; // GmsCore enters recovery mode to install package when having enough battery // percentage. Normally, the threshold is 40% without charger and 20% with charger. @@ -1120,6 +1123,29 @@ static bool is_battery_ok() { } } +static void set_retry_bootloader_message(int retry_count, int argc, char** argv) { + struct bootloader_message boot {}; + strlcpy(boot.command, "boot-recovery", sizeof(boot.command)); + strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery)); + + for (int i = 1; i < argc; ++i) { + if (strstr(argv[i], "retry_count") == nullptr) { + strlcat(boot.recovery, argv[i], sizeof(boot.recovery)); + strlcat(boot.recovery, "\n", sizeof(boot.recovery)); + } + } + + // Initialize counter to 1 if it's not in BCB, otherwise increment it by 1. + if (retry_count == 0) { + strlcat(boot.recovery, "--retry_count=1\n", sizeof(boot.recovery)); + } else { + char buffer[20]; + snprintf(buffer, sizeof(buffer), "--retry_count=%d\n", retry_count+1); + strlcat(boot.recovery, buffer, sizeof(boot.recovery)); + } + set_bootloader_message(&boot); +} + int main(int argc, char **argv) { // If this binary is started with the single argument "--adbd", // instead of being the normal recovery binary, it turns into kind @@ -1153,11 +1179,13 @@ int main(int argc, char **argv) { bool sideload_auto_reboot = false; bool just_exit = false; bool shutdown_after = false; + int retry_count = 0; int arg; while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) { switch (arg) { case 'i': send_intent = optarg; break; + case 'n': android::base::ParseInt(optarg, &retry_count, 0); break; case 'u': update_package = optarg; break; case 'w': should_wipe_data = true; break; case 'c': should_wipe_cache = true; break; @@ -1262,7 +1290,24 @@ int main(int argc, char **argv) { } if (status != INSTALL_SUCCESS) { ui->Print("Installation aborted.\n"); - + // When I/O error happens, reboot and retry installation EIO_RETRY_COUNT + // times before we abandon this OTA update. + if (status == INSTALL_RETRY && retry_count < EIO_RETRY_COUNT) { + copy_logs(); + set_retry_bootloader_message(retry_count, argc, argv); + // Print retry count on screen. + ui->Print("Retry attempt %d\n", retry_count); + + // Reboot and retry the update + int ret = property_set(ANDROID_RB_PROPERTY, "reboot,recovery"); + if (ret < 0) { + ui->Print("Reboot failed\n"); + } else { + while (true) { + pause(); + } + } + } // If this is an eng or userdebug build, then automatically // turn the text display on if the script fails so the error // message is visible. diff --git a/updater/updater.cpp b/updater/updater.cpp index efb4a8cec..1693fa1db 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -36,6 +36,8 @@ // (Note it's "updateR-script", not the older "update-script".) #define SCRIPT_NAME "META-INF/com/google/android/updater-script" +extern bool have_eio_error; + struct selabel_handle *sehandle; int main(int argc, char** argv) { @@ -141,6 +143,11 @@ int main(int argc, char** argv) { state.errmsg = NULL; char* result = Evaluate(&state, root); + + if (have_eio_error) { + fprintf(cmd_pipe, "retry_update\n"); + } + if (result == NULL) { if (state.errmsg == NULL) { printf("script aborted (no error message)\n"); -- cgit v1.2.3 From d80a99883d5ae2b117c54f076fe1df7eae86d2f8 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 3 Mar 2016 11:43:47 -0800 Subject: Fix the improper use of LOCAL_WHOLE_STATIC_LIBRARIES. If two libraries both use LOCAL_WHOLE_STATIC_LIBRARIES and include a same library, there would be linking errors when generating a shared library (or executable) that depends on the two libraries both. Also clean up Android.mk files. Remove the "LOCAL_MODULE_TAGS := eng" line for the updater module. The module will then default to "optional" which won't be built until needed. Change-Id: I3ec227109b8aa744b7568e7f82f575aae3fe0e6f --- Android.mk | 9 ++-- applypatch/Android.mk | 64 +++++++++++++++------- applypatch/applypatch.cpp | 2 +- applypatch/applypatch.h | 87 ------------------------------ applypatch/bspatch.cpp | 2 +- applypatch/freecache.cpp | 2 +- applypatch/imgpatch.cpp | 2 +- applypatch/include/applypatch/applypatch.h | 87 ++++++++++++++++++++++++++++++ applypatch/main.cpp | 2 +- otafault/Android.mk | 13 +++-- updater/Android.mk | 66 +++++++++++++---------- 11 files changed, 189 insertions(+), 147 deletions(-) delete mode 100644 applypatch/applypatch.h create mode 100644 applypatch/include/applypatch/applypatch.h diff --git a/Android.mk b/Android.mk index 4477fefe3..fc981e12d 100644 --- a/Android.mk +++ b/Android.mk @@ -14,18 +14,20 @@ LOCAL_PATH := $(call my-dir) +# libfusesideload (static library) +# =============================== include $(CLEAR_VARS) LOCAL_SRC_FILES := fuse_sideload.cpp LOCAL_CLANG := true LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE - LOCAL_MODULE := libfusesideload - LOCAL_STATIC_LIBRARIES := libcutils libc libmincrypt include $(BUILD_STATIC_LIBRARY) +# recovery (static executable) +# =============================== include $(CLEAR_VARS) LOCAL_SRC_FILES := \ @@ -102,7 +104,8 @@ endif include $(BUILD_EXECUTABLE) -# All the APIs for testing +# libverifier (static library) +# =============================== include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_MODULE := libverifier diff --git a/applypatch/Android.mk b/applypatch/Android.mk index 90a86dcb0..9e64718c1 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -14,59 +14,83 @@ LOCAL_PATH := $(call my-dir) +# libapplypatch (static library) +# =============================== include $(CLEAR_VARS) - LOCAL_CLANG := true -LOCAL_SRC_FILES := applypatch.cpp bspatch.cpp freecache.cpp imgpatch.cpp utils.cpp +LOCAL_SRC_FILES := \ + applypatch.cpp \ + bspatch.cpp \ + freecache.cpp \ + imgpatch.cpp \ + utils.cpp LOCAL_MODULE := libapplypatch LOCAL_MODULE_TAGS := eng -LOCAL_C_INCLUDES += bootable/recovery -LOCAL_STATIC_LIBRARIES += libbase libotafault libmtdutils libcrypto_static libbz libz - +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/include \ + bootable/recovery +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +LOCAL_STATIC_LIBRARIES += \ + libotafault \ + libmtdutils \ + libbase \ + libcrypto_static \ + libbz \ + libz include $(BUILD_STATIC_LIBRARY) +# libimgpatch (static library) +# =============================== include $(CLEAR_VARS) - LOCAL_CLANG := true LOCAL_SRC_FILES := bspatch.cpp imgpatch.cpp utils.cpp LOCAL_MODULE := libimgpatch -LOCAL_C_INCLUDES += bootable/recovery +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/include \ + bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES += libcrypto_static libbz libz - include $(BUILD_STATIC_LIBRARY) -ifeq ($(HOST_OS),linux) +# libimgpatch (host static library) +# =============================== include $(CLEAR_VARS) - LOCAL_CLANG := true LOCAL_SRC_FILES := bspatch.cpp imgpatch.cpp utils.cpp LOCAL_MODULE := libimgpatch -LOCAL_C_INCLUDES += bootable/recovery +LOCAL_MODULE_HOST_OS := linux +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/include \ + bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES += libcrypto_static libbz libz - include $(BUILD_HOST_STATIC_LIBRARY) -endif # HOST_OS == linux +# applypatch (executable) +# =============================== include $(CLEAR_VARS) - LOCAL_CLANG := true LOCAL_SRC_FILES := main.cpp LOCAL_MODULE := applypatch LOCAL_C_INCLUDES += bootable/recovery -LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libmtdutils libcrypto_static libbz libedify +LOCAL_STATIC_LIBRARIES += \ + libapplypatch \ + libbase \ + libedify \ + libotafault \ + libminzip \ + libmtdutils \ + libcrypto_static \ + libbz LOCAL_SHARED_LIBRARIES += libz libcutils libc - include $(BUILD_EXECUTABLE) +# imgdiff (host static executable) +# =============================== include $(CLEAR_VARS) - LOCAL_CLANG := true LOCAL_SRC_FILES := imgdiff.cpp utils.cpp bsdiff.cpp LOCAL_MODULE := imgdiff -LOCAL_FORCE_STATIC_EXECUTABLE := true -LOCAL_C_INCLUDES += external/zlib external/bzip2 LOCAL_STATIC_LIBRARIES += libz libbz - +LOCAL_FORCE_STATIC_EXECUTABLE := true include $(BUILD_HOST_EXECUTABLE) diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 644515997..c8594c283 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -31,7 +31,7 @@ #include #include "openssl/sha.h" -#include "applypatch.h" +#include "applypatch/applypatch.h" #include "mtdutils/mtdutils.h" #include "edify/expr.h" #include "ota_io.h" diff --git a/applypatch/applypatch.h b/applypatch/applypatch.h deleted file mode 100644 index 9ee39d293..000000000 --- a/applypatch/applypatch.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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. - */ - -#ifndef _APPLYPATCH_H -#define _APPLYPATCH_H - -#include -#include - -#include - -#include "openssl/sha.h" -#include "edify/expr.h" - -struct FileContents { - uint8_t sha1[SHA_DIGEST_LENGTH]; - std::vector data; - struct stat st; -}; - -// When there isn't enough room on the target filesystem to hold the -// patched version of the file, we copy the original here and delete -// it to free up space. If the expected source file doesn't exist, or -// is corrupted, we look to see if this file contains the bits we want -// and use it as the source instead. -#define CACHE_TEMP_SOURCE "/cache/saved.file" - -typedef ssize_t (*SinkFn)(const unsigned char*, ssize_t, void*); - -// applypatch.c -int ShowLicenses(); -size_t FreeSpaceForFile(const char* filename); -int CacheSizeCheck(size_t bytes); -int ParseSha1(const char* str, uint8_t* digest); - -int applypatch_flash(const char* source_filename, const char* target_filename, - const char* target_sha1_str, size_t target_size); -int applypatch(const char* source_filename, - const char* target_filename, - const char* target_sha1_str, - size_t target_size, - int num_patches, - char** const patch_sha1_str, - Value** patch_data, - Value* bonus_data); -int applypatch_check(const char* filename, - int num_patches, - char** const patch_sha1_str); - -int LoadFileContents(const char* filename, FileContents* file); -int SaveFileContents(const char* filename, const FileContents* file); -void FreeFileContents(FileContents* file); -int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, - int num_patches); - -// bsdiff.cpp -void ShowBSDiffLicense(); -int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, - const Value* patch, ssize_t patch_offset, - SinkFn sink, void* token, SHA_CTX* ctx); -int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, - const Value* patch, ssize_t patch_offset, - std::vector* new_data); - -// imgpatch.cpp -int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, - const Value* patch, - SinkFn sink, void* token, SHA_CTX* ctx, - const Value* bonus_data); - -// freecache.cpp -int MakeFreeSpaceOnCache(size_t bytes_needed); - -#endif diff --git a/applypatch/bspatch.cpp b/applypatch/bspatch.cpp index 1fc1455a6..a4945da28 100644 --- a/applypatch/bspatch.cpp +++ b/applypatch/bspatch.cpp @@ -30,7 +30,7 @@ #include #include "openssl/sha.h" -#include "applypatch.h" +#include "applypatch/applypatch.h" void ShowBSDiffLicense() { puts("The bsdiff library used herein is:\n" diff --git a/applypatch/freecache.cpp b/applypatch/freecache.cpp index c84f42797..331cae265 100644 --- a/applypatch/freecache.cpp +++ b/applypatch/freecache.cpp @@ -32,7 +32,7 @@ #include #include -#include "applypatch.h" +#include "applypatch/applypatch.h" static int EliminateOpenFiles(std::set* files) { std::unique_ptr d(opendir("/proc"), closedir); diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp index 0ab995b30..4251c0120 100644 --- a/applypatch/imgpatch.cpp +++ b/applypatch/imgpatch.cpp @@ -28,7 +28,7 @@ #include "zlib.h" #include "openssl/sha.h" -#include "applypatch.h" +#include "applypatch/applypatch.h" #include "imgdiff.h" #include "utils.h" diff --git a/applypatch/include/applypatch/applypatch.h b/applypatch/include/applypatch/applypatch.h new file mode 100644 index 000000000..9ee39d293 --- /dev/null +++ b/applypatch/include/applypatch/applypatch.h @@ -0,0 +1,87 @@ +/* + * 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. + */ + +#ifndef _APPLYPATCH_H +#define _APPLYPATCH_H + +#include +#include + +#include + +#include "openssl/sha.h" +#include "edify/expr.h" + +struct FileContents { + uint8_t sha1[SHA_DIGEST_LENGTH]; + std::vector data; + struct stat st; +}; + +// When there isn't enough room on the target filesystem to hold the +// patched version of the file, we copy the original here and delete +// it to free up space. If the expected source file doesn't exist, or +// is corrupted, we look to see if this file contains the bits we want +// and use it as the source instead. +#define CACHE_TEMP_SOURCE "/cache/saved.file" + +typedef ssize_t (*SinkFn)(const unsigned char*, ssize_t, void*); + +// applypatch.c +int ShowLicenses(); +size_t FreeSpaceForFile(const char* filename); +int CacheSizeCheck(size_t bytes); +int ParseSha1(const char* str, uint8_t* digest); + +int applypatch_flash(const char* source_filename, const char* target_filename, + const char* target_sha1_str, size_t target_size); +int applypatch(const char* source_filename, + const char* target_filename, + const char* target_sha1_str, + size_t target_size, + int num_patches, + char** const patch_sha1_str, + Value** patch_data, + Value* bonus_data); +int applypatch_check(const char* filename, + int num_patches, + char** const patch_sha1_str); + +int LoadFileContents(const char* filename, FileContents* file); +int SaveFileContents(const char* filename, const FileContents* file); +void FreeFileContents(FileContents* file); +int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, + int num_patches); + +// bsdiff.cpp +void ShowBSDiffLicense(); +int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, + const Value* patch, ssize_t patch_offset, + SinkFn sink, void* token, SHA_CTX* ctx); +int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, + const Value* patch, ssize_t patch_offset, + std::vector* new_data); + +// imgpatch.cpp +int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, + const Value* patch, + SinkFn sink, void* token, SHA_CTX* ctx, + const Value* bonus_data); + +// freecache.cpp +int MakeFreeSpaceOnCache(size_t bytes_needed); + +#endif diff --git a/applypatch/main.cpp b/applypatch/main.cpp index 9013760c4..0ff8cbf9a 100644 --- a/applypatch/main.cpp +++ b/applypatch/main.cpp @@ -22,7 +22,7 @@ #include #include -#include "applypatch.h" +#include "applypatch/applypatch.h" #include "edify/expr.h" #include "openssl/sha.h" diff --git a/otafault/Android.mk b/otafault/Android.mk index 7468de6c4..52d706722 100644 --- a/otafault/Android.mk +++ b/otafault/Android.mk @@ -14,29 +14,34 @@ LOCAL_PATH := $(call my-dir) +# otafault (static library) +# =============================== include $(CLEAR_VARS) otafault_static_libs := \ libminzip \ - libz \ libselinux \ + libz LOCAL_SRC_FILES := config.cpp ota_io.cpp -LOCAL_MODULE_TAGS := eng LOCAL_MODULE := libotafault LOCAL_CLANG := true LOCAL_C_INCLUDES := bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) -LOCAL_WHOLE_STATIC_LIBRARIES := $(otafault_static_libs) +LOCAL_STATIC_LIBRARIES := $(otafault_static_libs) include $(BUILD_STATIC_LIBRARY) +# otafault_test (static executable) +# =============================== include $(CLEAR_VARS) LOCAL_SRC_FILES := config.cpp ota_io.cpp test.cpp LOCAL_MODULE_TAGS := tests LOCAL_MODULE := otafault_test -LOCAL_STATIC_LIBRARIES := $(otafault_static_libs) +LOCAL_STATIC_LIBRARIES := \ + libotafault \ + $(otafault_static_libs) LOCAL_C_INCLUDES := bootable/recovery LOCAL_FORCE_STATIC_EXECUTABLE := true diff --git a/updater/Android.mk b/updater/Android.mk index d7aa613e9..47c56ccd9 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -14,26 +14,50 @@ LOCAL_PATH := $(call my-dir) -updater_src_files := \ - install.cpp \ - blockimg.cpp \ - updater.cpp - -# -# Build a statically-linked binary to include in OTA packages -# +# updater (static executable) +# =============================== +# Build a statically-linked binary to include in OTA packages. include $(CLEAR_VARS) -# Build only in eng, so we don't end up with a copy of this in /system -# on user builds. (TODO: find a better way to build device binaries -# needed only for OTA packages.) -LOCAL_MODULE_TAGS := eng +updater_src_files := \ + install.cpp \ + blockimg.cpp \ + updater.cpp LOCAL_CLANG := true - LOCAL_SRC_FILES := $(updater_src_files) -LOCAL_STATIC_LIBRARIES += libfec libfec_rs libext4_utils_static libsquashfs_utils libcrypto_static +LOCAL_STATIC_LIBRARIES += \ + $(TARGET_RECOVERY_UPDATER_LIBS) \ + $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS) \ + libfec \ + libfec_rs \ + libext4_utils_static \ + libsquashfs_utils \ + libcrypto_static \ + libapplypatch \ + libbase \ + libotafault \ + libedify \ + libmtdutils \ + libminzip \ + libz \ + libbz \ + libcutils \ + liblog \ + libselinux + +tune2fs_static_libraries := \ + libext2_com_err \ + libext2_blkid \ + libext2_quota \ + libext2_uuid_static \ + libext2_e2p \ + libext2fs + +LOCAL_STATIC_LIBRARIES += \ + libtune2fs \ + $(tune2fs_static_libraries) ifeq ($(TARGET_USERIMAGES_USE_EXT4), true) LOCAL_CFLAGS += -DUSE_EXT4 @@ -44,20 +68,6 @@ LOCAL_STATIC_LIBRARIES += \ libz endif -LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS) -LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libedify libmtdutils libminzip libz -LOCAL_STATIC_LIBRARIES += libbz -LOCAL_STATIC_LIBRARIES += libcutils liblog libc -LOCAL_STATIC_LIBRARIES += libselinux -tune2fs_static_libraries := \ - libext2_com_err \ - libext2_blkid \ - libext2_quota \ - libext2_uuid_static \ - libext2_e2p \ - libext2fs -LOCAL_STATIC_LIBRARIES += libtune2fs $(tune2fs_static_libraries) - LOCAL_C_INCLUDES += external/e2fsprogs/misc LOCAL_C_INCLUDES += $(LOCAL_PATH)/.. -- cgit v1.2.3 From ef2016f711eaef6c22d177a12d335055556ea3a0 Mon Sep 17 00:00:00 2001 From: Sen Jiang Date: Tue, 8 Mar 2016 14:27:14 -0800 Subject: applypatch: add -fPIC for libimgpatch in Chrome OS. To make the static library position independent. Bug: 26866274 Test: emerge-peppy imgdiff; sudo emerge imgdiff; emerge nyan imgdiff Change-Id: I319e721ccfb6a51f63d31afa49f54aa7f607f4bf --- applypatch/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/applypatch/Makefile b/applypatch/Makefile index fa6298d46..de6d4268f 100644 --- a/applypatch/Makefile +++ b/applypatch/Makefile @@ -28,5 +28,6 @@ clean: imgdiff: imgdiff.o bsdiff.o utils.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDLIBS) -o $@ $^ +libimgpatch.a utils.o: CXXFLAGS += -fPIC libimgpatch.a: imgpatch.o bspatch.o utils.o ${AR} rcs $@ $^ -- cgit v1.2.3 From 82f8c820463f73ac1149ffbe65e4a6f24f826ab4 Mon Sep 17 00:00:00 2001 From: Alex Deymo Date: Mon, 14 Mar 2016 14:25:33 -0700 Subject: Add include/ to the Makefile include path. The applypatch heaaders were recently moved to the include/ directory. This patch reflects that change in the Makefile. Bug: None TEST=sudo emerge imgdiff Change-Id: I0bf3f991b5e0c98054033c5939ed69b3e3c827a9 --- applypatch/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applypatch/Makefile b/applypatch/Makefile index de6d4268f..fb4984303 100644 --- a/applypatch/Makefile +++ b/applypatch/Makefile @@ -14,7 +14,7 @@ # This file is for building imgdiff in Chrome OS. -CPPFLAGS += -iquote.. +CPPFLAGS += -iquote.. -Iinclude CXXFLAGS += -std=c++11 -O3 -Wall -Werror LDLIBS += -lbz2 -lz -- cgit v1.2.3 From 2584f9c24dcc86f23775e3b6c178ab41605d6d75 Mon Sep 17 00:00:00 2001 From: caozhiyuan Date: Fri, 11 Mar 2016 15:18:29 +0800 Subject: Fix: full ota package larger than 2GB fails to upgrade Change-Id: I45d9fab8739cc6fa8a0bacaca9238896118d9d7f Signed-off-by: diruomeng Signed-off-by: caozhiyuan --- minzip/Zip.c | 16 +++++++++------- minzip/Zip.h | 10 +++++----- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/minzip/Zip.c b/minzip/Zip.c index 38f939fb2..0f89835ca 100644 --- a/minzip/Zip.c +++ b/minzip/Zip.c @@ -91,7 +91,7 @@ enum { static void dumpEntry(const ZipEntry* pEntry) { LOGI(" %p '%.*s'\n", pEntry->fileName,pEntry->fileNameLen,pEntry->fileName); - LOGI(" off=%ld comp=%ld uncomp=%ld how=%d\n", pEntry->offset, + LOGI(" off=%u comp=%u uncomp=%u how=%d\n", pEntry->offset, pEntry->compLen, pEntry->uncompLen, pEntry->compression); } #endif @@ -505,7 +505,8 @@ static bool processDeflatedEntry(const ZipArchive *pArchive, const ZipEntry *pEntry, ProcessZipEntryContentsFunction processFunction, void *cookie) { - long result = -1; + bool success = false; + unsigned long totalOut = 0; unsigned char procBuf[32 * 1024]; z_stream zstream; int zerr; @@ -569,16 +570,17 @@ static bool processDeflatedEntry(const ZipArchive *pArchive, assert(zerr == Z_STREAM_END); /* other errors should've been caught */ // success! - result = zstream.total_out; + totalOut = zstream.total_out; + success = true; z_bail: inflateEnd(&zstream); /* free up any allocated structures */ bail: - if (result != pEntry->uncompLen) { - if (result != -1) // error already shown? - LOGW("Size mismatch on inflated file (%ld vs %ld)\n", - result, pEntry->uncompLen); + if (totalOut != pEntry->uncompLen) { + if (success) { // error already shown? + LOGW("Size mismatch on inflated file (%lu vs %u)\n", totalOut, pEntry->uncompLen); + } return false; } return true; diff --git a/minzip/Zip.h b/minzip/Zip.h index 86d8db597..e6b19e1f0 100644 --- a/minzip/Zip.h +++ b/minzip/Zip.h @@ -32,9 +32,9 @@ extern "C" { typedef struct ZipEntry { unsigned int fileNameLen; const char* fileName; // not null-terminated - long offset; - long compLen; - long uncompLen; + uint32_t offset; + uint32_t compLen; + uint32_t uncompLen; int compression; long modTime; long crc32; @@ -85,10 +85,10 @@ void mzCloseZipArchive(ZipArchive* pArchive); const ZipEntry* mzFindZipEntry(const ZipArchive* pArchive, const char* entryName); -INLINE long mzGetZipEntryOffset(const ZipEntry* pEntry) { +INLINE uint32_t mzGetZipEntryOffset(const ZipEntry* pEntry) { return pEntry->offset; } -INLINE long mzGetZipEntryUncompLen(const ZipEntry* pEntry) { +INLINE uint32_t mzGetZipEntryUncompLen(const ZipEntry* pEntry) { return pEntry->uncompLen; } -- cgit v1.2.3 From 57eb4fd6e20f53ec80eab66dcd5a0c1cefaa9262 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 22 Mar 2016 21:08:39 -0700 Subject: Remove dead tools. None of these have been touched since cupcake, except to keep them building. Change-Id: I5ed13849e6842e755c62da05f1a8a6da2583b1ee --- tools/ota/Android.mk | 33 ---------- tools/ota/add-property-tag.c | 141 ----------------------------------------- tools/ota/check-lost+found.c | 145 ------------------------------------------- tools/ota/convert-to-bmp.py | 79 ----------------------- 4 files changed, 398 deletions(-) delete mode 100644 tools/ota/Android.mk delete mode 100644 tools/ota/add-property-tag.c delete mode 100644 tools/ota/check-lost+found.c delete mode 100644 tools/ota/convert-to-bmp.py diff --git a/tools/ota/Android.mk b/tools/ota/Android.mk deleted file mode 100644 index 142c3b257..000000000 --- a/tools/ota/Android.mk +++ /dev/null @@ -1,33 +0,0 @@ -# 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) -LOCAL_FORCE_STATIC_EXECUTABLE := true -LOCAL_MODULE := add-property-tag -LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) -LOCAL_MODULE_TAGS := debug -LOCAL_SRC_FILES := add-property-tag.c -LOCAL_STATIC_LIBRARIES := libc -include $(BUILD_EXECUTABLE) - -include $(CLEAR_VARS) -LOCAL_FORCE_STATIC_EXECUTABLE := true -LOCAL_MODULE := check-lost+found -LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) -LOCAL_MODULE_TAGS := debug -LOCAL_SRC_FILES := check-lost+found.c -LOCAL_STATIC_LIBRARIES := libcutils libc -include $(BUILD_EXECUTABLE) diff --git a/tools/ota/add-property-tag.c b/tools/ota/add-property-tag.c deleted file mode 100644 index aab30b2d0..000000000 --- a/tools/ota/add-property-tag.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include - -/* - * Append a tag to a property value in a .prop file if it isn't already there. - * Normally used to modify build properties to record incremental updates. - */ - -// Return nonzero if the tag should be added to this line. -int should_tag(const char *line, const char *propname) { - const char *prop = strstr(line, propname); - if (prop == NULL) return 0; - - // Make sure this is actually the property name (not an accidental hit) - const char *ptr; - for (ptr = line; ptr < prop && isspace(*ptr); ++ptr) ; - if (ptr != prop) return 0; // Must be at the beginning of the line - - for (ptr += strlen(propname); *ptr != '\0' && isspace(*ptr); ++ptr) ; - return (*ptr == '='); // Must be followed by a '=' -} - -// Remove existing tags from the line, return the following number (if any) -int remove_tag(char *line, const char *tag) { - char *pos = strstr(line, tag); - if (pos == NULL) return 0; - - char *end; - int num = strtoul(pos + strlen(tag), &end, 10); - strcpy(pos, end); - return num; -} - -// Write line to output with the tag added, adding a number (if >0) -void write_tagged(FILE *out, const char *line, const char *tag, int number) { - const char *end = line + strlen(line); - while (end > line && isspace(end[-1])) --end; - if (number > 0) { - fprintf(out, "%.*s%s%d%s", (int)(end - line), line, tag, number, end); - } else { - fprintf(out, "%.*s%s%s", (int)(end - line), line, tag, end); - } -} - -int main(int argc, char **argv) { - const char *filename = "/system/build.prop"; - const char *propname = "ro.build.fingerprint"; - const char *tag = NULL; - int do_remove = 0, do_number = 0; - - int opt; - while ((opt = getopt(argc, argv, "f:p:rn")) != -1) { - switch (opt) { - case 'f': filename = optarg; break; - case 'p': propname = optarg; break; - case 'r': do_remove = 1; break; - case 'n': do_number = 1; break; - case '?': return 2; - } - } - - if (argc != optind + 1) { - fprintf(stderr, - "usage: add-property-tag [flags] tag-to-add\n" - "flags: -f /dir/file.prop (default /system/build.prop)\n" - " -p prop.name (default ro.build.fingerprint)\n" - " -r (if set, remove the tag rather than adding it)\n" - " -n (if set, add and increment a number after the tag)\n"); - return 2; - } - - tag = argv[optind]; - FILE *input = fopen(filename, "r"); - if (input == NULL) { - fprintf(stderr, "can't read %s: %s\n", filename, strerror(errno)); - return 1; - } - - char tmpname[PATH_MAX]; - snprintf(tmpname, sizeof(tmpname), "%s.tmp", filename); - FILE *output = fopen(tmpname, "w"); - if (output == NULL) { - fprintf(stderr, "can't write %s: %s\n", tmpname, strerror(errno)); - return 1; - } - - int found = 0; - char line[4096]; - while (fgets(line, sizeof(line), input)) { - if (!should_tag(line, propname)) { - fputs(line, output); // Pass through unmodified - } else { - found = 1; - int number = remove_tag(line, tag); - if (do_remove) { - fputs(line, output); // Remove the tag but don't re-add it - } else { - write_tagged(output, line, tag, number + do_number); - } - } - } - - fclose(input); - fclose(output); - - if (!found) { - fprintf(stderr, "property %s not found in %s\n", propname, filename); - remove(tmpname); - return 1; - } - - if (rename(tmpname, filename)) { - fprintf(stderr, "can't rename %s to %s: %s\n", - tmpname, filename, strerror(errno)); - remove(tmpname); - return 1; - } - - return 0; -} diff --git a/tools/ota/check-lost+found.c b/tools/ota/check-lost+found.c deleted file mode 100644 index 8ce12d39f..000000000 --- a/tools/ota/check-lost+found.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "private/android_filesystem_config.h" - -// Sentinel file used to track whether we've forced a reboot -static const char *kMarkerFile = "/data/misc/check-lost+found-rebooted-2"; - -// Output file in tombstones directory (first 8K will be uploaded) -static const char *kOutputDir = "/data/tombstones"; -static const char *kOutputFile = "/data/tombstones/check-lost+found-log"; - -// Partitions to check -static const char *kPartitions[] = { "/system", "/data", "/cache", NULL }; - -/* - * 1. If /data/misc/forced-reboot is missing, touch it & force "unclean" boot. - * 2. Write a log entry with the number of files in lost+found directories. - */ - -int main(int argc __attribute__((unused)), char **argv __attribute__((unused))) { - mkdir(kOutputDir, 0755); - chown(kOutputDir, AID_SYSTEM, AID_SYSTEM); - FILE *out = fopen(kOutputFile, "a"); - if (out == NULL) { - fprintf(stderr, "Can't write %s: %s\n", kOutputFile, strerror(errno)); - return 1; - } - - // Note: only the first 8K of log will be uploaded, so be terse. - time_t start = time(NULL); - fprintf(out, "*** check-lost+found ***\nStarted: %s", ctime(&start)); - - struct stat st; - if (stat(kMarkerFile, &st)) { - // No reboot marker -- need to force an unclean reboot. - // But first, try to create the marker file. If that fails, - // skip the reboot, so we don't get caught in an infinite loop. - - int fd = open(kMarkerFile, O_WRONLY|O_CREAT, 0444); - if (fd >= 0 && close(fd) == 0) { - fprintf(out, "Wrote %s, rebooting\n", kMarkerFile); - fflush(out); - sync(); // Make sure the marker file is committed to disk - - // If possible, dirty each of these partitions before rebooting, - // to make sure the filesystem has to do a scan on mount. - int i; - for (i = 0; kPartitions[i] != NULL; ++i) { - char fn[PATH_MAX]; - snprintf(fn, sizeof(fn), "%s/%s", kPartitions[i], "dirty"); - fd = open(fn, O_WRONLY|O_CREAT, 0444); - if (fd >= 0) { // Don't sweat it if we can't write the file. - TEMP_FAILURE_RETRY(write(fd, fn, sizeof(fn))); // write, you know, some data - close(fd); - unlink(fn); - } - } - - reboot(RB_AUTOBOOT); // reboot immediately, with dirty filesystems - fprintf(out, "Reboot failed?!\n"); - exit(1); - } else { - fprintf(out, "Can't write %s: %s\n", kMarkerFile, strerror(errno)); - } - } else { - fprintf(out, "Found %s\n", kMarkerFile); - } - - int i; - for (i = 0; kPartitions[i] != NULL; ++i) { - char fn[PATH_MAX]; - snprintf(fn, sizeof(fn), "%s/%s", kPartitions[i], "lost+found"); - DIR *dir = opendir(fn); - if (dir == NULL) { - fprintf(out, "Can't open %s: %s\n", fn, strerror(errno)); - } else { - int count = 0; - struct dirent *ent; - while ((ent = readdir(dir))) { - if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) - ++count; - } - closedir(dir); - if (count > 0) { - fprintf(out, "OMGZ FOUND %d FILES IN %s\n", count, fn); - } else { - fprintf(out, "%s is clean\n", fn); - } - } - } - - char dmesg[131073]; - int len = klogctl(KLOG_READ_ALL, dmesg, sizeof(dmesg) - 1); - if (len < 0) { - fprintf(out, "Can't read kernel log: %s\n", strerror(errno)); - } else { // To conserve space, only write lines with certain keywords - fprintf(out, "--- Kernel log ---\n"); - dmesg[len] = '\0'; - char *saveptr, *line; - int in_yaffs = 0; - for (line = strtok_r(dmesg, "\n", &saveptr); line != NULL; - line = strtok_r(NULL, "\n", &saveptr)) { - if (strstr(line, "yaffs: dev is")) in_yaffs = 1; - - if (in_yaffs || - strstr(line, "yaffs") || - strstr(line, "mtd") || - strstr(line, "msm_nand")) { - fprintf(out, "%s\n", line); - } - - if (strstr(line, "yaffs_read_super: isCheckpointed")) in_yaffs = 0; - } - } - - return 0; -} diff --git a/tools/ota/convert-to-bmp.py b/tools/ota/convert-to-bmp.py deleted file mode 100644 index 446c09da8..000000000 --- a/tools/ota/convert-to-bmp.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/python2.4 - -"""A simple script to convert asset images to BMP files, that supports -RGBA image.""" - -import struct -import Image -import sys - -infile = sys.argv[1] -outfile = sys.argv[2] - -if not outfile.endswith(".bmp"): - print >> sys.stderr, "Warning: I'm expecting to write BMP files." - -im = Image.open(infile) -if im.mode == 'RGB': - im.save(outfile) -elif im.mode == 'RGBA': - # Python Imaging Library doesn't write RGBA BMP files, so we roll - # our own. - - BMP_HEADER_FMT = ("<" # little-endian - "H" # signature - "L" # file size - "HH" # reserved (set to 0) - "L" # offset to start of bitmap data) - ) - - BITMAPINFO_HEADER_FMT= ("<" # little-endian - "L" # size of this struct - "L" # width - "L" # height - "H" # planes (set to 1) - "H" # bit count - "L" # compression (set to 0 for minui) - "L" # size of image data (0 if uncompressed) - "L" # x pixels per meter (1) - "L" # y pixels per meter (1) - "L" # colors used (0) - "L" # important colors (0) - ) - - fileheadersize = struct.calcsize(BMP_HEADER_FMT) - infoheadersize = struct.calcsize(BITMAPINFO_HEADER_FMT) - - header = struct.pack(BMP_HEADER_FMT, - 0x4d42, # "BM" in little-endian - (fileheadersize + infoheadersize + - im.size[0] * im.size[1] * 4), - 0, 0, - fileheadersize + infoheadersize) - - info = struct.pack(BITMAPINFO_HEADER_FMT, - infoheadersize, - im.size[0], - im.size[1], - 1, - 32, - 0, - 0, - 1, - 1, - 0, - 0) - - f = open(outfile, "wb") - f.write(header) - f.write(info) - data = im.tostring() - for j in range(im.size[1]-1, -1, -1): # rows bottom-to-top - for i in range(j*im.size[0]*4, (j+1)*im.size[0]*4, 4): - f.write(data[i+2]) # B - f.write(data[i+1]) # G - f.write(data[i+0]) # R - f.write(data[i+3]) # A - f.close() -else: - print >> sys.stderr, "Don't know how to handle image mode '%s'." % (im.mode,) -- cgit v1.2.3 From c14d95da5874053eb37cd2fe6187ab7658a2a03a Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Thu, 24 Mar 2016 11:50:34 -0700 Subject: Clean up intent_file related code in recovery.cpp No one in recovery or framework is utilizing intent file. Clean up the code. Bug:27725880 Change-Id: I78b37ff94261793e0d6a86a0fa6d27dcfe3f4783 --- recovery.cpp | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/recovery.cpp b/recovery.cpp index 6781fa4b4..4ee835c98 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -59,7 +59,6 @@ struct selabel_handle *sehandle; static const struct option OPTIONS[] = { - { "send_intent", required_argument, NULL, 'i' }, { "update_package", required_argument, NULL, 'u' }, { "retry_count", required_argument, NULL, 'n' }, { "wipe_data", no_argument, NULL, 'w' }, @@ -77,7 +76,6 @@ static const struct option OPTIONS[] = { static const char *CACHE_LOG_DIR = "/cache/recovery"; static const char *COMMAND_FILE = "/cache/recovery/command"; -static const char *INTENT_FILE = "/cache/recovery/intent"; static const char *LOG_FILE = "/cache/recovery/log"; static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install"; static const char *LOCALE_FILE = "/cache/recovery/last_locale"; @@ -107,10 +105,8 @@ static bool has_cache = false; * The recovery tool communicates with the main system through /cache files. * /cache/recovery/command - INPUT - command line for tool, one arg per line * /cache/recovery/log - OUTPUT - combined log file from recovery run(s) - * /cache/recovery/intent - OUTPUT - intent that was passed in * * The arguments which may be supplied in the recovery.command file: - * --send_intent=anystring - write the text out to recovery.intent * --update_package=path - verify install an OTA package file * --wipe_data - erase user data (and cache), then reboot * --wipe_cache - wipe cache (but not user data), then reboot @@ -467,22 +463,10 @@ static void copy_logs() { } // clear the recovery command and prepare to boot a (hopefully working) system, -// copy our log file to cache as well (for the system to read), and -// record any intent we were asked to communicate back to the system. -// this function is idempotent: call it as many times as you like. +// copy our log file to cache as well (for the system to read). This function is +// idempotent: call it as many times as you like. static void -finish_recovery(const char *send_intent) { - // By this point, we're ready to return to the main system... - if (send_intent != NULL && has_cache) { - FILE *fp = fopen_path(INTENT_FILE, "w"); - if (fp == NULL) { - LOGE("Can't open %s\n", INTENT_FILE); - } else { - fputs(send_intent, fp); - check_and_fclose(fp, INTENT_FILE); - } - } - +finish_recovery() { // Save the locale to cache, so if recovery is next started up // without a --locale argument (eg, directly from the bootloader) // it will use the last-known locale. @@ -947,7 +931,7 @@ static int apply_from_sdcard(Device* device, bool* wipe_cache) { static Device::BuiltinAction prompt_and_wait(Device* device, int status) { for (;;) { - finish_recovery(NULL); + finish_recovery(); switch (status) { case INSTALL_SUCCESS: case INSTALL_NONE: @@ -1189,7 +1173,6 @@ int main(int argc, char **argv) { get_args(&argc, &argv); - const char *send_intent = NULL; const char *update_package = NULL; bool should_wipe_data = false; bool should_wipe_cache = false; @@ -1203,7 +1186,6 @@ int main(int argc, char **argv) { int arg; while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) { switch (arg) { - case 'i': send_intent = optarg; break; case 'n': android::base::ParseInt(optarg, &retry_count, 0); break; case 'u': update_package = optarg; break; case 'w': should_wipe_data = true; break; @@ -1390,7 +1372,7 @@ int main(int argc, char **argv) { } // Save logs and clean up before rebooting or shutting down. - finish_recovery(send_intent); + finish_recovery(); switch (after) { case Device::SHUTDOWN: -- cgit v1.2.3 From e326b224460cfe2e3f7e2c7c79778ef092f4f917 Mon Sep 17 00:00:00 2001 From: Jed Estep Date: Tue, 22 Mar 2016 15:25:27 -0700 Subject: Correct caching behavior for should_inject_cache Bug: 27800498 Change-Id: I5255283c1d04a385ed719c5bc2be461cae9f3648 (cherry picked from commit 88dd7796a1fd4c64d57afb20021bf66cb26fa886) --- otafault/Android.mk | 5 +++-- otafault/config.cpp | 36 ++++++++++++++++++++---------------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/otafault/Android.mk b/otafault/Android.mk index 52d706722..50e385efb 100644 --- a/otafault/Android.mk +++ b/otafault/Android.mk @@ -19,9 +19,10 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) otafault_static_libs := \ + libbase \ libminzip \ - libselinux \ - libz + libz \ + libselinux LOCAL_SRC_FILES := config.cpp ota_io.cpp LOCAL_MODULE := libotafault diff --git a/otafault/config.cpp b/otafault/config.cpp index c87f9a631..b4567392d 100644 --- a/otafault/config.cpp +++ b/otafault/config.cpp @@ -20,6 +20,8 @@ #include #include +#include + #include "minzip/Zip.h" #include "config.h" #include "ota_io.h" @@ -27,12 +29,10 @@ #define OTAIO_MAX_FNAME_SIZE 128 static ZipArchive* archive; -static std::map should_inject_cache; +static std::map should_inject_cache; -static const char* get_type_path(const char* io_type) { - char* path = (char*)calloc(strlen(io_type) + strlen(OTAIO_BASE_DIR) + 2, sizeof(char)); - sprintf(path, "%s/%s", OTAIO_BASE_DIR, io_type); - return path; +static std::string get_type_path(const char* io_type) { + return android::base::StringPrintf("%s/%s", OTAIO_BASE_DIR, io_type); } void ota_io_init(ZipArchive* za) { @@ -41,13 +41,17 @@ void ota_io_init(ZipArchive* za) { } bool should_fault_inject(const char* io_type) { - if (should_inject_cache.find(io_type) != should_inject_cache.end()) { - return should_inject_cache[io_type]; + // archive will be NULL if we used an entry point other + // than updater/updater.cpp:main + if (archive == NULL) { + return false; + } + const std::string type_path = get_type_path(io_type); + if (should_inject_cache.find(type_path) != should_inject_cache.end()) { + return should_inject_cache[type_path]; } - const char* type_path = get_type_path(io_type); - const ZipEntry* entry = mzFindZipEntry(archive, type_path); + const ZipEntry* entry = mzFindZipEntry(archive, type_path.c_str()); should_inject_cache[type_path] = entry != nullptr; - free((void*)type_path); return entry != NULL; } @@ -56,10 +60,10 @@ bool should_hit_cache() { } std::string fault_fname(const char* io_type) { - const char* type_path = get_type_path(io_type); - char* fname = (char*) calloc(OTAIO_MAX_FNAME_SIZE, sizeof(char)); - const ZipEntry* entry = mzFindZipEntry(archive, type_path); - mzReadZipEntry(archive, entry, fname, OTAIO_MAX_FNAME_SIZE); - free((void*)type_path); - return std::string(fname); + std::string type_path = get_type_path(io_type); + std::string fname; + fname.resize(OTAIO_MAX_FNAME_SIZE); + const ZipEntry* entry = mzFindZipEntry(archive, type_path.c_str()); + mzReadZipEntry(archive, entry, &fname[0], OTAIO_MAX_FNAME_SIZE); + return fname; } -- cgit v1.2.3 From 7eca97e75df5d152730a7faad78e13fe741bc4d2 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Tue, 22 Mar 2016 18:08:12 -0700 Subject: Skip stashing source blocks in verify mode Currently block_image_verify() stashes source blocks to /cache and in some case triggers I/O errors. To avoid this risk, We create a map from the hash value to the source blocks' range_set. When executing stash command in verify mode, source range is saved but block contents aren't stashed. And load_stash could get its value from either the stashed file from the previous update, or the contents on the source partition specified by the saved range. Bug: 27584487 Bug: 25633753 Change-Id: I775baf4bee55762b6e7b204f8294afc597afd996 (cherry picked from commit 0188935d55206e8c2becb29e995f166cb7040355) --- updater/blockimg.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 56378d4f5..9d329cd24 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -67,6 +68,8 @@ struct RangeSet { std::vector pos; // Actual limit is INT_MAX. }; +static std::map stash_map; + static void parse_range(const std::string& range_text, RangeSet& rs) { std::vector pieces = android::base::Split(range_text, ","); @@ -522,8 +525,28 @@ static void DeleteStash(const std::string& base) { } } -static int LoadStash(const std::string& base, const std::string& id, bool verify, size_t* blocks, - std::vector& buffer, bool printnoent) { +static int LoadStash(CommandParameters& params, const std::string& base, const std::string& id, + bool verify, size_t* blocks, std::vector& buffer, bool printnoent) { + // In verify mode, if source range_set was saved for the given hash, + // check contents in the source blocks first. If the check fails, + // search for the stashed files on /cache as usual. + if (!params.canwrite) { + if (stash_map.find(id) != stash_map.end()) { + const RangeSet& src = stash_map[id]; + allocate(src.size * BLOCKSIZE, buffer); + + if (ReadBlocks(src, buffer, params.fd) == -1) { + fprintf(stderr, "failed to read source blocks in stash map.\n"); + return -1; + } + if (VerifyBlocks(id, buffer, src.size, true) != 0) { + fprintf(stderr, "failed to verify loaded source blocks in stash map.\n"); + return -1; + } + return 0; + } + } + if (base.empty()) { return -1; } @@ -722,7 +745,7 @@ static int SaveStash(CommandParameters& params, const std::string& base, const std::string& id = params.tokens[params.cpos++]; size_t blocks = 0; - if (usehash && LoadStash(base, id, true, &blocks, buffer, false) == 0) { + if (usehash && LoadStash(params, base, id, true, &blocks, buffer, false) == 0) { // Stash file already exists and has expected contents. Do not // read from source again, as the source may have been already // overwritten during a previous attempt. @@ -747,6 +770,12 @@ static int SaveStash(CommandParameters& params, const std::string& base, return 0; } + // In verify mode, save source range_set instead of stashing blocks. + if (!params.canwrite && usehash) { + stash_map[id] = src; + return 0; + } + fprintf(stderr, "stashing %zu blocks to %s\n", blocks, id.c_str()); return WriteStash(base, id, blocks, buffer, false, nullptr); } @@ -857,7 +886,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& } std::vector stash; - int res = LoadStash(stashbase, tokens[0], false, nullptr, stash, true); + int res = LoadStash(params, stashbase, tokens[0], false, nullptr, stash, true); if (res == -1) { // These source blocks will fail verification if used later, but we @@ -931,8 +960,9 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& if (VerifyBlocks(srchash, params.buffer, src_blocks, true) == 0) { // If source and target blocks overlap, stash the source blocks so we can - // resume from possible write errors - if (overlap) { + // resume from possible write errors. In verify mode, we can skip stashing + // because the source blocks won't be overwritten. + if (overlap && params.canwrite) { fprintf(stderr, "stashing %zu overlapping blocks to %s\n", src_blocks, srchash.c_str()); @@ -953,7 +983,8 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& return 0; } - if (overlap && LoadStash(params.stashbase, srchash, true, nullptr, params.buffer, true) == 0) { + if (overlap && LoadStash(params, params.stashbase, srchash, true, nullptr, params.buffer, + true) == 0) { // Overlapping source blocks were previously stashed, command can proceed. // We are recovering from an interrupted command, so we don't know if the // stash can safely be deleted after this command. @@ -1028,8 +1059,15 @@ static int PerformCommandFree(CommandParameters& params) { return -1; } + const std::string& id = params.tokens[params.cpos++]; + + if (!params.canwrite && stash_map.find(id) != stash_map.end()) { + stash_map.erase(id); + return 0; + } + if (params.createdstash || params.canwrite) { - return FreeStash(params.stashbase, params.tokens[params.cpos++]); + return FreeStash(params.stashbase, id); } return 0; -- cgit v1.2.3 From 3d0153a807042dd1bdb7e9fd81d16429a205d9ce Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 22 Mar 2016 21:18:58 -0700 Subject: Move recovery_l10n here from development/tools. Bug: http://b/27837319 Change-Id: I116fc13ae108a59b657f5c9f7efe971de72ac743 --- tools/recovery_l10n/Android.mk | 12 + tools/recovery_l10n/AndroidManifest.xml | 18 ++ tools/recovery_l10n/res/layout/main.xml | 31 ++ tools/recovery_l10n/res/values-af/strings.xml | 8 + tools/recovery_l10n/res/values-am/strings.xml | 8 + tools/recovery_l10n/res/values-ar/strings.xml | 8 + tools/recovery_l10n/res/values-az-rAZ/strings.xml | 8 + tools/recovery_l10n/res/values-bg/strings.xml | 8 + tools/recovery_l10n/res/values-bn-rBD/strings.xml | 8 + tools/recovery_l10n/res/values-ca/strings.xml | 8 + tools/recovery_l10n/res/values-cs/strings.xml | 8 + tools/recovery_l10n/res/values-da/strings.xml | 8 + tools/recovery_l10n/res/values-de/strings.xml | 8 + tools/recovery_l10n/res/values-el/strings.xml | 8 + tools/recovery_l10n/res/values-en-rAU/strings.xml | 8 + tools/recovery_l10n/res/values-en-rGB/strings.xml | 8 + tools/recovery_l10n/res/values-en-rIN/strings.xml | 8 + tools/recovery_l10n/res/values-es-rUS/strings.xml | 8 + tools/recovery_l10n/res/values-es/strings.xml | 8 + tools/recovery_l10n/res/values-et-rEE/strings.xml | 8 + tools/recovery_l10n/res/values-eu-rES/strings.xml | 8 + tools/recovery_l10n/res/values-fa/strings.xml | 8 + tools/recovery_l10n/res/values-fi/strings.xml | 8 + tools/recovery_l10n/res/values-fr-rCA/strings.xml | 8 + tools/recovery_l10n/res/values-fr/strings.xml | 8 + tools/recovery_l10n/res/values-gl-rES/strings.xml | 8 + tools/recovery_l10n/res/values-gu-rIN/strings.xml | 8 + tools/recovery_l10n/res/values-hi/strings.xml | 8 + tools/recovery_l10n/res/values-hr/strings.xml | 8 + tools/recovery_l10n/res/values-hu/strings.xml | 8 + tools/recovery_l10n/res/values-hy-rAM/strings.xml | 8 + tools/recovery_l10n/res/values-in/strings.xml | 8 + tools/recovery_l10n/res/values-is-rIS/strings.xml | 8 + tools/recovery_l10n/res/values-it/strings.xml | 8 + tools/recovery_l10n/res/values-iw/strings.xml | 8 + tools/recovery_l10n/res/values-ja/strings.xml | 8 + tools/recovery_l10n/res/values-ka-rGE/strings.xml | 8 + tools/recovery_l10n/res/values-kk-rKZ/strings.xml | 8 + tools/recovery_l10n/res/values-km-rKH/strings.xml | 8 + tools/recovery_l10n/res/values-kn-rIN/strings.xml | 8 + tools/recovery_l10n/res/values-ko/strings.xml | 8 + tools/recovery_l10n/res/values-ky-rKG/strings.xml | 8 + tools/recovery_l10n/res/values-lo-rLA/strings.xml | 8 + tools/recovery_l10n/res/values-lt/strings.xml | 8 + tools/recovery_l10n/res/values-lv/strings.xml | 8 + tools/recovery_l10n/res/values-mk-rMK/strings.xml | 8 + tools/recovery_l10n/res/values-ml-rIN/strings.xml | 8 + tools/recovery_l10n/res/values-mn-rMN/strings.xml | 8 + tools/recovery_l10n/res/values-mr-rIN/strings.xml | 8 + tools/recovery_l10n/res/values-ms-rMY/strings.xml | 8 + tools/recovery_l10n/res/values-my-rMM/strings.xml | 8 + tools/recovery_l10n/res/values-nb/strings.xml | 8 + tools/recovery_l10n/res/values-ne-rNP/strings.xml | 8 + tools/recovery_l10n/res/values-nl/strings.xml | 8 + tools/recovery_l10n/res/values-pa-rIN/strings.xml | 8 + tools/recovery_l10n/res/values-pl/strings.xml | 8 + tools/recovery_l10n/res/values-pt-rBR/strings.xml | 8 + tools/recovery_l10n/res/values-pt-rPT/strings.xml | 8 + tools/recovery_l10n/res/values-pt/strings.xml | 8 + tools/recovery_l10n/res/values-ro/strings.xml | 8 + tools/recovery_l10n/res/values-ru/strings.xml | 8 + tools/recovery_l10n/res/values-si-rLK/strings.xml | 8 + tools/recovery_l10n/res/values-sk/strings.xml | 8 + tools/recovery_l10n/res/values-sl/strings.xml | 8 + tools/recovery_l10n/res/values-sq-rAL/strings.xml | 8 + tools/recovery_l10n/res/values-sr/strings.xml | 8 + tools/recovery_l10n/res/values-sv/strings.xml | 8 + tools/recovery_l10n/res/values-sw/strings.xml | 8 + tools/recovery_l10n/res/values-ta-rIN/strings.xml | 8 + tools/recovery_l10n/res/values-te-rIN/strings.xml | 8 + tools/recovery_l10n/res/values-th/strings.xml | 8 + tools/recovery_l10n/res/values-tl/strings.xml | 8 + tools/recovery_l10n/res/values-tr/strings.xml | 8 + tools/recovery_l10n/res/values-uk/strings.xml | 8 + tools/recovery_l10n/res/values-ur-rPK/strings.xml | 8 + tools/recovery_l10n/res/values-uz-rUZ/strings.xml | 8 + tools/recovery_l10n/res/values-vi/strings.xml | 8 + tools/recovery_l10n/res/values-zh-rCN/strings.xml | 8 + tools/recovery_l10n/res/values-zh-rHK/strings.xml | 8 + tools/recovery_l10n/res/values-zh-rTW/strings.xml | 8 + tools/recovery_l10n/res/values-zu/strings.xml | 8 + tools/recovery_l10n/res/values/strings.xml | 34 +++ .../src/com/android/recovery_l10n/Main.java | 319 +++++++++++++++++++++ 83 files changed, 1038 insertions(+) create mode 100644 tools/recovery_l10n/Android.mk create mode 100644 tools/recovery_l10n/AndroidManifest.xml create mode 100644 tools/recovery_l10n/res/layout/main.xml create mode 100644 tools/recovery_l10n/res/values-af/strings.xml create mode 100644 tools/recovery_l10n/res/values-am/strings.xml create mode 100644 tools/recovery_l10n/res/values-ar/strings.xml create mode 100644 tools/recovery_l10n/res/values-az-rAZ/strings.xml create mode 100644 tools/recovery_l10n/res/values-bg/strings.xml create mode 100644 tools/recovery_l10n/res/values-bn-rBD/strings.xml create mode 100644 tools/recovery_l10n/res/values-ca/strings.xml create mode 100644 tools/recovery_l10n/res/values-cs/strings.xml create mode 100644 tools/recovery_l10n/res/values-da/strings.xml create mode 100644 tools/recovery_l10n/res/values-de/strings.xml create mode 100644 tools/recovery_l10n/res/values-el/strings.xml create mode 100644 tools/recovery_l10n/res/values-en-rAU/strings.xml create mode 100644 tools/recovery_l10n/res/values-en-rGB/strings.xml create mode 100644 tools/recovery_l10n/res/values-en-rIN/strings.xml create mode 100644 tools/recovery_l10n/res/values-es-rUS/strings.xml create mode 100644 tools/recovery_l10n/res/values-es/strings.xml create mode 100644 tools/recovery_l10n/res/values-et-rEE/strings.xml create mode 100644 tools/recovery_l10n/res/values-eu-rES/strings.xml create mode 100644 tools/recovery_l10n/res/values-fa/strings.xml create mode 100644 tools/recovery_l10n/res/values-fi/strings.xml create mode 100644 tools/recovery_l10n/res/values-fr-rCA/strings.xml create mode 100644 tools/recovery_l10n/res/values-fr/strings.xml create mode 100644 tools/recovery_l10n/res/values-gl-rES/strings.xml create mode 100644 tools/recovery_l10n/res/values-gu-rIN/strings.xml create mode 100644 tools/recovery_l10n/res/values-hi/strings.xml create mode 100644 tools/recovery_l10n/res/values-hr/strings.xml create mode 100644 tools/recovery_l10n/res/values-hu/strings.xml create mode 100644 tools/recovery_l10n/res/values-hy-rAM/strings.xml create mode 100644 tools/recovery_l10n/res/values-in/strings.xml create mode 100644 tools/recovery_l10n/res/values-is-rIS/strings.xml create mode 100644 tools/recovery_l10n/res/values-it/strings.xml create mode 100644 tools/recovery_l10n/res/values-iw/strings.xml create mode 100644 tools/recovery_l10n/res/values-ja/strings.xml create mode 100644 tools/recovery_l10n/res/values-ka-rGE/strings.xml create mode 100644 tools/recovery_l10n/res/values-kk-rKZ/strings.xml create mode 100644 tools/recovery_l10n/res/values-km-rKH/strings.xml create mode 100644 tools/recovery_l10n/res/values-kn-rIN/strings.xml create mode 100644 tools/recovery_l10n/res/values-ko/strings.xml create mode 100644 tools/recovery_l10n/res/values-ky-rKG/strings.xml create mode 100644 tools/recovery_l10n/res/values-lo-rLA/strings.xml create mode 100644 tools/recovery_l10n/res/values-lt/strings.xml create mode 100644 tools/recovery_l10n/res/values-lv/strings.xml create mode 100644 tools/recovery_l10n/res/values-mk-rMK/strings.xml create mode 100644 tools/recovery_l10n/res/values-ml-rIN/strings.xml create mode 100644 tools/recovery_l10n/res/values-mn-rMN/strings.xml create mode 100644 tools/recovery_l10n/res/values-mr-rIN/strings.xml create mode 100644 tools/recovery_l10n/res/values-ms-rMY/strings.xml create mode 100644 tools/recovery_l10n/res/values-my-rMM/strings.xml create mode 100644 tools/recovery_l10n/res/values-nb/strings.xml create mode 100644 tools/recovery_l10n/res/values-ne-rNP/strings.xml create mode 100644 tools/recovery_l10n/res/values-nl/strings.xml create mode 100644 tools/recovery_l10n/res/values-pa-rIN/strings.xml create mode 100644 tools/recovery_l10n/res/values-pl/strings.xml create mode 100644 tools/recovery_l10n/res/values-pt-rBR/strings.xml create mode 100644 tools/recovery_l10n/res/values-pt-rPT/strings.xml create mode 100644 tools/recovery_l10n/res/values-pt/strings.xml create mode 100644 tools/recovery_l10n/res/values-ro/strings.xml create mode 100644 tools/recovery_l10n/res/values-ru/strings.xml create mode 100644 tools/recovery_l10n/res/values-si-rLK/strings.xml create mode 100644 tools/recovery_l10n/res/values-sk/strings.xml create mode 100644 tools/recovery_l10n/res/values-sl/strings.xml create mode 100644 tools/recovery_l10n/res/values-sq-rAL/strings.xml create mode 100644 tools/recovery_l10n/res/values-sr/strings.xml create mode 100644 tools/recovery_l10n/res/values-sv/strings.xml create mode 100644 tools/recovery_l10n/res/values-sw/strings.xml create mode 100644 tools/recovery_l10n/res/values-ta-rIN/strings.xml create mode 100644 tools/recovery_l10n/res/values-te-rIN/strings.xml create mode 100644 tools/recovery_l10n/res/values-th/strings.xml create mode 100644 tools/recovery_l10n/res/values-tl/strings.xml create mode 100644 tools/recovery_l10n/res/values-tr/strings.xml create mode 100644 tools/recovery_l10n/res/values-uk/strings.xml create mode 100644 tools/recovery_l10n/res/values-ur-rPK/strings.xml create mode 100644 tools/recovery_l10n/res/values-uz-rUZ/strings.xml create mode 100644 tools/recovery_l10n/res/values-vi/strings.xml create mode 100644 tools/recovery_l10n/res/values-zh-rCN/strings.xml create mode 100644 tools/recovery_l10n/res/values-zh-rHK/strings.xml create mode 100644 tools/recovery_l10n/res/values-zh-rTW/strings.xml create mode 100644 tools/recovery_l10n/res/values-zu/strings.xml create mode 100644 tools/recovery_l10n/res/values/strings.xml create mode 100644 tools/recovery_l10n/src/com/android/recovery_l10n/Main.java diff --git a/tools/recovery_l10n/Android.mk b/tools/recovery_l10n/Android.mk new file mode 100644 index 000000000..937abd1e1 --- /dev/null +++ b/tools/recovery_l10n/Android.mk @@ -0,0 +1,12 @@ +# Copyright 2012 Google Inc. All Rights Reserved. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_PACKAGE_NAME := RecoveryLocalizer +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +include $(BUILD_PACKAGE) diff --git a/tools/recovery_l10n/AndroidManifest.xml b/tools/recovery_l10n/AndroidManifest.xml new file mode 100644 index 000000000..8c51a4e08 --- /dev/null +++ b/tools/recovery_l10n/AndroidManifest.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/tools/recovery_l10n/res/layout/main.xml b/tools/recovery_l10n/res/layout/main.xml new file mode 100644 index 000000000..0900b1102 --- /dev/null +++ b/tools/recovery_l10n/res/layout/main.xml @@ -0,0 +1,31 @@ + + + + + +