resolve merge conflicts of e5d3d15cd2 to nyc-dev
am: 0d28ba452f

* commit '0d28ba452fb8884f3dfeb20fab193be5343ec29e':
  Fix integer overflows in recovery procedure.
diff --git a/Android.mk b/Android.mk
index 4da34ee..4477fef 100644
--- a/Android.mk
+++ b/Android.mk
@@ -64,6 +64,7 @@
     system/core/adb \
 
 LOCAL_STATIC_LIBRARIES := \
+    libbatterymonitor \
     libext4_utils_static \
     libsparse_static \
     libminzip \
@@ -77,11 +78,14 @@
     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/applypatch/Android.mk b/applypatch/Android.mk
index 887a570..90a86dc 100644
--- a/applypatch/Android.mk
+++ b/applypatch/Android.mk
@@ -55,9 +55,7 @@
 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 libotafault libmtdutils libcrypto_static libbz libedify
 LOCAL_SHARED_LIBRARIES += libz libcutils libc
 
 include $(BUILD_EXECUTABLE)
diff --git a/applypatch/Makefile b/applypatch/Makefile
new file mode 100644
index 0000000..fa6298d
--- /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.cpp b/applypatch/applypatch.cpp
index 9f5e2f2..6445159 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);
@@ -56,8 +56,6 @@
 //
 // 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 @@
         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 @@
     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 @@
             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 @@
 
         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 @@
             found = true;
             break;
         }
-
-        p += read;
     }
 
     switch (type) {
@@ -264,13 +248,13 @@
     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 @@
         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 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 @@
         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 @@
 
         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 @@
 
     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 @@
             // 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 @@
     }
 
     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 @@
         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 @@
     }
 
     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 @@
         // 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 @@
             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 @@
 
             // 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 @@
                     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 @@
         } 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 @@
 
         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 14fb490..9ee39d2 100644
--- a/applypatch/applypatch.h
+++ b/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/bsdiff.cpp b/applypatch/bsdiff.cpp
index 55dbe5c..cca1b32 100644
--- a/applypatch/bsdiff.cpp
+++ b/applypatch/bsdiff.cpp
@@ -224,7 +224,6 @@
 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 ebb55f1..1fc1455 100644
--- a/applypatch/bspatch.cpp
+++ b/applypatch/bspatch.cpp
@@ -182,7 +182,6 @@
 
     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 f22502e..2aa4a68 100644
--- a/applypatch/imgdiff.cpp
+++ b/applypatch/imgdiff.cpp
@@ -407,7 +407,6 @@
   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 @@
         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 @@
     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 @@
   }
 
   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 8824038..0ab995b 100644
--- a/applypatch/imgpatch.cpp
+++ b/applypatch/imgpatch.cpp
@@ -130,6 +130,7 @@
             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 @@
                                     &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/libimgpatch.pc b/applypatch/libimgpatch.pc
new file mode 100644
index 0000000..e500293
--- /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 7606d5d..9013760 100644
--- a/applypatch/main.cpp
+++ b/applypatch/main.cpp
@@ -46,40 +46,32 @@
     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 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 @@
 
     // 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 c0d0077..33c1f54 100644
--- a/install.cpp
+++ b/install.cpp
@@ -124,20 +124,20 @@
     //   - 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);
     }
diff --git a/install.h b/install.h
index 680499d..f92f061 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/minadbd/services.cpp b/minadbd/services.cpp
index d25648f..658a43f 100644
--- a/minadbd/services.cpp
+++ b/minadbd/services.cpp
@@ -35,11 +35,10 @@
     void *cookie;
 };
 
-void* service_bootstrap_func(void* x) {
+void service_bootstrap_func(void* x) {
     stinfo* sti = reinterpret_cast<stinfo*>(x);
     sti->func(sti->fd, sti->cookie);
     free(sti);
-    return 0;
 }
 
 static void sideload_host_service(int sfd, void* data) {
diff --git a/minui/resources.cpp b/minui/resources.cpp
index 63a0dff..8489d60 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 @@
         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 @@
     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 @@
     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 @@
         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 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 @@
         } 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 22eabfb..3d36fd6 100644
--- a/minzip/Android.mk
+++ b/minzip/Android.mk
@@ -4,7 +4,7 @@
 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
similarity index 78%
rename from minzip/DirUtil.c
rename to minzip/DirUtil.cpp
index 97cb2e0..823b6ed 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 @@
         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 @@
     /* 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 @@
         /* 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 @@
             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 @@
             }
 
             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/otafault/Android.mk b/otafault/Android.mk
index 75617a1..7468de6 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 0000000..c87f9a6
--- /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 0000000..4430be3
--- /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 02e80f9..2ce3dfc 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,128 @@
 #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 = "";
+
+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 641a5ae..84187a7 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 a0f7315..6514782 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 ee2fb43..593d094 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -40,6 +40,8 @@
 #include <cutils/android_reboot.h>
 #include <cutils/properties.h>
 
+#include <healthd/BatteryMonitor.h>
+
 #include "adb_install.h"
 #include "bootloader.h"
 #include "common.h"
@@ -87,6 +89,12 @@
 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;
@@ -1080,8 +1088,61 @@
     }
 }
 
-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
@@ -1211,18 +1272,25 @@
     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 (!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);
+                // 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) {
@@ -1271,7 +1339,8 @@
     }
 
     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;
diff --git a/tests/Android.mk b/tests/Android.mk
index 3f3c433..262fb8b 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -43,7 +43,7 @@
     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 c54aa11..d6f1e0b 100644
--- a/tests/component/verifier_test.cpp
+++ b/tests/component/verifier_test.cpp
@@ -138,13 +138,13 @@
     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 @@
     }
     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/updater/blockimg.cpp b/updater/blockimg.cpp
index e9c8ddb..56378d4 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 @@
         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 @@
 
     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 @@
     }
 
     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 @@
         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 @@
         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 @@
         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 a2efc0b..bc4cca9 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 @@
     }
 
     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 @@
     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 @@
     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 @@
 
     // 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 @@
     // 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 @@
         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 @@
     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 0f22e6d..efb4a8c 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 @@
                argv[3], strerror(err));
         return 3;
     }
+    ota_io_init(&za);
 
     const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME);
     if (script_entry == NULL) {