Merge "Add ScopedSilentDeath to libbase"
diff --git a/Android.bp b/Android.bp
index 5648d06..c98cd21 100644
--- a/Android.bp
+++ b/Android.bp
@@ -57,6 +57,9 @@
     native_bridge_supported: true,
     export_include_dirs: ["include"],
 
+    header_libs: ["fmtlib_headers"],
+    export_header_lib_headers: ["fmtlib_headers"],
+
     target: {
         linux_bionic: {
             enabled: true,
@@ -85,6 +88,7 @@
         "mapped_file.cpp",
         "parsebool.cpp",
         "parsenetaddress.cpp",
+        "posix_strerror_r.cpp",
         "process.cpp",
         "properties.cpp",
         "stringprintf.cpp",
@@ -148,6 +152,7 @@
     ],
     export_header_lib_headers: ["libbase_headers"],
     whole_static_libs: ["fmtlib"],
+    export_static_lib_headers: ["fmtlib"],
     apex_available: [
         "//apex_available:anyapex",
         "//apex_available:platform",
diff --git a/include/android-base/errors.h b/include/android-base/errors.h
index 06f29fc..f67e6eb 100644
--- a/include/android-base/errors.h
+++ b/include/android-base/errors.h
@@ -29,6 +29,8 @@
 
 #pragma once
 
+#include <assert.h>
+
 #include <string>
 
 namespace android {
@@ -41,3 +43,99 @@
 
 }  // namespace base
 }  // namespace android
+
+// Convenient macros for evaluating a statement, checking if the result is error, and returning it
+// to the caller.
+//
+// Usage with Result<T>:
+//
+// Result<Foo> getFoo() {...}
+//
+// Result<Bar> getBar() {
+//   Foo foo = OR_RETURN(getFoo());
+//   return Bar{foo};
+// }
+//
+// Usage with status_t:
+//
+// status_t getFoo(Foo*) {...}
+//
+// status_t getBar(Bar* bar) {
+//   Foo foo;
+//   OR_RETURN(getFoo(&foo));
+//   *bar = Bar{foo};
+//   return OK;
+// }
+//
+// Actually this can be used for any type as long as the OkOrFail<T> contract is satisfied. See
+// below.
+#define OR_RETURN(expr)                                                                 \
+  ({                                                                                    \
+    decltype(expr)&& tmp = (expr);                                                      \
+    typedef android::base::OkOrFail<std::remove_reference_t<decltype(tmp)>> ok_or_fail; \
+    if (!ok_or_fail::IsOk(tmp)) {                                                       \
+      return ok_or_fail::Fail(std::move(tmp));                                          \
+    }                                                                                   \
+    ok_or_fail::Unwrap(std::move(tmp));                                                 \
+  })
+
+// Same as OR_RETURN, but aborts if expr is a failure.
+#if defined(__BIONIC__)
+#define OR_FATAL(expr)                                                                  \
+  ({                                                                                    \
+    decltype(expr)&& tmp = (expr);                                                      \
+    typedef android::base::OkOrFail<std::remove_reference_t<decltype(tmp)>> ok_or_fail; \
+    if (!ok_or_fail::IsOk(tmp)) {                                                       \
+      __assert(__FILE__, __LINE__, ok_or_fail::ErrorMessage(tmp).c_str());              \
+    }                                                                                   \
+    ok_or_fail::Unwrap(std::move(tmp));                                                 \
+  })
+#else
+#define OR_FATAL(expr)                                                                  \
+  ({                                                                                    \
+    decltype(expr)&& tmp = (expr);                                                      \
+    typedef android::base::OkOrFail<std::remove_reference_t<decltype(tmp)>> ok_or_fail; \
+    if (!ok_or_fail::IsOk(tmp)) {                                                       \
+      fprintf(stderr, "%s:%d: assertion \"%s\" failed", __FILE__, __LINE__,             \
+              ok_or_fail::ErrorMessage(tmp).c_str());                                   \
+      abort();                                                                          \
+    }                                                                                   \
+    ok_or_fail::Unwrap(std::move(tmp));                                                 \
+  })
+#endif
+
+namespace android {
+namespace base {
+
+// The OkOrFail contract for a type T. This must be implemented for a type T if you want to use
+// OR_RETURN(stmt) where stmt evalues to a value of type T.
+template <typename T>
+struct OkOrFail {
+  // Checks if T is ok or fail.
+  static bool IsOk(const T&);
+
+  // Turns T into the success value.
+  template <typename U>
+  static U Unwrap(T&&);
+
+  // Moves T into OkOrFail<T>, so that we can convert it to other types
+  OkOrFail(T&& v);
+  OkOrFail() = delete;
+  OkOrFail(const T&) = delete;
+
+  // And there need to be one or more conversion operators that turns the error value of T into a
+  // target type. For example, for T = Result<V, E>, there can be ...
+  //
+  // // for the case where OR_RETURN is called in a function expecting E
+  // operator E()&& { return val_.error().code(); }
+  //
+  // // for the case where OR_RETURN is called in a function expecting Result<U, E>
+  // template <typename U>
+  // operator Result<U, E>()&& { return val_.error(); }
+
+  // Returns the string representation of the fail value.
+  static std::string ErrorMessage(const T& v);
+};
+
+}  // namespace base
+}  // namespace android
diff --git a/include/android-base/result.h b/include/android-base/result.h
index faa722e..a5016b9 100644
--- a/include/android-base/result.h
+++ b/include/android-base/result.h
@@ -41,17 +41,33 @@
 //
 // Using custom error code type:
 //
-// enum class MyError { A, B };
-// struct MyErrorPrinter {
-//   static std::string print(const MyError& e) {
-//     switch(e) {
+// enum class MyError { A, B }; // assume that this is the error code you already have
+//
+// // To use the error code with Result, define a wrapper class that provides the following
+// operations and use the wrapper class as the second type parameter (E) when instantiating
+// Result<T, E>
+//
+// 1. default constructor
+// 2. copy constructor / and move constructor if copying is expensive
+// 3. conversion operator to the error code type
+// 4. value() function that return the error code value
+// 5. print() function that gives a string representation of the error ode value
+//
+// struct MyErrorWrapper {
+//   MyError val_;
+//   MyErrorWrapper() : val_(/* reasonable default value */) {}
+//   MyErrorWrapper(MyError&& e) : val_(std:forward<MyError>(e)) {}
+//   operator const MyError&() const { return val_; }
+//   MyError value() const { return val_; }
+//   std::string print() const {
+//     switch(val_) {
 //       MyError::A: return "A";
 //       MyError::B: return "B";
 //     }
 //   }
 // };
 //
-// #define NewMyError(e) Error<MyError, MyErrorPrinter>(MyError::e)
+// #define NewMyError(e) Error<MyErrorWrapper>(MyError::e)
 //
 // Result<T, MyError> val = NewMyError(A) << "some message";
 //
@@ -81,16 +97,38 @@
 #include <sstream>
 #include <string>
 
+#include "android-base/errors.h"
 #include "android-base/expected.h"
 #include "android-base/format.h"
 
 namespace android {
 namespace base {
 
-template <typename E = int>
+// Errno is a wrapper class for errno(3). Use this type instead of `int` when instantiating
+// `Result<T, E>` and `Error<E>` template classes. This is required to distinguish errno from other
+// integer-based error code types like `status_t`.
+struct Errno {
+  Errno() : val_(0) {}
+  Errno(int e) : val_(e) {}
+  int value() const { return val_; }
+  operator int() const { return value(); }
+  std::string print() const { return strerror(value()); }
+
+  int val_;
+
+  // TODO(b/209929099): remove this conversion operator. This currently is needed to not break
+  // existing places where error().code() is used to construct enum values.
+  template <typename E, typename = std::enable_if_t<std::is_enum_v<E>>>
+  operator E() const {
+    return E(val_);
+  }
+};
+
+template <typename E = Errno, bool include_message = true>
 struct ResultError {
-  template <typename T>
-  ResultError(T&& message, E code) : message_(std::forward<T>(message)), code_(code) {}
+  template <typename T, typename P, typename = std::enable_if_t<std::is_convertible_v<P, E>>>
+  ResultError(T&& message, P&& code)
+      : message_(std::forward<T>(message)), code_(E(std::forward<P>(code))) {}
 
   template <typename T>
   // NOLINTNEXTLINE(google-explicit-constructor)
@@ -99,7 +137,7 @@
   }
 
   std::string message() const { return message_; }
-  E code() const { return code_; }
+  const E& code() const { return code_; }
 
  private:
   std::string message_;
@@ -107,6 +145,22 @@
 };
 
 template <typename E>
+struct ResultError<E, /* include_message */ false> {
+  template <typename P, typename = std::enable_if_t<std::is_convertible_v<P, E>>>
+  ResultError(P&& code) : code_(E(std::forward<P>(code))) {}
+
+  template <typename T>
+  operator android::base::expected<T, ResultError<E, false>>() const {
+    return android::base::unexpected(ResultError<E, false>(code_));
+  }
+
+  const E& code() const { return code_; }
+
+ private:
+  E code_;
+};
+
+template <typename E>
 inline bool operator==(const ResultError<E>& lhs, const ResultError<E>& rhs) {
   return lhs.message() == rhs.message() && lhs.code() == rhs.code();
 }
@@ -122,16 +176,28 @@
   return os;
 }
 
-struct ErrnoPrinter {
-  static std::string print(const int& e) { return strerror(e); }
-};
+namespace internal {
+// Stream class that does nothing and is has zero (actually 1) size. It is used instead of
+// std::stringstream when include_message is false so that we use less on stack.
+// sizeof(std::stringstream) is 280 on arm64.
+struct DoNothingStream {
+  template <typename T>
+  DoNothingStream& operator<<(T&&) {
+    return *this;
+  }
 
-template <typename E = int, typename ErrorCodePrinter = ErrnoPrinter>
+  std::string str() const { return ""; }
+};
+}  // namespace internal
+
+template <typename E = Errno, bool include_message = true,
+          typename = std::enable_if_t<!std::is_same_v<E, int>>>
 class Error {
  public:
   Error() : code_(0), has_code_(false) {}
+  template <typename P, typename = std::enable_if_t<std::is_convertible_v<P, E>>>
   // NOLINTNEXTLINE(google-explicit-constructor)
-  Error(E code) : code_(code), has_code_(true) {}
+  Error(P&& code) : code_(std::forward<P>(code)), has_code_(true) {}
 
   template <typename T, typename P, typename = std::enable_if_t<std::is_convertible_v<E, P>>>
   // NOLINTNEXTLINE(google-explicit-constructor)
@@ -139,8 +205,15 @@
     return android::base::unexpected(ResultError<P>(str(), static_cast<P>(code_)));
   }
 
+  template <typename T, typename P, typename = std::enable_if_t<std::is_convertible_v<E, P>>>
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  operator android::base::expected<T, ResultError<P, false>>() const {
+    return android::base::unexpected(ResultError<P, false>(static_cast<P>(code_)));
+  }
+
   template <typename T>
   Error& operator<<(T&& t) {
+    static_assert(include_message, "<< not supported when include_message = false");
     // NOLINTNEXTLINE(bugprone-suspicious-semicolon)
     if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, ResultError<E>>) {
       if (!has_code_) {
@@ -155,12 +228,13 @@
   }
 
   const std::string str() const {
+    static_assert(include_message, "str() not supported when include_message = false");
     std::string str = ss_.str();
     if (has_code_) {
       if (str.empty()) {
-        return ErrorCodePrinter::print(code_);
+        return code_.print();
       }
-      return std::move(str) + ": " + ErrorCodePrinter::print(code_);
+      return std::move(str) + ": " + code_.print();
     }
     return str;
   }
@@ -181,13 +255,13 @@
     (*this) << message;
   }
 
-  std::stringstream ss_;
+  std::conditional_t<include_message, std::stringstream, internal::DoNothingStream> ss_;
   E code_;
   const bool has_code_;
 };
 
-inline Error<int, ErrnoPrinter> ErrnoError() {
-  return Error<int, ErrnoPrinter>(errno);
+inline Error<Errno> ErrnoError() {
+  return Error<Errno>(Errno{errno});
 }
 
 template <typename E>
@@ -206,42 +280,67 @@
 }
 
 template <typename T, typename... Args>
-inline Error<int, ErrnoPrinter> ErrorfImpl(const T&& fmt, const Args&... args) {
-  return Error(false, ErrorCode(0, args...), fmt::format(fmt, args...));
+inline Error<Errno> ErrorfImpl(const T&& fmt, const Args&... args) {
+  return Error(false, ErrorCode(Errno{}, args...), fmt::format(fmt, args...));
 }
 
 template <typename T, typename... Args>
-inline Error<int, ErrnoPrinter> ErrnoErrorfImpl(const T&& fmt, const Args&... args) {
-  return Error<int, ErrnoPrinter>(true, errno, fmt::format(fmt, args...));
+inline Error<Errno> ErrnoErrorfImpl(const T&& fmt, const Args&... args) {
+  return Error<Errno>(true, Errno{errno}, fmt::format(fmt, args...));
 }
 
 #define Errorf(fmt, ...) android::base::ErrorfImpl(FMT_STRING(fmt), ##__VA_ARGS__)
 #define ErrnoErrorf(fmt, ...) android::base::ErrnoErrorfImpl(FMT_STRING(fmt), ##__VA_ARGS__)
 
-template <typename T, typename E = int>
-using Result = android::base::expected<T, ResultError<E>>;
+template <typename T, typename E = Errno, bool include_message = true>
+using Result = android::base::expected<T, ResultError<E, include_message>>;
+
+// Specialization of android::base::OkOrFail<V> for V = Result<T, E>. See android-base/errors.h
+// for the contract.
+template <typename T, typename E>
+struct OkOrFail<Result<T, E>> {
+  typedef Result<T, E> V;
+  // Checks if V is ok or fail
+  static bool IsOk(const V& val) { return val.ok(); }
+
+  // Turns V into a success value
+  static T Unwrap(V&& val) { return std::move(val.value()); }
+
+  // Consumes V when it's a fail value
+  static OkOrFail<V> Fail(V&& v) {
+    assert(!IsOk(v));
+    return OkOrFail<V>{std::move(v)};
+  }
+  V val_;
+
+  // Turns V into S (convertible from E) or Result<U, E>
+  template <typename S, typename = std::enable_if_t<std::is_convertible_v<E, S>>>
+  operator S() && {
+    return val_.error().code();
+  }
+  template <typename U>
+  operator Result<U, E>() && {
+    return val_.error();
+  }
+
+  static std::string ErrorMessage(const V& val) { return val.error().message(); }
+};
 
 // Macros for testing the results of functions that return android::base::Result.
 // These also work with base::android::expected.
 // For advanced matchers and customized error messages, see result-gtest.h.
 
-#define CHECK_RESULT_OK(stmt)       \
-  do {                              \
-    const auto& tmp = (stmt);       \
-    CHECK(tmp.ok()) << tmp.error(); \
-  } while (0)
+#define ASSERT_RESULT_OK(stmt)                            \
+  if (const auto& tmp = (stmt); !tmp.ok())                \
+  FAIL() << "Value of: " << #stmt << "\n"                 \
+         << "  Actual: " << tmp.error().message() << "\n" \
+         << "Expected: is ok\n"
 
-#define ASSERT_RESULT_OK(stmt)            \
-  do {                                    \
-    const auto& tmp = (stmt);             \
-    ASSERT_TRUE(tmp.ok()) << tmp.error(); \
-  } while (0)
-
-#define EXPECT_RESULT_OK(stmt)            \
-  do {                                    \
-    auto tmp = (stmt);                    \
-    EXPECT_TRUE(tmp.ok()) << tmp.error(); \
-  } while (0)
+#define EXPECT_RESULT_OK(stmt)                                   \
+  if (const auto& tmp = (stmt); !tmp.ok())                       \
+  ADD_FAILURE() << "Value of: " << #stmt << "\n"                 \
+                << "  Actual: " << tmp.error().message() << "\n" \
+                << "Expected: is ok\n"
 
 }  // namespace base
 }  // namespace android
diff --git a/include/android-base/scopeguard.h b/include/android-base/scopeguard.h
index 5a224d6..8293b2c 100644
--- a/include/android-base/scopeguard.h
+++ b/include/android-base/scopeguard.h
@@ -26,14 +26,14 @@
 template <typename F>
 class ScopeGuard {
  public:
-  ScopeGuard(F&& f) : f_(std::forward<F>(f)), active_(true) {}
+  constexpr ScopeGuard(F&& f) : f_(std::forward<F>(f)), active_(true) {}
 
-  ScopeGuard(ScopeGuard&& that) noexcept : f_(std::move(that.f_)), active_(that.active_) {
+  constexpr ScopeGuard(ScopeGuard&& that) noexcept : f_(std::move(that.f_)), active_(that.active_) {
     that.active_ = false;
   }
 
   template <typename Functor>
-  ScopeGuard(ScopeGuard<Functor>&& that) : f_(std::move(that.f_)), active_(that.active_) {
+  constexpr ScopeGuard(ScopeGuard<Functor>&& that) : f_(std::move(that.f_)), active_(that.active_) {
     that.active_ = false;
   }
 
@@ -48,7 +48,7 @@
 
   void Disable() { active_ = false; }
 
-  bool active() const { return active_; }
+  constexpr bool active() const { return active_; }
 
  private:
   template <typename Functor>
diff --git a/include/android-base/strings.h b/include/android-base/strings.h
index 95d6077..e794540 100644
--- a/include/android-base/strings.h
+++ b/include/android-base/strings.h
@@ -104,5 +104,8 @@
 [[nodiscard]] std::string StringReplace(std::string_view s, std::string_view from,
                                         std::string_view to, bool all);
 
+// Converts an errno number to its error message string.
+std::string ErrnoNumberAsString(int errnum);
+
 }  // namespace base
 }  // namespace android
diff --git a/mapped_file.cpp b/mapped_file.cpp
index fff3453..91d0b0f 100644
--- a/mapped_file.cpp
+++ b/mapped_file.cpp
@@ -63,8 +63,8 @@
     }
     return nullptr;
   }
-  void* base = MapViewOfFile(handle, (prot & PROT_WRITE) ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ, 0,
-                             file_offset, file_length);
+  void* base = MapViewOfFile(handle, (prot & PROT_WRITE) ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ,
+                             (file_offset >> 32), file_offset, file_length);
   if (base == nullptr) {
     CloseHandle(handle);
     return nullptr;
diff --git a/posix_strerror_r.cpp b/posix_strerror_r.cpp
new file mode 100644
index 0000000..6428a98
--- /dev/null
+++ b/posix_strerror_r.cpp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2021 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.
+//
+
+/* Undefine _GNU_SOURCE so that this compilation unit can access the
+ * posix version of strerror_r */
+#undef _GNU_SOURCE
+#include <string.h>
+
+namespace android {
+namespace base {
+
+extern "C" int posix_strerror_r(int errnum, char* buf, size_t buflen) {
+#ifdef _WIN32
+  return strerror_s(buf, buflen, errnum);
+#else
+  return strerror_r(errnum, buf, buflen);
+#endif
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/result_test.cpp b/result_test.cpp
index 592b0b8..47feeee 100644
--- a/result_test.cpp
+++ b/result_test.cpp
@@ -192,18 +192,24 @@
 }
 
 enum class CustomError { A, B };
-struct CustomErrorPrinter {
-  static std::string print(const CustomError& e) {
-    switch (e) {
+
+struct CustomErrorWrapper {
+  CustomErrorWrapper() : val_(CustomError::A) {}
+  CustomErrorWrapper(const CustomError& e) : val_(e) {}
+  CustomError value() const { return val_; }
+  operator CustomError() const { return value(); }
+  std::string print() const {
+    switch (val_) {
       case CustomError::A:
         return "A";
       case CustomError::B:
         return "B";
     }
   }
+  CustomError val_;
 };
 
-#define NewCustomError(e) Error<CustomError, CustomErrorPrinter>(CustomError::e)
+#define NewCustomError(e) Error<CustomErrorWrapper>(CustomError::e)
 
 TEST(result, result_with_custom_errorcode) {
   Result<void, CustomError> ok = {};
@@ -237,6 +243,72 @@
   EXPECT_EQ("aaaaa", *result);
 }
 
+TEST(result, unwrap_or_return) {
+  auto f = [](bool success) -> Result<size_t, CustomError> {
+    return OR_RETURN(success_or_fail(success)).size();
+  };
+
+  auto r = f(true);
+  EXPECT_TRUE(r.ok());
+  EXPECT_EQ(strlen("success"), *r);
+
+  auto s = f(false);
+  EXPECT_FALSE(s.ok());
+  EXPECT_EQ(CustomError::A, s.error().code());
+  EXPECT_EQ("fail: A", s.error().message());
+}
+
+TEST(result, unwrap_or_return_errorcode) {
+  auto f = [](bool success) -> CustomError {
+    // Note that we use the same OR_RETURN macro for different return types: Result<U, CustomError>
+    // and CustomError.
+    std::string val = OR_RETURN(success_or_fail(success));
+    EXPECT_EQ("success", val);
+    return CustomError::B;
+  };
+
+  auto r = f(true);
+  EXPECT_EQ(CustomError::B, r);
+
+  auto s = f(false);
+  EXPECT_EQ(CustomError::A, s);
+}
+
+TEST(result, unwrap_or_fatal) {
+  auto r = OR_FATAL(success_or_fail(true));
+  EXPECT_EQ("success", r);
+
+  EXPECT_DEATH(OR_FATAL(success_or_fail(false)), "fail: A");
+}
+
+struct MyData {
+  const int data;
+  static int copy_constructed;
+  static int move_constructed;
+  MyData(int d) : data(d) {}
+  MyData(const MyData& other) : data(other.data) { copy_constructed++; }
+  MyData(MyData&& other) : data(other.data) { move_constructed++; }
+};
+
+int MyData::copy_constructed = 0;
+int MyData::move_constructed = 0;
+
+TEST(result, unwrap_does_not_incur_additional_copying) {
+  MyData::copy_constructed = 0;
+  MyData::move_constructed = 0;
+  auto f = []() -> Result<MyData> { return MyData{10}; };
+
+  [&]() -> Result<void> {
+    int data = OR_RETURN(f()).data;
+    EXPECT_EQ(10, data);
+    EXPECT_EQ(0, MyData::copy_constructed);
+    // Moved once when MyData{10} is returned as Result<MyData> in the lambda f.
+    // Moved once again when the variable d is constructed from OR_RETURN.
+    EXPECT_EQ(2, MyData::move_constructed);
+    return {};
+  }();
+}
+
 struct ConstructorTracker {
   static size_t constructor_called;
   static size_t copy_constructor_called;
@@ -463,6 +535,14 @@
             outer.error().message());
 }
 
+TEST(result, error_without_message) {
+  constexpr bool include_message = false;
+  Result<void, Errno, include_message> res = Error<Errno, include_message>(10);
+  EXPECT_FALSE(res.ok());
+  EXPECT_EQ(10, res.error().code());
+  EXPECT_EQ(sizeof(int), sizeof(res.error()));
+}
+
 namespace testing {
 
 class Listener : public ::testing::MatchResultListener {
diff --git a/strings.cpp b/strings.cpp
index 8f3c7d9..deb6e28 100644
--- a/strings.cpp
+++ b/strings.cpp
@@ -16,12 +16,18 @@
 
 #include "android-base/strings.h"
 
+#include "android-base/stringprintf.h"
+
 #include <stdlib.h>
 #include <string.h>
 
 #include <string>
 #include <vector>
 
+// Wraps the posix version of strerror_r to make it available in translation units
+// that define _GNU_SOURCE.
+extern "C" int posix_strerror_r(int errnum, char* buf, size_t buflen);
+
 namespace android {
 namespace base {
 
@@ -152,5 +158,15 @@
   return result;
 }
 
+std::string ErrnoNumberAsString(int errnum) {
+  char buf[100];
+  buf[0] = '\0';
+  int strerror_err = posix_strerror_r(errnum, buf, sizeof(buf));
+  if (strerror_err < 0) {
+    return StringPrintf("Failed to convert errno %d to string: %d", errnum, strerror_err);
+  }
+  return buf;
+}
+
 }  // namespace base
 }  // namespace android
diff --git a/strings_test.cpp b/strings_test.cpp
index 7a57489..fb111b8 100644
--- a/strings_test.cpp
+++ b/strings_test.cpp
@@ -400,3 +400,7 @@
   ASSERT_EQ("xxyzx", android::base::StringReplace("abcxyzabc", "abc", "x", true));
   ASSERT_EQ("<xx>", android::base::StringReplace("<abcabc>", "abc", "x", true));
 }
+
+TEST(strings, ErrnoNumberAsString) {
+  EXPECT_EQ("No such file or directory", android::base::ErrnoNumberAsString(ENOENT));
+}