libbase: update from upstream
Followed instructions from go/nnapi-dep-instructions.
No manual changes / interventions have been made.
$ git merge cros/upstream/master --no-ff
$ repo upload --cbr . --no-verify
BUG=b:197814725
TEST=cq passes
Change-Id: Idd0474acff423a60ebad4cbcc2b0443ce7cf612f
diff --git a/Android.bp b/Android.bp
index 524ff65..0d32885 100644
--- a/Android.bp
+++ b/Android.bp
@@ -14,6 +14,22 @@
// limitations under the License.
//
+package {
+ default_applicable_licenses: ["system_libbase_license"],
+}
+
+license {
+ name: "system_libbase_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ "SPDX-license-identifier-BSD",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_defaults {
name: "libbase_cflags_defaults",
cflags: [
@@ -64,7 +80,7 @@
"chrono_utils.cpp",
"cmsg.cpp",
"file.cpp",
- "liblog_symbols.cpp",
+ "hex.cpp",
"logging.cpp",
"mapped_file.cpp",
"parsebool.cpp",
@@ -164,6 +180,8 @@
"errors_test.cpp",
"expected_test.cpp",
"file_test.cpp",
+ "function_ref_test.cpp",
+ "hex_test.cpp",
"logging_splitters_test.cpp",
"logging_test.cpp",
"macros_test.cpp",
@@ -199,6 +217,7 @@
},
local_include_dirs: ["."],
shared_libs: ["libbase"],
+ static_libs: ["libgmock"],
compile_multilib: "both",
multilib: {
lib32: {
diff --git a/function_ref_test.cpp b/function_ref_test.cpp
new file mode 100644
index 0000000..44194f7
--- /dev/null
+++ b/function_ref_test.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#include "android-base/function_ref.h"
+
+#include <gtest/gtest.h>
+
+#include <functional>
+#include <string>
+
+namespace android::base {
+
+TEST(function_ref, Ctor) {
+ // Making sure it can be constructed in all meaningful ways
+
+ using EmptyFunc = function_ref<void()>;
+
+ EmptyFunc f1([] {});
+
+ struct Functor {
+ void operator()() const {}
+ };
+ EmptyFunc f2(Functor{});
+ Functor fctr;
+ EmptyFunc f3(fctr);
+
+ EmptyFunc f4(std::function<void()>([f1, f2, f3] {
+ (void)f1;
+ (void)f2;
+ (void)f3;
+ }));
+
+ const std::function<void()> func = [] {};
+ EmptyFunc f5(func);
+
+ static_assert(sizeof(f1) <= 2 * sizeof(void*), "Too big function_ref");
+ static_assert(sizeof(f2) <= 2 * sizeof(void*), "Too big function_ref");
+ static_assert(sizeof(f3) <= 2 * sizeof(void*), "Too big function_ref");
+ static_assert(sizeof(f4) <= 2 * sizeof(void*), "Too big function_ref");
+ static_assert(sizeof(f5) <= 2 * sizeof(void*), "Too big function_ref");
+}
+
+TEST(function_ref, Call) {
+ function_ref<int(int)> view = [](int i) { return i + 1; };
+ EXPECT_EQ(1, view(0));
+ EXPECT_EQ(-1, view(-2));
+
+ function_ref<std::string(std::string)> fs = [](const std::string& s) { return s + "1"; };
+ EXPECT_STREQ("s1", fs("s").c_str());
+ EXPECT_STREQ("ssss1", fs("ssss").c_str());
+
+ std::string base;
+ auto lambda = [&base]() { return base + "1"; };
+ function_ref<std::string()> fs2 = lambda;
+ base = "one";
+ EXPECT_STREQ("one1", fs2().c_str());
+ base = "forty two";
+ EXPECT_STREQ("forty two1", fs2().c_str());
+}
+
+TEST(function_ref, CopyAndAssign) {
+ function_ref<int(int)> view = [](int i) { return i + 1; };
+ EXPECT_EQ(1, view(0));
+ view = [](int i) { return i - 1; };
+ EXPECT_EQ(0, view(1));
+
+ function_ref<int(int)> view2 = view;
+ EXPECT_EQ(view(10), view2(10));
+
+ view = view2;
+ EXPECT_EQ(view(10), view2(10));
+}
+
+} // namespace android::base
diff --git a/hex.cpp b/hex.cpp
new file mode 100644
index 0000000..a4b7715
--- /dev/null
+++ b/hex.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#include "android-base/hex.h"
+
+#include "android-base/logging.h"
+
+namespace android {
+namespace base {
+
+std::string HexString(const void* bytes, size_t len) {
+ CHECK(bytes != nullptr || len == 0) << bytes << " " << len;
+
+ // b/132916539: Doing this the 'C way', std::setfill triggers ubsan implicit conversion
+ const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
+ const char chars[] = "0123456789abcdef";
+ std::string result;
+ result.resize(len * 2);
+
+ for (size_t i = 0; i < len; i++) {
+ result[2 * i] = chars[bytes8[i] >> 4];
+ result[2 * i + 1] = chars[bytes8[i] & 0xf];
+ }
+
+ return result;
+}
+
+} // namespace base
+} // namespace android
diff --git a/hex_test.cpp b/hex_test.cpp
new file mode 100644
index 0000000..ebf798c
--- /dev/null
+++ b/hex_test.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#include "android-base/hex.h"
+
+#include <gtest/gtest.h>
+
+TEST(hex, empty) {
+ ASSERT_EQ("", android::base::HexString(nullptr, 0));
+ ASSERT_EQ("", android::base::HexString(reinterpret_cast<void*>(int32_t(0)), 0));
+}
+
+TEST(hex, short) {
+ const int32_t kShortData = 0xDEADBEEF;
+ ASSERT_EQ("ef", android::base::HexString(&kShortData, 1));
+ ASSERT_EQ("efbe", android::base::HexString(&kShortData, 2));
+ ASSERT_EQ("efbead", android::base::HexString(&kShortData, 3));
+ ASSERT_EQ("efbeadde", android::base::HexString(&kShortData, 4));
+}
+
+TEST(hex, all) {
+ constexpr size_t kSize = 256;
+ uint8_t kLongData[kSize];
+ for (size_t i = 0; i < kSize; i++) {
+ kLongData[i] = i;
+ }
+
+ ASSERT_EQ(
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d"
+ "2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b"
+ "5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283848586878889"
+ "8a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7"
+ "b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5"
+ "e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+ android::base::HexString(&kLongData, kSize));
+}
diff --git a/include/android-base/endian.h b/include/android-base/endian.h
index 8fa6365..b47494b 100644
--- a/include/android-base/endian.h
+++ b/include/android-base/endian.h
@@ -25,18 +25,19 @@
#include <sys/endian.h>
-#elif defined(__GLIBC__)
+#elif defined(__GLIBC__) || defined(ANDROID_HOST_MUSL)
-/* glibc's <endian.h> is like bionic's <sys/endian.h>. */
+/* glibc and musl's <endian.h> are like bionic's <sys/endian.h>. */
#include <endian.h>
-/* glibc keeps htons and htonl in <netinet/in.h>. */
+/* glibc and musl keep htons and htonl in <netinet/in.h>. */
#include <netinet/in.h>
-/* glibc doesn't have the 64-bit variants. */
+/* glibc and musl don't have the 64-bit variants. */
#define htonq(x) htobe64(x)
#define ntohq(x) be64toh(x)
+#if defined(__GLIBC__)
/* glibc has different names to BSD for these. */
#define betoh16(x) be16toh(x)
#define betoh32(x) be32toh(x)
@@ -44,6 +45,7 @@
#define letoh16(x) le16toh(x)
#define letoh32(x) le32toh(x)
#define letoh64(x) le64toh(x)
+#endif
#else
diff --git a/include/android-base/expected.h b/include/android-base/expected.h
index 11cf1ac..3b9d45f 100644
--- a/include/android-base/expected.h
+++ b/include/android-base/expected.h
@@ -37,7 +37,7 @@
//
// void test() {
// auto q = safe_divide(10, 0);
-// if (q) { printf("%f\n", q.value()); }
+// if (q.ok()) { printf("%f\n", q.value()); }
// else { printf("%s\n", q.error().c_str()); }
// }
//
diff --git a/include/android-base/function_ref.h b/include/android-base/function_ref.h
new file mode 100644
index 0000000..2de14e3
--- /dev/null
+++ b/include/android-base/function_ref.h
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <type_traits>
+#include <utility>
+
+namespace android::base {
+
+//
+// function_ref<> - a class that stores a reference to a callable object,
+// similar to string_view for strings.
+//
+// We need to pass around lots of callbacks. The standard way of doing it
+// is via std::function<> class, and it usually works OK. But there are some
+// noticeable drawbacks:
+//
+// 1. std::function<> in most STLs performs heap allocation for all callables
+// bigger than a single poiner to a function.
+// 2. std::function<> goes through at least two pointers + a vptr call to call
+// the stored function.
+// 3. std::function<> copies the passed object inside at least once; this also
+// means it can't work with non-copyable functors.
+//
+// function_ref is an alternative way of passing functors around. Instead of
+// storing a copy of the functor inside, it follows the path of string_view and
+// merely captures a pointer to the object to call. This allows for a simple,
+// fast and lightweight wrapper design; it also dictates the limitations:
+//
+// 1. function_ref<> stores a pointer to outside functor. That functor _must_
+// outlive the ref.
+// 2. function_ref<> has two calls through a function pointer in its call
+// operator. That's still better than std::function<>, but slower compared
+// to a raw function pointer call with a "void* opaque" context parameter.
+//
+// Limitation #1 dictates the best use case: a function parameter type for some
+// generic callback which doesn't get stored inside an object field but only
+// gets called in this call. E.g.:
+//
+// void someLongOperation(function_ref<void(int progress)> onProgress) {
+// firstStep(onProgress);
+// ...
+// onProgress(50);
+// ...
+// lastStep(onProgress);
+// onProgress(100);
+// }
+//
+// In this code std::function<> is an overkill as the whole use of |onProgresss|
+// callback is scoped and easy to track. An alternative design - making it a
+// template parameter (template <class Callback> ... (Callback onProgress))
+// forces one to put someLongOperation() + some private functions into the
+// header. function_ref<> is the choice then.
+//
+// NOTE: Beware of passing temporary functions via function_ref<>! Temporaries
+// live until the end of full expression (usually till the next semicolon), and
+// having a function_ref<> that refers to a dangling pointer is a bug that's
+// hard to debug. E.g.:
+// function_ref<...> v = [](){}; // this is fine
+// function_ref<...> v = std::function<...>([](){}); // this will kill you
+//
+// NOTE2: function_ref<> should not have an empty state, but it doesn't have a
+// runtime check against that. Don't construct it from a null function!
+
+template <class Signature>
+class function_ref;
+
+template <class Ret, class... Args>
+class function_ref<Ret(Args...)> final {
+ public:
+ constexpr function_ref() noexcept = delete;
+ constexpr function_ref(const function_ref& other) noexcept = default;
+ constexpr function_ref& operator=(const function_ref&) noexcept = default;
+
+ template <class Callable, class = std::enable_if_t<
+ std::is_invocable_r<Ret, Callable, Args...>::value &&
+ !std::is_same_v<function_ref, std::remove_reference_t<Callable>>>>
+ function_ref(Callable&& c) noexcept
+ : mTypeErasedFunction([](const function_ref* self, Args... args) -> Ret {
+ // Generate a lambda that remembers the type of the passed
+ // |Callable|.
+ return (*reinterpret_cast<std::remove_reference_t<Callable>*>(self->mCallable))(
+ std::forward<Args>(args)...);
+ }),
+ mCallable(reinterpret_cast<intptr_t>(&c)) {}
+
+ template <class Callable, class = std::enable_if_t<
+ std::is_invocable_r<Ret, Callable, Args...>::value &&
+ !std::is_same_v<function_ref, std::remove_reference_t<Callable>>>>
+ function_ref& operator=(Callable&& c) noexcept {
+ mTypeErasedFunction = [](const function_ref* self, Args... args) -> Ret {
+ // Generate a lambda that remembers the type of the passed
+ // |Callable|.
+ return (*reinterpret_cast<std::remove_reference_t<Callable>*>(self->mCallable))(
+ std::forward<Args>(args)...);
+ };
+ mCallable = reinterpret_cast<intptr_t>(&c);
+ return *this;
+ }
+
+ Ret operator()(Args... args) const {
+ return mTypeErasedFunction(this, std::forward<Args>(args)...);
+ }
+
+ private:
+ using TypeErasedFunc = Ret(const function_ref*, Args...);
+ TypeErasedFunc* mTypeErasedFunction;
+ intptr_t mCallable;
+};
+
+} // namespace android::base
diff --git a/include/android-base/hex.h b/include/android-base/hex.h
new file mode 100644
index 0000000..cbb26a8
--- /dev/null
+++ b/include/android-base/hex.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace android {
+namespace base {
+
+// Converts binary data into a hexString.
+//
+// Hex values are printed in order, e.g. 0xDEAD will result in 'adde' because
+// Android is little-endian.
+std::string HexString(const void* bytes, size_t len);
+
+} // namespace base
+} // namespace android
diff --git a/include/android-base/logging.h b/include/android-base/logging.h
index 9064075..179ddf0 100644
--- a/include/android-base/logging.h
+++ b/include/android-base/logging.h
@@ -27,6 +27,8 @@
// LOG(INFO) << "Some text; " << some_value;
//
// Replace `INFO` with any severity from `enum LogSeverity`.
+// Most devices filter out VERBOSE logs by default, run
+// `adb shell setprop log.tag.<TAG> V` to see them in adb logcat.
//
// To log the result of a failed function and include the string
// representation of `errno` at the end:
diff --git a/include/android-base/properties.h b/include/android-base/properties.h
index 8b34573..021f466 100644
--- a/include/android-base/properties.h
+++ b/include/android-base/properties.h
@@ -97,6 +97,10 @@
};
#endif
+static inline int HwTimeoutMultiplier() {
+ return android::base::GetIntProperty("ro.hw_timeout_multiplier", 1);
+}
+
} // namespace base
} // namespace android
diff --git a/include/android-base/result-gmock.h b/include/android-base/result-gmock.h
new file mode 100644
index 0000000..1fd9f00
--- /dev/null
+++ b/include/android-base/result-gmock.h
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+#pragma once
+#include <android-base/result.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+/*
+ * Matchers for android::base::Result<T> that produces human-readable test results.
+ *
+ * Example:
+ *
+ * Result<int> result = ...
+ *
+ * using namespace ::android::base::testing;
+ * using namespace ::testing;
+ *
+ * EXPECT_THAT(result, Ok());
+ * EXPECT_THAT(result, Not(Ok()));
+ * EXPECT_THAT(result, HasValue(5));
+ * EXPECT_THAT(result, HasError(WithCode(EBADF)));
+ * EXPECT_THAT(result, HasError(WithMessageMessage("expected error message")));
+ *
+ * // Advance usage
+ * EXPECT_THAT(result, AnyOf(Ok(), HasError(WithCode(EACCES)));
+ * EXPECT_THAT(result, HasError(WithCode(AnyOf(EBADF, EACCES))) << "Unexpected code from library";
+ */
+
+namespace android::base {
+
+template <typename T>
+inline void PrintTo(const Result<T>& result, std::ostream* os) {
+ if (result.ok()) {
+ *os << "OK: " << ::testing::PrintToString(result.value());
+ } else {
+ *os << "Error: " << result.error();
+ }
+}
+
+template <>
+inline void PrintTo(const Result<void>& result, std::ostream* os) {
+ if (result.ok()) {
+ *os << "OK";
+ } else {
+ *os << "Error: " << result.error();
+ }
+}
+
+namespace testing {
+
+MATCHER(Ok, "") {
+ if (arg.ok()) {
+ *result_listener << "result is OK";
+ return true;
+ }
+ *result_listener << "error is " << arg.error();
+ return false;
+}
+
+MATCHER_P(HasValue, value_matcher, "") {
+ if (arg.ok()) {
+ return ::testing::ExplainMatchResult(value_matcher, arg.value(), result_listener);
+ }
+ *result_listener << "error is " << arg.error();
+ return false;
+}
+
+MATCHER_P(HasError, error_matcher, "") {
+ if (!arg.ok()) {
+ return ::testing::ExplainMatchResult(error_matcher, arg.error(), result_listener);
+ }
+ *result_listener << "result is OK";
+ return false;
+}
+
+MATCHER_P(WithCode, code_matcher, "") {
+ *result_listener << "actual error is " << arg;
+ return ::testing::ExplainMatchResult(code_matcher, arg.code(), result_listener);
+}
+
+MATCHER_P(WithMessage, message_matcher, "") {
+ *result_listener << "actual error is " << arg;
+ return ::testing::ExplainMatchResult(message_matcher, arg.message(), result_listener);
+}
+
+} // namespace testing
+} // namespace android::base
diff --git a/include/android-base/result.h b/include/android-base/result.h
index 56a4f3e..acec791 100644
--- a/include/android-base/result.h
+++ b/include/android-base/result.h
@@ -210,6 +210,7 @@
// 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 { \
diff --git a/include/android-base/silent_death_test.h b/include/android-base/silent_death_test.h
new file mode 100644
index 0000000..2aec890
--- /dev/null
+++ b/include/android-base/silent_death_test.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#pragma once
+
+#include <signal.h>
+
+#include <gtest/gtest.h>
+
+#if !defined(__BIONIC__)
+#define sigaction64 sigaction
+#endif
+
+// Disables debuggerd stack traces to speed up death tests and make them less
+// noisy in logcat.
+//
+// Use `using my_DeathTest = SilentDeathTest;` instead of inheriting from
+// testing::Test yourself.
+class SilentDeathTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // Suppress debuggerd stack traces. Too slow.
+ for (int signo : {SIGABRT, SIGBUS, SIGSEGV, SIGSYS}) {
+ struct sigaction64 action = {.sa_handler = SIG_DFL};
+ sigaction64(signo, &action, &previous_);
+ }
+ }
+
+ virtual void TearDown() {
+ for (int signo : {SIGABRT, SIGBUS, SIGSEGV, SIGSYS}) {
+ sigaction64(signo, &previous_, nullptr);
+ }
+ }
+
+ private:
+ struct sigaction64 previous_;
+};
diff --git a/include/android-base/unique_fd.h b/include/android-base/unique_fd.h
index 9ceb5db..e929e4c 100644
--- a/include/android-base/unique_fd.h
+++ b/include/android-base/unique_fd.h
@@ -20,19 +20,25 @@
#include <errno.h>
#include <fcntl.h>
-#if !defined(_WIN32)
-#include <sys/socket.h>
-#endif
-
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
-// DO NOT INCLUDE OTHER LIBBASE HEADERS!
+// DO NOT INCLUDE OTHER LIBBASE HEADERS HERE!
// This file gets used in libbinder, and libbinder is used everywhere.
// Including other headers from libbase frequently results in inclusion of
// android-base/macros.h, which causes macro collisions.
+#if defined(__BIONIC__)
+#include <android/fdsan.h>
+#endif
+#if !defined(_WIN32)
+#include <sys/socket.h>
+#endif
+
+namespace android {
+namespace base {
+
// Container for a file descriptor that automatically closes the descriptor as
// it goes out of scope.
//
@@ -43,47 +49,14 @@
//
// return 0; // Descriptor is closed for you.
//
+// See also the Pipe()/Socketpair()/Fdopen()/Fdopendir() functions in this file
+// that provide interoperability with the libc functions with the same (but
+// lowercase) names.
+//
// unique_fd is also known as ScopedFd/ScopedFD/scoped_fd; mentioned here to help
// you find this class if you're searching for one of those names.
-
-#if defined(__BIONIC__)
-#include <android/fdsan.h>
-#endif
-
-namespace android {
-namespace base {
-
-struct DefaultCloser {
-#if defined(__BIONIC__)
- static void Tag(int fd, void* old_addr, void* new_addr) {
- if (android_fdsan_exchange_owner_tag) {
- uint64_t old_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
- reinterpret_cast<uint64_t>(old_addr));
- uint64_t new_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
- reinterpret_cast<uint64_t>(new_addr));
- android_fdsan_exchange_owner_tag(fd, old_tag, new_tag);
- }
- }
- static void Close(int fd, void* addr) {
- if (android_fdsan_close_with_tag) {
- uint64_t tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
- reinterpret_cast<uint64_t>(addr));
- android_fdsan_close_with_tag(fd, tag);
- } else {
- close(fd);
- }
- }
-#else
- static void Close(int fd) {
- // Even if close(2) fails with EINTR, the fd will have been closed.
- // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone
- // else's fd.
- // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
- ::close(fd);
- }
-#endif
-};
-
+//
+// unique_fd itself is a specialization of unique_fd_impl with a default closer.
template <typename Closer>
class unique_fd_impl final {
public:
@@ -175,11 +148,48 @@
}
};
+// The actual details of closing are factored out to support unusual cases.
+// Almost everyone will want this DefaultCloser, which handles fdsan on bionic.
+struct DefaultCloser {
+#if defined(__BIONIC__)
+ static void Tag(int fd, void* old_addr, void* new_addr) {
+ if (android_fdsan_exchange_owner_tag) {
+ uint64_t old_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
+ reinterpret_cast<uint64_t>(old_addr));
+ uint64_t new_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
+ reinterpret_cast<uint64_t>(new_addr));
+ android_fdsan_exchange_owner_tag(fd, old_tag, new_tag);
+ }
+ }
+ static void Close(int fd, void* addr) {
+ if (android_fdsan_close_with_tag) {
+ uint64_t tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
+ reinterpret_cast<uint64_t>(addr));
+ android_fdsan_close_with_tag(fd, tag);
+ } else {
+ close(fd);
+ }
+ }
+#else
+ static void Close(int fd) {
+ // Even if close(2) fails with EINTR, the fd will have been closed.
+ // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone
+ // else's fd.
+ // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
+ ::close(fd);
+ }
+#endif
+};
+
using unique_fd = unique_fd_impl<DefaultCloser>;
#if !defined(_WIN32)
// Inline functions, so that they can be used header-only.
+
+// See pipe(2).
+// This helper hides the details of converting to unique_fd, and also hides the
+// fact that macOS doesn't support O_CLOEXEC or O_NONBLOCK directly.
template <typename Closer>
inline bool Pipe(unique_fd_impl<Closer>* read, unique_fd_impl<Closer>* write,
int flags = O_CLOEXEC) {
@@ -218,6 +228,8 @@
return true;
}
+// See socketpair(2).
+// This helper hides the details of converting to unique_fd.
template <typename Closer>
inline bool Socketpair(int domain, int type, int protocol, unique_fd_impl<Closer>* left,
unique_fd_impl<Closer>* right) {
@@ -230,11 +242,14 @@
return true;
}
+// See socketpair(2).
+// This helper hides the details of converting to unique_fd.
template <typename Closer>
inline bool Socketpair(int type, unique_fd_impl<Closer>* left, unique_fd_impl<Closer>* right) {
return Socketpair(AF_UNIX, type, 0, left, right);
}
+// See fdopen(3).
// Using fdopen with unique_fd correctly is more annoying than it should be,
// because fdopen doesn't close the file descriptor received upon failure.
inline FILE* Fdopen(unique_fd&& ufd, const char* mode) {
@@ -246,6 +261,7 @@
return file;
}
+// See fdopendir(3).
// Using fdopendir with unique_fd correctly is more annoying than it should be,
// because fdopen doesn't close the file descriptor received upon failure.
inline DIR* Fdopendir(unique_fd&& ufd) {
@@ -259,7 +275,20 @@
#endif // !defined(_WIN32)
-// A wrapper type that can be implicitly constructed from either int or unique_fd.
+// A wrapper type that can be implicitly constructed from either int or
+// unique_fd. This supports cases where you don't actually own the file
+// descriptor, and can't take ownership, but are temporarily acting as if
+// you're the owner.
+//
+// One example would be a function that needs to also allow
+// STDERR_FILENO, not just a newly-opened fd. Another example would be JNI code
+// that's using a file descriptor that's actually owned by a
+// ParcelFileDescriptor or whatever on the Java side, but where the JNI code
+// would like to enforce this weaker sense of "temporary ownership".
+//
+// If you think of unique_fd as being like std::string in that represents
+// ownership, borrowed_fd is like std::string_view (and int is like const
+// char*).
struct borrowed_fd {
/* implicit */ borrowed_fd(int fd) : fd_(fd) {} // NOLINT
template <typename T>
diff --git a/liblog_symbols.cpp b/liblog_symbols.cpp
deleted file mode 100644
index 2e4ab3e..0000000
--- a/liblog_symbols.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2020 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 "liblog_symbols.h"
-
-// __ANDROID_APEX_MIN_SDK_VERSION__ is the max of all the minSdkVersions that
-// this module shares an APEX with. In other words, this is the lowest OS
-// version that this code could possibly run on.
-#if defined(__ANDROID_APEX_MIN_SDK_VERSION__) && (__ANDROID_APEX_MIN_SDK_VERSION__ <= 29)
-#define USE_DLSYM
-#endif
-
-// __ANDROID_API__ is the historical name for __ANDROID_MIN_SDK_VERSION__. The
-// latter is not set by the Clang we're currently using. This path will be used
-// when this code is built by NDK modules rather than APEX modules.
-#if defined(__ANDROID_API__) && (__ANDROID_API__ <= 29)
-#define USE_DLSYM
-#endif
-
-#ifdef USE_DLSYM
-#include <dlfcn.h>
-#endif
-
-namespace android {
-namespace base {
-
-#ifdef USE_DLSYM
-
-const std::optional<LibLogFunctions>& GetLibLogFunctions() {
- static std::optional<LibLogFunctions> liblog_functions = []() -> std::optional<LibLogFunctions> {
- void* liblog_handle = dlopen("liblog.so", RTLD_NOW);
- if (liblog_handle == nullptr) {
- return {};
- }
-
- LibLogFunctions real_liblog_functions = {};
-
-#define DLSYM(name) \
- real_liblog_functions.name = \
- reinterpret_cast<decltype(LibLogFunctions::name)>(dlsym(liblog_handle, #name)); \
- if (real_liblog_functions.name == nullptr) { \
- return {}; \
- }
-
- DLSYM(__android_log_set_logger)
- DLSYM(__android_log_write_log_message)
- DLSYM(__android_log_logd_logger)
- DLSYM(__android_log_stderr_logger)
- DLSYM(__android_log_set_aborter)
- DLSYM(__android_log_call_aborter)
- DLSYM(__android_log_default_aborter)
- DLSYM(__android_log_set_minimum_priority);
- DLSYM(__android_log_get_minimum_priority);
- DLSYM(__android_log_set_default_tag);
-#undef DLSYM
-
- return real_liblog_functions;
- }();
-
- return liblog_functions;
-}
-
-#else
-
-const std::optional<LibLogFunctions>& GetLibLogFunctions() {
- static std::optional<LibLogFunctions> liblog_functions = []() -> std::optional<LibLogFunctions> {
- return LibLogFunctions{
- .__android_log_set_logger = __android_log_set_logger,
- .__android_log_write_log_message = __android_log_write_log_message,
- .__android_log_logd_logger = __android_log_logd_logger,
- .__android_log_stderr_logger = __android_log_stderr_logger,
- .__android_log_set_aborter = __android_log_set_aborter,
- .__android_log_call_aborter = __android_log_call_aborter,
- .__android_log_default_aborter = __android_log_default_aborter,
- .__android_log_set_minimum_priority = __android_log_set_minimum_priority,
- .__android_log_get_minimum_priority = __android_log_get_minimum_priority,
- .__android_log_set_default_tag = __android_log_set_default_tag,
- };
- }();
- return liblog_functions;
-}
-
-#endif
-
-} // namespace base
-} // namespace android
diff --git a/liblog_symbols.h b/liblog_symbols.h
deleted file mode 100644
index 2e6b47f..0000000
--- a/liblog_symbols.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <optional>
-
-#include <android/log.h>
-
-namespace android {
-namespace base {
-
-struct LibLogFunctions {
- void (*__android_log_set_logger)(__android_logger_function logger);
- void (*__android_log_write_log_message)(struct __android_log_message* log_message);
-
- void (*__android_log_logd_logger)(const struct __android_log_message* log_message);
- void (*__android_log_stderr_logger)(const struct __android_log_message* log_message);
-
- void (*__android_log_set_aborter)(__android_aborter_function aborter);
- void (*__android_log_call_aborter)(const char* abort_message);
- void (*__android_log_default_aborter)(const char* abort_message);
- int32_t (*__android_log_set_minimum_priority)(int32_t priority);
- int32_t (*__android_log_get_minimum_priority)();
- void (*__android_log_set_default_tag)(const char* tag);
-};
-
-const std::optional<LibLogFunctions>& GetLibLogFunctions();
-
-} // namespace base
-} // namespace android
diff --git a/logging.cpp b/logging.cpp
index d6ecc78..d36126a 100644
--- a/logging.cpp
+++ b/logging.cpp
@@ -32,10 +32,6 @@
#include <errno.h>
#endif
-#if defined(__linux__)
-#include <sys/uio.h>
-#endif
-
#include <atomic>
#include <iostream>
#include <limits>
@@ -60,18 +56,15 @@
#include <android-base/strings.h>
#include <android-base/threads.h>
-#include "liblog_symbols.h"
#include "logging_splitters.h"
namespace android {
namespace base {
// BSD-based systems like Android/macOS have getprogname(). Others need us to provide one.
-#if defined(__GLIBC__) || defined(_WIN32)
+#if !defined(__APPLE__) && !defined(__BIONIC__)
static const char* getprogname() {
-#if defined(__GLIBC__)
- return program_invocation_short_name;
-#elif defined(_WIN32)
+#ifdef _WIN32
static bool first = true;
static char progname[MAX_PATH] = {};
@@ -82,6 +75,8 @@
}
return progname;
+#else
+ return program_invocation_short_name;
#endif
}
#endif
@@ -214,9 +209,8 @@
static std::string* gDefaultTag;
void SetDefaultTag(const std::string& tag) {
- static auto& liblog_functions = GetLibLogFunctions();
- if (liblog_functions) {
- liblog_functions->__android_log_set_default_tag(tag.c_str());
+ if (__builtin_available(android 30, *)) {
+ __android_log_set_default_tag(tag.c_str());
} else {
std::lock_guard<std::recursive_mutex> lock(TagLock());
if (gDefaultTag != nullptr) {
@@ -257,20 +251,22 @@
int level = kLogSeverityToKernelLogLevel[severity];
- // The kernel's printk buffer is only 1024 bytes.
- // TODO: should we automatically break up long lines into multiple lines?
- // Or we could log but with something like "..." at the end?
- char buf[1024] __attribute__((__uninitialized__));
+ // The kernel's printk buffer is only |1024 - PREFIX_MAX| bytes, where
+ // PREFIX_MAX could be 48 or 32.
+ // Reference: kernel/printk/printk.c
+ static constexpr int LOG_LINE_MAX = 1024 - 48;
+ char buf[LOG_LINE_MAX] __attribute__((__uninitialized__));
size_t size = snprintf(buf, sizeof(buf), "<%d>%s: %.*s\n", level, tag, length, msg);
- if (size > sizeof(buf)) {
- size = snprintf(buf, sizeof(buf), "<%d>%s: %zu-byte message too long for printk\n",
- level, tag, size);
- }
+ TEMP_FAILURE_RETRY(write(klog_fd, buf, std::min(size, sizeof(buf))));
- iovec iov[1];
- iov[0].iov_base = buf;
- iov[0].iov_len = size;
- TEMP_FAILURE_RETRY(writev(klog_fd, iov, 1));
+ if (size > sizeof(buf)) {
+ size_t truncated = size - sizeof(buf);
+ size = snprintf(
+ buf, sizeof(buf),
+ "<%d>%s: **previous message missing %zu bytes** %zu-byte message too long for printk\n",
+ level, tag, truncated, size);
+ TEMP_FAILURE_RETRY(write(klog_fd, buf, std::min(size, sizeof(buf))));
+ }
}
void KernelLogger(android::base::LogId, android::base::LogSeverity severity, const char* tag,
@@ -318,11 +314,10 @@
int32_t lg_id = LogIdTolog_id_t(id);
int32_t priority = LogSeverityToPriority(severity);
- static auto& liblog_functions = GetLibLogFunctions();
- if (liblog_functions) {
+ if (__builtin_available(android 30, *)) {
__android_log_message log_message = {sizeof(__android_log_message), lg_id, priority, tag,
static_cast<const char*>(nullptr), 0, message};
- liblog_functions->__android_log_logd_logger(&log_message);
+ __android_log_logd_logger(&log_message);
} else {
__android_log_buf_print(lg_id, priority, tag, "%s", message);
}
@@ -401,9 +396,8 @@
LogFunction old_logger = std::move(Logger());
Logger() = std::move(logger);
- static auto& liblog_functions = GetLibLogFunctions();
- if (liblog_functions) {
- liblog_functions->__android_log_set_logger([](const struct __android_log_message* log_message) {
+ if (__builtin_available(android 30, *)) {
+ __android_log_set_logger([](const struct __android_log_message* log_message) {
auto log_id = log_id_tToLogId(log_message->buffer_id);
auto severity = PriorityToLogSeverity(log_message->priority);
@@ -418,10 +412,8 @@
AbortFunction old_aborter = std::move(Aborter());
Aborter() = std::move(aborter);
- static auto& liblog_functions = GetLibLogFunctions();
- if (liblog_functions) {
- liblog_functions->__android_log_set_aborter(
- [](const char* abort_message) { Aborter()(abort_message); });
+ if (__builtin_available(android 30, *)) {
+ __android_log_set_aborter([](const char* abort_message) { Aborter()(abort_message); });
}
return old_aborter;
}
@@ -508,9 +500,8 @@
// Abort if necessary.
if (data_->GetSeverity() == FATAL) {
- static auto& liblog_functions = GetLibLogFunctions();
- if (liblog_functions) {
- liblog_functions->__android_log_call_aborter(msg.c_str());
+ if (__builtin_available(android 30, *)) {
+ __android_log_call_aborter(msg.c_str());
} else {
Aborter()(msg.c_str());
}
@@ -523,12 +514,11 @@
void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag,
const char* message) {
- static auto& liblog_functions = GetLibLogFunctions();
int32_t priority = LogSeverityToPriority(severity);
- if (liblog_functions) {
+ if (__builtin_available(android 30, *)) {
__android_log_message log_message = {
sizeof(__android_log_message), LOG_ID_DEFAULT, priority, tag, file, line, message};
- liblog_functions->__android_log_write_log_message(&log_message);
+ __android_log_write_log_message(&log_message);
} else {
if (tag == nullptr) {
std::lock_guard<std::recursive_mutex> lock(TagLock());
@@ -544,20 +534,18 @@
}
LogSeverity GetMinimumLogSeverity() {
- static auto& liblog_functions = GetLibLogFunctions();
- if (liblog_functions) {
- return PriorityToLogSeverity(liblog_functions->__android_log_get_minimum_priority());
+ if (__builtin_available(android 30, *)) {
+ return PriorityToLogSeverity(__android_log_get_minimum_priority());
} else {
return gMinimumLogSeverity;
}
}
bool ShouldLog(LogSeverity severity, const char* tag) {
- static auto& liblog_functions = GetLibLogFunctions();
// Even though we're not using the R liblog functions in this function, if we're running on Q,
// we need to fall back to using gMinimumLogSeverity, since __android_log_is_loggable() will not
// take into consideration the value from SetMinimumLogSeverity().
- if (liblog_functions) {
+ if (__builtin_available(android 30, *)) {
int32_t priority = LogSeverityToPriority(severity);
return __android_log_is_loggable(priority, tag, ANDROID_LOG_INFO);
} else {
@@ -566,10 +554,9 @@
}
LogSeverity SetMinimumLogSeverity(LogSeverity new_severity) {
- static auto& liblog_functions = GetLibLogFunctions();
- if (liblog_functions) {
+ if (__builtin_available(android 30, *)) {
int32_t priority = LogSeverityToPriority(new_severity);
- return PriorityToLogSeverity(liblog_functions->__android_log_set_minimum_priority(priority));
+ return PriorityToLogSeverity(__android_log_set_minimum_priority(priority));
} else {
LogSeverity old_severity = gMinimumLogSeverity;
gMinimumLogSeverity = new_severity;
diff --git a/result_test.cpp b/result_test.cpp
index c0ac0fd..88eb658 100644
--- a/result_test.cpp
+++ b/result_test.cpp
@@ -21,9 +21,17 @@
#include <istream>
#include <string>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include "android-base/result-gmock.h"
+
using namespace std::string_literals;
+using ::testing::Eq;
+using ::testing::ExplainMatchResult;
+using ::testing::HasSubstr;
+using ::testing::Not;
+using ::testing::StartsWith;
namespace android {
namespace base {
@@ -418,5 +426,99 @@
outer.error().message());
}
+namespace testing {
+
+class Listener : public ::testing::MatchResultListener {
+ public:
+ Listener() : MatchResultListener(&ss_) {}
+ ~Listener() = default;
+ std::string message() const { return ss_.str(); }
+
+ private:
+ std::stringstream ss_;
+};
+
+class ResultMatchers : public ::testing::Test {
+ public:
+ Result<int> result = 1;
+ Result<int> error = Error(EBADF) << "error message";
+ Listener listener;
+};
+
+TEST_F(ResultMatchers, ok_result) {
+ EXPECT_TRUE(ExplainMatchResult(Ok(), result, &listener));
+ EXPECT_THAT(listener.message(), Eq("result is OK"));
+}
+
+TEST_F(ResultMatchers, ok_error) {
+ EXPECT_FALSE(ExplainMatchResult(Ok(), error, &listener));
+ EXPECT_THAT(listener.message(), StartsWith("error is"));
+ EXPECT_THAT(listener.message(), HasSubstr(error.error().message()));
+ EXPECT_THAT(listener.message(), HasSubstr(strerror(error.error().code())));
+}
+
+TEST_F(ResultMatchers, not_ok_result) {
+ EXPECT_FALSE(ExplainMatchResult(Not(Ok()), result, &listener));
+ EXPECT_THAT(listener.message(), Eq("result is OK"));
+}
+
+TEST_F(ResultMatchers, not_ok_error) {
+ EXPECT_TRUE(ExplainMatchResult(Not(Ok()), error, &listener));
+ EXPECT_THAT(listener.message(), StartsWith("error is"));
+ EXPECT_THAT(listener.message(), HasSubstr(error.error().message()));
+ EXPECT_THAT(listener.message(), HasSubstr(strerror(error.error().code())));
+}
+
+TEST_F(ResultMatchers, has_value_result) {
+ EXPECT_TRUE(ExplainMatchResult(HasValue(*result), result, &listener));
+}
+
+TEST_F(ResultMatchers, has_value_wrong_result) {
+ EXPECT_FALSE(ExplainMatchResult(HasValue(*result + 1), result, &listener));
+}
+
+TEST_F(ResultMatchers, has_value_error) {
+ EXPECT_FALSE(ExplainMatchResult(HasValue(*result), error, &listener));
+ EXPECT_THAT(listener.message(), StartsWith("error is"));
+ EXPECT_THAT(listener.message(), HasSubstr(error.error().message()));
+ EXPECT_THAT(listener.message(), HasSubstr(strerror(error.error().code())));
+}
+
+TEST_F(ResultMatchers, has_error_code_result) {
+ EXPECT_FALSE(ExplainMatchResult(HasError(WithCode(error.error().code())), result, &listener));
+ EXPECT_THAT(listener.message(), Eq("result is OK"));
+}
+
+TEST_F(ResultMatchers, has_error_code_wrong_code) {
+ EXPECT_FALSE(ExplainMatchResult(HasError(WithCode(error.error().code() + 1)), error, &listener));
+ EXPECT_THAT(listener.message(), StartsWith("actual error is"));
+ EXPECT_THAT(listener.message(), HasSubstr(strerror(error.error().code())));
+}
+
+TEST_F(ResultMatchers, has_error_code_correct_code) {
+ EXPECT_TRUE(ExplainMatchResult(HasError(WithCode(error.error().code())), error, &listener));
+ EXPECT_THAT(listener.message(), StartsWith("actual error is"));
+ EXPECT_THAT(listener.message(), HasSubstr(strerror(error.error().code())));
+}
+
+TEST_F(ResultMatchers, has_error_message_result) {
+ EXPECT_FALSE(
+ ExplainMatchResult(HasError(WithMessage(error.error().message())), result, &listener));
+ EXPECT_THAT(listener.message(), Eq("result is OK"));
+}
+
+TEST_F(ResultMatchers, has_error_message_wrong_message) {
+ EXPECT_FALSE(ExplainMatchResult(HasError(WithMessage("foo")), error, &listener));
+ EXPECT_THAT(listener.message(), StartsWith("actual error is"));
+ EXPECT_THAT(listener.message(), HasSubstr(error.error().message()));
+}
+
+TEST_F(ResultMatchers, has_error_message_correct_message) {
+ EXPECT_TRUE(ExplainMatchResult(HasError(WithMessage(error.error().message())), error, &listener));
+ EXPECT_THAT(listener.message(), StartsWith("actual error is"));
+ EXPECT_THAT(listener.message(), HasSubstr(error.error().message()));
+}
+
+} // namespace testing
} // namespace base
} // namespace android