summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk9
-rw-r--r--applypatch/Android.mk66
-rw-r--r--applypatch/Makefile33
-rw-r--r--applypatch/applypatch.cpp111
-rw-r--r--applypatch/bsdiff.cpp1
-rw-r--r--applypatch/bspatch.cpp3
-rw-r--r--applypatch/freecache.cpp2
-rw-r--r--applypatch/imgdiff.cpp24
-rw-r--r--applypatch/imgpatch.cpp8
-rw-r--r--applypatch/include/applypatch/applypatch.h (renamed from applypatch/applypatch.h)13
-rw-r--r--applypatch/libimgpatch.pc6
-rw-r--r--applypatch/main.cpp69
-rw-r--r--install.cpp16
-rw-r--r--install.h3
-rw-r--r--minui/resources.cpp28
-rw-r--r--minzip/Android.mk2
-rw-r--r--minzip/DirUtil.cpp (renamed from minzip/DirUtil.c)61
-rw-r--r--minzip/Zip.c5
-rw-r--r--otafault/Android.mk50
-rw-r--r--otafault/config.cpp65
-rw-r--r--otafault/config.h74
-rw-r--r--otafault/ota_io.cpp200
-rw-r--r--otafault/ota_io.h4
-rw-r--r--otafault/test.cpp6
-rw-r--r--recovery.cpp47
-rw-r--r--tests/Android.mk2
-rw-r--r--tests/component/verifier_test.cpp17
-rw-r--r--tools/dumpkey/Android.mk22
-rw-r--r--tools/dumpkey/DumpPublicKey.java270
-rw-r--r--tools/dumpkey/DumpPublicKey.mf1
-rw-r--r--updater/Android.mk66
-rw-r--r--updater/blockimg.cpp14
-rw-r--r--updater/install.cpp41
-rw-r--r--updater/updater.cpp9
34 files changed, 926 insertions, 422 deletions
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 887a570db..9e64718c1 100644
--- a/applypatch/Android.mk
+++ b/applypatch/Android.mk
@@ -14,61 +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/Makefile b/applypatch/Makefile
new file mode 100644
index 000000000..de6d4268f
--- /dev/null
+++ b/applypatch/Makefile
@@ -0,0 +1,33 @@
+# 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 utils.o: CXXFLAGS += -fPIC
+libimgpatch.a: imgpatch.o bspatch.o utils.o
+ ${AR} rcs $@ $^
diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp
index 9f5e2f200..c8594c283 100644
--- a/applypatch/applypatch.cpp
+++ b/applypatch/applypatch.cpp
@@ -31,11 +31,11 @@
#include <android-base/strings.h>
#include "openssl/sha.h"
-#include "applypatch.h"
+#include "applypatch/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);
@@ -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<unsigned char, decltype(&free)> data(
- static_cast<unsigned char*>(malloc(file->size)), free);
- if (data == nullptr) {
- printf("failed to allocate memory: %s\n", strerror(errno));
- return -1;
- }
-
+ std::vector<unsigned char> 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<size_t>(file->size)) {
- printf("short read of \"%s\" (%zu bytes of %zd)\n", filename, bytes_read, file->size);
- fclose(f);
+ 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<unsigned char*>(malloc(size[index[pairs-1]]));
- char* p = (char*)file->data;
- file->size = 0; // # bytes read so far
+ std::vector<unsigned char> data(size[index[pairs-1]]);
+ char* p = reinterpret_cast<char*>(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<ssize_t>(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, &copy_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,
- &copy_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,
+ &copy_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<std::string> 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;
}
@@ -936,7 +897,7 @@ static int GenerateTarget(FileContents* source_file,
} else {
// We write the decoded output to "<tgt-file>.patch".
output_fd = ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC,
- S_IRUSR | S_IWUSR);
+ S_IRUSR | S_IWUSR);
if (output_fd < 0) {
printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(),
strerror(errno));
@@ -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/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..a4945da28 100644
--- a/applypatch/bspatch.cpp
+++ b/applypatch/bspatch.cpp
@@ -30,7 +30,7 @@
#include <bzlib.h>
#include "openssl/sha.h"
-#include "applypatch.h"
+#include "applypatch/applypatch.h"
void ShowBSDiffLicense() {
puts("The bsdiff library used herein is:\n"
@@ -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/freecache.cpp b/applypatch/freecache.cpp
index c84f42797..331cae265 100644
--- a/applypatch/freecache.cpp
+++ b/applypatch/freecache.cpp
@@ -32,7 +32,7 @@
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
-#include "applypatch.h"
+#include "applypatch/applypatch.h"
static int EliminateOpenFiles(std::set<std::string>* files) {
std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/proc"), closedir);
diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp
index f22502e38..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<unsigned char*>(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;
@@ -598,7 +596,6 @@ int ReconstructDeflateChunk(ImageChunk* chunk) {
return -1;
}
- size_t p = 0;
unsigned char* out = reinterpret_cast<unsigned char*>(malloc(BUFFER_SIZE));
// We only check two combinations of encoder parameters: level 6
@@ -844,7 +841,6 @@ int main(int argc, char** argv) {
}
if (argc != 4) {
- usage:
printf("usage: %s [-z] [-b <bonus-file>] <src-img> <tgt-img> <patch-file>\n",
argv[0]);
return 2;
diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp
index 8824038ea..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"
@@ -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.
diff --git a/applypatch/applypatch.h b/applypatch/include/applypatch/applypatch.h
index 14fb490ba..9ee39d293 100644
--- a/applypatch/applypatch.h
+++ b/applypatch/include/applypatch/applypatch.h
@@ -17,6 +17,7 @@
#ifndef _APPLYPATCH_H
#define _APPLYPATCH_H
+#include <stdint.h>
#include <sys/stat.h>
#include <vector>
@@ -24,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<unsigned char> 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/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
diff --git a/applypatch/main.cpp b/applypatch/main.cpp
index 7606d5d3c..0ff8cbf9a 100644
--- a/applypatch/main.cpp
+++ b/applypatch/main.cpp
@@ -22,7 +22,7 @@
#include <memory>
#include <vector>
-#include "applypatch.h"
+#include "applypatch/applypatch.h"
#include "edify/expr.h"
#include "openssl/sha.h"
@@ -46,40 +46,32 @@ static int SpaceMode(int argc, char** argv) {
return CacheSizeCheck(bytes);
}
-// Parse arguments (which should be of the form "<sha1>" or
-// "<sha1>:<filename>" 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 "<sha1>:<filename>"
+// into the new parallel arrays *sha1s and *files.Returns true on
// success.
static bool ParsePatchArgs(int argc, char** argv, std::vector<char*>* sha1s,
- std::vector<std::unique_ptr<Value, decltype(&FreeValue)>>* patches) {
+ std::vector<FileContents>* 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, decltype(&FreeValue)> value(new Value, FreeValue);
- value->type = VAL_BLOB;
- value->size = fc.size;
- value->data = reinterpret_cast<char*>(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<Value, decltype(&FreeValue)> 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<char*>(fc.data);
+ bonus->size = bonusFc.data.size();
+ bonus->data = reinterpret_cast<char*>(bonusFc.data.data());
argc -= 2;
argv += 2;
}
@@ -118,28 +112,29 @@ static int PatchMode(int argc, char** argv) {
// If no <src-sha1>:<patch> 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<char*> sha1s;
- std::vector<std::unique_ptr<Value, decltype(&FreeValue)>> patches;
- if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &patches)) {
+ std::vector<FileContents> files;
+ if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &files)) {
printf("failed to parse patch args\n");
return 1;
}
-
- std::vector<Value*> patch_ptrs;
- for (const auto& p : patches) {
- patch_ptrs.push_back(p.get());
+ std::vector<Value> patches(files.size());
+ std::vector<Value*> 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<char*>(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/install.cpp b/install.cpp
index c0d007709..144a353d6 100644
--- a/install.cpp
+++ b/install.cpp
@@ -124,26 +124,27 @@ 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<char**>(args));
fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno));
_exit(-1);
}
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/minui/resources.cpp b/minui/resources.cpp
index 63a0dff28..8489d60ef 100644
--- a/minui/resources.cpp
+++ b/minui/resources.cpp
@@ -28,6 +28,7 @@
#include <linux/fb.h>
#include <linux/kd.h>
+#include <vector>
#include <png.h>
#include "minui.h"
@@ -282,7 +283,7 @@ int res_create_multi_display_surface(const char* name, int* frames, int* fps,
goto exit;
}
- surface = reinterpret_cast<GRSurface**>(malloc(*frames * sizeof(GRSurface*)));
+ surface = reinterpret_cast<GRSurface**>(calloc(*frames, sizeof(GRSurface*)));
if (surface == NULL) {
result = -8;
goto exit;
@@ -317,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);
}
@@ -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<unsigned char> 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<unsigned char*>(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;
+ __unused int len = row[4];
+ char* loc = reinterpret_cast<char*>(&row[5]);
if (y+1+h >= height || matches_locale(loc, locale)) {
printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
@@ -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<GRSurface*>(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.cpp
index 97cb2e0ee..823b6ed2f 100644
--- a/minzip/DirUtil.c
+++ b/minzip/DirUtil.cpp
@@ -24,6 +24,8 @@
#include <dirent.h>
#include <limits.h>
+#include <string>
+
#include "DirUtil.h"
typedef enum { DMISSING, DDIR, DILLEGAL } DirStatus;
@@ -66,43 +68,25 @@ dirCreateHierarchy(const char *path, int mode,
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);
+ // 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.
- */
- 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.
- */
+ // Strip everything after the last slash.
+ size_t pos = cpath.rfind('/');
+ if (pos == std::string::npos) {
errno = ENOENT;
- free(cpath);
return -1;
}
- c[1] = '\0'; // Terminate after the slash we found.
+ cpath.resize(pos + 1);
} else {
- /* Make sure that the path ends in a slash.
- */
- cpath[pathLen] = '/';
- cpath[pathLen + 1] = '\0';
+ // Make sure that the path ends in a slash.
+ cpath.push_back('/');
}
/* See if it already exists.
*/
- ds = getPathDirStatus(cpath);
+ ds = getPathDirStatus(cpath.c_str());
if (ds == DDIR) {
return 0;
} else if (ds == DILLEGAL) {
@@ -112,7 +96,8 @@ dirCreateHierarchy(const char *path, int mode,
/* Walk up the path from the root and make each level.
* If a directory already exists, no big deal.
*/
- char *p = cpath;
+ const char *path_start = &cpath[0];
+ char *p = &cpath[0];
while (*p != '\0') {
/* Skip any slashes, watching out for the end of the string.
*/
@@ -135,12 +120,11 @@ dirCreateHierarchy(const char *path, int mode,
/* Check this part of the path and make a new directory
* if necessary.
*/
- ds = getPathDirStatus(cpath);
+ ds = getPathDirStatus(path_start);
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;
@@ -148,11 +132,11 @@ dirCreateHierarchy(const char *path, int mode,
char *secontext = NULL;
if (sehnd) {
- selabel_lookup(sehnd, &secontext, cpath, mode);
+ selabel_lookup(sehnd, &secontext, path_start, mode);
setfscreatecon(secontext);
}
- err = mkdir(cpath, mode);
+ err = mkdir(path_start, mode);
if (secontext) {
freecon(secontext);
@@ -160,22 +144,17 @@ dirCreateHierarchy(const char *path, int mode,
}
if (err != 0) {
- free(cpath);
return -1;
}
- if (timestamp != NULL && utime(cpath, timestamp)) {
- free(cpath);
+ if (timestamp != NULL && utime(path_start, timestamp)) {
return -1;
}
}
// else, this directory already exists.
-
- /* Repair the path and continue.
- */
+
+ // Repair the path and continue.
*p = '/';
}
- free(cpath);
-
return 0;
}
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;
diff --git a/otafault/Android.mk b/otafault/Android.mk
index 75617a146..52d706722 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,35 @@
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
-
+# otafault (static library)
+# ===============================
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := ota_io.cpp
-LOCAL_MODULE_TAGS := eng
+otafault_static_libs := \
+ libminzip \
+ libselinux \
+ libz
+
+LOCAL_SRC_FILES := config.cpp ota_io.cpp
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_STATIC_LIBRARIES := $(otafault_static_libs)
include $(BUILD_STATIC_LIBRARY)
+# otafault_test (static executable)
+# ===============================
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 := \
+ libotafault \
+ $(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 <map>
+#include <string>
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "minzip/Zip.h"
+#include "config.h"
+#include "ota_io.h"
+
+#define OTAIO_MAX_FNAME_SIZE 128
+
+static ZipArchive* archive;
+static std::map<const char*, bool> 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
+ * <normal package contents>
+ * .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 <string>
+
+#include <stdbool.h>
+
+#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..dd805e56e 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 <map>
-#endif
#include <errno.h>
#include <fcntl.h>
@@ -24,137 +22,155 @@
#include <sys/stat.h>
#include <unistd.h>
+#include "config.h"
#include "ota_io.h"
-#if defined (TARGET_INJECT_FAULTS)
-static std::map<int, const char*> 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<intptr_t, const char*> 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()
+ ? !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;
+ have_eio_error = true;
+ return 0;
+ }
+ }
+ 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;
}
-#else
- return fread(ptr, size, nitems, stream);
-#endif
+ return status;
}
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;
+ have_eio_error = true;
+ return -1;
+ }
}
-#else
- return read(fd, buf, nbyte);
-#endif
+ 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) {
-#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;
+ have_eio_error = true;
+ return 0;
+ }
+ }
+ size_t status = fwrite(ptr, size, count, stream);
+ if (status != count && errno == EIO) {
+ have_eio_error = true;
}
-#else
- return fwrite(ptr, size, count, stream);
-#endif
+ return status;
}
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;
+ have_eio_error = true;
+ return -1;
+ }
}
-#else
- return write(fd, buf, nbyte);
-#endif
+ ssize_t status = write(fd, buf, nbyte);
+ if (status == -1 && errno == EIO) {
+ have_eio_error = true;
+ }
+ return status;
}
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;
+ have_eio_error = true;
+ return -1;
+ }
+ }
+ int status = fsync(fd);
+ if (status == -1 && errno == EIO) {
+ have_eio_error = true;
}
-#else
- return fsync(fd);
-#endif
+ return status;
}
+
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 <stdio.h>
#include <sys/stat.h>
+#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 <errno.h>
#include <fcntl.h>
#include <stdio.h>
+#include <unistd.h>
#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/recovery.cpp b/recovery.cpp
index fe6793da0..7620f1a00 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -36,6 +36,7 @@
#include <adb.h>
#include <android-base/file.h>
+#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <cutils/android_reboot.h>
#include <cutils/properties.h>
@@ -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' },
@@ -89,6 +91,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.
@@ -1162,6 +1165,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
@@ -1197,11 +1223,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;
@@ -1306,7 +1334,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/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 c54aa111f..d6f1e0bb9 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() { }
};
diff --git a/tools/dumpkey/Android.mk b/tools/dumpkey/Android.mk
new file mode 100644
index 000000000..31549146d
--- /dev/null
+++ b/tools/dumpkey/Android.mk
@@ -0,0 +1,22 @@
+# 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_MODULE := dumpkey
+LOCAL_SRC_FILES := DumpPublicKey.java
+LOCAL_JAR_MANIFEST := DumpPublicKey.mf
+LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host
+include $(BUILD_HOST_JAVA_LIBRARY)
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
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)/..
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp
index e9c8ddbc0..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"
@@ -554,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) {
@@ -611,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) {
@@ -635,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) {
@@ -1347,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) {
@@ -1615,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));
@@ -1669,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 a2efc0b97..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"
@@ -996,7 +996,7 @@ 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;
@@ -1005,12 +1005,12 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
if (ota_fread(buffer, 1, st.st_size, f) != static_cast<size_t>(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");
@@ -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<Value*>(malloc(sizeof(Value)));
+ Value* v = static_cast<Value*>(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<char*>(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;
}
@@ -1439,10 +1440,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);
ota_fwrite(buffer, sizeof(((struct bootloader_message*)0)->command), 1, f);
- fclose(f);
+ ota_fclose(f);
free(filename);
strcpy(buffer, "reboot,");
@@ -1481,7 +1482,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);
@@ -1490,7 +1491,7 @@ Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
stagestr[max_size-1] = 0;
}
ota_fwrite(stagestr, to_write, 1, f);
- fclose(f);
+ ota_fclose(f);
free(stagestr);
return StringValue(filename);
@@ -1507,10 +1508,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);
ota_fread(buffer, sizeof(buffer), 1, f);
- fclose(f);
+ ota_fclose(f);
buffer[sizeof(buffer)-1] = '\0';
return StringValue(strdup(buffer));
diff --git a/updater/updater.cpp b/updater/updater.cpp
index 0f22e6d04..1693fa1db 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
@@ -35,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) {
@@ -82,6 +85,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) {
@@ -139,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");