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));
+}