Snap for 10453563 from 2f003fc209a6552d59640a281830a73e75754bb7 to mainline-permission-release

Change-Id: Ie9f6dab794bc13fa597a3e504bcb51d6d5c4c321
diff --git a/Android.bp b/Android.bp
index ef56692..d2cdadd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -283,7 +283,11 @@
     name: "libbase_benchmark",
     defaults: ["libbase_cflags_defaults"],
 
-    srcs: ["format_benchmark.cpp"],
+    srcs: [
+        "file_benchmark.cpp",
+        "format_benchmark.cpp",
+        "function_ref_benchmark.cpp",
+    ],
     shared_libs: ["libbase"],
 
     compile_multilib: "both",
diff --git a/TEST_MAPPING b/TEST_MAPPING
index a3b2bfc..3724fa5 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -4,7 +4,7 @@
       "name": "libbase_test"
     }
   ],
-  "hwasan-postsubmit": [
+  "hwasan-presubmit": [
     {
       "name": "libbase_test"
     }
diff --git a/abi_compatibility.cpp b/abi_compatibility.cpp
index 06a7801..b5e4741 100644
--- a/abi_compatibility.cpp
+++ b/abi_compatibility.cpp
@@ -46,7 +46,11 @@
 }
 
 bool WriteStringToFd(const std::string& content, int fd) {
-  return WriteStringToFd(content, borrowed_fd(fd));
+  return WriteStringToFd(std::string_view(content), borrowed_fd(fd));
+}
+
+bool WriteStringToFd(const std::string& content, borrowed_fd fd) {
+  return WriteStringToFd(std::string_view(content), fd);
 }
 
 bool ReadFully(int fd, void* data, size_t byte_count) {
@@ -61,6 +65,14 @@
   return WriteFully(borrowed_fd(fd), data, byte_count);
 }
 
+std::string Basename(const std::string& path) {
+  return Basename(std::string_view(path));
+}
+
+std::string Dirname(const std::string& path) {
+  return Dirname(std::string_view(path));
+}
+
 #if defined(__LP64__)
 #define MAPPEDFILE_FROMFD _ZN10MappedFile6FromFdEilmi
 #else
diff --git a/file.cpp b/file.cpp
index a580dcc..69ee69f 100644
--- a/file.cpp
+++ b/file.cpp
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -225,7 +226,7 @@
     content->reserve(sb.st_size);
   }
 
-  char buf[BUFSIZ] __attribute__((__uninitialized__));
+  char buf[4096] __attribute__((__uninitialized__));
   ssize_t n;
   while ((n = TEMP_FAILURE_RETRY(read(fd.get(), &buf[0], sizeof(buf)))) > 0) {
     content->append(buf, n);
@@ -244,7 +245,7 @@
   return ReadFdToString(fd, content);
 }
 
-bool WriteStringToFd(const std::string& content, borrowed_fd fd) {
+bool WriteStringToFd(std::string_view content, borrowed_fd fd) {
   const char* p = content.data();
   size_t left = content.size();
   while (left > 0) {
@@ -336,6 +337,21 @@
   }
   return static_cast<ssize_t>(bytes_read);
 }
+
+static ssize_t pwrite(borrowed_fd fd, const void* data, size_t byte_count, off64_t offset) {
+  DWORD bytes_written;
+  OVERLAPPED overlapped;
+  memset(&overlapped, 0, sizeof(OVERLAPPED));
+  overlapped.Offset = static_cast<DWORD>(offset);
+  overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
+  if (!WriteFile(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), data,
+                 static_cast<DWORD>(byte_count), &bytes_written, &overlapped)) {
+    // In case someone tries to read errno (since this is masquerading as a POSIX call)
+    errno = EIO;
+    return -1;
+  }
+  return static_cast<ssize_t>(bytes_written);
+}
 #endif
 
 bool ReadFullyAtOffset(borrowed_fd fd, void* data, size_t byte_count, off64_t offset) {
@@ -350,6 +366,19 @@
   return true;
 }
 
+bool WriteFullyAtOffset(borrowed_fd fd, const void* data, size_t byte_count, off64_t offset) {
+  const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
+  size_t remaining = byte_count;
+  while (remaining > 0) {
+    ssize_t n = TEMP_FAILURE_RETRY(pwrite(fd.get(), p, remaining, offset));
+    if (n == -1) return false;
+    p += n;
+    remaining -= n;
+    offset += n;
+  }
+  return true;
+}
+
 bool WriteFully(borrowed_fd fd, const void* data, size_t byte_count) {
   const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
   size_t remaining = byte_count;
@@ -469,7 +498,7 @@
 }
 
 #if defined(_WIN32)
-std::string Basename(const std::string& path) {
+std::string Basename(std::string_view path) {
   // TODO: how much of this is actually necessary for mingw?
 
   // Copy path because basename may modify the string passed in.
@@ -495,21 +524,21 @@
 }
 #else
 // Copied from bionic so that Basename() below can be portable and thread-safe.
-static int __basename_r(const char* path, char* buffer, size_t buffer_size) {
+static int _basename_r(const char* path, size_t path_size, char* buffer, size_t buffer_size) {
   const char* startp = nullptr;
   const char* endp = nullptr;
   int len;
   int result;
 
   // Empty or NULL string gets treated as ".".
-  if (path == nullptr || *path == '\0') {
+  if (path == nullptr || path_size == 0) {
     startp = ".";
     len = 1;
     goto Exit;
   }
 
   // Strip trailing slashes.
-  endp = path + strlen(path) - 1;
+  endp = path + path_size - 1;
   while (endp > path && *endp == '/') {
     endp--;
   }
@@ -546,25 +575,26 @@
   }
   return result;
 }
-std::string Basename(const std::string& path) {
-  char buf[PATH_MAX];
-  __basename_r(path.c_str(), buf, sizeof(buf));
-  return buf;
+std::string Basename(std::string_view path) {
+  char buf[PATH_MAX] __attribute__((__uninitialized__));
+  const auto size = _basename_r(path.data(), path.size(), buf, sizeof(buf));
+  return size > 0 ? std::string(buf, size) : std::string();
 }
 #endif
 
-std::string Dirname(const std::string& path) {
+#if defined(_WIN32)
+std::string Dirname(std::string_view path) {
+  // TODO: how much of this is actually necessary for mingw?
+
   // Copy path because dirname may modify the string passed in.
   std::string result(path);
 
-#if !defined(__BIONIC__)
   // Use lock because dirname() may write to a process global and return a
   // pointer to that. Note that this locking strategy only works if all other
   // callers to dirname in the process also grab this same lock, but its
   // better than nothing.  Bionic's dirname returns a thread-local buffer.
   static std::mutex& dirname_lock = *new std::mutex();
   std::lock_guard<std::mutex> lock(dirname_lock);
-#endif
 
   // Note that if std::string uses copy-on-write strings, &str[0] will cause
   // the copy to be made, so there is no chance of us accidentally writing to
@@ -577,6 +607,72 @@
 
   return result;
 }
+#else
+// Copied from bionic so that Dirname() below can be portable and thread-safe.
+static int _dirname_r(const char* path, size_t path_size, char* buffer, size_t buffer_size) {
+  const char* endp = nullptr;
+  int len;
+  int result;
+
+  // Empty or NULL string gets treated as ".".
+  if (path == nullptr || path_size == 0) {
+    path = ".";
+    len = 1;
+    goto Exit;
+  }
+
+  // Strip trailing slashes.
+  endp = path + path_size - 1;
+  while (endp > path && *endp == '/') {
+    endp--;
+  }
+
+  // Find the start of the dir.
+  while (endp > path && *endp != '/') {
+    endp--;
+  }
+
+  // Either the dir is "/" or there are no slashes.
+  if (endp == path) {
+    path = (*endp == '/') ? "/" : ".";
+    len = 1;
+    goto Exit;
+  }
+
+  do {
+    endp--;
+  } while (endp > path && *endp == '/');
+
+  len = endp - path + 1;
+
+ Exit:
+  result = len;
+  if (len + 1 > MAXPATHLEN) {
+    errno = ENAMETOOLONG;
+    return -1;
+  }
+  if (buffer == nullptr) {
+    return result;
+  }
+
+  if (len > static_cast<int>(buffer_size) - 1) {
+    len = buffer_size - 1;
+    result = -1;
+    errno = ERANGE;
+  }
+
+  if (len >= 0) {
+    memcpy(buffer, path, len);
+    buffer[len] = 0;
+  }
+  return result;
+}
+std::string Dirname(std::string_view path) {
+  char buf[PATH_MAX] __attribute__((__uninitialized__));
+  const auto size = _dirname_r(path.data(), path.size(), buf, sizeof(buf));
+  return size > 0 ? std::string(buf, size) : std::string();
+}
+#endif
 
 }  // namespace base
 }  // namespace android
diff --git a/file_benchmark.cpp b/file_benchmark.cpp
new file mode 100644
index 0000000..86252ce
--- /dev/null
+++ b/file_benchmark.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 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 <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <benchmark/benchmark.h>
+
+#include "android-base/file.h"
+#include "android-base/logging.h"
+
+static void BenchmarkReadFdToString(benchmark::State& state) {
+  android::base::unique_fd fd(memfd_create("memfile", 0));
+  CHECK(fd.get() > 0);
+  CHECK_EQ(ftruncate(fd, state.range(0)), 0);
+  for (auto _ : state) {
+    CHECK_EQ(lseek(fd, 0, SEEK_SET), 0);
+    std::string str;
+    benchmark::DoNotOptimize(android::base::ReadFdToString(fd, &str));
+  }
+  state.SetBytesProcessed(state.iterations() * state.range(0));
+}
+
+BENCHMARK_RANGE(BenchmarkReadFdToString, 0, 1024 * 1024);
diff --git a/file_test.cpp b/file_test.cpp
index c739664..2474f7b 100644
--- a/file_test.cpp
+++ b/file_test.cpp
@@ -176,7 +176,7 @@
 }
 #endif
 
-TEST(file, WriteStringToFd) {
+TEST(file, WriteStringToFd_StringLiteral) {
   TemporaryFile tf;
   ASSERT_NE(tf.fd, -1) << tf.path;
   ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
@@ -188,6 +188,32 @@
   EXPECT_EQ("abc", s);
 }
 
+TEST(file, WriteStringToFd_String) {
+  std::string testStr = "def";
+  TemporaryFile tf;
+  ASSERT_NE(tf.fd, -1) << tf.path;
+  ASSERT_TRUE(android::base::WriteStringToFd(testStr, tf.fd));
+
+  ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
+
+  std::string s;
+  ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
+  EXPECT_EQ(testStr, s);
+}
+
+TEST(file, WriteStringToFd_StringView) {
+  std::string_view testStrView = "ghi";
+  TemporaryFile tf;
+  ASSERT_NE(tf.fd, -1) << tf.path;
+  ASSERT_TRUE(android::base::WriteStringToFd(testStrView, tf.fd));
+
+  ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
+
+  std::string s;
+  ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
+  EXPECT_EQ(testStrView, s);
+}
+
 TEST(file, WriteFully) {
   TemporaryFile tf;
   ASSERT_NE(tf.fd, -1) << tf.path;
@@ -350,6 +376,15 @@
   EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh"));
   EXPECT_EQ(".", android::base::Dirname("sh"));
   EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh/"));
+
+  // Since we've copy & pasted bionic's implementation, copy & paste the tests.
+  EXPECT_EQ(".", android::base::Dirname(""));
+  EXPECT_EQ("/usr", android::base::Dirname("/usr/lib"));
+  EXPECT_EQ("/", android::base::Dirname("/usr/"));
+  EXPECT_EQ(".", android::base::Dirname("usr"));
+  EXPECT_EQ(".", android::base::Dirname("."));
+  EXPECT_EQ(".", android::base::Dirname(".."));
+  EXPECT_EQ("/", android::base::Dirname("/"));
 }
 
 TEST(file, ReadFileToString_capacity) {
diff --git a/function_ref_benchmark.cpp b/function_ref_benchmark.cpp
new file mode 100644
index 0000000..404043e
--- /dev/null
+++ b/function_ref_benchmark.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 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 <benchmark/benchmark.h>
+
+#include <functional>
+#include <utility>
+
+#include <time.h>
+
+using android::base::function_ref;
+
+template <class Callable, class... Args>
+[[clang::noinline]] auto call(Callable&& c, Args&&... args) {
+  return c(std::forward<Args>(args)...);
+}
+
+[[clang::noinline]] static int testFunc(int, const char*, char) {
+  return time(nullptr);
+}
+
+using Func = decltype(testFunc);
+
+static void BenchmarkFuncRaw(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(call(testFunc, 1, "1", '1'));
+  }
+}
+BENCHMARK(BenchmarkFuncRaw);
+
+static void BenchmarkFuncPtr(benchmark::State& state) {
+  auto ptr = &testFunc;
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(call(ptr, 1, "1", '1'));
+  }
+}
+BENCHMARK(BenchmarkFuncPtr);
+
+static void BenchmarkStdFunction(benchmark::State& state) {
+  std::function<Func> f(testFunc);
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(call(f, 1, "1", '1'));
+  }
+}
+BENCHMARK(BenchmarkStdFunction);
+
+static void BenchmarkFunctionRef(benchmark::State& state) {
+  function_ref<Func> f(testFunc);
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(call(f, 1, "1", '1'));
+  }
+}
+BENCHMARK(BenchmarkFunctionRef);
+
+namespace {
+struct BigFunc {
+  char big[128];
+  [[clang::noinline]] int operator()(int, const char*, char) const { return time(nullptr); }
+};
+
+static BigFunc bigFunc;
+}  // namespace
+
+static void BenchmarkBigRaw(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(call(bigFunc, 1, "1", '1'));
+  }
+}
+BENCHMARK(BenchmarkBigRaw);
+
+static void BenchmarkBigStdFunction(benchmark::State& state) {
+  std::function<Func> f(bigFunc);
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(call(f, 1, "1", '1'));
+  }
+}
+BENCHMARK(BenchmarkBigStdFunction);
+
+static void BenchmarkBigFunctionRef(benchmark::State& state) {
+  function_ref<Func> f(bigFunc);
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(call(f, 1, "1", '1'));
+  }
+}
+BENCHMARK(BenchmarkBigFunctionRef);
+
+static void BenchmarkMakeFunctionRef(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(call<function_ref<Func>>(bigFunc, 1, "1", '1'));
+  }
+}
+BENCHMARK(BenchmarkMakeFunctionRef);
+
+static void BenchmarkMakeStdFunction(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(call<std::function<Func>>(bigFunc, 1, "1", '1'));
+  }
+}
+BENCHMARK(BenchmarkMakeStdFunction);
diff --git a/include/android-base/file.h b/include/android-base/file.h
index c622562..b11b305 100644
--- a/include/android-base/file.h
+++ b/include/android-base/file.h
@@ -84,7 +84,7 @@
 
 bool WriteStringToFile(const std::string& content, const std::string& path,
                        bool follow_symlinks = false);
-bool WriteStringToFd(const std::string& content, borrowed_fd fd);
+bool WriteStringToFd(std::string_view content, borrowed_fd fd);
 
 #if !defined(_WIN32)
 bool WriteStringToFile(const std::string& content, const std::string& path,
@@ -105,6 +105,7 @@
 bool ReadFullyAtOffset(borrowed_fd fd, void* data, size_t byte_count, off64_t offset);
 
 bool WriteFully(borrowed_fd fd, const void* data, size_t byte_count);
+bool WriteFullyAtOffset(borrowed_fd fd, const void* data, size_t byte_count, off64_t offset);
 
 bool RemoveFileIfExists(const std::string& path, std::string* err = nullptr);
 
@@ -118,8 +119,8 @@
 
 // Like the regular basename and dirname, but thread-safe on all
 // platforms and capable of correctly handling exotic Windows paths.
-std::string Basename(const std::string& path);
-std::string Dirname(const std::string& path);
+std::string Basename(std::string_view path);
+std::string Dirname(std::string_view path);
 
 }  // namespace base
 }  // namespace android
diff --git a/include/android-base/function_ref.h b/include/android-base/function_ref.h
index 2de14e3..42594cc 100644
--- a/include/android-base/function_ref.h
+++ b/include/android-base/function_ref.h
@@ -87,40 +87,47 @@
   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)) {}
+  using RawFunc = Ret(Args...);
+
+  function_ref(RawFunc* funcptr) noexcept { *this = funcptr; }
 
   template <class Callable, class = std::enable_if_t<
-                                std::is_invocable_r<Ret, Callable, Args...>::value &&
+                                std::is_invocable_r_v<Ret, Callable, Args...> &&
+                                !std::is_same_v<function_ref, std::remove_reference_t<Callable>>>>
+  function_ref(Callable&& c) noexcept {
+    *this = std::forward<Callable>(c);
+  }
+
+  function_ref& operator=(RawFunc* funcptr) noexcept {
+    mTypeErasedFunction = [](uintptr_t funcptr, Args... args) -> Ret {
+      return (reinterpret_cast<RawFunc*>(funcptr))(std::forward<Args>(args)...);
+    };
+    mCallable = reinterpret_cast<uintptr_t>(funcptr);
+    return *this;
+  }
+
+  template <class Callable, class = std::enable_if_t<
+                                std::is_invocable_r_v<Ret, Callable, Args...> &&
                                 !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 {
+    mTypeErasedFunction = [](uintptr_t callable, Args... args) -> Ret {
       // Generate a lambda that remembers the type of the passed
       // |Callable|.
-      return (*reinterpret_cast<std::remove_reference_t<Callable>*>(self->mCallable))(
+      return (*reinterpret_cast<std::remove_reference_t<Callable>*>(callable))(
           std::forward<Args>(args)...);
     };
-    mCallable = reinterpret_cast<intptr_t>(&c);
+    mCallable = reinterpret_cast<uintptr_t>(&c);
     return *this;
   }
 
   Ret operator()(Args... args) const {
-    return mTypeErasedFunction(this, std::forward<Args>(args)...);
+    return mTypeErasedFunction(mCallable, std::forward<Args>(args)...);
   }
 
  private:
-  using TypeErasedFunc = Ret(const function_ref*, Args...);
+  using TypeErasedFunc = Ret(uintptr_t, Args...);
   TypeErasedFunc* mTypeErasedFunction;
-  intptr_t mCallable;
+  uintptr_t mCallable;
 };
 
 }  // namespace android::base
diff --git a/include/android-base/macros.h b/include/android-base/macros.h
index 546b2ec..f141f34 100644
--- a/include/android-base/macros.h
+++ b/include/android-base/macros.h
@@ -141,6 +141,8 @@
 #define ABI_STRING "arm64"
 #elif defined(__i386__)
 #define ABI_STRING "x86"
+#elif defined(__riscv)
+#define ABI_STRING "riscv64"
 #elif defined(__x86_64__)
 #define ABI_STRING "x86_64"
 #endif
diff --git a/include/android-base/parseint.h b/include/android-base/parseint.h
index be8b97b..c76d625 100644
--- a/include/android-base/parseint.h
+++ b/include/android-base/parseint.h
@@ -44,6 +44,9 @@
     return false;
   }
 
+  // This is never out of bounds. If string is zero-sized, s[0] == '\0'
+  // so the second condition is not checked. If string is "0",
+  // s[1] will compare against the '\0'.
   int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
   errno = 0;
   char* end;
diff --git a/include/android-base/result.h b/include/android-base/result.h
index 9715a8c..3c325f2 100644
--- a/include/android-base/result.h
+++ b/include/android-base/result.h
@@ -369,8 +369,9 @@
 };
 
 #ifdef __cpp_concepts
-template<class U>
-concept Trivial = std::is_same_v<U, U>;
+template <class U>
+// Define a concept which **any** type matches to
+concept Universal = std::is_same_v<U, U>;
 #endif
 } // namespace impl
 
@@ -389,7 +390,14 @@
   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()); }
+  static T Unwrap(V&& val) {
+    if constexpr (std::is_same_v<T, void>) {
+      assert(IsOk(val));
+      return;
+    } else {
+      return std::move(val.value());
+    }
+  }
 
   // Consumes V when it's a fail value
   static const OkOrFail<V> Fail(V&& v) {
@@ -403,11 +411,16 @@
     return unexpected(std::move(this->error_));
   }
 #ifdef __cpp_concepts
-  template <impl::Trivial U>
+  // The idea here is to match this template method to any type (not simply trivial types).
+  // The reason for including a constraint is to take advantage of the fact that a constrained
+  // method always has strictly lower precedence than a non-constrained method in template
+  // specialization rules (thus avoiding ambiguity). So we use a universally matching constraint to
+  // mark this function as less preferable (but still accepting of all types).
+  template <impl::Universal U>
 #else
   template <typename U>
 #endif
-  operator const Result<U, E, include_message>() const && {
+  operator const Result<U, E, include_message>() const&& {
     return unexpected(std::move(this->error_));
   }
 
diff --git a/include/android-base/strings.h b/include/android-base/strings.h
index e794540..9557fad 100644
--- a/include/android-base/strings.h
+++ b/include/android-base/strings.h
@@ -16,9 +16,13 @@
 
 #pragma once
 
+#include <ctype.h>
+
 #include <sstream>
 #include <string>
 #include <string_view>
+#include <type_traits>
+#include <utility>
 #include <vector>
 
 namespace android {
@@ -46,8 +50,48 @@
 // The empty string is not a valid delimiter list.
 std::vector<std::string> Tokenize(const std::string& s, const std::string& delimiters);
 
-// Trims whitespace off both ends of the given string.
-std::string Trim(const std::string& s);
+namespace internal {
+template <typename>
+constexpr bool always_false_v = false;
+}
+
+template <typename T>
+std::string Trim(T&& t) {
+  std::string_view sv;
+  std::string s;
+  if constexpr (std::is_convertible_v<T, std::string_view>) {
+    sv = std::forward<T>(t);
+  } else if constexpr (std::is_convertible_v<T, std::string>) {
+    // The previous version of this function allowed for types which are implicitly convertible
+    // to std::string but not to std::string_view. For these types we go through std::string first
+    // here in order to retain source compatibility.
+    s = t;
+    sv = s;
+  } else {
+    static_assert(internal::always_false_v<T>,
+                  "Implicit conversion to std::string or std::string_view not possible");
+  }
+
+  // Skip initial whitespace.
+  while (!sv.empty() && isspace(sv.front())) {
+    sv.remove_prefix(1);
+  }
+
+  // Skip terminating whitespace.
+  while (!sv.empty() && isspace(sv.back())) {
+    sv.remove_suffix(1);
+  }
+
+  return std::string(sv);
+}
+
+// We instantiate the common cases in strings.cpp.
+extern template std::string Trim(const char*&);
+extern template std::string Trim(const char*&&);
+extern template std::string Trim(const std::string&);
+extern template std::string Trim(const std::string&&);
+extern template std::string Trim(std::string_view&);
+extern template std::string Trim(std::string_view&&);
 
 // Joins a container of things into a single string, using the given separator.
 template <typename ContainerT, typename SeparatorT>
diff --git a/include/android-base/unique_fd.h b/include/android-base/unique_fd.h
index e929e4c..1ffe02f 100644
--- a/include/android-base/unique_fd.h
+++ b/include/android-base/unique_fd.h
@@ -32,7 +32,7 @@
 #if defined(__BIONIC__)
 #include <android/fdsan.h>
 #endif
-#if !defined(_WIN32)
+#if !defined(_WIN32) && !defined(__TRUSTY__)
 #include <sys/socket.h>
 #endif
 
@@ -183,7 +183,7 @@
 
 using unique_fd = unique_fd_impl<DefaultCloser>;
 
-#if !defined(_WIN32)
+#if !defined(_WIN32) && !defined(__TRUSTY__)
 
 // Inline functions, so that they can be used header-only.
 
@@ -273,7 +273,7 @@
   return dir;
 }
 
-#endif  // !defined(_WIN32)
+#endif  // !defined(_WIN32) && !defined(__TRUSTY__)
 
 // 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
diff --git a/result_test.cpp b/result_test.cpp
index 19b48c3..b2cd303 100644
--- a/result_test.cpp
+++ b/result_test.cpp
@@ -16,6 +16,7 @@
 
 #include "android-base/result.h"
 #include <utils/ErrorsMacros.h>
+#include "android-base/errors.h"
 #include "errno.h"
 
 #include <istream>
@@ -488,6 +489,17 @@
   EXPECT_EQ(**result2, 3);
 }
 
+TEST(result, void) {
+  using testing::Ok;
+
+  auto return_void = []() -> Result<void> {
+    OR_RETURN(Result<void>());
+    return {};
+  };
+
+  ASSERT_THAT(return_void(), Ok());
+}
+
 struct ConstructorTracker {
   static size_t constructor_called;
   static size_t copy_constructor_called;
diff --git a/strings.cpp b/strings.cpp
index deb6e28..5ff2a52 100644
--- a/strings.cpp
+++ b/strings.cpp
@@ -69,40 +69,18 @@
   return result;
 }
 
+[[deprecated("Retained only for binary compatibility (symbol name)")]]
 std::string Trim(const std::string& s) {
-  std::string result;
-
-  if (s.size() == 0) {
-    return result;
-  }
-
-  size_t start_index = 0;
-  size_t end_index = s.size() - 1;
-
-  // Skip initial whitespace.
-  while (start_index < s.size()) {
-    if (!isspace(s[start_index])) {
-      break;
-    }
-    start_index++;
-  }
-
-  // Skip terminating whitespace.
-  while (end_index >= start_index) {
-    if (!isspace(s[end_index])) {
-      break;
-    }
-    end_index--;
-  }
-
-  // All spaces, no beef.
-  if (end_index < start_index) {
-    return "";
-  }
-  // Start_index is the first non-space, end_index is the last one.
-  return s.substr(start_index, end_index - start_index + 1);
+  return Trim(std::string_view(s));
 }
 
+template std::string Trim(const char*&);
+template std::string Trim(const char*&&);
+template std::string Trim(const std::string&);
+template std::string Trim(const std::string&&);
+template std::string Trim(std::string_view&);
+template std::string Trim(std::string_view&&);
+
 // These cases are probably the norm, so we mark them extern in the header to
 // aid compile time and binary size.
 template std::string Join(const std::vector<std::string>&, char);
diff --git a/strings_test.cpp b/strings_test.cpp
index fb111b8..f92e39a 100644
--- a/strings_test.cpp
+++ b/strings_test.cpp
@@ -157,6 +157,22 @@
   ASSERT_EQ("foo", android::base::Trim("\v\tfoo\n\f"));
 }
 
+TEST(strings, trim_build_implicit_string_conversion) {
+  struct Foo {
+    operator std::string() { return " foo "; }
+    explicit operator std::string_view() { return " foo "; }
+  };
+  ASSERT_EQ("foo", android::base::Trim(Foo()));
+}
+
+TEST(strings, trim_build_implicit_string_view_conversion) {
+  struct Foo {
+    explicit operator std::string() { return " foo "; }
+    operator std::string_view() { return " foo "; }
+  };
+  ASSERT_EQ("foo", android::base::Trim(Foo()));
+}
+
 TEST(strings, join_nothing) {
   std::vector<std::string> list = {};
   ASSERT_EQ("", android::base::Join(list, ','));