Merge "Revert "Add derived UsbTransport class with USB reset method""
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 9b48702..19300f6 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -924,25 +924,6 @@
 // This returns 1 on success, 0 on failure, and -1 to indicate this is not
 // a forwarding-related request.
 int handle_forward_request(const char* service, atransport* transport, int reply_fd) {
-    if (!strcmp(service, "list-forward")) {
-        // Create the list of forward redirections.
-        std::string listeners = format_listeners();
-#if ADB_HOST
-        SendOkay(reply_fd);
-#endif
-        return SendProtocolString(reply_fd, listeners);
-    }
-
-    if (!strcmp(service, "killforward-all")) {
-        remove_all_listeners();
-#if ADB_HOST
-        /* On the host: 1st OKAY is connect, 2nd OKAY is status */
-        SendOkay(reply_fd);
-#endif
-        SendOkay(reply_fd);
-        return 1;
-    }
-
     if (!strncmp(service, "forward:", 8) || !strncmp(service, "killforward:", 12)) {
         // killforward:local
         // forward:(norebind:)?local;remote
@@ -1205,10 +1186,30 @@
         return SendOkay(reply_fd, response);
     }
 
+    if (!strcmp(service, "list-forward")) {
+        // Create the list of forward redirections.
+        std::string listeners = format_listeners();
+#if ADB_HOST
+        SendOkay(reply_fd);
+#endif
+        return SendProtocolString(reply_fd, listeners);
+    }
+
+    if (!strcmp(service, "killforward-all")) {
+        remove_all_listeners();
+#if ADB_HOST
+        /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+        SendOkay(reply_fd);
+#endif
+        SendOkay(reply_fd);
+        return 1;
+    }
+
     std::string error;
     atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
     if (!t) {
-        return -1;
+        SendFail(reply_fd, error);
+        return 1;
     }
 
     int ret = handle_forward_request(service, t, reply_fd);
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
index dfdc365..1bb2fbb 100644
--- a/adb/daemon/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -178,10 +178,6 @@
     }
 
     unsigned long remount_flags = get_mount_flags(fd, dir);
-    if ((remount_flags & MS_RDONLY) == 0) {
-        // Mount is already writable.
-        return true;
-    }
     remount_flags &= ~MS_RDONLY;
     remount_flags |= MS_REMOUNT;
 
@@ -192,7 +188,7 @@
         WriteFdFmt(fd, "remount of the %s mount failed: %s.\n", dir, strerror(errno));
         return false;
     }
-    if (mount(dev.c_str(), dir, "none", remount_flags, nullptr) == -1) {
+    if (mount(dev.c_str(), dir, "none", MS_REMOUNT, nullptr) == -1) {
         WriteFdFmt(fd, "remount of the %s superblock failed: %s\n", dir, strerror(errno));
         return false;
     }
diff --git a/base/Android.bp b/base/Android.bp
index 3d80d97..46a0233 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -135,6 +135,7 @@
         "strings_test.cpp",
         "test_main.cpp",
         "test_utils_test.cpp",
+        "unique_fd_test.cpp",
     ],
     target: {
         android: {
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
index fc68d56..bb54c99 100644
--- a/base/include/android-base/parseint.h
+++ b/base/include/android-base/parseint.h
@@ -47,7 +47,9 @@
   if (max < result) {
     return false;
   }
-  *out = static_cast<T>(result);
+  if (out != nullptr) {
+    *out = static_cast<T>(result);
+  }
   return true;
 }
 
@@ -87,7 +89,9 @@
   if (result < min || max < result) {
     return false;
   }
-  *out = static_cast<T>(result);
+  if (out != nullptr) {
+    *out = static_cast<T>(result);
+  }
   return true;
 }
 
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index c733081..c6936f1 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -42,10 +42,35 @@
 //
 // unique_fd is also known as ScopedFd/ScopedFD/scoped_fd; mentioned here to help
 // you find this class if you're searching for one of those names.
+
+#if defined(__BIONIC__)
+#include <android/fdsan.h>
+#endif
+
 namespace android {
 namespace base {
 
 struct DefaultCloser {
+#if defined(__BIONIC__)
+  static void Tag(int fd, void* old_addr, void* new_addr) {
+    if (android_fdsan_exchange_owner_tag) {
+      uint64_t old_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
+                                                        reinterpret_cast<uint64_t>(old_addr));
+      uint64_t new_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
+                                                        reinterpret_cast<uint64_t>(new_addr));
+      android_fdsan_exchange_owner_tag(fd, old_tag, new_tag);
+    }
+  }
+  static void Close(int fd, void* addr) {
+    if (android_fdsan_close_with_tag) {
+      uint64_t tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
+                                                    reinterpret_cast<uint64_t>(addr));
+      android_fdsan_close_with_tag(fd, tag);
+    } else {
+      close(fd);
+    }
+  }
+#else
   static void Close(int fd) {
     // Even if close(2) fails with EINTR, the fd will have been closed.
     // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone
@@ -53,40 +78,75 @@
     // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
     ::close(fd);
   }
+#endif
 };
 
 template <typename Closer>
 class unique_fd_impl final {
  public:
-  unique_fd_impl() : value_(-1) {}
+  unique_fd_impl() {}
 
-  explicit unique_fd_impl(int value) : value_(value) {}
+  explicit unique_fd_impl(int fd) { reset(fd); }
   ~unique_fd_impl() { reset(); }
 
-  unique_fd_impl(unique_fd_impl&& other) : value_(other.release()) {}
+  unique_fd_impl(unique_fd_impl&& other) { reset(other.release()); }
   unique_fd_impl& operator=(unique_fd_impl&& s) {
-    reset(s.release());
+    int fd = s.fd_;
+    s.fd_ = -1;
+    reset(fd, &s);
     return *this;
   }
 
-  void reset(int new_value = -1) {
-    if (value_ != -1) {
-      Closer::Close(value_);
-    }
-    value_ = new_value;
-  }
+  void reset(int new_value = -1) { reset(new_value, nullptr); }
 
-  int get() const { return value_; }
+  int get() const { return fd_; }
   operator int() const { return get(); }
 
   int release() __attribute__((warn_unused_result)) {
-    int ret = value_;
-    value_ = -1;
+    tag(fd_, this, nullptr);
+    int ret = fd_;
+    fd_ = -1;
     return ret;
   }
 
  private:
-  int value_;
+  void reset(int new_value, void* previous_tag) {
+    if (fd_ != -1) {
+      close(fd_, this);
+    }
+
+    fd_ = new_value;
+    if (new_value != -1) {
+      tag(new_value, previous_tag, this);
+    }
+  }
+
+  int fd_ = -1;
+
+  // Template magic to use Closer::Tag if available, and do nothing if not.
+  // If Closer::Tag exists, this implementation is preferred, because int is a better match.
+  // If not, this implementation is SFINAEd away, and the no-op below is the only one that exists.
+  template <typename T = Closer>
+  static auto tag(int fd, void* old_tag, void* new_tag)
+      -> decltype(T::Tag(fd, old_tag, new_tag), void()) {
+    T::Tag(fd, old_tag, new_tag);
+  }
+
+  template <typename T = Closer>
+  static void tag(long, void*, void*) {
+    // No-op.
+  }
+
+  // Same as above, to select between Closer::Close(int) and Closer::Close(int, void*).
+  template <typename T = Closer>
+  static auto close(int fd, void* tag_value) -> decltype(T::Close(fd, tag_value), void()) {
+    T::Close(fd, tag_value);
+  }
+
+  template <typename T = Closer>
+  static auto close(int fd, void*) -> decltype(T::Close(fd), void()) {
+    T::Close(fd);
+  }
 
   unique_fd_impl(const unique_fd_impl&);
   void operator=(const unique_fd_impl&);
diff --git a/base/parseint_test.cpp b/base/parseint_test.cpp
index fb1c339..8f9ed77 100644
--- a/base/parseint_test.cpp
+++ b/base/parseint_test.cpp
@@ -36,6 +36,10 @@
   ASSERT_EQ(12, i);
   ASSERT_FALSE(android::base::ParseInt("-12", &i, 0, 15));
   ASSERT_FALSE(android::base::ParseInt("16", &i, 0, 15));
+
+  ASSERT_FALSE(android::base::ParseInt<int>("x", nullptr));
+  ASSERT_FALSE(android::base::ParseInt<int>("123x", nullptr));
+  ASSERT_TRUE(android::base::ParseInt<int>("1234", nullptr));
 }
 
 TEST(parseint, unsigned_smoke) {
@@ -55,6 +59,10 @@
   ASSERT_EQ(12u, i);
   ASSERT_FALSE(android::base::ParseUint("-12", &i, 15u));
   ASSERT_FALSE(android::base::ParseUint("16", &i, 15u));
+
+  ASSERT_FALSE(android::base::ParseUint<unsigned short>("x", nullptr));
+  ASSERT_FALSE(android::base::ParseUint<unsigned short>("123x", nullptr));
+  ASSERT_TRUE(android::base::ParseUint<unsigned short>("1234", nullptr));
 }
 
 TEST(parseint, no_implicit_octal) {
diff --git a/base/unique_fd_test.cpp b/base/unique_fd_test.cpp
new file mode 100644
index 0000000..3fdf12a
--- /dev/null
+++ b/base/unique_fd_test.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 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 "android-base/unique_fd.h"
+
+#include <gtest/gtest.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+using android::base::unique_fd;
+
+TEST(unique_fd, unowned_close) {
+#if defined(__BIONIC__)
+  unique_fd fd(open("/dev/null", O_RDONLY));
+  EXPECT_DEATH(close(fd.get()), "incorrect tag");
+#endif
+}
+
+TEST(unique_fd, untag_on_release) {
+  unique_fd fd(open("/dev/null", O_RDONLY));
+  close(fd.release());
+}
+
+TEST(unique_fd, move) {
+  unique_fd fd(open("/dev/null", O_RDONLY));
+  unique_fd fd_moved = std::move(fd);
+  ASSERT_EQ(-1, fd.get());
+  ASSERT_GT(fd_moved.get(), -1);
+}
+
+TEST(unique_fd, unowned_close_after_move) {
+#if defined(__BIONIC__)
+  unique_fd fd(open("/dev/null", O_RDONLY));
+  unique_fd fd_moved = std::move(fd);
+  ASSERT_EQ(-1, fd.get());
+  ASSERT_GT(fd_moved.get(), -1);
+  EXPECT_DEATH(close(fd_moved.get()), "incorrect tag");
+#endif
+}
diff --git a/fastboot/OWNERS b/fastboot/OWNERS
index 2d12d50..2088ae3 100644
--- a/fastboot/OWNERS
+++ b/fastboot/OWNERS
@@ -1,3 +1,4 @@
 dpursell@google.com
 enh@google.com
 jmgao@google.com
+tomcherry@google.com
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index 28e910b..05e03e1 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -79,6 +79,25 @@
     return true;
 }
 
+static bool CreateLogicalPartition(const std::string& block_device, const LpMetadata& metadata,
+                                   const LpMetadataPartition& partition, std::string* path) {
+    DeviceMapper& dm = DeviceMapper::Instance();
+
+    DmTable table;
+    if (!CreateDmTable(block_device, metadata, partition, &table)) {
+        return false;
+    }
+    std::string name = GetPartitionName(partition);
+    if (!dm.CreateDevice(name, table)) {
+        return false;
+    }
+    if (!dm.GetDmDevicePathByName(name, path)) {
+        return false;
+    }
+    LINFO << "Created logical partition " << name << " on device " << *path;
+    return true;
+}
+
 bool CreateLogicalPartitions(const std::string& block_device) {
     uint32_t slot = SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix());
     auto metadata = ReadMetadata(block_device.c_str(), slot);
@@ -86,23 +105,36 @@
         LOG(ERROR) << "Could not read partition table.";
         return true;
     }
-
-    DeviceMapper& dm = DeviceMapper::Instance();
     for (const auto& partition : metadata->partitions) {
-        DmTable table;
-        if (!CreateDmTable(block_device, *metadata.get(), partition, &table)) {
-            return false;
-        }
-        std::string name = GetPartitionName(partition);
-        if (!dm.CreateDevice(name, table)) {
-            return false;
-        }
         std::string path;
-        dm.GetDmDevicePathByName(partition.name, &path);
-        LINFO << "Created logical partition " << name << " on device " << path;
+        if (!CreateLogicalPartition(block_device, *metadata.get(), partition, &path)) {
+            LERROR << "Could not create logical partition: " << GetPartitionName(partition);
+            return false;
+        }
     }
     return true;
 }
 
+bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
+                            const std::string& partition_name, std::string* path) {
+    auto metadata = ReadMetadata(block_device.c_str(), metadata_slot);
+    if (!metadata) {
+        LOG(ERROR) << "Could not read partition table.";
+        return true;
+    }
+    for (const auto& partition : metadata->partitions) {
+        if (GetPartitionName(partition) == partition_name) {
+            return CreateLogicalPartition(block_device, *metadata.get(), partition, path);
+        }
+    }
+    LERROR << "Could not find any partition with name: " << partition_name;
+    return false;
+}
+
+bool DestroyLogicalPartition(const std::string& name) {
+    DeviceMapper& dm = DeviceMapper::Instance();
+    return dm.DeleteDevice(name);
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h
index 42af9d0..cac475c 100644
--- a/fs_mgr/include/fs_mgr_dm_linear.h
+++ b/fs_mgr/include/fs_mgr_dm_linear.h
@@ -39,6 +39,15 @@
 
 bool CreateLogicalPartitions(const std::string& block_device);
 
+// Create a block device for a single logical partition, given metadata and
+// the partition name. On success, a path to the partition's block device is
+// returned.
+bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
+                            const std::string& partition_name, std::string* path);
+
+// Destroy the block device for a logical partition, by name.
+bool DestroyLogicalPartition(const std::string& name);
+
 }  // namespace fs_mgr
 }  // namespace android
 
diff --git a/init/Android.bp b/init/Android.bp
index 5bbb7a0..c02b8d1 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -104,11 +104,10 @@
         "devices.cpp",
         "epoll.cpp",
         "firmware_handler.cpp",
+        "first_stage_mount.cpp",
         "import_parser.cpp",
         "init.cpp",
-        "init_first_stage.cpp",
         "keychords.cpp",
-        "log.cpp",
         "parser.cpp",
         "persistent_properties.cpp",
         "persistent_properties.proto",
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/init/devices.cpp b/init/devices.cpp
index ada1e28..ed4a739 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -31,7 +31,6 @@
 #include <selinux/selinux.h>
 
 #include "selinux.h"
-#include "ueventd.h"
 #include "util.h"
 
 #ifdef _INIT_INIT_H
diff --git a/init/init_first_stage.cpp b/init/first_stage_mount.cpp
similarity index 95%
rename from init/init_first_stage.cpp
rename to init/first_stage_mount.cpp
index 0ee0203..8ded873 100644
--- a/init/init_first_stage.cpp
+++ b/init/first_stage_mount.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "init_first_stage.h"
+#include "first_stage_mount.h"
 
 #include <stdlib.h>
 #include <unistd.h>
@@ -125,11 +125,12 @@
     if (checked) {
         return enabled;
     }
-    import_kernel_cmdline(false, [](const std::string& key, const std::string& value, bool in_qemu) {
-        if (key == "androidboot.logical_partitions" && value == "1") {
-            enabled = true;
-        }
-    });
+    import_kernel_cmdline(false,
+                          [](const std::string& key, const std::string& value, bool in_qemu) {
+                              if (key == "androidboot.logical_partitions" && value == "1") {
+                                  enabled = true;
+                              }
+                          });
     checked = true;
     return enabled;
 }
@@ -149,9 +150,9 @@
     }
 
     auto boot_devices = fs_mgr_get_boot_devices();
-    device_handler_ =
-        std::make_unique<DeviceHandler>(std::vector<Permissions>{}, std::vector<SysfsPermissions>{},
-                                        std::vector<Subsystem>{}, std::move(boot_devices), false);
+    device_handler_ = std::make_unique<DeviceHandler>(
+            std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{},
+            std::move(boot_devices), false);
 }
 
 std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
@@ -484,7 +485,7 @@
     // as it finds them, so this must happen first.
     if (!uevent.partition_name.empty() &&
         required_devices_partition_names_.find(uevent.partition_name) !=
-            required_devices_partition_names_.end()) {
+                required_devices_partition_names_.end()) {
         // GetBlockDeviceSymlinks() will return three symlinks at most, depending on
         // the content of uevent. by-name symlink will be at [0] if uevent->partition_name
         // is not empty. e.g.,
@@ -492,7 +493,7 @@
         //   - /dev/block/platform/soc.0/f9824900.sdhci/mmcblk0p1
         std::vector<std::string> links = device_handler_->GetBlockDeviceSymlinks(uevent);
         if (!links.empty()) {
-            auto[it, inserted] = by_name_symlink_map_.emplace(uevent.partition_name, links[0]);
+            auto [it, inserted] = by_name_symlink_map_.emplace(uevent.partition_name, links[0]);
             if (!inserted) {
                 LOG(ERROR) << "Partition '" << uevent.partition_name
                            << "' already existed in the by-name symlink map with a value of '"
@@ -508,7 +509,7 @@
     if (fs_mgr_is_avb(fstab_rec)) {
         if (!InitAvbHandle()) return false;
         SetUpAvbHashtreeResult hashtree_result =
-            avb_handle_->SetUpAvbHashtree(fstab_rec, false /* wait_for_verity_dev */);
+                avb_handle_->SetUpAvbHashtree(fstab_rec, false /* wait_for_verity_dev */);
         switch (hashtree_result) {
             case SetUpAvbHashtreeResult::kDisabled:
                 return true;  // Returns true to mount the partition.
@@ -585,7 +586,7 @@
     }
 
     FsManagerAvbUniquePtr avb_handle =
-        FsManagerAvbHandle::Open(std::move(avb_first_mount.by_name_symlink_map_));
+            FsManagerAvbHandle::Open(std::move(avb_first_mount.by_name_symlink_map_));
     if (!avb_handle) {
         PLOG(ERROR) << "Failed to open FsManagerAvbHandle for INIT_AVB_VERSION";
         return;
diff --git a/init/init_first_stage.h b/init/first_stage_mount.h
similarity index 91%
rename from init/init_first_stage.h
rename to init/first_stage_mount.h
index c7a3867..21d87fd 100644
--- a/init/init_first_stage.h
+++ b/init/first_stage_mount.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef _INIT_FIRST_STAGE_H
-#define _INIT_FIRST_STAGE_H
+#pragma once
 
 namespace android {
 namespace init {
@@ -25,5 +24,3 @@
 
 }  // namespace init
 }  // namespace android
-
-#endif
diff --git a/init/init.cpp b/init/init.cpp
index 686cd6e..6569871 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -48,10 +48,9 @@
 
 #include "action_parser.h"
 #include "epoll.h"
+#include "first_stage_mount.h"
 #include "import_parser.h"
-#include "init_first_stage.h"
 #include "keychords.h"
-#include "log.h"
 #include "property_service.h"
 #include "reboot.h"
 #include "security.h"
@@ -582,6 +581,34 @@
     }
 }
 
+static void InitAborter(const char* abort_message) {
+    // When init forks, it continues to use this aborter for LOG(FATAL), but we want children to
+    // simply abort instead of trying to reboot the system.
+    if (getpid() != 1) {
+        android::base::DefaultAborter(abort_message);
+        return;
+    }
+
+    RebootSystem(ANDROID_RB_RESTART2, "bootloader");
+}
+
+static void InitKernelLogging(char* argv[]) {
+    // Make stdin/stdout/stderr all point to /dev/null.
+    int fd = open("/sys/fs/selinux/null", O_RDWR);
+    if (fd == -1) {
+        int saved_errno = errno;
+        android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
+        errno = saved_errno;
+        PLOG(FATAL) << "Couldn't open /sys/fs/selinux/null";
+    }
+    dup2(fd, 0);
+    dup2(fd, 1);
+    dup2(fd, 2);
+    if (fd > 2) close(fd);
+
+    android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
+}
+
 int main(int argc, char** argv) {
     if (!strcmp(basename(argv[0]), "ueventd")) {
         return ueventd_main(argc, argv);
@@ -592,7 +619,7 @@
     }
 
     if (argc > 1 && !strcmp(argv[1], "subcontext")) {
-        InitKernelLogging(argv);
+        android::base::InitLogging(argv, &android::base::KernelLogger);
         const BuiltinFunctionMap function_map;
         return SubcontextMain(argc, argv, &function_map);
     }
diff --git a/init/log.cpp b/init/log.cpp
deleted file mode 100644
index 6198fc2..0000000
--- a/init/log.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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 "log.h"
-
-#include <fcntl.h>
-#include <linux/audit.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <android-base/logging.h>
-#include <cutils/android_reboot.h>
-#include <selinux/selinux.h>
-
-#include "reboot.h"
-
-namespace android {
-namespace init {
-
-static void InitAborter(const char* abort_message) {
-    // When init forks, it continues to use this aborter for LOG(FATAL), but we want children to
-    // simply abort instead of trying to reboot the system.
-    if (getpid() != 1) {
-        android::base::DefaultAborter(abort_message);
-        return;
-    }
-
-    // DoReboot() does a lot to try to shutdown the system cleanly.  If something happens to call
-    // LOG(FATAL) in the shutdown path, we want to catch this and immediately use the syscall to
-    // reboot instead of recursing here.
-    static bool has_aborted = false;
-    if (!has_aborted) {
-        has_aborted = true;
-        // Do not queue "shutdown" trigger since we want to shutdown immediately and it's not likely
-        // that we can even run the ActionQueue at this point.
-        DoReboot(ANDROID_RB_RESTART2, "reboot", "bootloader", false);
-    } else {
-        RebootSystem(ANDROID_RB_RESTART2, "bootloader");
-    }
-}
-
-void InitKernelLogging(char* argv[]) {
-    // Make stdin/stdout/stderr all point to /dev/null.
-    int fd = open("/sys/fs/selinux/null", O_RDWR);
-    if (fd == -1) {
-        int saved_errno = errno;
-        android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
-        errno = saved_errno;
-        PLOG(FATAL) << "Couldn't open /sys/fs/selinux/null";
-    }
-    dup2(fd, 0);
-    dup2(fd, 1);
-    dup2(fd, 2);
-    if (fd > 2) close(fd);
-
-    android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
-}
-
-int selinux_klog_callback(int type, const char *fmt, ...) {
-    android::base::LogSeverity severity = android::base::ERROR;
-    if (type == SELINUX_WARNING) {
-        severity = android::base::WARNING;
-    } else if (type == SELINUX_INFO) {
-        severity = android::base::INFO;
-    }
-    char buf[1024];
-    va_list ap;
-    va_start(ap, fmt);
-    vsnprintf(buf, sizeof(buf), fmt, ap);
-    va_end(ap);
-    android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
-    return 0;
-}
-
-}  // namespace init
-}  // namespace android
diff --git a/init/log.h b/init/log.h
deleted file mode 100644
index 5a4eba6..0000000
--- a/init/log.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _INIT_LOG_H_
-#define _INIT_LOG_H_
-
-#include <sys/cdefs.h>
-
-namespace android {
-namespace init {
-
-void InitKernelLogging(char* argv[]);
-
-int selinux_klog_callback(int level, const char* fmt, ...) __printflike(2, 3);
-
-}  // namespace init
-}  // namespace android
-
-#endif
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 0ba5c4a..94f206e 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -59,7 +59,6 @@
 #include <android-base/unique_fd.h>
 #include <selinux/android.h>
 
-#include "log.h"
 #include "util.h"
 
 using android::base::ParseInt;
@@ -448,10 +447,26 @@
     selinux_android_restorecon("/sbin/sload.f2fs", 0);
 }
 
+int SelinuxKlogCallback(int type, const char* fmt, ...) {
+    android::base::LogSeverity severity = android::base::ERROR;
+    if (type == SELINUX_WARNING) {
+        severity = android::base::WARNING;
+    } else if (type == SELINUX_INFO) {
+        severity = android::base::INFO;
+    }
+    char buf[1024];
+    va_list ap;
+    va_start(ap, fmt);
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+    va_end(ap);
+    android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
+    return 0;
+}
+
 // This function sets up SELinux logging to be written to kmsg, to match init's logging.
 void SelinuxSetupKernelLogging() {
     selinux_callback cb;
-    cb.func_log = selinux_klog_callback;
+    cb.func_log = SelinuxKlogCallback;
     selinux_set_callback(SELINUX_CB_LOG, cb);
 }
 
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index b42a4c6..cd45a3f 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -36,7 +36,6 @@
 
 #include "devices.h"
 #include "firmware_handler.h"
-#include "log.h"
 #include "selinux.h"
 #include "uevent_listener.h"
 #include "ueventd_parser.h"
@@ -223,7 +222,7 @@
      */
     umask(000);
 
-    InitKernelLogging(argv);
+    android::base::InitLogging(argv, &android::base::KernelLogger);
 
     LOG(INFO) << "ueventd started!";
 
diff --git a/init/util.cpp b/init/util.cpp
index 5f2b87d..7735717 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -37,12 +37,9 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
-#include <cutils/android_reboot.h>
 #include <cutils/sockets.h>
 #include <selinux/android.h>
 
-#include "reboot.h"
-
 #if defined(__ANDROID__)
 #include "selinux.h"
 #else
diff --git a/init/watchdogd.cpp b/init/watchdogd.cpp
index e0164b4..e03a2c3 100644
--- a/init/watchdogd.cpp
+++ b/init/watchdogd.cpp
@@ -23,8 +23,6 @@
 
 #include <android-base/logging.h>
 
-#include "log.h"
-
 #ifdef _INIT_INIT_H
 #error "Do not include init.h in files used by ueventd or watchdogd; it will expose init's globals"
 #endif
@@ -35,7 +33,7 @@
 namespace init {
 
 int watchdogd_main(int argc, char **argv) {
-    InitKernelLogging(argv);
+    android::base::InitLogging(argv, &android::base::KernelLogger);
 
     int interval = 10;
     if (argc >= 2) interval = atoi(argv[1]);
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h
index f1ff31a..9c68ff2 100644
--- a/liblog/include/log/log_main.h
+++ b/liblog/include/log/log_main.h
@@ -43,10 +43,11 @@
 /*
  * Use __VA_ARGS__ if running a static analyzer,
  * to avoid warnings of unused variables in __VA_ARGS__.
+ * __FAKE_USE_VA_ARGS is undefined at link time,
+ * so don't link with __clang_analyzer__ defined.
  */
-
 #ifdef __clang_analyzer__
-#define __FAKE_USE_VA_ARGS(...) ((void)(__VA_ARGS__))
+extern void __FAKE_USE_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/backed_block.cpp b/libsparse/backed_block.cpp
index 7f5632e..f3d8022 100644
--- a/libsparse/backed_block.cpp
+++ b/libsparse/backed_block.cpp
@@ -133,7 +133,7 @@
                             struct backed_block* start, struct backed_block* end) {
   struct backed_block* bb;
 
-  if (start == NULL) {
+  if (start == nullptr) {
     start = from->data_blocks;
   }
 
@@ -142,12 +142,12 @@
       ;
   }
 
-  if (start == NULL || end == NULL) {
+  if (start == nullptr || end == nullptr) {
     return;
   }
 
-  from->last_used = NULL;
-  to->last_used = NULL;
+  from->last_used = nullptr;
+  to->last_used = nullptr;
   if (from->data_blocks == start) {
     from->data_blocks = end->next;
   } else {
@@ -161,7 +161,7 @@
 
   if (!to->data_blocks) {
     to->data_blocks = start;
-    end->next = NULL;
+    end->next = nullptr;
   } else {
     for (bb = to->data_blocks; bb; bb = bb->next) {
       if (!bb->next || bb->next->block > start->block) {
@@ -230,7 +230,7 @@
 static int queue_bb(struct backed_block_list* bbl, struct backed_block* new_bb) {
   struct backed_block* bb;
 
-  if (bbl->data_blocks == NULL) {
+  if (bbl->data_blocks == nullptr) {
     bbl->data_blocks = new_bb;
     return 0;
   }
@@ -253,7 +253,7 @@
   for (; bb->next && bb->next->block < new_bb->block; bb = bb->next)
     ;
 
-  if (bb->next == NULL) {
+  if (bb->next == nullptr) {
     bb->next = new_bb;
   } else {
     new_bb->next = bb->next;
@@ -273,7 +273,7 @@
 int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, unsigned int len,
                           unsigned int block) {
   struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
-  if (bb == NULL) {
+  if (bb == nullptr) {
     return -ENOMEM;
   }
 
@@ -281,7 +281,7 @@
   bb->len = len;
   bb->type = BACKED_BLOCK_FILL;
   bb->fill.val = fill_val;
-  bb->next = NULL;
+  bb->next = nullptr;
 
   return queue_bb(bbl, bb);
 }
@@ -290,7 +290,7 @@
 int backed_block_add_data(struct backed_block_list* bbl, void* data, unsigned int len,
                           unsigned int block) {
   struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
-  if (bb == NULL) {
+  if (bb == nullptr) {
     return -ENOMEM;
   }
 
@@ -298,7 +298,7 @@
   bb->len = len;
   bb->type = BACKED_BLOCK_DATA;
   bb->data.data = data;
-  bb->next = NULL;
+  bb->next = nullptr;
 
   return queue_bb(bbl, bb);
 }
@@ -307,7 +307,7 @@
 int backed_block_add_file(struct backed_block_list* bbl, const char* filename, int64_t offset,
                           unsigned int len, unsigned int block) {
   struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
-  if (bb == NULL) {
+  if (bb == nullptr) {
     return -ENOMEM;
   }
 
@@ -316,7 +316,7 @@
   bb->type = BACKED_BLOCK_FILE;
   bb->file.filename = strdup(filename);
   bb->file.offset = offset;
-  bb->next = NULL;
+  bb->next = nullptr;
 
   return queue_bb(bbl, bb);
 }
@@ -325,7 +325,7 @@
 int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, unsigned int len,
                         unsigned int block) {
   struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
-  if (bb == NULL) {
+  if (bb == nullptr) {
     return -ENOMEM;
   }
 
@@ -334,7 +334,7 @@
   bb->type = BACKED_BLOCK_FD;
   bb->fd.fd = fd;
   bb->fd.offset = offset;
-  bb->next = NULL;
+  bb->next = nullptr;
 
   return queue_bb(bbl, bb);
 }
@@ -350,7 +350,7 @@
   }
 
   new_bb = reinterpret_cast<backed_block*>(malloc(sizeof(struct backed_block)));
-  if (new_bb == NULL) {
+  if (new_bb == nullptr) {
     return -ENOMEM;
   }
 
diff --git a/libsparse/output_file.cpp b/libsparse/output_file.cpp
index 5388e77..fe314b3 100644
--- a/libsparse/output_file.cpp
+++ b/libsparse/output_file.cpp
@@ -233,7 +233,7 @@
   while (len > 0) {
     ret = gzwrite(outgz->gz_fd, data, min(len, (unsigned int)INT_MAX));
     if (ret == 0) {
-      error("gzwrite %s", gzerror(outgz->gz_fd, NULL));
+      error("gzwrite %s", gzerror(outgz->gz_fd, nullptr));
       return -1;
     }
     len -= ret;
@@ -269,7 +269,7 @@
 
   while (off > 0) {
     to_write = min(off, (int64_t)INT_MAX);
-    ret = outc->write(outc->priv, NULL, to_write);
+    ret = outc->write(outc->priv, nullptr, to_write);
     if (ret < 0) {
       return ret;
     }
@@ -568,7 +568,7 @@
       reinterpret_cast<struct output_file_gz*>(calloc(1, sizeof(struct output_file_gz)));
   if (!outgz) {
     error_errno("malloc struct outgz");
-    return NULL;
+    return nullptr;
   }
 
   outgz->out.ops = &gz_file_ops;
@@ -581,7 +581,7 @@
       reinterpret_cast<struct output_file_normal*>(calloc(1, sizeof(struct output_file_normal)));
   if (!outn) {
     error_errno("malloc struct outn");
-    return NULL;
+    return nullptr;
   }
 
   outn->out.ops = &file_ops;
@@ -599,7 +599,7 @@
       reinterpret_cast<struct output_file_callback*>(calloc(1, sizeof(struct output_file_callback)));
   if (!outc) {
     error_errno("malloc struct outc");
-    return NULL;
+    return nullptr;
   }
 
   outc->out.ops = &callback_file_ops;
@@ -609,7 +609,7 @@
   ret = output_file_init(&outc->out, block_size, len, sparse, chunks, crc);
   if (ret < 0) {
     free(outc);
-    return NULL;
+    return nullptr;
   }
 
   return &outc->out;
@@ -626,7 +626,7 @@
     out = output_file_new_normal();
   }
   if (!out) {
-    return NULL;
+    return nullptr;
   }
 
   out->ops->open(out, fd);
@@ -634,7 +634,7 @@
   ret = output_file_init(out, block_size, len, sparse, chunks, crc);
   if (ret < 0) {
     free(out);
-    return NULL;
+    return nullptr;
   }
 
   return out;
@@ -664,7 +664,7 @@
 #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));
+      reinterpret_cast<char*>(mmap64(nullptr, buffer_size, PROT_READ, MAP_SHARED, fd, aligned_offset));
   if (data == MAP_FAILED) {
     return -errno;
   }
diff --git a/libsparse/simg2simg.cpp b/libsparse/simg2simg.cpp
index 7e65701..a2c296e 100644
--- a/libsparse/simg2simg.cpp
+++ b/libsparse/simg2simg.cpp
@@ -66,7 +66,7 @@
     exit(-1);
   }
 
-  files = sparse_file_resparse(s, max_size, NULL, 0);
+  files = sparse_file_resparse(s, max_size, nullptr, 0);
   if (files < 0) {
     fprintf(stderr, "Failed to resparse\n");
     exit(-1);
diff --git a/libsparse/sparse.cpp b/libsparse/sparse.cpp
index 6ff97b6..cb288c5 100644
--- a/libsparse/sparse.cpp
+++ b/libsparse/sparse.cpp
@@ -30,13 +30,13 @@
 struct sparse_file* sparse_file_new(unsigned int block_size, int64_t len) {
   struct sparse_file* s = reinterpret_cast<sparse_file*>(calloc(sizeof(struct sparse_file), 1));
   if (!s) {
-    return NULL;
+    return nullptr;
   }
 
   s->backed_block_list = backed_block_list_new(block_size);
   if (!s->backed_block_list) {
     free(s);
-    return NULL;
+    return nullptr;
   }
 
   s->block_size = block_size;
@@ -252,7 +252,7 @@
                                                   unsigned int len) {
   int64_t count = 0;
   struct output_file* out_counter;
-  struct backed_block* last_bb = NULL;
+  struct backed_block* last_bb = nullptr;
   struct backed_block* bb;
   struct backed_block* start;
   unsigned int last_block = 0;
@@ -270,7 +270,7 @@
   out_counter = output_file_open_callback(out_counter_write, &count, to->block_size, to->len, false,
                                           true, 0, false);
   if (!out_counter) {
-    return NULL;
+    return nullptr;
   }
 
   for (bb = start; bb; bb = backed_block_iter_next(bb)) {
@@ -281,7 +281,7 @@
     /* will call out_counter_write to update count */
     ret = sparse_file_write_block(out_counter, bb);
     if (ret) {
-      bb = NULL;
+      bb = nullptr;
       goto out;
     }
     if (file_len + count > len) {
@@ -330,13 +330,13 @@
     if (c < out_s_count) {
       out_s[c] = s;
     } else {
-      backed_block_list_move(s->backed_block_list, tmp->backed_block_list, NULL, NULL);
+      backed_block_list_move(s->backed_block_list, tmp->backed_block_list, nullptr, nullptr);
       sparse_file_destroy(s);
     }
     c++;
   } while (bb);
 
-  backed_block_list_move(tmp->backed_block_list, in_s->backed_block_list, NULL, NULL);
+  backed_block_list_move(tmp->backed_block_list, in_s->backed_block_list, nullptr, nullptr);
 
   sparse_file_destroy(tmp);
 
diff --git a/libsparse/sparse_read.cpp b/libsparse/sparse_read.cpp
index 56e2c9a..c4c1823 100644
--- a/libsparse/sparse_read.cpp
+++ b/libsparse/sparse_read.cpp
@@ -276,7 +276,7 @@
     return ret;
   }
 
-  if (crc32 != NULL && file_crc32 != *crc32) {
+  if (crc32 != nullptr && file_crc32 != *crc32) {
     return -EINVAL;
   }
 
@@ -339,7 +339,7 @@
   sparse_header_t sparse_header;
   chunk_header_t chunk_header;
   uint32_t crc32 = 0;
-  uint32_t* crc_ptr = 0;
+  uint32_t* crc_ptr = nullptr;
   unsigned int cur_block = 0;
 
   if (!copybuf) {
@@ -489,39 +489,39 @@
   ret = source->ReadValue(&sparse_header, sizeof(sparse_header));
   if (ret < 0) {
     verbose_error(verbose, ret, "header");
-    return NULL;
+    return nullptr;
   }
 
   if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
     verbose_error(verbose, -EINVAL, "header magic");
-    return NULL;
+    return nullptr;
   }
 
   if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
     verbose_error(verbose, -EINVAL, "header major version");
-    return NULL;
+    return nullptr;
   }
 
   if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
-    return NULL;
+    return nullptr;
   }
 
   if (sparse_header.chunk_hdr_sz < sizeof(chunk_header_t)) {
-    return NULL;
+    return nullptr;
   }
 
   len = (int64_t)sparse_header.total_blks * sparse_header.blk_sz;
   s = sparse_file_new(sparse_header.blk_sz, len);
   if (!s) {
-    verbose_error(verbose, -EINVAL, NULL);
-    return NULL;
+    verbose_error(verbose, -EINVAL, nullptr);
+    return nullptr;
   }
 
   ret = source->SetOffset(0);
   if (ret < 0) {
     verbose_error(verbose, ret, "seeking");
     sparse_file_destroy(s);
-    return NULL;
+    return nullptr;
   }
 
   s->verbose = verbose;
@@ -529,7 +529,7 @@
   ret = sparse_file_read_sparse(s, source, crc);
   if (ret < 0) {
     sparse_file_destroy(s);
-    return NULL;
+    return nullptr;
   }
 
   return s;
@@ -557,20 +557,20 @@
 
   len = lseek64(fd, 0, SEEK_END);
   if (len < 0) {
-    return NULL;
+    return nullptr;
   }
 
   lseek64(fd, 0, SEEK_SET);
 
   s = sparse_file_new(4096, len);
   if (!s) {
-    return NULL;
+    return nullptr;
   }
 
   ret = sparse_file_read_normal(s, fd);
   if (ret < 0) {
     sparse_file_destroy(s);
-    return NULL;
+    return nullptr;
   }
 
   return s;
diff --git a/libsync/include/ndk/sync.h b/libsync/include/ndk/sync.h
index 49f01e1..ba7d8c4 100644
--- a/libsync/include/ndk/sync.h
+++ b/libsync/include/ndk/sync.h
@@ -27,11 +27,14 @@
 #define ANDROID_SYNC_H
 
 #include <stdint.h>
+#include <sys/cdefs.h>
 
 #include <linux/sync_file.h>
 
 __BEGIN_DECLS
 
+#if __ANDROID_API__ >= 26
+
 /* Fences indicate the status of an asynchronous task. They are initially
  * in unsignaled state (0), and make a one-time transition to either signaled
  * (1) or error (< 0) state. A sync file is a collection of one or more fences;
@@ -88,6 +91,8 @@
 /** Free a struct sync_file_info structure */
 void sync_file_info_free(struct sync_file_info* info) __INTRODUCED_IN(26);
 
+#endif /* __ANDROID_API__ >= 26 */
+
 __END_DECLS
 
 #endif /* ANDROID_SYNC_H */
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/libutils/Android.bp b/libutils/Android.bp
index bbfa9d8..d635e65 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -155,6 +155,7 @@
             ],
         },
         linux: {
+            shared_libs: ["libbase"],
             srcs: [
                 "Looper.cpp",
             ],
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index 7bc2397..102fdf0 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -60,24 +60,22 @@
 static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT;
 static pthread_key_t gTLSKey = 0;
 
-Looper::Looper(bool allowNonCallbacks) :
-        mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
-        mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
-        mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
-    mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
-    LOG_ALWAYS_FATAL_IF(mWakeEventFd < 0, "Could not make wake event fd: %s",
-                        strerror(errno));
+Looper::Looper(bool allowNonCallbacks)
+    : mAllowNonCallbacks(allowNonCallbacks),
+      mSendingMessage(false),
+      mPolling(false),
+      mEpollRebuildRequired(false),
+      mNextRequestSeq(0),
+      mResponseIndex(0),
+      mNextMessageUptime(LLONG_MAX) {
+    mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
+    LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));
 
     AutoMutex _l(mLock);
     rebuildEpollLocked();
 }
 
 Looper::~Looper() {
-    close(mWakeEventFd);
-    mWakeEventFd = -1;
-    if (mEpollFd >= 0) {
-        close(mEpollFd);
-    }
 }
 
 void Looper::initTLSKey() {
@@ -137,18 +135,18 @@
 #if DEBUG_CALLBACKS
         ALOGD("%p ~ rebuildEpollLocked - rebuilding epoll set", this);
 #endif
-        close(mEpollFd);
+        mEpollFd.reset();
     }
 
     // Allocate the new epoll instance and register the wake pipe.
-    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
+    mEpollFd.reset(epoll_create(EPOLL_SIZE_HINT));
     LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
 
     struct epoll_event eventItem;
     memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
     eventItem.events = EPOLLIN;
-    eventItem.data.fd = mWakeEventFd;
-    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
+    eventItem.data.fd = mWakeEventFd.get();
+    int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &eventItem);
     LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance: %s",
                         strerror(errno));
 
@@ -157,7 +155,7 @@
         struct epoll_event eventItem;
         request.initEventItem(&eventItem);
 
-        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, request.fd, & eventItem);
+        int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, request.fd, &eventItem);
         if (epollResult < 0) {
             ALOGE("Error adding epoll events for fd %d while rebuilding epoll set: %s",
                   request.fd, strerror(errno));
@@ -239,7 +237,7 @@
     mPolling = true;
 
     struct epoll_event eventItems[EPOLL_MAX_EVENTS];
-    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
+    int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
 
     // No longer idling.
     mPolling = false;
@@ -281,7 +279,7 @@
     for (int i = 0; i < eventCount; i++) {
         int fd = eventItems[i].data.fd;
         uint32_t epollEvents = eventItems[i].events;
-        if (fd == mWakeEventFd) {
+        if (fd == mWakeEventFd.get()) {
             if (epollEvents & EPOLLIN) {
                 awoken();
             } else {
@@ -401,11 +399,11 @@
 #endif
 
     uint64_t inc = 1;
-    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
+    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
     if (nWrite != sizeof(uint64_t)) {
         if (errno != EAGAIN) {
-            LOG_ALWAYS_FATAL("Could not write wake signal to fd %d: %s",
-                    mWakeEventFd, strerror(errno));
+            LOG_ALWAYS_FATAL("Could not write wake signal to fd %d: %s", mWakeEventFd.get(),
+                             strerror(errno));
         }
     }
 }
@@ -416,7 +414,7 @@
 #endif
 
     uint64_t counter;
-    TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t)));
+    TEMP_FAILURE_RETRY(read(mWakeEventFd.get(), &counter, sizeof(uint64_t)));
 }
 
 void Looper::pushResponse(int events, const Request& request) {
@@ -467,14 +465,14 @@
 
         ssize_t requestIndex = mRequests.indexOfKey(fd);
         if (requestIndex < 0) {
-            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
+            int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);
             if (epollResult < 0) {
                 ALOGE("Error adding epoll events for fd %d: %s", fd, strerror(errno));
                 return -1;
             }
             mRequests.add(fd, request);
         } else {
-            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
+            int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_MOD, fd, &eventItem);
             if (epollResult < 0) {
                 if (errno == ENOENT) {
                     // Tolerate ENOENT because it means that an older file descriptor was
@@ -495,7 +493,7 @@
                             "being recycled, falling back on EPOLL_CTL_ADD: %s",
                             this, strerror(errno));
 #endif
-                    epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
+                    epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);
                     if (epollResult < 0) {
                         ALOGE("Error modifying or adding epoll events for fd %d: %s",
                                 fd, strerror(errno));
@@ -542,7 +540,7 @@
         // updating the epoll set so that we avoid accidentally leaking callbacks.
         mRequests.removeItemsAt(requestIndex);
 
-        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, nullptr);
+        int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_DEL, fd, nullptr);
         if (epollResult < 0) {
             if (seq != -1 && (errno == EBADF || errno == ENOENT)) {
                 // Tolerate EBADF or ENOENT when the sequence number is known because it
diff --git a/libutils/include/utils/Looper.h b/libutils/include/utils/Looper.h
index 4509d75..c439c5c 100644
--- a/libutils/include/utils/Looper.h
+++ b/libutils/include/utils/Looper.h
@@ -24,6 +24,8 @@
 
 #include <sys/epoll.h>
 
+#include <android-base/unique_fd.h>
+
 namespace android {
 
 /*
@@ -447,7 +449,7 @@
 
     const bool mAllowNonCallbacks; // immutable
 
-    int mWakeEventFd;  // immutable
+    android::base::unique_fd mWakeEventFd;  // immutable
     Mutex mLock;
 
     Vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock
@@ -457,7 +459,7 @@
     // any use of it is racy anyway.
     volatile bool mPolling;
 
-    int mEpollFd; // guarded by mLock but only modified on the looper thread
+    android::base::unique_fd mEpollFd;  // guarded by mLock but only modified on the looper thread
     bool mEpollRebuildRequired; // guarded by mLock
 
     // Locked list of file descriptor monitoring requests.
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 5e5e7af..9536fc7 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -33,6 +33,10 @@
 #include <memory>
 #include <vector>
 
+#if defined(__BIONIC__)
+#include <android/fdsan.h>
+#endif
+
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/macros.h>  // TEMP_FAILURE_RETRY may or may not be in unistd
@@ -165,6 +169,44 @@
   return 0;
 }
 
+ZipArchive::ZipArchive(const int fd, bool assume_ownership)
+    : mapped_zip(fd),
+      close_file(assume_ownership),
+      directory_offset(0),
+      central_directory(),
+      directory_map(new android::FileMap()),
+      num_entries(0),
+      hash_table_size(0),
+      hash_table(nullptr) {
+#if defined(__BIONIC__)
+  if (assume_ownership) {
+    android_fdsan_exchange_owner_tag(fd, 0, reinterpret_cast<uint64_t>(this));
+  }
+#endif
+}
+
+ZipArchive::ZipArchive(void* address, size_t length)
+    : mapped_zip(address, length),
+      close_file(false),
+      directory_offset(0),
+      central_directory(),
+      directory_map(new android::FileMap()),
+      num_entries(0),
+      hash_table_size(0),
+      hash_table(nullptr) {}
+
+ZipArchive::~ZipArchive() {
+  if (close_file && mapped_zip.GetFileDescriptor() >= 0) {
+#if defined(__BIONIC__)
+    android_fdsan_close_with_tag(mapped_zip.GetFileDescriptor(), reinterpret_cast<uint64_t>(this));
+#else
+    close(mapped_zip.GetFileDescriptor());
+#endif
+  }
+
+  free(hash_table);
+}
+
 static int32_t MapCentralDirectory0(const char* debug_file_name, ZipArchive* archive,
                                     off64_t file_length, off64_t read_amount, uint8_t* scan_buffer) {
   const off64_t search_start = file_length - read_amount;
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 18e0229..0a73300 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -156,33 +156,9 @@
   uint32_t hash_table_size;
   ZipString* hash_table;
 
-  ZipArchive(const int fd, bool assume_ownership)
-      : mapped_zip(fd),
-        close_file(assume_ownership),
-        directory_offset(0),
-        central_directory(),
-        directory_map(new android::FileMap()),
-        num_entries(0),
-        hash_table_size(0),
-        hash_table(nullptr) {}
-
-  ZipArchive(void* address, size_t length)
-      : mapped_zip(address, length),
-        close_file(false),
-        directory_offset(0),
-        central_directory(),
-        directory_map(new android::FileMap()),
-        num_entries(0),
-        hash_table_size(0),
-        hash_table(nullptr) {}
-
-  ~ZipArchive() {
-    if (close_file && mapped_zip.GetFileDescriptor() >= 0) {
-      close(mapped_zip.GetFileDescriptor());
-    }
-
-    free(hash_table);
-  }
+  ZipArchive(const int fd, bool assume_ownership);
+  ZipArchive(void* address, size_t length);
+  ~ZipArchive();
 
   bool InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
                                   size_t cd_size);
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",