Merge "fs_mgr: Build and use shared libs."
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index 20b26df..7c18267 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -111,5 +111,9 @@
     return base + " " + std::to_string(optional_args_.size()) + " " + optional;
 }
 
+std::string DmTargetAndroidVerity::GetParameterString() const {
+    return keyid_ + " " + block_device_;
+}
+
 }  // namespace dm
 }  // namespace android
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index d5974f4..31863c8 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -128,6 +128,20 @@
     bool valid_;
 };
 
+class DmTargetAndroidVerity final : public DmTarget {
+  public:
+    DmTargetAndroidVerity(uint64_t start, uint64_t length, const std::string& block_device,
+                          const std::string& keyid)
+        : DmTarget(start, length), keyid_(keyid), block_device_(block_device) {}
+
+    std::string name() const override { return "android-verity"; }
+    std::string GetParameterString() const override;
+
+  private:
+    std::string keyid_;
+    std::string block_device_;
+};
+
 // This is the same as DmTargetVerity, but the table may be specified as a raw
 // string. This code exists only for fs_mgr_verity and should be avoided. Use
 // DmTargetVerity for new code instead.
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 5e11c84..45a81af 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -40,6 +40,7 @@
 using DmTarget = ::android::dm::DmTarget;
 using DmTargetLinear = ::android::dm::DmTargetLinear;
 using DmTargetZero = ::android::dm::DmTargetZero;
+using DmTargetAndroidVerity = ::android::dm::DmTargetAndroidVerity;
 using DmTargetTypeInfo = ::android::dm::DmTargetTypeInfo;
 using DmBlockDevice = ::android::dm::DeviceMapper::DmBlockDevice;
 
@@ -96,6 +97,16 @@
             }
             return std::make_unique<DmTargetLinear>(start_sector, num_sectors, block_device,
                                                     physical_sector);
+        } else if (target_type == "android-verity") {
+            if (!HasArgs(2)) {
+                std::cerr << "Expected \"android-verity\" <public-key-id> <block_device>"
+                          << std::endl;
+                return nullptr;
+            }
+            std::string keyid = NextArg();
+            std::string block_device = NextArg();
+            return std::make_unique<DmTargetAndroidVerity>(start_sector, num_sectors, keyid,
+                                                           block_device);
         } else {
             std::cerr << "Unrecognized target type: " << target_type << std::endl;
             return nullptr;
@@ -132,11 +143,11 @@
     while (arg_index < argc && argv[arg_index][0] == '-') {
         if (strcmp(argv[arg_index], "-ro") == 0) {
             table.set_readonly(true);
+            arg_index++;
         } else {
             std::cerr << "Unrecognized option: " << argv[arg_index] << std::endl;
             return -EINVAL;
         }
-        arg_index++;
     }
 
     // Parse everything else as target information.
diff --git a/gatekeeperd/OWNERS b/gatekeeperd/OWNERS
new file mode 100644
index 0000000..9c99c6e
--- /dev/null
+++ b/gatekeeperd/OWNERS
@@ -0,0 +1,2 @@
+swillden@google.com
+jdanis@google.com
diff --git a/init/action_parser.cpp b/init/action_parser.cpp
index 8a4b518..1481162 100644
--- a/init/action_parser.cpp
+++ b/init/action_parser.cpp
@@ -60,7 +60,7 @@
     prop_name.erase(equal_pos);
 
     if (!IsActionableProperty(subcontext, prop_name)) {
-        return Error() << "unexported property tigger found: " << prop_name;
+        return Error() << "unexported property trigger found: " << prop_name;
     }
 
     if (auto [it, inserted] = property_triggers->emplace(prop_name, prop_value); !inserted) {
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h
index 9c68ff2..1314330 100644
--- a/liblog/include/log/log_main.h
+++ b/liblog/include/log/log_main.h
@@ -47,7 +47,8 @@
  * so don't link with __clang_analyzer__ defined.
  */
 #ifdef __clang_analyzer__
-extern void __FAKE_USE_VA_ARGS(...);
+extern void __fake_use_va_args(int, ...);
+#define __FAKE_USE_VA_ARGS(...) __fake_use_va_args(0, ##__VA_ARGS__)
 #else
 #define __FAKE_USE_VA_ARGS(...) ((void)(0))
 #endif
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index b0bc497..c38279d 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -2,6 +2,7 @@
     srcs: ["processgroup.cpp"],
     name: "libprocessgroup",
     host_supported: true,
+    recovery_available: true,
     shared_libs: ["libbase"],
     export_include_dirs: ["include"],
     cflags: [
diff --git a/libprocinfo/include/procinfo/process.h b/libprocinfo/include/procinfo/process.h
index db56fc1..9278e18 100644
--- a/libprocinfo/include/procinfo/process.h
+++ b/libprocinfo/include/procinfo/process.h
@@ -56,23 +56,25 @@
 };
 
 // Parse the contents of /proc/<tid>/status into |process_info|.
-bool GetProcessInfo(pid_t tid, ProcessInfo* process_info);
+bool GetProcessInfo(pid_t tid, ProcessInfo* process_info, std::string* error = nullptr);
 
 // Parse the contents of <fd>/status into |process_info|.
 // |fd| should be an fd pointing at a /proc/<pid> directory.
-bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info);
+bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info, std::string* error = nullptr);
 
 // Fetch the list of threads from a given process's /proc/<pid> directory.
 // |fd| should be an fd pointing at a /proc/<pid> directory.
 template <typename Collection>
-auto GetProcessTidsFromProcPidFd(int fd, Collection* out) ->
+auto GetProcessTidsFromProcPidFd(int fd, Collection* out, std::string* error = nullptr) ->
     typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
   out->clear();
 
   int task_fd = openat(fd, "task", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
   std::unique_ptr<DIR, int (*)(DIR*)> dir(fdopendir(task_fd), closedir);
   if (!dir) {
-    PLOG(ERROR) << "failed to open task directory";
+    if (error != nullptr) {
+      *error = "failed to open task directory";
+    }
     return false;
   }
 
@@ -81,7 +83,9 @@
     if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0) {
       pid_t tid;
       if (!android::base::ParseInt(dent->d_name, &tid, 1, std::numeric_limits<pid_t>::max())) {
-        LOG(ERROR) << "failed to parse task id: " << dent->d_name;
+        if (error != nullptr) {
+          *error = std::string("failed to parse task id: ") + dent->d_name;
+        }
         return false;
       }
 
@@ -93,21 +97,25 @@
 }
 
 template <typename Collection>
-auto GetProcessTids(pid_t pid, Collection* out) ->
+auto GetProcessTids(pid_t pid, Collection* out, std::string* error = nullptr) ->
     typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
   char task_path[PATH_MAX];
   if (snprintf(task_path, PATH_MAX, "/proc/%d", pid) >= PATH_MAX) {
-    LOG(ERROR) << "task path overflow (pid = " << pid << ")";
+    if (error != nullptr) {
+      *error = "task path overflow (pid = " + std::to_string(pid) + ")";
+    }
     return false;
   }
 
   android::base::unique_fd fd(open(task_path, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
   if (fd == -1) {
-    PLOG(ERROR) << "failed to open " << task_path;
+    if (error != nullptr) {
+      *error = std::string("failed to open ") + task_path;
+    }
     return false;
   }
 
-  return GetProcessTidsFromProcPidFd(fd.get(), out);
+  return GetProcessTidsFromProcPidFd(fd.get(), out, error);
 }
 
 #endif
diff --git a/libprocinfo/process.cpp b/libprocinfo/process.cpp
index 6e5be6e..9194cf3 100644
--- a/libprocinfo/process.cpp
+++ b/libprocinfo/process.cpp
@@ -31,17 +31,19 @@
 namespace android {
 namespace procinfo {
 
-bool GetProcessInfo(pid_t tid, ProcessInfo* process_info) {
+bool GetProcessInfo(pid_t tid, ProcessInfo* process_info, std::string* error) {
   char path[PATH_MAX];
   snprintf(path, sizeof(path), "/proc/%d", tid);
 
   unique_fd dirfd(open(path, O_DIRECTORY | O_RDONLY));
   if (dirfd == -1) {
-    PLOG(ERROR) << "failed to open " << path;
+    if (error != nullptr) {
+      *error = std::string("failed to open ") + path;
+    }
     return false;
   }
 
-  return GetProcessInfoFromProcPidFd(dirfd.get(), process_info);
+  return GetProcessInfoFromProcPidFd(dirfd.get(), process_info, error);
 }
 
 static ProcessState parse_state(const char* state) {
@@ -62,17 +64,21 @@
   }
 }
 
-bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info) {
+bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info, std::string* error) {
   int status_fd = openat(fd, "status", O_RDONLY | O_CLOEXEC);
 
   if (status_fd == -1) {
-    PLOG(ERROR) << "failed to open status fd in GetProcessInfoFromProcPidFd";
+    if (error != nullptr) {
+      *error = "failed to open status fd in GetProcessInfoFromProcPidFd";
+    }
     return false;
   }
 
   std::unique_ptr<FILE, decltype(&fclose)> fp(fdopen(status_fd, "r"), fclose);
   if (!fp) {
-    PLOG(ERROR) << "failed to open status file in GetProcessInfoFromProcPidFd";
+    if (error != nullptr) {
+      *error = "failed to open status file in GetProcessInfoFromProcPidFd";
+    }
     close(status_fd);
     return false;
   }
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index 3d5fb0c..5865786 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -210,6 +210,37 @@
 		int (*write)(void *priv, const void *data, size_t len), void *priv);
 
 /**
+ * sparse_file_callback_typed - call a callback for blocks based on type
+ *
+ * @s - sparse file cookie
+ * @sparse - write in the Android sparse file format
+ * @data_write - function to call for data blocks. must not be null
+ * @fd_write - function to call for fd blocks
+ * @fill_write - function to call for fill blocks
+ * @skip_write - function to call for skip blocks
+ * @priv - value that will be passed as the first argument to each write
+ *
+ * Writes a sparse file by calling callback functions.  If sparse is true, the
+ * file will be written in the Android sparse file format, and fill and skip blocks
+ * along with metadata will be written with data_write. If sparse is false, the file
+ * will be expanded into normal format and fill and skip blocks will be written with
+ * the given callbacks.
+ * If a callback function is provided, the library will not unroll data into a buffer,
+ * and will instead pass it directly to the caller for custom implementation. If a
+ * callback is not provided, that type of block will be converted into a void* and
+ * written with data_write. If no callbacks other than data are provided, the behavior
+ * is the same as sparse_file_callback(). The callback should return negative on error,
+ * 0 on success.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int sparse_file_callback_typed(struct sparse_file* s, bool sparse,
+                               int (*data_write)(void* priv, const void* data, size_t len),
+                               int (*fd_write)(void* priv, int fd, size_t len),
+                               int (*fill_write)(void* priv, uint32_t fill_val, size_t len),
+                               int (*skip_write)(void* priv, int64_t len), void* priv);
+
+/**
  * sparse_file_foreach_chunk - call a callback for data blocks in sparse file
  *
  * @s - sparse file cookie
diff --git a/libsparse/output_file.cpp b/libsparse/output_file.cpp
index fe314b3..8a21dab 100644
--- a/libsparse/output_file.cpp
+++ b/libsparse/output_file.cpp
@@ -29,6 +29,8 @@
 #include <unistd.h>
 #include <zlib.h>
 
+#include <algorithm>
+
 #include "defs.h"
 #include "output_file.h"
 #include "sparse_crc32.h"
@@ -48,13 +50,6 @@
 #define off64_t off_t
 #endif
 
-#define min(a, b)        \
-  ({                     \
-    typeof(a) _a = (a);  \
-    typeof(b) _b = (b);  \
-    (_a < _b) ? _a : _b; \
-  })
-
 #define SPARSE_HEADER_MAJOR_VER 1
 #define SPARSE_HEADER_MINOR_VER 0
 #define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
@@ -67,11 +62,14 @@
   int (*skip)(struct output_file*, int64_t);
   int (*pad)(struct output_file*, int64_t);
   int (*write)(struct output_file*, void*, size_t);
+  int (*write_fd)(struct output_file*, int, size_t);
+  int (*write_fill)(struct output_file*, uint32_t, size_t);
   void (*close)(struct output_file*);
 };
 
 struct sparse_file_ops {
   int (*write_data_chunk)(struct output_file* out, unsigned int len, void* data);
+  int (*write_fd_chunk)(struct output_file* out, unsigned int len, int fd);
   int (*write_fill_chunk)(struct output_file* out, unsigned int len, uint32_t fill_val);
   int (*write_skip_chunk)(struct output_file* out, int64_t len);
   int (*write_end_chunk)(struct output_file* out);
@@ -108,11 +106,96 @@
 struct output_file_callback {
   struct output_file out;
   void* priv;
-  int (*write)(void* priv, const void* buf, size_t len);
+  int (*data_write)(void* priv, const void* data, size_t len);
+  int (*fd_write)(void* priv, int fd, size_t len);
+  int (*fill_write)(void* priv, uint32_t fill_val, size_t len);
+  int (*skip_write)(void* priv, off64_t len);
 };
 
 #define to_output_file_callback(_o) container_of((_o), struct output_file_callback, out)
 
+union handle_data {
+  void* data_ptr;
+  int fd;
+};
+
+static int default_file_write_fd(struct output_file* out, int fd, size_t len) {
+  int ret;
+  int64_t aligned_offset;
+  int aligned_diff;
+  uint64_t buffer_size;
+  char* ptr;
+  int64_t offset = lseek64(fd, 0, SEEK_CUR);
+
+  if (offset < 0) {
+    return -errno;
+  }
+
+  aligned_offset = offset & ~(4096 - 1);
+  aligned_diff = offset - aligned_offset;
+  buffer_size = (uint64_t)len + (uint64_t)aligned_diff;
+
+#ifndef _WIN32
+  if (buffer_size > SIZE_MAX) {
+    return -E2BIG;
+  }
+  char* data =
+      reinterpret_cast<char*>(mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd, aligned_offset));
+  if (data == MAP_FAILED) {
+    return -errno;
+  }
+  ptr = data + aligned_diff;
+#else
+  char* data = reinterpret_cast<char*>(malloc(len));
+  if (!data) {
+    return -errno;
+  }
+  ret = read_all(fd, data, len);
+  if (ret < 0) {
+    free(data);
+    return -errno;
+  }
+  ptr = data;
+#endif
+
+  ret = out->ops->write(out, ptr, len);
+
+  if (out->use_crc) {
+    out->crc32 = sparse_crc32(out->crc32, ptr, len);
+  }
+
+#ifndef _WIN32
+  munmap(data, buffer_size);
+#else
+  free(data);
+#endif
+
+  return ret;
+}
+
+static int default_file_write_fill(struct output_file* out, uint32_t fill_val, size_t len) {
+  int ret;
+  unsigned int i;
+  unsigned int write_len;
+
+  /* Initialize fill_buf with the fill_val */
+  for (i = 0; i < out->block_size / sizeof(uint32_t); i++) {
+    out->fill_buf[i] = fill_val;
+  }
+
+  while (len) {
+    write_len = std::min(len, static_cast<size_t>(out->block_size));
+    ret = out->ops->write(out, out->fill_buf, write_len);
+    if (ret < 0) {
+      return ret;
+    }
+
+    len -= write_len;
+  }
+
+  return 0;
+}
+
 static int file_open(struct output_file* out, int fd) {
   struct output_file_normal* outn = to_output_file_normal(out);
 
@@ -176,6 +259,8 @@
     .skip = file_skip,
     .pad = file_pad,
     .write = file_write,
+    .write_fd = default_file_write_fd,
+    .write_fill = default_file_write_fill,
     .close = file_close,
 };
 
@@ -231,7 +316,7 @@
   struct output_file_gz* outgz = to_output_file_gz(out);
 
   while (len > 0) {
-    ret = gzwrite(outgz->gz_fd, data, min(len, (unsigned int)INT_MAX));
+    ret = gzwrite(outgz->gz_fd, data, std::min(len, static_cast<size_t>(INT_MAX)));
     if (ret == 0) {
       error("gzwrite %s", gzerror(outgz->gz_fd, nullptr));
       return -1;
@@ -255,6 +340,8 @@
     .skip = gz_file_skip,
     .pad = gz_file_pad,
     .write = gz_file_write,
+    .write_fd = default_file_write_fd,
+    .write_fill = default_file_write_fill,
     .close = gz_file_close,
 };
 
@@ -267,9 +354,13 @@
   int to_write;
   int ret;
 
+  if (outc->skip_write) {
+    return outc->skip_write(outc->priv, off);
+  }
+
   while (off > 0) {
-    to_write = min(off, (int64_t)INT_MAX);
-    ret = outc->write(outc->priv, nullptr, to_write);
+    to_write = std::min(off, static_cast<int64_t>(INT_MAX));
+    ret = outc->data_write(outc->priv, nullptr, to_write);
     if (ret < 0) {
       return ret;
     }
@@ -285,8 +376,23 @@
 
 static int callback_file_write(struct output_file* out, void* data, size_t len) {
   struct output_file_callback* outc = to_output_file_callback(out);
+  return outc->data_write(outc->priv, data, len);
+}
 
-  return outc->write(outc->priv, data, len);
+static int callback_file_write_fd(struct output_file* out, int fd, size_t len) {
+  struct output_file_callback* outc = to_output_file_callback(out);
+  if (outc->fd_write) {
+    return outc->fd_write(outc->priv, fd, len);
+  }
+  return default_file_write_fd(out, fd, len);
+}
+
+static int callback_file_write_fill(struct output_file* out, uint32_t fill_val, size_t len) {
+  struct output_file_callback* outc = to_output_file_callback(out);
+  if (outc->fill_write) {
+    return outc->fill_write(outc->priv, fill_val, len);
+  }
+  return default_file_write_fill(out, fill_val, len);
 }
 
 static void callback_file_close(struct output_file* out) {
@@ -300,6 +406,8 @@
     .skip = callback_file_skip,
     .pad = callback_file_pad,
     .write = callback_file_write,
+    .write_fd = callback_file_write_fd,
+    .write_fill = callback_file_write_fill,
     .close = callback_file_close,
 };
 
@@ -376,7 +484,8 @@
   return 0;
 }
 
-static int write_sparse_data_chunk(struct output_file* out, unsigned int len, void* data) {
+static int write_sparse_data_chunk_variant(struct output_file* out, unsigned int len,
+                                           handle_data data, bool is_fd) {
   chunk_header_t chunk_header;
   int rnd_up_len, zero_len;
   int ret;
@@ -393,7 +502,16 @@
   ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
 
   if (ret < 0) return -1;
-  ret = out->ops->write(out, data, len);
+
+  if (is_fd) {
+    // CRC is handled by write_fd
+    ret = out->ops->write_fd(out, data.fd, len);
+  } else {
+    ret = out->ops->write(out, data.data_ptr, len);
+    if (out->use_crc) {
+      out->crc32 = sparse_crc32(out->crc32, data.data_ptr, len);
+    }
+  }
   if (ret < 0) return -1;
   if (zero_len) {
     ret = out->ops->write(out, out->zero_buf, zero_len);
@@ -401,7 +519,6 @@
   }
 
   if (out->use_crc) {
-    out->crc32 = sparse_crc32(out->crc32, data, len);
     if (zero_len) out->crc32 = sparse_crc32(out->crc32, out->zero_buf, zero_len);
   }
 
@@ -411,6 +528,16 @@
   return 0;
 }
 
+static int write_sparse_data_chunk(struct output_file* out, unsigned int len, void* data_ptr) {
+  handle_data data = {data_ptr};
+  return write_sparse_data_chunk_variant(out, len, data, false /* isFd */);
+}
+
+static int write_sparse_fd_chunk(struct output_file* out, unsigned int len, int fd) {
+  handle_data data = {.fd = fd};
+  return write_sparse_data_chunk_variant(out, len, data, true /* isFd */);
+}
+
 int write_sparse_end_chunk(struct output_file* out) {
   chunk_header_t chunk_header;
   int ret;
@@ -438,16 +565,22 @@
 
 static struct sparse_file_ops sparse_file_ops = {
     .write_data_chunk = write_sparse_data_chunk,
+    .write_fd_chunk = write_sparse_fd_chunk,
     .write_fill_chunk = write_sparse_fill_chunk,
     .write_skip_chunk = write_sparse_skip_chunk,
     .write_end_chunk = write_sparse_end_chunk,
 };
 
-static int write_normal_data_chunk(struct output_file* out, unsigned int len, void* data) {
+static int write_normal_data_chunk_variant(struct output_file* out, unsigned int len,
+                                           handle_data data, bool isFd) {
   int ret;
   unsigned int rnd_up_len = ALIGN(len, out->block_size);
 
-  ret = out->ops->write(out, data, len);
+  if (isFd) {
+    ret = out->ops->write_fd(out, data.fd, len);
+  } else {
+    ret = out->ops->write(out, data.data_ptr, len);
+  }
   if (ret < 0) {
     return ret;
   }
@@ -459,27 +592,18 @@
   return ret;
 }
 
+static int write_normal_data_chunk(struct output_file* out, unsigned int len, void* data_ptr) {
+  handle_data data = {data_ptr};
+  return write_normal_data_chunk_variant(out, len, data, false /* isFd */);
+}
+
+static int write_normal_fd_chunk(struct output_file* out, unsigned int len, int fd) {
+  handle_data data = {.fd = fd};
+  return write_normal_data_chunk_variant(out, len, data, true /* isFd */);
+}
+
 static int write_normal_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
-  int ret;
-  unsigned int i;
-  unsigned int write_len;
-
-  /* Initialize fill_buf with the fill_val */
-  for (i = 0; i < out->block_size / sizeof(uint32_t); i++) {
-    out->fill_buf[i] = fill_val;
-  }
-
-  while (len) {
-    write_len = min(len, out->block_size);
-    ret = out->ops->write(out, out->fill_buf, write_len);
-    if (ret < 0) {
-      return ret;
-    }
-
-    len -= write_len;
-  }
-
-  return 0;
+  return out->ops->write_fill(out, fill_val, len);
 }
 
 static int write_normal_skip_chunk(struct output_file* out, int64_t len) {
@@ -492,6 +616,7 @@
 
 static struct sparse_file_ops normal_file_ops = {
     .write_data_chunk = write_normal_data_chunk,
+    .write_fd_chunk = write_normal_fd_chunk,
     .write_fill_chunk = write_normal_fill_chunk,
     .write_skip_chunk = write_normal_skip_chunk,
     .write_end_chunk = write_normal_end_chunk,
@@ -589,12 +714,20 @@
   return &outn->out;
 }
 
-struct output_file* output_file_open_callback(int (*write)(void*, const void*, size_t), void* priv,
-                                              unsigned int block_size, int64_t len, int gz __unused,
-                                              int sparse, int chunks, int crc) {
+struct output_file* output_file_open_callback(int (*data_write)(void*, const void*, size_t),
+                                              int (*fd_write)(void*, int, size_t),
+                                              int (*fill_write)(void*, uint32_t, size_t),
+                                              int (*skip_write)(void*, off64_t), void* priv,
+                                              unsigned int block_size, int64_t len, int sparse,
+                                              int chunks, int crc) {
   int ret;
   struct output_file_callback* outc;
 
+  if (!data_write || (crc && (fd_write || fill_write))) {
+    errno = EINVAL;
+    return nullptr;
+  }
+
   outc =
       reinterpret_cast<struct output_file_callback*>(calloc(1, sizeof(struct output_file_callback)));
   if (!outc) {
@@ -604,7 +737,10 @@
 
   outc->out.ops = &callback_file_ops;
   outc->priv = priv;
-  outc->write = write;
+  outc->data_write = data_write;
+  outc->fd_write = fd_write;
+  outc->fill_write = fill_write;
+  outc->skip_write = skip_write;
 
   ret = output_file_init(&outc->out, block_size, len, sparse, chunks, crc);
   if (ret < 0) {
@@ -651,52 +787,8 @@
 }
 
 int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset) {
-  int ret;
-  int64_t aligned_offset;
-  int aligned_diff;
-  uint64_t buffer_size;
-  char* ptr;
-
-  aligned_offset = offset & ~(4096 - 1);
-  aligned_diff = offset - aligned_offset;
-  buffer_size = (uint64_t)len + (uint64_t)aligned_diff;
-
-#ifndef _WIN32
-  if (buffer_size > SIZE_MAX) return -E2BIG;
-  char* data =
-      reinterpret_cast<char*>(mmap64(nullptr, buffer_size, PROT_READ, MAP_SHARED, fd, aligned_offset));
-  if (data == MAP_FAILED) {
-    return -errno;
-  }
-  ptr = data + aligned_diff;
-#else
-  off64_t pos;
-  char* data = reinterpret_cast<char*>(malloc(len));
-  if (!data) {
-    return -errno;
-  }
-  pos = lseek64(fd, offset, SEEK_SET);
-  if (pos < 0) {
-    free(data);
-    return -errno;
-  }
-  ret = read_all(fd, data, len);
-  if (ret < 0) {
-    free(data);
-    return ret;
-  }
-  ptr = data;
-#endif
-
-  ret = out->sparse_ops->write_data_chunk(out, len, ptr);
-
-#ifndef _WIN32
-  munmap(data, buffer_size);
-#else
-  free(data);
-#endif
-
-  return ret;
+  lseek64(fd, offset, SEEK_SET);
+  return out->sparse_ops->write_fd_chunk(out, len, fd);
 }
 
 /* Write a contiguous region of data blocks from a file */
diff --git a/libsparse/output_file.h b/libsparse/output_file.h
index 278430b..114582e 100644
--- a/libsparse/output_file.h
+++ b/libsparse/output_file.h
@@ -22,14 +22,18 @@
 #endif
 
 #include <sparse/sparse.h>
+#include <sys/types.h>
 
 struct output_file;
 
 struct output_file* output_file_open_fd(int fd, unsigned int block_size, int64_t len, int gz,
                                         int sparse, int chunks, int crc);
-struct output_file* output_file_open_callback(int (*write)(void*, const void*, size_t), void* priv,
-                                              unsigned int block_size, int64_t len, int gz,
-                                              int sparse, int chunks, int crc);
+struct output_file* output_file_open_callback(int (*data_write)(void*, const void*, size_t),
+                                              int (*fd_write)(void*, int, size_t),
+                                              int (*fill_write)(void*, uint32_t, size_t),
+                                              int (*skip_write)(void*, off64_t), void* priv,
+                                              unsigned int block_size, int64_t len, int sparse,
+                                              int chunks, int crc);
 int write_data_chunk(struct output_file* out, unsigned int len, void* data);
 int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val);
 int write_file_chunk(struct output_file* out, unsigned int len, const char* file, int64_t offset);
diff --git a/libsparse/sparse.cpp b/libsparse/sparse.cpp
index cb288c5..f5ca907 100644
--- a/libsparse/sparse.cpp
+++ b/libsparse/sparse.cpp
@@ -160,7 +160,30 @@
   struct output_file* out;
 
   chunks = sparse_count_chunks(s);
-  out = output_file_open_callback(write, priv, s->block_size, s->len, false, sparse, chunks, crc);
+  out = output_file_open_callback(write, nullptr, nullptr, nullptr, priv, s->block_size, s->len,
+                                  sparse, chunks, crc);
+
+  if (!out) return -ENOMEM;
+
+  ret = write_all_blocks(s, out);
+
+  output_file_close(out);
+
+  return ret;
+}
+
+int sparse_file_callback_typed(struct sparse_file* s, bool sparse,
+                               int (*data_write)(void* priv, const void* data, size_t len),
+                               int (*fd_write)(void* priv, int fd, size_t len),
+                               int (*fill_write)(void* priv, uint32_t fill_val, size_t len),
+                               int (*skip_write)(void* priv, int64_t len), void* priv) {
+  int ret;
+  int chunks;
+  struct output_file* out;
+
+  chunks = sparse_count_chunks(s);
+  out = output_file_open_callback(data_write, fd_write, fill_write, skip_write, priv, s->block_size,
+                                  s->len, sparse, chunks, false);
 
   if (!out) return -ENOMEM;
 
@@ -198,8 +221,8 @@
   chk.write = write;
   chk.block = chk.nr_blocks = 0;
   chunks = sparse_count_chunks(s);
-  out = output_file_open_callback(foreach_chunk_write, &chk, s->block_size, s->len, false, sparse,
-                                  chunks, crc);
+  out = output_file_open_callback(foreach_chunk_write, nullptr, nullptr, nullptr, &chk,
+                                  s->block_size, s->len, sparse, chunks, crc);
 
   if (!out) return -ENOMEM;
 
@@ -227,8 +250,8 @@
   int64_t count = 0;
   struct output_file* out;
 
-  out = output_file_open_callback(out_counter_write, &count, s->block_size, s->len, false, sparse,
-                                  chunks, crc);
+  out = output_file_open_callback(out_counter_write, nullptr, nullptr, nullptr, &count,
+                                  s->block_size, s->len, sparse, chunks, crc);
   if (!out) {
     return -1;
   }
@@ -267,8 +290,8 @@
   len -= overhead;
 
   start = backed_block_iter_new(from->backed_block_list);
-  out_counter = output_file_open_callback(out_counter_write, &count, to->block_size, to->len, false,
-                                          true, 0, false);
+  out_counter = output_file_open_callback(out_counter_write, nullptr, nullptr, nullptr, &count,
+                                          to->block_size, to->len, true, 0, false);
   if (!out_counter) {
     return nullptr;
   }
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index 87e2684..835e226 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -42,7 +42,7 @@
 
 FrameworkListener::FrameworkListener(int sock) :
                             SocketListener(sock, true) {
-    init(NULL, false);
+    init(nullptr, false);
 }
 
 void FrameworkListener::init(const char *socketName UNUSED, bool withSeq) {
@@ -154,7 +154,7 @@
             if (!haveCmdNum) {
                 char *endptr;
                 int cmdNum = (int)strtol(tmp, &endptr, 0);
-                if (endptr == NULL || *endptr != '\0') {
+                if (endptr == nullptr || *endptr != '\0') {
                     cli->sendMsg(500, "Invalid sequence number", false);
                     goto out;
                 }
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index f0c66ec..24ea7aa 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -45,8 +45,8 @@
 NetlinkEvent::NetlinkEvent() {
     mAction = Action::kUnknown;
     memset(mParams, 0, sizeof(mParams));
-    mPath = NULL;
-    mSubsystem = NULL;
+    mPath = nullptr;
+    mSubsystem = nullptr;
 }
 
 NetlinkEvent::~NetlinkEvent() {
@@ -89,7 +89,7 @@
         NL_EVENT_RTM_NAME(LOCAL_QLOG_NL_EVENT);
         NL_EVENT_RTM_NAME(LOCAL_NFLOG_PACKET);
         default:
-            return NULL;
+            return nullptr;
     }
 #undef NL_EVENT_RTM_NAME
 }
@@ -158,7 +158,7 @@
  */
 bool NetlinkEvent::parseIfAddrMessage(const struct nlmsghdr *nh) {
     struct ifaddrmsg *ifaddr = (struct ifaddrmsg *) NLMSG_DATA(nh);
-    struct ifa_cacheinfo *cacheinfo = NULL;
+    struct ifa_cacheinfo *cacheinfo = nullptr;
     char addrstr[INET6_ADDRSTRLEN] = "";
     char ifname[IFNAMSIZ] = "";
 
@@ -286,7 +286,7 @@
 bool NetlinkEvent::parseNfPacketMessage(struct nlmsghdr *nh) {
     int uid = -1;
     int len = 0;
-    char* raw = NULL;
+    char* raw = nullptr;
 
     struct nlattr* uid_attr = findNlAttr(nh, sizeof(struct genlmsghdr), NFULA_UID);
     if (uid_attr) {
@@ -584,7 +584,7 @@
         (prefixlen == 0 || !memcmp(str, prefix, prefixlen))) {
         return str + prefixlen;
     } else {
-        return NULL;
+        return nullptr;
     }
 }
 
@@ -625,16 +625,16 @@
             first = 0;
         } else {
             const char* a;
-            if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
+            if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != nullptr) {
                 if (!strcmp(a, "add"))
                     mAction = Action::kAdd;
                 else if (!strcmp(a, "remove"))
                     mAction = Action::kRemove;
                 else if (!strcmp(a, "change"))
                     mAction = Action::kChange;
-            } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
+            } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != nullptr) {
                 mSeq = atoi(a);
-            } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
+            } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != nullptr) {
                 mSubsystem = strdup(a);
             } else if (param_idx < NL_PARAMS_MAX) {
                 mParams[param_idx++] = strdup(s);
@@ -656,14 +656,14 @@
 
 const char *NetlinkEvent::findParam(const char *paramName) {
     size_t len = strlen(paramName);
-    for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) {
+    for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != nullptr; ++i) {
         const char *ptr = mParams[i] + len;
         if (!strncmp(mParams[i], paramName, len) && *ptr == '=')
             return ++ptr;
     }
 
     SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName);
-    return NULL;
+    return nullptr;
 }
 
 nlattr* NetlinkEvent::findNlAttr(const nlmsghdr* nh, size_t hdrlen, uint16_t attr) {
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index 971f908..0625db7 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -42,8 +42,8 @@
     mSocket = socket;
     mSocketOwned = owned;
     mUseCmdNum = useCmdNum;
-    pthread_mutex_init(&mWriteMutex, NULL);
-    pthread_mutex_init(&mRefCountMutex, NULL);
+    pthread_mutex_init(&mWriteMutex, nullptr);
+    pthread_mutex_init(&mRefCountMutex, nullptr);
     mPid = -1;
     mUid = -1;
     mGid = -1;
@@ -135,9 +135,9 @@
     const char *end = arg + len;
     char *oldresult;
 
-    if(result == NULL) {
+    if(result == nullptr) {
         SLOGW("malloc error (%s)", strerror(errno));
-        return NULL;
+        return nullptr;
     }
 
     *(current++) = '"';
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 3f8f3db..0c8a688 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -39,7 +39,7 @@
 }
 
 SocketListener::SocketListener(int socketFd, bool listen) {
-    init(NULL, socketFd, listen, false);
+    init(nullptr, socketFd, listen, false);
 }
 
 SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {
@@ -51,7 +51,7 @@
     mSocketName = socketName;
     mSock = socketFd;
     mUseCmdNum = useCmdNum;
-    pthread_mutex_init(&mClientsLock, NULL);
+    pthread_mutex_init(&mClientsLock, nullptr);
     mClients = new SocketClientCollection();
 }
 
@@ -102,7 +102,7 @@
         return -1;
     }
 
-    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
+    if (pthread_create(&mThread, nullptr, SocketListener::threadStart, this)) {
         SLOGE("pthread_create (%s)", strerror(errno));
         return -1;
     }
@@ -147,8 +147,8 @@
     SocketListener *me = reinterpret_cast<SocketListener *>(obj);
 
     me->runListener();
-    pthread_exit(NULL);
-    return NULL;
+    pthread_exit(nullptr);
+    return nullptr;
 }
 
 void SocketListener::runListener() {
@@ -183,7 +183,7 @@
         }
         pthread_mutex_unlock(&mClientsLock);
         SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
-        if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
+        if ((rc = select(max + 1, &read_fds, nullptr, nullptr, nullptr)) < 0) {
             if (errno == EINTR)
                 continue;
             SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 1cfef34..c2487d6 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -332,7 +332,7 @@
         data->fd = -1;
         return -1;
     }
-    ALOG_ASSERT((size_t)size < buf_size - 1, data->filename " too large");
+    ALOG_ASSERT((size_t)size < buf_size - 1, "%s too large", data->filename);
     buf[size] = 0;
 
     return 0;
diff --git a/mkbootimg/Android.bp b/mkbootimg/Android.bp
index b494346..576a677 100644
--- a/mkbootimg/Android.bp
+++ b/mkbootimg/Android.bp
@@ -9,6 +9,7 @@
 cc_library_headers {
     name: "bootimg_headers",
     vendor_available: true,
+    recovery_available: true,
     export_include_dirs: ["include/bootimg"],
     host_supported: true,
     target: {
diff --git a/property_service/libpropertyinfoserializer/Android.bp b/property_service/libpropertyinfoserializer/Android.bp
index 3c4bdc3..51c1226 100644
--- a/property_service/libpropertyinfoserializer/Android.bp
+++ b/property_service/libpropertyinfoserializer/Android.bp
@@ -17,6 +17,7 @@
 cc_library_static {
     name: "libpropertyinfoserializer",
     defaults: ["propertyinfoserializer_defaults"],
+    recovery_available: true,
     srcs: [
         "property_info_file.cpp",
         "property_info_serializer.cpp",
diff --git a/trusty/OWNERS b/trusty/OWNERS
index 357b4f4..e807d71 100644
--- a/trusty/OWNERS
+++ b/trusty/OWNERS
@@ -1,3 +1,7 @@
-bohr@google.com
-swillden@google.com
+arve@google.com
 dkrahn@google.com
+drewry@google.com
+gmar@google.com
+ncbray@google.com
+rpere@google.com
+swillden@google.com
diff --git a/trusty/libtrusty/tipc-test/tipc_test.c b/trusty/libtrusty/tipc-test/tipc_test.c
index 1fb34c9..d20d4ee 100644
--- a/trusty/libtrusty/tipc-test/tipc_test.c
+++ b/trusty/libtrusty/tipc-test/tipc_test.c
@@ -587,8 +587,15 @@
 
 static int ta2ta_ipc_test(void)
 {
+	enum test_message_header {
+		TEST_PASSED = 0,
+		TEST_FAILED = 1,
+		TEST_MESSAGE = 2,
+	};
+
 	int fd;
-	char rx_buf[64];
+	int ret;
+	unsigned char rx_buf[256];
 
 	if (!opt_silent) {
 		printf("%s:\n", __func__);
@@ -601,12 +608,31 @@
 		return fd;
 	}
 
-	/* wait for test to complete */
-	(void) read(fd, rx_buf, sizeof(rx_buf));
+	/* Wait for tests to complete and read status */
+	while (true) {
+		ret = read(fd, rx_buf, sizeof(rx_buf));
+		if (ret <= 0 || ret >= (int)sizeof(rx_buf)) {
+			fprintf(stderr, "%s: Read failed: %d\n", __func__, ret);
+			tipc_close(fd);
+			return -1;
+		}
+
+		if (rx_buf[0] == TEST_PASSED) {
+			break;
+		} else if (rx_buf[0] == TEST_FAILED) {
+			break;
+		} else if (rx_buf[0] == TEST_MESSAGE) {
+			write(STDOUT_FILENO, rx_buf + 1, ret - 1);
+		} else {
+			fprintf(stderr, "%s: Bad message header: %d\n",
+			        __func__, rx_buf[0]);
+			break;
+		}
+	}
 
 	tipc_close(fd);
 
-	return 0;
+	return rx_buf[0] == TEST_PASSED ? 0 : -1;
 }
 
 typedef struct uuid