Merge "storaged: split proto file into multiple CE areas"
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 7ed5b2b..121197c 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -51,6 +51,14 @@
   ASSERT_EQ("bar", parts[2]);
 }
 
+TEST(strings, split_with_trailing_empty_part) {
+  std::vector<std::string> parts = android::base::Split("foo,bar,", ",");
+  ASSERT_EQ(3U, parts.size());
+  ASSERT_EQ("foo", parts[0]);
+  ASSERT_EQ("bar", parts[1]);
+  ASSERT_EQ("", parts[2]);
+}
+
 TEST(strings, split_null_char) {
   std::vector<std::string> parts =
       android::base::Split(std::string("foo\0bar", 7), std::string("\0", 1));
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index 209e81b..c1d5430 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -194,10 +194,12 @@
               sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
         if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]
         then
+          sleep 1
           break
         fi
         if [ "${vals}" = "`echo logbootcomplete=1 ; echo boot_completed=1`" ]
         then
+          sleep 1
           break
         fi
       fi
@@ -239,7 +241,8 @@
 
 [ "USAGE: EXPECT_PROPERTY <prop> <value> [--allow_failure]
 
-Returns true if current return (regex) value is true and the result matches" ]
+Returns true (0) if current return (regex) value is true and the result matches
+and the incoming return value is true as well (wired-or)" ]
 EXPECT_PROPERTY() {
   save_ret=${?}
   property="${1}"
@@ -287,6 +290,7 @@
 bootstat: Battery level at shutdown 100%
 bootstat: Battery level at startup 100%
 init    : Parsing file /system/etc/init/bootstat.rc...
+init    : Parsing file /system/etc/init/bootstat-debug.rc...
 init    : processing action (persist.test.boot.reason=*) from (/system/etc/init/bootstat-debug.rc:
 init    : Command 'setprop ro.boot.bootreason \${persist.test.boot.reason}' action=persist.test.boot.reason=* (/system/etc/init/bootstat-debug.rc:
 init    : processing action (post-fs-data) from (/system/etc/init/bootstat.rc
@@ -566,6 +570,8 @@
   esac
   adb reboot ${TEST}
   wait_for_screen
+  bootloader_reason=`validate_property ro.boot.bootreason`
+  EXPECT_PROPERTY ro.boot.bootreason ${bootloader_reason}
   EXPECT_PROPERTY sys.boot.reason ${reason}
   EXPECT_PROPERTY persist.sys.boot.reason ${reason}
   report_bootstat_logs ${reason}
@@ -623,8 +629,13 @@
     adb reboot-bootloader
   fi
   fastboot format userdata >&2
+  save_ret=${?}
+  if [ 0 != ${save_ret} ]; then
+    echo "ERROR: fastboot can not format userdata" >&2
+  fi
   fastboot reboot >&2
   wait_for_screen
+  ( exit ${save_ret} )  # because one can not just do ?=${save_ret}
   EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
   EXPECT_PROPERTY persist.sys.boot.reason ""
   report_bootstat_logs reboot,factory_reset bootloader \
@@ -868,17 +879,30 @@
 - NB: should report reboot,its_just_so_hard
 - NB: expect log \"... I bootstat: Unknown boot reason: reboot,its_just_so_hard\"" ]
 test_Its_Just_So_Hard_reboot() {
-  duration_test
+  if isDebuggable; then       # see below
+    duration_test
+  else
+    duration_test `expr ${DURATION_DEFAULT} + ${DURATION_DEFAULT}`
+  fi
   adb shell 'reboot "Its Just So Hard"'
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard
   EXPECT_PROPERTY persist.sys.boot.reason "reboot,Its Just So Hard"
-  adb shell su root setprop persist.sys.boot.reason reboot,its_just_so_hard
-  if checkDebugBuild; then
-    flag=""
+  # Do not leave this test with an illegal value in persist.sys.boot.reason
+  save_ret=${?}           # hold on to error code from above two lines
+  if isDebuggable; then   # can do this easy, or we can do this hard.
+    adb shell su root setprop persist.sys.boot.reason reboot,its_just_so_hard
+    ( exit ${save_ret} )  # because one can not just do ?=${save_ret}
   else
-    flag="--allow_failure"
+    report_bootstat_logs reboot,its_just_so_hard  # report what we have so far
+    # user build mitigation
+    adb shell reboot its_just_so_hard
+    wait_for_screen
+    ( exit ${save_ret} )  # because one can not just do ?=${save_ret}
+    EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard
   fi
+  # Ensure persist.sys.boot.reason now valid, failure here acts as a signal
+  # that we could choke up following tests.  For example test_properties.
   EXPECT_PROPERTY persist.sys.boot.reason reboot,its_just_so_hard ${flag}
   report_bootstat_logs reboot,its_just_so_hard
 }
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 2270133..8c11289 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -223,6 +223,11 @@
     {"2sec_reboot", 83},
     {"reboot,by_key", 84},
     {"reboot,longkey", 85},
+    {"reboot,2sec", 86},
+    {"shutdown,thermal,battery", 87},
+    {"reboot,its_just_so_hard", 88},  // produced by boot_reason_test
+    {"reboot,Its Just So Hard", 89},  // produced by boot_reason_test
+    {"usb", 90},
 };
 
 // Converts a string value representing the reason the system booted to an
@@ -324,7 +329,105 @@
   return android::base::ReadFileToString("/sys/fs/pstore/console-ramoops", &console);
 }
 
-bool addKernelPanicSubReason(const std::string& console, std::string& ret) {
+// Implement a variant of std::string::rfind that is resilient to errors in
+// the data stream being inspected.
+class pstoreConsole {
+ private:
+  const size_t kBitErrorRate = 8;  // number of bits per error
+  const std::string& console;
+
+  // Number of bits that differ between the two arguments l and r.
+  // Returns zero if the values for l and r are identical.
+  size_t numError(uint8_t l, uint8_t r) const { return std::bitset<8>(l ^ r).count(); }
+
+  // A string comparison function, reports the number of errors discovered
+  // in the match to a maximum of the bitLength / kBitErrorRate, at that
+  // point returning npos to indicate match is too poor.
+  //
+  // Since called in rfind which works backwards, expect cache locality will
+  // help if we check in reverse here as well for performance.
+  //
+  // Assumption: l (from console.c_str() + pos) is long enough to house
+  //             _r.length(), checked in rfind caller below.
+  //
+  size_t numError(size_t pos, const std::string& _r) const {
+    const char* l = console.c_str() + pos;
+    const char* r = _r.c_str();
+    size_t n = _r.length();
+    const uint8_t* le = reinterpret_cast<const uint8_t*>(l) + n;
+    const uint8_t* re = reinterpret_cast<const uint8_t*>(r) + n;
+    size_t count = 0;
+    n = 0;
+    do {
+      // individual character bit error rate > threshold + slop
+      size_t num = numError(*--le, *--re);
+      if (num > ((8 + kBitErrorRate) / kBitErrorRate)) return std::string::npos;
+      // total bit error rate > threshold + slop
+      count += num;
+      ++n;
+      if (count > ((n * 8 + kBitErrorRate - (n > 2)) / kBitErrorRate)) {
+        return std::string::npos;
+      }
+    } while (le != reinterpret_cast<const uint8_t*>(l));
+    return count;
+  }
+
+ public:
+  explicit pstoreConsole(const std::string& console) : console(console) {}
+  // scope of argument must be equal to or greater than scope of pstoreConsole
+  explicit pstoreConsole(const std::string&& console) = delete;
+  explicit pstoreConsole(std::string&& console) = delete;
+
+  // Our implementation of rfind, use exact match first, then resort to fuzzy.
+  size_t rfind(const std::string& needle) const {
+    size_t pos = console.rfind(needle);  // exact match?
+    if (pos != std::string::npos) return pos;
+
+    // Check to make sure needle fits in console string.
+    pos = console.length();
+    if (needle.length() > pos) return std::string::npos;
+    pos -= needle.length();
+    // fuzzy match to maximum kBitErrorRate
+    do {
+      if (numError(pos, needle) != std::string::npos) return pos;
+    } while (pos-- != 0);
+    return std::string::npos;
+  }
+
+  // Our implementation of find, use only fuzzy match.
+  size_t find(const std::string& needle, size_t start = 0) const {
+    // Check to make sure needle fits in console string.
+    if (needle.length() > console.length()) return std::string::npos;
+    const size_t last_pos = console.length() - needle.length();
+    // fuzzy match to maximum kBitErrorRate
+    for (size_t pos = start; pos <= last_pos; ++pos) {
+      if (numError(pos, needle) != std::string::npos) return pos;
+    }
+    return std::string::npos;
+  }
+};
+
+// If bit error match to needle, correct it.
+// Return true if any corrections were discovered and applied.
+bool correctForBer(std::string& reason, const std::string& needle) {
+  bool corrected = false;
+  if (reason.length() < needle.length()) return corrected;
+  const pstoreConsole console(reason);
+  const size_t last_pos = reason.length() - needle.length();
+  for (size_t pos = 0; pos <= last_pos; pos += needle.length()) {
+    pos = console.find(needle, pos);
+    if (pos == std::string::npos) break;
+
+    // exact match has no malice
+    if (needle == reason.substr(pos, needle.length())) continue;
+
+    corrected = true;
+    reason = reason.substr(0, pos) + needle + reason.substr(pos + needle.length());
+  }
+  return corrected;
+}
+
+bool addKernelPanicSubReason(const pstoreConsole& console, std::string& ret) {
   // Check for kernel panic types to refine information
   if (console.rfind("SysRq : Trigger a crash") != std::string::npos) {
     // Can not happen, except on userdebug, during testing/debugging.
@@ -343,16 +446,28 @@
   return false;
 }
 
+bool addKernelPanicSubReason(const std::string& content, std::string& ret) {
+  return addKernelPanicSubReason(pstoreConsole(content), ret);
+}
+
 // std::transform Helper callback functions:
 // Converts a string value representing the reason the system booted to a
 // string complying with Android system standard reason.
 char tounderline(char c) {
   return ::isblank(c) ? '_' : c;
 }
+
 char toprintable(char c) {
   return ::isprint(c) ? c : '?';
 }
 
+// Cleanup boot_reason regarding acceptable character set
+void transformReason(std::string& reason) {
+  std::transform(reason.begin(), reason.end(), reason.begin(), ::tolower);
+  std::transform(reason.begin(), reason.end(), reason.begin(), tounderline);
+  std::transform(reason.begin(), reason.end(), reason.begin(), toprintable);
+}
+
 const char system_reboot_reason_property[] = "sys.boot.reason";
 const char last_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY;
 const char bootloader_reboot_reason_property[] = "ro.boot.bootreason";
@@ -366,10 +481,7 @@
   // If sys.boot.reason == ro.boot.bootreason, let's re-evaluate
   if (reason == ret) ret = "";
 
-  // Cleanup boot_reason regarding acceptable character set
-  std::transform(reason.begin(), reason.end(), reason.begin(), ::tolower);
-  std::transform(reason.begin(), reason.end(), reason.begin(), tounderline);
-  std::transform(reason.begin(), reason.end(), reason.begin(), toprintable);
+  transformReason(reason);
 
   // Is the current system boot reason sys.boot.reason valid?
   if (!isKnownRebootReason(ret)) ret = "";
@@ -406,6 +518,7 @@
         {"shutdown,thermal", "thermal"},
         {"warm,s3_wakeup", "s3_wakeup"},
         {"hard,hw_reset", "hw_reset"},
+        {"reboot,2sec", "2sec_reboot"},
         {"bootloader", ""},
     };
 
@@ -441,9 +554,10 @@
     // Check to see if last klog has some refinement hints.
     std::string content;
     if (readPstoreConsole(content)) {
+      const pstoreConsole console(content);
       // The toybox reboot command used directly (unlikely)? But also
       // catches init's response to Android's more controlled reboot command.
-      if (content.rfind("reboot: Power down") != std::string::npos) {
+      if (console.rfind("reboot: Power down") != std::string::npos) {
         ret = "shutdown";  // Still too blunt, but more accurate.
         // ToDo: init should record the shutdown reason to kernel messages ala:
         //           init: shutdown system with command 'last_reboot_reason'
@@ -452,32 +566,46 @@
       }
 
       static const char cmd[] = "reboot: Restarting system with command '";
-      size_t pos = content.rfind(cmd);
+      size_t pos = console.rfind(cmd);
       if (pos != std::string::npos) {
         pos += strlen(cmd);
         std::string subReason(content.substr(pos, max_reason_length));
+        // Correct against any known strings that Bit Error Match
+        for (const auto& s : knownReasons) {
+          correctForBer(subReason, s);
+        }
+        for (const auto& m : kBootReasonMap) {
+          if (m.first.length() <= strlen("cold")) continue;  // too short?
+          if (correctForBer(subReason, m.first + "'")) continue;
+          if (m.first.length() <= strlen("reboot,cold")) continue;  // short?
+          if (!android::base::StartsWith(m.first, "reboot,")) continue;
+          correctForBer(subReason, m.first.substr(strlen("reboot,")) + "'");
+        }
         for (pos = 0; pos < subReason.length(); ++pos) {
-          char c = tounderline(subReason[pos]);
-          if (!::isprint(c) || (c == '\'')) {
+          char c = subReason[pos];
+          // #, &, %, / are common single bit error for ' that we can block
+          if (!::isprint(c) || (c == '\'') || (c == '#') || (c == '&') || (c == '%') || (c == '/')) {
             subReason.erase(pos);
             break;
           }
-          subReason[pos] = ::tolower(c);
         }
+        transformReason(subReason);
         if (subReason != "") {  // Will not land "reboot" as that is too blunt.
           if (isKernelRebootReason(subReason)) {
             ret = "reboot," + subReason;  // User space can't talk kernel reasons.
-          } else {
+          } else if (isKnownRebootReason(subReason)) {
             ret = subReason;
+          } else {
+            ret = "reboot," + subReason;  // legitimize unknown reasons
           }
         }
       }
 
       // Check for kernel panics, allowed to override reboot command.
-      if (!addKernelPanicSubReason(content, ret) &&
+      if (!addKernelPanicSubReason(console, ret) &&
           // check for long-press power down
-          ((content.rfind("Power held for ") != std::string::npos) ||
-           (content.rfind("charger: [") != std::string::npos))) {
+          ((console.rfind("Power held for ") != std::string::npos) ||
+           (console.rfind("charger: [") != std::string::npos))) {
         ret = "cold";
       }
     }
@@ -493,14 +621,33 @@
       // Really a hail-mary pass to find it in last klog content ...
       static const int battery_dead_threshold = 2;  // percent
       static const char battery[] = "healthd: battery l=";
-      size_t pos = content.rfind(battery);  // last one
+      const pstoreConsole console(content);
+      size_t pos = console.rfind(battery);  // last one
       std::string digits;
       if (pos != std::string::npos) {
-        digits = content.substr(pos + strlen(battery));
+        digits = content.substr(pos + strlen(battery), strlen("100 "));
+        // correct common errors
+        correctForBer(digits, "100 ");
+        if (digits[0] == '!') digits[0] = '1';
+        if (digits[1] == '!') digits[1] = '1';
       }
-      char* endptr = NULL;
-      unsigned long long level = strtoull(digits.c_str(), &endptr, 10);
-      if ((level <= 100) && (endptr != digits.c_str()) && (*endptr == ' ')) {
+      const char* endptr = digits.c_str();
+      unsigned level = 0;
+      while (::isdigit(*endptr)) {
+        level *= 10;
+        level += *endptr++ - '0';
+        // make sure no leading zeros, except zero itself, and range check.
+        if ((level == 0) || (level > 100)) break;
+      }
+      // example bit error rate issues for 10%
+      //   'l=10 ' no bits in error
+      //   'l=00 ' single bit error (fails above)
+      //   'l=1  ' single bit error
+      //   'l=0  ' double bit error
+      // There are others, not typically critical because of 2%
+      // battery_dead_threshold. KISS check, make sure second
+      // character after digit sequence is not a space.
+      if ((level <= 100) && (endptr != digits.c_str()) && (endptr[0] == ' ') && (endptr[1] != ' ')) {
         LOG(INFO) << "Battery level at shutdown " << level << "%";
         if (level <= battery_dead_threshold) {
           ret = "shutdown,battery";
@@ -540,10 +687,16 @@
 
         pos = content.find(match);  // The first one it finds.
         if (pos != std::string::npos) {
-          digits = content.substr(pos + strlen(match));
+          digits = content.substr(pos + strlen(match), strlen("100 "));
         }
-        endptr = NULL;
-        level = strtoull(digits.c_str(), &endptr, 10);
+        endptr = digits.c_str();
+        level = 0;
+        while (::isdigit(*endptr)) {
+          level *= 10;
+          level += *endptr++ - '0';
+          // make sure no leading zeros, except zero itself, and range check.
+          if ((level == 0) || (level > 100)) break;
+        }
         if ((level <= 100) && (endptr != digits.c_str()) && (*endptr == ' ')) {
           LOG(INFO) << "Battery level at startup " << level << "%";
           if (level <= battery_dead_threshold) {
@@ -560,10 +713,7 @@
       // Content buffer no longer will have console data. Beware if more
       // checks added below, that depend on parsing console content.
       content = GetProperty(last_reboot_reason_property);
-      // Cleanup last_boot_reason regarding acceptable character set
-      std::transform(content.begin(), content.end(), content.begin(), ::tolower);
-      std::transform(content.begin(), content.end(), content.begin(), tounderline);
-      std::transform(content.begin(), content.end(), content.begin(), toprintable);
+      transformReason(content);
 
       // Anything in last is better than 'super-blunt' reboot or shutdown.
       if ((ret == "") || (ret == "reboot") || (ret == "shutdown") || !isBluntRebootReason(content)) {
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 2b5f4f6..17a9f3a 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -193,7 +193,6 @@
         "libdebuggerd/test/elf_fake.cpp",
         "libdebuggerd/test/log_fake.cpp",
         "libdebuggerd/test/open_files_list_test.cpp",
-        "libdebuggerd/test/property_fake.cpp",
         "libdebuggerd/test/ptrace_fake.cpp",
         "libdebuggerd/test/tombstone_test.cpp",
     ],
diff --git a/debuggerd/NOTICE b/debuggerd/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/debuggerd/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
-   Copyright (c) 2005-2008, The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-
-   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.
-
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 6ef3ed6..827420e 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -348,11 +348,6 @@
       LOG(FATAL) << "failed to create backtrace map";
     }
   }
-  std::unique_ptr<BacktraceMap> backtrace_map_new;
-  backtrace_map_new.reset(BacktraceMap::CreateNew(main_tid));
-  if (!backtrace_map_new) {
-    LOG(FATAL) << "failed to create backtrace map new";
-  }
 
   // Collect the list of open files.
   OpenFilesList open_files;
@@ -432,9 +427,8 @@
     dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, process_name, threads, 0);
   } else {
     ATRACE_NAME("engrave_tombstone");
-    engrave_tombstone(output_fd.get(), backtrace_map.get(), backtrace_map_new.get(), &open_files,
-                      target, main_tid, process_name, threads, abort_address,
-                      fatal_signal ? &amfd_data : nullptr);
+    engrave_tombstone(output_fd.get(), backtrace_map.get(), &open_files, target, main_tid,
+                      process_name, threads, abort_address, fatal_signal ? &amfd_data : nullptr);
   }
 
   // We don't actually need to PTRACE_DETACH, as long as our tracees aren't in
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
index 45740df..79743b6 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
@@ -35,10 +35,10 @@
 int open_tombstone(std::string* path);
 
 /* Creates a tombstone file and writes the crash dump to it. */
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map, BacktraceMap* map_new,
-                       const OpenFilesList* open_files, pid_t pid, pid_t tid,
-                       const std::string& process_name, const std::map<pid_t, std::string>& threads,
-                       uintptr_t abort_msg_address, std::string* amfd_data);
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files,
+                       pid_t pid, pid_t tid, const std::string& process_name,
+                       const std::map<pid_t, std::string>& threads, uintptr_t abort_msg_address,
+                       std::string* amfd_data);
 
 void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
                                 ucontext_t* ucontext);
diff --git a/debuggerd/libdebuggerd/test/property_fake.cpp b/debuggerd/libdebuggerd/test/property_fake.cpp
deleted file mode 100644
index 02069f1..0000000
--- a/debuggerd/libdebuggerd/test/property_fake.cpp
+++ /dev/null
@@ -1,45 +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 <string.h>
-
-#include <string>
-#include <unordered_map>
-
-#include <sys/system_properties.h>
-
-std::unordered_map<std::string, std::string> g_properties;
-
-extern "C" int property_set(const char* name, const char* value) {
-  if (g_properties.count(name) != 0) {
-    g_properties.erase(name);
-  }
-  g_properties[name] = value;
-  return 0;
-}
-
-extern "C" int property_get(const char* key, char* value, const char* default_value) {
-  if (g_properties.count(key) == 0) {
-    if (default_value == nullptr) {
-      return 0;
-    }
-    strncpy(value, default_value, PROP_VALUE_MAX-1);
-  } else {
-    strncpy(value, g_properties[key].c_str(), PROP_VALUE_MAX-1);
-  }
-  value[PROP_VALUE_MAX-1] = '\0';
-  return strlen(value);
-}
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index 934ceba..59a43b7 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -19,8 +19,9 @@
 #include <memory>
 #include <string>
 
-#include <gtest/gtest.h>
 #include <android-base/file.h>
+#include <android-base/properties.h>
+#include <gtest/gtest.h>
 
 #include "libdebuggerd/utility.h"
 
@@ -639,7 +640,10 @@
 TEST_F(TombstoneTest, dump_header_info) {
   dump_header_info(&log_);
 
-  std::string expected = "Build fingerprint: 'unknown'\nRevision: 'unknown'\n";
+  std::string expected = android::base::StringPrintf(
+      "Build fingerprint: '%s'\nRevision: '%s'\n",
+      android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
+      android::base::GetProperty("ro.revision", "unknown").c_str());
   expected += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
   ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
 }
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 6fb29a9..725c42c 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -496,55 +496,8 @@
   _LOG(log, logtype::REGISTERS, "    register dumping unimplemented on this architecture");
 }
 
-static bool verify_backtraces_equal(Backtrace* back1, Backtrace* back2) {
-  if (back1->NumFrames() != back2->NumFrames()) {
-    return false;
-  }
-  std::string back1_str;
-  std::string back2_str;
-  for (size_t i = 0; i < back1->NumFrames(); i++) {
-    back1_str += back1->FormatFrameData(i);
-    back2_str += back2->FormatFrameData(i);
-  }
-  return back1_str == back2_str;
-}
-
-static void log_mismatch_data(log_t* log, Backtrace* backtrace) {
-  _LOG(log, logtype::THREAD, "MISMATCH: This unwind is different.\n");
-  if (backtrace->NumFrames() == 0) {
-    _LOG(log, logtype::THREAD, "MISMATCH: No frames in new backtrace.\n");
-    return;
-  }
-  _LOG(log, logtype::THREAD, "MISMATCH: Backtrace from new unwinder.\n");
-  for (size_t i = 0; i < backtrace->NumFrames(); i++) {
-    _LOG(log, logtype::THREAD, "MISMATCH: %s\n", backtrace->FormatFrameData(i).c_str());
-  }
-
-  // Get the stack trace up to 8192 bytes.
-  std::vector<uint64_t> buffer(8192 / sizeof(uint64_t));
-  size_t bytes =
-      backtrace->Read(backtrace->GetFrame(0)->sp, reinterpret_cast<uint8_t*>(buffer.data()),
-                      buffer.size() * sizeof(uint64_t));
-  std::string log_data;
-  for (size_t i = 0; i < bytes / sizeof(uint64_t); i++) {
-    if ((i % 4) == 0) {
-      if (!log_data.empty()) {
-        _LOG(log, logtype::THREAD, "MISMATCH: stack_data%s\n", log_data.c_str());
-        log_data = "";
-      }
-    }
-    log_data += android::base::StringPrintf(" 0x%016" PRIx64, buffer[i]);
-  }
-
-  if (!log_data.empty()) {
-    _LOG(log, logtype::THREAD, "MISMATCH: data%s\n", log_data.c_str());
-  }
-
-  // If there is any leftover (bytes % sizeof(uint64_t) != 0, ignore it for now.
-}
-
-static bool dump_thread(log_t* log, pid_t pid, pid_t tid, const std::string& process_name,
-                        const std::string& thread_name, BacktraceMap* map, BacktraceMap* map_new,
+static void dump_thread(log_t* log, pid_t pid, pid_t tid, const std::string& process_name,
+                        const std::string& thread_name, BacktraceMap* map,
                         uintptr_t abort_msg_address, bool primary_thread) {
   log->current_tid = tid;
   if (!primary_thread) {
@@ -558,18 +511,7 @@
     dump_abort_message(backtrace.get(), log, abort_msg_address);
   }
   dump_registers(log, tid);
-  bool matches = true;
   if (backtrace->Unwind(0)) {
-    // Use the new method and verify it is the same as old.
-    std::unique_ptr<Backtrace> backtrace_new(Backtrace::CreateNew(pid, tid, map_new));
-    if (!backtrace_new->Unwind(0)) {
-      _LOG(log, logtype::THREAD, "Failed to unwind with new unwinder: %s\n",
-           backtrace_new->GetErrorString(backtrace_new->GetError()).c_str());
-      matches = false;
-    } else if (!verify_backtraces_equal(backtrace.get(), backtrace_new.get())) {
-      log_mismatch_data(log, backtrace_new.get());
-      matches = false;
-    }
     dump_backtrace_and_stack(backtrace.get(), log);
   } else {
     ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
@@ -583,8 +525,6 @@
   }
 
   log->current_tid = log->crashed_tid;
-
-  return matches;
 }
 
 // Reads the contents of the specified log device, filters out the entries
@@ -718,18 +658,16 @@
 }
 
 // Dumps all information about the specified pid to the tombstone.
-static void dump_crash(log_t* log, BacktraceMap* map, BacktraceMap* map_new,
-                       const OpenFilesList* open_files, pid_t pid, pid_t tid,
-                       const std::string& process_name, const std::map<pid_t, std::string>& threads,
-                       uintptr_t abort_msg_address) {
+static void dump_crash(log_t* log, BacktraceMap* map, const OpenFilesList* open_files, pid_t pid,
+                       pid_t tid, const std::string& process_name,
+                       const std::map<pid_t, std::string>& threads, uintptr_t abort_msg_address) {
   // don't copy log messages to tombstone unless this is a dev device
   bool want_logs = GetBoolProperty("ro.debuggable", false);
 
   _LOG(log, logtype::HEADER,
        "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
   dump_header_info(log);
-  bool new_unwind_matches = dump_thread(log, pid, tid, process_name, threads.find(tid)->second, map,
-                                        map_new, abort_msg_address, true);
+  dump_thread(log, pid, tid, process_name, threads.find(tid)->second, map, abort_msg_address, true);
   if (want_logs) {
     dump_logs(log, pid, 5);
   }
@@ -739,9 +677,7 @@
     const std::string& thread_name = it.second;
 
     if (thread_tid != tid) {
-      bool match =
-          dump_thread(log, pid, thread_tid, process_name, thread_name, map, map_new, 0, false);
-      new_unwind_matches = new_unwind_matches && match;
+      dump_thread(log, pid, thread_tid, process_name, thread_name, map, 0, false);
     }
   }
 
@@ -753,26 +689,18 @@
   if (want_logs) {
     dump_logs(log, pid, 0);
   }
-  if (!new_unwind_matches) {
-    _LOG(log, logtype::THREAD, "MISMATCH: New and old unwinder do not agree.\n");
-    _LOG(log, logtype::THREAD, "MISMATCH: If you see this please file a bug in:\n");
-    _LOG(log, logtype::THREAD,
-         "MISMATCH: Android > Android OS & Apps > Runtime > native > tools "
-         "(debuggerd/gdb/init/simpleperf/strace/valgrind)\n");
-    _LOG(log, logtype::THREAD, "MISMATCH: and attach this tombstone.\n");
-  }
 }
 
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map, BacktraceMap* map_new,
-                       const OpenFilesList* open_files, pid_t pid, pid_t tid,
-                       const std::string& process_name, const std::map<pid_t, std::string>& threads,
-                       uintptr_t abort_msg_address, std::string* amfd_data) {
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files,
+                       pid_t pid, pid_t tid, const std::string& process_name,
+                       const std::map<pid_t, std::string>& threads, uintptr_t abort_msg_address,
+                       std::string* amfd_data) {
   log_t log;
   log.current_tid = tid;
   log.crashed_tid = tid;
   log.tfd = tombstone_fd;
   log.amfd_data = amfd_data;
-  dump_crash(&log, map, map_new, open_files, pid, tid, process_name, threads, abort_msg_address);
+  dump_crash(&log, map, open_files, pid, tid, process_name, threads, abort_msg_address);
 }
 
 void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
diff --git a/debuggerd/signal_sender.cpp b/debuggerd/signal_sender.cpp
deleted file mode 100644
index 42a8e77..0000000
--- a/debuggerd/signal_sender.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "debuggerd-signal"
-
-#include <errno.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include "signal_sender.h"
-
-static int signal_fd = -1;
-static pid_t signal_pid;
-struct signal_message {
-  pid_t pid;
-  pid_t tid;
-  int signal;
-};
-
-static void set_signal_sender_process_name() {
-#if defined(__LP64__)
-  static constexpr char long_process_name[] = "debuggerd64:signaller";
-  static constexpr char short_process_name[] = "debuggerd64:sig";
-  static_assert(sizeof(long_process_name) <= sizeof("/system/bin/debuggerd64"), "");
-#else
-  static constexpr char long_process_name[] = "debuggerd:signaller";
-  static constexpr char short_process_name[] = "debuggerd:sig";
-  static_assert(sizeof(long_process_name) <= sizeof("/system/bin/debuggerd"), "");
-#endif
-
-  // pthread_setname_np has a maximum length of 16 chars, including null terminator.
-  static_assert(sizeof(short_process_name) <= 16, "");
-  pthread_setname_np(pthread_self(), short_process_name);
-
-  char* progname = const_cast<char*>(getprogname());
-  if (strlen(progname) <= strlen(long_process_name)) {
-    ALOGE("debuggerd: unexpected progname %s", progname);
-    return;
-  }
-
-  memset(progname, 0, strlen(progname));
-  strcpy(progname, long_process_name);
-}
-
-// Fork a process to send signals for the worker processes to use after they've dropped privileges.
-bool start_signal_sender() {
-  if (signal_pid != 0) {
-    ALOGE("debuggerd: attempted to start signal sender multiple times");
-    return false;
-  }
-
-  int sfd[2];
-  if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sfd) != 0) {
-    ALOGE("debuggerd: failed to create socketpair for signal sender: %s", strerror(errno));
-    return false;
-  }
-
-  pid_t parent = getpid();
-  pid_t fork_pid = fork();
-  if (fork_pid == -1) {
-    ALOGE("debuggerd: failed to initialize signal sender: fork failed: %s", strerror(errno));
-    return false;
-  } else if (fork_pid == 0) {
-    close(sfd[1]);
-
-    set_signal_sender_process_name();
-
-    while (true) {
-      signal_message msg;
-      int rc = TEMP_FAILURE_RETRY(read(sfd[0], &msg, sizeof(msg)));
-      if (rc < 0) {
-        ALOGE("debuggerd: signal sender failed to read from socket");
-        break;
-      } else if (rc != sizeof(msg)) {
-        ALOGE("debuggerd: signal sender read unexpected number of bytes: %d", rc);
-        break;
-      }
-
-      // Report success after sending a signal
-      int err = 0;
-      if (msg.tid > 0) {
-        if (syscall(SYS_tgkill, msg.pid, msg.tid, msg.signal) != 0) {
-          err = errno;
-        }
-      } else {
-        if (kill(msg.pid, msg.signal) != 0) {
-          err = errno;
-        }
-      }
-
-      if (TEMP_FAILURE_RETRY(write(sfd[0], &err, sizeof(err))) < 0) {
-        ALOGE("debuggerd: signal sender failed to write: %s", strerror(errno));
-      }
-    }
-
-    // Our parent proably died, but if not, kill them.
-    if (getppid() == parent) {
-      kill(parent, SIGKILL);
-    }
-    _exit(1);
-  } else {
-    close(sfd[0]);
-    signal_fd = sfd[1];
-    signal_pid = fork_pid;
-    return true;
-  }
-}
-
-bool stop_signal_sender() {
-  if (signal_pid <= 0) {
-    return false;
-  }
-
-  if (kill(signal_pid, SIGKILL) != 0) {
-    ALOGE("debuggerd: failed to kill signal sender: %s", strerror(errno));
-    return false;
-  }
-
-  close(signal_fd);
-  signal_fd = -1;
-
-  int status;
-  waitpid(signal_pid, &status, 0);
-  signal_pid = 0;
-
-  return true;
-}
-
-bool send_signal(pid_t pid, pid_t tid, int signal) {
-  if (signal_fd == -1) {
-    ALOGE("debuggerd: attempted to send signal before signal sender was started");
-    errno = EHOSTUNREACH;
-    return false;
-  }
-
-  signal_message msg = {.pid = pid, .tid = tid, .signal = signal };
-  if (TEMP_FAILURE_RETRY(write(signal_fd, &msg, sizeof(msg))) < 0) {
-    ALOGE("debuggerd: failed to send message to signal sender: %s", strerror(errno));
-    errno = EHOSTUNREACH;
-    return false;
-  }
-
-  int response;
-  ssize_t rc = TEMP_FAILURE_RETRY(read(signal_fd, &response, sizeof(response)));
-  if (rc == 0) {
-    ALOGE("debuggerd: received EOF from signal sender");
-    errno = EHOSTUNREACH;
-    return false;
-  } else if (rc < 0) {
-    ALOGE("debuggerd: failed to receive response from signal sender: %s", strerror(errno));
-    errno = EHOSTUNREACH;
-    return false;
-  }
-
-  if (response == 0) {
-    return true;
-  }
-
-  errno = response;
-  return false;
-}
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 5f2267c..c3b1bfb 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -444,13 +444,13 @@
                                  const char* cmdline) {
     int64_t ksize;
     void* kdata = load_file(kernel.c_str(), &ksize);
-    if (kdata == nullptr) die("cannot load '%s': %s\n", kernel.c_str(), strerror(errno));
+    if (kdata == nullptr) die("cannot load '%s': %s", kernel.c_str(), strerror(errno));
 
     // Is this actually a boot image?
     if (!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
         if (cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
 
-        if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk\n");
+        if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk");
 
         *sz = ksize;
         return kdata;
@@ -460,14 +460,14 @@
     int64_t rsize = 0;
     if (!ramdisk.empty()) {
         rdata = load_file(ramdisk.c_str(), &rsize);
-        if (rdata == nullptr) die("cannot load '%s': %s\n", ramdisk.c_str(), strerror(errno));
+        if (rdata == nullptr) die("cannot load '%s': %s", ramdisk.c_str(), strerror(errno));
     }
 
     void* sdata = nullptr;
     int64_t ssize = 0;
     if (!second_stage.empty()) {
         sdata = load_file(second_stage.c_str(), &ssize);
-        if (sdata == nullptr) die("cannot load '%s': %s\n", second_stage.c_str(), strerror(errno));
+        if (sdata == nullptr) die("cannot load '%s': %s", second_stage.c_str(), strerror(errno));
     }
 
     fprintf(stderr,"creating boot image...\n");
@@ -476,7 +476,7 @@
                       rdata, rsize, ramdisk_offset,
                       sdata, ssize, second_offset,
                       page_size, base_addr, tags_offset, &bsize);
-    if (bdata == nullptr) die("failed to create boot.img\n");
+    if (bdata == nullptr) die("failed to create boot.img");
 
     if (cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline);
     fprintf(stderr, "creating boot image - %" PRId64 " bytes\n", bsize);
@@ -490,24 +490,17 @@
     ZipEntry zip_entry;
     if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
         fprintf(stderr, "archive does not contain '%s'\n", entry_name);
-        return 0;
+        return nullptr;
     }
 
     *sz = zip_entry.uncompressed_length;
 
     fprintf(stderr, "extracting %s (%" PRId64 " MB)...\n", entry_name, *sz / 1024 / 1024);
     uint8_t* data = reinterpret_cast<uint8_t*>(malloc(zip_entry.uncompressed_length));
-    if (data == nullptr) {
-        fprintf(stderr, "failed to allocate %" PRId64 " bytes for '%s'\n", *sz, entry_name);
-        return 0;
-    }
+    if (data == nullptr) die("failed to allocate %" PRId64 " bytes for '%s'", *sz, entry_name);
 
     int error = ExtractToMemory(zip, &zip_entry, data, zip_entry.uncompressed_length);
-    if (error != 0) {
-        fprintf(stderr, "failed to extract '%s': %s\n", entry_name, ErrorCodeString(error));
-        free(data);
-        return 0;
-    }
+    if (error != 0) die("failed to extract '%s': %s", entry_name, ErrorCodeString(error));
 
     return data;
 }
@@ -524,14 +517,12 @@
     char temp_path[PATH_MAX];
     DWORD nchars = GetTempPath(sizeof(temp_path), temp_path);
     if (nchars == 0 || nchars >= sizeof(temp_path)) {
-        fprintf(stderr, "GetTempPath failed, error %ld\n", GetLastError());
-        return nullptr;
+        die("GetTempPath failed, error %ld", GetLastError());
     }
 
     char filename[PATH_MAX];
     if (GetTempFileName(temp_path, "fastboot", 0, filename) == 0) {
-        fprintf(stderr, "GetTempFileName failed, error %ld\n", GetLastError());
-        return nullptr;
+        die("GetTempFileName failed, error %ld", GetLastError());
     }
 
     return fopen(filename, "w+bTD");
@@ -540,8 +531,7 @@
 #define tmpfile win32_tmpfile
 
 static std::string make_temporary_directory() {
-    fprintf(stderr, "make_temporary_directory not supported under Windows, sorry!");
-    return "";
+    die("make_temporary_directory not supported under Windows, sorry!");
 }
 
 static int make_temporary_fd() {
@@ -613,9 +603,7 @@
 static int unzip_to_file(ZipArchiveHandle zip, const char* entry_name) {
     unique_fd fd(make_temporary_fd());
     if (fd == -1) {
-        fprintf(stderr, "failed to create temporary file for '%s': %s\n",
-                entry_name, strerror(errno));
-        return -1;
+        die("failed to create temporary file for '%s': %s", entry_name, strerror(errno));
     }
 
     ZipString zip_entry_name(entry_name);
@@ -629,12 +617,13 @@
             zip_entry.uncompressed_length / 1024 / 1024);
     int error = ExtractEntryToFile(zip, &zip_entry, fd);
     if (error != 0) {
-        fprintf(stderr, "failed to extract '%s': %s\n", entry_name, ErrorCodeString(error));
-        return -1;
+        die("failed to extract '%s': %s", entry_name, ErrorCodeString(error));
     }
 
-    lseek(fd, 0, SEEK_SET);
-    // TODO: We're leaking 'fp' here.
+    if (lseek(fd, 0, SEEK_SET) != 0) {
+        die("lseek on extracted file '%s' failed: %s", entry_name, strerror(errno));
+    }
+
     return fd.release();
 }
 
@@ -738,27 +727,18 @@
     fb_queue_notice("--------------------------------------------");
 }
 
-static struct sparse_file **load_sparse_files(int fd, int max_size)
-{
+static struct sparse_file** load_sparse_files(int fd, int max_size) {
     struct sparse_file* s = sparse_file_import_auto(fd, false, true);
-    if (!s) {
-        die("cannot sparse read file\n");
-    }
+    if (!s) die("cannot sparse read file");
 
     int files = sparse_file_resparse(s, max_size, nullptr, 0);
-    if (files < 0) {
-        die("Failed to resparse\n");
-    }
+    if (files < 0) die("Failed to resparse");
 
     sparse_file** out_s = reinterpret_cast<sparse_file**>(calloc(sizeof(struct sparse_file *), files + 1));
-    if (!out_s) {
-        die("Failed to allocate sparse file array\n");
-    }
+    if (!out_s) die("Failed to allocate sparse file array");
 
     files = sparse_file_resparse(s, max_size, out_s, files);
-    if (files < 0) {
-        die("Failed to resparse\n");
-    }
+    if (files < 0) die("Failed to resparse");
 
     return out_s;
 }
@@ -1017,18 +997,18 @@
             if (count > 0) {
                 return "a";
             } else {
-                die("No known slots.");
+                die("No known slots");
             }
         }
     }
 
     int count = get_slot_count(transport);
-    if (count == 0) die("Device does not support slots.\n");
+    if (count == 0) die("Device does not support slots");
 
     if (slot == "other") {
         std::string other = get_other_slot(transport, count);
         if (other == "") {
-           die("No known slots.");
+           die("No known slots");
         }
         return other;
     }
@@ -1060,7 +1040,7 @@
         if (slot == "") {
             current_slot = get_current_slot(transport);
             if (current_slot == "") {
-                die("Failed to identify current slot.\n");
+                die("Failed to identify current slot");
             }
             func(part + "_" + current_slot);
         } else {
@@ -1086,7 +1066,7 @@
 
     if (slot == "all") {
         if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) {
-            die("Could not check if partition %s has slot.", part.c_str());
+            die("Could not check if partition %s has slot %s", part.c_str(), slot.c_str());
         }
         if (has_slot == "yes") {
             for (int i=0; i < get_slot_count(transport); i++) {
@@ -1146,14 +1126,12 @@
     ZipArchiveHandle zip;
     int error = OpenArchive(filename, &zip);
     if (error != 0) {
-        CloseArchive(zip);
         die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
     }
 
     int64_t sz;
     void* data = unzip_file(zip, "android-info.txt", &sz);
     if (data == nullptr) {
-        CloseArchive(zip);
         die("update package '%s' has no android-info.txt", filename);
     }
 
@@ -1186,17 +1164,17 @@
         int fd = unzip_to_file(zip, images[i].img_name);
         if (fd == -1) {
             if (images[i].is_optional) {
-                continue;
+                continue; // An optional file is missing, so ignore it.
             }
-            CloseArchive(zip);
-            exit(1); // unzip_to_file already explained why.
+            die("non-optional file %s missing", images[i].img_name);
         }
+
         fastboot_buffer buf;
         if (!load_buf_fd(transport, fd, &buf)) {
             die("cannot load %s from flash: %s", images[i].img_name, strerror(errno));
         }
 
-        auto update = [&](const std::string &partition) {
+        auto update = [&](const std::string& partition) {
             do_update_signature(zip, images[i].sig_name);
             if (erase_first && needs_erase(transport, partition.c_str())) {
                 fb_queue_erase(partition.c_str());
@@ -1210,12 +1188,13 @@
         do_for_partitions(transport, images[i].part_name, slot, update, false);
     }
 
-    CloseArchive(zip);
     if (slot_override == "all") {
         set_active(transport, "a");
     } else {
         set_active(transport, slot_override);
     }
+
+    CloseArchive(zip);
 }
 
 static void do_send_signature(const std::string& fn) {
@@ -1274,7 +1253,7 @@
         fastboot_buffer buf;
         if (!load_buf(transport, fname.c_str(), &buf)) {
             if (images[i].is_optional) continue;
-            die("could not load '%s': %s\n", images[i].img_name, strerror(errno));
+            die("could not load '%s': %s", images[i].img_name, strerror(errno));
         }
 
         auto flashall = [&](const std::string &partition) {
@@ -1463,7 +1442,7 @@
 
     if (fs_generator_generate(gen, output.path, size, initial_dir,
             eraseBlkSize, logicalBlkSize)) {
-        die("Cannot generate image for %s\n", partition);
+        die("Cannot generate image for %s", partition);
         return;
     }
 
@@ -1583,9 +1562,7 @@
             break;
         case 'S':
             sparse_limit = parse_num(optarg);
-            if (sparse_limit < 0) {
-                    die("invalid sparse limit");
-            }
+            if (sparse_limit < 0) die("invalid sparse limit");
             break;
         case 'u':
             erase_first = false;
@@ -1718,7 +1695,7 @@
             std::string filename = next_arg(&args);
             data = load_file(filename.c_str(), &sz);
             if (data == nullptr) die("could not load '%s': %s", filename.c_str(), strerror(errno));
-            if (sz != 256) die("signature must be 256 bytes");
+            if (sz != 256) die("signature must be 256 bytes (got %" PRId64 ")", sz);
             fb_queue_download("signature", data, sz);
             fb_queue_command("signature", "installing signature");
         } else if (command == "reboot") {
diff --git a/init/service.cpp b/init/service.cpp
index 765b61e..12acfc6 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -101,8 +101,22 @@
 
     // It's OK to LOG(FATAL) in this function since it's running in the first
     // child process.
-    if (mount("", "/proc", "proc", kSafeFlags | MS_REMOUNT, "") == -1) {
-        PLOG(FATAL) << "couldn't remount(/proc) for " << service_name;
+
+    // Recursively remount / as slave like zygote does so unmounting and mounting /proc
+    // doesn't interfere with the parent namespace's /proc mount. This will also
+    // prevent any other mounts/unmounts initiated by the service from interfering
+    // with the parent namespace but will still allow mount events from the parent
+    // namespace to propagate to the child.
+    if (mount("rootfs", "/", nullptr, (MS_SLAVE | MS_REC), nullptr) == -1) {
+        PLOG(FATAL) << "couldn't remount(/) recursively as slave for " << service_name;
+    }
+    // umount() then mount() /proc.
+    // Note that it is not sufficient to mount with MS_REMOUNT.
+    if (umount("/proc") == -1) {
+        PLOG(FATAL) << "couldn't umount(/proc) for " << service_name;
+    }
+    if (mount("", "/proc", "proc", kSafeFlags, "") == -1) {
+        PLOG(FATAL) << "couldn't mount(/proc) for " << service_name;
     }
 
     if (prctl(PR_SET_NAME, service_name.c_str()) == -1) {
@@ -706,14 +720,20 @@
 }
 
 Result<Success> Service::Start() {
+    bool disabled = (flags_ & (SVC_DISABLED | SVC_RESET));
     // Starting a service removes it from the disabled or reset state and
     // immediately takes it out of the restarting state if it was in there.
     flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
 
     // Running processes require no additional work --- if they're in the
     // process of exiting, we've ensured that they will immediately restart
-    // on exit, unless they are ONESHOT.
+    // on exit, unless they are ONESHOT. For ONESHOT service, if it's in
+    // stopping status, we just set SVC_RESTART flag so it will get restarted
+    // in Reap().
     if (flags_ & SVC_RUNNING) {
+        if ((flags_ & SVC_ONESHOT) && disabled) {
+            flags_ |= SVC_RESTART;
+        }
         // It is not an error to try to start a service that is already running.
         return Success();
     }
@@ -940,6 +960,13 @@
     } else {
         flags_ |= how;
     }
+    // Make sure it's in right status when a restart immediately follow a
+    // stop/reset or vice versa.
+    if (how == SVC_RESTART) {
+        flags_ &= (~(SVC_DISABLED | SVC_RESET));
+    } else {
+        flags_ &= (~SVC_RESTART);
+    }
 
     if (pid_) {
         KillProcessGroup(SIGKILL);
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index b2c0c0f..0b2ce1d 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -73,6 +73,10 @@
     defaults: ["libbacktrace_common"],
     host_supported: true,
 
+    cflags: [
+        "-Wexit-time-destructors",
+    ],
+
     srcs: [
         "BacktraceMap.cpp",
     ],
@@ -230,5 +234,6 @@
     shared_libs: [
         "libbacktrace",
         "libbase",
+        "libunwindstack",
     ],
 }
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index afe518c..e18dbf3 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <assert.h>
 #include <inttypes.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -136,34 +135,6 @@
   }
 
   if (pid == getpid()) {
-    return new UnwindCurrent(pid, tid, map);
-  } else {
-    return new UnwindPtrace(pid, tid, map);
-  }
-}
-
-Backtrace* Backtrace::CreateNew(pid_t pid, pid_t tid, BacktraceMap* map) {
-  if (pid == BACKTRACE_CURRENT_PROCESS) {
-    pid = getpid();
-    if (tid == BACKTRACE_CURRENT_THREAD) {
-      tid = gettid();
-    }
-  } else if (tid == BACKTRACE_CURRENT_THREAD) {
-    tid = pid;
-  }
-
-  if (map == nullptr) {
-// This would cause the wrong type of map object to be created, so disallow.
-#if defined(__ANDROID__)
-    __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__,
-              "Backtrace::CreateNew() must be called with a real map pointer.");
-#else
-    BACK_LOGE("Backtrace::CreateNew() must be called with a real map pointer.");
-    abort();
-#endif
-  }
-
-  if (pid == getpid()) {
     return new UnwindStackCurrent(pid, tid, map);
   } else {
     return new UnwindStackPtrace(pid, tid, map);
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index 0b8232b..3cab0d1 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -146,24 +146,3 @@
     }
   }
 }
-
-//-------------------------------------------------------------------------
-// BacktraceMap create function.
-//-------------------------------------------------------------------------
-BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) {
-  BacktraceMap* map;
-
-  if (uncached) {
-    // Force use of the base class to parse the maps when this call is made.
-    map = new BacktraceMap(pid);
-  } else if (pid == getpid()) {
-    map = new UnwindMapLocal();
-  } else {
-    map = new UnwindMapRemote(pid);
-  }
-  if (!map->Build()) {
-    delete map;
-    return nullptr;
-  }
-  return map;
-}
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index c3f08c8..d17c211 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -45,7 +45,7 @@
 
 bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
                        std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames) {
-  static std::vector<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"};
+  std::vector<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"};
   UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
   auto process_memory = stack_map->process_memory();
   unwindstack::Unwinder unwinder(MAX_BACKTRACE_FRAMES + num_ignore_frames, stack_map->stack_maps(),
@@ -64,7 +64,7 @@
     auto frame = &unwinder_frames[i];
     backtrace_frame_data_t* back_frame = &frames->at(cur_frame);
 
-    back_frame->num = frame->num;
+    back_frame->num = frame->num - num_ignore_frames;
 
     back_frame->rel_pc = frame->rel_pc;
     back_frame->pc = frame->pc;
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index e7e5e4c..25e5002 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -103,7 +103,7 @@
 //-------------------------------------------------------------------------
 // BacktraceMap create function.
 //-------------------------------------------------------------------------
-BacktraceMap* BacktraceMap::CreateNew(pid_t pid, bool uncached) {
+BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) {
   BacktraceMap* map;
 
   if (uncached) {
diff --git a/libbacktrace/backtrace_benchmarks.cpp b/libbacktrace/backtrace_benchmarks.cpp
index aa1662f..bb4134f 100644
--- a/libbacktrace/backtrace_benchmarks.cpp
+++ b/libbacktrace/backtrace_benchmarks.cpp
@@ -32,13 +32,13 @@
 
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
+#include <unwindstack/Memory.h>
 
 // Definitions of prctl arguments to set a vma name in Android kernels.
 #define ANDROID_PR_SET_VMA 0x53564d41
 #define ANDROID_PR_SET_VMA_ANON_NAME 0
 
 constexpr size_t kNumMaps = 2000;
-constexpr size_t kNumIterations = 1000;
 
 static bool CountMaps(pid_t pid, size_t* num_maps) {
   // Minimize the calls that might allocate memory. If too much memory
@@ -132,14 +132,12 @@
   }
 
   while (state.KeepRunning()) {
-    for (size_t i = 0; i < static_cast<size_t>(state.range(0)); i++) {
-      BacktraceMap* map = map_func(pid, false);
-      if (map == nullptr) {
-        fprintf(stderr, "Failed to create map\n");
-        return;
-      }
-      delete map;
+    BacktraceMap* map = map_func(pid, false);
+    if (map == nullptr) {
+      fprintf(stderr, "Failed to create map\n");
+      return;
     }
+    delete map;
   }
 
   kill(pid, SIGKILL);
@@ -149,11 +147,21 @@
 static void BM_create_map(benchmark::State& state) {
   CreateMap(state, BacktraceMap::Create);
 }
-BENCHMARK(BM_create_map)->Arg(kNumIterations);
+BENCHMARK(BM_create_map);
 
-static void BM_create_map_new(benchmark::State& state) {
-  CreateMap(state, BacktraceMap::CreateNew);
+using BacktraceCreateFn = decltype(Backtrace::Create);
+
+static void CreateBacktrace(benchmark::State& state, BacktraceMap* map, BacktraceCreateFn fn) {
+  while (state.KeepRunning()) {
+    std::unique_ptr<Backtrace> backtrace(fn(getpid(), gettid(), map));
+    backtrace->Unwind(0);
+  }
 }
-BENCHMARK(BM_create_map_new)->Arg(kNumIterations);
+
+static void BM_create_backtrace(benchmark::State& state) {
+  std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(getpid()));
+  CreateBacktrace(state, backtrace_map.get(), Backtrace::Create);
+}
+BENCHMARK(BM_create_backtrace);
 
 BENCHMARK_MAIN();
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index e5eb9e3..0a60ec4 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -368,20 +368,6 @@
   ASSERT_EQ(waitpid(pid, &status, 0), pid);
 }
 
-TEST(libbacktrace, ptrace_trace_new) {
-  pid_t pid;
-  if ((pid = fork()) == 0) {
-    ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
-    _exit(1);
-  }
-  VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyLevelDump,
-                 Backtrace::CreateNew, BacktraceMap::CreateNew);
-
-  kill(pid, SIGKILL);
-  int status;
-  ASSERT_EQ(waitpid(pid, &status, 0), pid);
-}
-
 TEST(libbacktrace, ptrace_max_trace) {
   pid_t pid;
   if ((pid = fork()) == 0) {
@@ -396,20 +382,6 @@
   ASSERT_EQ(waitpid(pid, &status, 0), pid);
 }
 
-TEST(libbacktrace, ptrace_max_trace_new) {
-  pid_t pid;
-  if ((pid = fork()) == 0) {
-    ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES + 10, nullptr, nullptr), 0);
-    _exit(1);
-  }
-  VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyMaxBacktrace, VerifyMaxDump,
-                 Backtrace::CreateNew, BacktraceMap::CreateNew);
-
-  kill(pid, SIGKILL);
-  int status;
-  ASSERT_EQ(waitpid(pid, &status, 0), pid);
-}
-
 static void VerifyProcessIgnoreFrames(Backtrace* bt_all, create_func_t create_func,
                                       map_create_func_t map_create_func) {
   std::unique_ptr<BacktraceMap> map(map_create_func(bt_all->Pid(), false));
@@ -440,20 +412,6 @@
   ASSERT_EQ(waitpid(pid, &status, 0), pid);
 }
 
-TEST(libbacktrace, ptrace_ignore_frames_new) {
-  pid_t pid;
-  if ((pid = fork()) == 0) {
-    ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
-    _exit(1);
-  }
-  VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyProcessIgnoreFrames,
-                 Backtrace::CreateNew, BacktraceMap::CreateNew);
-
-  kill(pid, SIGKILL);
-  int status;
-  ASSERT_EQ(waitpid(pid, &status, 0), pid);
-}
-
 // Create a process with multiple threads and dump all of the threads.
 static void* PtraceThreadLevelRun(void*) {
   EXPECT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
@@ -517,45 +475,6 @@
   FinishRemoteProcess(pid);
 }
 
-TEST(libbacktrace, ptrace_threads_new) {
-  pid_t pid;
-  if ((pid = fork()) == 0) {
-    for (size_t i = 0; i < NUM_PTRACE_THREADS; i++) {
-      pthread_attr_t attr;
-      pthread_attr_init(&attr);
-      pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
-      pthread_t thread;
-      ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, nullptr) == 0);
-    }
-    ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
-    _exit(1);
-  }
-
-  // Check to see that all of the threads are running before unwinding.
-  std::vector<pid_t> threads;
-  uint64_t start = NanoTime();
-  do {
-    usleep(US_PER_MSEC);
-    threads.clear();
-    GetThreads(pid, &threads);
-  } while ((threads.size() != NUM_PTRACE_THREADS + 1) && ((NanoTime() - start) <= 5 * NS_PER_SEC));
-  ASSERT_EQ(threads.size(), static_cast<size_t>(NUM_PTRACE_THREADS + 1));
-
-  ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
-  WaitForStop(pid);
-  for (std::vector<int>::const_iterator it = threads.begin(); it != threads.end(); ++it) {
-    // Skip the current forked process, we only care about the threads.
-    if (pid == *it) {
-      continue;
-    }
-    VerifyProcTest(pid, *it, ReadyLevelBacktrace, VerifyLevelDump, Backtrace::CreateNew,
-                   BacktraceMap::CreateNew);
-  }
-
-  FinishRemoteProcess(pid);
-}
-
 void VerifyLevelThread(void*) {
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
   ASSERT_TRUE(backtrace.get() != nullptr);
@@ -1663,7 +1582,7 @@
   munmap(device_map, DEVICE_MAP_SIZE);
 }
 
-TEST(libbacktrace, unwind_disallow_device_map_remote_new) {
+TEST(libbacktrace, unwind_disallow_device_map_remote) {
   void* device_map;
   SetupDeviceMap(&device_map);
 
@@ -1672,9 +1591,7 @@
   CreateRemoteProcess(&pid);
 
   // Now create an unwind object.
-  std::unique_ptr<BacktraceMap> map(BacktraceMap::CreateNew(pid));
-  ASSERT_TRUE(map.get() != nullptr);
-  std::unique_ptr<Backtrace> backtrace(Backtrace::CreateNew(pid, pid, map.get()));
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
 
   UnwindFromDevice(backtrace.get(), device_map);
 
@@ -1832,16 +1749,20 @@
   UnwindThroughSignal(false, Backtrace::Create, BacktraceMap::Create);
 }
 
-TEST(libbacktrace, unwind_remote_through_signal_using_handler_new) {
-  UnwindThroughSignal(false, Backtrace::CreateNew, BacktraceMap::CreateNew);
-}
-
 TEST(libbacktrace, unwind_remote_through_signal_using_action) {
   UnwindThroughSignal(true, Backtrace::Create, BacktraceMap::Create);
 }
 
-TEST(libbacktrace, unwind_remote_through_signal_using_action_new) {
-  UnwindThroughSignal(true, Backtrace::CreateNew, BacktraceMap::CreateNew);
+static void TestFrameSkipNumbering(create_func_t create_func, map_create_func_t map_create_func) {
+  std::unique_ptr<BacktraceMap> map(map_create_func(getpid(), false));
+  std::unique_ptr<Backtrace> backtrace(create_func(getpid(), gettid(), map.get()));
+  backtrace->Unwind(1);
+  ASSERT_NE(0U, backtrace->NumFrames());
+  ASSERT_EQ(0U, backtrace->GetFrame(0)->num);
+}
+
+TEST(libbacktrace, unwind_frame_skip_numbering) {
+  TestFrameSkipNumbering(Backtrace::Create, BacktraceMap::Create);
 }
 
 #if defined(ENABLE_PSS_TESTS)
@@ -1850,9 +1771,11 @@
 #define MAX_LEAK_BYTES (32*1024UL)
 
 static void CheckForLeak(pid_t pid, pid_t tid) {
+  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
+
   // Do a few runs to get the PSS stable.
   for (size_t i = 0; i < 100; i++) {
-    Backtrace* backtrace = Backtrace::Create(pid, tid);
+    Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
     ASSERT_TRUE(backtrace != nullptr);
     ASSERT_TRUE(backtrace->Unwind(0));
     ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
@@ -1863,7 +1786,7 @@
 
   // Loop enough that even a small leak should be detectable.
   for (size_t i = 0; i < 4096; i++) {
-    Backtrace* backtrace = Backtrace::Create(pid, tid);
+    Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
     ASSERT_TRUE(backtrace != nullptr);
     ASSERT_TRUE(backtrace->Unwind(0));
     ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 274c64b..73a58b5 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -94,8 +94,6 @@
   // If map is NULL, then create the map and manage it internally.
   // If map is not NULL, the map is still owned by the caller.
   static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = NULL);
-  // Same as above, but uses a different underlying unwinder.
-  static Backtrace* CreateNew(pid_t pid, pid_t tid, BacktraceMap* map = NULL);
 
   // Create an offline Backtrace object that can be used to do an unwind without a process
   // that is still running. If cache_file is set to true, then elf information will be cached
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index 84e7132..d078392 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -56,8 +56,6 @@
   // Passing a map created with uncached set to true to Backtrace::Create()
   // is unsupported.
   static BacktraceMap* Create(pid_t pid, bool uncached = false);
-  // Same as above, but is compatible with the new unwinder.
-  static BacktraceMap* CreateNew(pid_t pid, bool uncached = false);
 
   static BacktraceMap* Create(pid_t pid, const std::vector<backtrace_map_t>& maps);
 
diff --git a/liblog/tests/log_read_test.cpp b/liblog/tests/log_read_test.cpp
index 6ed568a..444a5ac 100644
--- a/liblog/tests/log_read_test.cpp
+++ b/liblog/tests/log_read_test.cpp
@@ -100,9 +100,13 @@
       EXPECT_LT(0, get_log_size);
       // crash buffer is allowed to be empty, that is actually healthy!
       // kernel buffer is allowed to be empty on "user" builds
+      // stats buffer is allowed to be empty TEMPORARILY.
+      // TODO: remove stats buffer from here once we start to use it in
+      // framework (b/68266385).
       EXPECT_LE(  // boolean 1 or 0 depending on expected content or empty
           !!((strcmp("crash", name) != 0) &&
-             ((strcmp("kernel", name) != 0) || __android_log_is_debuggable())),
+             ((strcmp("kernel", name) != 0) || __android_log_is_debuggable()) &&
+             (strcmp("stats", name) != 0)),
           android_logger_get_log_readable_size(logger));
     } else {
       EXPECT_NE(0, get_log_size);
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index e687a68..c885c3f 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -65,6 +65,10 @@
         "Symbols.cpp",
     ],
 
+    cflags: [
+        "-Wexit-time-destructors",
+    ],
+
     target: {
         // Always disable optimizations for host to make it easier to debug.
         host: {
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index e3faee3..075fb86 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -86,19 +86,6 @@
     },
 }
 
-// Also provide libziparchive-host until everything is switched over to using libziparchive
-cc_library {
-    name: "libziparchive-host",
-    host_supported: true,
-    device_supported: false,
-    defaults: [
-        "libziparchive_defaults",
-        "libziparchive_flags",
-    ],
-    shared_libs: ["libz"],
-    static_libs: ["libutils"],
-}
-
 // Tests.
 cc_test {
     name: "ziparchive-tests",
diff --git a/libziparchive/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
index 73ae68d..018b1a9 100644
--- a/libziparchive/include/ziparchive/zip_archive.h
+++ b/libziparchive/include/ziparchive/zip_archive.h
@@ -230,4 +230,47 @@
                                 ProcessZipEntryFunction func, void* cookie);
 #endif
 
+namespace zip_archive {
+
+class Writer {
+ public:
+  virtual bool Append(uint8_t* buf, size_t buf_size) = 0;
+  virtual ~Writer();
+
+ protected:
+  Writer() = default;
+
+ private:
+  Writer(const Writer&) = delete;
+  void operator=(const Writer&) = delete;
+};
+
+class Reader {
+ public:
+  virtual bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const = 0;
+  virtual ~Reader();
+
+ protected:
+  Reader() = default;
+
+ private:
+  Reader(const Reader&) = delete;
+  void operator=(const Reader&) = delete;
+};
+
+/*
+ * Inflates the first |compressed_length| bytes of |reader| to a given |writer|.
+ * |crc_out| is set to the CRC32 checksum of the uncompressed data.
+ *
+ * Returns 0 on success and negative values on failure, for example if |reader|
+ * cannot supply the right amount of data, or if the number of bytes written to
+ * data does not match |uncompressed_length|.
+ *
+ * If |crc_out| is not nullptr, it is set to the crc32 checksum of the
+ * uncompressed data.
+ */
+int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
+                const uint32_t uncompressed_length, Writer* writer, uint64_t* crc_out);
+}  // namespace zip_archive
+
 #endif  // LIBZIPARCHIVE_ZIPARCHIVE_H_
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 1be4061..91e775f 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -741,22 +741,10 @@
   return kIterationEnd;
 }
 
-class Writer {
- public:
-  virtual bool Append(uint8_t* buf, size_t buf_size) = 0;
-  virtual ~Writer() {}
-
- protected:
-  Writer() = default;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(Writer);
-};
-
 // A Writer that writes data to a fixed size memory region.
 // The size of the memory region must be equal to the total size of
 // the data appended to it.
-class MemoryWriter : public Writer {
+class MemoryWriter : public zip_archive::Writer {
  public:
   MemoryWriter(uint8_t* buf, size_t size) : Writer(), buf_(buf), size_(size), bytes_written_(0) {}
 
@@ -780,7 +768,7 @@
 
 // A Writer that appends data to a file |fd| at its current position.
 // The file will be truncated to the end of the written data.
-class FileWriter : public Writer {
+class FileWriter : public zip_archive::Writer {
  public:
   // Creates a FileWriter for |fd| and prepare to write |entry| to it,
   // guaranteeing that the file descriptor is valid and that there's enough
@@ -811,7 +799,7 @@
       // disk does not have enough space.
       result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
       if (result == -1 && errno == ENOSPC) {
-        ALOGW("Zip: unable to allocate  %" PRId64 " bytes at offset %" PRId64 " : %s",
+        ALOGW("Zip: unable to allocate %" PRId64 " bytes at offset %" PRId64 ": %s",
               static_cast<int64_t>(declared_length), static_cast<int64_t>(current_offset),
               strerror(errno));
         return std::unique_ptr<FileWriter>(nullptr);
@@ -864,6 +852,22 @@
   size_t total_bytes_written_;
 };
 
+class EntryReader : public zip_archive::Reader {
+ public:
+  EntryReader(const MappedZipFile& zip_file, const ZipEntry* entry)
+      : Reader(), zip_file_(zip_file), entry_(entry) {}
+
+  virtual bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
+    return zip_file_.ReadAtOffset(buf, len, entry_->offset + offset);
+  }
+
+  virtual ~EntryReader() {}
+
+ private:
+  const MappedZipFile& zip_file_;
+  const ZipEntry* entry_;
+};
+
 // This method is using libz macros with old-style-casts
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wold-style-cast"
@@ -872,8 +876,14 @@
 }
 #pragma GCC diagnostic pop
 
-static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry,
-                                    Writer* writer, uint64_t* crc_out) {
+namespace zip_archive {
+
+// Moved out of line to avoid -Wweak-vtables.
+Reader::~Reader() {}
+Writer::~Writer() {}
+
+int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
+                const uint32_t uncompressed_length, Writer* writer, uint64_t* crc_out) {
   const size_t kBufSize = 32768;
   std::vector<uint8_t> read_buf(kBufSize);
   std::vector<uint8_t> write_buf(kBufSize);
@@ -914,25 +924,24 @@
 
   std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter);
 
-  const uint32_t uncompressed_length = entry->uncompressed_length;
-
+  const bool compute_crc = (crc_out != nullptr);
   uint64_t crc = 0;
-  uint32_t compressed_length = entry->compressed_length;
+  uint32_t remaining_bytes = compressed_length;
   do {
     /* read as much as we can */
     if (zstream.avail_in == 0) {
-      const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
-      off64_t offset = entry->offset + (entry->compressed_length - compressed_length);
+      const size_t read_size = (remaining_bytes > kBufSize) ? kBufSize : remaining_bytes;
+      const uint32_t offset = (compressed_length - remaining_bytes);
       // Make sure to read at offset to ensure concurrent access to the fd.
-      if (!mapped_zip.ReadAtOffset(read_buf.data(), getSize, offset)) {
-        ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno));
+      if (!reader.ReadAtOffset(read_buf.data(), read_size, offset)) {
+        ALOGW("Zip: inflate read failed, getSize = %zu: %s", read_size, strerror(errno));
         return kIoError;
       }
 
-      compressed_length -= getSize;
+      remaining_bytes -= read_size;
 
       zstream.next_in = &read_buf[0];
-      zstream.avail_in = getSize;
+      zstream.avail_in = read_size;
     }
 
     /* uncompress the data */
@@ -947,9 +956,8 @@
     if (zstream.avail_out == 0 || (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
       const size_t write_size = zstream.next_out - &write_buf[0];
       if (!writer->Append(&write_buf[0], write_size)) {
-        // The file might have declared a bogus length.
-        return kInconsistentInformation;
-      } else {
+        return kIoError;
+      } else if (compute_crc) {
         crc = crc32(crc, &write_buf[0], write_size);
       }
 
@@ -966,9 +974,11 @@
   // it ourselves above because there are no additional gains to be made by
   // having zlib calculate it for us, since they do it by calling crc32 in
   // the same manner that we have above.
-  *crc_out = crc;
+  if (compute_crc) {
+    *crc_out = crc;
+  }
 
-  if (zstream.total_out != uncompressed_length || compressed_length != 0) {
+  if (zstream.total_out != uncompressed_length || remaining_bytes != 0) {
     ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")", zstream.total_out,
           uncompressed_length);
     return kInconsistentInformation;
@@ -976,9 +986,18 @@
 
   return 0;
 }
+}  // namespace zip_archive
 
-static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry, Writer* writer,
-                                 uint64_t* crc_out) {
+static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry,
+                                    zip_archive::Writer* writer, uint64_t* crc_out) {
+  const EntryReader reader(mapped_zip, entry);
+
+  return zip_archive::Inflate(reader, entry->compressed_length, entry->uncompressed_length, writer,
+                              crc_out);
+}
+
+static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry,
+                                 zip_archive::Writer* writer, uint64_t* crc_out) {
   static const uint32_t kBufSize = 32768;
   std::vector<uint8_t> buf(kBufSize);
 
@@ -1011,7 +1030,7 @@
   return 0;
 }
 
-int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, Writer* writer) {
+int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, zip_archive::Writer* writer) {
   ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
   const uint16_t method = entry->method;
 
@@ -1041,12 +1060,12 @@
 }
 
 int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry, uint8_t* begin, uint32_t size) {
-  std::unique_ptr<Writer> writer(new MemoryWriter(begin, size));
+  std::unique_ptr<zip_archive::Writer> writer(new MemoryWriter(begin, size));
   return ExtractToWriter(handle, entry, writer.get());
 }
 
 int32_t ExtractEntryToFile(ZipArchiveHandle handle, ZipEntry* entry, int fd) {
-  std::unique_ptr<Writer> writer(FileWriter::Create(fd, entry));
+  std::unique_ptr<zip_archive::Writer> writer(FileWriter::Create(fd, entry));
   if (writer.get() == nullptr) {
     return kIoError;
   }
@@ -1079,7 +1098,7 @@
 }
 
 #if !defined(_WIN32)
-class ProcessWriter : public Writer {
+class ProcessWriter : public zip_archive::Writer {
  public:
   ProcessWriter(ProcessZipEntryFunction func, void* cookie)
       : Writer(), proc_function_(func), cookie_(cookie) {}
@@ -1134,7 +1153,7 @@
 }
 
 // Attempts to read |len| bytes into |buf| at offset |off|.
-bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) {
+bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) const {
   if (has_fd_) {
     if (!android::base::ReadFullyAtOffset(fd_, buf, len, off)) {
       ALOGE("Zip: failed to read at offset %" PRId64 "\n", off);
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 174aa3f..18e0229 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -106,7 +106,7 @@
 
   off64_t GetFileLength() const;
 
-  bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off);
+  bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off) const;
 
  private:
   // If has_fd_ is true, fd is valid and we'll read contents of a zip archive
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 753bd44..374310b 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -766,6 +766,93 @@
   ASSERT_EQ(-1, OpenArchiveFd(tmp_file.fd, "LeadingNonZipBytes", &handle));
 }
 
+class VectorReader : public zip_archive::Reader {
+ public:
+  VectorReader(const std::vector<uint8_t>& input) : Reader(), input_(input) {}
+
+  bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
+    if ((offset + len) < input_.size()) {
+      return false;
+    }
+
+    memcpy(buf, &input_[offset], len);
+    return true;
+  }
+
+ private:
+  const std::vector<uint8_t>& input_;
+};
+
+class VectorWriter : public zip_archive::Writer {
+ public:
+  VectorWriter() : Writer() {}
+
+  bool Append(uint8_t* buf, size_t size) {
+    output_.insert(output_.end(), buf, buf + size);
+    return true;
+  }
+
+  std::vector<uint8_t>& GetOutput() { return output_; }
+
+ private:
+  std::vector<uint8_t> output_;
+};
+
+class BadReader : public zip_archive::Reader {
+ public:
+  BadReader() : Reader() {}
+
+  bool ReadAtOffset(uint8_t*, size_t, uint32_t) const { return false; }
+};
+
+class BadWriter : public zip_archive::Writer {
+ public:
+  BadWriter() : Writer() {}
+
+  bool Append(uint8_t*, size_t) { return false; }
+};
+
+TEST(ziparchive, Inflate) {
+  const uint32_t compressed_length = kATxtContentsCompressed.size();
+  const uint32_t uncompressed_length = kATxtContents.size();
+
+  const VectorReader reader(kATxtContentsCompressed);
+  {
+    VectorWriter writer;
+    uint64_t crc_out = 0;
+
+    int32_t ret =
+        zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, &crc_out);
+    ASSERT_EQ(0, ret);
+    ASSERT_EQ(kATxtContents, writer.GetOutput());
+    ASSERT_EQ(0x950821C5u, crc_out);
+  }
+
+  {
+    VectorWriter writer;
+    int32_t ret =
+        zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, nullptr);
+    ASSERT_EQ(0, ret);
+    ASSERT_EQ(kATxtContents, writer.GetOutput());
+  }
+
+  {
+    BadWriter writer;
+    int32_t ret =
+        zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, nullptr);
+    ASSERT_EQ(kIoError, ret);
+  }
+
+  {
+    BadReader reader;
+    VectorWriter writer;
+    int32_t ret =
+        zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, nullptr);
+    ASSERT_EQ(kIoError, ret);
+    ASSERT_EQ(0u, writer.GetOutput().size());
+  }
+}
+
 int main(int argc, char** argv) {
   ::testing::InitGoogleTest(&argc, argv);
 
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 6fca4cd..ff85f54 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -457,7 +457,7 @@
                     "  -d              Dump the log and then exit (don't block)\n"
                     "  -e <expr>, --regex=<expr>\n"
                     "                  Only print lines where the log message matches <expr>\n"
-                    "                  where <expr> is a regular expression\n"
+                    "                  where <expr> is a Perl-compatible regular expression\n"
                     // Leave --head undocumented as alias for -m
                     "  -m <count>, --max-count=<count>\n"
                     "                  Quit after printing <count> lines. This is meant to be\n"
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 860c1f1..6aadf9e 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -62,7 +62,6 @@
   cameraserver \
   cnd \
   debuggerd \
-  debuggerd64 \
   dex2oat \
   drmserver \
   fingerprintd \
diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in
index 394f0e1..1b274d6 100644
--- a/rootdir/etc/ld.config.txt.in
+++ b/rootdir/etc/ld.config.txt.in
@@ -51,7 +51,7 @@
 namespace.sphal.isolated = true
 namespace.sphal.visible = true
 namespace.sphal.search.paths = /vendor/${LIB}/egl:/vendor/${LIB}/hw:/vendor/${LIB}
-namespace.sphal.permitted.paths = /vendor/${LIB}:/system/${LIB}/vndk-sp/hw
+namespace.sphal.permitted.paths = /vendor/${LIB}:/system/${LIB}/vndk-sp${VNDK_VER}/hw
 
 namespace.sphal.asan.search.paths = /data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}:/vendor/${LIB}
 namespace.sphal.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}
@@ -79,10 +79,10 @@
 ###############################################################################
 namespace.rs.isolated = true
 namespace.rs.visible = true
-namespace.rs.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/vendor/${LIB}
+namespace.rs.search.paths = /vendor/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}
 namespace.rs.permitted.paths = /vendor/${LIB}:/data
 
-namespace.rs.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/vendor/${LIB}:/vendor/${LIB}
+namespace.rs.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/data/asan/vendor/${LIB}:/vendor/${LIB}
 namespace.rs.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data
 
 namespace.rs.links = default,vndk
@@ -96,10 +96,10 @@
 ###############################################################################
 namespace.vndk.isolated = true
 namespace.vndk.visible = true
-namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}
 namespace.vndk.permitted.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl
 
-namespace.vndk.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}
 namespace.vndk.asan.permitted.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl
 
 # When these NDK libs are required inside this namespace, then it is redirected
@@ -125,11 +125,11 @@
 namespace.default.isolated = true
 namespace.default.visible = true
 
-namespace.default.search.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/vendor/${LIB}/vndk:/system/${LIB}/vndk:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
-namespace.default.permitted.paths = /vendor:/system/${LIB}/vndk:/system/${LIB}/vndk-sp
+namespace.default.search.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/vendor/${LIB}/vndk${VNDK_VER}:/system/${LIB}/vndk${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}
+namespace.default.permitted.paths = /vendor:/system/${LIB}/vndk${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}
 
-namespace.default.asan.search.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk:/vendor/${LIB}/vndk:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
-namespace.default.asan.permitted.paths = /data/asan/vendor:/vendor:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.default.asan.search.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk${VNDK_VER}:/vendor/${LIB}/vndk${VNDK_VER}:/data/asan/system/${LIB}/vndk${VNDK_VER}:/system/${LIB}/vndk${VNDK_VER}:/data/asan/vendor/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}
+namespace.default.asan.permitted.paths = /data/asan/vendor:/vendor:/data/asan/system/${LIB}/vndk${VNDK_VER}:/system/${LIB}/vndk${VNDK_VER}:/data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}
 
 namespace.default.links = system
 namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%